1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef BASE_PLUGINS_H 24 #define BASE_PLUGINS_H 25 26 #include "common/array.h" 27 #include "common/fs.h" 28 #include "common/str.h" 29 #include "backends/plugins/elf/version.h" 30 31 #define INCLUDED_FROM_BASE_PLUGINS_H 32 #include "base/internal_plugins.h" 33 #undef INCLUDED_FROM_BASE_PLUGINS_H 34 35 36 /** 37 * @page pagePlugins An overview of the ScummVM plugin system 38 * This is a brief overview of how plugins (dynamically loadable code modules) 39 * work in ScummVM. We will explain how to write plugins, how they work internally, 40 * and sketch how porters can add support for them in their ports. 41 * 42 * \section secPluginImpl Implementing a plugin 43 * TODO 44 * 45 * \section secPluginUse Using plugins 46 * TODO 47 * 48 * \section secPluginInternals How plugins work internally 49 * TODO 50 * 51 * \section secPluginBackend How to add support for dynamic plugins to a port 52 * TODO 53 */ 54 55 56 57 // Plugin versioning 58 59 /** Global Plugin API version */ 60 #define PLUGIN_VERSION 1 61 62 enum PluginType { 63 PLUGIN_TYPE_ENGINE = 0, 64 PLUGIN_TYPE_MUSIC, 65 /* PLUGIN_TYPE_SCALER, */ // TODO: Add graphics scaler plugins 66 67 PLUGIN_TYPE_MAX 68 }; 69 70 // TODO: Make the engine API version depend on ScummVM's version 71 // because of the backlinking (posibly from the checkout revision) 72 #define PLUGIN_TYPE_ENGINE_VERSION 1 73 #define PLUGIN_TYPE_MUSIC_VERSION 1 74 75 extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; 76 77 78 // Plugin linking 79 80 // see comments in backends/plugins/elf/elf-provider.cpp 81 #if defined(USE_ELF_LOADER) && defined(ELF_LOADER_CXA_ATEXIT) 82 #define PLUGIN_DYNAMIC_DSO_HANDLE \ 83 uint32 __dso_handle __attribute__((visibility("hidden"))) = 0; 84 #else 85 #define PLUGIN_DYNAMIC_DSO_HANDLE 86 #endif 87 88 #ifdef USE_ELF_LOADER 89 #define PLUGIN_DYNAMIC_BUILD_DATE \ 90 PLUGIN_EXPORT const char *PLUGIN_getBuildDate() { return gScummVMPluginBuildDate; } 91 #else 92 #define PLUGIN_DYNAMIC_BUILD_DATE 93 #endif 94 95 /** 96 * REGISTER_PLUGIN_STATIC is a convenience macro which is used to declare 97 * the plugin interface for static plugins. Code (such as game engines) 98 * which needs to implement a static plugin can simply invoke this macro 99 * with a plugin ID, plugin type and PluginObject subclass, and the correct 100 * wrapper code will be inserted. 101 * 102 * @see REGISTER_PLUGIN_DYNAMIC 103 */ 104 #define REGISTER_PLUGIN_STATIC(ID,TYPE,PLUGINCLASS) \ 105 PluginType g_##ID##_type = TYPE; \ 106 PluginObject *g_##ID##_getObject() { \ 107 return new PLUGINCLASS(); \ 108 } \ 109 void dummyFuncToAllowTrailingSemicolon() 110 111 #ifdef DYNAMIC_MODULES 112 113 /** 114 * REGISTER_PLUGIN_DYNAMIC is a convenience macro which is used to declare 115 * the plugin interface for dynamically loadable plugins. Code (such as game engines) 116 * which needs to implement a dynamic plugin can simply invoke this macro 117 * with a plugin ID, plugin type and PluginObject subclass, and the correct 118 * wrapper code will be inserted. 119 * 120 * @see REGISTER_PLUGIN_STATIC 121 */ 122 #define REGISTER_PLUGIN_DYNAMIC(ID,TYPE,PLUGINCLASS) \ 123 extern "C" { \ 124 PLUGIN_DYNAMIC_DSO_HANDLE \ 125 PLUGIN_DYNAMIC_BUILD_DATE \ 126 PLUGIN_EXPORT int32 PLUGIN_getVersion() { return PLUGIN_VERSION; } \ 127 PLUGIN_EXPORT int32 PLUGIN_getType() { return TYPE; } \ 128 PLUGIN_EXPORT int32 PLUGIN_getTypeVersion() { return TYPE##_VERSION; } \ 129 PLUGIN_EXPORT PluginObject *PLUGIN_getObject() { \ 130 return new PLUGINCLASS(); \ 131 } \ 132 } \ 133 void dummyFuncToAllowTrailingSemicolon() 134 135 #endif // DYNAMIC_MODULES 136 137 138 // Abstract plugins 139 140 /** 141 * Abstract base class for the plugin objects which handle plugins 142 * instantiation. Subclasses for this may be used for engine plugins and other 143 * types of plugins. An existing PluginObject refers to an executable file 144 * loaded in memory and ready to run. The plugin, on the other hand, is just 145 * a handle to the file/object, whether it's loaded in memory or not. 146 */ 147 class PluginObject { 148 public: ~PluginObject()149 virtual ~PluginObject() {} 150 151 /** Returns the name of the plugin. */ 152 virtual const char *getName() const = 0; 153 }; 154 155 /** 156 * Abstract base class for the plugin system. 157 * Subclasses for this can be used to wrap both static and dynamic 158 * plugins. This class refers to a plugin which may or may not be loaded in 159 * memory. 160 */ 161 class Plugin { 162 protected: 163 PluginObject *_pluginObject; 164 PluginType _type; 165 166 public: Plugin()167 Plugin() : _pluginObject(0), _type(PLUGIN_TYPE_MAX) {} ~Plugin()168 virtual ~Plugin() { 169 //if (isLoaded()) 170 //unloadPlugin(); 171 } 172 173 // virtual bool isLoaded() const = 0; // TODO 174 virtual bool loadPlugin() = 0; // TODO: Rename to load() ? 175 virtual void unloadPlugin() = 0; // TODO: Rename to unload() ? 176 177 /** 178 * The following functions query information from the plugin object once 179 * it's loaded into memory. 180 **/ 181 PluginType getType() const; 182 const char *getName() const; 183 184 template <class T> get()185 T &get() const { 186 T *pluginObject = dynamic_cast<T *>(_pluginObject); 187 if (!pluginObject) { 188 error("Invalid cast of plugin %s", getName()); 189 } 190 return *pluginObject; 191 } 192 193 /** 194 * The getFileName() function gets the name of the plugin file for those 195 * plugins that have files (ie. not static). It doesn't require the plugin 196 * object to be loaded into memory, unlike getName() 197 **/ getFileName()198 virtual const char *getFileName() const { return 0; } 199 }; 200 201 /** List of Plugin instances. */ 202 typedef Common::Array<Plugin *> PluginList; 203 204 /** 205 * Abstract base class for Plugin factories. Subclasses of this 206 * are responsible for creating plugin objects, e.g. by loading 207 * loadable modules from storage media; by creating "fake" plugins 208 * from static code; or whatever other means. 209 */ 210 class PluginProvider { 211 public: ~PluginProvider()212 virtual ~PluginProvider() {} 213 214 /** 215 * Return a list of Plugin objects. The caller is responsible for actually 216 * loading/unloading them (by invoking the appropriate Plugin methods). 217 * Furthermore, the caller is responsible for deleting these objects 218 * eventually. 219 * 220 * @return a list of Plugin instances 221 */ 222 virtual PluginList getPlugins() = 0; 223 224 /** 225 * @return whether or not object is a FilePluginProvider. 226 */ isFilePluginProvider()227 virtual bool isFilePluginProvider() { return false; } 228 }; 229 230 #ifdef DYNAMIC_MODULES 231 232 /** 233 * Abstract base class for Plugin factories which load binary code from files. 234 * Subclasses only have to implement the createPlugin() method, and optionally 235 * can overload the other protected methods to achieve custom behavior. 236 */ 237 class FilePluginProvider : public PluginProvider { 238 public: 239 /** 240 * Return a list of Plugin objects loaded via createPlugin from disk. 241 * For this, a list of directories is searched for plugin objects: 242 * The current dir and its "plugins" subdirectory (if present), a list 243 * of custom search dirs (see addCustomDirectories) and finally the 244 * directory specified via the "pluginspath" config variable (if any). 245 * 246 * @return a list of Plugin instances 247 */ 248 virtual PluginList getPlugins(); 249 250 /** 251 * @return whether or not object is a FilePluginProvider. 252 */ isFilePluginProvider()253 bool isFilePluginProvider() { return true; } 254 255 protected: 256 /** 257 * Create a Plugin instance from a loadable code module with the specified name. 258 * Subclasses of FilePluginProvider have to at least overload this method. 259 * If the file is not found, or does not contain loadable code, 0 is returned instead. 260 * 261 * @param node the FSNode of the loadable code module 262 * @return a pointer to a Plugin instance, or 0 if an error occurred. 263 */ 264 virtual Plugin *createPlugin(const Common::FSNode &node) const = 0; 265 266 /** 267 * Check if the supplied file corresponds to a loadable plugin file in 268 * the current platform. Usually, this will just check the file name. 269 * 270 * @param node the FSNode of the file to check 271 * @return true if the filename corresponds to a plugin, false otherwise 272 */ 273 virtual bool isPluginFilename(const Common::FSNode &node) const; 274 275 /** 276 * Optionally add to the list of directories to be searched for 277 * plugins by getPlugins(). 278 * 279 * @param dirs the reference to the list of directories to be used when 280 * searching for plugins. 281 */ 282 virtual void addCustomDirectories(Common::FSList &dirs) const; 283 }; 284 285 #endif // DYNAMIC_MODULES 286 287 #define PluginMan PluginManager::instance() 288 289 /** 290 * Singleton class which manages all plugins, including loading them, 291 * managing all Plugin class instances, and unloading them. 292 */ 293 class PluginManager { 294 protected: 295 typedef Common::Array<PluginProvider *> ProviderList; 296 297 PluginList _pluginsInMem[PLUGIN_TYPE_MAX]; 298 ProviderList _providers; 299 300 bool tryLoadPlugin(Plugin *plugin); 301 void addToPluginsInMemList(Plugin *plugin); 302 303 static PluginManager *_instance; 304 PluginManager(); 305 306 public: 307 virtual ~PluginManager(); 308 destroy()309 static void destroy() { delete _instance; _instance = 0; } 310 static PluginManager &instance(); 311 312 void addPluginProvider(PluginProvider *pp); 313 314 // Functions used by the uncached PluginManager init()315 virtual void init() {} loadFirstPlugin()316 virtual void loadFirstPlugin() {} loadNextPlugin()317 virtual bool loadNextPlugin() { return false; } loadPluginFromGameId(const Common::String & gameId)318 virtual bool loadPluginFromGameId(const Common::String &gameId) { return false; } updateConfigWithFileName(const Common::String & gameId)319 virtual void updateConfigWithFileName(const Common::String &gameId) {} 320 321 // Functions used only by the cached PluginManager 322 virtual void loadAllPlugins(); 323 virtual void loadAllPluginsOfType(PluginType type); 324 void unloadAllPlugins(); 325 326 void unloadPluginsExcept(PluginType type, const Plugin *plugin, bool deletePlugin = true); 327 getPlugins(PluginType t)328 const PluginList &getPlugins(PluginType t) { return _pluginsInMem[t]; } 329 }; 330 331 /** 332 * Uncached version of plugin manager 333 * Keeps only one dynamic plugin in memory at a time 334 **/ 335 class PluginManagerUncached : public PluginManager { 336 protected: 337 friend class PluginManager; 338 PluginList _allEnginePlugins; 339 PluginList::iterator _currentPlugin; 340 PluginManagerUncached()341 PluginManagerUncached() {} 342 bool loadPluginByFileName(const Common::String &filename); 343 344 public: 345 virtual void init(); 346 virtual void loadFirstPlugin(); 347 virtual bool loadNextPlugin(); 348 virtual bool loadPluginFromGameId(const Common::String &gameId); 349 virtual void updateConfigWithFileName(const Common::String &gameId); 350 loadAllPlugins()351 virtual void loadAllPlugins() {} // we don't allow these loadAllPluginsOfType(PluginType type)352 virtual void loadAllPluginsOfType(PluginType type) {} 353 }; 354 355 #endif 356