annotate src/vamp-hostsdk/PluginLoader.cpp @ 354:e85513153c71

Initialise rate to 0. Otherwise there's a danger plugins will change the SampleType (e.g. to VariableSampleRate) but not set the rate because they don't think they need it (when in fact it needs to be set to 0)
author Chris Cannam
date Thu, 28 Mar 2013 15:49:17 +0000
parents 9648ba9812d6
children 06988ce35ff0
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@290 9 Copyright 2006-2009 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@293 273 if (forPlugin != "") {
cannam@293 274 cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
cannam@293 275 << fullPath << "\"" << endl;
cannam@293 276 }
cannam@233 277 unloadLibrary(handle);
cannam@233 278 continue;
cannam@233 279 }
cannam@233 280
cannam@233 281 int index = 0;
cannam@233 282 const VampPluginDescriptor *descriptor = 0;
cannam@295 283 bool found = false;
cannam@233 284
cannam@233 285 while ((descriptor = fn(VAMP_API_VERSION, index))) {
cannam@233 286 ++index;
cannam@233 287 if (identifier != "") {
cannam@233 288 if (descriptor->identifier != identifier) continue;
cannam@233 289 }
cannam@295 290 found = true;
cannam@233 291 PluginKey key = composePluginKey(*fi, descriptor->identifier);
cannam@233 292 // std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl;
cannam@233 293 if (m_pluginLibraryNameMap.find(key) ==
cannam@233 294 m_pluginLibraryNameMap.end()) {
cannam@233 295 m_pluginLibraryNameMap[key] = fullPath;
cannam@233 296 }
cannam@233 297 }
cannam@295 298
cannam@295 299 if (!found && forPlugin != "") {
cannam@295 300 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
cannam@295 301 << identifier << "\" not found in library \""
cannam@295 302 << fullPath << "\"" << endl;
cannam@295 303 }
cannam@233 304
cannam@233 305 unloadLibrary(handle);
cannam@233 306 }
cannam@233 307 }
cannam@233 308
cannam@233 309 if (forPlugin == "") m_allPluginsEnumerated = true;
cannam@233 310 }
cannam@233 311
cannam@233 312 PluginLoader::PluginKey
cannam@233 313 PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
cannam@233 314 {
cannam@233 315 string basename = libraryName;
cannam@233 316
cannam@233 317 string::size_type li = basename.rfind('/');
cannam@233 318 if (li != string::npos) basename = basename.substr(li + 1);
cannam@233 319
cannam@233 320 li = basename.find('.');
cannam@233 321 if (li != string::npos) basename = basename.substr(0, li);
cannam@233 322
cannam@233 323 for (size_t i = 0; i < basename.length(); ++i) {
cannam@233 324 basename[i] = tolower(basename[i]);
cannam@233 325 }
cannam@233 326
cannam@233 327 return basename + ":" + identifier;
cannam@233 328 }
cannam@233 329
cannam@233 330 bool
cannam@233 331 PluginLoader::Impl::decomposePluginKey(PluginKey key,
cannam@233 332 string &libraryName,
cannam@233 333 string &identifier)
cannam@233 334 {
cannam@233 335 string::size_type ki = key.find(':');
cannam@233 336 if (ki == string::npos) {
cannam@233 337 return false;
cannam@233 338 }
cannam@233 339
cannam@233 340 libraryName = key.substr(0, ki);
cannam@233 341 identifier = key.substr(ki + 1);
cannam@233 342 return true;
cannam@233 343 }
cannam@233 344
cannam@233 345 PluginLoader::PluginCategoryHierarchy
cannam@233 346 PluginLoader::Impl::getPluginCategory(PluginKey plugin)
cannam@233 347 {
cannam@233 348 if (m_taxonomy.empty()) generateTaxonomy();
cannam@233 349 if (m_taxonomy.find(plugin) == m_taxonomy.end()) {
cannam@233 350 return PluginCategoryHierarchy();
cannam@233 351 }
cannam@233 352 return m_taxonomy[plugin];
cannam@233 353 }
cannam@233 354
cannam@233 355 string
cannam@233 356 PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
cannam@233 357 {
cannam@233 358 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cannam@233 359 if (m_allPluginsEnumerated) return "";
cannam@233 360 enumeratePlugins(plugin);
cannam@233 361 }
cannam@233 362 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cannam@233 363 return "";
cannam@233 364 }
cannam@233 365 return m_pluginLibraryNameMap[plugin];
cannam@233 366 }
cannam@233 367
cannam@233 368 Plugin *
cannam@233 369 PluginLoader::Impl::loadPlugin(PluginKey key,
cannam@233 370 float inputSampleRate, int adapterFlags)
cannam@233 371 {
cannam@233 372 string libname, identifier;
cannam@233 373 if (!decomposePluginKey(key, libname, identifier)) {
cannam@233 374 std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \""
cannam@233 375 << key << "\" in loadPlugin" << std::endl;
cannam@233 376 return 0;
cannam@233 377 }
cannam@233 378
cannam@233 379 string fullPath = getLibraryPathForPlugin(key);
cannam@293 380 if (fullPath == "") {
cannam@295 381 std::cerr << "Vamp::HostExt::PluginLoader: No library found in Vamp path for plugin \"" << key << "\"" << std::endl;
cannam@293 382 return 0;
cannam@293 383 }
cannam@233 384
cannam@233 385 void *handle = loadLibrary(fullPath);
cannam@233 386 if (!handle) return 0;
cannam@233 387
cannam@233 388 VampGetPluginDescriptorFunction fn =
cannam@233 389 (VampGetPluginDescriptorFunction)lookupInLibrary
cannam@233 390 (handle, "vampGetPluginDescriptor");
cannam@233 391
cannam@233 392 if (!fn) {
cannam@293 393 cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
cannam@293 394 << fullPath << "\"" << endl;
cannam@233 395 unloadLibrary(handle);
cannam@233 396 return 0;
cannam@233 397 }
cannam@233 398
cannam@233 399 int index = 0;
cannam@233 400 const VampPluginDescriptor *descriptor = 0;
cannam@233 401
cannam@233 402 while ((descriptor = fn(VAMP_API_VERSION, index))) {
cannam@233 403
cannam@233 404 if (string(descriptor->identifier) == identifier) {
cannam@233 405
cannam@233 406 Vamp::PluginHostAdapter *plugin =
cannam@233 407 new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
cannam@233 408
cannam@233 409 Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this);
cannam@233 410
cannam@233 411 m_pluginLibraryHandleMap[adapter] = handle;
cannam@233 412
cannam@233 413 if (adapterFlags & ADAPT_INPUT_DOMAIN) {
cannam@233 414 if (adapter->getInputDomain() == Plugin::FrequencyDomain) {
cannam@233 415 adapter = new PluginInputDomainAdapter(adapter);
cannam@233 416 }
cannam@233 417 }
cannam@233 418
cannam@233 419 if (adapterFlags & ADAPT_BUFFER_SIZE) {
cannam@233 420 adapter = new PluginBufferingAdapter(adapter);
cannam@233 421 }
cannam@233 422
cannam@233 423 if (adapterFlags & ADAPT_CHANNEL_COUNT) {
cannam@233 424 adapter = new PluginChannelAdapter(adapter);
cannam@233 425 }
cannam@233 426
cannam@233 427 return adapter;
cannam@233 428 }
cannam@233 429
cannam@233 430 ++index;
cannam@233 431 }
cannam@233 432
cannam@233 433 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
cannam@233 434 << identifier << "\" not found in library \""
cannam@233 435 << fullPath << "\"" << endl;
cannam@233 436
cannam@233 437 return 0;
cannam@233 438 }
cannam@233 439
cannam@233 440 void
cannam@233 441 PluginLoader::Impl::generateTaxonomy()
cannam@233 442 {
cannam@233 443 // cerr << "PluginLoader::Impl::generateTaxonomy" << endl;
cannam@233 444
cannam@233 445 vector<string> path = PluginHostAdapter::getPluginPath();
cannam@233 446 string libfragment = "/lib/";
cannam@233 447 vector<string> catpath;
cannam@233 448
cannam@233 449 string suffix = "cat";
cannam@233 450
cannam@233 451 for (vector<string>::iterator i = path.begin();
cannam@233 452 i != path.end(); ++i) {
cannam@233 453
cannam@233 454 // It doesn't matter that we're using literal forward-slash in
cannam@233 455 // this bit, as it's only relevant if the path contains
cannam@233 456 // "/lib/", which is only meaningful and only plausible on
cannam@233 457 // systems with forward-slash delimiters
cannam@233 458
cannam@233 459 string dir = *i;
cannam@233 460 string::size_type li = dir.find(libfragment);
cannam@233 461
cannam@233 462 if (li != string::npos) {
cannam@233 463 catpath.push_back
cannam@233 464 (dir.substr(0, li)
cannam@233 465 + "/share/"
cannam@233 466 + dir.substr(li + libfragment.length()));
cannam@233 467 }
cannam@233 468
cannam@233 469 catpath.push_back(dir);
cannam@233 470 }
cannam@233 471
cannam@233 472 char buffer[1024];
cannam@233 473
cannam@233 474 for (vector<string>::iterator i = catpath.begin();
cannam@233 475 i != catpath.end(); ++i) {
cannam@233 476
cannam@233 477 vector<string> files = listFiles(*i, suffix);
cannam@233 478
cannam@233 479 for (vector<string>::iterator fi = files.begin();
cannam@233 480 fi != files.end(); ++fi) {
cannam@233 481
cannam@233 482 string filepath = splicePath(*i, *fi);
cannam@233 483 ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
cannam@233 484
cannam@233 485 if (is.fail()) {
cannam@233 486 // cerr << "failed to open: " << filepath << endl;
cannam@233 487 continue;
cannam@233 488 }
cannam@233 489
cannam@233 490 // cerr << "opened: " << filepath << endl;
cannam@233 491
cannam@233 492 while (!!is.getline(buffer, 1024)) {
cannam@233 493
cannam@233 494 string line(buffer);
cannam@233 495
cannam@233 496 // cerr << "line = " << line << endl;
cannam@233 497
cannam@233 498 string::size_type di = line.find("::");
cannam@233 499 if (di == string::npos) continue;
cannam@233 500
cannam@233 501 string id = line.substr(0, di);
cannam@233 502 string encodedCat = line.substr(di + 2);
cannam@233 503
cannam@233 504 if (id.substr(0, 5) != "vamp:") continue;
cannam@233 505 id = id.substr(5);
cannam@233 506
cannam@233 507 while (encodedCat.length() >= 1 &&
cannam@233 508 encodedCat[encodedCat.length()-1] == '\r') {
cannam@233 509 encodedCat = encodedCat.substr(0, encodedCat.length()-1);
cannam@233 510 }
cannam@233 511
cannam@233 512 // cerr << "id = " << id << ", cat = " << encodedCat << endl;
cannam@233 513
cannam@233 514 PluginCategoryHierarchy category;
cannam@233 515 string::size_type ai;
cannam@233 516 while ((ai = encodedCat.find(" > ")) != string::npos) {
cannam@233 517 category.push_back(encodedCat.substr(0, ai));
cannam@233 518 encodedCat = encodedCat.substr(ai + 3);
cannam@233 519 }
cannam@233 520 if (encodedCat != "") category.push_back(encodedCat);
cannam@233 521
cannam@233 522 m_taxonomy[id] = category;
cannam@233 523 }
cannam@233 524 }
cannam@233 525 }
cannam@233 526 }
cannam@233 527
cannam@233 528 void *
cannam@233 529 PluginLoader::Impl::loadLibrary(string path)
cannam@233 530 {
cannam@233 531 void *handle = 0;
cannam@233 532 #ifdef _WIN32
cannam@284 533 #ifdef UNICODE
Chris@331 534 int len = path.length() + 1; // cannot be more wchars than length in bytes of utf8 string
cannam@284 535 wchar_t *buffer = new wchar_t[len];
cannam@284 536 int rv = MultiByteToWideChar(CP_UTF8, 0, path.c_str(), len, buffer, len);
cannam@284 537 if (rv <= 0) {
cannam@284 538 cerr << "Vamp::HostExt::PluginLoader: Unable to convert library path \""
cannam@284 539 << path << "\" to wide characters " << endl;
cannam@284 540 delete[] buffer;
cannam@284 541 return handle;
cannam@284 542 }
cannam@284 543 handle = LoadLibrary(buffer);
cannam@284 544 delete[] buffer;
cannam@284 545 #else
cannam@233 546 handle = LoadLibrary(path.c_str());
cannam@284 547 #endif
cannam@233 548 if (!handle) {
cannam@233 549 cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
cannam@233 550 << path << "\"" << endl;
cannam@233 551 }
cannam@233 552 #else
cannam@233 553 handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
cannam@233 554 if (!handle) {
cannam@233 555 cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
cannam@233 556 << path << "\": " << dlerror() << endl;
cannam@233 557 }
cannam@233 558 #endif
cannam@233 559 return handle;
cannam@233 560 }
cannam@233 561
cannam@233 562 void
cannam@233 563 PluginLoader::Impl::unloadLibrary(void *handle)
cannam@233 564 {
cannam@233 565 #ifdef _WIN32
cannam@233 566 FreeLibrary((HINSTANCE)handle);
cannam@233 567 #else
cannam@233 568 dlclose(handle);
cannam@233 569 #endif
cannam@233 570 }
cannam@233 571
cannam@233 572 void *
cannam@233 573 PluginLoader::Impl::lookupInLibrary(void *handle, const char *symbol)
cannam@233 574 {
cannam@233 575 #ifdef _WIN32
cannam@233 576 return (void *)GetProcAddress((HINSTANCE)handle, symbol);
cannam@233 577 #else
cannam@233 578 return (void *)dlsym(handle, symbol);
cannam@233 579 #endif
cannam@233 580 }
cannam@233 581
cannam@233 582 string
cannam@233 583 PluginLoader::Impl::splicePath(string a, string b)
cannam@233 584 {
cannam@233 585 #ifdef _WIN32
cannam@233 586 return a + "\\" + b;
cannam@233 587 #else
cannam@233 588 return a + "/" + b;
cannam@233 589 #endif
cannam@233 590 }
cannam@233 591
cannam@233 592 vector<string>
cannam@233 593 PluginLoader::Impl::listFiles(string dir, string extension)
cannam@233 594 {
cannam@233 595 vector<string> files;
cannam@233 596
cannam@233 597 #ifdef _WIN32
cannam@284 598 string expression = dir + "\\*." + extension;
cannam@284 599 #ifdef UNICODE
Chris@331 600 int len = expression.length() + 1; // cannot be more wchars than length in bytes of utf8 string
cannam@284 601 wchar_t *buffer = new wchar_t[len];
cannam@284 602 int rv = MultiByteToWideChar(CP_UTF8, 0, expression.c_str(), len, buffer, len);
cannam@284 603 if (rv <= 0) {
cannam@284 604 cerr << "Vamp::HostExt::PluginLoader: Unable to convert wildcard path \""
cannam@284 605 << expression << "\" to wide characters" << endl;
cannam@284 606 delete[] buffer;
cannam@284 607 return files;
cannam@284 608 }
cannam@284 609 WIN32_FIND_DATA data;
cannam@284 610 HANDLE fh = FindFirstFile(buffer, &data);
cannam@284 611 if (fh == INVALID_HANDLE_VALUE) {
cannam@284 612 delete[] buffer;
cannam@284 613 return files;
cannam@284 614 }
cannam@233 615
cannam@284 616 bool ok = true;
cannam@284 617 while (ok) {
cannam@284 618 wchar_t *fn = data.cFileName;
Chris@331 619 int wlen = wcslen(fn) + 1;
cannam@284 620 int maxlen = wlen * 6;
cannam@284 621 char *conv = new char[maxlen];
cannam@284 622 int rv = WideCharToMultiByte(CP_UTF8, 0, fn, wlen, conv, maxlen, 0, 0);
cannam@284 623 if (rv > 0) {
cannam@284 624 files.push_back(conv);
cannam@284 625 }
cannam@284 626 delete[] conv;
cannam@284 627 ok = FindNextFile(fh, &data);
cannam@284 628 }
cannam@284 629
cannam@284 630 FindClose(fh);
cannam@284 631 delete[] buffer;
cannam@284 632 #else
cannam@233 633 WIN32_FIND_DATA data;
cannam@233 634 HANDLE fh = FindFirstFile(expression.c_str(), &data);
cannam@233 635 if (fh == INVALID_HANDLE_VALUE) return files;
cannam@233 636
cannam@233 637 bool ok = true;
cannam@233 638 while (ok) {
cannam@233 639 files.push_back(data.cFileName);
cannam@233 640 ok = FindNextFile(fh, &data);
cannam@233 641 }
cannam@233 642
cannam@233 643 FindClose(fh);
cannam@284 644 #endif
cannam@233 645 #else
cannam@233 646
cannam@233 647 size_t extlen = extension.length();
cannam@233 648 DIR *d = opendir(dir.c_str());
cannam@233 649 if (!d) return files;
cannam@233 650
cannam@233 651 struct dirent *e = 0;
cannam@233 652 while ((e = readdir(d))) {
cannam@233 653
cannam@233 654 if (!e->d_name) continue;
cannam@233 655
cannam@233 656 size_t len = strlen(e->d_name);
cannam@233 657 if (len < extlen + 2 ||
cannam@233 658 e->d_name + len - extlen - 1 != "." + extension) {
cannam@233 659 continue;
cannam@233 660 }
cannam@233 661
cannam@233 662 files.push_back(e->d_name);
cannam@233 663 }
cannam@233 664
cannam@233 665 closedir(d);
cannam@233 666 #endif
cannam@233 667
cannam@233 668 return files;
cannam@233 669 }
cannam@233 670
cannam@233 671 void
cannam@233 672 PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
cannam@233 673 {
cannam@233 674 void *handle = m_pluginLibraryHandleMap[adapter];
cannam@233 675 if (handle) unloadLibrary(handle);
cannam@233 676 m_pluginLibraryHandleMap.erase(adapter);
cannam@233 677 }
cannam@233 678
cannam@233 679 PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
cannam@233 680 Impl *loader) :
cannam@233 681 PluginWrapper(plugin),
cannam@233 682 m_loader(loader)
cannam@233 683 {
cannam@233 684 }
cannam@233 685
cannam@233 686 PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
cannam@233 687 {
cannam@233 688 // We need to delete the plugin before calling pluginDeleted, as
cannam@233 689 // the delete call may require calling through to the descriptor
cannam@233 690 // (for e.g. cleanup) but pluginDeleted may unload the required
cannam@233 691 // library for the call. To prevent a double deletion when our
cannam@233 692 // parent's destructor runs (after this one), be sure to set
cannam@233 693 // m_plugin to 0 after deletion.
cannam@233 694 delete m_plugin;
cannam@233 695 m_plugin = 0;
cannam@233 696
cannam@233 697 if (m_loader) m_loader->pluginDeleted(this);
cannam@233 698 }
cannam@233 699
cannam@233 700 }
cannam@233 701
cannam@233 702 }
cannam@263 703
cannam@263 704 _VAMP_SDK_HOSTSPACE_END(PluginLoader.cpp)
cannam@263 705