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