annotate vamp-sdk/hostext/PluginLoader.cpp @ 98:896a97349ac5

* Add a static wrapper object to wrap the static instance pointer, so that it can be properly deleted on program exit instead of showing up in certain tools as leaked
author cannam
date Mon, 03 Dec 2007 12:57:27 +0000
parents ca44b3594d2e
children 44e6b94c2696
rev   line source
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@71 9 Copyright 2006-2007 Chris Cannam and QMUL.
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@92 41 #include "PluginBufferingAdapter.h"
cannam@64 42
cannam@64 43 #include <fstream>
cannam@75 44 #include <cctype> // tolower
cannam@64 45
cannam@64 46 #ifdef _WIN32
cannam@64 47
cannam@64 48 #include <windows.h>
cannam@64 49 #include <tchar.h>
cannam@64 50 #define PLUGIN_SUFFIX "dll"
cannam@64 51
cannam@64 52 #else /* ! _WIN32 */
cannam@64 53
cannam@64 54 #include <dirent.h>
cannam@64 55 #include <dlfcn.h>
cannam@64 56
cannam@64 57 #ifdef __APPLE__
cannam@64 58 #define PLUGIN_SUFFIX "dylib"
cannam@64 59 #else /* ! __APPLE__ */
cannam@64 60 #define PLUGIN_SUFFIX "so"
cannam@64 61 #endif /* ! __APPLE__ */
cannam@64 62
cannam@64 63 #endif /* ! _WIN32 */
cannam@64 64
cannam@64 65 using namespace std;
cannam@64 66
cannam@64 67 namespace Vamp {
cannam@64 68
cannam@64 69 namespace HostExt {
cannam@64 70
cannam@69 71 class PluginLoader::Impl
cannam@69 72 {
cannam@69 73 public:
cannam@72 74 Impl();
cannam@72 75 virtual ~Impl();
cannam@69 76
cannam@69 77 PluginKeyList listPlugins();
cannam@69 78
cannam@69 79 Plugin *loadPlugin(PluginKey key,
cannam@69 80 float inputSampleRate,
cannam@69 81 int adapterFlags);
cannam@69 82
cannam@69 83 PluginKey composePluginKey(string libraryName, string identifier);
cannam@69 84
cannam@69 85 PluginCategoryHierarchy getPluginCategory(PluginKey key);
cannam@69 86
cannam@72 87 string getLibraryPathForPlugin(PluginKey key);
cannam@69 88
cannam@98 89 static void setInstanceToClean(PluginLoader *instance);
cannam@98 90
cannam@69 91 protected:
cannam@69 92 class PluginDeletionNotifyAdapter : public PluginWrapper {
cannam@69 93 public:
cannam@69 94 PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader);
cannam@69 95 virtual ~PluginDeletionNotifyAdapter();
cannam@69 96 protected:
cannam@69 97 Impl *m_loader;
cannam@69 98 };
cannam@69 99
cannam@98 100 class InstanceCleaner {
cannam@98 101 public:
cannam@98 102 InstanceCleaner() : m_instance(0) { }
cannam@98 103 ~InstanceCleaner() { delete m_instance; }
cannam@98 104 void setInstance(PluginLoader *instance) { m_instance = instance; }
cannam@98 105 protected:
cannam@98 106 PluginLoader *m_instance;
cannam@98 107 };
cannam@98 108
cannam@69 109 virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter);
cannam@69 110
cannam@72 111 map<PluginKey, string> m_pluginLibraryNameMap;
cannam@72 112 bool m_allPluginsEnumerated;
cannam@72 113 void enumeratePlugins(PluginKey forPlugin = "");
cannam@69 114
cannam@72 115 map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
cannam@69 116 void generateTaxonomy();
cannam@69 117
cannam@72 118 map<Plugin *, void *> m_pluginLibraryHandleMap;
cannam@69 119
cannam@72 120 bool decomposePluginKey(PluginKey key,
cannam@72 121 string &libraryName, string &identifier);
cannam@72 122
cannam@72 123 void *loadLibrary(string path);
cannam@69 124 void unloadLibrary(void *handle);
cannam@69 125 void *lookupInLibrary(void *handle, const char *symbol);
cannam@69 126
cannam@72 127 string splicePath(string a, string b);
cannam@72 128 vector<string> listFiles(string dir, string ext);
cannam@98 129
cannam@98 130 static InstanceCleaner m_cleaner;
cannam@69 131 };
cannam@69 132
cannam@64 133 PluginLoader *
cannam@64 134 PluginLoader::m_instance = 0;
cannam@64 135
cannam@98 136 PluginLoader::Impl::InstanceCleaner
cannam@98 137 PluginLoader::Impl::m_cleaner;
cannam@98 138
cannam@64 139 PluginLoader::PluginLoader()
cannam@64 140 {
cannam@69 141 m_impl = new Impl();
cannam@64 142 }
cannam@64 143
cannam@64 144 PluginLoader::~PluginLoader()
cannam@64 145 {
cannam@69 146 delete m_impl;
cannam@64 147 }
cannam@64 148
cannam@64 149 PluginLoader *
cannam@64 150 PluginLoader::getInstance()
cannam@64 151 {
cannam@98 152 if (!m_instance) {
cannam@98 153 // The cleaner doesn't own the instance, because we leave the
cannam@98 154 // instance pointer in the base class for binary backwards
cannam@98 155 // compatibility reasons and to avoid waste
cannam@98 156 m_instance = new PluginLoader();
cannam@98 157 Impl::setInstanceToClean(m_instance);
cannam@98 158 }
cannam@64 159 return m_instance;
cannam@64 160 }
cannam@64 161
cannam@64 162 vector<PluginLoader::PluginKey>
cannam@64 163 PluginLoader::listPlugins()
cannam@64 164 {
cannam@69 165 return m_impl->listPlugins();
cannam@69 166 }
cannam@69 167
cannam@69 168 Plugin *
cannam@69 169 PluginLoader::loadPlugin(PluginKey key,
cannam@69 170 float inputSampleRate,
cannam@69 171 int adapterFlags)
cannam@69 172 {
cannam@69 173 return m_impl->loadPlugin(key, inputSampleRate, adapterFlags);
cannam@69 174 }
cannam@69 175
cannam@69 176 PluginLoader::PluginKey
cannam@69 177 PluginLoader::composePluginKey(string libraryName, string identifier)
cannam@69 178 {
cannam@69 179 return m_impl->composePluginKey(libraryName, identifier);
cannam@69 180 }
cannam@69 181
cannam@69 182 PluginLoader::PluginCategoryHierarchy
cannam@69 183 PluginLoader::getPluginCategory(PluginKey key)
cannam@69 184 {
cannam@69 185 return m_impl->getPluginCategory(key);
cannam@69 186 }
cannam@69 187
cannam@69 188 string
cannam@69 189 PluginLoader::getLibraryPathForPlugin(PluginKey key)
cannam@69 190 {
cannam@69 191 return m_impl->getLibraryPathForPlugin(key);
cannam@69 192 }
cannam@72 193
cannam@72 194 PluginLoader::Impl::Impl() :
cannam@72 195 m_allPluginsEnumerated(false)
cannam@72 196 {
cannam@72 197 }
cannam@72 198
cannam@72 199 PluginLoader::Impl::~Impl()
cannam@72 200 {
cannam@72 201 }
cannam@69 202
cannam@98 203 void
cannam@98 204 PluginLoader::Impl::setInstanceToClean(PluginLoader *instance)
cannam@98 205 {
cannam@98 206 m_cleaner.setInstance(instance);
cannam@98 207 }
cannam@98 208
cannam@69 209 vector<PluginLoader::PluginKey>
cannam@69 210 PluginLoader::Impl::listPlugins()
cannam@69 211 {
cannam@72 212 if (!m_allPluginsEnumerated) enumeratePlugins();
cannam@64 213
cannam@64 214 vector<PluginKey> plugins;
cannam@72 215 for (map<PluginKey, string>::iterator mi = m_pluginLibraryNameMap.begin();
cannam@64 216 mi != m_pluginLibraryNameMap.end(); ++mi) {
cannam@64 217 plugins.push_back(mi->first);
cannam@64 218 }
cannam@64 219
cannam@64 220 return plugins;
cannam@64 221 }
cannam@64 222
cannam@64 223 void
cannam@72 224 PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin)
cannam@64 225 {
cannam@64 226 vector<string> path = PluginHostAdapter::getPluginPath();
cannam@64 227
cannam@72 228 string libraryName, identifier;
cannam@72 229 if (forPlugin != "") {
cannam@72 230 if (!decomposePluginKey(forPlugin, libraryName, identifier)) {
cannam@72 231 std::cerr << "WARNING: Vamp::HostExt::PluginLoader: Invalid plugin key \""
cannam@72 232 << forPlugin << "\" in enumerate" << std::endl;
cannam@72 233 return;
cannam@72 234 }
cannam@72 235 }
cannam@72 236
cannam@64 237 for (size_t i = 0; i < path.size(); ++i) {
cannam@64 238
cannam@64 239 vector<string> files = listFiles(path[i], PLUGIN_SUFFIX);
cannam@64 240
cannam@64 241 for (vector<string>::iterator fi = files.begin();
cannam@64 242 fi != files.end(); ++fi) {
cannam@64 243
cannam@72 244 if (libraryName != "") {
cannam@73 245 // libraryName is lowercased and lacking an extension,
cannam@73 246 // as it came from the plugin key
cannam@73 247 string temp = *fi;
cannam@73 248 for (size_t i = 0; i < temp.length(); ++i) {
cannam@75 249 temp[i] = tolower(temp[i]);
cannam@73 250 }
cannam@73 251 string::size_type pi = temp.find('.');
cannam@72 252 if (pi == string::npos) {
cannam@73 253 if (libraryName != temp) continue;
cannam@72 254 } else {
cannam@73 255 if (libraryName != temp.substr(0, pi)) continue;
cannam@72 256 }
cannam@72 257 }
cannam@72 258
cannam@64 259 string fullPath = path[i];
cannam@64 260 fullPath = splicePath(fullPath, *fi);
cannam@64 261 void *handle = loadLibrary(fullPath);
cannam@64 262 if (!handle) continue;
cannam@64 263
cannam@64 264 VampGetPluginDescriptorFunction fn =
cannam@64 265 (VampGetPluginDescriptorFunction)lookupInLibrary
cannam@64 266 (handle, "vampGetPluginDescriptor");
cannam@64 267
cannam@64 268 if (!fn) {
cannam@64 269 unloadLibrary(handle);
cannam@64 270 continue;
cannam@64 271 }
cannam@64 272
cannam@64 273 int index = 0;
cannam@64 274 const VampPluginDescriptor *descriptor = 0;
cannam@64 275
cannam@64 276 while ((descriptor = fn(VAMP_API_VERSION, index))) {
cannam@72 277 ++index;
cannam@72 278 if (identifier != "") {
cannam@72 279 if (descriptor->identifier != identifier) continue;
cannam@72 280 }
cannam@64 281 PluginKey key = composePluginKey(*fi, descriptor->identifier);
cannam@72 282 // std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl;
cannam@64 283 if (m_pluginLibraryNameMap.find(key) ==
cannam@64 284 m_pluginLibraryNameMap.end()) {
cannam@64 285 m_pluginLibraryNameMap[key] = fullPath;
cannam@64 286 }
cannam@64 287 }
cannam@64 288
cannam@64 289 unloadLibrary(handle);
cannam@64 290 }
cannam@64 291 }
cannam@72 292
cannam@72 293 if (forPlugin == "") m_allPluginsEnumerated = true;
cannam@64 294 }
cannam@64 295
cannam@64 296 PluginLoader::PluginKey
cannam@69 297 PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
cannam@64 298 {
cannam@64 299 string basename = libraryName;
cannam@64 300
cannam@64 301 string::size_type li = basename.rfind('/');
cannam@64 302 if (li != string::npos) basename = basename.substr(li + 1);
cannam@64 303
cannam@64 304 li = basename.find('.');
cannam@64 305 if (li != string::npos) basename = basename.substr(0, li);
cannam@64 306
cannam@73 307 for (size_t i = 0; i < basename.length(); ++i) {
cannam@75 308 basename[i] = tolower(basename[i]);
cannam@73 309 }
cannam@73 310
cannam@64 311 return basename + ":" + identifier;
cannam@64 312 }
cannam@64 313
cannam@72 314 bool
cannam@72 315 PluginLoader::Impl::decomposePluginKey(PluginKey key,
cannam@72 316 string &libraryName,
cannam@72 317 string &identifier)
cannam@72 318 {
cannam@72 319 string::size_type ki = key.find(':');
cannam@72 320 if (ki == string::npos) {
cannam@72 321 return false;
cannam@72 322 }
cannam@72 323
cannam@72 324 libraryName = key.substr(0, ki);
cannam@72 325 identifier = key.substr(ki + 1);
cannam@72 326 return true;
cannam@72 327 }
cannam@72 328
cannam@64 329 PluginLoader::PluginCategoryHierarchy
cannam@69 330 PluginLoader::Impl::getPluginCategory(PluginKey plugin)
cannam@64 331 {
cannam@64 332 if (m_taxonomy.empty()) generateTaxonomy();
cannam@69 333 if (m_taxonomy.find(plugin) == m_taxonomy.end()) {
cannam@69 334 return PluginCategoryHierarchy();
cannam@69 335 }
cannam@64 336 return m_taxonomy[plugin];
cannam@64 337 }
cannam@64 338
cannam@64 339 string
cannam@69 340 PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
cannam@64 341 {
cannam@72 342 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cannam@72 343 if (m_allPluginsEnumerated) return "";
cannam@72 344 enumeratePlugins(plugin);
cannam@72 345 }
cannam@72 346 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cannam@72 347 return "";
cannam@72 348 }
cannam@64 349 return m_pluginLibraryNameMap[plugin];
cannam@64 350 }
cannam@64 351
cannam@64 352 Plugin *
cannam@69 353 PluginLoader::Impl::loadPlugin(PluginKey key,
cannam@69 354 float inputSampleRate, int adapterFlags)
cannam@64 355 {
cannam@72 356 string libname, identifier;
cannam@72 357 if (!decomposePluginKey(key, libname, identifier)) {
cannam@72 358 std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \""
cannam@72 359 << key << "\" in loadPlugin" << std::endl;
cannam@72 360 return 0;
cannam@72 361 }
cannam@72 362
cannam@64 363 string fullPath = getLibraryPathForPlugin(key);
cannam@64 364 if (fullPath == "") return 0;
cannam@64 365
cannam@64 366 void *handle = loadLibrary(fullPath);
cannam@64 367 if (!handle) return 0;
cannam@64 368
cannam@64 369 VampGetPluginDescriptorFunction fn =
cannam@64 370 (VampGetPluginDescriptorFunction)lookupInLibrary
cannam@64 371 (handle, "vampGetPluginDescriptor");
cannam@64 372
cannam@64 373 if (!fn) {
cannam@64 374 unloadLibrary(handle);
cannam@64 375 return 0;
cannam@64 376 }
cannam@64 377
cannam@64 378 int index = 0;
cannam@64 379 const VampPluginDescriptor *descriptor = 0;
cannam@64 380
cannam@64 381 while ((descriptor = fn(VAMP_API_VERSION, index))) {
cannam@64 382
cannam@64 383 if (string(descriptor->identifier) == identifier) {
cannam@64 384
cannam@64 385 Vamp::PluginHostAdapter *plugin =
cannam@64 386 new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
cannam@64 387
cannam@64 388 Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this);
cannam@64 389
cannam@64 390 m_pluginLibraryHandleMap[adapter] = handle;
cannam@64 391
cannam@64 392 if (adapterFlags & ADAPT_INPUT_DOMAIN) {
cannam@64 393 if (adapter->getInputDomain() == Plugin::FrequencyDomain) {
cannam@64 394 adapter = new PluginInputDomainAdapter(adapter);
cannam@64 395 }
cannam@64 396 }
cannam@64 397
cannam@92 398 if (adapterFlags & ADAPT_BUFFER_SIZE) {
cannam@92 399 adapter = new PluginBufferingAdapter(adapter);
cannam@92 400 }
cannam@92 401
cannam@64 402 if (adapterFlags & ADAPT_CHANNEL_COUNT) {
cannam@64 403 adapter = new PluginChannelAdapter(adapter);
cannam@64 404 }
cannam@64 405
cannam@64 406 return adapter;
cannam@64 407 }
cannam@64 408
cannam@64 409 ++index;
cannam@64 410 }
cannam@64 411
cannam@64 412 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
cannam@64 413 << identifier << "\" not found in library \""
cannam@64 414 << fullPath << "\"" << endl;
cannam@64 415
cannam@64 416 return 0;
cannam@64 417 }
cannam@64 418
cannam@64 419 void
cannam@69 420 PluginLoader::Impl::generateTaxonomy()
cannam@64 421 {
cannam@69 422 // cerr << "PluginLoader::Impl::generateTaxonomy" << endl;
cannam@64 423
cannam@64 424 vector<string> path = PluginHostAdapter::getPluginPath();
cannam@64 425 string libfragment = "/lib/";
cannam@64 426 vector<string> catpath;
cannam@64 427
cannam@64 428 string suffix = "cat";
cannam@64 429
cannam@64 430 for (vector<string>::iterator i = path.begin();
cannam@64 431 i != path.end(); ++i) {
cannam@64 432
cannam@64 433 // It doesn't matter that we're using literal forward-slash in
cannam@64 434 // this bit, as it's only relevant if the path contains
cannam@64 435 // "/lib/", which is only meaningful and only plausible on
cannam@64 436 // systems with forward-slash delimiters
cannam@64 437
cannam@64 438 string dir = *i;
cannam@64 439 string::size_type li = dir.find(libfragment);
cannam@64 440
cannam@64 441 if (li != string::npos) {
cannam@64 442 catpath.push_back
cannam@64 443 (dir.substr(0, li)
cannam@64 444 + "/share/"
cannam@64 445 + dir.substr(li + libfragment.length()));
cannam@64 446 }
cannam@64 447
cannam@64 448 catpath.push_back(dir);
cannam@64 449 }
cannam@64 450
cannam@64 451 char buffer[1024];
cannam@64 452
cannam@64 453 for (vector<string>::iterator i = catpath.begin();
cannam@64 454 i != catpath.end(); ++i) {
cannam@64 455
cannam@64 456 vector<string> files = listFiles(*i, suffix);
cannam@64 457
cannam@64 458 for (vector<string>::iterator fi = files.begin();
cannam@64 459 fi != files.end(); ++fi) {
cannam@64 460
cannam@64 461 string filepath = splicePath(*i, *fi);
cannam@64 462 ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
cannam@64 463
cannam@64 464 if (is.fail()) {
cannam@64 465 // cerr << "failed to open: " << filepath << endl;
cannam@64 466 continue;
cannam@64 467 }
cannam@64 468
cannam@64 469 // cerr << "opened: " << filepath << endl;
cannam@64 470
cannam@64 471 while (!!is.getline(buffer, 1024)) {
cannam@64 472
cannam@64 473 string line(buffer);
cannam@64 474
cannam@64 475 // cerr << "line = " << line << endl;
cannam@64 476
cannam@64 477 string::size_type di = line.find("::");
cannam@64 478 if (di == string::npos) continue;
cannam@64 479
cannam@64 480 string id = line.substr(0, di);
cannam@64 481 string encodedCat = line.substr(di + 2);
cannam@64 482
cannam@64 483 if (id.substr(0, 5) != "vamp:") continue;
cannam@64 484 id = id.substr(5);
cannam@64 485
cannam@64 486 while (encodedCat.length() >= 1 &&
cannam@64 487 encodedCat[encodedCat.length()-1] == '\r') {
cannam@64 488 encodedCat = encodedCat.substr(0, encodedCat.length()-1);
cannam@64 489 }
cannam@64 490
cannam@64 491 // cerr << "id = " << id << ", cat = " << encodedCat << endl;
cannam@64 492
cannam@64 493 PluginCategoryHierarchy category;
cannam@64 494 string::size_type ai;
cannam@64 495 while ((ai = encodedCat.find(" > ")) != string::npos) {
cannam@64 496 category.push_back(encodedCat.substr(0, ai));
cannam@64 497 encodedCat = encodedCat.substr(ai + 3);
cannam@64 498 }
cannam@64 499 if (encodedCat != "") category.push_back(encodedCat);
cannam@64 500
cannam@64 501 m_taxonomy[id] = category;
cannam@64 502 }
cannam@64 503 }
cannam@64 504 }
cannam@64 505 }
cannam@64 506
cannam@64 507 void *
cannam@69 508 PluginLoader::Impl::loadLibrary(string path)
cannam@64 509 {
cannam@64 510 void *handle = 0;
cannam@64 511 #ifdef _WIN32
cannam@64 512 handle = LoadLibrary(path.c_str());
cannam@64 513 if (!handle) {
cannam@64 514 cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
cannam@64 515 << path << "\"" << endl;
cannam@64 516 }
cannam@64 517 #else
cannam@64 518 handle = dlopen(path.c_str(), RTLD_LAZY);
cannam@64 519 if (!handle) {
cannam@64 520 cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
cannam@64 521 << path << "\": " << dlerror() << endl;
cannam@64 522 }
cannam@64 523 #endif
cannam@64 524 return handle;
cannam@64 525 }
cannam@64 526
cannam@64 527 void
cannam@69 528 PluginLoader::Impl::unloadLibrary(void *handle)
cannam@64 529 {
cannam@64 530 #ifdef _WIN32
cannam@64 531 FreeLibrary((HINSTANCE)handle);
cannam@64 532 #else
cannam@64 533 dlclose(handle);
cannam@64 534 #endif
cannam@64 535 }
cannam@64 536
cannam@64 537 void *
cannam@69 538 PluginLoader::Impl::lookupInLibrary(void *handle, const char *symbol)
cannam@64 539 {
cannam@64 540 #ifdef _WIN32
cannam@64 541 return (void *)GetProcAddress((HINSTANCE)handle, symbol);
cannam@64 542 #else
cannam@64 543 return (void *)dlsym(handle, symbol);
cannam@64 544 #endif
cannam@64 545 }
cannam@64 546
cannam@64 547 string
cannam@69 548 PluginLoader::Impl::splicePath(string a, string b)
cannam@64 549 {
cannam@64 550 #ifdef _WIN32
cannam@64 551 return a + "\\" + b;
cannam@64 552 #else
cannam@64 553 return a + "/" + b;
cannam@64 554 #endif
cannam@64 555 }
cannam@64 556
cannam@64 557 vector<string>
cannam@69 558 PluginLoader::Impl::listFiles(string dir, string extension)
cannam@64 559 {
cannam@64 560 vector<string> files;
cannam@64 561
cannam@64 562 #ifdef _WIN32
cannam@64 563
cannam@64 564 string expression = dir + "\\*." + extension;
cannam@64 565 WIN32_FIND_DATA data;
cannam@64 566 HANDLE fh = FindFirstFile(expression.c_str(), &data);
cannam@64 567 if (fh == INVALID_HANDLE_VALUE) return files;
cannam@64 568
cannam@64 569 bool ok = true;
cannam@64 570 while (ok) {
cannam@64 571 files.push_back(data.cFileName);
cannam@64 572 ok = FindNextFile(fh, &data);
cannam@64 573 }
cannam@64 574
cannam@64 575 FindClose(fh);
cannam@64 576
cannam@64 577 #else
cannam@78 578
cannam@78 579 size_t extlen = extension.length();
cannam@64 580 DIR *d = opendir(dir.c_str());
cannam@64 581 if (!d) return files;
cannam@64 582
cannam@64 583 struct dirent *e = 0;
cannam@64 584 while ((e = readdir(d))) {
cannam@97 585
cannam@97 586 if (!(e->d_type & DT_REG) && (e->d_type != DT_UNKNOWN)) continue;
cannam@64 587
cannam@97 588 if (!e->d_name) continue;
cannam@97 589
cannam@64 590 size_t len = strlen(e->d_name);
cannam@64 591 if (len < extlen + 2 ||
cannam@64 592 e->d_name + len - extlen - 1 != "." + extension) {
cannam@64 593 continue;
cannam@64 594 }
cannam@64 595
cannam@64 596 files.push_back(e->d_name);
cannam@64 597 }
cannam@64 598
cannam@64 599 closedir(d);
cannam@64 600 #endif
cannam@64 601
cannam@64 602 return files;
cannam@64 603 }
cannam@64 604
cannam@64 605 void
cannam@69 606 PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
cannam@64 607 {
cannam@64 608 void *handle = m_pluginLibraryHandleMap[adapter];
cannam@64 609 if (handle) unloadLibrary(handle);
cannam@64 610 m_pluginLibraryHandleMap.erase(adapter);
cannam@64 611 }
cannam@64 612
cannam@69 613 PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
cannam@69 614 Impl *loader) :
cannam@64 615 PluginWrapper(plugin),
cannam@64 616 m_loader(loader)
cannam@64 617 {
cannam@64 618 }
cannam@64 619
cannam@69 620 PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
cannam@64 621 {
cannam@64 622 // We need to delete the plugin before calling pluginDeleted, as
cannam@64 623 // the delete call may require calling through to the descriptor
cannam@64 624 // (for e.g. cleanup) but pluginDeleted may unload the required
cannam@64 625 // library for the call. To prevent a double deletion when our
cannam@64 626 // parent's destructor runs (after this one), be sure to set
cannam@64 627 // m_plugin to 0 after deletion.
cannam@64 628 delete m_plugin;
cannam@64 629 m_plugin = 0;
cannam@64 630
cannam@64 631 if (m_loader) m_loader->pluginDeleted(this);
cannam@64 632 }
cannam@64 633
cannam@64 634 }
cannam@64 635
cannam@64 636 }