diff options
-rw-r--r-- | common/advancedDetector.cpp | 120 | ||||
-rw-r--r-- | common/advancedDetector.h | 5 | ||||
-rw-r--r-- | engines/agi/detection.cpp | 2 | ||||
-rw-r--r-- | engines/agos/game.cpp | 2 | ||||
-rw-r--r-- | engines/cine/detection.cpp | 2 | ||||
-rw-r--r-- | engines/gob/detection.cpp | 160 | ||||
-rw-r--r-- | engines/kyra/plugin.cpp | 2 | ||||
-rw-r--r-- | engines/parallaction/detection.cpp | 2 | ||||
-rw-r--r-- | engines/saga/game.cpp | 2 |
9 files changed, 242 insertions, 55 deletions
diff --git a/common/advancedDetector.cpp b/common/advancedDetector.cpp index 1193b1c72e..faca7184d0 100644 --- a/common/advancedDetector.cpp +++ b/common/advancedDetector.cpp @@ -251,6 +251,7 @@ static ADList detectGame(const FSList *fslist, const Common::ADParams ¶ms, L typedef HashMap<String, int32, Common::CaseSensitiveString_Hash, Common::CaseSensitiveString_EqualTo> IntMap; StringMap filesMD5; IntMap filesSize; + IntMap allFiles; String tstr, tstr2; @@ -293,6 +294,8 @@ static ADList detectGame(const FSList *fslist, const Common::ADParams ¶ms, L tstr.toLowercase(); tstr2 = tstr + "."; + allFiles[tstr] = allFiles[tstr2] = 1; + debug(3, "+ %s", tstr.c_str()); if (!filesList.contains(tstr) && !filesList.contains(tstr2)) continue; @@ -349,7 +352,12 @@ static ADList detectGame(const FSList *fslist, const Common::ADParams ¶ms, L (platform != kPlatformUnknown && g->platform != platform)) { continue; } - + + if (g->filesDescriptions[0].fileName == 0) { + debug(5, "Skipping dummy entry: %s", g->gameid); + continue; + } + // Try to open all files for this game for (j = 0; g->filesDescriptions[j].fileName; j++) { fileDesc = &g->filesDescriptions[j]; @@ -357,28 +365,26 @@ static ADList detectGame(const FSList *fslist, const Common::ADParams ¶ms, L tstr.toLowercase(); tstr2 = tstr + "."; + if (!filesMD5.contains(tstr) && !filesMD5.contains(tstr2)) { + fileMissing = true; + break; + } if (fileDesc->md5 != NULL) { - if (!filesMD5.contains(tstr) && !filesMD5.contains(tstr2)) { - fileMissing = true; - break; - } if (strcmp(fileDesc->md5, filesMD5[tstr].c_str()) && strcmp(fileDesc->md5, filesMD5[tstr2].c_str())) { debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesMD5[tstr].c_str()); fileMissing = true; break; } } + if (fileDesc->fileSize != -1) { - if (!filesMD5.contains(tstr) && !filesMD5.contains(tstr2)) { - fileMissing = true; - break; - } if (fileDesc->fileSize != filesSize[tstr] && fileDesc->fileSize != filesSize[tstr2]) { debug(3, "Size Mismatch. Skipping"); fileMissing = true; break; } } + debug(3, "Matched file: %s", tstr.c_str()); } if (!fileMissing) { @@ -416,6 +422,102 @@ static ADList detectGame(const FSList *fslist, const Common::ADParams ¶ms, L printf("%s: \"%s\", %d\n", file->_key.c_str(), file->_value.c_str(), filesSize[file->_key]); } + if (params.flags & kADFlagFilebasedFallback) { + if (params.fileBased == NULL) { + error("Engine %s has FilebasedFallback flag set but list fileBased is empty", + params.singleid); // We may get 0 as singleid here, but let's ignore it + } + + const char **ptr = params.fileBased; + + // First we create list of files required for detection + if (allFiles.empty()) { + File testFile; + + while (*ptr) { + ptr++; + + while (*ptr) { + tstr = String(*ptr); + tstr.toLowercase(); + + if (!allFiles.contains(tstr)) { + if (testFile.open(tstr)) { + tstr2 = tstr + "."; + allFiles[tstr] = allFiles[tstr2] = 1; + testFile.close(); + } + } + + ptr++; + } + + ptr++; + } + } + + int maxFiles = 0; + int matchFiles; + const char **matchEntry = 0; + const char **entryStart; + + ptr = params.fileBased; + + while (*ptr) { + entryStart = ptr; + fileMissing = false; + matchFiles = 0; + + ptr++; + + while (*ptr) { + if (fileMissing) { + ptr++; + continue; + } + + tstr = String(*ptr); + + tstr.toLowercase(); + tstr2 = tstr + "."; + + debug(3, "++ %s", *ptr); + if (!allFiles.contains(tstr) && !allFiles.contains(tstr2)) { + fileMissing = true; + ptr++; + continue; + } + + matchFiles++; + ptr++; + } + + if (!fileMissing) + debug(4, "Matched: %s", *entryStart); + + if (!fileMissing && matchFiles > maxFiles) { + matchEntry = entryStart; + maxFiles = matchFiles; + + debug(4, "and overrided"); + } + + ptr++; + } + + if (matchEntry) { // We got a match + for (i = 0; i < gameDescriptions.size(); i++) { + if (gameDescriptions[i]->filesDescriptions[0].fileName == 0) { + if (!scumm_stricmp(gameDescriptions[i]->gameid, *matchEntry)) { + warning("But it looks like unknown variant of %s", *matchEntry); + + matched.push_back(i); + } + } + } + } + } + return matched; } diff --git a/common/advancedDetector.h b/common/advancedDetector.h index 4f79cd87db..93650f7f72 100644 --- a/common/advancedDetector.h +++ b/common/advancedDetector.h @@ -52,7 +52,8 @@ struct ADObsoleteGameID { }; enum ADFlags { - kADFlagComplexID = (1 << 0) // Generate complex suggested IDs + kADFlagComplexID = (1 << 0), // Generate complex suggested IDs + kADFlagFilebasedFallback = (1 << 1) // Use file based fallback detection }; struct ADParams { @@ -68,6 +69,8 @@ struct ADParams { const Common::ADObsoleteGameID *obsoleteList; // Name of single gameid (optional) const char *singleid; + // List of files for file-based fallback detection (optional) + const char **fileBased; // Flags uint32 flags; }; diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index dcb328c314..6b8e7348de 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -1013,6 +1013,8 @@ static const Common::ADParams detectionParams = { 0, // Name of single gameid (optional) "agi", + // List of files for file-based fallback detection (optional) + 0, // Flags Common::kADFlagComplexID }; diff --git a/engines/agos/game.cpp b/engines/agos/game.cpp index 89a22caa30..8652cb726b 100644 --- a/engines/agos/game.cpp +++ b/engines/agos/game.cpp @@ -95,6 +95,8 @@ static const Common::ADParams detectionParams = { obsoleteGameIDsTable, // Name of single gameid (optional) 0, + // List of files for file-based fallback detection (optional) + 0, // Flags 0 }; diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp index c455322a85..14c829a0dc 100644 --- a/engines/cine/detection.cpp +++ b/engines/cine/detection.cpp @@ -450,6 +450,8 @@ static const Common::ADParams detectionParams = { obsoleteGameIDsTable, // Name of single gameid (optional) "cine", + // List of files for file-based fallback detection (optional) + 0, // Flags Common::kADFlagComplexID }; diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 2379e8fa97..1997b117d6 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -45,10 +45,13 @@ using namespace Common; static const PlainGameDescriptor gobGames[] = { {"gob", "Gob engine game"}, {"gob1", "Gobliiins"}, + {"gob1cd", "Gobliiins CD"}, {"gob1-demo", "Gobliiins Demo"}, {"gob2", "Gobliins 2"}, + {"gob2cd", "Gobliins 2 CD"}, {"gob2-demo", "Gobliins 2 Demo"}, {"gob3", "Goblins Quest 3"}, + {"gob3cd", "Goblins Quest 3 CD"}, {"gob3-demo", "Goblins Quest 3 Demo"}, {"bargon", "Bargon Attack"}, {"ween", "Ween: The Prohpecy"}, @@ -66,6 +69,17 @@ static const ADObsoleteGameID obsoleteGameIDsTable[] = { namespace Gob { static const GOBGameDescription gameDescriptions[] = { + { // Dummy entry for fallback detection + { + "gob1", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + }, + GF_GOB1, + "intro" + }, { // Supplied by Florian Zeitz on scummvm-devel { "gob1", @@ -99,10 +113,21 @@ static const GOBGameDescription gameDescriptions[] = { GF_GOB1, "intro" }, - { // CD 1.000 version. Multilingual + { // Dummy entry for fallback detection { - "gob1", - "CD 1.000", + "gob1cd", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + }, + GF_GOB1 | GF_CD, + "intro" + }, + { // CD 1.000 version. + { + "gob1cd", + "v1.000", AD_ENTRY1("intro.stk", "2fbf4b5b82bbaee87eb45d4404c28998"), UNK_LANG, kPlatformPC, @@ -112,10 +137,43 @@ static const GOBGameDescription gameDescriptions[] = { }, { // CD 1.02 version. Multilingual { - "gob1", - "CD 1.02", + "gob1cd", + "v1.02", AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), - UNK_LANG, + EN_USA, + kPlatformPC, + }, + GF_GOB1 | GF_CD, + "intro" + }, + { // CD 1.02 version. Multilingual + { + "gob1cd", + "v1.02", + AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), + FR_FRA, + kPlatformPC, + }, + GF_GOB1 | GF_CD, + "intro" + }, + { // CD 1.02 version. Multilingual + { + "gob1cd", + "v1.02", + AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), + IT_ITA, + kPlatformPC, + }, + GF_GOB1 | GF_CD, + "intro" + }, + { // CD 1.02 version. Multilingual + { + "gob1cd", + "v1.02", + AD_ENTRY1("intro.stk", "8bd873137b6831c896ee8ad217a6a398"), + ES_ESP, kPlatformPC, }, GF_GOB1 | GF_CD, @@ -154,6 +212,17 @@ static const GOBGameDescription gameDescriptions[] = { GF_GOB1, "intro" }, + { // Dummy entry for fallback detection + { + "gob2", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + }, + GF_GOB2, + "intro" + }, { { "gob2", @@ -231,10 +300,21 @@ static const GOBGameDescription gameDescriptions[] = { GF_GOB2, "intro" }, + { // Dummy entry for fallback detection + { + "gob2cd", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + }, + GF_GOB2 | GF_CD, + "intro" + }, { { - "gob2", - "CD 1.000", + "gob2cd", + "v1.000", AD_ENTRY1("intro.stk", "9de5fbb41cf97182109e5fecc9d90347"), EN_USA, kPlatformPC, @@ -244,8 +324,8 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "gob2", - "CD 1.02", + "gob2cd", + "v1.02", AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), EN_ANY, kPlatformPC, @@ -255,8 +335,8 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "gob2", - "CD 1.02", + "gob2cd", + "v1.02", AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), DE_DEU, kPlatformPC, @@ -266,8 +346,8 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "gob2", - "CD 1.02", + "gob2cd", + "v1.02", AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), FR_FRA, kPlatformPC, @@ -277,8 +357,8 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "gob2", - "CD 1.02", + "gob2cd", + "v1.02", AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), IT_ITA, kPlatformPC, @@ -288,8 +368,8 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "gob2", - "CD 1.02", + "gob2cd", + "v1.02", AD_ENTRY1("intro.stk", "24a6b32757752ccb1917ce92fd7c2a04"), ES_ESP, kPlatformPC, @@ -453,8 +533,8 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "gob3", - "CD 1.000", + "gob3cd", + "v1.000", AD_ENTRY1("intro.stk", "6f2c226c62dd7ab0ab6f850e89d3fc47"), UNK_LANG, kPlatformPC, @@ -464,8 +544,8 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "gob3", - "CD 1.02", + "gob3cd", + "v1.02", AD_ENTRY1("intro.stk", "c3e9132ea9dc0fb866b6d60dcda10261"), UNK_LANG, kPlatformPC, @@ -542,6 +622,15 @@ static const GOBGameDescription gameDescriptions[] = { { { NULL, NULL, { { NULL, 0, NULL, 0 } }, UNK_LANG, kPlatformUnknown }, 0, NULL } }; +static const char *fileBased[] = { + "gob1", "intro.stk", "disk1.stk", "disk2.stk", "disk3.stk", "disk4.stk", 0, + "gob1cd", "intro.stk", "gob.lic", 0, + "gob2", "intro.stk", 0, + "gob2", "intro.stk", "disk2.stk", "disk3.stk", 0, + "gob2cd", "intro.stk", "gobnew.lic", 0, + 0 +}; + } static const ADParams detectionParams = { @@ -557,8 +646,10 @@ static const ADParams detectionParams = { obsoleteGameIDsTable, // Name of single gameid (optional) "gob", + // List of files for file-based fallback detection (optional) + Gob::fileBased, // Flags - kADFlagComplexID + kADFlagComplexID | kADFlagFilebasedFallback }; ADVANCED_DETECTOR_DEFINE_PLUGIN(GOB, Gob::GobEngine, Gob::GAME_detectGames, detectionParams); @@ -593,28 +684,7 @@ bool GobEngine::detectGame() { } GameList GAME_detectGames(const FSList &fslist) { - GameList gl(AdvancedDetector::detectAllGames(fslist, detectionParams)); - - if (gl.empty()) { - for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { - if (file->isDirectory()) continue; - - if (!scumm_stricmp(file->name().c_str(), "intro.stk")) { - const PlainGameDescriptor *g = detectionParams.list; - while (g->gameid) { - if (0 == scumm_stricmp(detectionParams.singleid, g->gameid)) { - gl.push_back(GameDescriptor(g->gameid, g->description)); - - return gl; - } - - g++; - } - } - } - } - - return gl; + return AdvancedDetector::detectAllGames(fslist, detectionParams); } } // End of namespace Parallaction diff --git a/engines/kyra/plugin.cpp b/engines/kyra/plugin.cpp index 6f497e3a61..31f87afaa8 100644 --- a/engines/kyra/plugin.cpp +++ b/engines/kyra/plugin.cpp @@ -94,6 +94,8 @@ const Common::ADParams detectionParams = { 0, // Name of single gameid (optional) 0, + // List of files for file-based fallback detection (optional) + 0, // Flags 0 }; diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp index 898df9d7da..709879a4c0 100644 --- a/engines/parallaction/detection.cpp +++ b/engines/parallaction/detection.cpp @@ -93,6 +93,8 @@ static const Common::ADParams detectionParams = { 0, // Name of single gameid (optional) "parallaction", + // List of files for file-based fallback detection (optional) + 0, // Flags Common::kADFlagComplexID }; diff --git a/engines/saga/game.cpp b/engines/saga/game.cpp index f2c3ff0628..24dfd41398 100644 --- a/engines/saga/game.cpp +++ b/engines/saga/game.cpp @@ -114,6 +114,8 @@ static const Common::ADParams detectionParams = { obsoleteGameIDsTable, // Name of single gameid (optional) "saga", + // List of files for file-based fallback detection (optional) + 0, // Flags Common::kADFlagComplexID }; |