annotate src/vamp-hostsdk/PluginLoader.cpp @ 287:f3b1ba71a305

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