annotate src/vamp-hostsdk/PluginLoader.cpp @ 331:9648ba9812d6

Apply vamp-2.3-windows-unicode.patch from RJ Ryan in #464
author Chris Cannam
date Thu, 24 May 2012 16:38:09 +0100
parents 0e08ebd5c13b
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