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@403
|
177 #ifdef _WIN32
|
Chris@405
|
178 li = basename.rfind('\\');
|
Chris@403
|
179 if (li != string::npos) basename = basename.substr(li + 1);
|
Chris@403
|
180 #endif
|
Chris@403
|
181
|
Chris@390
|
182 li = basename.find('.');
|
Chris@390
|
183 if (li != string::npos) basename = basename.substr(0, li);
|
Chris@390
|
184
|
Chris@390
|
185 for (size_t i = 0; i < basename.length(); ++i) {
|
Chris@390
|
186 basename[i] = tolower(basename[i]);
|
Chris@390
|
187 }
|
Chris@390
|
188
|
Chris@390
|
189 return basename;
|
Chris@390
|
190 }
|
Chris@390
|
191
|
Chris@390
|
192 string
|
Chris@390
|
193 Files::splicePath(string a, string b)
|
Chris@390
|
194 {
|
Chris@390
|
195 #ifdef _WIN32
|
Chris@390
|
196 return a + "\\" + b;
|
Chris@390
|
197 #else
|
Chris@390
|
198 return a + "/" + b;
|
Chris@390
|
199 #endif
|
Chris@390
|
200 }
|
Chris@390
|
201
|
Chris@390
|
202 vector<string>
|
Chris@390
|
203 Files::listFiles(string dir, string extension)
|
Chris@390
|
204 {
|
Chris@390
|
205 vector<string> files;
|
Chris@390
|
206
|
Chris@390
|
207 #ifdef _WIN32
|
Chris@390
|
208 string expression = dir + "\\*." + extension;
|
Chris@390
|
209 #ifdef UNICODE
|
Chris@390
|
210 int len = expression.length() + 1; // cannot be more wchars than length in bytes of utf8 string
|
Chris@390
|
211 wchar_t *buffer = new wchar_t[len];
|
Chris@390
|
212 int rv = MultiByteToWideChar(CP_UTF8, 0, expression.c_str(), len, buffer, len);
|
Chris@390
|
213 if (rv <= 0) {
|
Chris@390
|
214 cerr << "Vamp::HostExt: Unable to convert wildcard path \""
|
Chris@390
|
215 << expression << "\" to wide characters" << endl;
|
Chris@390
|
216 delete[] buffer;
|
Chris@390
|
217 return files;
|
Chris@390
|
218 }
|
Chris@390
|
219 WIN32_FIND_DATA data;
|
Chris@390
|
220 HANDLE fh = FindFirstFile(buffer, &data);
|
Chris@390
|
221 if (fh == INVALID_HANDLE_VALUE) {
|
Chris@390
|
222 delete[] buffer;
|
Chris@390
|
223 return files;
|
Chris@390
|
224 }
|
Chris@390
|
225
|
Chris@390
|
226 bool ok = true;
|
Chris@390
|
227 while (ok) {
|
Chris@390
|
228 wchar_t *fn = data.cFileName;
|
Chris@390
|
229 int wlen = wcslen(fn) + 1;
|
Chris@390
|
230 int maxlen = wlen * 6;
|
Chris@390
|
231 char *conv = new char[maxlen];
|
Chris@390
|
232 int rv = WideCharToMultiByte(CP_UTF8, 0, fn, wlen, conv, maxlen, 0, 0);
|
Chris@390
|
233 if (rv > 0) {
|
Chris@390
|
234 files.push_back(conv);
|
Chris@390
|
235 }
|
Chris@390
|
236 delete[] conv;
|
Chris@390
|
237 ok = FindNextFile(fh, &data);
|
Chris@390
|
238 }
|
Chris@390
|
239
|
Chris@390
|
240 FindClose(fh);
|
Chris@390
|
241 delete[] buffer;
|
Chris@390
|
242 #else
|
Chris@390
|
243 WIN32_FIND_DATA data;
|
Chris@390
|
244 HANDLE fh = FindFirstFile(expression.c_str(), &data);
|
Chris@390
|
245 if (fh == INVALID_HANDLE_VALUE) return files;
|
Chris@390
|
246
|
Chris@390
|
247 bool ok = true;
|
Chris@390
|
248 while (ok) {
|
Chris@390
|
249 files.push_back(data.cFileName);
|
Chris@390
|
250 ok = FindNextFile(fh, &data);
|
Chris@390
|
251 }
|
Chris@390
|
252
|
Chris@390
|
253 FindClose(fh);
|
Chris@390
|
254 #endif
|
Chris@390
|
255 #else
|
Chris@390
|
256
|
Chris@390
|
257 size_t extlen = extension.length();
|
Chris@390
|
258 DIR *d = opendir(dir.c_str());
|
Chris@390
|
259 if (!d) return files;
|
Chris@390
|
260
|
Chris@390
|
261 struct dirent *e = 0;
|
Chris@390
|
262 while ((e = readdir(d))) {
|
Chris@390
|
263
|
Chris@390
|
264 size_t len = strlen(e->d_name);
|
Chris@390
|
265 if (len < extlen + 2 ||
|
Chris@390
|
266 e->d_name + len - extlen - 1 != "." + extension) {
|
Chris@390
|
267 continue;
|
Chris@390
|
268 }
|
Chris@390
|
269
|
Chris@390
|
270 files.push_back(e->d_name);
|
Chris@390
|
271 }
|
Chris@390
|
272
|
Chris@390
|
273 closedir(d);
|
Chris@390
|
274 #endif
|
Chris@390
|
275
|
Chris@390
|
276 return files;
|
Chris@390
|
277 }
|