annotate src/vamp-hostsdk/Files.cpp @ 390:06988ce35ff0 vh

Initial draft of C API for plugin loading
author Chris Cannam
date Wed, 20 May 2015 16:12:18 +0100
parents
children 732afc16cdd6
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@390 53 #include <dirent.h>
Chris@390 54 #include <dlfcn.h>
Chris@390 55
Chris@390 56 #ifdef __APPLE__
Chris@390 57 #define PLUGIN_SUFFIX "dylib"
Chris@390 58 #else /* ! __APPLE__ */
Chris@390 59 #define PLUGIN_SUFFIX "so"
Chris@390 60 #endif /* ! __APPLE__ */
Chris@390 61
Chris@390 62 #endif /* ! _WIN32 */
Chris@390 63
Chris@390 64 using namespace std;
Chris@390 65
Chris@390 66 vector<string>
Chris@390 67 Files::listLibraryFiles()
Chris@390 68 {
Chris@390 69 return listLibraryFilesMatching("");
Chris@390 70 }
Chris@390 71
Chris@390 72 vector<string>
Chris@390 73 Files::listLibraryFilesMatching(string libraryName)
Chris@390 74 {
Chris@390 75 vector<string> path = Vamp::PluginHostAdapter::getPluginPath();
Chris@390 76 vector<string> libraryFiles;
Chris@390 77
Chris@390 78 // we match case-insensitively
Chris@390 79 for (size_t i = 0; i < libraryName.length(); ++i) {
Chris@390 80 libraryName[i] = tolower(libraryName[i]);
Chris@390 81 }
Chris@390 82
Chris@390 83 for (size_t i = 0; i < path.size(); ++i) {
Chris@390 84
Chris@390 85 vector<string> files = listFiles(path[i], PLUGIN_SUFFIX);
Chris@390 86
Chris@390 87 for (vector<string>::iterator fi = files.begin();
Chris@390 88 fi != files.end(); ++fi) {
Chris@390 89
Chris@390 90 if (libraryName != "") {
Chris@390 91 // we match case-insensitively
Chris@390 92 string temp = *fi;
Chris@390 93 for (size_t i = 0; i < temp.length(); ++i) {
Chris@390 94 temp[i] = tolower(temp[i]);
Chris@390 95 }
Chris@390 96 // libraryName should be lacking an extension, as it
Chris@390 97 // is supposed to have come from the plugin key
Chris@390 98 string::size_type pi = temp.find('.');
Chris@390 99 if (pi == string::npos) {
Chris@390 100 if (libraryName != temp) continue;
Chris@390 101 } else {
Chris@390 102 if (libraryName != temp.substr(0, pi)) continue;
Chris@390 103 }
Chris@390 104 }
Chris@390 105
Chris@390 106 string fullPath = path[i];
Chris@390 107 fullPath = splicePath(fullPath, *fi);
Chris@390 108 libraryFiles.push_back(fullPath);
Chris@390 109 }
Chris@390 110 }
Chris@390 111
Chris@390 112 return libraryFiles;
Chris@390 113 }
Chris@390 114
Chris@390 115 void *
Chris@390 116 Files::loadLibrary(string path)
Chris@390 117 {
Chris@390 118 void *handle = 0;
Chris@390 119 #ifdef _WIN32
Chris@390 120 #ifdef UNICODE
Chris@390 121 int len = path.length() + 1; // cannot be more wchars than length in bytes of utf8 string
Chris@390 122 wchar_t *buffer = new wchar_t[len];
Chris@390 123 int rv = MultiByteToWideChar(CP_UTF8, 0, path.c_str(), len, buffer, len);
Chris@390 124 if (rv <= 0) {
Chris@390 125 cerr << "Vamp::HostExt: Unable to convert library path \""
Chris@390 126 << path << "\" to wide characters " << endl;
Chris@390 127 delete[] buffer;
Chris@390 128 return handle;
Chris@390 129 }
Chris@390 130 handle = LoadLibrary(buffer);
Chris@390 131 delete[] buffer;
Chris@390 132 #else
Chris@390 133 handle = LoadLibrary(path.c_str());
Chris@390 134 #endif
Chris@390 135 if (!handle) {
Chris@390 136 cerr << "Vamp::HostExt: Unable to load library \""
Chris@390 137 << path << "\"" << endl;
Chris@390 138 }
Chris@390 139 #else
Chris@390 140 handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
Chris@390 141 if (!handle) {
Chris@390 142 cerr << "Vamp::HostExt: Unable to load library \""
Chris@390 143 << path << "\": " << dlerror() << endl;
Chris@390 144 }
Chris@390 145 #endif
Chris@390 146 return handle;
Chris@390 147 }
Chris@390 148
Chris@390 149 void
Chris@390 150 Files::unloadLibrary(void *handle)
Chris@390 151 {
Chris@390 152 #ifdef _WIN32
Chris@390 153 FreeLibrary((HINSTANCE)handle);
Chris@390 154 #else
Chris@390 155 dlclose(handle);
Chris@390 156 #endif
Chris@390 157 }
Chris@390 158
Chris@390 159 void *
Chris@390 160 Files::lookupInLibrary(void *handle, const char *symbol)
Chris@390 161 {
Chris@390 162 #ifdef _WIN32
Chris@390 163 return (void *)GetProcAddress((HINSTANCE)handle, symbol);
Chris@390 164 #else
Chris@390 165 return (void *)dlsym(handle, symbol);
Chris@390 166 #endif
Chris@390 167 }
Chris@390 168
Chris@390 169 string
Chris@390 170 Files::lcBasename(string path)
Chris@390 171 {
Chris@390 172 string basename(path);
Chris@390 173
Chris@390 174 string::size_type li = basename.rfind('/');
Chris@390 175 if (li != string::npos) basename = basename.substr(li + 1);
Chris@390 176
Chris@390 177 li = basename.find('.');
Chris@390 178 if (li != string::npos) basename = basename.substr(0, li);
Chris@390 179
Chris@390 180 for (size_t i = 0; i < basename.length(); ++i) {
Chris@390 181 basename[i] = tolower(basename[i]);
Chris@390 182 }
Chris@390 183
Chris@390 184 return basename;
Chris@390 185 }
Chris@390 186
Chris@390 187 string
Chris@390 188 Files::splicePath(string a, string b)
Chris@390 189 {
Chris@390 190 #ifdef _WIN32
Chris@390 191 return a + "\\" + b;
Chris@390 192 #else
Chris@390 193 return a + "/" + b;
Chris@390 194 #endif
Chris@390 195 }
Chris@390 196
Chris@390 197 vector<string>
Chris@390 198 Files::listFiles(string dir, string extension)
Chris@390 199 {
Chris@390 200 vector<string> files;
Chris@390 201
Chris@390 202 #ifdef _WIN32
Chris@390 203 string expression = dir + "\\*." + extension;
Chris@390 204 #ifdef UNICODE
Chris@390 205 int len = expression.length() + 1; // cannot be more wchars than length in bytes of utf8 string
Chris@390 206 wchar_t *buffer = new wchar_t[len];
Chris@390 207 int rv = MultiByteToWideChar(CP_UTF8, 0, expression.c_str(), len, buffer, len);
Chris@390 208 if (rv <= 0) {
Chris@390 209 cerr << "Vamp::HostExt: Unable to convert wildcard path \""
Chris@390 210 << expression << "\" to wide characters" << endl;
Chris@390 211 delete[] buffer;
Chris@390 212 return files;
Chris@390 213 }
Chris@390 214 WIN32_FIND_DATA data;
Chris@390 215 HANDLE fh = FindFirstFile(buffer, &data);
Chris@390 216 if (fh == INVALID_HANDLE_VALUE) {
Chris@390 217 delete[] buffer;
Chris@390 218 return files;
Chris@390 219 }
Chris@390 220
Chris@390 221 bool ok = true;
Chris@390 222 while (ok) {
Chris@390 223 wchar_t *fn = data.cFileName;
Chris@390 224 int wlen = wcslen(fn) + 1;
Chris@390 225 int maxlen = wlen * 6;
Chris@390 226 char *conv = new char[maxlen];
Chris@390 227 int rv = WideCharToMultiByte(CP_UTF8, 0, fn, wlen, conv, maxlen, 0, 0);
Chris@390 228 if (rv > 0) {
Chris@390 229 files.push_back(conv);
Chris@390 230 }
Chris@390 231 delete[] conv;
Chris@390 232 ok = FindNextFile(fh, &data);
Chris@390 233 }
Chris@390 234
Chris@390 235 FindClose(fh);
Chris@390 236 delete[] buffer;
Chris@390 237 #else
Chris@390 238 WIN32_FIND_DATA data;
Chris@390 239 HANDLE fh = FindFirstFile(expression.c_str(), &data);
Chris@390 240 if (fh == INVALID_HANDLE_VALUE) return files;
Chris@390 241
Chris@390 242 bool ok = true;
Chris@390 243 while (ok) {
Chris@390 244 files.push_back(data.cFileName);
Chris@390 245 ok = FindNextFile(fh, &data);
Chris@390 246 }
Chris@390 247
Chris@390 248 FindClose(fh);
Chris@390 249 #endif
Chris@390 250 #else
Chris@390 251
Chris@390 252 size_t extlen = extension.length();
Chris@390 253 DIR *d = opendir(dir.c_str());
Chris@390 254 if (!d) return files;
Chris@390 255
Chris@390 256 struct dirent *e = 0;
Chris@390 257 while ((e = readdir(d))) {
Chris@390 258
Chris@390 259 if (!e->d_name) continue;
Chris@390 260
Chris@390 261 size_t len = strlen(e->d_name);
Chris@390 262 if (len < extlen + 2 ||
Chris@390 263 e->d_name + len - extlen - 1 != "." + extension) {
Chris@390 264 continue;
Chris@390 265 }
Chris@390 266
Chris@390 267 files.push_back(e->d_name);
Chris@390 268 }
Chris@390 269
Chris@390 270 closedir(d);
Chris@390 271 #endif
Chris@390 272
Chris@390 273 return files;
Chris@390 274 }