annotate src/vamp-hostsdk/Files.cpp @ 531:347ad7d3527c c++11-mutex

Use the tag (which doesn't exist yet)
author Chris Cannam
date Tue, 22 Oct 2019 12:23:34 +0100
parents da86fb0bccb3
children 45b2bd15d8ae
rev   line source
Chris@390 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@390 2
Chris@390 3 /*
Chris@390 4 Vamp
Chris@390 5
Chris@390 6 An API for audio analysis and feature extraction plugins.
Chris@390 7
Chris@390 8 Centre for Digital Music, Queen Mary, University of London.
Chris@390 9 Copyright 2006-2015 Chris Cannam and QMUL.
Chris@390 10
Chris@390 11 Permission is hereby granted, free of charge, to any person
Chris@390 12 obtaining a copy of this software and associated documentation
Chris@390 13 files (the "Software"), to deal in the Software without
Chris@390 14 restriction, including without limitation the rights to use, copy,
Chris@390 15 modify, merge, publish, distribute, sublicense, and/or sell copies
Chris@390 16 of the Software, and to permit persons to whom the Software is
Chris@390 17 furnished to do so, subject to the following conditions:
Chris@390 18
Chris@390 19 The above copyright notice and this permission notice shall be
Chris@390 20 included in all copies or substantial portions of the Software.
Chris@390 21
Chris@390 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@390 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@390 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Chris@390 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
Chris@390 26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@390 27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@390 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@390 29
Chris@390 30 Except as contained in this notice, the names of the Centre for
Chris@390 31 Digital Music; Queen Mary, University of London; and Chris Cannam
Chris@390 32 shall not be used in advertising or otherwise to promote the sale,
Chris@390 33 use or other dealings in this Software without prior written
Chris@390 34 authorization.
Chris@390 35 */
Chris@390 36
Chris@390 37 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@390 38
Chris@390 39 #include "Files.h"
Chris@390 40
Chris@390 41 #include <cctype> // tolower
Chris@390 42
Chris@390 43 #include <cstring>
Chris@390 44
Chris@390 45 #ifdef _WIN32
Chris@390 46
Chris@390 47 #include <windows.h>
Chris@390 48 #include <tchar.h>
Chris@390 49 #define PLUGIN_SUFFIX "dll"
Chris@390 50
Chris@390 51 #else /* ! _WIN32 */
Chris@390 52
Chris@514 53 #include <cstdlib>
Chris@390 54 #include <dirent.h>
Chris@390 55 #include <dlfcn.h>
Chris@390 56
Chris@390 57 #ifdef __APPLE__
Chris@390 58 #define PLUGIN_SUFFIX "dylib"
Chris@390 59 #else /* ! __APPLE__ */
Chris@390 60 #define PLUGIN_SUFFIX "so"
Chris@390 61 #endif /* ! __APPLE__ */
Chris@390 62
Chris@390 63 #endif /* ! _WIN32 */
Chris@390 64
Chris@390 65 using namespace std;
Chris@390 66
Chris@390 67 vector<string>
Chris@390 68 Files::listLibraryFiles()
Chris@390 69 {
Chris@477 70 return listLibraryFilesMatching(Filter());
Chris@390 71 }
Chris@390 72
Chris@390 73 vector<string>
Chris@473 74 Files::listLibraryFilesMatching(Filter filter)
Chris@390 75 {
Chris@390 76 vector<string> path = Vamp::PluginHostAdapter::getPluginPath();
Chris@390 77 vector<string> libraryFiles;
Chris@390 78
Chris@421 79 // we match case-insensitively, but only with ascii range
Chris@473 80 // characters (input strings are expected to be utf-8)
Chris@473 81 vector<string> libraryNames;
Chris@477 82 for (int j = 0; j < int(filter.libraryNames.size()); ++j) {
Chris@477 83 string n = filter.libraryNames[j];
Chris@473 84 for (size_t i = 0; i < n.length(); ++i) {
Chris@473 85 if (!(n[i] & 0x80)) {
Chris@473 86 n[i] = char(tolower(n[i]));
Chris@473 87 }
Chris@421 88 }
Chris@473 89 libraryNames.push_back(n);
Chris@390 90 }
Chris@390 91
Chris@390 92 for (size_t i = 0; i < path.size(); ++i) {
Chris@390 93
Chris@390 94 vector<string> files = listFiles(path[i], PLUGIN_SUFFIX);
Chris@390 95
Chris@390 96 for (vector<string>::iterator fi = files.begin();
Chris@390 97 fi != files.end(); ++fi) {
Chris@473 98
Chris@473 99 // we match case-insensitively, but only with ascii range
Chris@473 100 // characters (this string is expected to be utf-8)
Chris@473 101 string cleaned = *fi;
Chris@477 102 for (size_t j = 0; j < cleaned.length(); ++j) {
Chris@477 103 if (!(cleaned[j] & 0x80)) {
Chris@477 104 cleaned[j] = char(tolower(cleaned[j]));
Chris@390 105 }
Chris@390 106 }
Chris@390 107
Chris@473 108 // libraryName should be lacking an extension, as it is
Chris@473 109 // supposed to have come from the plugin key
Chris@473 110 string::size_type pi = cleaned.find('.');
Chris@473 111 if (pi != string::npos) {
Chris@473 112 cleaned = cleaned.substr(0, pi);
Chris@473 113 }
Chris@473 114
Chris@473 115 bool matched = false;
Chris@473 116
Chris@473 117 switch (filter.type) {
Chris@473 118
Chris@473 119 case Filter::All:
Chris@473 120 matched = true;
Chris@473 121 break;
Chris@473 122
Chris@473 123 case Filter::Matching:
Chris@477 124 for (int j = 0; j < int(libraryNames.size()); ++j) {
Chris@477 125 if (cleaned == libraryNames[j]) {
Chris@473 126 matched = true;
Chris@473 127 break;
Chris@473 128 }
Chris@473 129 }
Chris@473 130 break;
Chris@473 131
Chris@473 132 case Filter::NotMatching:
Chris@473 133 matched = true;
Chris@477 134 for (int j = 0; j < int(libraryNames.size()); ++j) {
Chris@477 135 if (cleaned == libraryNames[j]) {
Chris@473 136 matched = false;
Chris@473 137 break;
Chris@473 138 }
Chris@473 139 }
Chris@473 140 break;
Chris@473 141 }
Chris@473 142
Chris@473 143 if (!matched) continue;
Chris@473 144
Chris@390 145 string fullPath = path[i];
Chris@390 146 fullPath = splicePath(fullPath, *fi);
Chris@390 147 libraryFiles.push_back(fullPath);
Chris@390 148 }
Chris@390 149 }
Chris@390 150
Chris@390 151 return libraryFiles;
Chris@390 152 }
Chris@390 153
Chris@390 154 void *
Chris@390 155 Files::loadLibrary(string path)
Chris@390 156 {
Chris@390 157 void *handle = 0;
Chris@390 158 #ifdef _WIN32
Chris@390 159 #ifdef UNICODE
Chris@472 160 int wlen = MultiByteToWideChar(CP_UTF8, 0, path.c_str(), path.length(), 0, 0);
Chris@472 161 if (wlen < 0) {
Chris@390 162 cerr << "Vamp::HostExt: Unable to convert library path \""
Chris@390 163 << path << "\" to wide characters " << endl;
Chris@390 164 return handle;
Chris@390 165 }
Chris@472 166 wchar_t *buffer = new wchar_t[wlen+1];
Chris@472 167 (void)MultiByteToWideChar(CP_UTF8, 0, path.c_str(), path.length(), buffer, wlen);
Chris@472 168 buffer[wlen] = L'\0';
Chris@390 169 handle = LoadLibrary(buffer);
Chris@390 170 delete[] buffer;
Chris@390 171 #else
Chris@390 172 handle = LoadLibrary(path.c_str());
Chris@390 173 #endif
Chris@390 174 if (!handle) {
Chris@390 175 cerr << "Vamp::HostExt: Unable to load library \""
Chris@390 176 << path << "\"" << endl;
Chris@390 177 }
Chris@390 178 #else
Chris@390 179 handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
Chris@390 180 if (!handle) {
Chris@390 181 cerr << "Vamp::HostExt: Unable to load library \""
Chris@390 182 << path << "\": " << dlerror() << endl;
Chris@390 183 }
Chris@390 184 #endif
Chris@390 185 return handle;
Chris@390 186 }
Chris@390 187
Chris@390 188 void
Chris@390 189 Files::unloadLibrary(void *handle)
Chris@390 190 {
Chris@390 191 #ifdef _WIN32
Chris@390 192 FreeLibrary((HINSTANCE)handle);
Chris@390 193 #else
Chris@390 194 dlclose(handle);
Chris@390 195 #endif
Chris@390 196 }
Chris@390 197
Chris@390 198 void *
Chris@390 199 Files::lookupInLibrary(void *handle, const char *symbol)
Chris@390 200 {
Chris@390 201 #ifdef _WIN32
Chris@390 202 return (void *)GetProcAddress((HINSTANCE)handle, symbol);
Chris@390 203 #else
Chris@390 204 return (void *)dlsym(handle, symbol);
Chris@390 205 #endif
Chris@390 206 }
Chris@390 207
Chris@390 208 string
Chris@390 209 Files::lcBasename(string path)
Chris@390 210 {
Chris@390 211 string basename(path);
Chris@390 212
Chris@390 213 string::size_type li = basename.rfind('/');
Chris@390 214 if (li != string::npos) basename = basename.substr(li + 1);
Chris@390 215
Chris@403 216 #ifdef _WIN32
Chris@405 217 li = basename.rfind('\\');
Chris@403 218 if (li != string::npos) basename = basename.substr(li + 1);
Chris@403 219 #endif
Chris@403 220
Chris@390 221 li = basename.find('.');
Chris@390 222 if (li != string::npos) basename = basename.substr(0, li);
Chris@390 223
Chris@421 224 // case-insensitive, but only with ascii range characters (this
Chris@421 225 // string is expected to be utf-8)
Chris@390 226 for (size_t i = 0; i < basename.length(); ++i) {
Chris@421 227 if (!(basename[i] & 0x80)) {
Chris@421 228 basename[i] = char(tolower(basename[i]));
Chris@421 229 }
Chris@390 230 }
Chris@390 231
Chris@390 232 return basename;
Chris@390 233 }
Chris@390 234
Chris@390 235 string
Chris@390 236 Files::splicePath(string a, string b)
Chris@390 237 {
Chris@390 238 #ifdef _WIN32
Chris@390 239 return a + "\\" + b;
Chris@390 240 #else
Chris@390 241 return a + "/" + b;
Chris@390 242 #endif
Chris@390 243 }
Chris@390 244
Chris@390 245 vector<string>
Chris@390 246 Files::listFiles(string dir, string extension)
Chris@390 247 {
Chris@390 248 vector<string> files;
Chris@390 249
Chris@390 250 #ifdef _WIN32
Chris@390 251 string expression = dir + "\\*." + extension;
Chris@390 252 #ifdef UNICODE
Chris@472 253 int wlen = MultiByteToWideChar(CP_UTF8, 0, expression.c_str(), expression.length(), 0, 0);
Chris@472 254 if (wlen < 0) {
Chris@390 255 cerr << "Vamp::HostExt: Unable to convert wildcard path \""
Chris@390 256 << expression << "\" to wide characters" << endl;
Chris@390 257 return files;
Chris@390 258 }
Chris@472 259 wchar_t *buffer = new wchar_t[wlen+1];
Chris@472 260 (void)MultiByteToWideChar(CP_UTF8, 0, expression.c_str(), expression.length(), buffer, wlen);
Chris@472 261 buffer[wlen] = L'\0';
Chris@390 262 WIN32_FIND_DATA data;
Chris@390 263 HANDLE fh = FindFirstFile(buffer, &data);
Chris@390 264 if (fh == INVALID_HANDLE_VALUE) {
Chris@390 265 delete[] buffer;
Chris@390 266 return files;
Chris@390 267 }
Chris@390 268
Chris@390 269 bool ok = true;
Chris@390 270 while (ok) {
Chris@390 271 wchar_t *fn = data.cFileName;
Chris@472 272 int wlen = wcslen(fn);
Chris@472 273 int len = WideCharToMultiByte(CP_UTF8, 0, fn, wlen, 0, 0, 0, 0);
Chris@472 274 if (len < 0) {
Chris@472 275 cerr << "Vamp::HostExt: Unable to convert wide char filename to utf-8" << endl;
Chris@472 276 break;
Chris@472 277 }
Chris@472 278 char *conv = new char[len+1];
Chris@472 279 (void)WideCharToMultiByte(CP_UTF8, 0, fn, wlen, conv, len, 0, 0);
Chris@472 280 conv[len] = '\0';
Chris@472 281 if (len > 0) {
Chris@390 282 files.push_back(conv);
Chris@390 283 }
Chris@390 284 delete[] conv;
Chris@390 285 ok = FindNextFile(fh, &data);
Chris@390 286 }
Chris@390 287
Chris@390 288 FindClose(fh);
Chris@390 289 delete[] buffer;
Chris@390 290 #else
Chris@390 291 WIN32_FIND_DATA data;
Chris@390 292 HANDLE fh = FindFirstFile(expression.c_str(), &data);
Chris@390 293 if (fh == INVALID_HANDLE_VALUE) return files;
Chris@390 294
Chris@390 295 bool ok = true;
Chris@390 296 while (ok) {
Chris@390 297 files.push_back(data.cFileName);
Chris@390 298 ok = FindNextFile(fh, &data);
Chris@390 299 }
Chris@390 300
Chris@390 301 FindClose(fh);
Chris@390 302 #endif
Chris@390 303 #else
Chris@390 304
Chris@390 305 size_t extlen = extension.length();
Chris@390 306 DIR *d = opendir(dir.c_str());
Chris@390 307 if (!d) return files;
Chris@390 308
Chris@390 309 struct dirent *e = 0;
Chris@390 310 while ((e = readdir(d))) {
Chris@390 311
Chris@390 312 size_t len = strlen(e->d_name);
Chris@390 313 if (len < extlen + 2 ||
Chris@390 314 e->d_name + len - extlen - 1 != "." + extension) {
Chris@390 315 continue;
Chris@390 316 }
Chris@390 317
Chris@390 318 files.push_back(e->d_name);
Chris@390 319 }
Chris@390 320
Chris@390 321 closedir(d);
Chris@390 322 #endif
Chris@390 323
Chris@390 324 return files;
Chris@390 325 }
Chris@512 326
Chris@512 327 bool
Chris@513 328 Files::isNonNative32Bit()
Chris@513 329 {
Chris@513 330 // Return true if we are running on a system for which we should
Chris@513 331 // use the VAMP_PATH_32 variable instead of VAMP_PATH. This will
Chris@513 332 // be the case if we are a 32-bit executable but the OS is
Chris@513 333 // natively 64-bit.
Chris@513 334 //
Chris@513 335 // This currently works only on Windows; other operating systems
Chris@513 336 // will use VAMP_PATH always.
Chris@513 337
Chris@513 338 if (sizeof(void *) == 8) {
Chris@513 339 return false;
Chris@513 340 }
Chris@513 341
Chris@513 342 #ifdef _WIN32
Chris@513 343 BOOL wow64 = FALSE;
Chris@513 344 BOOL (WINAPI *fnIsWow64Process)(HANDLE, PBOOL) =
Chris@513 345 (BOOL (WINAPI *)(HANDLE, PBOOL)) GetProcAddress
Chris@513 346 (GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
Chris@513 347 if (fnIsWow64Process) {
Chris@513 348 if (fnIsWow64Process(GetCurrentProcess(), &wow64)) {
Chris@513 349 if (wow64) {
Chris@513 350 return true;
Chris@513 351 } else {
Chris@513 352 return false;
Chris@513 353 }
Chris@513 354 } else {
Chris@513 355 cerr << "Vamp::HostExt: Unable to query process architecture"
Chris@513 356 << endl;
Chris@513 357 return false;
Chris@513 358 }
Chris@513 359 } else {
Chris@513 360 cerr << "Vamp::HostExt: Unable to query process architecture: "
Chris@513 361 << "Function not available" << endl;
Chris@513 362 return false;
Chris@513 363 }
Chris@513 364 #endif
Chris@513 365
Chris@513 366 return false;
Chris@513 367 }
Chris@513 368
Chris@513 369 bool
Chris@512 370 Files::getEnvUtf8(std::string variable, std::string &value)
Chris@512 371 {
Chris@512 372 value = "";
Chris@512 373
Chris@512 374 #ifdef _WIN32
Chris@512 375 int wvarlen = MultiByteToWideChar(CP_UTF8, 0,
Chris@512 376 variable.c_str(), int(variable.length()),
Chris@512 377 0, 0);
Chris@512 378 if (wvarlen < 0) {
Chris@512 379 cerr << "Vamp::HostExt: Unable to convert environment variable name "
Chris@512 380 << variable << " to wide characters" << endl;
Chris@512 381 return false;
Chris@512 382 }
Chris@512 383
Chris@512 384 wchar_t *wvarbuf = new wchar_t[wvarlen + 1];
Chris@512 385 (void)MultiByteToWideChar(CP_UTF8, 0,
Chris@512 386 variable.c_str(), int(variable.length()),
Chris@512 387 wvarbuf, wvarlen);
Chris@512 388 wvarbuf[wvarlen] = L'\0';
Chris@512 389
Chris@512 390 wchar_t *wvalue = _wgetenv(wvarbuf);
Chris@512 391
Chris@512 392 delete[] wvarbuf;
Chris@512 393
Chris@512 394 if (!wvalue) {
Chris@512 395 return false;
Chris@512 396 }
Chris@512 397
Chris@512 398 int wvallen = int(wcslen(wvalue));
Chris@512 399 int vallen = WideCharToMultiByte(CP_UTF8, 0,
Chris@512 400 wvalue, wvallen,
Chris@512 401 0, 0, 0, 0);
Chris@512 402 if (vallen < 0) {
Chris@512 403 cerr << "Vamp::HostExt: Unable to convert environment value to UTF-8"
Chris@512 404 << endl;
Chris@512 405 return false;
Chris@512 406 }
Chris@512 407
Chris@512 408 char *val = new char[vallen + 1];
Chris@512 409 (void)WideCharToMultiByte(CP_UTF8, 0,
Chris@512 410 wvalue, wvallen,
Chris@512 411 val, vallen, 0, 0);
Chris@512 412 val[vallen] = '\0';
Chris@512 413
Chris@512 414 value = val;
Chris@512 415
Chris@512 416 delete[] val;
Chris@512 417 return true;
Chris@512 418
Chris@512 419 #else
Chris@512 420
Chris@512 421 char *val = getenv(variable.c_str());
Chris@512 422 if (!val) {
Chris@512 423 return false;
Chris@512 424 }
Chris@512 425
Chris@512 426 value = val;
Chris@512 427 return true;
Chris@512 428
Chris@512 429 #endif
Chris@512 430 }