diff --git a/common/advancedDetector.cpp b/common/advancedDetector.cpp index cc3b269fc1e..33af4736d26 100644 --- a/common/advancedDetector.cpp +++ b/common/advancedDetector.cpp @@ -148,24 +148,6 @@ static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGa return gd; } -// Almost identical to the toGameDescriptor function that takes a ADGameDescription and PlainGameDescriptor. -// Just a little fine tuning about accessing variables. -// Used because of fallback detection and the dynamic string content it needs. -static GameDescriptor toGameDescriptor(const EncapsulatedADGameDesc &g, const PlainGameDescriptor *sg) { - const char *title = 0; - - while (sg->gameid) { - if (!scumm_stricmp(g.getGameID(), sg->gameid)) - title = sg->description; - sg++; - } - - assert(g.realDesc); - GameDescriptor gd(g.getGameID(), title, g.realDesc->language, g.realDesc->platform); - gd.updateDesc(g.getExtra()); - return gd; -} - /** * Generate a preferred target value as * GAMEID-PLAFORM-LANG @@ -213,10 +195,10 @@ GameList AdvancedMetaEngine::detectGames(const FSList &fslist) const { // Use fallback detector if there were no matches by other means if (matches.empty()) { - EncapsulatedADGameDesc fallbackDesc = fallbackDetect(&fslist); - if (fallbackDesc.realDesc != 0) { - GameDescriptor desc(toGameDescriptor(fallbackDesc, params.list)); - updateGameDescriptor(desc, fallbackDesc.realDesc, params); + const Common::ADGameDescription *fallbackDesc = fallbackDetect(&fslist); + if (fallbackDesc != 0) { + GameDescriptor desc(toGameDescriptor(*fallbackDesc, params.list)); + updateGameDescriptor(desc, fallbackDesc, params); detectedGames.push_back(desc); } } else for (uint i = 0; i < matches.size(); i++) { // Otherwise use the found matches @@ -233,7 +215,6 @@ PluginError AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) c upgradeTargetIfNecessary(params); const ADGameDescription *agdDesc = 0; - EncapsulatedADGameDesc result; Common::Language language = Common::UNK_LANG; Common::Platform platform = Common::kPlatformUnknown; Common::String extra(""); @@ -261,22 +242,23 @@ PluginError AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) c agdDesc = matches[0]; } - if (agdDesc != 0) { // Check if we found a match without fallback detection - result = EncapsulatedADGameDesc(agdDesc); - } else { + if (agdDesc == 0) { // Use fallback detector if there were no matches by other means - EncapsulatedADGameDesc fallbackDesc = fallbackDetect(NULL); - if (fallbackDesc.realDesc != 0 && (params.singleid != NULL || fallbackDesc.getGameID() == gameid)) { - result = fallbackDesc; // Found a fallback match + agdDesc = fallbackDetect(NULL); + if (agdDesc != 0) { + // Seems we found a fallback match. But first perform a basic + // sanity check: the gameid must match. + if (params.singleid == NULL && agdDesc->gameid != gameid) + agdDesc = 0; } } - if (result.realDesc == 0) { + if (agdDesc == 0) { return kNoGameDataFoundError; } - debug(2, "Running %s", toGameDescriptor(result, params.list).description().c_str()); - if (!createInstance(syst, engine, result.realDesc)) { + debug(2, "Running %s", toGameDescriptor(*agdDesc, params.list).description().c_str()); + if (!createInstance(syst, engine, agdDesc)) { return kNoGameDataFoundError; } return kNoError; diff --git a/common/advancedDetector.h b/common/advancedDetector.h index cb93510231f..94e21a3a9b8 100644 --- a/common/advancedDetector.h +++ b/common/advancedDetector.h @@ -64,31 +64,6 @@ struct ADGameDescription { uint32 flags; }; -/** - * Encapsulates ADGameDescription and makes gameid and extra strings dynamic. - * Used in fallback detection when dynamically creating string content. - * - * @todo Get rid of this once the fallback detection is a member of AdvancedMetaEngine. - */ -struct EncapsulatedADGameDesc { - Common::String gameid; - Common::String extra; - const ADGameDescription *realDesc; - - // Constructor for the EncapsulatedADGameDesc - EncapsulatedADGameDesc() : realDesc(0) {} - EncapsulatedADGameDesc(const ADGameDescription *paramRealDesc, - Common::String paramGameID = Common::String(), - Common::String paramExtra = Common::String()) - : realDesc(paramRealDesc), gameid(paramGameID), extra(paramExtra) { - assert(paramRealDesc != NULL); - } - - // Functions for getting the correct gameid and extra values from the struct - const char *getGameID() const { return (gameid.empty() && realDesc != 0) ? realDesc->gameid : gameid.c_str(); } - const char *getExtra() const { return (extra.empty() && realDesc != 0) ? realDesc->extra : extra.c_str(); } -}; - /** * A list of pointers to ADGameDescription structs (or subclasses thereof). */ @@ -242,8 +217,8 @@ public: * @note The fslist parameter may be 0 -- in that case, it is assumed * that the callback searchs the current directory. */ - EncapsulatedADGameDesc fallbackDetect(const FSList *fslist) const { - return EncapsulatedADGameDesc(); + const Common::ADGameDescription *fallbackDetect(const FSList *fslist) const { + return 0; } }; diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 2adb2aacd4c..825614c48e4 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -23,8 +23,6 @@ * */ - - #include "base/plugins.h" #include "common/advancedDetector.h" @@ -2057,8 +2055,8 @@ static const AGIGameDescription gameDescriptions[] = { */ static AGIGameDescription g_fallbackDesc = { { - "", // Not used by the fallback descriptor, it uses the EncapsulatedADGameDesc's gameid - "", // Not used by the fallback descriptor, it uses the EncapsulatedADGameDesc's extra + "", + "", AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor Common::UNK_LANG, Common::kPlatformPC, @@ -2070,7 +2068,69 @@ static AGIGameDescription g_fallbackDesc = { 0x2917, }; -Common::EncapsulatedADGameDesc fallbackDetector(const FSList *fslist) { +static const Common::ADParams detectionParams = { + // Pointer to ADGameDescription or its superset structure + (const byte *)Agi::gameDescriptions, + // Size of that superset structure + sizeof(Agi::AGIGameDescription), + // Number of bytes to compute MD5 sum for + 5000, + // List of all engine targets + agiGames, + // Structure for autoupgrading obsolete targets + 0, + // Name of single gameid (optional) + "agi", + // List of files for file-based fallback detection (optional) + 0, + // Flags + Common::kADFlagAugmentPreferredTarget +}; + +} // End of namespace Agi + +using namespace Agi; + +class AgiMetaEngine : public Common::AdvancedMetaEngine { + mutable Common::String _gameid; + mutable Common::String _extra; + +public: + AgiMetaEngine() : Common::AdvancedMetaEngine(detectionParams) {} + + virtual const char *getName() const { + return "AGI preAGI + v2 + v3 Engine"; + } + virtual const char *getCopyright() const { + return "Sierra AGI Engine (C) Sierra On-Line Software"; + } + + virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; + + const Common::ADGameDescription *fallbackDetect(const FSList *fslist) const; +}; + +bool AgiMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { + const Agi::AGIGameDescription *gd = (const Agi::AGIGameDescription *)desc; + bool res = true; + + switch (gd->gameType) { + case Agi::GType_PreAGI: + *engine = new Agi::PreAgiEngine(syst, gd); + break; + case Agi::GType_V2: + case Agi::GType_V3: + *engine = new Agi::AgiEngine(syst, gd); + break; + default: + res = false; + error("AGI engine: unknown gameType"); + } + + return res; +} + +const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const FSList *fslist) const { typedef Common::HashMap IntMap; IntMap allFiles; bool matchedUsingFilenames = false; @@ -2078,9 +2138,13 @@ Common::EncapsulatedADGameDesc fallbackDetector(const FSList *fslist) { int wagFileCount = 0; WagFileParser wagFileParser; Common::String wagFilePath; - Common::String gameid("agi-fanmade"), description, extra; // Set the defaults for gameid, description and extra + Common::String description; FSList fslistCurrentDir; // Only used if fslist == NULL + // // Set the defaults for gameid and extra + _gameid = "agi-fanmade"; + _extra.clear(); + // Use the current directory for searching if fslist == NULL if (fslist == NULL) { Common::String path = ConfMan.get("path"); @@ -2184,8 +2248,8 @@ Common::EncapsulatedADGameDesc fallbackDetector(const FSList *fslist) { // Set gameid according to *.wag file information if it's present and it doesn't contain whitespace. if (wagGameID != NULL && !Common::String(wagGameID->getData()).contains(" ")) { - gameid = wagGameID->getData(); - debug(3, "Agi::fallbackDetector: Using game id (%s) from WAG file", gameid.c_str()); + _gameid = wagGameID->getData(); + debug(3, "Agi::fallbackDetector: Using game id (%s) from WAG file", _gameid.c_str()); } // Set game description and extra according to *.wag file information if they're present @@ -2195,14 +2259,14 @@ Common::EncapsulatedADGameDesc fallbackDetector(const FSList *fslist) { // If there's game version in the *.wag file, set extra to it if (wagGameVer != NULL) { - extra = wagGameVer->getData(); + _extra = wagGameVer->getData(); debug(3, "Agi::fallbackDetector: Game version (%s) from WAG file", wagGameVer->getData()); } // If there's game last edit date in the *.wag file, add it to extra if (wagGameLastEdit != NULL) { - if (!extra.empty() ) extra += " "; - extra += wagGameLastEdit->getData(); + if (!_extra.empty() ) _extra += " "; + _extra += wagGameLastEdit->getData(); debug(3, "Agi::fallbackDetector: Game's last edit date (%s) from WAG file", wagGameLastEdit->getData()); } } @@ -2223,78 +2287,24 @@ Common::EncapsulatedADGameDesc fallbackDetector(const FSList *fslist) { g_fallbackDesc.gameType = GType_V3; // Check if we found a match with any of the fallback methods - Common::EncapsulatedADGameDesc result; if (matchedUsingWag || matchedUsingFilenames) { - extra = description + (!extra.empty() ? " " : "") + extra; // Let's combine the description and extra - result = Common::EncapsulatedADGameDesc((const Common::ADGameDescription *)&g_fallbackDesc, gameid, extra); + _extra = description + (!_extra.empty() ? " " : "") + _extra; // Let's combine the description and extra + + // Override the gameid & extra values in g_fallbackDesc.desc. This only works + // until the fallback detector is called again, and while the MetaEngine instance + // is alive (as else the string storage is modified/deleted). + g_fallbackDesc.desc.gameid = _gameid.c_str(); + g_fallbackDesc.desc.extra = _extra.c_str(); printf("Your game version has been detected using fallback matching as a\n"); - printf("variant of %s (%s).\n", result.getGameID(), result.getExtra()); + printf("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra); printf("If this is an original and unmodified version or new made Fanmade game,\n"); printf("please report any, information previously printed by ScummVM to the team.\n"); + return (const Common::ADGameDescription *)&g_fallbackDesc; } - return result; -} - -} // End of namespace Agi - -static const Common::ADParams detectionParams = { - // Pointer to ADGameDescription or its superset structure - (const byte *)Agi::gameDescriptions, - // Size of that superset structure - sizeof(Agi::AGIGameDescription), - // Number of bytes to compute MD5 sum for - 5000, - // List of all engine targets - agiGames, - // Structure for autoupgrading obsolete targets - 0, - // Name of single gameid (optional) - "agi", - // List of files for file-based fallback detection (optional) - 0, - // Flags - Common::kADFlagAugmentPreferredTarget -}; - -class AgiMetaEngine : public Common::AdvancedMetaEngine { -public: - AgiMetaEngine() : Common::AdvancedMetaEngine(detectionParams) {} - - virtual const char *getName() const { - return "AGI preAGI + v2 + v3 Engine"; - } - virtual const char *getCopyright() const { - return "Sierra AGI Engine (C) Sierra On-Line Software"; - } - - virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; - - Common::EncapsulatedADGameDesc fallbackDetect(const FSList *fslist) const { - return Agi::fallbackDetector(fslist); - } -}; - -bool AgiMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { - const Agi::AGIGameDescription *gd = (const Agi::AGIGameDescription *)desc; - bool res = true; - - switch (gd->gameType) { - case Agi::GType_PreAGI: - *engine = new Agi::PreAgiEngine(syst, gd); - break; - case Agi::GType_V2: - case Agi::GType_V3: - *engine = new Agi::AgiEngine(syst, gd); - break; - default: - res = false; - error("AGI engine: unknown gameType"); - } - - return res; + return 0; } REGISTER_PLUGIN(AGI, PLUGIN_TYPE_ENGINE, AgiMetaEngine); diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp index a51c563383e..e2042bf93fa 100644 --- a/engines/drascula/detection.cpp +++ b/engines/drascula/detection.cpp @@ -111,8 +111,8 @@ static const DrasculaGameDescription gameDescriptions[] = { */ static DrasculaGameDescription g_fallbackDesc = { { - "", // Not used by the fallback descriptor, it uses the EncapsulatedADGameDesc's gameid - "", // Not used by the fallback descriptor, it uses the EncapsulatedADGameDesc's extra + "", + "", AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor Common::UNK_LANG, Common::kPlatformPC, @@ -124,22 +124,6 @@ static DrasculaGameDescription g_fallbackDesc = { 0, }; -Common::EncapsulatedADGameDesc fallbackDetector(const FSList *fslist) { - // Set the default values for the fallback descriptor's ADGameDescription part. - g_fallbackDesc.desc.language = Common::UNK_LANG; - g_fallbackDesc.desc.platform = Common::kPlatformPC; - g_fallbackDesc.desc.flags = Common::ADGF_NO_FLAGS; - - // Set default values for the fallback descriptor's DrasculaGameDescription part. - g_fallbackDesc.gameID = 0; - g_fallbackDesc.features = 0; - g_fallbackDesc.version = 0; - - Common::EncapsulatedADGameDesc result; - - return result; -} - } // End of namespace Drascula static const Common::ADParams detectionParams = { @@ -175,9 +159,8 @@ public: virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; - Common::EncapsulatedADGameDesc fallbackDetect(const FSList *fslist) const { - return Drascula::fallbackDetector(fslist); - } + const Common::ADGameDescription *fallbackDetect(const FSList *fslist) const; + }; bool DrasculaMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { @@ -188,4 +171,18 @@ bool DrasculaMetaEngine::createInstance(OSystem *syst, Engine **engine, const Co return gd != 0; } +const Common::ADGameDescription *DrasculaMetaEngine::fallbackDetect(const FSList *fslist) const { + // Set the default values for the fallback descriptor's ADGameDescription part. + Drascula::g_fallbackDesc.desc.language = Common::UNK_LANG; + Drascula::g_fallbackDesc.desc.platform = Common::kPlatformPC; + Drascula::g_fallbackDesc.desc.flags = Common::ADGF_NO_FLAGS; + + // Set default values for the fallback descriptor's DrasculaGameDescription part. + Drascula::g_fallbackDesc.gameID = 0; + Drascula::g_fallbackDesc.features = 0; + Drascula::g_fallbackDesc.version = 0; + + return (const Common::ADGameDescription *)&Drascula::g_fallbackDesc; +} + REGISTER_PLUGIN(DRASCULA, PLUGIN_TYPE_ENGINE, DrasculaMetaEngine);