cannam@64
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@64
|
2
|
cannam@64
|
3 /*
|
cannam@64
|
4 Vamp
|
cannam@64
|
5
|
cannam@64
|
6 An API for audio analysis and feature extraction plugins.
|
cannam@64
|
7
|
cannam@64
|
8 Centre for Digital Music, Queen Mary, University of London.
|
cannam@64
|
9 Copyright 2006 Chris Cannam.
|
cannam@64
|
10
|
cannam@64
|
11 Permission is hereby granted, free of charge, to any person
|
cannam@64
|
12 obtaining a copy of this software and associated documentation
|
cannam@64
|
13 files (the "Software"), to deal in the Software without
|
cannam@64
|
14 restriction, including without limitation the rights to use, copy,
|
cannam@64
|
15 modify, merge, publish, distribute, sublicense, and/or sell copies
|
cannam@64
|
16 of the Software, and to permit persons to whom the Software is
|
cannam@64
|
17 furnished to do so, subject to the following conditions:
|
cannam@64
|
18
|
cannam@64
|
19 The above copyright notice and this permission notice shall be
|
cannam@64
|
20 included in all copies or substantial portions of the Software.
|
cannam@64
|
21
|
cannam@64
|
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
cannam@64
|
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
cannam@64
|
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
cannam@64
|
25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
cannam@64
|
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
cannam@64
|
27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
cannam@64
|
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
cannam@64
|
29
|
cannam@64
|
30 Except as contained in this notice, the names of the Centre for
|
cannam@64
|
31 Digital Music; Queen Mary, University of London; and Chris Cannam
|
cannam@64
|
32 shall not be used in advertising or otherwise to promote the sale,
|
cannam@64
|
33 use or other dealings in this Software without prior written
|
cannam@64
|
34 authorization.
|
cannam@64
|
35 */
|
cannam@64
|
36
|
cannam@64
|
37 #include "vamp-sdk/PluginHostAdapter.h"
|
cannam@64
|
38 #include "PluginLoader.h"
|
cannam@64
|
39 #include "PluginInputDomainAdapter.h"
|
cannam@64
|
40 #include "PluginChannelAdapter.h"
|
cannam@64
|
41
|
cannam@64
|
42 #include <fstream>
|
cannam@64
|
43
|
cannam@64
|
44 #ifdef _WIN32
|
cannam@64
|
45
|
cannam@64
|
46 #include <windows.h>
|
cannam@64
|
47 #include <tchar.h>
|
cannam@64
|
48 #define PLUGIN_SUFFIX "dll"
|
cannam@64
|
49
|
cannam@64
|
50 #else /* ! _WIN32 */
|
cannam@64
|
51
|
cannam@64
|
52 #include <dirent.h>
|
cannam@64
|
53 #include <dlfcn.h>
|
cannam@64
|
54
|
cannam@64
|
55 #ifdef __APPLE__
|
cannam@64
|
56 #define PLUGIN_SUFFIX "dylib"
|
cannam@64
|
57 #else /* ! __APPLE__ */
|
cannam@64
|
58 #define PLUGIN_SUFFIX "so"
|
cannam@64
|
59 #endif /* ! __APPLE__ */
|
cannam@64
|
60
|
cannam@64
|
61 #endif /* ! _WIN32 */
|
cannam@64
|
62
|
cannam@64
|
63 using namespace std;
|
cannam@64
|
64
|
cannam@64
|
65 namespace Vamp {
|
cannam@64
|
66
|
cannam@64
|
67 namespace HostExt {
|
cannam@64
|
68
|
cannam@69
|
69 class PluginLoader::Impl
|
cannam@69
|
70 {
|
cannam@69
|
71 public:
|
cannam@69
|
72 virtual ~Impl() { }
|
cannam@69
|
73
|
cannam@69
|
74 PluginKeyList listPlugins();
|
cannam@69
|
75
|
cannam@69
|
76 Plugin *loadPlugin(PluginKey key,
|
cannam@69
|
77 float inputSampleRate,
|
cannam@69
|
78 int adapterFlags);
|
cannam@69
|
79
|
cannam@69
|
80 PluginKey composePluginKey(string libraryName, string identifier);
|
cannam@69
|
81
|
cannam@69
|
82 PluginCategoryHierarchy getPluginCategory(PluginKey key);
|
cannam@69
|
83
|
cannam@69
|
84 std::string getLibraryPathForPlugin(PluginKey key);
|
cannam@69
|
85
|
cannam@69
|
86 protected:
|
cannam@69
|
87 class PluginDeletionNotifyAdapter : public PluginWrapper {
|
cannam@69
|
88 public:
|
cannam@69
|
89 PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader);
|
cannam@69
|
90 virtual ~PluginDeletionNotifyAdapter();
|
cannam@69
|
91 protected:
|
cannam@69
|
92 Impl *m_loader;
|
cannam@69
|
93 };
|
cannam@69
|
94
|
cannam@69
|
95 virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter);
|
cannam@69
|
96
|
cannam@69
|
97 std::map<PluginKey, std::string> m_pluginLibraryNameMap;
|
cannam@69
|
98 void generateLibraryMap();
|
cannam@69
|
99
|
cannam@69
|
100 std::map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
|
cannam@69
|
101 void generateTaxonomy();
|
cannam@69
|
102
|
cannam@69
|
103 std::map<Plugin *, void *> m_pluginLibraryHandleMap;
|
cannam@69
|
104
|
cannam@69
|
105 void *loadLibrary(std::string path);
|
cannam@69
|
106 void unloadLibrary(void *handle);
|
cannam@69
|
107 void *lookupInLibrary(void *handle, const char *symbol);
|
cannam@69
|
108
|
cannam@69
|
109 std::string splicePath(std::string a, std::string b);
|
cannam@69
|
110 std::vector<std::string> listFiles(std::string dir, std::string ext);
|
cannam@69
|
111 };
|
cannam@69
|
112
|
cannam@64
|
113 PluginLoader *
|
cannam@64
|
114 PluginLoader::m_instance = 0;
|
cannam@64
|
115
|
cannam@64
|
116 PluginLoader::PluginLoader()
|
cannam@64
|
117 {
|
cannam@69
|
118 m_impl = new Impl();
|
cannam@64
|
119 }
|
cannam@64
|
120
|
cannam@64
|
121 PluginLoader::~PluginLoader()
|
cannam@64
|
122 {
|
cannam@69
|
123 delete m_impl;
|
cannam@64
|
124 }
|
cannam@64
|
125
|
cannam@64
|
126 PluginLoader *
|
cannam@64
|
127 PluginLoader::getInstance()
|
cannam@64
|
128 {
|
cannam@64
|
129 if (!m_instance) m_instance = new PluginLoader();
|
cannam@64
|
130 return m_instance;
|
cannam@64
|
131 }
|
cannam@64
|
132
|
cannam@64
|
133 vector<PluginLoader::PluginKey>
|
cannam@64
|
134 PluginLoader::listPlugins()
|
cannam@64
|
135 {
|
cannam@69
|
136 return m_impl->listPlugins();
|
cannam@69
|
137 }
|
cannam@69
|
138
|
cannam@69
|
139 Plugin *
|
cannam@69
|
140 PluginLoader::loadPlugin(PluginKey key,
|
cannam@69
|
141 float inputSampleRate,
|
cannam@69
|
142 int adapterFlags)
|
cannam@69
|
143 {
|
cannam@69
|
144 return m_impl->loadPlugin(key, inputSampleRate, adapterFlags);
|
cannam@69
|
145 }
|
cannam@69
|
146
|
cannam@69
|
147 PluginLoader::PluginKey
|
cannam@69
|
148 PluginLoader::composePluginKey(string libraryName, string identifier)
|
cannam@69
|
149 {
|
cannam@69
|
150 return m_impl->composePluginKey(libraryName, identifier);
|
cannam@69
|
151 }
|
cannam@69
|
152
|
cannam@69
|
153 PluginLoader::PluginCategoryHierarchy
|
cannam@69
|
154 PluginLoader::getPluginCategory(PluginKey key)
|
cannam@69
|
155 {
|
cannam@69
|
156 return m_impl->getPluginCategory(key);
|
cannam@69
|
157 }
|
cannam@69
|
158
|
cannam@69
|
159 string
|
cannam@69
|
160 PluginLoader::getLibraryPathForPlugin(PluginKey key)
|
cannam@69
|
161 {
|
cannam@69
|
162 return m_impl->getLibraryPathForPlugin(key);
|
cannam@69
|
163 }
|
cannam@69
|
164
|
cannam@69
|
165 vector<PluginLoader::PluginKey>
|
cannam@69
|
166 PluginLoader::Impl::listPlugins()
|
cannam@69
|
167 {
|
cannam@64
|
168 if (m_pluginLibraryNameMap.empty()) generateLibraryMap();
|
cannam@64
|
169
|
cannam@64
|
170 vector<PluginKey> plugins;
|
cannam@64
|
171 for (map<PluginKey, string>::iterator mi =
|
cannam@64
|
172 m_pluginLibraryNameMap.begin();
|
cannam@64
|
173 mi != m_pluginLibraryNameMap.end(); ++mi) {
|
cannam@64
|
174 plugins.push_back(mi->first);
|
cannam@64
|
175 }
|
cannam@64
|
176
|
cannam@64
|
177 return plugins;
|
cannam@64
|
178 }
|
cannam@64
|
179
|
cannam@64
|
180 void
|
cannam@69
|
181 PluginLoader::Impl::generateLibraryMap()
|
cannam@64
|
182 {
|
cannam@64
|
183 vector<string> path = PluginHostAdapter::getPluginPath();
|
cannam@64
|
184
|
cannam@64
|
185 for (size_t i = 0; i < path.size(); ++i) {
|
cannam@64
|
186
|
cannam@64
|
187 vector<string> files = listFiles(path[i], PLUGIN_SUFFIX);
|
cannam@64
|
188
|
cannam@64
|
189 for (vector<string>::iterator fi = files.begin();
|
cannam@64
|
190 fi != files.end(); ++fi) {
|
cannam@64
|
191
|
cannam@64
|
192 string fullPath = path[i];
|
cannam@64
|
193 fullPath = splicePath(fullPath, *fi);
|
cannam@64
|
194 void *handle = loadLibrary(fullPath);
|
cannam@64
|
195 if (!handle) continue;
|
cannam@64
|
196
|
cannam@64
|
197 VampGetPluginDescriptorFunction fn =
|
cannam@64
|
198 (VampGetPluginDescriptorFunction)lookupInLibrary
|
cannam@64
|
199 (handle, "vampGetPluginDescriptor");
|
cannam@64
|
200
|
cannam@64
|
201 if (!fn) {
|
cannam@64
|
202 unloadLibrary(handle);
|
cannam@64
|
203 continue;
|
cannam@64
|
204 }
|
cannam@64
|
205
|
cannam@64
|
206 int index = 0;
|
cannam@64
|
207 const VampPluginDescriptor *descriptor = 0;
|
cannam@64
|
208
|
cannam@64
|
209 while ((descriptor = fn(VAMP_API_VERSION, index))) {
|
cannam@64
|
210 PluginKey key = composePluginKey(*fi, descriptor->identifier);
|
cannam@64
|
211 if (m_pluginLibraryNameMap.find(key) ==
|
cannam@64
|
212 m_pluginLibraryNameMap.end()) {
|
cannam@64
|
213 m_pluginLibraryNameMap[key] = fullPath;
|
cannam@64
|
214 }
|
cannam@64
|
215 ++index;
|
cannam@64
|
216 }
|
cannam@64
|
217
|
cannam@64
|
218 unloadLibrary(handle);
|
cannam@64
|
219 }
|
cannam@64
|
220 }
|
cannam@64
|
221 }
|
cannam@64
|
222
|
cannam@64
|
223 PluginLoader::PluginKey
|
cannam@69
|
224 PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
|
cannam@64
|
225 {
|
cannam@64
|
226 string basename = libraryName;
|
cannam@64
|
227
|
cannam@64
|
228 string::size_type li = basename.rfind('/');
|
cannam@64
|
229 if (li != string::npos) basename = basename.substr(li + 1);
|
cannam@64
|
230
|
cannam@64
|
231 li = basename.find('.');
|
cannam@64
|
232 if (li != string::npos) basename = basename.substr(0, li);
|
cannam@64
|
233
|
cannam@64
|
234 return basename + ":" + identifier;
|
cannam@64
|
235 }
|
cannam@64
|
236
|
cannam@64
|
237 PluginLoader::PluginCategoryHierarchy
|
cannam@69
|
238 PluginLoader::Impl::getPluginCategory(PluginKey plugin)
|
cannam@64
|
239 {
|
cannam@64
|
240 if (m_taxonomy.empty()) generateTaxonomy();
|
cannam@69
|
241 if (m_taxonomy.find(plugin) == m_taxonomy.end()) {
|
cannam@69
|
242 return PluginCategoryHierarchy();
|
cannam@69
|
243 }
|
cannam@64
|
244 return m_taxonomy[plugin];
|
cannam@64
|
245 }
|
cannam@64
|
246
|
cannam@64
|
247 string
|
cannam@69
|
248 PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
|
cannam@64
|
249 {
|
cannam@64
|
250 if (m_pluginLibraryNameMap.empty()) generateLibraryMap();
|
cannam@64
|
251 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) return "";
|
cannam@64
|
252 return m_pluginLibraryNameMap[plugin];
|
cannam@64
|
253 }
|
cannam@64
|
254
|
cannam@64
|
255 Plugin *
|
cannam@69
|
256 PluginLoader::Impl::loadPlugin(PluginKey key,
|
cannam@69
|
257 float inputSampleRate, int adapterFlags)
|
cannam@64
|
258 {
|
cannam@64
|
259 string fullPath = getLibraryPathForPlugin(key);
|
cannam@64
|
260 if (fullPath == "") return 0;
|
cannam@64
|
261
|
cannam@64
|
262 string::size_type ki = key.find(':');
|
cannam@64
|
263 if (ki == string::npos) {
|
cannam@64
|
264 //!!! flag error
|
cannam@64
|
265 return 0;
|
cannam@64
|
266 }
|
cannam@64
|
267
|
cannam@64
|
268 string identifier = key.substr(ki + 1);
|
cannam@64
|
269
|
cannam@64
|
270 void *handle = loadLibrary(fullPath);
|
cannam@64
|
271 if (!handle) return 0;
|
cannam@64
|
272
|
cannam@64
|
273 VampGetPluginDescriptorFunction fn =
|
cannam@64
|
274 (VampGetPluginDescriptorFunction)lookupInLibrary
|
cannam@64
|
275 (handle, "vampGetPluginDescriptor");
|
cannam@64
|
276
|
cannam@64
|
277 if (!fn) {
|
cannam@64
|
278 unloadLibrary(handle);
|
cannam@64
|
279 return 0;
|
cannam@64
|
280 }
|
cannam@64
|
281
|
cannam@64
|
282 int index = 0;
|
cannam@64
|
283 const VampPluginDescriptor *descriptor = 0;
|
cannam@64
|
284
|
cannam@64
|
285 while ((descriptor = fn(VAMP_API_VERSION, index))) {
|
cannam@64
|
286
|
cannam@64
|
287 if (string(descriptor->identifier) == identifier) {
|
cannam@64
|
288
|
cannam@64
|
289 Vamp::PluginHostAdapter *plugin =
|
cannam@64
|
290 new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
|
cannam@64
|
291
|
cannam@64
|
292 Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this);
|
cannam@64
|
293
|
cannam@64
|
294 m_pluginLibraryHandleMap[adapter] = handle;
|
cannam@64
|
295
|
cannam@64
|
296 if (adapterFlags & ADAPT_INPUT_DOMAIN) {
|
cannam@64
|
297 if (adapter->getInputDomain() == Plugin::FrequencyDomain) {
|
cannam@64
|
298 adapter = new PluginInputDomainAdapter(adapter);
|
cannam@64
|
299 }
|
cannam@64
|
300 }
|
cannam@64
|
301
|
cannam@64
|
302 if (adapterFlags & ADAPT_CHANNEL_COUNT) {
|
cannam@64
|
303 adapter = new PluginChannelAdapter(adapter);
|
cannam@64
|
304 }
|
cannam@64
|
305
|
cannam@64
|
306 return adapter;
|
cannam@64
|
307 }
|
cannam@64
|
308
|
cannam@64
|
309 ++index;
|
cannam@64
|
310 }
|
cannam@64
|
311
|
cannam@64
|
312 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
|
cannam@64
|
313 << identifier << "\" not found in library \""
|
cannam@64
|
314 << fullPath << "\"" << endl;
|
cannam@64
|
315
|
cannam@64
|
316 return 0;
|
cannam@64
|
317 }
|
cannam@64
|
318
|
cannam@64
|
319 void
|
cannam@69
|
320 PluginLoader::Impl::generateTaxonomy()
|
cannam@64
|
321 {
|
cannam@69
|
322 // cerr << "PluginLoader::Impl::generateTaxonomy" << endl;
|
cannam@64
|
323
|
cannam@64
|
324 vector<string> path = PluginHostAdapter::getPluginPath();
|
cannam@64
|
325 string libfragment = "/lib/";
|
cannam@64
|
326 vector<string> catpath;
|
cannam@64
|
327
|
cannam@64
|
328 string suffix = "cat";
|
cannam@64
|
329
|
cannam@64
|
330 for (vector<string>::iterator i = path.begin();
|
cannam@64
|
331 i != path.end(); ++i) {
|
cannam@64
|
332
|
cannam@64
|
333 // It doesn't matter that we're using literal forward-slash in
|
cannam@64
|
334 // this bit, as it's only relevant if the path contains
|
cannam@64
|
335 // "/lib/", which is only meaningful and only plausible on
|
cannam@64
|
336 // systems with forward-slash delimiters
|
cannam@64
|
337
|
cannam@64
|
338 string dir = *i;
|
cannam@64
|
339 string::size_type li = dir.find(libfragment);
|
cannam@64
|
340
|
cannam@64
|
341 if (li != string::npos) {
|
cannam@64
|
342 catpath.push_back
|
cannam@64
|
343 (dir.substr(0, li)
|
cannam@64
|
344 + "/share/"
|
cannam@64
|
345 + dir.substr(li + libfragment.length()));
|
cannam@64
|
346 }
|
cannam@64
|
347
|
cannam@64
|
348 catpath.push_back(dir);
|
cannam@64
|
349 }
|
cannam@64
|
350
|
cannam@64
|
351 char buffer[1024];
|
cannam@64
|
352
|
cannam@64
|
353 for (vector<string>::iterator i = catpath.begin();
|
cannam@64
|
354 i != catpath.end(); ++i) {
|
cannam@64
|
355
|
cannam@64
|
356 vector<string> files = listFiles(*i, suffix);
|
cannam@64
|
357
|
cannam@64
|
358 for (vector<string>::iterator fi = files.begin();
|
cannam@64
|
359 fi != files.end(); ++fi) {
|
cannam@64
|
360
|
cannam@64
|
361 string filepath = splicePath(*i, *fi);
|
cannam@64
|
362 ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
|
cannam@64
|
363
|
cannam@64
|
364 if (is.fail()) {
|
cannam@64
|
365 // cerr << "failed to open: " << filepath << endl;
|
cannam@64
|
366 continue;
|
cannam@64
|
367 }
|
cannam@64
|
368
|
cannam@64
|
369 // cerr << "opened: " << filepath << endl;
|
cannam@64
|
370
|
cannam@64
|
371 while (!!is.getline(buffer, 1024)) {
|
cannam@64
|
372
|
cannam@64
|
373 string line(buffer);
|
cannam@64
|
374
|
cannam@64
|
375 // cerr << "line = " << line << endl;
|
cannam@64
|
376
|
cannam@64
|
377 string::size_type di = line.find("::");
|
cannam@64
|
378 if (di == string::npos) continue;
|
cannam@64
|
379
|
cannam@64
|
380 string id = line.substr(0, di);
|
cannam@64
|
381 string encodedCat = line.substr(di + 2);
|
cannam@64
|
382
|
cannam@64
|
383 if (id.substr(0, 5) != "vamp:") continue;
|
cannam@64
|
384 id = id.substr(5);
|
cannam@64
|
385
|
cannam@64
|
386 while (encodedCat.length() >= 1 &&
|
cannam@64
|
387 encodedCat[encodedCat.length()-1] == '\r') {
|
cannam@64
|
388 encodedCat = encodedCat.substr(0, encodedCat.length()-1);
|
cannam@64
|
389 }
|
cannam@64
|
390
|
cannam@64
|
391 // cerr << "id = " << id << ", cat = " << encodedCat << endl;
|
cannam@64
|
392
|
cannam@64
|
393 PluginCategoryHierarchy category;
|
cannam@64
|
394 string::size_type ai;
|
cannam@64
|
395 while ((ai = encodedCat.find(" > ")) != string::npos) {
|
cannam@64
|
396 category.push_back(encodedCat.substr(0, ai));
|
cannam@64
|
397 encodedCat = encodedCat.substr(ai + 3);
|
cannam@64
|
398 }
|
cannam@64
|
399 if (encodedCat != "") category.push_back(encodedCat);
|
cannam@64
|
400
|
cannam@64
|
401 m_taxonomy[id] = category;
|
cannam@64
|
402 }
|
cannam@64
|
403 }
|
cannam@64
|
404 }
|
cannam@64
|
405 }
|
cannam@64
|
406
|
cannam@64
|
407 void *
|
cannam@69
|
408 PluginLoader::Impl::loadLibrary(string path)
|
cannam@64
|
409 {
|
cannam@64
|
410 void *handle = 0;
|
cannam@64
|
411 #ifdef _WIN32
|
cannam@64
|
412 handle = LoadLibrary(path.c_str());
|
cannam@64
|
413 if (!handle) {
|
cannam@64
|
414 cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
|
cannam@64
|
415 << path << "\"" << endl;
|
cannam@64
|
416 }
|
cannam@64
|
417 #else
|
cannam@64
|
418 handle = dlopen(path.c_str(), RTLD_LAZY);
|
cannam@64
|
419 if (!handle) {
|
cannam@64
|
420 cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
|
cannam@64
|
421 << path << "\": " << dlerror() << endl;
|
cannam@64
|
422 }
|
cannam@64
|
423 #endif
|
cannam@64
|
424 return handle;
|
cannam@64
|
425 }
|
cannam@64
|
426
|
cannam@64
|
427 void
|
cannam@69
|
428 PluginLoader::Impl::unloadLibrary(void *handle)
|
cannam@64
|
429 {
|
cannam@64
|
430 #ifdef _WIN32
|
cannam@64
|
431 FreeLibrary((HINSTANCE)handle);
|
cannam@64
|
432 #else
|
cannam@64
|
433 dlclose(handle);
|
cannam@64
|
434 #endif
|
cannam@64
|
435 }
|
cannam@64
|
436
|
cannam@64
|
437 void *
|
cannam@69
|
438 PluginLoader::Impl::lookupInLibrary(void *handle, const char *symbol)
|
cannam@64
|
439 {
|
cannam@64
|
440 #ifdef _WIN32
|
cannam@64
|
441 return (void *)GetProcAddress((HINSTANCE)handle, symbol);
|
cannam@64
|
442 #else
|
cannam@64
|
443 return (void *)dlsym(handle, symbol);
|
cannam@64
|
444 #endif
|
cannam@64
|
445 }
|
cannam@64
|
446
|
cannam@64
|
447 string
|
cannam@69
|
448 PluginLoader::Impl::splicePath(string a, string b)
|
cannam@64
|
449 {
|
cannam@64
|
450 #ifdef _WIN32
|
cannam@64
|
451 return a + "\\" + b;
|
cannam@64
|
452 #else
|
cannam@64
|
453 return a + "/" + b;
|
cannam@64
|
454 #endif
|
cannam@64
|
455 }
|
cannam@64
|
456
|
cannam@64
|
457 vector<string>
|
cannam@69
|
458 PluginLoader::Impl::listFiles(string dir, string extension)
|
cannam@64
|
459 {
|
cannam@64
|
460 vector<string> files;
|
cannam@64
|
461 size_t extlen = extension.length();
|
cannam@64
|
462
|
cannam@64
|
463 #ifdef _WIN32
|
cannam@64
|
464
|
cannam@64
|
465 string expression = dir + "\\*." + extension;
|
cannam@64
|
466 WIN32_FIND_DATA data;
|
cannam@64
|
467 HANDLE fh = FindFirstFile(expression.c_str(), &data);
|
cannam@64
|
468 if (fh == INVALID_HANDLE_VALUE) return files;
|
cannam@64
|
469
|
cannam@64
|
470 bool ok = true;
|
cannam@64
|
471 while (ok) {
|
cannam@64
|
472 files.push_back(data.cFileName);
|
cannam@64
|
473 ok = FindNextFile(fh, &data);
|
cannam@64
|
474 }
|
cannam@64
|
475
|
cannam@64
|
476 FindClose(fh);
|
cannam@64
|
477
|
cannam@64
|
478 #else
|
cannam@64
|
479 DIR *d = opendir(dir.c_str());
|
cannam@64
|
480 if (!d) return files;
|
cannam@64
|
481
|
cannam@64
|
482 struct dirent *e = 0;
|
cannam@64
|
483 while ((e = readdir(d))) {
|
cannam@64
|
484
|
cannam@64
|
485 if (!(e->d_type & DT_REG) || !e->d_name) continue;
|
cannam@64
|
486
|
cannam@64
|
487 size_t len = strlen(e->d_name);
|
cannam@64
|
488 if (len < extlen + 2 ||
|
cannam@64
|
489 e->d_name + len - extlen - 1 != "." + extension) {
|
cannam@64
|
490 continue;
|
cannam@64
|
491 }
|
cannam@64
|
492
|
cannam@64
|
493 files.push_back(e->d_name);
|
cannam@64
|
494 }
|
cannam@64
|
495
|
cannam@64
|
496 closedir(d);
|
cannam@64
|
497 #endif
|
cannam@64
|
498
|
cannam@64
|
499 return files;
|
cannam@64
|
500 }
|
cannam@64
|
501
|
cannam@64
|
502 void
|
cannam@69
|
503 PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
|
cannam@64
|
504 {
|
cannam@64
|
505 void *handle = m_pluginLibraryHandleMap[adapter];
|
cannam@64
|
506 if (handle) unloadLibrary(handle);
|
cannam@64
|
507 m_pluginLibraryHandleMap.erase(adapter);
|
cannam@64
|
508 }
|
cannam@64
|
509
|
cannam@69
|
510 PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
|
cannam@69
|
511 Impl *loader) :
|
cannam@64
|
512 PluginWrapper(plugin),
|
cannam@64
|
513 m_loader(loader)
|
cannam@64
|
514 {
|
cannam@64
|
515 }
|
cannam@64
|
516
|
cannam@69
|
517 PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
|
cannam@64
|
518 {
|
cannam@64
|
519 // We need to delete the plugin before calling pluginDeleted, as
|
cannam@64
|
520 // the delete call may require calling through to the descriptor
|
cannam@64
|
521 // (for e.g. cleanup) but pluginDeleted may unload the required
|
cannam@64
|
522 // library for the call. To prevent a double deletion when our
|
cannam@64
|
523 // parent's destructor runs (after this one), be sure to set
|
cannam@64
|
524 // m_plugin to 0 after deletion.
|
cannam@64
|
525 delete m_plugin;
|
cannam@64
|
526 m_plugin = 0;
|
cannam@64
|
527
|
cannam@64
|
528 if (m_loader) m_loader->pluginDeleted(this);
|
cannam@64
|
529 }
|
cannam@64
|
530
|
cannam@64
|
531 }
|
cannam@64
|
532
|
cannam@64
|
533 }
|