diff options
-rw-r--r-- | backends/plugins/dc/dc-provider.cpp | 3 | ||||
-rw-r--r-- | backends/plugins/dynamic-plugin.h | 9 | ||||
-rw-r--r-- | backends/plugins/elf/elf-provider.h | 3 | ||||
-rw-r--r-- | backends/plugins/posix/posix-provider.cpp | 3 | ||||
-rw-r--r-- | backends/plugins/sdl/sdl-provider.cpp | 3 | ||||
-rw-r--r-- | backends/plugins/win32/win32-provider.cpp | 3 | ||||
-rw-r--r-- | base/plugins.cpp | 103 | ||||
-rw-r--r-- | base/plugins.h | 35 |
8 files changed, 135 insertions, 27 deletions
diff --git a/backends/plugins/dc/dc-provider.cpp b/backends/plugins/dc/dc-provider.cpp index 67877dc9f4..86ef68828c 100644 --- a/backends/plugins/dc/dc-provider.cpp +++ b/backends/plugins/dc/dc-provider.cpp @@ -37,7 +37,6 @@ class DCPlugin : public DynamicPlugin { protected: void *_dlHandle; - Common::String _filename; virtual VoidFunc findSymbol(const char *symbol) { void *func = dlsym(_dlHandle, symbol); @@ -56,7 +55,7 @@ protected: public: DCPlugin(const Common::String &filename) - : _dlHandle(0), _filename(filename) {} + : DynamicPlugin(filename), _dlHandle(0) {} bool loadPlugin() { assert(!_dlHandle); diff --git a/backends/plugins/dynamic-plugin.h b/backends/plugins/dynamic-plugin.h index ec051c4ed7..32d411656c 100644 --- a/backends/plugins/dynamic-plugin.h +++ b/backends/plugins/dynamic-plugin.h @@ -37,7 +37,12 @@ protected: virtual VoidFunc findSymbol(const char *symbol) = 0; + const Common::String _filename; + public: + DynamicPlugin(const Common::String &filename) : + _filename(filename) {} + virtual bool loadPlugin() { // Validate the plugin API version IntFunc verFunc = (IntFunc)findSymbol("PLUGIN_getVersion"); @@ -97,6 +102,10 @@ public: virtual void unloadPlugin() { delete _pluginObject; } + + virtual const char *getFileName() const { + return _filename.c_str(); + } }; #endif diff --git a/backends/plugins/elf/elf-provider.h b/backends/plugins/elf/elf-provider.h index fe8346f95e..8cc9e0a996 100644 --- a/backends/plugins/elf/elf-provider.h +++ b/backends/plugins/elf/elf-provider.h @@ -48,15 +48,14 @@ protected: typedef const char *(*CharFunc)(); DLObject *_dlHandle; - Common::String _filename; void *_dso_handle; virtual VoidFunc findSymbol(const char *symbol); public: ELFPlugin(const Common::String &filename) : + DynamicPlugin(filename), _dlHandle(0), - _filename(filename), _dso_handle(0) { } diff --git a/backends/plugins/posix/posix-provider.cpp b/backends/plugins/posix/posix-provider.cpp index 01e48739bd..dd3591a992 100644 --- a/backends/plugins/posix/posix-provider.cpp +++ b/backends/plugins/posix/posix-provider.cpp @@ -37,7 +37,6 @@ class POSIXPlugin : public DynamicPlugin { protected: void *_dlHandle; - Common::String _filename; virtual VoidFunc findSymbol(const char *symbol) { void *func = dlsym(_dlHandle, symbol); @@ -56,7 +55,7 @@ protected: public: POSIXPlugin(const Common::String &filename) - : _dlHandle(0), _filename(filename) {} + : DynamicPlugin(filename), _dlHandle(0) {} bool loadPlugin() { assert(!_dlHandle); diff --git a/backends/plugins/sdl/sdl-provider.cpp b/backends/plugins/sdl/sdl-provider.cpp index 51c19fcef3..5172abc4b0 100644 --- a/backends/plugins/sdl/sdl-provider.cpp +++ b/backends/plugins/sdl/sdl-provider.cpp @@ -36,7 +36,6 @@ class SDLPlugin : public DynamicPlugin { protected: void *_dlHandle; - Common::String _filename; virtual VoidFunc findSymbol(const char *symbol) { void *func = SDL_LoadFunction(_dlHandle, symbol); @@ -55,7 +54,7 @@ protected: public: SDLPlugin(const Common::String &filename) - : _dlHandle(0), _filename(filename) {} + : DynamicPlugin(filename), _dlHandle(0) {} bool loadPlugin() { assert(!_dlHandle); diff --git a/backends/plugins/win32/win32-provider.cpp b/backends/plugins/win32/win32-provider.cpp index 16532d4059..793b1bfc0c 100644 --- a/backends/plugins/win32/win32-provider.cpp +++ b/backends/plugins/win32/win32-provider.cpp @@ -51,7 +51,6 @@ private: protected: void *_dlHandle; - Common::String _filename; virtual VoidFunc findSymbol(const char *symbol) { #ifndef _WIN32_WCE @@ -67,7 +66,7 @@ protected: public: Win32Plugin(const Common::String &filename) - : _dlHandle(0), _filename(filename) {} + : DynamicPlugin(filename), _dlHandle(0) {} bool loadPlugin() { assert(!_dlHandle); diff --git a/base/plugins.cpp b/base/plugins.cpp index 62ff15bf81..83377600af 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -335,16 +335,15 @@ void PluginManager::addPluginProvider(PluginProvider *pp) { _providers.push_back(pp); } -// -// This should only be run once +/** + * This should only be called once by main() + **/ void PluginManagerUncached::init() { unloadAllPlugins(); _allEnginePlugins.clear(); - // We need to resize our pluginsInMem list to prevent fragmentation - // Otherwise, as soon as we add our 1 engine plugin (which is all we'll have in memory at a time) - // We'll get an allocation in memory that will never go away - _pluginsInMem[PLUGIN_TYPE_ENGINE].resize(2); // more than we need + // Resize our pluginsInMem list to prevent fragmentation + _pluginsInMem[PLUGIN_TYPE_ENGINE].resize(2); for (ProviderList::iterator pp = _providers.begin(); pp != _providers.end(); @@ -371,6 +370,63 @@ void PluginManagerUncached::init() { } } +/** + * Try to load the plugin by searching in the ConfigManager for a matching + * gameId under the domain 'plugin_files'. + **/ +bool PluginManagerUncached::loadPluginFromGameId(const Common::String &gameId) { + Common::ConfigManager::Domain *domain = ConfMan.getDomain("plugin_files"); + + if (domain) { + if (domain->contains(gameId)) { + Common::String filename = (*domain)[gameId]; + + if (loadPluginByFileName(filename)) { + return true; + } + } + } + return false; +} + +/** + * Load a plugin with a filename taken from ConfigManager. + **/ +bool PluginManagerUncached::loadPluginByFileName(const Common::String &filename) { + if (filename.empty()) + return false; + + unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); + + PluginList::iterator i; + for (i = _allEnginePlugins.begin(); i != _allEnginePlugins.end(); ++i) { + if (Common::String((*i)->getFileName()) == filename && (*i)->loadPlugin()) { + addToPluginsInMemList(*i); + _currentPlugin = i; + return true; + } + } + return false; +} + +/** + * Update the config manager with a plugin file name that we found can handle + * the game. + **/ +void PluginManagerUncached::updateConfigWithFileName(const Common::String &gameId) { + // Check if we have a filename for the current plugin + if ((*_currentPlugin)->getFileName()) { + if (!ConfMan.hasMiscDomain("plugin_files")) + ConfMan.addMiscDomain("plugin_files"); + + Common::ConfigManager::Domain *domain = ConfMan.getDomain("plugin_files"); + assert(domain); + (*domain)[gameId] = (*_currentPlugin)->getFileName(); + + ConfMan.flushToDisk(); + } +} + void PluginManagerUncached::loadFirstPlugin() { unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); @@ -395,6 +451,10 @@ bool PluginManagerUncached::loadNextPlugin() { return false; // no more in list } +/** + * Used by only the cached plugin manager. The uncached manager can only have + * one plugin in memory at a time. + **/ void PluginManager::loadAllPlugins() { for (ProviderList::iterator pp = _providers.begin(); pp != _providers.end(); @@ -426,6 +486,9 @@ void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin, b } } +/* + * Used only by the cached plugin manager since it deletes the plugin. + */ bool PluginManager::tryLoadPlugin(Plugin *plugin) { assert(plugin); // Try to load the plugin @@ -439,6 +502,9 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) { } } +/** + * Add to the list of plugins loaded in memory. + */ void PluginManager::addToPluginsInMemList(Plugin *plugin) { bool found = false; // The plugin is valid, see if it provides the same module as an @@ -468,16 +534,35 @@ void PluginManager::addToPluginsInMemList(Plugin *plugin) { DECLARE_SINGLETON(EngineManager); +/** + * This function works for both cached and uncached PluginManagers. + * For the cached version, most of the logic here will short circuit. + * + * For the uncached version, we first try to find the plugin using the gameId + * and only if we can't find it there, we loop through the plugins. + **/ GameDescriptor EngineManager::findGame(const Common::String &gameName, const EnginePlugin **plugin) const { GameDescriptor result; - - PluginManager::instance().loadFirstPlugin(); + + // first look for the game using the gameId + if (PluginMan.loadPluginFromGameId(gameName)) { + result = findGameInLoadedPlugins(gameName, plugin); + if (!result.gameid().empty()) { + return result; + } + } + + // We failed to find it using the gameid. Scan the list of plugins + PluginMan.loadFirstPlugin(); do { result = findGameInLoadedPlugins(gameName, plugin); if (!result.gameid().empty()) { + // Update with new plugin file name + PluginMan.updateConfigWithFileName(gameName); break; } - } while (PluginManager::instance().loadNextPlugin()); + } while (PluginMan.loadNextPlugin()); + return result; } diff --git a/base/plugins.h b/base/plugins.h index 928be85c32..4f6d37ac86 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -152,11 +152,11 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; // Abstract plugins /** - * Abstract base class for the plugin objects which handle plugins - * instantiation. Subclasses for this may be used for engine plugins - * and other types of plugins. - * - * FIXME: This class needs better documentation, esp. how it differs from class Plugin + * Abstract base class for the plugin objects which handle plugins + * instantiation. Subclasses for this may be used for engine plugins and other + * types of plugins. An existing PluginObject refers to an executable file + * loaded in memory and ready to run. The plugin, on the other hand, is just + * a handle to the file/object, whether it's loaded in memory or not. */ class PluginObject { public: @@ -169,9 +169,8 @@ public: /** * Abstract base class for the plugin system. * Subclasses for this can be used to wrap both static and dynamic - * plugins. - * - * FIXME: This class needs better documentation, esp. how it differs from class PluginObject + * plugins. This class refers to a plugin which may or may not be loaded in + * memory. */ class Plugin { protected: @@ -189,8 +188,19 @@ public: virtual bool loadPlugin() = 0; // TODO: Rename to load() ? virtual void unloadPlugin() = 0; // TODO: Rename to unload() ? + /** + * The following functions query information from the plugin object once + * it's loaded into memory. + **/ PluginType getType() const; const char *getName() const; + + /** + * The getFileName() function gets the name of the plugin file for those + * plugins that have files (ie. not static). It doesn't require the plugin + * object to be loaded into memory, unlike getName() + **/ + virtual const char *getFileName() const { return 0; } }; /** List of Plugin instances. */ @@ -294,6 +304,8 @@ protected: #endif // DYNAMIC_MODULES +#define PluginMan PluginManager::instance() + /** * Singleton class which manages all plugins, including loading them, * managing all Plugin class instances, and unloading them. @@ -319,10 +331,14 @@ public: void addPluginProvider(PluginProvider *pp); + // Functions used by the uncached PluginManager virtual void init() {} virtual void loadFirstPlugin() {} virtual bool loadNextPlugin() { return false; } + virtual bool loadPluginFromGameId(const Common::String &gameId) { return false; } + virtual void updateConfigWithFileName(const Common::String &gameId) {} + // Functions used only by the cached PluginManager virtual void loadAllPlugins(); void unloadAllPlugins(); @@ -342,11 +358,14 @@ protected: PluginList::iterator _currentPlugin; PluginManagerUncached() {} + bool loadPluginByFileName(const Common::String &filename); public: virtual void init(); virtual void loadFirstPlugin(); virtual bool loadNextPlugin(); + virtual bool loadPluginFromGameId(const Common::String &gameId); + virtual void updateConfigWithFileName(const Common::String &gameId); virtual void loadAllPlugins() {} // we don't allow this }; |