annotate vamp-sdk/hostext/PluginLoader.cpp @ 211:caa9d07bb9bd

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