Speech bubbles can point down right.
[scummvm-innocent.git] / base / plugins.cpp
blobebbf82b12f82a81b957e095a00bb1351e9751ef3
1 /* ScummVM - Graphic Adventure Engine
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.
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.
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.
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.
21 * $URL$
22 * $Id$
26 #include "base/plugins.h"
28 #include "common/func.h"
29 #include "common/debug.h"
31 #ifdef DYNAMIC_MODULES
32 #include "common/config-manager.h"
33 #include "common/fs.h"
34 #endif
36 // Plugin versioning
38 int pluginTypeVersions[PLUGIN_TYPE_MAX] = {
39 PLUGIN_TYPE_ENGINE_VERSION,
40 PLUGIN_TYPE_MUSIC_VERSION,
44 // Abstract plugins
46 PluginType Plugin::getType() const {
47 return _type;
50 const char *Plugin::getName() const {
51 return _pluginObject->getName();
54 class StaticPlugin : public Plugin {
55 public:
56 StaticPlugin(PluginObject *pluginobject, PluginType type) {
57 assert(pluginobject);
58 assert(type < PLUGIN_TYPE_MAX);
59 _pluginObject = pluginobject;
60 _type = type;
63 ~StaticPlugin() {
64 delete _pluginObject;
67 virtual bool loadPlugin() { return true; }
68 virtual void unloadPlugin() {}
71 class StaticPluginProvider : public PluginProvider {
72 public:
73 StaticPluginProvider() {
76 ~StaticPluginProvider() {
79 virtual PluginList getPlugins() {
80 PluginList pl;
82 #define LINK_PLUGIN(ID) \
83 extern PluginType g_##ID##_type; \
84 extern PluginObject *g_##ID##_getObject(); \
85 pl.push_back(new StaticPlugin(g_##ID##_getObject(), g_##ID##_type));
87 // "Loader" for the static plugins.
88 // Iterate over all registered (static) plugins and load them.
90 // Engine plugins
91 #if PLUGIN_ENABLED_STATIC(SCUMM)
92 LINK_PLUGIN(SCUMM)
93 #endif
94 #if PLUGIN_ENABLED_STATIC(AGI)
95 LINK_PLUGIN(AGI)
96 #endif
97 #if PLUGIN_ENABLED_STATIC(AGOS)
98 LINK_PLUGIN(AGOS)
99 #endif
100 #if PLUGIN_ENABLED_STATIC(CINE)
101 LINK_PLUGIN(CINE)
102 #endif
103 #if PLUGIN_ENABLED_STATIC(CRUISE)
104 LINK_PLUGIN(CRUISE)
105 #endif
106 #if PLUGIN_ENABLED_STATIC(DRASCULA)
107 LINK_PLUGIN(DRASCULA)
108 #endif
109 #if PLUGIN_ENABLED_STATIC(GOB)
110 LINK_PLUGIN(GOB)
111 #endif
112 #if PLUGIN_ENABLED_STATIC(GROOVIE)
113 LINK_PLUGIN(GROOVIE)
114 #endif
115 #if PLUGIN_ENABLED_STATIC(IGOR)
116 LINK_PLUGIN(IGOR)
117 #endif
118 #if PLUGIN_ENABLED_STATIC(INNOCENT)
119 LINK_PLUGIN(INNOCENT)
120 #endif
121 #if PLUGIN_ENABLED_STATIC(KYRA)
122 LINK_PLUGIN(KYRA)
123 #endif
124 #if PLUGIN_ENABLED_STATIC(LURE)
125 LINK_PLUGIN(LURE)
126 #endif
127 #if PLUGIN_ENABLED_STATIC(M4)
128 LINK_PLUGIN(M4)
129 #endif
130 #if PLUGIN_ENABLED_STATIC(MADE)
131 LINK_PLUGIN(MADE)
132 #endif
133 #if PLUGIN_ENABLED_STATIC(PARALLACTION)
134 LINK_PLUGIN(PARALLACTION)
135 #endif
136 #if PLUGIN_ENABLED_STATIC(QUEEN)
137 LINK_PLUGIN(QUEEN)
138 #endif
139 #if PLUGIN_ENABLED_STATIC(SAGA)
140 LINK_PLUGIN(SAGA)
141 #endif
142 #if PLUGIN_ENABLED_STATIC(SCI)
143 LINK_PLUGIN(SCI)
144 #endif
145 #if PLUGIN_ENABLED_STATIC(SKY)
146 LINK_PLUGIN(SKY)
147 #endif
148 #if PLUGIN_ENABLED_STATIC(SWORD1)
149 LINK_PLUGIN(SWORD1)
150 #endif
151 #if PLUGIN_ENABLED_STATIC(SWORD2)
152 LINK_PLUGIN(SWORD2)
153 #endif
154 #if PLUGIN_ENABLED_STATIC(TINSEL)
155 LINK_PLUGIN(TINSEL)
156 #endif
157 #if PLUGIN_ENABLED_STATIC(TOUCHE)
158 LINK_PLUGIN(TOUCHE)
159 #endif
160 #if PLUGIN_ENABLED_STATIC(TUCKER)
161 LINK_PLUGIN(TUCKER)
162 #endif
164 // Music plugins
165 // TODO: Use defines to disable or enable each MIDI driver as a
166 // static/dynamic plugin, like it's done for the engines
167 LINK_PLUGIN(NULL)
168 #if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
169 LINK_PLUGIN(WINDOWS)
170 #endif
171 #if defined(UNIX) && defined(USE_ALSA)
172 LINK_PLUGIN(ALSA)
173 #endif
174 #if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__) && !defined(__MINT__)
175 LINK_PLUGIN(SEQ)
176 #endif
177 #if defined(__MINT__)
178 LINK_PLUGIN(STMIDI)
179 #endif
180 #if defined(IRIX)
181 LINK_PLUGIN(DMEDIA)
182 #endif
183 #if defined(__amigaos4__)
184 LINK_PLUGIN(CAMD)
185 #endif
186 #if defined(MACOSX)
187 LINK_PLUGIN(COREAUDIO)
188 LINK_PLUGIN(COREMIDI)
189 LINK_PLUGIN(QUICKTIME)
190 #endif
191 #if defined(PALMOS_MODE)
192 # if defined(COMPILE_CLIE)
193 LINK_PLUGIN(YPA1)
194 # elif defined(COMPILE_ZODIAC) && (!defined(ENABLE_SCUMM) || !defined(PALMOS_ARM))
195 LINK_PLUGIN(ZODIAC)
196 # endif
197 #endif
198 #ifdef USE_FLUIDSYNTH
199 LINK_PLUGIN(FLUIDSYNTH)
200 #endif
201 #ifdef USE_MT32EMU
202 LINK_PLUGIN(MT32)
203 #endif
204 LINK_PLUGIN(ADLIB)
205 LINK_PLUGIN(TOWNS)
206 #if defined (UNIX)
207 LINK_PLUGIN(TIMIDITY)
208 #endif
210 return pl;
214 #ifdef DYNAMIC_MODULES
216 PluginList FilePluginProvider::getPlugins() {
217 PluginList pl;
219 // Prepare the list of directories to search
220 Common::FSList pluginDirs;
222 // Add the default directories
223 pluginDirs.push_back(Common::FSNode("."));
224 pluginDirs.push_back(Common::FSNode("plugins"));
226 // Add the provider's custom directories
227 addCustomDirectories(pluginDirs);
229 // Add the user specified directory
230 Common::String pluginsPath(ConfMan.get("pluginspath"));
231 if (!pluginsPath.empty())
232 pluginDirs.push_back(Common::FSNode(pluginsPath));
234 Common::FSList::const_iterator dir;
235 for (dir = pluginDirs.begin(); dir != pluginDirs.end(); dir++) {
236 // Load all plugins.
237 // Scan for all plugins in this directory
238 Common::FSList files;
239 if (!dir->getChildren(files, Common::FSNode::kListFilesOnly)) {
240 debug(1, "Couldn't open plugin directory '%s'", dir->getPath().c_str());
241 continue;
242 } else {
243 debug(1, "Reading plugins from plugin directory '%s'", dir->getPath().c_str());
246 for (Common::FSList::const_iterator i = files.begin(); i != files.end(); ++i) {
247 if (isPluginFilename(*i)) {
248 pl.push_back(createPlugin(*i));
253 return pl;
256 bool FilePluginProvider::isPluginFilename(const Common::FSNode &node) const {
257 Common::String filename = node.getName();
259 #ifdef PLUGIN_PREFIX
260 // Check the plugin prefix
261 if (!filename.hasPrefix(PLUGIN_PREFIX))
262 return false;
263 #endif
265 #ifdef PLUGIN_SUFFIX
266 // Check the plugin suffix
267 if (!filename.hasSuffix(PLUGIN_SUFFIX))
268 return false;
269 #endif
271 return true;
274 void FilePluginProvider::addCustomDirectories(Common::FSList &dirs) const {
275 #ifdef PLUGIN_DIRECTORY
276 dirs.push_back(Common::FSNode(PLUGIN_DIRECTORY));
277 #endif
280 #endif // DYNAMIC_MODULES
282 #pragma mark -
284 DECLARE_SINGLETON(PluginManager);
286 PluginManager::PluginManager() {
287 // Always add the static plugin provider.
288 addPluginProvider(new StaticPluginProvider());
291 PluginManager::~PluginManager() {
292 // Explicitly unload all loaded plugins
293 unloadPlugins();
295 // Delete the plugin providers
296 for (ProviderList::iterator pp = _providers.begin();
297 pp != _providers.end();
298 ++pp) {
299 delete *pp;
303 void PluginManager::addPluginProvider(PluginProvider *pp) {
304 _providers.push_back(pp);
307 void PluginManager::loadPlugins() {
308 for (ProviderList::iterator pp = _providers.begin();
309 pp != _providers.end();
310 ++pp) {
311 PluginList pl((*pp)->getPlugins());
312 Common::for_each(pl.begin(), pl.end(), Common::bind1st(Common::mem_fun(&PluginManager::tryLoadPlugin), this));
317 void PluginManager::unloadPlugins() {
318 for (int i = 0; i < PLUGIN_TYPE_MAX; i++)
319 unloadPluginsExcept((PluginType)i, NULL);
322 void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin) {
323 Plugin *found = NULL;
324 for (PluginList::iterator p = _plugins[type].begin(); p != _plugins[type].end(); ++p) {
325 if (*p == plugin) {
326 found = *p;
327 } else {
328 (*p)->unloadPlugin();
329 delete *p;
332 _plugins[type].clear();
333 if (found != NULL) {
334 _plugins[type].push_back(found);
338 bool PluginManager::tryLoadPlugin(Plugin *plugin) {
339 assert(plugin);
340 // Try to load the plugin
341 if (plugin->loadPlugin()) {
342 // The plugin is valid, see if it provides the same module as an
343 // already loaded one and should replace it.
344 bool found = false;
346 PluginList::iterator pl = _plugins[plugin->getType()].begin();
347 while (!found && pl != _plugins[plugin->getType()].end()) {
348 if (!strcmp(plugin->getName(), (*pl)->getName())) {
349 // Found a duplicated module. Replace the old one.
350 found = true;
351 delete *pl;
352 *pl = plugin;
353 debug(1, "Replaced the duplicated plugin: '%s'", plugin->getName());
355 pl++;
358 if (!found) {
359 // If it provides a new module, just add it to the list of known plugins.
360 _plugins[plugin->getType()].push_back(plugin);
363 return true;
364 } else {
365 // Failed to load the plugin
366 delete plugin;
367 return false;
372 // Engine plugins
374 #include "engines/metaengine.h"
376 DECLARE_SINGLETON(EngineManager);
378 GameDescriptor EngineManager::findGame(const Common::String &gameName, const EnginePlugin **plugin) const {
379 // Find the GameDescriptor for this target
380 const EnginePlugin::List &plugins = getPlugins();
381 GameDescriptor result;
383 if (plugin)
384 *plugin = 0;
386 EnginePlugin::List::const_iterator iter = plugins.begin();
387 for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
388 result = (**iter)->findGame(gameName.c_str());
389 if (!result.gameid().empty()) {
390 if (plugin)
391 *plugin = *iter;
392 break;
395 return result;
398 GameList EngineManager::detectGames(const Common::FSList &fslist) const {
399 GameList candidates;
401 const EnginePlugin::List &plugins = getPlugins();
403 // Iterate over all known games and for each check if it might be
404 // the game in the presented directory.
405 EnginePlugin::List::const_iterator iter;
406 for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
407 candidates.push_back((**iter)->detectGames(fslist));
410 return candidates;
413 const EnginePlugin::List &EngineManager::getPlugins() const {
414 return (const EnginePlugin::List &)PluginManager::instance().getPlugins(PLUGIN_TYPE_ENGINE);
418 // Music plugins
420 #include "sound/musicplugin.h"
422 DECLARE_SINGLETON(MusicManager);
424 const MusicPlugin::List &MusicManager::getPlugins() const {
425 return (const MusicPlugin::List &)PluginManager::instance().getPlugins(PLUGIN_TYPE_MUSIC);