annotate vamp-sdk/hostext/PluginLoader.cpp @ 124:7aedffbc2088

...
author cannam
date Mon, 25 Feb 2008 17:01:40 +0000
parents 896a97349ac5
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 }