PLUGINS: single plugin model now saves plugin filename to config file
After searching for the right plugin once, the filename will be saved to the config file under the domain 'plugin_files'. The key is the gameid and the value is the plugin file. The backup mechanism is searching plugin by plugin. svn-id: r55061
This commit is contained in:
parent
77a6dc7046
commit
8f36a5f887
8 changed files with 135 additions and 27 deletions
|
@ -37,7 +37,6 @@
|
||||||
class DCPlugin : public DynamicPlugin {
|
class DCPlugin : public DynamicPlugin {
|
||||||
protected:
|
protected:
|
||||||
void *_dlHandle;
|
void *_dlHandle;
|
||||||
Common::String _filename;
|
|
||||||
|
|
||||||
virtual VoidFunc findSymbol(const char *symbol) {
|
virtual VoidFunc findSymbol(const char *symbol) {
|
||||||
void *func = dlsym(_dlHandle, symbol);
|
void *func = dlsym(_dlHandle, symbol);
|
||||||
|
@ -56,7 +55,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DCPlugin(const Common::String &filename)
|
DCPlugin(const Common::String &filename)
|
||||||
: _dlHandle(0), _filename(filename) {}
|
: DynamicPlugin(filename), _dlHandle(0) {}
|
||||||
|
|
||||||
bool loadPlugin() {
|
bool loadPlugin() {
|
||||||
assert(!_dlHandle);
|
assert(!_dlHandle);
|
||||||
|
|
|
@ -37,7 +37,12 @@ protected:
|
||||||
|
|
||||||
virtual VoidFunc findSymbol(const char *symbol) = 0;
|
virtual VoidFunc findSymbol(const char *symbol) = 0;
|
||||||
|
|
||||||
|
const Common::String _filename;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
DynamicPlugin(const Common::String &filename) :
|
||||||
|
_filename(filename) {}
|
||||||
|
|
||||||
virtual bool loadPlugin() {
|
virtual bool loadPlugin() {
|
||||||
// Validate the plugin API version
|
// Validate the plugin API version
|
||||||
IntFunc verFunc = (IntFunc)findSymbol("PLUGIN_getVersion");
|
IntFunc verFunc = (IntFunc)findSymbol("PLUGIN_getVersion");
|
||||||
|
@ -97,6 +102,10 @@ public:
|
||||||
virtual void unloadPlugin() {
|
virtual void unloadPlugin() {
|
||||||
delete _pluginObject;
|
delete _pluginObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual const char *getFileName() const {
|
||||||
|
return _filename.c_str();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -48,15 +48,14 @@ protected:
|
||||||
typedef const char *(*CharFunc)();
|
typedef const char *(*CharFunc)();
|
||||||
|
|
||||||
DLObject *_dlHandle;
|
DLObject *_dlHandle;
|
||||||
Common::String _filename;
|
|
||||||
void *_dso_handle;
|
void *_dso_handle;
|
||||||
|
|
||||||
virtual VoidFunc findSymbol(const char *symbol);
|
virtual VoidFunc findSymbol(const char *symbol);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ELFPlugin(const Common::String &filename) :
|
ELFPlugin(const Common::String &filename) :
|
||||||
|
DynamicPlugin(filename),
|
||||||
_dlHandle(0),
|
_dlHandle(0),
|
||||||
_filename(filename),
|
|
||||||
_dso_handle(0) {
|
_dso_handle(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,6 @@
|
||||||
class POSIXPlugin : public DynamicPlugin {
|
class POSIXPlugin : public DynamicPlugin {
|
||||||
protected:
|
protected:
|
||||||
void *_dlHandle;
|
void *_dlHandle;
|
||||||
Common::String _filename;
|
|
||||||
|
|
||||||
virtual VoidFunc findSymbol(const char *symbol) {
|
virtual VoidFunc findSymbol(const char *symbol) {
|
||||||
void *func = dlsym(_dlHandle, symbol);
|
void *func = dlsym(_dlHandle, symbol);
|
||||||
|
@ -56,7 +55,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
POSIXPlugin(const Common::String &filename)
|
POSIXPlugin(const Common::String &filename)
|
||||||
: _dlHandle(0), _filename(filename) {}
|
: DynamicPlugin(filename), _dlHandle(0) {}
|
||||||
|
|
||||||
bool loadPlugin() {
|
bool loadPlugin() {
|
||||||
assert(!_dlHandle);
|
assert(!_dlHandle);
|
||||||
|
|
|
@ -36,7 +36,6 @@
|
||||||
class SDLPlugin : public DynamicPlugin {
|
class SDLPlugin : public DynamicPlugin {
|
||||||
protected:
|
protected:
|
||||||
void *_dlHandle;
|
void *_dlHandle;
|
||||||
Common::String _filename;
|
|
||||||
|
|
||||||
virtual VoidFunc findSymbol(const char *symbol) {
|
virtual VoidFunc findSymbol(const char *symbol) {
|
||||||
void *func = SDL_LoadFunction(_dlHandle, symbol);
|
void *func = SDL_LoadFunction(_dlHandle, symbol);
|
||||||
|
@ -55,7 +54,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SDLPlugin(const Common::String &filename)
|
SDLPlugin(const Common::String &filename)
|
||||||
: _dlHandle(0), _filename(filename) {}
|
: DynamicPlugin(filename), _dlHandle(0) {}
|
||||||
|
|
||||||
bool loadPlugin() {
|
bool loadPlugin() {
|
||||||
assert(!_dlHandle);
|
assert(!_dlHandle);
|
||||||
|
|
|
@ -51,7 +51,6 @@ private:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void *_dlHandle;
|
void *_dlHandle;
|
||||||
Common::String _filename;
|
|
||||||
|
|
||||||
virtual VoidFunc findSymbol(const char *symbol) {
|
virtual VoidFunc findSymbol(const char *symbol) {
|
||||||
#ifndef _WIN32_WCE
|
#ifndef _WIN32_WCE
|
||||||
|
@ -67,7 +66,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Win32Plugin(const Common::String &filename)
|
Win32Plugin(const Common::String &filename)
|
||||||
: _dlHandle(0), _filename(filename) {}
|
: DynamicPlugin(filename), _dlHandle(0) {}
|
||||||
|
|
||||||
bool loadPlugin() {
|
bool loadPlugin() {
|
||||||
assert(!_dlHandle);
|
assert(!_dlHandle);
|
||||||
|
|
101
base/plugins.cpp
101
base/plugins.cpp
|
@ -335,16 +335,15 @@ void PluginManager::addPluginProvider(PluginProvider *pp) {
|
||||||
_providers.push_back(pp);
|
_providers.push_back(pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
/**
|
||||||
// This should only be run once
|
* This should only be called once by main()
|
||||||
|
**/
|
||||||
void PluginManagerUncached::init() {
|
void PluginManagerUncached::init() {
|
||||||
unloadAllPlugins();
|
unloadAllPlugins();
|
||||||
_allEnginePlugins.clear();
|
_allEnginePlugins.clear();
|
||||||
|
|
||||||
// We need to resize our pluginsInMem list to prevent fragmentation
|
// 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)
|
_pluginsInMem[PLUGIN_TYPE_ENGINE].resize(2);
|
||||||
// We'll get an allocation in memory that will never go away
|
|
||||||
_pluginsInMem[PLUGIN_TYPE_ENGINE].resize(2); // more than we need
|
|
||||||
|
|
||||||
for (ProviderList::iterator pp = _providers.begin();
|
for (ProviderList::iterator pp = _providers.begin();
|
||||||
pp != _providers.end();
|
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() {
|
void PluginManagerUncached::loadFirstPlugin() {
|
||||||
unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
|
unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
|
||||||
|
|
||||||
|
@ -395,6 +451,10 @@ bool PluginManagerUncached::loadNextPlugin() {
|
||||||
return false; // no more in list
|
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() {
|
void PluginManager::loadAllPlugins() {
|
||||||
for (ProviderList::iterator pp = _providers.begin();
|
for (ProviderList::iterator pp = _providers.begin();
|
||||||
pp != _providers.end();
|
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) {
|
bool PluginManager::tryLoadPlugin(Plugin *plugin) {
|
||||||
assert(plugin);
|
assert(plugin);
|
||||||
// Try to load the 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) {
|
void PluginManager::addToPluginsInMemList(Plugin *plugin) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
// The plugin is valid, see if it provides the same module as an
|
// 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);
|
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 EngineManager::findGame(const Common::String &gameName, const EnginePlugin **plugin) const {
|
||||||
GameDescriptor result;
|
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 {
|
do {
|
||||||
result = findGameInLoadedPlugins(gameName, plugin);
|
result = findGameInLoadedPlugins(gameName, plugin);
|
||||||
if (!result.gameid().empty()) {
|
if (!result.gameid().empty()) {
|
||||||
|
// Update with new plugin file name
|
||||||
|
PluginMan.updateConfigWithFileName(gameName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (PluginManager::instance().loadNextPlugin());
|
} while (PluginMan.loadNextPlugin());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -153,10 +153,10 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for the plugin objects which handle plugins
|
* Abstract base class for the plugin objects which handle plugins
|
||||||
* instantiation. Subclasses for this may be used for engine plugins
|
* instantiation. Subclasses for this may be used for engine plugins and other
|
||||||
* and other types of plugins.
|
* 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
|
||||||
* FIXME: This class needs better documentation, esp. how it differs from class Plugin
|
* a handle to the file/object, whether it's loaded in memory or not.
|
||||||
*/
|
*/
|
||||||
class PluginObject {
|
class PluginObject {
|
||||||
public:
|
public:
|
||||||
|
@ -169,9 +169,8 @@ public:
|
||||||
/**
|
/**
|
||||||
* Abstract base class for the plugin system.
|
* Abstract base class for the plugin system.
|
||||||
* Subclasses for this can be used to wrap both static and dynamic
|
* Subclasses for this can be used to wrap both static and dynamic
|
||||||
* plugins.
|
* plugins. This class refers to a plugin which may or may not be loaded in
|
||||||
*
|
* memory.
|
||||||
* FIXME: This class needs better documentation, esp. how it differs from class PluginObject
|
|
||||||
*/
|
*/
|
||||||
class Plugin {
|
class Plugin {
|
||||||
protected:
|
protected:
|
||||||
|
@ -189,8 +188,19 @@ public:
|
||||||
virtual bool loadPlugin() = 0; // TODO: Rename to load() ?
|
virtual bool loadPlugin() = 0; // TODO: Rename to load() ?
|
||||||
virtual void unloadPlugin() = 0; // TODO: Rename to unload() ?
|
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;
|
PluginType getType() const;
|
||||||
const char *getName() 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. */
|
/** List of Plugin instances. */
|
||||||
|
@ -294,6 +304,8 @@ protected:
|
||||||
|
|
||||||
#endif // DYNAMIC_MODULES
|
#endif // DYNAMIC_MODULES
|
||||||
|
|
||||||
|
#define PluginMan PluginManager::instance()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton class which manages all plugins, including loading them,
|
* Singleton class which manages all plugins, including loading them,
|
||||||
* managing all Plugin class instances, and unloading them.
|
* managing all Plugin class instances, and unloading them.
|
||||||
|
@ -319,10 +331,14 @@ public:
|
||||||
|
|
||||||
void addPluginProvider(PluginProvider *pp);
|
void addPluginProvider(PluginProvider *pp);
|
||||||
|
|
||||||
|
// Functions used by the uncached PluginManager
|
||||||
virtual void init() {}
|
virtual void init() {}
|
||||||
virtual void loadFirstPlugin() {}
|
virtual void loadFirstPlugin() {}
|
||||||
virtual bool loadNextPlugin() { return false; }
|
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();
|
virtual void loadAllPlugins();
|
||||||
void unloadAllPlugins();
|
void unloadAllPlugins();
|
||||||
|
|
||||||
|
@ -342,11 +358,14 @@ protected:
|
||||||
PluginList::iterator _currentPlugin;
|
PluginList::iterator _currentPlugin;
|
||||||
|
|
||||||
PluginManagerUncached() {}
|
PluginManagerUncached() {}
|
||||||
|
bool loadPluginByFileName(const Common::String &filename);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void init();
|
virtual void init();
|
||||||
virtual void loadFirstPlugin();
|
virtual void loadFirstPlugin();
|
||||||
virtual bool loadNextPlugin();
|
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
|
virtual void loadAllPlugins() {} // we don't allow this
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue