annotate plugin/FeatureExtractionPluginFactory.cpp @ 1165:d57f9344db19

Check for plugin loadability before trying to load in the main process (POSIX only so far)
author Chris Cannam
date Mon, 11 Jan 2016 14:18:56 +0000
parents 0f90a357cb2a
children 4607603c46d0
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@202 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@0 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "FeatureExtractionPluginFactory.h"
Chris@0 17 #include "PluginIdentifier.h"
Chris@0 18
Chris@475 19 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@475 20 #include <vamp-hostsdk/PluginWrapper.h>
Chris@66 21
Chris@150 22 #include "system/System.h"
Chris@66 23
Chris@66 24 #include <QDir>
Chris@66 25 #include <QFile>
Chris@66 26 #include <QFileInfo>
Chris@165 27 #include <QTextStream>
Chris@66 28
Chris@0 29 #include <iostream>
Chris@0 30
Chris@408 31 #include "base/Profiler.h"
Chris@408 32
Chris@1164 33 using namespace std;
Chris@1164 34
Chris@249 35 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1
Chris@249 36
Chris@298 37 class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper {
Chris@298 38 public:
Chris@298 39 PluginDeletionNotifyAdapter(Vamp::Plugin *plugin,
Chris@298 40 FeatureExtractionPluginFactory *factory) :
Chris@298 41 PluginWrapper(plugin), m_factory(factory) { }
Chris@298 42 virtual ~PluginDeletionNotifyAdapter();
Chris@298 43 protected:
Chris@298 44 FeatureExtractionPluginFactory *m_factory;
Chris@298 45 };
Chris@298 46
Chris@298 47 PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
Chris@298 48 {
Chris@298 49 // see notes in vamp-sdk/hostext/PluginLoader.cpp from which this is drawn
Chris@298 50 Vamp::Plugin *p = m_plugin;
Chris@298 51 delete m_plugin;
Chris@298 52 m_plugin = 0;
Chris@973 53 // acceptable use after free here, as pluginDeleted uses p only as
Chris@973 54 // pointer key and does not deref it
Chris@298 55 if (m_factory) m_factory->pluginDeleted(p);
Chris@298 56 }
Chris@298 57
Chris@0 58 static FeatureExtractionPluginFactory *_nativeInstance = 0;
Chris@0 59
Chris@0 60 FeatureExtractionPluginFactory *
Chris@0 61 FeatureExtractionPluginFactory::instance(QString pluginType)
Chris@0 62 {
Chris@71 63 if (pluginType == "vamp") {
Chris@0 64 if (!_nativeInstance) {
Chris@690 65 // SVDEBUG << "FeatureExtractionPluginFactory::instance(" << pluginType// << "): creating new FeatureExtractionPluginFactory" << endl;
Chris@0 66 _nativeInstance = new FeatureExtractionPluginFactory();
Chris@0 67 }
Chris@0 68 return _nativeInstance;
Chris@0 69 }
Chris@0 70
Chris@0 71 else return 0;
Chris@0 72 }
Chris@0 73
Chris@0 74 FeatureExtractionPluginFactory *
Chris@0 75 FeatureExtractionPluginFactory::instanceFor(QString identifier)
Chris@0 76 {
Chris@0 77 QString type, soName, label;
Chris@0 78 PluginIdentifier::parseIdentifier(identifier, type, soName, label);
Chris@0 79 return instance(type);
Chris@0 80 }
Chris@0 81
Chris@1164 82 vector<QString>
Chris@66 83 FeatureExtractionPluginFactory::getPluginPath()
Chris@66 84 {
Chris@117 85 if (!m_pluginPath.empty()) return m_pluginPath;
Chris@117 86
Chris@1164 87 vector<string> p = Vamp::PluginHostAdapter::getPluginPath();
Chris@186 88 for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str());
Chris@186 89 return m_pluginPath;
Chris@66 90 }
Chris@66 91
Chris@1164 92 vector<QString>
Chris@0 93 FeatureExtractionPluginFactory::getAllPluginIdentifiers()
Chris@0 94 {
Chris@0 95 FeatureExtractionPluginFactory *factory;
Chris@1164 96 vector<QString> rv;
Chris@0 97
Chris@66 98 factory = instance("vamp");
Chris@0 99 if (factory) {
Chris@1164 100 vector<QString> tmp = factory->getPluginIdentifiers();
Chris@0 101 for (size_t i = 0; i < tmp.size(); ++i) {
Chris@843 102 // cerr << "identifier: " << tmp[i] << endl;
Chris@0 103 rv.push_back(tmp[i]);
Chris@0 104 }
Chris@0 105 }
Chris@0 106
Chris@0 107 // Plugins can change the locale, revert it to default.
Chris@608 108 RestoreStartupLocale();
Chris@608 109
Chris@0 110 return rv;
Chris@0 111 }
Chris@0 112
Chris@1164 113 vector<QString>
Chris@1164 114 FeatureExtractionPluginFactory::getPluginCandidateFiles()
Chris@1164 115 {
Chris@1164 116 vector<QString> path = getPluginPath();
Chris@1164 117 vector<QString> candidates;
Chris@1164 118
Chris@1164 119 for (QString dirname : path) {
Chris@1164 120
Chris@1164 121 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1164 122 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << dirname << endl;
Chris@1164 123 #endif
Chris@1164 124
Chris@1164 125 QDir pluginDir(dirname, PLUGIN_GLOB,
Chris@1164 126 QDir::Name | QDir::IgnoreCase,
Chris@1164 127 QDir::Files | QDir::Readable);
Chris@1164 128
Chris@1164 129 for (unsigned int j = 0; j < pluginDir.count(); ++j) {
Chris@1164 130 QString soname = pluginDir.filePath(pluginDir[j]);
Chris@1164 131 candidates.push_back(soname);
Chris@1164 132 }
Chris@1164 133 }
Chris@1164 134
Chris@1164 135 return candidates;
Chris@1164 136 }
Chris@1164 137
Chris@1164 138 vector<QString>
Chris@1165 139 FeatureExtractionPluginFactory::winnowPluginCandidates(vector<QString> candidates)
Chris@1165 140 {
Chris@1165 141 vector<QString> good, bad;
Chris@1165 142 vector<PluginLoadStatus> badStatuses;
Chris@1165 143
Chris@1165 144 for (QString c: candidates) {
Chris@1165 145
Chris@1165 146 PluginLoadStatus status =
Chris@1165 147 TestPluginLoadability(c, "vampGetPluginDescriptor");
Chris@1165 148
Chris@1165 149 if (status == PluginLoadOK) {
Chris@1165 150 good.push_back(c);
Chris@1165 151 } else if (status == UnknownPluginLoadStatus) {
Chris@1165 152 cerr << "WARNING: Unknown load status for plugin candidate \""
Chris@1165 153 << c << "\", continuing" << endl;
Chris@1165 154 good.push_back(c);
Chris@1165 155 } else {
Chris@1165 156 bad.push_back(c);
Chris@1165 157 badStatuses.push_back(status);
Chris@1165 158 }
Chris@1165 159 }
Chris@1165 160
Chris@1165 161 if (!bad.empty()) {
Chris@1165 162 QString warningMessage = "<b>Failed to load plugins</b></p>Failed to load one or more plugin libraries:</p><ul>\n";
Chris@1165 163 for (int i = 0; i < bad.size(); ++i) {
Chris@1165 164 QString m;
Chris@1165 165 if (badStatuses[i] == PluginLoadFailedToLoadLibrary) {
Chris@1165 166 m = "Failed to load library";
Chris@1165 167 } else if (badStatuses[i] == PluginLoadFailedToFindDescriptor) {
Chris@1165 168 m = "Failed to query plugins from library after loading";
Chris@1165 169 } else if (badStatuses[i] == PluginLoadFailedElsewhere) {
Chris@1165 170 m = "Unknown failure";
Chris@1165 171 } else {
Chris@1165 172 m = "Success: internal error?";
Chris@1165 173 }
Chris@1165 174 warningMessage += QString("<li>%1 (%2)</li>\n")
Chris@1165 175 .arg(bad[i])
Chris@1165 176 .arg(m);
Chris@1165 177 }
Chris@1165 178 warningMessage += "</ul>";
Chris@1165 179 cerr << warningMessage; //!!! for now!
Chris@1165 180 }
Chris@1165 181 return good;
Chris@1165 182 }
Chris@1165 183
Chris@1165 184 vector<QString>
Chris@0 185 FeatureExtractionPluginFactory::getPluginIdentifiers()
Chris@0 186 {
Chris@408 187 Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers");
Chris@408 188
Chris@1164 189 vector<QString> rv;
Chris@1165 190 vector<QString> candidates = winnowPluginCandidates(getPluginCandidateFiles());
Chris@1165 191
Chris@1164 192 for (QString soname : candidates) {
Chris@66 193
Chris@249 194 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1164 195 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: trying potential library " << soname << endl;
Chris@249 196 #endif
Chris@66 197
Chris@1164 198 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL);
Chris@1164 199
Chris@1164 200 if (!libraryHandle) {
Chris@1164 201 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname << ": " << DLERROR() << endl;
Chris@1164 202 continue;
Chris@1164 203 }
Chris@66 204
Chris@249 205 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1164 206 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: It's a library all right, checking for descriptor" << endl;
Chris@249 207 #endif
Chris@249 208
Chris@1164 209 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@1164 210 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@1164 211
Chris@1164 212 if (!fn) {
Chris@1164 213 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname << endl;
Chris@1164 214 if (DLCLOSE(libraryHandle) != 0) {
Chris@1164 215 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl;
Chris@1164 216 }
Chris@1164 217 continue;
Chris@1164 218 }
Chris@1164 219
Chris@1164 220 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1164 221 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: Vamp descriptor found" << endl;
Chris@1164 222 #endif
Chris@1164 223
Chris@1164 224 const VampPluginDescriptor *descriptor = 0;
Chris@1164 225 int index = 0;
Chris@1164 226
Chris@1164 227 map<string, int> known;
Chris@1164 228 bool ok = true;
Chris@1164 229
Chris@1164 230 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@1164 231
Chris@1164 232 if (known.find(descriptor->identifier) != known.end()) {
Chris@1164 233 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Plugin library "
Chris@1164 234 << soname
Chris@1164 235 << " returns the same plugin identifier \""
Chris@1164 236 << descriptor->identifier << "\" at indices "
Chris@1164 237 << known[descriptor->identifier] << " and "
Chris@1164 238 << index << endl;
Chris@1164 239 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << endl;
Chris@1164 240 ok = false;
Chris@1164 241 break;
Chris@1164 242 } else {
Chris@1164 243 known[descriptor->identifier] = index;
Chris@66 244 }
Chris@66 245
Chris@1164 246 ++index;
Chris@1164 247 }
Chris@249 248
Chris@1164 249 if (ok) {
Chris@66 250
Chris@1164 251 index = 0;
Chris@251 252
Chris@239 253 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@251 254
Chris@1164 255 QString id = PluginIdentifier::createIdentifier
Chris@1164 256 ("vamp", soname, descriptor->identifier);
Chris@1164 257 rv.push_back(id);
Chris@1164 258 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1164 259 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: Found plugin id " << id << " at index " << index << endl;
Chris@1164 260 #endif
Chris@251 261 ++index;
Chris@251 262 }
Chris@1164 263 }
Chris@66 264
Chris@1164 265 if (DLCLOSE(libraryHandle) != 0) {
Chris@1164 266 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl;
Chris@1164 267 }
Chris@66 268 }
Chris@66 269
Chris@165 270 generateTaxonomy();
Chris@165 271
Chris@0 272 return rv;
Chris@0 273 }
Chris@0 274
Chris@66 275 QString
Chris@66 276 FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir)
Chris@66 277 {
Chris@66 278 QString file = "";
Chris@66 279
Chris@249 280 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 281 cerr << "FeatureExtractionPluginFactory::findPluginFile(\""
Chris@686 282 << soname << "\", \"" << inDir << "\")"
Chris@687 283 << endl;
Chris@249 284 #endif
Chris@249 285
Chris@66 286 if (inDir != "") {
Chris@66 287
Chris@66 288 QDir dir(inDir, PLUGIN_GLOB,
Chris@66 289 QDir::Name | QDir::IgnoreCase,
Chris@66 290 QDir::Files | QDir::Readable);
Chris@66 291 if (!dir.exists()) return "";
Chris@66 292
Chris@66 293 file = dir.filePath(QFileInfo(soname).fileName());
Chris@249 294
Chris@249 295 if (QFileInfo(file).exists() && QFileInfo(file).isFile()) {
Chris@249 296
Chris@249 297 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 298 cerr << "FeatureExtractionPluginFactory::findPluginFile: "
Chris@687 299 << "found trivially at " << file << endl;
Chris@249 300 #endif
Chris@249 301
Chris@66 302 return file;
Chris@66 303 }
Chris@66 304
Chris@66 305 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@66 306 file = dir.filePath(dir[j]);
Chris@66 307 if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) {
Chris@249 308
Chris@249 309 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 310 cerr << "FeatureExtractionPluginFactory::findPluginFile: "
Chris@687 311 << "found \"" << soname << "\" at " << file << endl;
Chris@249 312 #endif
Chris@249 313
Chris@66 314 return file;
Chris@66 315 }
Chris@66 316 }
Chris@66 317
Chris@249 318 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 319 cerr << "FeatureExtractionPluginFactory::findPluginFile (with dir): "
Chris@687 320 << "not found" << endl;
Chris@249 321 #endif
Chris@249 322
Chris@66 323 return "";
Chris@66 324
Chris@66 325 } else {
Chris@66 326
Chris@66 327 QFileInfo fi(soname);
Chris@249 328
Chris@249 329 if (fi.isAbsolute() && fi.exists() && fi.isFile()) {
Chris@249 330 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 331 cerr << "FeatureExtractionPluginFactory::findPluginFile: "
Chris@687 332 << "found trivially at " << soname << endl;
Chris@249 333 #endif
Chris@249 334 return soname;
Chris@249 335 }
Chris@66 336
Chris@66 337 if (fi.isAbsolute() && fi.absolutePath() != "") {
Chris@66 338 file = findPluginFile(soname, fi.absolutePath());
Chris@66 339 if (file != "") return file;
Chris@66 340 }
Chris@66 341
Chris@1164 342 vector<QString> path = getPluginPath();
Chris@1164 343 for (vector<QString>::iterator i = path.begin();
Chris@66 344 i != path.end(); ++i) {
Chris@66 345 if (*i != "") {
Chris@66 346 file = findPluginFile(soname, *i);
Chris@66 347 if (file != "") return file;
Chris@66 348 }
Chris@66 349 }
Chris@66 350
Chris@249 351 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 352 cerr << "FeatureExtractionPluginFactory::findPluginFile: "
Chris@687 353 << "not found" << endl;
Chris@249 354 #endif
Chris@249 355
Chris@66 356 return "";
Chris@66 357 }
Chris@66 358 }
Chris@66 359
Chris@66 360 Vamp::Plugin *
Chris@0 361 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier,
Chris@1040 362 sv_samplerate_t inputSampleRate)
Chris@0 363 {
Chris@408 364 Profiler profiler("FeatureExtractionPluginFactory::instantiatePlugin");
Chris@408 365
Chris@66 366 Vamp::Plugin *rv = 0;
Chris@298 367 Vamp::PluginHostAdapter *plugin = 0;
Chris@66 368
Chris@66 369 const VampPluginDescriptor *descriptor = 0;
Chris@66 370 int index = 0;
Chris@66 371
Chris@66 372 QString type, soname, label;
Chris@66 373 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@71 374 if (type != "vamp") {
Chris@1140 375 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type << endl;
Chris@0 376 return 0;
Chris@0 377 }
Chris@0 378
Chris@66 379 QString found = findPluginFile(soname);
Chris@66 380
Chris@66 381 if (found == "") {
Chris@843 382 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname << endl;
Chris@117 383 return 0;
Chris@66 384 } else if (found != soname) {
Chris@249 385
Chris@249 386 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 387 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Given library name was " << soname << ", found at " << found << endl;
Chris@843 388 cerr << soname << " -> " << found << endl;
Chris@249 389 #endif
Chris@249 390
Chris@249 391 }
Chris@0 392
Chris@66 393 soname = found;
Chris@66 394
Chris@435 395 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL);
Chris@66 396
Chris@66 397 if (!libraryHandle) {
Chris@843 398 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname << ": " << DLERROR() << endl;
Chris@66 399 return 0;
Chris@19 400 }
Chris@19 401
Chris@66 402 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@66 403 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@66 404
Chris@66 405 if (!fn) {
Chris@1140 406 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname << endl;
Chris@66 407 goto done;
Chris@0 408 }
Chris@0 409
Chris@239 410 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@238 411 if (label == descriptor->identifier) break;
Chris@66 412 ++index;
Chris@47 413 }
Chris@47 414
Chris@66 415 if (!descriptor) {
Chris@843 416 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label << "\" in library " << soname << endl;
Chris@66 417 goto done;
Martin@37 418 }
Martin@37 419
Chris@1040 420 plugin = new Vamp::PluginHostAdapter(descriptor, float(inputSampleRate));
Chris@298 421
Chris@298 422 if (plugin) {
Chris@298 423 m_handleMap[plugin] = libraryHandle;
Chris@298 424 rv = new PluginDeletionNotifyAdapter(plugin, this);
Chris@298 425 }
Chris@66 426
Chris@690 427 // SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << endl;
Chris@79 428
Chris@66 429 //!!! need to dlclose() when plugins from a given library are unloaded
Chris@66 430
Chris@66 431 done:
Chris@66 432 if (!rv) {
Chris@66 433 if (DLCLOSE(libraryHandle) != 0) {
Chris@843 434 cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname << endl;
Chris@66 435 }
Chris@66 436 }
Chris@73 437
Chris@690 438 // SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Instantiated plugin " << label << " from library " << soname << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << endl;
Chris@73 439
Chris@66 440 return rv;
Chris@0 441 }
Chris@0 442
Chris@298 443 void
Chris@298 444 FeatureExtractionPluginFactory::pluginDeleted(Vamp::Plugin *plugin)
Chris@298 445 {
Chris@298 446 void *handle = m_handleMap[plugin];
Chris@298 447 if (handle) {
Chris@690 448 // SVDEBUG << "unloading library " << handle << " for plugin " << plugin << endl;
Chris@298 449 DLCLOSE(handle);
Chris@298 450 }
Chris@298 451 m_handleMap.erase(plugin);
Chris@298 452 }
Chris@298 453
Chris@165 454 QString
Chris@165 455 FeatureExtractionPluginFactory::getPluginCategory(QString identifier)
Chris@165 456 {
Chris@165 457 return m_taxonomy[identifier];
Chris@165 458 }
Chris@165 459
Chris@165 460 void
Chris@165 461 FeatureExtractionPluginFactory::generateTaxonomy()
Chris@165 462 {
Chris@1164 463 vector<QString> pluginPath = getPluginPath();
Chris@1164 464 vector<QString> path;
Chris@165 465
Chris@165 466 for (size_t i = 0; i < pluginPath.size(); ++i) {
Chris@165 467 if (pluginPath[i].contains("/lib/")) {
Chris@165 468 QString p(pluginPath[i]);
Chris@165 469 path.push_back(p);
Chris@165 470 p.replace("/lib/", "/share/");
Chris@165 471 path.push_back(p);
Chris@165 472 }
Chris@165 473 path.push_back(pluginPath[i]);
Chris@165 474 }
Chris@165 475
Chris@165 476 for (size_t i = 0; i < path.size(); ++i) {
Chris@165 477
Chris@165 478 QDir dir(path[i], "*.cat");
Chris@165 479
Chris@690 480 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << endl;
Chris@165 481 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@165 482
Chris@165 483 QFile file(path[i] + "/" + dir[j]);
Chris@165 484
Chris@690 485 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i]+ "/" + dir[j]) << endl;
Chris@165 486
Chris@165 487 if (file.open(QIODevice::ReadOnly)) {
Chris@843 488 // cerr << "...opened" << endl;
Chris@165 489 QTextStream stream(&file);
Chris@165 490 QString line;
Chris@165 491
Chris@165 492 while (!stream.atEnd()) {
Chris@165 493 line = stream.readLine();
Chris@843 494 // cerr << "line is: \"" << line << "\"" << endl;
Chris@165 495 QString id = PluginIdentifier::canonicalise
Chris@165 496 (line.section("::", 0, 0));
Chris@165 497 QString cat = line.section("::", 1, 1);
Chris@165 498 m_taxonomy[id] = cat;
Chris@843 499 // cerr << "FeatureExtractionPluginFactory: set id \"" << id << "\" to cat \"" << cat << "\"" << endl;
Chris@165 500 }
Chris@165 501 }
Chris@165 502 }
Chris@165 503 }
Chris@165 504 }