Chris@390: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@390: Chris@390: /* Chris@390: Vamp Chris@390: Chris@390: An API for audio analysis and feature extraction plugins. Chris@390: Chris@390: Centre for Digital Music, Queen Mary, University of London. Chris@390: Copyright 2006-2015 Chris Cannam and QMUL. Chris@390: Chris@390: Permission is hereby granted, free of charge, to any person Chris@390: obtaining a copy of this software and associated documentation Chris@390: files (the "Software"), to deal in the Software without Chris@390: restriction, including without limitation the rights to use, copy, Chris@390: modify, merge, publish, distribute, sublicense, and/or sell copies Chris@390: of the Software, and to permit persons to whom the Software is Chris@390: furnished to do so, subject to the following conditions: Chris@390: Chris@390: The above copyright notice and this permission notice shall be Chris@390: included in all copies or substantial portions of the Software. Chris@390: Chris@390: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Chris@390: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF Chris@390: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND Chris@390: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR Chris@390: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF Chris@390: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION Chris@390: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Chris@390: Chris@390: Except as contained in this notice, the names of the Centre for Chris@390: Digital Music; Queen Mary, University of London; and Chris Cannam Chris@390: shall not be used in advertising or otherwise to promote the sale, Chris@390: use or other dealings in this Software without prior written Chris@390: authorization. Chris@390: */ Chris@390: Chris@390: #include Chris@390: Chris@390: #include "Files.h" Chris@390: Chris@390: #include // tolower Chris@390: Chris@390: #include Chris@390: Chris@390: #ifdef _WIN32 Chris@390: Chris@390: #include Chris@390: #include Chris@390: #define PLUGIN_SUFFIX "dll" Chris@390: Chris@390: #else /* ! _WIN32 */ Chris@390: Chris@390: #include Chris@390: #include Chris@390: Chris@390: #ifdef __APPLE__ Chris@390: #define PLUGIN_SUFFIX "dylib" Chris@390: #else /* ! __APPLE__ */ Chris@390: #define PLUGIN_SUFFIX "so" Chris@390: #endif /* ! __APPLE__ */ Chris@390: Chris@390: #endif /* ! _WIN32 */ Chris@390: Chris@390: using namespace std; Chris@390: Chris@390: vector Chris@390: Files::listLibraryFiles() Chris@390: { Chris@390: return listLibraryFilesMatching(""); Chris@390: } Chris@390: Chris@390: vector Chris@390: Files::listLibraryFilesMatching(string libraryName) Chris@390: { Chris@390: vector path = Vamp::PluginHostAdapter::getPluginPath(); Chris@390: vector libraryFiles; Chris@390: Chris@390: // we match case-insensitively Chris@390: for (size_t i = 0; i < libraryName.length(); ++i) { Chris@390: libraryName[i] = tolower(libraryName[i]); Chris@390: } Chris@390: Chris@390: for (size_t i = 0; i < path.size(); ++i) { Chris@390: Chris@390: vector files = listFiles(path[i], PLUGIN_SUFFIX); Chris@390: Chris@390: for (vector::iterator fi = files.begin(); Chris@390: fi != files.end(); ++fi) { Chris@390: Chris@390: if (libraryName != "") { Chris@390: // we match case-insensitively Chris@390: string temp = *fi; Chris@390: for (size_t i = 0; i < temp.length(); ++i) { Chris@390: temp[i] = tolower(temp[i]); Chris@390: } Chris@390: // libraryName should be lacking an extension, as it Chris@390: // is supposed to have come from the plugin key Chris@390: string::size_type pi = temp.find('.'); Chris@390: if (pi == string::npos) { Chris@390: if (libraryName != temp) continue; Chris@390: } else { Chris@390: if (libraryName != temp.substr(0, pi)) continue; Chris@390: } Chris@390: } Chris@390: Chris@390: string fullPath = path[i]; Chris@390: fullPath = splicePath(fullPath, *fi); Chris@390: libraryFiles.push_back(fullPath); Chris@390: } Chris@390: } Chris@390: Chris@390: return libraryFiles; Chris@390: } Chris@390: Chris@390: void * Chris@390: Files::loadLibrary(string path) Chris@390: { Chris@390: void *handle = 0; Chris@390: #ifdef _WIN32 Chris@390: #ifdef UNICODE Chris@390: int len = path.length() + 1; // cannot be more wchars than length in bytes of utf8 string Chris@390: wchar_t *buffer = new wchar_t[len]; Chris@390: int rv = MultiByteToWideChar(CP_UTF8, 0, path.c_str(), len, buffer, len); Chris@390: if (rv <= 0) { Chris@390: cerr << "Vamp::HostExt: Unable to convert library path \"" Chris@390: << path << "\" to wide characters " << endl; Chris@390: delete[] buffer; Chris@390: return handle; Chris@390: } Chris@390: handle = LoadLibrary(buffer); Chris@390: delete[] buffer; Chris@390: #else Chris@390: handle = LoadLibrary(path.c_str()); Chris@390: #endif Chris@390: if (!handle) { Chris@390: cerr << "Vamp::HostExt: Unable to load library \"" Chris@390: << path << "\"" << endl; Chris@390: } Chris@390: #else Chris@390: handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); Chris@390: if (!handle) { Chris@390: cerr << "Vamp::HostExt: Unable to load library \"" Chris@390: << path << "\": " << dlerror() << endl; Chris@390: } Chris@390: #endif Chris@390: return handle; Chris@390: } Chris@390: Chris@390: void Chris@390: Files::unloadLibrary(void *handle) Chris@390: { Chris@390: #ifdef _WIN32 Chris@390: FreeLibrary((HINSTANCE)handle); Chris@390: #else Chris@390: dlclose(handle); Chris@390: #endif Chris@390: } Chris@390: Chris@390: void * Chris@390: Files::lookupInLibrary(void *handle, const char *symbol) Chris@390: { Chris@390: #ifdef _WIN32 Chris@390: return (void *)GetProcAddress((HINSTANCE)handle, symbol); Chris@390: #else Chris@390: return (void *)dlsym(handle, symbol); Chris@390: #endif Chris@390: } Chris@390: Chris@390: string Chris@390: Files::lcBasename(string path) Chris@390: { Chris@390: string basename(path); Chris@390: Chris@390: string::size_type li = basename.rfind('/'); Chris@390: if (li != string::npos) basename = basename.substr(li + 1); Chris@390: Chris@403: #ifdef _WIN32 Chris@405: li = basename.rfind('\\'); Chris@403: if (li != string::npos) basename = basename.substr(li + 1); Chris@403: #endif Chris@403: Chris@390: li = basename.find('.'); Chris@390: if (li != string::npos) basename = basename.substr(0, li); Chris@390: Chris@390: for (size_t i = 0; i < basename.length(); ++i) { Chris@390: basename[i] = tolower(basename[i]); Chris@390: } Chris@390: Chris@390: return basename; Chris@390: } Chris@390: Chris@390: string Chris@390: Files::splicePath(string a, string b) Chris@390: { Chris@390: #ifdef _WIN32 Chris@390: return a + "\\" + b; Chris@390: #else Chris@390: return a + "/" + b; Chris@390: #endif Chris@390: } Chris@390: Chris@390: vector Chris@390: Files::listFiles(string dir, string extension) Chris@390: { Chris@390: vector files; Chris@390: Chris@390: #ifdef _WIN32 Chris@390: string expression = dir + "\\*." + extension; Chris@390: #ifdef UNICODE Chris@390: int len = expression.length() + 1; // cannot be more wchars than length in bytes of utf8 string Chris@390: wchar_t *buffer = new wchar_t[len]; Chris@390: int rv = MultiByteToWideChar(CP_UTF8, 0, expression.c_str(), len, buffer, len); Chris@390: if (rv <= 0) { Chris@390: cerr << "Vamp::HostExt: Unable to convert wildcard path \"" Chris@390: << expression << "\" to wide characters" << endl; Chris@390: delete[] buffer; Chris@390: return files; Chris@390: } Chris@390: WIN32_FIND_DATA data; Chris@390: HANDLE fh = FindFirstFile(buffer, &data); Chris@390: if (fh == INVALID_HANDLE_VALUE) { Chris@390: delete[] buffer; Chris@390: return files; Chris@390: } Chris@390: Chris@390: bool ok = true; Chris@390: while (ok) { Chris@390: wchar_t *fn = data.cFileName; Chris@390: int wlen = wcslen(fn) + 1; Chris@390: int maxlen = wlen * 6; Chris@390: char *conv = new char[maxlen]; Chris@390: int rv = WideCharToMultiByte(CP_UTF8, 0, fn, wlen, conv, maxlen, 0, 0); Chris@390: if (rv > 0) { Chris@390: files.push_back(conv); Chris@390: } Chris@390: delete[] conv; Chris@390: ok = FindNextFile(fh, &data); Chris@390: } Chris@390: Chris@390: FindClose(fh); Chris@390: delete[] buffer; Chris@390: #else Chris@390: WIN32_FIND_DATA data; Chris@390: HANDLE fh = FindFirstFile(expression.c_str(), &data); Chris@390: if (fh == INVALID_HANDLE_VALUE) return files; Chris@390: Chris@390: bool ok = true; Chris@390: while (ok) { Chris@390: files.push_back(data.cFileName); Chris@390: ok = FindNextFile(fh, &data); Chris@390: } Chris@390: Chris@390: FindClose(fh); Chris@390: #endif Chris@390: #else Chris@390: Chris@390: size_t extlen = extension.length(); Chris@390: DIR *d = opendir(dir.c_str()); Chris@390: if (!d) return files; Chris@390: Chris@390: struct dirent *e = 0; Chris@390: while ((e = readdir(d))) { Chris@390: Chris@390: size_t len = strlen(e->d_name); Chris@390: if (len < extlen + 2 || Chris@390: e->d_name + len - extlen - 1 != "." + extension) { Chris@390: continue; Chris@390: } Chris@390: Chris@390: files.push_back(e->d_name); Chris@390: } Chris@390: Chris@390: closedir(d); Chris@390: #endif Chris@390: Chris@390: return files; Chris@390: }