factored out the EFFv2 saving into EFFImporter
[gemrb.git] / gemrb / core / PluginMgr.cpp
blob8b31b1551196c0789fd1c4ca47f1c0f4afc7c246
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "PluginMgr.h"
23 #include "win32def.h"
25 #include "Interface.h"
26 #include "Plugin.h"
27 #include "ResourceDesc.h"
28 #include "Variables.h" // FIXME: this should be in Interface.h instead
30 #include <cstdio>
31 #include <cstdlib>
32 #ifdef WIN32
33 #include <io.h>
34 #include <windows.h>
35 #else
36 #include <sys/types.h>
37 #include <dirent.h>
38 #include <fnmatch.h>
39 #include <dlfcn.h>
40 #endif
42 typedef const char* (*Version_t)(void);
43 typedef const char* (*Description_t)(void);
44 typedef PluginID (*ID_t)();
45 typedef bool (* Register_t)(PluginMgr*);
47 #ifdef HAVE_FORBIDDEN_OBJECT_TO_FUNCTION_CAST
48 #include <assert.h>
49 typedef void *(* voidvoid)(void);
50 inline voidvoid my_dlsym(void *handle, const char *symbol)
52 void *value = dlsym(handle,symbol);
53 voidvoid ret;
54 assert(sizeof(ret)==sizeof(value) );
55 memcpy(&ret, &value, sizeof(ret) );
56 return ret;
58 #else
59 #define my_dlsym dlsym
60 #endif
62 #ifdef WIN32
63 #define FREE_PLUGIN( handle ) FreeLibrary( handle )
64 #define GET_PLUGIN_SYMBOL( handle, name ) GetProcAddress( handle, name )
65 #define PRINT_DLERROR
66 #else
67 #define FREE_PLUGIN( handle ) dlclose( handle )
68 #define GET_PLUGIN_SYMBOL( handle, name ) my_dlsym( handle, name )
69 #define PRINT_DLERROR printf( "%s\n", dlerror() )
70 #endif
72 PluginMgr *PluginMgr::Get()
74 static PluginMgr mgr;
75 return &mgr;
78 PluginMgr::PluginMgr()
82 void PluginMgr::LoadPlugins(char* pluginpath)
84 printMessage( "PluginMgr", "Loading Plugins from ", WHITE );
85 printf( "%s\n", pluginpath );
87 char path[_MAX_PATH];
88 strcpy( path, pluginpath );
90 std::list< char * > files;
91 if (! FindFiles( path, files ))
92 return;
94 //Iterate through all the available modules to load
95 int file_count = files.size (); // keeps track of first-pass files
96 while (! files.empty()) {
97 char* file = files.front();
98 files.pop_front();
99 file_count--;
101 PathJoin( path, pluginpath, file, NULL );
102 printBracket( "PluginMgr", LIGHT_WHITE );
103 printf( ": Loading: " );
104 textcolor( LIGHT_WHITE );
105 printf( "%s", path );
106 textcolor( WHITE );
107 printf( "..." );
110 ieDword flags = 0;
111 core->plugin_flags->Lookup (file, flags);
113 // module is sent to the back
114 if ((flags == PLF_DELAY) && (file_count >= 0)) {
115 printStatus( "DELAYING", YELLOW );
116 files.push_back( file );
117 continue;
120 // We do not need the basename anymore now
121 free( file );
123 // module is skipped
124 if (flags == PLF_SKIP) {
125 printStatus( "SKIPPING", YELLOW );
126 continue;
131 // Try to load the Module
132 #ifdef WIN32
133 HMODULE hMod = LoadLibrary( path );
134 #else
135 // Note: the RTLD_GLOBAL is necessary to export symbols to modules
136 // which python may have to dlopen (-wjp, 20060716)
137 // (to reproduce, try 'import bz2' or another .so module)
138 void* hMod = dlopen( path, RTLD_NOW | RTLD_GLOBAL );
139 #endif
140 if (hMod == NULL) {
141 printBracket( "ERROR", LIGHT_RED );
142 printf( "\nCannot Load Module, Skipping...\n" );
143 PRINT_DLERROR;
144 continue;
147 //printStatus( "OK", LIGHT_GREEN );
148 //using C bindings, so we don't need to jump through extra hoops
149 //with the symbol name
150 Version_t LibVersion = ( Version_t ) GET_PLUGIN_SYMBOL( hMod, "GemRBPlugin_Version" );
151 Description_t Description = ( Description_t ) GET_PLUGIN_SYMBOL( hMod, "GemRBPlugin_Description" );
152 ID_t ID = ( ID_t ) GET_PLUGIN_SYMBOL( hMod, "GemRBPlugin_ID" );
153 Register_t Register = ( Register_t ) GET_PLUGIN_SYMBOL( hMod, "GemRBPlugin_Register" );
155 //printMessage( "PluginMgr", "Checking Plugin Version...", WHITE );
156 if (LibVersion==NULL) {
157 printStatus( "ERROR", LIGHT_RED );
158 printf( "Invalid Plug-in, Skipping...\n" );
159 FREE_PLUGIN( hMod );
160 continue;
162 if (strcmp(LibVersion(), VERSION_GEMRB) ) {
163 printStatus( "ERROR", LIGHT_RED );
164 printf( "Plug-in Version not valid, Skipping...\n" );
165 FREE_PLUGIN( hMod );
166 continue;
169 PluginDesc desc = { hMod, ID(), Description(), Register };
171 //printStatus( "OK", LIGHT_GREEN );
172 //printMessage( "PluginMgr", "Loading Exports for ", WHITE );
173 printf( " " );
174 textcolor( LIGHT_WHITE );
175 printf( "%s", desc.Description );
176 textcolor( WHITE );
177 printf( "..." );
178 printStatus( "OK", LIGHT_GREEN );
179 if (libs.find(desc.ID) != libs.end()) {
180 printMessage( "PluginMgr", "Plug-in Already Loaded! ", WHITE );
181 printStatus( "SKIPPING", YELLOW );
182 FREE_PLUGIN( hMod );
183 continue;
185 if (desc.Register != NULL) {
186 if (!desc.Register(this)) {
187 printMessage( "PluginMgr", "Plug-in Registration Failed! Perhaps a duplicate? ", WHITE );
188 printStatus( "SKIPPING", YELLOW );
189 FREE_PLUGIN( hMod );
192 libs[desc.ID] = desc;
196 PluginMgr::~PluginMgr(void)
198 //don't free the shared libraries in debug mode, so valgrind can resolve the stack trace
199 #ifndef _DEBUG
200 for (unsigned int i = 0; i < libs.size(); i++) {
201 #ifdef WIN32
202 FreeLibrary(libs[i].handle);
203 #else
204 // dlclose(libs[i].handle);
205 #endif
207 #endif
210 #ifdef WIN32
211 bool
212 PluginMgr::FindFiles( char* path, std::list<char*> &files )
214 //The windows _findfirst/_findnext functions allow the use of wildcards so we'll use them :)
215 struct _finddata_t c_file;
216 long hFile;
217 strcat( path, "*.dll" );
218 if (( hFile = ( long ) _findfirst( path, &c_file ) ) == -1L) //If there is no file matching our search
219 return false;
221 do {
222 files.push_back( strdup( c_file.name ));
223 } while (_findnext( hFile, &c_file ) == 0);
225 _findclose( hFile );
226 return true;
229 #else // ! WIN32
231 bool
232 PluginMgr::FindFiles( char* path, std::list<char*> &files )
234 DirectoryIterator dir(path);
235 if (!dir) //If we cannot open the Directory
236 return false;
238 do {
239 const char *name = dir.GetName();
240 if (fnmatch( "*.so", name, 0 ) != 0) //If the current file has no ".so" extension, skip it
241 continue;
242 files.push_back( strdup( name ));
243 } while (++dir);
245 return true;
247 #endif // ! WIN32
249 bool PluginMgr::IsAvailable(SClass_ID plugintype) const
251 return plugins.find(plugintype) != plugins.end();
254 Plugin* PluginMgr::GetPlugin(SClass_ID plugintype) const
256 std::map<SClass_ID, PluginFunc>::const_iterator iter = plugins.find(plugintype);
257 if (iter != plugins.end())
258 return iter->second();
259 return NULL;
262 const std::vector<ResourceDesc>& PluginMgr::GetResourceDesc(const TypeID* type)
264 return resources[type];
267 bool PluginMgr::RegisterPlugin(SClass_ID id, PluginFunc create)
269 if (plugins.find(id) != plugins.end())
270 return false;
271 plugins[id] = create;
272 return true;
275 void PluginMgr::RegisterResource(const TypeID* type, ResourceFunc create, const char *ext, ieWord keyType)
277 resources[type].push_back(ResourceDesc(type,create,ext,keyType));
280 void PluginMgr::RegisterInitializer(void (*func)(void))
282 intializerFunctions.push_back(func);
285 void PluginMgr::RegisterCleanup(void (*func)(void))
287 cleanupFunctions.push_back(func);
290 void PluginMgr::RunInitializers() const
292 for (size_t i = 0; i < intializerFunctions.size(); i++)
293 intializerFunctions[i]();
296 void PluginMgr::RunCleanup() const
298 for (size_t i = 0; i < cleanupFunctions.size(); i++)
299 cleanupFunctions[i]();
302 bool PluginMgr::RegisterDriver(const TypeID* type, const char* name, PluginFunc create)
304 driver_map &map = drivers[type];
305 driver_map::const_iterator iter = map.find(name);
306 if (iter != map.end())
307 return false;
308 map[name] = create;
309 return true;
312 Plugin* PluginMgr::GetDriver(const TypeID* type, const char* name)
314 driver_map &map = drivers[type];
315 if (map.begin() == map.end())
316 return NULL;
317 driver_map::const_iterator iter = map.find(name);
318 if (iter != map.end())
319 return iter->second();
320 return map.begin()->second();