Ticket #8690: fallbackDetector.patch
File fallbackDetector.patch, 23.3 KB (added by , 17 years ago) |
---|
-
engines/touche/detection.cpp
124 124 namespace Touche { 125 125 126 126 bool ToucheEngine::detectGame() { 127 const Common::ADGameDescription *gd = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 128 if (gd == 0) 127 const Common::ADGameDescription *gd = NULL; 128 const Common::EncapsulatedADGameDesc *encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 129 if (encapsulatedDesc != NULL) { 130 gd = encapsulatedDesc->realDesc; 131 delete encapsulatedDesc; // This is on the detectBestMatchingGame's caller's responsibility. 132 } 133 134 if (gd == NULL) 129 135 return false; 130 136 131 137 _language = gd->language; -
engines/agos/detection.cpp
117 117 assert(engine); 118 118 const char *gameid = ConfMan.get("gameid").c_str(); 119 119 120 //const AGOSGameDescription gd = (const AGOSGameDescription *)Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 121 //if (gd == 0) { 120 //const AGOSGameDescription *gd = NULL; 121 //const Common::EncapsulatedADGameDesc *encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 122 //if (encapsulatedDesc != NULL) { 123 // gd = (const AGOSGameDescription *)(encapsulatedDesc->realDesc); 124 // delete encapsulatedDesc; // This is on the detectBestMatchingGame's caller's responsibility. 125 //} 126 //if (gd == NULL) { 122 127 // return kNoGameDataFoundError; 123 128 //} 124 129 … … 154 159 namespace AGOS { 155 160 156 161 bool AGOSEngine::initGame() { 157 _gameDescription = (const AGOSGameDescription *)Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 158 return (_gameDescription != 0); 162 const Common::EncapsulatedADGameDesc *encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 163 if (encapsulatedDesc != NULL) { 164 _gameDescription = (const AGOSGameDescription *)(encapsulatedDesc->realDesc); 165 delete encapsulatedDesc; // This is on the detectBestMatchingGame's caller's responsibility. 166 } else { 167 _gameDescription = NULL; 168 } 169 170 return (_gameDescription != NULL); 159 171 } 160 172 161 173 -
engines/cruise/detection.cpp
118 118 namespace Cruise { 119 119 120 120 bool CruiseEngine::initGame() { 121 _gameDescription = (const CRUISEGameDescription *)Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 121 const Common::EncapsulatedADGameDesc *encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 122 if (encapsulatedDesc != NULL) { 123 _gameDescription = (const CRUISEGameDescription *)(encapsulatedDesc->realDesc); 124 delete encapsulatedDesc; // This is on the detectBestMatchingGame's caller's responsibility. 125 } else { 126 _gameDescription = NULL; 127 } 122 128 123 return (_gameDescription != 0);129 return (_gameDescription != NULL); 124 130 } 125 131 126 132 } // End of namespace Cruise -
engines/agi/detection.cpp
1825 1825 { AD_TABLE_END_MARKER, 0, 0, 0, 0 } 1826 1826 }; 1827 1827 1828 static const AGIGameDescription fallbackDescs[] = { 1828 /** 1829 * The fallback game descriptor used by the AGI engine's fallbackDetector. 1830 * Contents of this struct are to be overwritten by the fallbackDetector. 1831 */ 1832 static AGIGameDescription g_fallbackDesc = { 1829 1833 { 1830 { 1831 "agi-fanmade", 1832 "Unknown v2 Game", 1833 AD_ENTRY1(0, 0), 1834 Common::UNK_LANG, 1835 Common::kPlatformPC, 1836 Common::ADGF_NO_FLAGS 1837 }, 1838 GID_FANMADE, 1839 GType_V2, 1840 GF_FANMADE, 1841 0x2917, 1834 "", // Not used by the fallback descriptor, it uses the EncapsulatedADGameDesc's gameid 1835 "", // Not used by the fallback descriptor, it uses the EncapsulatedADGameDesc's extra 1836 AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor 1837 Common::UNK_LANG, 1838 Common::kPlatformPC, 1839 Common::ADGF_NO_FLAGS 1842 1840 }, 1843 { 1844 { 1845 "agi-fanmade", 1846 "Unknown v2 AGIPAL Game", 1847 AD_ENTRY1(0, 0), 1848 Common::UNK_LANG, 1849 Common::kPlatformPC, 1850 Common::ADGF_NO_FLAGS 1851 }, 1852 GID_FANMADE, 1853 GType_V2, 1854 GF_FANMADE | GF_AGIPAL, 1855 0x2917, 1856 }, 1857 { 1858 { 1859 "agi-fanmade", 1860 "Unknown v3 Game", 1861 AD_ENTRY1(0, 0), 1862 Common::UNK_LANG, 1863 Common::kPlatformPC, 1864 Common::ADGF_NO_FLAGS 1865 }, 1866 GID_FANMADE, 1867 GType_V3, 1868 GF_FANMADE, 1869 0x3149, 1870 }, 1841 GID_FANMADE, 1842 GType_V2, 1843 GF_FANMADE, 1844 0x2917, 1871 1845 }; 1872 1846 1873 Common::ADGameDescList fallbackDetector(const FSList *fslist) { 1874 Common::String tstr; 1847 const Common::EncapsulatedADGameDesc *fallbackDetector(const FSList *fslist) { 1875 1848 typedef Common::HashMap<Common::String, int32, Common::CaseSensitiveString_Hash, Common::CaseSensitiveString_EqualTo> IntMap; 1876 1849 IntMap allFiles; 1877 Common::ADGameDescList matched; 1878 int matchedNum = -1; 1850 bool matchedUsingFilenames = false; 1851 Common::String gameid("agi-fanmade"), description, extra; // Set the defaults for gameid, description and extra 1852 FSList fslistCurrentDir; // Only used if fslist == NULL 1879 1853 1880 // TODO: 1881 // WinAGI produces *.wag file with interpreter version, game name 1882 // and other parameters. Add support for this once specs are known 1854 // Use the current directory for searching if fslist == NULL 1855 if (fslist == NULL) { 1856 FilesystemNode fsCurrentDir("."); 1857 fslistCurrentDir.push_back(fsCurrentDir); 1858 fslist = &fslistCurrentDir; 1859 } 1883 1860 1861 // Set the default values for the fallback descriptor's ADGameDescription part. 1862 g_fallbackDesc.desc.language = Common::UNK_LANG; 1863 g_fallbackDesc.desc.platform = Common::kPlatformPC; 1864 g_fallbackDesc.desc.flags = Common::ADGF_NO_FLAGS; 1865 // g_fallbackDesc.desc.gameid can't be modified so let it be 1866 // g_fallbackDesc.desc.extra can't be modified so let it be 1867 // g_fallbackDesc.desc.filesDescriptions shouldn't be modified here, it should always be AD_ENTRY1(0, 0) 1884 1868 1869 // Set default values for the fallback descriptor's AGIGameDescription part. 1870 g_fallbackDesc.gameID = GID_FANMADE; 1871 g_fallbackDesc.features = GF_FANMADE; 1872 g_fallbackDesc.version = 0x2917; 1873 // g_fallbackDesc.gameType is set later according to the AGI interpreter version number 1874 1885 1875 // First grab all filenames 1886 1876 for (FSList::const_iterator file = fslist->begin(); file != fslist->end(); ++file) { 1887 1877 if (file->isDirectory()) continue; 1888 tstr = file->name(); 1889 tstr.toLowercase(); 1890 1891 allFiles[tstr] = true; 1878 Common::String filename = file->name(); 1879 filename.toLowercase(); 1880 allFiles[filename] = true; // Save the filename in a hash table 1892 1881 } 1893 1882 1894 // Now check for v21895 1883 if (allFiles.contains("logdir") && allFiles.contains("object") && 1896 1884 allFiles.contains("picdir") && allFiles.contains("snddir") && 1897 1885 allFiles.contains("viewdir") && allFiles.contains("vol.0") && 1898 allFiles.contains("words.tok")) { 1899 matchedNum = 0; 1886 allFiles.contains("words.tok")) { // Check for v2 1887 // The default AGI interpreter version 0x2917 is okay for v2 games 1888 // so we don't have to change it here. 1889 matchedUsingFilenames = true; 1900 1890 1901 // Check if it is AGIPAL 1902 if (allFiles.contains("pal.101")) 1903 matchedNum = 1; 1891 if (allFiles.contains("pal.101")) { // Check if it is AGIPAL 1892 description = "Unknown v2 AGIPAL Game"; 1893 g_fallbackDesc.features |= GF_AGIPAL; // Add AGIPAL feature flag 1894 } else { // Not AGIPAL so just plain v2 1895 description = "Unknown v2 Game"; 1896 } 1904 1897 } else { // Try v3 1905 1898 char name[8]; 1906 1899 … … 1911 1904 1912 1905 if (allFiles.contains("object") && allFiles.contains("words.tok") && 1913 1906 allFiles.contains(Common::String(name) + "dir")) { 1914 matchedNum = 2; 1907 matchedUsingFilenames = true; 1908 description = "Unknown v3 Game"; 1909 g_fallbackDesc.version = 0x3149; // Set the default AGI version for an AGI v3 game 1915 1910 break; 1916 1911 } 1917 1912 } 1918 1913 } 1919 1914 } 1920 1915 1921 if (matchedNum != -1) { 1922 matched.push_back(&fallbackDescs[matchedNum].desc); 1916 // Check that the AGI interpreter version is a supported one 1917 if (!(g_fallbackDesc.version >= 0x2000 && g_fallbackDesc.version < 0x4000)) { 1918 warning("Unsupported AGI interpreter version 0x%x in AGI's fallback detection. Using default 0x2917", g_fallbackDesc.version); 1919 g_fallbackDesc.version = 0x2917; 1920 } 1923 1921 1922 // Set game type (v2 or v3) according to the AGI interpreter version number 1923 if (g_fallbackDesc.version >= 0x2000 && g_fallbackDesc.version < 0x3000) 1924 g_fallbackDesc.gameType = GType_V2; 1925 else if (g_fallbackDesc.version >= 0x3000 && g_fallbackDesc.version < 0x4000) 1926 g_fallbackDesc.gameType = GType_V3; 1927 1928 // Check if we found a match with any of the fallback methods 1929 if (matchedUsingFilenames) { 1930 extra = description + " " + extra; // Let's combine the description and extra 1931 const Common::EncapsulatedADGameDesc *result = new Common::EncapsulatedADGameDesc((const Common::ADGameDescription *)&g_fallbackDesc, gameid, extra); 1932 1924 1933 printf("Your game version has been detected using fallback matching as a\n"); 1925 printf("variant of %s (%s).\n", fallbackDescs[matchedNum].desc.gameid, fallbackDescs[matchedNum].desc.extra);1934 printf("variant of %s (%s).\n", result->getGameID(), result->getExtra()); 1926 1935 printf("If this is an original and unmodified version or new made Fanmade game,\n"); 1927 1936 printf("please report any, information previously printed by ScummVM to the team.\n"); 1928 }1929 1937 1930 return matched; 1938 return result; 1939 } else // If we found no match then let's return NULL 1940 return NULL; 1931 1941 } 1932 1942 1933 } 1943 } // End of namespace Agi 1934 1944 1935 1945 static const Common::ADParams detectionParams = { 1936 1946 // Pointer to ADGameDescription or its superset structure … … 1960 1970 namespace Agi { 1961 1971 1962 1972 bool AgiEngine::initGame() { 1963 _gameDescription = (const AGIGameDescription *)Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 1964 return (_gameDescription != 0); 1973 const Common::EncapsulatedADGameDesc *encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 1974 if (encapsulatedDesc != NULL) { 1975 _gameDescription = (const AGIGameDescription *)(encapsulatedDesc->realDesc); 1976 delete encapsulatedDesc; // This is on the detectBestMatchingGame's caller's responsibility. 1977 } else { 1978 _gameDescription = NULL; 1979 } 1980 1981 return (_gameDescription != NULL); 1965 1982 } 1966 1983 1967 1984 } // End of namespace Agi -
engines/kyra/detection.cpp
133 133 assert(engine); 134 134 const char *gameid = ConfMan.get("gameid").c_str(); 135 135 136 const KYRAGameDescription *gd = (const KYRAGameDescription *)Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 137 if (gd == 0) { 136 const KYRAGameDescription *gd = NULL; 137 const Common::EncapsulatedADGameDesc *encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 138 if (encapsulatedDesc != NULL) { 139 gd = (const KYRAGameDescription *)(encapsulatedDesc->realDesc); 140 delete encapsulatedDesc; // This is on the detectBestMatchingGame's caller's responsibility. 141 } 142 143 if (gd == NULL) { 138 144 // maybe add non md5 based detection again? 139 145 return kNoGameDataFoundError; 140 146 } -
engines/gob/detection.cpp
1150 1150 namespace Gob { 1151 1151 1152 1152 bool GobEngine::detectGame() { 1153 const GOBGameDescription *gd = (const GOBGameDescription *)Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 1154 if (gd == 0) 1153 const GOBGameDescription *gd = NULL; 1154 const Common::EncapsulatedADGameDesc *encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 1155 if (encapsulatedDesc != NULL) { 1156 gd = (const GOBGameDescription *)(encapsulatedDesc->realDesc); 1157 delete encapsulatedDesc; // This is on the detectBestMatchingGame's caller's responsibility. 1158 } 1159 1160 if (gd == NULL) 1155 1161 return false; 1156 1162 1157 if (gd->startTotBase == 0) {1163 if (gd->startTotBase == NULL) { 1158 1164 _startTot = new char[10]; 1159 1165 _startTot0 = new char[11]; 1160 1166 strcpy(_startTot, "intro.tot"); -
engines/parallaction/detection.cpp
131 131 namespace Parallaction { 132 132 133 133 bool Parallaction::detectGame() { 134 _gameDescription = (const PARALLACTIONGameDescription *)Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 135 return (_gameDescription != 0); 134 const Common::EncapsulatedADGameDesc *encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 135 if (encapsulatedDesc != NULL) { 136 _gameDescription = (const PARALLACTIONGameDescription *)(encapsulatedDesc->realDesc); 137 delete encapsulatedDesc; // This is on the detectBestMatchingGame's caller's responsibility. 138 } else { 139 _gameDescription = NULL; 140 } 141 142 return (_gameDescription != NULL); 136 143 } 137 144 138 145 } // End of namespace Parallaction -
engines/saga/detection.cpp
124 124 namespace Saga { 125 125 126 126 bool SagaEngine::initGame() { 127 _gameDescription = (const SAGAGameDescription *)Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 128 if (_gameDescription == 0) 127 const Common::EncapsulatedADGameDesc *encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 128 if (encapsulatedDesc != NULL) { 129 _gameDescription = (const SAGAGameDescription *)(encapsulatedDesc->realDesc); 130 delete encapsulatedDesc; // This is on the detectBestMatchingGame's caller's responsibility. 131 } else { 132 _gameDescription = NULL; 133 } 134 135 if (_gameDescription == NULL) 129 136 return false; 130 137 131 138 _displayClip.right = getDisplayInfo().logicalWidth; -
engines/cine/detection.cpp
494 494 namespace Cine { 495 495 496 496 bool CineEngine::initGame() { 497 _gameDescription = (const CINEGameDescription *)Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 498 return (_gameDescription != 0); 497 const Common::EncapsulatedADGameDesc *encapsulatedDesc = Common::AdvancedDetector::detectBestMatchingGame(detectionParams); 498 if (encapsulatedDesc != NULL) { 499 _gameDescription = (const CINEGameDescription *)(encapsulatedDesc->realDesc); 500 delete encapsulatedDesc; // This is on the detectBestMatchingGame's caller's responsibility. 501 } else { 502 _gameDescription = NULL; 503 } 504 505 return (_gameDescription != NULL); 499 506 } 500 507 501 508 } // End of namespace Cine -
common/advancedDetector.h
64 64 }; 65 65 66 66 /** 67 * Encapsulates ADGameDescription and makes gameid and extra strings dynamic. 68 * Used in fallback detection when dynamically creating string content. 69 */ 70 struct EncapsulatedADGameDesc { 71 Common::String gameid; 72 Common::String extra; 73 const ADGameDescription *realDesc; 74 75 // Constructor for the EncapsulatedADGameDesc 76 EncapsulatedADGameDesc(const ADGameDescription *paramRealDesc = NULL, 77 Common::String paramGameID = Common::String(""), 78 Common::String paramExtra = Common::String("")) 79 : realDesc(paramRealDesc), gameid(paramGameID), extra(paramExtra) { 80 assert(paramRealDesc != NULL); 81 } 82 83 // Functions for getting the correct gameid and extra values from the struct 84 const char *getGameID() const { return gameid.empty() ? realDesc->gameid : gameid.c_str(); } 85 const char *getExtra() const { return extra.empty() ? realDesc->extra : extra.c_str(); } 86 }; 87 88 /** 67 89 * A list of pointers to ADGameDescription structs (or subclasses thereof). 68 90 */ 69 91 typedef Array<const ADGameDescription*> ADGameDescList; … … 175 197 * @note The fslist parameter may be 0 -- in that case, it is assumed 176 198 * that the callback searchs the current directory. 177 199 * 200 * @note You need to handle deleting the returned pointer if it's not NULL. 201 * You don't need to delete the memory pointed to by the realDesc 202 * pointer inside the struct though because it should be statically 203 * allocated. 204 * 205 * @return A pointer to a single EncapsulatedADGameDesc if there was a 206 * match, otherwise NULL. 207 * 178 208 * @todo 179 209 */ 180 ADGameDescList(*fallbackDetectFunc)(const FSList *fslist);210 const EncapsulatedADGameDesc *(*fallbackDetectFunc)(const FSList *fslist); 181 211 182 212 /** 183 213 * A bitmask of flags which can be used to configure the behavior … … 206 236 // FIXME/TODO: Rename this function to something more sensible. 207 237 GameList detectAllGames(const FSList &fslist, const Common::ADParams ¶ms); 208 238 209 // FIXME/TODO: Rename this function to something more sensible. 210 const ADGameDescription *detectBestMatchingGame(const Common::ADParams ¶ms); 239 /** 240 * Detect the best matching game. 241 * 242 * FIXME/TODO: Rename this function to something more sensible. 243 * 244 * @note You need to handle deleting the returned pointer if it's not NULL. 245 * You don't need to delete the memory pointed to by the realDesc 246 * pointer inside the struct though because it should be statically 247 * allocated. 248 */ 249 const EncapsulatedADGameDesc *detectBestMatchingGame(const Common::ADParams ¶ms); 211 250 212 251 // FIXME/TODO: Rename this function to something more sensible. 213 252 // Only used by ADVANCED_DETECTOR_DEFINE_PLUGIN_WITH_FUNC -
common/advancedDetector.cpp
110 110 return gd; 111 111 } 112 112 113 // Almost identical to the toGameDescriptor function that takes a ADGameDescription and PlainGameDescriptor. 114 // Just a little fine tuning about accessing variables. 115 // Used because of fallback detection and the dynamic string content it needs. 116 static GameDescriptor toGameDescriptor(const EncapsulatedADGameDesc &g, const PlainGameDescriptor *sg) { 117 const char *title = 0; 118 119 while (sg->gameid) { 120 if (!scumm_stricmp(g.getGameID(), sg->gameid)) 121 title = sg->description; 122 sg++; 123 } 124 125 GameDescriptor gd(g.getGameID(), title, g.realDesc->language, g.realDesc->platform); 126 gd.updateDesc(g.getExtra()); 127 return gd; 128 } 129 113 130 /** 114 131 * Generate a preferred target value as 115 132 * GAMEID-PLAFORM-LANG … … 139 156 const Common::ADParams ¶ms 140 157 ) { 141 158 ADGameDescList matches = detectGame(&fslist, params, Common::UNK_LANG, Common::kPlatformUnknown); 142 143 159 GameList detectedGames; 144 for (uint i = 0; i < matches.size(); i++) { 145 GameDescriptor desc(toGameDescriptor(*matches[i], params.list)); 160 const EncapsulatedADGameDesc *fallbackDesc = NULL; 146 161 162 // Use fallback detector if there were no matches by other means 163 if (matches.empty() && params.fallbackDetectFunc != NULL) { 164 fallbackDesc = (*params.fallbackDetectFunc)(&fslist); 165 if (fallbackDesc != NULL) detectedGames.push_back(toGameDescriptor(*fallbackDesc, params.list)); 166 } else for (uint i = 0; i < matches.size(); i++) // Otherwise use the found matches 167 detectedGames.push_back(toGameDescriptor(*matches[i], params.list)); 168 169 for (uint i = 0; i < detectedGames.size(); i++) { 147 170 if (params.singleid != NULL) { 148 de sc["preferredtarget"] = desc["gameid"];149 de sc["gameid"] = params.singleid;171 detectedGames[i]["preferredtarget"] = detectedGames[i]["gameid"]; 172 detectedGames[i]["gameid"] = params.singleid; 150 173 } 151 174 152 175 if (params.flags & kADFlagAugmentPreferredTarget) { 153 if (!de sc.contains("preferredtarget"))154 de sc["preferredtarget"] = desc["gameid"];176 if (!detectedGames[i].contains("preferredtarget")) 177 detectedGames[i]["preferredtarget"] = detectedGames[i]["gameid"]; 155 178 156 desc["preferredtarget"] = generatePreferredTarget(desc["preferredtarget"], matches[i]); 179 if (!matches.empty()) { // If found a match or matches without fallback detection 180 detectedGames[i]["preferredtarget"] = generatePreferredTarget(detectedGames[i]["preferredtarget"], matches[i]); 181 } else if (fallbackDesc != NULL) { // If found match with the fallback detection 182 // This assumes that generatePreferredTarget doesn't need gameid or extra fields from the fallbackDesc, 183 // so we can just give it the ADGameDescription from inside the *fallbackDesc. 184 detectedGames[i]["preferredtarget"] = generatePreferredTarget(detectedGames[i]["preferredtarget"], fallbackDesc->realDesc); 185 } 157 186 } 158 159 detectedGames.push_back(desc);160 187 } 161 188 189 if (fallbackDesc != NULL) 190 delete fallbackDesc; // Delete the fallback descriptor! Must be done to avoid memory leakage! 191 162 192 return detectedGames; 163 193 } 164 194 165 const ADGameDescription*detectBestMatchingGame(195 const EncapsulatedADGameDesc *detectBestMatchingGame( 166 196 const Common::ADParams ¶ms 167 197 ) { 168 const ADGameDescription *agdDesc = 0; 198 const ADGameDescription *agdDesc = NULL; 199 const EncapsulatedADGameDesc *result = NULL; 169 200 Common::Language language = Common::UNK_LANG; 170 201 Common::Platform platform = Common::kPlatformUnknown; 171 202 … … 176 207 177 208 Common::String gameid = ConfMan.get("gameid"); 178 209 179 ADGameDescList matches = detectGame( 0, params, language, platform);210 ADGameDescList matches = detectGame(NULL, params, language, platform); 180 211 181 212 if (params.singleid == NULL) { 182 213 for (uint i = 0; i < matches.size(); i++) { … … 189 220 agdDesc = matches[0]; 190 221 } 191 222 192 if (agdDesc != 0) { 193 debug(2, "Running %s", toGameDescriptor(*agdDesc, params.list).description().c_str()); 223 // Use fallback detector if there were no matches by other means 224 if (matches.empty() && params.fallbackDetectFunc != NULL) { 225 const EncapsulatedADGameDesc *fallbackDesc = (*params.fallbackDetectFunc)(NULL); 226 if (fallbackDesc != NULL && (params.singleid != NULL || fallbackDesc->getGameID() == gameid)) { 227 result = fallbackDesc; // Found a fallback match 228 } 194 229 } 195 230 196 return agdDesc; 231 // If we found a match without fallback detection 232 // then let's convert it to this function's return format 233 if (agdDesc != NULL) { 234 assert(result == NULL); // Should be NULL at the moment 235 result = new EncapsulatedADGameDesc(agdDesc); 236 } 237 238 if (result != NULL) { 239 debug(2, "Running %s", toGameDescriptor(*result, params.list).description().c_str()); 240 } 241 242 return result; 197 243 } 198 244 199 245 PluginError detectGameForEngineCreation( … … 236 282 } 237 283 } 238 284 285 // Use fallback detector if there were no matches by other means 286 if (matches.empty() && params.fallbackDetectFunc != NULL) { 287 const EncapsulatedADGameDesc *fallbackDesc = (*params.fallbackDetectFunc)(&fslist); 288 if (fallbackDesc != NULL) { 289 bool foundFallbackMatch = (params.singleid != NULL || fallbackDesc->getGameID() == gameid); 290 delete fallbackDesc; // Delete the fallback descriptor! Must be done to avoid memory leakage! 291 if (foundFallbackMatch) return kNoError; 292 } 293 } 294 239 295 return kNoGameDataFoundError; 240 296 } 241 297 … … 486 542 } 487 543 } 488 544 489 // If we still haven't got a match, try to use the fallback callback :-)490 if (matched.empty() && params.fallbackDetectFunc != 0) {491 matched = (*params.fallbackDetectFunc)(fslist);492 }493 494 545 return matched; 495 546 } 496 547