1 /*
2     MPEG Maaate: An Australian MPEG audio analysis toolkit
3     Copyright (C) 2000 Commonwealth Scientific and Industrial Research Organisation
4     (CSIRO), Australia.
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include "plugins.H"
27 
28 #include <dirent.h>
29 
30 #if (defined (WIN32) || (_WIN32))
31 	#define DIRSEP "\\"
32 	#define PATHSEP ";"
33 #else
34 	#include <dlfcn.h>
35 	#define DIRSEP '/'
36 	#define PATHSEP ":"
37 #endif
38 
39 
40 #include <cstdlib>
41 #include <sys/types.h>
42 
43 typedef list<Module> * (*loadFunc) ();
44 typedef void (*unloadFunc) ();
45 
46 CSAPI_TIER2
PluginLibrary(string filename)47 PluginLibrary::PluginLibrary (string filename) {
48   list<Module> * tmp;
49   // remember filename
50   name = filename;
51 
52   // open the library and get a handle to it
53 #if (defined (WIN32) || (_WIN32))
54   hLib = LoadLibrary(filename.c_str());
55   if (!hLib) {
56     cerr << "MaaateA: error opening " << filename << ": " << endl;
57     return;
58   }
59 #else
60   plib = dlopen (filename.c_str(), RTLD_NOW);
61   if (!plib) {
62     cerr << "MaaateA: error opening " << filename << ": " << dlerror() << endl;
63     return;
64   }
65 #endif
66 
67   // get the function to load the modules of the library and call it
68   // returning a list of modules; the initialisation functions are
69   // also called during construction of modules
70     loadFunc loadModules;
71 #if (defined (WIN32) || (_WIN32))
72     loadModules = (loadFunc)GetProcAddress(hLib, "loadModules");
73     if (!loadModules) {
74       cerr << "MaaateA: error reading symbol from " << filename << ": " << endl;
75       return;
76     }
77 #else
78     loadModules = (loadFunc) dlsym (plib, "loadModules");
79     if (!loadModules) {
80       cerr << "MaaateA: error reading symbol from " << filename << ": " << endl;
81       cerr << dlerror () << endl;
82       return;
83     }
84 #endif
85     tmp = loadModules();
86     modList = *tmp;
87 
88   // set the plib/hLib member of each module that was loaded
89     list<Module>::iterator iter;
90     for (iter = modList.begin(); iter != modList.end(); ++iter) {
91       (*iter).plib = this;
92     }
93 }
94 
95 CSAPI_TIER2
~PluginLibrary()96 PluginLibrary::~PluginLibrary() {
97   // cleanup the modules
98   unloadFunc unloadModules;
99 
100 #if (defined (WIN32) || (_WIN32))
101   unloadModules = (unloadFunc)GetProcAddress((HMODULE)hLib, "unloadModules");
102   unloadModules();
103 
104   // close the library
105   FreeLibrary((HMODULE)hLib);
106 #else
107   unloadModules = (unloadFunc) dlsym (plib, "unloadModules");
108   unloadModules();
109 
110   // close the library
111   dlclose(plib);
112 #endif
113 }
114 
115 CSAPI_TIER2 void
AddStaticModules()116 Plugins::AddStaticModules () {
117 }
118 
119 CSAPI_TIER2 bool
AddLibrary(string filename)120 Plugins::AddLibrary (string filename) {
121   // find library either at given place or
122   // in MAAATE_PATH environment variable path or
123   // in standard PACKAGE_PLUGIN_DIR path or
124   // in standard /usr/local/lib
125   struct stat *buf = (struct stat *) malloc (sizeof(struct stat));
126   string filepath = string(filename);
127 
128   // Check that filename ends in ".so"
129   //  string::size_type pos = filename.rfind ('.');
130   string::size_type pos = filename.rfind ('.');
131   if (pos == string::npos) {
132     cerr << "MaaateA: warning " << filename << " not opened" << endl;
133     free(buf);
134     return false;
135   }
136   string extension(filename, pos, string::npos);
137 #if (defined (WIN32) || (_WIN32))
138   if (extension != ".dll") {
139     cerr << "MaaateA: warning " << filename << " not opened" << endl;
140     free(buf);
141     return false;
142   }
143 
144 #else
145   if (extension != ".so") {
146     cerr << "MaaateA: warning " << filename << " not opened" << endl;
147     free(buf);
148     return false;
149   }
150 #endif
151 
152 
153   if (stat(filename.c_str(), buf) != 0) {
154     // some error occured when opening file - presume file doesn't exist
155     // => try with different paths
156     char * mpath = getenv("MAAATE_PATH");
157     string crudpath;
158     if (mpath != NULL && strlen(mpath) != 0)
159     {
160       crudpath.append(mpath);
161       crudpath.append(PATHSEP);
162     }
163 
164     crudpath.append(PACKAGE_PLUGIN_DIR);
165 #if (defined (WIN32) || (_WIN32))
166 #ifdef _DEBUG
167 	crudpath.append(";.\\debug");
168 #else
169 	crudpath.append(";.\\release");
170 #endif
171 #else
172     crudpath.append(":/usr/local/lib/");
173 #endif
174 
175     // go through colon-separated directory list and try library in each
176     // always cutting out the first name
177     bool found = false;
178     string tmpdir;
179     string::size_type pos = 0;
180     while ((pos=crudpath.find(PATHSEP, pos)) != string::npos) {
181       tmpdir = string(crudpath, (string::size_type) 0, pos);
182       if (stat((tmpdir+DIRSEP+filename).c_str(), buf) == 0) {
183 	filepath = (tmpdir+DIRSEP+filename);
184 	found = true;
185 	break;
186       }
187       crudpath.erase ((string::size_type) 0, pos+1);
188     }
189     if (!found) {
190       // try last dirname
191       if (stat((crudpath+DIRSEP+filename).c_str(), buf) == 0) {
192 	filepath = (crudpath)+DIRSEP+filename;
193       } else {
194 	free(buf);
195 	return false;
196       }
197     }
198   }
199 
200   PluginLibrary * pl = new PluginLibrary (filepath);
201   list<Module> * ml = pl->Modules();
202 
203   list<Module>::iterator iter;
204   for (iter = ml->begin(); iter != ml->end(); ++iter) {
205     AddModule (&(*iter));
206   }
207   free(buf);
208   return true;
209 }
210 
211 CSAPI_TIER2 void
AddLibraries(string dirname)212 Plugins::AddLibraries (string dirname) {
213   DIR * dir;
214   struct dirent * direntity;
215 
216   dir = opendir(dirname.c_str());
217   if (dir == NULL) return;
218 
219   /* read directory entries one at a time */
220   while ((direntity=readdir(dir)) != NULL) {
221     AddLibrary(direntity->d_name);
222   }
223 }
224 
225 CSAPI_TIER2 void
AddLibrariesPath(string pathlist)226 Plugins::AddLibrariesPath (string pathlist) {
227   string crudpath = string(pathlist);
228   string tmpdir;
229   string::size_type pos = 0;
230 
231   // go through colon-separated directory list and add libraries from there
232   // always cutting out the first name
233   while ((pos=crudpath.find(':', pos)) != string::npos) {
234     tmpdir = string(crudpath, (string::size_type) 0, pos);
235     AddLibraries (crudpath);
236     crudpath.erase ((string::size_type) 0, pos+1);
237   }
238   // add last dirname
239   AddLibraries (crudpath);
240 
241 }
242 
243 CSAPI_TIER2 void
AddLibrariesMaaatePath()244 Plugins::AddLibrariesMaaatePath () {
245   AddStaticModules ();
246 
247   char * mpath = getenv("MAAATE_PATH");
248   string crudpath = string();
249   if (mpath != NULL && strlen(mpath) != 0) {
250     crudpath.append(mpath);
251     crudpath.append(":");
252   }
253   crudpath.append(PACKAGE_PLUGIN_DIR);
254 
255   AddLibrariesPath (crudpath);
256 }
257 
258 CSAPI_TIER2 void
AddModule(Module * module)259 Plugins::AddModule (Module * module) {
260   list<Module>::iterator iter;
261 
262   for (iter = removedList.begin(); iter != removedList.end(); ++iter) {
263     if (&(*iter) == module) {
264       modList.splice(modList.begin(), removedList, iter);
265       return;
266     }
267   }
268 
269   modList.push_back (*module);
270 }
271 
272 CSAPI_TIER2 void
RemoveLibrary(string name)273 Plugins::RemoveLibrary (string name) {
274   list<Module> * lM;
275 
276   lM = LibraryModules (name);
277 
278   list<Module>::iterator iter;
279 
280   for (iter = lM->begin(); iter != lM->end(); ++iter) {
281     RemoveModule (&(*iter));
282   }
283 }
284 
285 CSAPI_TIER2 void
RemoveModule(Module * module)286 Plugins::RemoveModule (Module * module) {
287   list<Module>::iterator iter;
288 
289   for (iter = modList.begin(); iter != modList.end(); ++iter) {
290     if (&(*iter) == module) {
291       removedList.splice(removedList.begin(), modList, iter);
292       return;
293     }
294   }
295 }
296 
297 // get a specific module of a given name
298 CSAPI_TIER2 Module *
GetModule(string name)299 Plugins::GetModule (string name) {
300   list<Module>::iterator iter;
301 
302   for (iter = modList.begin(); iter != modList.end(); ++iter) {
303     if ((*iter).name() == name) {
304       return &(*iter);
305     }
306   }
307 
308   return NULL;
309 }
310 
311 CSAPI_TIER2 list<Module> *
LibraryModules(string name)312 Plugins::LibraryModules (string name) {
313   list<Module>::const_iterator iter;
314 
315   for (iter = modList.begin(); iter != modList.end(); ++iter) {
316     if ((*iter).plib->filename() == name) {
317       return (*iter).plib->Modules();
318     }
319   }
320   return NULL;
321 }
322 
323 
324 
325 
326