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