annotate src/vamp-hostsdk/hostext/PluginLoader.cpp @ 228:e58242c9ff85 distinct-libraries

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