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(__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         #endif
00121         #ifdef USE_FLUIDSYNTH
00122         LINK_PLUGIN(FLUIDSYNTH)
00123         #endif
00124         #ifdef USE_MT32EMU
00125         LINK_PLUGIN(MT32)
00126         #endif
00127         #if defined(__ANDROID__)
00128         LINK_PLUGIN(EAS)
00129         #endif
00130         LINK_PLUGIN(ADLIB)
00131         LINK_PLUGIN(PCSPK)
00132         LINK_PLUGIN(PCJR)
00133         LINK_PLUGIN(CMS)
00134         #ifndef DISABLE_SID
00135         LINK_PLUGIN(C64)
00136         #endif
00137         LINK_PLUGIN(AMIGA)
00138         LINK_PLUGIN(APPLEIIGS)
00139         LINK_PLUGIN(TOWNS)
00140         LINK_PLUGIN(PC98)
00141         #if defined(USE_TIMIDITY)
00142         LINK_PLUGIN(TIMIDITY)
00143         #endif
00144         #if defined(MACOSX)
00145         // Keep this at the end of the list - it takes a long time to enumerate
00146         // and is only for hardware midi devices
00147         LINK_PLUGIN(COREMIDI)
00148         #endif*/
00149 
00150         return pl;
00151     }
00152 };
00153 
00154 #ifdef DYNAMIC_MODULES
00155 
00156 PluginList FilePluginProvider::getPlugins() {
00157     PluginList pl;
00158 
00159     // Prepare the list of directories to search
00160     Common::FSList pluginDirs;
00161 
00162     // Add the default directories
00163     pluginDirs.push_back(Common::FSNode("."));
00164     pluginDirs.push_back(Common::FSNode("plugins"));
00165 
00166     // Add the provider's custom directories
00167     addCustomDirectories(pluginDirs);
00168 
00169     // Add the user specified directory
00170     Common::String pluginsPath(ConfMan.get("pluginspath"));
00171     if (!pluginsPath.empty())
00172         pluginDirs.push_back(Common::FSNode(pluginsPath));
00173 
00174     Common::FSList::const_iterator dir;
00175     for (dir = pluginDirs.begin(); dir != pluginDirs.end(); ++dir) {
00176         // Load all plugins.
00177         // Scan for all plugins in this directory
00178         Common::FSList files;
00179         if (!dir->getChildren(files, Common::FSNode::kListFilesOnly)) {
00180             debug(1, "Couldn't open plugin directory '%s'", dir->getPath().c_str());
00181             continue;
00182         } else {
00183             debug(1, "Reading plugins from plugin directory '%s'", dir->getPath().c_str());
00184         }
00185 
00186         for (Common::FSList::const_iterator i = files.begin(); i != files.end(); ++i) {
00187             if (isPluginFilename(*i)) {
00188                 pl.push_back(createPlugin(*i));
00189             }
00190         }
00191     }
00192 
00193     return pl;
00194 }
00195 
00196 bool FilePluginProvider::isPluginFilename(const Common::FSNode &node) const {
00197     Common::String filename = node.getName();
00198 
00199 #ifdef PLUGIN_PREFIX
00200     // Check the plugin prefix
00201     if (!filename.hasPrefix(PLUGIN_PREFIX))
00202         return false;
00203 #endif
00204 
00205 #ifdef PLUGIN_SUFFIX
00206     // Check the plugin suffix
00207     if (!filename.hasSuffix(PLUGIN_SUFFIX))
00208         return false;
00209 #endif
00210 
00211     return true;
00212 }
00213 
00214 void FilePluginProvider::addCustomDirectories(Common::FSList &dirs) const {
00215 #ifdef PLUGIN_DIRECTORY
00216     dirs.push_back(Common::FSNode(PLUGIN_DIRECTORY));
00217 #endif
00218 }
00219 
00220 #endif // DYNAMIC_MODULES
00221 
00222 #pragma mark -
00223 
00224 PluginManager *PluginManager::_instance = NULL;
00225 
00226 PluginManager &PluginManager::instance() {
00227     if (_instance)
00228         return *_instance;
00229 
00230 #if defined(UNCACHED_PLUGINS) && defined(DYNAMIC_MODULES)
00231         _instance = new PluginManagerUncached();
00232 #else
00233         _instance = new PluginManager();
00234 #endif
00235     return *_instance;
00236 }
00237 
00238 PluginManager::PluginManager() {
00239     // Always add the static plugin provider.
00240     addPluginProvider(new StaticPluginProvider());
00241 }
00242 
00243 PluginManager::~PluginManager() {
00244     // Explicitly unload all loaded plugins
00245     unloadAllPlugins();
00246 
00247     // Delete the plugin providers
00248     for (ProviderList::iterator pp = _providers.begin();
00249                                 pp != _providers.end();
00250                                 ++pp) {
00251         delete *pp;
00252     }
00253 }
00254 
00255 void PluginManager::addPluginProvider(PluginProvider *pp) {
00256     _providers.push_back(pp);
00257 }
00258 
00262 void PluginManagerUncached::init() {
00263     unloadAllPlugins();
00264     _allEnginePlugins.clear();
00265 
00266     unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); // empty the engine plugins
00267 
00268     for (ProviderList::iterator pp = _providers.begin();
00269                                 pp != _providers.end();
00270                                 ++pp) {
00271         PluginList pl((*pp)->getPlugins());
00272 
00273         for (PluginList::iterator p = pl.begin(); p != pl.end(); ++p) {
00274             // This is a 'hack' based on the assumption that we have no sound
00275             // file plugins. Currently this is the case. If it changes, we
00276             // should find a fast way of detecting whether a plugin is a
00277             // music or an engine plugin.
00278             if ((*pp)->isFilePluginProvider()) {
00279                 _allEnginePlugins.push_back(*p);
00280             } else if ((*p)->loadPlugin()) { // and this is the proper method
00281                 if ((*p)->getType() == PLUGIN_TYPE_ENGINE) {
00282                     (*p)->unloadPlugin();
00283                     _allEnginePlugins.push_back(*p);
00284                 } else {    // add non-engine plugins to the 'in-memory' list
00285                             // these won't ever get unloaded
00286                     addToPluginsInMemList(*p);
00287                 }
00288             }
00289         }
00290     }
00291 }
00292 
00297 bool PluginManagerUncached::loadPluginFromEngineId(const Common::String &engineId) {
00298     Common::ConfigManager::Domain *domain = ConfMan.getDomain("engine_plugin_files");
00299 
00300     if (domain) {
00301         if (domain->contains(engineId)) {
00302             Common::String filename = (*domain)[engineId];
00303 
00304             if (loadPluginByFileName(filename)) {
00305                 return true;
00306             }
00307         }
00308     }
00309     return false;
00310 }
00311 
00315 bool PluginManagerUncached::loadPluginByFileName(const Common::String &filename) {
00316     if (filename.empty())
00317         return false;
00318 
00319     unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
00320 
00321     PluginList::iterator i;
00322     for (i = _allEnginePlugins.begin(); i != _allEnginePlugins.end(); ++i) {
00323         if (Common::String((*i)->getFileName()) == filename && (*i)->loadPlugin()) {
00324             addToPluginsInMemList(*i);
00325             _currentPlugin = i;
00326             return true;
00327         }
00328     }
00329     return false;
00330 }
00331 
00336 void PluginManagerUncached::updateConfigWithFileName(const Common::String &engineId) {
00337     // Check if we have a filename for the current plugin
00338     if ((*_currentPlugin)->getFileName()) {
00339         if (!ConfMan.hasMiscDomain("engine_plugin_files"))
00340             ConfMan.addMiscDomain("engine_plugin_files");
00341 
00342         Common::ConfigManager::Domain *domain = ConfMan.getDomain("engine_plugin_files");
00343         assert(domain);
00344         (*domain)[engineId] = (*_currentPlugin)->getFileName();
00345 
00346         ConfMan.flushToDisk();
00347     }
00348 }
00349 
00350 void PluginManagerUncached::loadFirstPlugin() {
00351     unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
00352 
00353     // let's try to find one we can load
00354     for (_currentPlugin = _allEnginePlugins.begin(); _currentPlugin != _allEnginePlugins.end(); ++_currentPlugin) {
00355         if ((*_currentPlugin)->loadPlugin()) {
00356             addToPluginsInMemList(*_currentPlugin);
00357             break;
00358         }
00359     }
00360 }
00361 
00362 bool PluginManagerUncached::loadNextPlugin() {
00363     unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
00364 
00365     if (!_currentPlugin)
00366         return false;
00367 
00368     for (++_currentPlugin; _currentPlugin != _allEnginePlugins.end(); ++_currentPlugin) {
00369         if ((*_currentPlugin)->loadPlugin()) {
00370             addToPluginsInMemList(*_currentPlugin);
00371             return true;
00372         }
00373     }
00374     return false; // no more in list
00375 }
00376 
00381 void PluginManager::loadAllPlugins() {
00382     for (ProviderList::iterator pp = _providers.begin();
00383                                 pp != _providers.end();
00384                                 ++pp) {
00385         PluginList pl((*pp)->getPlugins());
00386         Common::for_each(pl.begin(), pl.end(), Common::bind1st(Common::mem_fun(&PluginManager::tryLoadPlugin), this));
00387     }
00388 }
00389 
00390 void PluginManager::loadAllPluginsOfType(PluginType type) {
00391     for (ProviderList::iterator pp = _providers.begin();
00392                                 pp != _providers.end();
00393                                 ++pp) {
00394         PluginList pl((*pp)->getPlugins());
00395         for (PluginList::iterator p = pl.begin();
00396                                   p != pl.end();
00397                                   ++p) {
00398             if ((*p)->loadPlugin()) {
00399                 if ((*p)->getType() == type) {
00400                     addToPluginsInMemList((*p));
00401                 } else {
00402                     // Plugin is wrong type
00403                     (*p)->unloadPlugin();
00404                     delete (*p);
00405                 }
00406             } else {
00407                 // Plugin did not load
00408                 delete (*p);
00409             }
00410         }
00411     }
00412 }
00413 
00414 void PluginManager::unloadAllPlugins() {
00415     for (int i = 0; i < PLUGIN_TYPE_MAX; i++)
00416         unloadPluginsExcept((PluginType)i, NULL);
00417 }
00418 
00419 void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin, bool deletePlugin /*=true*/) {
00420     Plugin *found = NULL;
00421     for (PluginList::iterator p = _pluginsInMem[type].begin(); p != _pluginsInMem[type].end(); ++p) {
00422         if (*p == plugin) {
00423             found = *p;
00424         } else {
00425             (*p)->unloadPlugin();
00426             if (deletePlugin)
00427                 delete *p;
00428         }
00429     }
00430     _pluginsInMem[type].clear();
00431     if (found != NULL) {
00432         _pluginsInMem[type].push_back(found);
00433     }
00434 }
00435 
00436 /*
00437  * Used only by the cached plugin manager since it deletes the plugin.
00438  */
00439 bool PluginManager::tryLoadPlugin(Plugin *plugin) {
00440     assert(plugin);
00441     // Try to load the plugin
00442     if (plugin->loadPlugin()) {
00443         addToPluginsInMemList(plugin);
00444         return true;
00445     } else {
00446         // Failed to load the plugin
00447         delete plugin;
00448         return false;
00449     }
00450 }
00451 
00455 void PluginManager::addToPluginsInMemList(Plugin *plugin) {
00456     bool found = false;
00457     // The plugin is valid, see if it provides the same module as an
00458     // already loaded one and should replace it.
00459 
00460     PluginList::iterator pl = _pluginsInMem[plugin->getType()].begin();
00461     while (!found && pl != _pluginsInMem[plugin->getType()].end()) {
00462         if (!strcmp(plugin->getName(), (*pl)->getName())) {
00463             // Found a duplicated module. Replace the old one.
00464             found = true;
00465             delete *pl;
00466             *pl = plugin;
00467             debug(1, "Replaced the duplicated plugin: '%s'", plugin->getName());
00468         }
00469         pl++;
00470     }
00471 
00472     if (!found) {
00473         // If it provides a new module, just add it to the list of known plugins in memory.
00474         _pluginsInMem[plugin->getType()].push_back(plugin);
00475     }
00476 }
00477 
00478 // Engine plugins
00479 
00480 #include "engines/metaengine.h"
00481 
00482 namespace Common {
00483 DECLARE_SINGLETON(EngineManager);
00484 }
00485 
00493 QualifiedGameList EngineManager::findGamesMatching(const Common::String &engineId, const Common::String &gameId) const {
00494     QualifiedGameList results;
00495 
00496     if (!engineId.empty()) {
00497         // If we got an engine name, look for THE game only in that engine
00498         const Plugin *p = EngineMan.findPlugin(engineId);
00499         if (p) {
00500             const MetaEngine &engine = p->get<MetaEngine>();
00501 
00502             PlainGameDescriptor pluginResult = engine.findGame(gameId.c_str());
00503             if (pluginResult.gameId) {
00504                 results.push_back(QualifiedGameDescriptor(engine.getEngineId(), pluginResult));
00505             }
00506         }
00507     } else {
00508         // This is a slow path, we have to scan the list of plugins
00509         PluginMan.loadFirstPlugin();
00510         do {
00511             results.push_back(findGameInLoadedPlugins(gameId));
00512         } while (PluginMan.loadNextPlugin());
00513     }
00514 
00515     return results;
00516 }
00517 
00521 QualifiedGameList EngineManager::findGameInLoadedPlugins(const Common::String &gameId) const {
00522     // Find the GameDescriptor for this target
00523     const PluginList &plugins = getPlugins();
00524 
00525     QualifiedGameList results;
00526     PluginList::const_iterator iter;
00527 
00528     for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
00529         const MetaEngine &engine = (*iter)->get<MetaEngine>();
00530         PlainGameDescriptor pluginResult = engine.findGame(gameId.c_str());
00531 
00532         if (pluginResult.gameId) {
00533             results.push_back(QualifiedGameDescriptor(engine.getEngineId(), pluginResult));
00534         }
00535     }
00536 
00537     return results;
00538 }
00539 
00540 DetectionResults EngineManager::detectGames(const Common::FSList &fslist) const {
00541     DetectedGames candidates;
00542     PluginList plugins;
00543     PluginList::const_iterator iter;
00544     PluginMan.loadFirstPlugin();
00545     do {
00546         plugins = getPlugins();
00547         // Iterate over all known games and for each check if it might be
00548         // the game in the presented directory.
00549         for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
00550             const MetaEngine &metaEngine = (*iter)->get<MetaEngine>();
00551             DetectedGames engineCandidates = metaEngine.detectGames(fslist);
00552 
00553             for (uint i = 0; i < engineCandidates.size(); i++) {
00554                 engineCandidates[i].path = fslist.begin()->getParent().getPath();
00555                 engineCandidates[i].shortPath = fslist.begin()->getParent().getDisplayName();
00556                 candidates.push_back(engineCandidates[i]);
00557             }
00558 
00559         }
00560     } while (PluginMan.loadNextPlugin());
00561 
00562     return DetectionResults(candidates);
00563 }
00564 
00565 const PluginList &EngineManager::getPlugins() const {
00566     return PluginManager::instance().getPlugins(PLUGIN_TYPE_ENGINE);
00567 }
00568 
00569 namespace {
00570 
00571 void addStringToConf(const Common::String &key, const Common::String &value, const Common::String &domain) {
00572     if (!value.empty())
00573         ConfMan.set(key, value, domain);
00574 }
00575 
00576 } // End of anonymous namespace
00577 
00578 Common::String EngineManager::createTargetForGame(const DetectedGame &game) {
00579     // The auto detector or the user made a choice.
00580     // Pick a domain name which does not yet exist (after all, we
00581     // are *adding* a game to the config, not replacing).
00582     Common::String domain = game.preferredTarget;
00583 
00584     assert(!domain.empty());
00585     if (ConfMan.hasGameDomain(domain)) {
00586         int suffixN = 1;
00587         Common::String gameid(domain);
00588 
00589         while (ConfMan.hasGameDomain(domain)) {
00590             domain = gameid + Common::String::format("-%d", suffixN);
00591             suffixN++;
00592         }
00593     }
00594 
00595     // Add the name domain
00596     ConfMan.addGameDomain(domain);
00597 
00598     // Copy all non-empty relevant values into the new domain
00599     addStringToConf("engineid", game.engineId, domain);
00600     addStringToConf("gameid", game.gameId, domain);
00601     addStringToConf("description", game.description, domain);
00602     addStringToConf("language", Common::getLanguageCode(game.language), domain);
00603     addStringToConf("platform", Common::getPlatformCode(game.platform), domain);
00604     addStringToConf("path", game.path, domain);
00605     addStringToConf("extra", game.extra, domain);
00606     addStringToConf("guioptions", game.getGUIOptions(), domain);
00607 
00608     // Add any extra configuration keys
00609     for (Common::StringMap::iterator i = game._extraConfigEntries.begin();
00610             i != game._extraConfigEntries.end(); ++i)
00611         addStringToConf((*i)._key, (*i)._value, domain);
00612 
00613     // TODO: Setting the description field here has the drawback
00614     // that the user does never notice when we upgrade our descriptions.
00615     // It might be nice to leave this field empty, and only set it to
00616     // a value when the user edits the description string.
00617     // However, at this point, that's impractical. Once we have a method
00618     // to query all backends for the proper & full description of a given
00619     // game target, we can change this (currently, you can only query
00620     // for the generic gameid description; it's not possible to obtain
00621     // a description which contains extended information like language, etc.).
00622 
00623     return domain;
00624 }
00625 
00626 const Plugin *EngineManager::findLoadedPlugin(const Common::String &engineId) const {
00627     const PluginList &plugins = getPlugins();
00628 
00629     for (PluginList::const_iterator iter = plugins.begin(); iter != plugins.end(); iter++)
00630         if (engineId == (*iter)->get<MetaEngine>().getEngineId())
00631             return *iter;
00632 
00633     return 0;
00634 }
00635 
00636 const Plugin *EngineManager::findPlugin(const Common::String &engineId) const {
00637     // First look for the game using the plugins in memory. This is critical
00638     // for calls coming from inside games
00639     const Plugin *plugin = findLoadedPlugin(engineId);
00640     if (plugin)
00641         return plugin;
00642 
00643     // Now look for the plugin using the engine ID. This is much faster than scanning plugin
00644     // by plugin
00645     if (PluginMan.loadPluginFromEngineId(engineId))  {
00646         plugin = findLoadedPlugin(engineId);
00647         if (plugin)
00648             return plugin;
00649     }
00650 
00651     // We failed to find it using the engine ID. Scan the list of plugins
00652     PluginMan.loadFirstPlugin();
00653     do {
00654         plugin = findLoadedPlugin(engineId);
00655         if (plugin) {
00656             // Update with new plugin file name
00657             PluginMan.updateConfigWithFileName(engineId);
00658             return plugin;
00659         }
00660     } while (PluginMan.loadNextPlugin());
00661 
00662     return 0;
00663 }
00664 
00665 QualifiedGameDescriptor EngineManager::findTarget(const Common::String &target, const Plugin **plugin) const {
00666     // Ignore empty targets
00667     if (target.empty())
00668         return QualifiedGameDescriptor();
00669 
00670     // Lookup the domain. If we have no domain, fallback on the old function [ultra-deprecated].
00671     const Common::ConfigManager::Domain *domain = ConfMan.getDomain(target);
00672     if (!domain || !domain->contains("gameid") || !domain->contains("engineid"))
00673         return QualifiedGameDescriptor();
00674 
00675     // Look for the engine ID
00676     const Plugin *foundPlugin = findPlugin(domain->getVal("engineid"));
00677     if (!foundPlugin) {
00678         return QualifiedGameDescriptor();
00679     }
00680 
00681     // Make sure it does support the game ID
00682     const MetaEngine &engine = foundPlugin->get<MetaEngine>();
00683     PlainGameDescriptor desc = engine.findGame(domain->getVal("gameid").c_str());
00684     if (!desc.gameId) {
00685         return QualifiedGameDescriptor();
00686     }
00687 
00688     if (plugin)
00689         *plugin = foundPlugin;
00690 
00691     return QualifiedGameDescriptor(engine.getEngineId(), desc);
00692 }
00693 
00694 void EngineManager::upgradeTargetIfNecessary(const Common::String &target) const {
00695     Common::ConfigManager::Domain *domain = ConfMan.getDomain(target);
00696     assert(domain);
00697 
00698     if (!domain->contains("engineid")) {
00699         upgradeTargetForEngineId(target);
00700     }
00701 }
00702 
00703 void EngineManager::upgradeTargetForEngineId(const Common::String &target) const {
00704     Common::ConfigManager::Domain *domain = ConfMan.getDomain(target);
00705     assert(domain);
00706 
00707     debug("Target '%s' lacks an engine ID, upgrading...", target.c_str());
00708 
00709     Common::String oldGameId = domain->getVal("gameid");
00710     Common::String path = domain->getVal("path");
00711 
00712     // At this point the game ID and game path must be known
00713     if (oldGameId.empty()) {
00714         warning("The game ID is required to upgrade target '%s'", target.c_str());
00715         return;
00716     }
00717     if (path.empty()) {
00718         warning("The game path is required to upgrade target '%s'", target.c_str());
00719         return;
00720     }
00721 
00722     // Game descriptor for the upgraded target
00723     Common::String engineId;
00724     Common::String newGameId;
00725 
00726     // First, try to update entries for engines that previously used the "single id" system
00727     // Search for an engine whose ID is the game ID
00728     const Plugin *plugin = findPlugin(oldGameId);
00729     if (plugin) {
00730         // Run detection on the game path
00731         Common::FSNode dir(path);
00732         Common::FSList files;
00733         if (!dir.getChildren(files, Common::FSNode::kListAll)) {
00734             warning("Failed to access path '%s' when upgrading target '%s'", path.c_str(), target.c_str());
00735             return;
00736         }
00737 
00738         // Take the first detection entry
00739         const MetaEngine &metaEngine = plugin->get<MetaEngine>();
00740         DetectedGames candidates = metaEngine.detectGames(files);
00741         if (candidates.empty()) {
00742             warning("No games supported by the engine '%s' were found in path '%s' when upgrading target '%s'",
00743                     metaEngine.getEngineId(), path.c_str(), target.c_str());
00744             return;
00745         }
00746 
00747         engineId = candidates[0].engineId;
00748         newGameId = candidates[0].gameId;
00749     }
00750 
00751     // Next, try to find an engine with the game ID in its supported games list
00752     if (engineId.empty()) {
00753         QualifiedGameList candidates = findGamesMatching("", oldGameId);
00754         if (candidates.size() > 1) {
00755             warning("Multiple matching engines were found when upgrading target '%s'", target.c_str());
00756             return;
00757         } else if (!candidates.empty()) {
00758             engineId = candidates[0].engineId;
00759             newGameId = candidates[0].gameId;
00760         }
00761     }
00762 
00763     if (engineId.empty() || newGameId.empty()) {
00764         warning("No matching engine was found when upgrading target '%s'", target.c_str());
00765         return;
00766     }
00767 
00768     domain->setVal("engineid", engineId);
00769     domain->setVal("gameid", newGameId);
00770 
00771     // Save a backup of the pre-upgrade gameId to the config file
00772     if (newGameId != oldGameId) {
00773         domain->setVal("oldgameid", oldGameId);
00774     }
00775 
00776     debug("Upgrade complete (engine ID '%s', game ID '%s')", engineId.c_str(), newGameId.c_str());
00777 
00778     ConfMan.flushToDisk();
00779 }
00780 
00781 // Music plugins
00782 
00783 #include "audio/musicplugin.h"
00784 
00785 namespace Common {
00786 DECLARE_SINGLETON(MusicManager);
00787 }
00788 
00789 const PluginList &MusicManager::getPlugins() const {
00790     return PluginManager::instance().getPlugins(PLUGIN_TYPE_MUSIC);
00791 }


Generated on Sat Jul 4 2020 05:01:11 for ResidualVM by doxygen 1.7.1
curved edge   curved edge