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 // Plugin versioning 37 38 /** Global Plugin API version */ 39 #define PLUGIN_VERSION 1 40 41 enum PluginType { 42 PLUGIN_TYPE_ENGINE_DETECTION = 0, 43 PLUGIN_TYPE_ENGINE, 44 PLUGIN_TYPE_MUSIC, 45 PLUGIN_TYPE_DETECTION, 46 PLUGIN_TYPE_SCALER, 47 48 PLUGIN_TYPE_MAX 49 }; 50 51 // TODO: Make the engine API version depend on ScummVM's version 52 // because of the backlinking (posibly from the checkout revision) 53 #define PLUGIN_TYPE_ENGINE_DETECTION_VERSION 1 54 #define PLUGIN_TYPE_ENGINE_VERSION 2 55 #define PLUGIN_TYPE_MUSIC_VERSION 1 56 #define PLUGIN_TYPE_DETECTION_VERSION 1 57 #define PLUGIN_TYPE_SCALER_VERSION 1 58 59 extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; 60 61 62 // Plugin linking 63 64 // see comments in backends/plugins/elf/elf-provider.cpp 65 #if defined(USE_ELF_LOADER) && defined(ELF_LOADER_CXA_ATEXIT) 66 #define PLUGIN_DYNAMIC_DSO_HANDLE \ 67 uint32 __dso_handle __attribute__((visibility("hidden"))) = 0; 68 #else 69 #define PLUGIN_DYNAMIC_DSO_HANDLE 70 #endif 71 72 #ifdef USE_ELF_LOADER 73 #define PLUGIN_DYNAMIC_BUILD_DATE \ 74 PLUGIN_EXPORT const char *PLUGIN_getBuildDate() { return gScummVMPluginBuildDate; } 75 #else 76 #define PLUGIN_DYNAMIC_BUILD_DATE 77 #endif 78 79 /** 80 * REGISTER_PLUGIN_STATIC is a convenience macro which is used to declare 81 * the plugin interface for static plugins. Code (such as game engines) 82 * which needs to implement a static plugin can simply invoke this macro 83 * with a plugin ID, plugin type and PluginObject subclass, and the correct 84 * wrapper code will be inserted. 85 * 86 * @see REGISTER_PLUGIN_DYNAMIC 87 */ 88 #define REGISTER_PLUGIN_STATIC(ID,TYPE,PLUGINCLASS) \ 89 PluginType g_##ID##_type = TYPE; \ 90 PluginObject *g_##ID##_getObject() { \ 91 return new PLUGINCLASS(); \ 92 } \ 93 void dummyFuncToAllowTrailingSemicolon() 94 95 #ifdef DYNAMIC_MODULES 96 97 /** 98 * REGISTER_PLUGIN_DYNAMIC is a convenience macro which is used to declare 99 * the plugin interface for dynamically loadable plugins. Code (such as game engines) 100 * which needs to implement a dynamic plugin can simply invoke this macro 101 * with a plugin ID, plugin type and PluginObject subclass, and the correct 102 * wrapper code will be inserted. 103 * 104 * @see REGISTER_PLUGIN_STATIC 105 */ 106 #define REGISTER_PLUGIN_DYNAMIC(ID,TYPE,PLUGINCLASS) \ 107 extern "C" { \ 108 PLUGIN_DYNAMIC_DSO_HANDLE \ 109 PLUGIN_DYNAMIC_BUILD_DATE \ 110 PLUGIN_EXPORT int32 PLUGIN_getVersion() { return PLUGIN_VERSION; } \ 111 PLUGIN_EXPORT int32 PLUGIN_getType() { return TYPE; } \ 112 PLUGIN_EXPORT int32 PLUGIN_getTypeVersion() { return TYPE##_VERSION; } \ 113 PLUGIN_EXPORT PluginObject *PLUGIN_getObject() { \ 114 return new PLUGINCLASS(); \ 115 } \ 116 } \ 117 void dummyFuncToAllowTrailingSemicolon() 118 119 #endif // DYNAMIC_MODULES 120 121 122 // Abstract plugins 123 124 /** 125 * Abstract base class for the plugin objects which handle plugins 126 * instantiation. Subclasses for this may be used for engine plugins and other 127 * types of plugins. An existing PluginObject refers to an executable file 128 * loaded in memory and ready to run. The plugin, on the other hand, is just 129 * a handle to the file/object, whether it's loaded in memory or not. 130 */ 131 class PluginObject { 132 public: ~PluginObject()133 virtual ~PluginObject() {} 134 135 /** Returns the name of the plugin. */ 136 virtual const char *getName() const = 0; 137 138 /** 139 * Returns the engine id of the plugin, if implemented. 140 * This mostly has the use with MetaEngines, but if another 141 * type of plugins request this, we return a nullptr. 142 * This is used because MetaEngines are now available in the 143 * executable, and querying this we can match a MetaEngine 144 * with it's related engine. 145 */ getEngineId()146 virtual const char *getEngineId() const { 147 return nullptr; 148 } 149 }; 150 151 /** 152 * Abstract base class for the plugin system. 153 * Subclasses for this can be used to wrap both static and dynamic 154 * plugins. This class refers to a plugin which may or may not be loaded in 155 * memory. 156 */ 157 class Plugin { 158 protected: 159 PluginObject *_pluginObject; 160 PluginType _type; 161 162 public: Plugin()163 Plugin() : _pluginObject(0), _type(PLUGIN_TYPE_MAX) {} ~Plugin()164 virtual ~Plugin() { 165 //if (isLoaded()) 166 //unloadPlugin(); 167 } 168 169 // virtual bool isLoaded() const = 0; // TODO 170 virtual bool loadPlugin() = 0; // TODO: Rename to load() ? 171 virtual void unloadPlugin() = 0; // TODO: Rename to unload() ? 172 173 /** 174 * The following functions query information from the plugin object once 175 * it's loaded into memory. 176 **/ 177 PluginType getType() const; 178 const char *getName() const; 179 const char *getEngineId() const; 180 181 template <class T> get()182 T &get() const { 183 T *pluginObject = dynamic_cast<T *>(_pluginObject); 184 if (!pluginObject) { 185 error("Invalid cast of plugin %s", getName()); 186 } 187 return *pluginObject; 188 } 189 190 /** 191 * The getFileName() function gets the name of the plugin file for those 192 * plugins that have files (ie. not static). It doesn't require the plugin 193 * object to be loaded into memory, unlike getName() 194 **/ getFileName()195 virtual const char *getFileName() const { return 0; } 196 }; 197 198 class StaticPlugin : public Plugin { 199 public: 200 StaticPlugin(PluginObject *pluginobject, PluginType type); 201 ~StaticPlugin(); 202 virtual bool loadPlugin(); 203 virtual void unloadPlugin(); 204 }; 205 206 207 /** List of Plugin instances. */ 208 typedef Common::Array<Plugin *> PluginList; 209 210 /** 211 * Abstract base class for Plugin factories. Subclasses of this 212 * are responsible for creating plugin objects, e.g. by loading 213 * loadable modules from storage media; by creating "fake" plugins 214 * from static code; or whatever other means. 215 */ 216 class PluginProvider { 217 public: ~PluginProvider()218 virtual ~PluginProvider() {} 219 220 /** 221 * Return a list of Plugin objects. The caller is responsible for actually 222 * loading/unloading them (by invoking the appropriate Plugin methods). 223 * Furthermore, the caller is responsible for deleting these objects 224 * eventually. 225 * 226 * @return a list of Plugin instances 227 */ 228 virtual PluginList getPlugins() = 0; 229 230 /** 231 * @return whether or not object is a FilePluginProvider. 232 */ isFilePluginProvider()233 virtual bool isFilePluginProvider() { return false; } 234 }; 235 236 #ifdef DYNAMIC_MODULES 237 238 /** 239 * Abstract base class for Plugin factories which load binary code from files. 240 * Subclasses only have to implement the createPlugin() method, and optionally 241 * can overload the other protected methods to achieve custom behavior. 242 */ 243 class FilePluginProvider : public PluginProvider { 244 public: 245 /** 246 * Return a list of Plugin objects loaded via createPlugin from disk. 247 * For this, a list of directories is searched for plugin objects: 248 * The current dir and its "plugins" subdirectory (if present), a list 249 * of custom search dirs (see addCustomDirectories) and finally the 250 * directory specified via the "pluginspath" config variable (if any). 251 * 252 * @return a list of Plugin instances 253 */ 254 virtual PluginList getPlugins(); 255 256 /** 257 * @return whether or not object is a FilePluginProvider. 258 */ isFilePluginProvider()259 bool isFilePluginProvider() { return true; } 260 261 protected: 262 /** 263 * Create a Plugin instance from a loadable code module with the specified name. 264 * Subclasses of FilePluginProvider have to at least overload this method. 265 * If the file is not found, or does not contain loadable code, 0 is returned instead. 266 * 267 * @param node the FSNode of the loadable code module 268 * @return a pointer to a Plugin instance, or 0 if an error occurred. 269 */ 270 virtual Plugin *createPlugin(const Common::FSNode &node) const = 0; 271 272 /** 273 * Check if the supplied file corresponds to a loadable plugin file in 274 * the current platform. Usually, this will just check the file name. 275 * 276 * @param node the FSNode of the file to check 277 * @return true if the filename corresponds to a plugin, false otherwise 278 */ 279 virtual bool isPluginFilename(const Common::FSNode &node) const; 280 281 /** 282 * Optionally add to the list of directories to be searched for 283 * plugins by getPlugins(). 284 * 285 * @param dirs the reference to the list of directories to be used when 286 * searching for plugins. 287 */ 288 virtual void addCustomDirectories(Common::FSList &dirs) const; 289 }; 290 291 #endif // DYNAMIC_MODULES 292 293 #define PluginMan PluginManager::instance() 294 295 /** 296 * Singleton class which manages all plugins, including loading them, 297 * managing all Plugin class instances, and unloading them. 298 */ 299 class PluginManager { 300 protected: 301 typedef Common::Array<PluginProvider *> ProviderList; 302 303 PluginList _pluginsInMem[PLUGIN_TYPE_MAX]; 304 ProviderList _providers; 305 306 bool tryLoadPlugin(Plugin *plugin); 307 void addToPluginsInMemList(Plugin *plugin); 308 const Plugin *findEnginePlugin(const Common::String &engineId); 309 const Plugin *findLoadedPlugin(const Common::String &engineId); 310 311 static PluginManager *_instance; 312 PluginManager(); 313 314 public: 315 virtual ~PluginManager(); 316 destroy()317 static void destroy() { delete _instance; _instance = 0; } 318 static PluginManager &instance(); 319 320 void addPluginProvider(PluginProvider *pp); 321 322 /** 323 * A method which takes in a plugin of type ENGINE, 324 * and returns the appropriate & matching METAENGINE. 325 * It uses the Engine plugin's getName method, which is an identifier, 326 * and then tries to matches it with each plugin present in memory. 327 * 328 * @param plugin A plugin of type ENGINE. 329 * 330 * @return A plugin of type METAENGINE. 331 */ 332 const Plugin *getMetaEngineFromEngine(const Plugin *plugin); 333 334 /** 335 * A method which takes in a plugin of type METAENGINE, 336 * and returns the appropriate & matching ENGINE. 337 * It uses the MetaEngine's getEngineID to reconstruct the name 338 * of engine plugin, and then tries to matches it with each plugin in memory. 339 * 340 * @param A plugin of type METAENGINE. 341 * 342 * @return A plugin of type ENGINE. 343 */ 344 const Plugin *getEngineFromMetaEngine(const Plugin *plugin); 345 346 // Functions used by the uncached PluginManager init()347 virtual void init() {} loadFirstPlugin()348 virtual void loadFirstPlugin() {} loadNextPlugin()349 virtual bool loadNextPlugin() { return false; } loadPluginFromEngineId(const Common::String & engineId)350 virtual bool loadPluginFromEngineId(const Common::String &engineId) { return false; } updateConfigWithFileName(const Common::String & engineId)351 virtual void updateConfigWithFileName(const Common::String &engineId) {} loadDetectionPlugin()352 virtual void loadDetectionPlugin() {} unloadDetectionPlugin()353 virtual void unloadDetectionPlugin() {} 354 355 // Functions used only by the cached PluginManager 356 virtual void loadAllPlugins(); 357 virtual void loadAllPluginsOfType(PluginType type); 358 void unloadAllPlugins(); 359 360 void unloadPluginsExcept(PluginType type, const Plugin *plugin, bool deletePlugin = true); 361 getPlugins(PluginType t)362 const PluginList &getPlugins(PluginType t) { return _pluginsInMem[t]; } 363 }; 364 365 /** 366 * Uncached version of plugin manager 367 * Keeps only one dynamic plugin in memory at a time 368 **/ 369 class PluginManagerUncached : public PluginManager { 370 protected: 371 friend class PluginManager; 372 PluginList _allEnginePlugins; 373 Plugin *_detectionPlugin; 374 PluginList::iterator _currentPlugin; 375 376 bool _isDetectionLoaded; 377 PluginManagerUncached()378 PluginManagerUncached() : _isDetectionLoaded(false), _detectionPlugin(nullptr) {} 379 bool loadPluginByFileName(const Common::String &filename); 380 381 public: 382 virtual void init() override; 383 virtual void loadFirstPlugin() override; 384 virtual bool loadNextPlugin() override; 385 virtual bool loadPluginFromEngineId(const Common::String &engineId) override; 386 virtual void updateConfigWithFileName(const Common::String &engineId) override; 387 #ifndef DETECTION_STATIC 388 virtual void loadDetectionPlugin() override; 389 virtual void unloadDetectionPlugin() override; 390 #endif 391 loadAllPlugins()392 virtual void loadAllPlugins() override {} // we don't allow these loadAllPluginsOfType(PluginType type)393 virtual void loadAllPluginsOfType(PluginType type) override {} 394 }; 395 396 #endif 397