ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

plugins.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "base/plugins.h"
00024 
00025 #include "common/translation.h"
00026 #include "common/func.h"
00027 #include "common/debug.h"
00028 #include "common/config-manager.h"
00029 
00030 #ifdef DYNAMIC_MODULES
00031 #include "common/fs.h"
00032 #endif
00033 
00034 // Plugin versioning
00035 
00036 int pluginTypeVersions[PLUGIN_TYPE_MAX] = {
00037     PLUGIN_TYPE_ENGINE_VERSION,
00038     PLUGIN_TYPE_MUSIC_VERSION,
00039 };
00040 
00041 
00042 // Abstract plugins
00043 
00044 PluginType Plugin::getType() const {
00045     return _type;
00046 }
00047 
00048 const char *Plugin::getName() const {
00049     return _pluginObject->getName();
00050 }
00051 
00052 class StaticPlugin : public Plugin {
00053 public:
00054     StaticPlugin(PluginObject *pluginobject, PluginType type) {
00055         assert(pluginobject);
00056         assert(type < PLUGIN_TYPE_MAX);
00057         _pluginObject = pluginobject;
00058         _type = type;
00059     }
00060 
00061     ~StaticPlugin() {
00062         delete _pluginObject;
00063     }
00064 
00065     virtual bool loadPlugin()       { return true; }
00066     virtual void unloadPlugin()     {}
00067 };
00068 
00069 class StaticPluginProvider : public PluginProvider {
00070 public:
00071     StaticPluginProvider() {
00072     }
00073 
00074     ~StaticPluginProvider() {
00075     }
00076 
00077     virtual PluginList getPlugins() {
00078         PluginList pl;
00079 
00080         #define LINK_PLUGIN(ID) \
00081             extern PluginType g_##ID##_type; \
00082             extern PluginObject *g_##ID##_getObject(); \
00083             pl.push_back(new StaticPlugin(g_##ID##_getObject(), g_##ID##_type));
00084 
00085         // "Loader" for the static plugins.
00086         // Iterate over all registered (static) plugins and load them.
00087 
00088         // Engine plugins
00089         #include "engines/plugins_table.h"
00090 
00091         // Music plugins
00092         // TODO: Use defines to disable or enable each MIDI driver as a
00093         // static/dynamic plugin, like it's done for the engines
00094 //ResidualVM: disabled belows:
00095 //      LINK_PLUGIN(AUTO)
00096 //      LINK_PLUGIN(NULL)
00097 //      #if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
00098 //      LINK_PLUGIN(WINDOWS)
00099 //      #endif
00100 //      #if defined(USE_ALSA)
00101 //      LINK_PLUGIN(ALSA)
00102 //      #endif
00103 //      #if defined(USE_SEQ_MIDI)
00104 //      LINK_PLUGIN(SEQ)
00105 //      #endif
00106 //      #if defined(USE_SNDIO)
00107 //      LINK_PLUGIN(SNDIO)
00108 //      #endif
00109 //      #if defined(__MINT__)
00110 //      LINK_PLUGIN(STMIDI)
00111 //      #endif
00112 //      #if defined(IRIX)
00113 //      LINK_PLUGIN(DMEDIA)
00114 //      #endif
00115 //      #if defined(__amigaos4__)
00116 //      LINK_PLUGIN(CAMD)
00117 //      #endif
00118 //      #if defined(MACOSX)
00119 //      LINK_PLUGIN(COREAUDIO)
00120 //      LINK_PLUGIN(COREMIDI)
00121 //      #endif
00122 //      #ifdef USE_FLUIDSYNTH
00123 //      LINK_PLUGIN(FLUIDSYNTH)
00124 //      #endif
00125 //      #ifdef USE_MT32EMU
00126 //      LINK_PLUGIN(MT32)
00127 //      #endif
00128 //      LINK_PLUGIN(ADLIB)
00129 //      LINK_PLUGIN(PCSPK)
00130 //      LINK_PLUGIN(PCJR)
00131 //      LINK_PLUGIN(CMS)
00132 //      #if defined(__ANDROID__)
00133 //      LINK_PLUGIN(EAS)
00134 //      #endif
00135 //      #ifndef DISABLE_SID
00136 //      LINK_PLUGIN(C64)
00137 //      #endif
00138 //      LINK_PLUGIN(AMIGA)
00139 //      LINK_PLUGIN(APPLEIIGS)
00140 //      LINK_PLUGIN(TOWNS)
00141 //      LINK_PLUGIN(PC98)
00142 //      #if defined(USE_TIMIDITY)
00143 //      LINK_PLUGIN(TIMIDITY)
00144 //      #endif
00145 
00146         return pl;
00147     }
00148 };
00149 
00150 #ifdef DYNAMIC_MODULES
00151 
00152 PluginList FilePluginProvider::getPlugins() {
00153     PluginList pl;
00154 
00155     // Prepare the list of directories to search
00156     Common::FSList pluginDirs;
00157 
00158     // Add the default directories
00159     pluginDirs.push_back(Common::FSNode("."));
00160     pluginDirs.push_back(Common::FSNode("plugins"));
00161 
00162     // Add the provider's custom directories
00163     addCustomDirectories(pluginDirs);
00164 
00165     // Add the user specified directory
00166     Common::String pluginsPath(ConfMan.get("pluginspath"));
00167     if (!pluginsPath.empty())
00168         pluginDirs.push_back(Common::FSNode(pluginsPath));
00169 
00170     Common::FSList::const_iterator dir;
00171     for (dir = pluginDirs.begin(); dir != pluginDirs.end(); ++dir) {
00172         // Load all plugins.
00173         // Scan for all plugins in this directory
00174         Common::FSList files;
00175         if (!dir->getChildren(files, Common::FSNode::kListFilesOnly)) {
00176             debug(1, "Couldn't open plugin directory '%s'", dir->getPath().c_str());
00177             continue;
00178         } else {
00179             debug(1, "Reading plugins from plugin directory '%s'", dir->getPath().c_str());
00180         }
00181 
00182         for (Common::FSList::const_iterator i = files.begin(); i != files.end(); ++i) {
00183             if (isPluginFilename(*i)) {
00184                 pl.push_back(createPlugin(*i));
00185             }
00186         }
00187     }
00188 
00189     return pl;
00190 }
00191 
00192 bool FilePluginProvider::isPluginFilename(const Common::FSNode &node) const {
00193     Common::String filename = node.getName();
00194 
00195 #ifdef PLUGIN_PREFIX
00196     // Check the plugin prefix
00197     if (!filename.hasPrefix(PLUGIN_PREFIX))
00198         return false;
00199 #endif
00200 
00201 #ifdef PLUGIN_SUFFIX
00202     // Check the plugin suffix
00203     if (!filename.hasSuffix(PLUGIN_SUFFIX))
00204         return false;
00205 #endif
00206 
00207     return true;
00208 }
00209 
00210 void FilePluginProvider::addCustomDirectories(Common::FSList &dirs) const {
00211 #ifdef PLUGIN_DIRECTORY
00212     dirs.push_back(Common::FSNode(PLUGIN_DIRECTORY));
00213 #endif
00214 }
00215 
00216 #endif // DYNAMIC_MODULES
00217 
00218 #pragma mark -
00219 
00220 PluginManager *PluginManager::_instance = NULL;
00221 
00222 PluginManager &PluginManager::instance() {
00223     if (_instance)
00224         return *_instance;
00225 
00226 #if defined(UNCACHED_PLUGINS) && defined(DYNAMIC_MODULES)
00227         _instance = new PluginManagerUncached();
00228 #else
00229         _instance = new PluginManager();
00230 #endif
00231     return *_instance;
00232 }
00233 
00234 PluginManager::PluginManager() {
00235     // Always add the static plugin provider.
00236     addPluginProvider(new StaticPluginProvider());
00237 }
00238 
00239 PluginManager::~PluginManager() {
00240     // Explicitly unload all loaded plugins
00241     unloadAllPlugins();
00242 
00243     // Delete the plugin providers
00244     for (ProviderList::iterator pp = _providers.begin();
00245                                 pp != _providers.end();
00246                                 ++pp) {
00247         delete *pp;
00248     }
00249 }
00250 
00251 void PluginManager::addPluginProvider(PluginProvider *pp) {
00252     _providers.push_back(pp);
00253 }
00254 
00258 void PluginManagerUncached::init() {
00259     unloadAllPlugins();
00260     _allEnginePlugins.clear();
00261 
00262     unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); // empty the engine plugins
00263 
00264     for (ProviderList::iterator pp = _providers.begin();
00265                                 pp != _providers.end();
00266                                 ++pp) {
00267         PluginList pl((*pp)->getPlugins());
00268 
00269         for (PluginList::iterator p = pl.begin(); p != pl.end(); ++p) {
00270             // This is a 'hack' based on the assumption that we have no sound
00271             // file plugins. Currently this is the case. If it changes, we
00272             // should find a fast way of detecting whether a plugin is a
00273             // music or an engine plugin.
00274             if ((*pp)->isFilePluginProvider()) {
00275                 _allEnginePlugins.push_back(*p);
00276             } else if ((*p)->loadPlugin()) { // and this is the proper method
00277                 if ((*p)->getType() == PLUGIN_TYPE_ENGINE) {
00278                     (*p)->unloadPlugin();
00279                     _allEnginePlugins.push_back(*p);
00280                 } else {    // add non-engine plugins to the 'in-memory' list
00281                             // these won't ever get unloaded
00282                     addToPluginsInMemList(*p);
00283                 }
00284             }
00285         }
00286     }
00287 }
00288 
00293 bool PluginManagerUncached::loadPluginFromEngineId(const Common::String &engineId) {
00294     Common::ConfigManager::Domain *domain = ConfMan.getDomain("engine_plugin_files");
00295 
00296     if (domain) {
00297         if (domain->contains(engineId)) {
00298             Common::String filename = (*domain)[engineId];
00299 
00300             if (loadPluginByFileName(filename)) {
00301                 return true;
00302             }
00303         }
00304     }
00305     return false;
00306 }
00307 
00311 bool PluginManagerUncached::loadPluginByFileName(const Common::String &filename) {
00312     if (filename.empty())
00313         return false;
00314 
00315     unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
00316 
00317     PluginList::iterator i;
00318     for (i = _allEnginePlugins.begin(); i != _allEnginePlugins.end(); ++i) {
00319         if (Common::String((*i)->getFileName()) == filename && (*i)->loadPlugin()) {
00320             addToPluginsInMemList(*i);
00321             _currentPlugin = i;
00322             return true;
00323         }
00324     }
00325     return false;
00326 }
00327 
00332 void PluginManagerUncached::updateConfigWithFileName(const Common::String &engineId) {
00333     // Check if we have a filename for the current plugin
00334     if ((*_currentPlugin)->getFileName()) {
00335         if (!ConfMan.hasMiscDomain("engine_plugin_files"))
00336             ConfMan.addMiscDomain("engine_plugin_files");
00337 
00338         Common::ConfigManager::Domain *domain = ConfMan.getDomain("engine_plugin_files");
00339         assert(domain);
00340         (*domain)[engineId] = (*_currentPlugin)->getFileName();
00341 
00342         ConfMan.flushToDisk();
00343     }
00344 }
00345 
00346 void PluginManagerUncached::loadFirstPlugin() {
00347     unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
00348 
00349     // let's try to find one we can load
00350     for (_currentPlugin = _allEnginePlugins.begin(); _currentPlugin != _allEnginePlugins.end(); ++_currentPlugin) {
00351         if ((*_currentPlugin)->loadPlugin()) {
00352             addToPluginsInMemList(*_currentPlugin);
00353             break;
00354         }
00355     }
00356 }
00357 
00358 bool PluginManagerUncached::loadNextPlugin() {
00359     unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
00360 
00361     for (++_currentPlugin; _currentPlugin != _allEnginePlugins.end(); ++_currentPlugin) {
00362         if ((*_currentPlugin)->loadPlugin()) {
00363             addToPluginsInMemList(*_currentPlugin);
00364             return true;
00365         }
00366     }
00367     return false; // no more in list
00368 }
00369 
00374 void PluginManager::loadAllPlugins() {
00375     for (ProviderList::iterator pp = _providers.begin();
00376                                 pp != _providers.end();
00377                                 ++pp) {
00378         PluginList pl((*pp)->getPlugins());
00379         Common::for_each(pl.begin(), pl.end(), Common::bind1st(Common::mem_fun(&PluginManager::tryLoadPlugin), this));
00380     }
00381 }
00382 
00383 void PluginManager::loadAllPluginsOfType(PluginType type) {
00384     for (ProviderList::iterator pp = _providers.begin();
00385                                 pp != _providers.end();
00386                                 ++pp) {
00387         PluginList pl((*pp)->getPlugins());
00388         for (PluginList::iterator p = pl.begin();
00389                                   p != pl.end();
00390                                   ++p) {
00391             if ((*p)->loadPlugin()) {
00392                 if ((*p)->getType() == type) {
00393                     addToPluginsInMemList((*p));
00394                 } else {
00395                     // Plugin is wrong type
00396                     (*p)->unloadPlugin();
00397                     delete (*p);
00398                 }
00399             } else {
00400                 // Plugin did not load
00401                 delete (*p);
00402             }
00403         }
00404     }
00405 }
00406 
00407 void PluginManager::unloadAllPlugins() {
00408     for (int i = 0; i < PLUGIN_TYPE_MAX; i++)
00409         unloadPluginsExcept((PluginType)i, NULL);
00410 }
00411 
00412 void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin, bool deletePlugin /*=true*/) {
00413     Plugin *found = NULL;
00414     for (PluginList::iterator p = _pluginsInMem[type].begin(); p != _pluginsInMem[type].end(); ++p) {
00415         if (*p == plugin) {
00416             found = *p;
00417         } else {
00418             (*p)->unloadPlugin();
00419             if (deletePlugin)
00420                 delete *p;
00421         }
00422     }
00423     _pluginsInMem[type].clear();
00424     if (found != NULL) {
00425         _pluginsInMem[type].push_back(found);
00426     }
00427 }
00428 
00429 /*
00430  * Used only by the cached plugin manager since it deletes the plugin.
00431  */
00432 bool PluginManager::tryLoadPlugin(Plugin *plugin) {
00433     assert(plugin);
00434     // Try to load the plugin
00435     if (plugin->loadPlugin()) {
00436         addToPluginsInMemList(plugin);
00437         return true;
00438     } else {
00439         // Failed to load the plugin
00440         delete plugin;
00441         return false;
00442     }
00443 }
00444 
00448 void PluginManager::addToPluginsInMemList(Plugin *plugin) {
00449     bool found = false;
00450     // The plugin is valid, see if it provides the same module as an
00451     // already loaded one and should replace it.
00452 
00453     PluginList::iterator pl = _pluginsInMem[plugin->getType()].begin();
00454     while (!found && pl != _pluginsInMem[plugin->getType()].end()) {
00455         if (!strcmp(plugin->getName(), (*pl)->getName())) {
00456             // Found a duplicated module. Replace the old one.
00457             found = true;
00458             delete *pl;
00459             *pl = plugin;
00460             debug(1, "Replaced the duplicated plugin: '%s'", plugin->getName());
00461         }
00462         pl++;
00463     }
00464 
00465     if (!found) {
00466         // If it provides a new module, just add it to the list of known plugins in memory.
00467         _pluginsInMem[plugin->getType()].push_back(plugin);
00468     }
00469 }
00470 
00471 // Engine plugins
00472 
00473 #include "engines/metaengine.h"
00474 
00475 namespace Common {
00476 DECLARE_SINGLETON(EngineManager);
00477 }
00478 
00486 QualifiedGameList EngineManager::findGamesMatching(const Common::String &engineId, const Common::String &gameId) const {
00487     QualifiedGameList results;
00488 
00489     if (!engineId.empty()) {
00490         // If we got an engine name, look for THE game only in that engine
00491         const Plugin *p = EngineMan.findPlugin(engineId);
00492         if (p) {
00493             const MetaEngine &engine = p->get<MetaEngine>();
00494 
00495             PlainGameDescriptor pluginResult = engine.findGame(gameId.c_str());
00496             if (pluginResult.gameId) {
00497                 results.push_back(QualifiedGameDescriptor(engine.getEngineId(), pluginResult));
00498             }
00499         }
00500     } else {
00501         // This is a slow path, we have to scan the list of plugins
00502         PluginMan.loadFirstPlugin();
00503         do {
00504             results.push_back(findGameInLoadedPlugins(gameId));
00505         } while (PluginMan.loadNextPlugin());
00506     }
00507 
00508     return results;
00509 }
00510 
00514 QualifiedGameList EngineManager::findGameInLoadedPlugins(const Common::String &gameId) const {
00515     // Find the GameDescriptor for this target
00516     const PluginList &plugins = getPlugins();
00517 
00518     QualifiedGameList results;
00519     PluginList::const_iterator iter;
00520 
00521     for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
00522         const MetaEngine &engine = (*iter)->get<MetaEngine>();
00523         PlainGameDescriptor pluginResult = engine.findGame(gameId.c_str());
00524 
00525         if (pluginResult.gameId) {
00526             results.push_back(QualifiedGameDescriptor(engine.getEngineId(), pluginResult));
00527         }
00528     }
00529 
00530     return results;
00531 }
00532 
00533 DetectionResults EngineManager::detectGames(const Common::FSList &fslist) const {
00534     DetectedGames candidates;
00535     PluginList plugins;
00536     PluginList::const_iterator iter;
00537     PluginManager::instance().loadFirstPlugin();
00538     do {
00539         plugins = getPlugins();
00540         // Iterate over all known games and for each check if it might be
00541         // the game in the presented directory.
00542         for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
00543             const MetaEngine &metaEngine = (*iter)->get<MetaEngine>();
00544             DetectedGames engineCandidates = metaEngine.detectGames(fslist);
00545 
00546             for (uint i = 0; i < engineCandidates.size(); i++) {
00547                 engineCandidates[i].path = fslist.begin()->getParent().getPath();
00548                 engineCandidates[i].shortPath = fslist.begin()->getParent().getDisplayName();
00549                 candidates.push_back(engineCandidates[i]);
00550             }
00551 
00552         }
00553     } while (PluginManager::instance().loadNextPlugin());
00554 
00555     return DetectionResults(candidates);
00556 }
00557 
00558 const PluginList &EngineManager::getPlugins() const {
00559     return PluginManager::instance().getPlugins(PLUGIN_TYPE_ENGINE);
00560 }
00561 
00562 namespace {
00563 
00564 void addStringToConf(const Common::String &key, const Common::String &value, const Common::String &domain) {
00565     if (!value.empty())
00566         ConfMan.set(key, value, domain);
00567 }
00568 
00569 } // End of anonymous namespace
00570 
00571 Common::String EngineManager::createTargetForGame(const DetectedGame &game) {
00572     // The auto detector or the user made a choice.
00573     // Pick a domain name which does not yet exist (after all, we
00574     // are *adding* a game to the config, not replacing).
00575     Common::String domain = game.preferredTarget;
00576 
00577     assert(!domain.empty());
00578     if (ConfMan.hasGameDomain(domain)) {
00579         int suffixN = 1;
00580         Common::String gameid(domain);
00581 
00582         while (ConfMan.hasGameDomain(domain)) {
00583             domain = gameid + Common::String::format("-%d", suffixN);
00584             suffixN++;
00585         }
00586     }
00587 
00588     // Add the name domain
00589     ConfMan.addGameDomain(domain);
00590 
00591     // Copy all non-empty relevant values into the new domain
00592     addStringToConf("engineid", game.engineId, domain);
00593     addStringToConf("gameid", game.gameId, domain);
00594     addStringToConf("description", game.description, domain);
00595     addStringToConf("language", Common::getLanguageCode(game.language), domain);
00596     addStringToConf("platform", Common::getPlatformCode(game.platform), domain);
00597     addStringToConf("path", game.path, domain);
00598     addStringToConf("extra", game.extra, domain);
00599     addStringToConf("guioptions", game.getGUIOptions(), domain);
00600 
00601     // Add any extra configuration keys
00602     for (Common::StringMap::iterator i = game._extraConfigEntries.begin();
00603             i != game._extraConfigEntries.end(); ++i)
00604         addStringToConf((*i)._key, (*i)._value, domain);
00605 
00606     // TODO: Setting the description field here has the drawback
00607     // that the user does never notice when we upgrade our descriptions.
00608     // It might be nice to leave this field empty, and only set it to
00609     // a value when the user edits the description string.
00610     // However, at this point, that's impractical. Once we have a method
00611     // to query all backends for the proper & full description of a given
00612     // game target, we can change this (currently, you can only query
00613     // for the generic gameid description; it's not possible to obtain
00614     // a description which contains extended information like language, etc.).
00615 
00616     return domain;
00617 }
00618 
00619 const Plugin *EngineManager::findLoadedPlugin(const Common::String &engineId) const {
00620     const PluginList &plugins = getPlugins();
00621 
00622     for (PluginList::const_iterator iter = plugins.begin(); iter != plugins.end(); iter++)
00623         if (engineId == (*iter)->get<MetaEngine>().getEngineId())
00624             return *iter;
00625 
00626     return 0;
00627 }
00628 
00629 const Plugin *EngineManager::findPlugin(const Common::String &engineId) const {
00630     // First look for the game using the plugins in memory. This is critical
00631     // for calls coming from inside games
00632     const Plugin *plugin = findLoadedPlugin(engineId);
00633     if (plugin)
00634         return plugin;
00635 
00636     // Now look for the plugin using the engine ID. This is much faster than scanning plugin
00637     // by plugin
00638     if (PluginMan.loadPluginFromEngineId(engineId))  {
00639         plugin = findLoadedPlugin(engineId);
00640         if (plugin)
00641             return plugin;
00642     }
00643 
00644     // We failed to find it using the engine ID. Scan the list of plugins
00645     const PluginList &plugins = getPlugins();
00646     if (!plugins.empty()) {
00647         PluginMan.loadFirstPlugin();
00648         do {
00649             plugin = findLoadedPlugin(engineId);
00650             if (plugin) {
00651                 // Update with new plugin file name
00652                 PluginMan.updateConfigWithFileName(engineId);
00653                 return plugin;
00654             }
00655         } while (PluginMan.loadNextPlugin());
00656     }
00657 
00658     return 0;
00659 }
00660 
00661 QualifiedGameDescriptor EngineManager::findTarget(const Common::String &target, const Plugin **plugin) const {
00662     // Ignore empty targets
00663     if (target.empty())
00664         return QualifiedGameDescriptor();
00665 
00666     // Lookup the domain. If we have no domain, fallback on the old function [ultra-deprecated].
00667     const Common::ConfigManager::Domain *domain = ConfMan.getDomain(target);
00668     if (!domain || !domain->contains("gameid") || !domain->contains("engineid"))
00669         return QualifiedGameDescriptor();
00670 
00671     // Look for the engine ID
00672     const Plugin *foundPlugin = findPlugin(domain->getVal("engineid"));
00673     if (!foundPlugin) {
00674         return QualifiedGameDescriptor();
00675     }
00676 
00677     // Make sure it does support the game ID
00678     const MetaEngine &engine = foundPlugin->get<MetaEngine>();
00679     PlainGameDescriptor desc = engine.findGame(domain->getVal("gameid").c_str());
00680     if (!desc.gameId) {
00681         return QualifiedGameDescriptor();
00682     }
00683 
00684     if (plugin)
00685         *plugin = foundPlugin;
00686 
00687     return QualifiedGameDescriptor(engine.getEngineId(), desc);
00688 }
00689 
00690 void EngineManager::upgradeTargetIfNecessary(const Common::String &target) const {
00691     Common::ConfigManager::Domain *domain = ConfMan.getDomain(target);
00692     assert(domain);
00693 
00694     if (!domain->contains("engineid")) {
00695         upgradeTargetForEngineId(target);
00696     }
00697 }
00698 
00699 void EngineManager::upgradeTargetForEngineId(const Common::String &target) const {
00700     Common::ConfigManager::Domain *domain = ConfMan.getDomain(target);
00701     assert(domain);
00702 
00703     debug("Target '%s' lacks an engine ID, upgrading...", target.c_str());
00704 
00705     Common::String oldGameId = domain->getVal("gameid");
00706     Common::String path = domain->getVal("path");
00707 
00708     // At this point the game ID and game path must be known
00709     if (oldGameId.empty()) {
00710         warning("The game ID is required to upgrade target '%s'", target.c_str());
00711         return;
00712     }
00713     if (path.empty()) {
00714         warning("The game path is required to upgrade target '%s'", target.c_str());
00715         return;
00716     }
00717 
00718     // Game descriptor for the upgraded target
00719     Common::String engineId;
00720     Common::String newGameId;
00721 
00722     // First, try to update entries for engines that previously used the "single id" system
00723     // Search for an engine whose ID is the game ID
00724     const Plugin *plugin = findPlugin(oldGameId);
00725     if (plugin) {
00726         // Run detection on the game path
00727         Common::FSNode dir(path);
00728         Common::FSList files;
00729         if (!dir.getChildren(files, Common::FSNode::kListAll)) {
00730             warning("Failed to access path '%s' when upgrading target '%s'", path.c_str(), target.c_str());
00731             return;
00732         }
00733 
00734         // Take the first detection entry
00735         const MetaEngine &metaEngine = plugin->get<MetaEngine>();
00736         DetectedGames candidates = metaEngine.detectGames(files);
00737         if (candidates.empty()) {
00738             warning("No games supported by the engine '%s' were found in path '%s' when upgrading target '%s'",
00739                     metaEngine.getEngineId(), path.c_str(), target.c_str());
00740             return;
00741         }
00742 
00743         engineId = candidates[0].engineId;
00744         newGameId = candidates[0].gameId;
00745     }
00746 
00747     // Next, try to find an engine with the game ID in its supported games list
00748     if (engineId.empty()) {
00749         QualifiedGameList candidates = findGamesMatching("", oldGameId);
00750         if (candidates.size() > 1) {
00751             warning("Multiple matching engines were found when upgrading target '%s'", target.c_str());
00752             return;
00753         } else if (!candidates.empty()) {
00754             engineId = candidates[0].engineId;
00755             newGameId = candidates[0].gameId;
00756         }
00757     }
00758 
00759     if (engineId.empty() || newGameId.empty()) {
00760         warning("No matching engine was found when upgrading target '%s'", target.c_str());
00761         return;
00762     }
00763 
00764     domain->setVal("engineid", engineId);
00765     domain->setVal("gameid", newGameId);
00766 
00767     // Save a backup of the pre-upgrade gameId to the config file
00768     if (newGameId != oldGameId) {
00769         domain->setVal("oldgameid", oldGameId);
00770     }
00771 
00772     debug("Upgrade complete (engine ID '%s', game ID '%s')", engineId.c_str(), newGameId.c_str());
00773 
00774     ConfMan.flushToDisk();
00775 }
00776 
00777 // Music plugins
00778 
00779 #include "audio/musicplugin.h"
00780 
00781 namespace Common {
00782 DECLARE_SINGLETON(MusicManager);
00783 }
00784 
00785 const PluginList &MusicManager::getPlugins() const {
00786     return PluginManager::instance().getPlugins(PLUGIN_TYPE_MUSIC);
00787 }


Generated on Sat Dec 14 2019 05:00:31 for ResidualVM by doxygen 1.7.1
curved edge   curved edge