Mercurial > hg > vamp-plugin-load-checker
comparison src/helper.cpp @ 40:40c6936c2fc9 errorcode
Return numerical error codes, so the caller can apply i18n on display; distinguish explicitly the common win32 architecture problems
author | Chris Cannam |
---|---|
date | Wed, 29 Aug 2018 17:40:22 +0100 |
parents | a43d7a2867d2 |
children | 49946b02414e |
comparison
equal
deleted
inserted
replaced
38:a43d7a2867d2 | 40:40c6936c2fc9 |
---|---|
17 * | 17 * |
18 * Output line for successful load of library libname.so: | 18 * Output line for successful load of library libname.so: |
19 * SUCCESS|/path/to/libname.so| | 19 * SUCCESS|/path/to/libname.so| |
20 * | 20 * |
21 * Output line for failed load of library libname.so: | 21 * Output line for failed load of library libname.so: |
22 * FAILURE|/path/to/libname.so|Reason for failure if available | 22 * FAILURE|/path/to/libname.so|Error message [failureCode] |
23 * | |
24 * or: | |
25 * FAILURE|/path/to/libname.so|[failureCode] | |
26 * | |
27 * where the error message is an optional system-level message, such | |
28 * as may be returned from strerror or similar (which should be in the | |
29 * native language for the system ready to show the user), and the | |
30 * failureCode in square brackets is a mandatory number corresponding | |
31 * to one of the PluginCandidates::FailureCode values (requiring | |
32 * conversion to a translated string by the client). | |
23 * | 33 * |
24 * Although this program was written for use with Vamp audio analysis | 34 * Although this program was written for use with Vamp audio analysis |
25 * plugins, it also works with other plugin formats. The program has | 35 * plugins, it also works with other plugin formats. The program has |
26 * some hardcoded knowledge of Vamp, LADSPA, and DSSI plugins, but it | 36 * some hardcoded knowledge of Vamp, LADSPA, and DSSI plugins, but it |
27 * can be used with any plugins that involve loading DLLs and looking | 37 * can be used with any plugins that involve loading DLLs and looking |
62 dealings in this Software without prior written authorization. | 72 dealings in this Software without prior written authorization. |
63 */ | 73 */ |
64 | 74 |
65 #include "../version.h" | 75 #include "../version.h" |
66 | 76 |
77 #include "../checker/checkcode.h" | |
78 | |
67 static const char programName[] = "vamp-plugin-load-checker"; | 79 static const char programName[] = "vamp-plugin-load-checker"; |
68 | 80 |
69 #ifdef _WIN32 | 81 #ifdef _WIN32 |
70 #include <windows.h> | 82 #include <windows.h> |
71 #include <process.h> | 83 #include <process.h> |
76 | 88 |
77 #ifdef _WIN32 | 89 #ifdef _WIN32 |
78 #ifndef UNICODE | 90 #ifndef UNICODE |
79 #error "This must be compiled with UNICODE defined" | 91 #error "This must be compiled with UNICODE defined" |
80 #endif | 92 #endif |
93 | |
81 static std::string lastLibraryName = ""; | 94 static std::string lastLibraryName = ""; |
95 | |
82 static HMODULE LoadLibraryUTF8(std::string name) { | 96 static HMODULE LoadLibraryUTF8(std::string name) { |
83 lastLibraryName = name; | 97 lastLibraryName = name; |
84 int n = name.size(); | 98 int n = name.size(); |
85 int wn = MultiByteToWideChar(CP_UTF8, 0, name.c_str(), n, 0, 0); | 99 int wn = MultiByteToWideChar(CP_UTF8, 0, name.c_str(), n, 0, 0); |
86 wchar_t *wname = new wchar_t[wn+1]; | 100 wchar_t *wname = new wchar_t[wn+1]; |
88 wname[wn] = L'\0'; | 102 wname[wn] = L'\0'; |
89 HMODULE h = LoadLibraryW(wname); | 103 HMODULE h = LoadLibraryW(wname); |
90 delete[] wname; | 104 delete[] wname; |
91 return h; | 105 return h; |
92 } | 106 } |
107 | |
93 static std::string GetErrorText() { | 108 static std::string GetErrorText() { |
94 DWORD err = GetLastError(); | 109 DWORD err = GetLastError(); |
95 wchar_t *buffer; | 110 wchar_t *buffer; |
96 FormatMessageW( | 111 FormatMessageW( |
97 FORMAT_MESSAGE_ALLOCATE_BUFFER | | 112 FORMAT_MESSAGE_ALLOCATE_BUFFER | |
98 FORMAT_MESSAGE_FROM_SYSTEM | | 113 FORMAT_MESSAGE_FROM_SYSTEM | |
99 FORMAT_MESSAGE_IGNORE_INSERTS, | 114 FORMAT_MESSAGE_IGNORE_INSERTS, |
100 NULL, | 115 NULL, |
101 err, | 116 err, |
102 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | 117 MAKELANGID(LANG_USER_DEFAULT, SUBLANG_USER_DEFAULT), |
103 (LPWSTR) &buffer, | 118 (LPWSTR) &buffer, |
104 0, NULL ); | 119 0, NULL ); |
105 int wn = wcslen(buffer); | 120 int wn = wcslen(buffer); |
106 int n = WideCharToMultiByte(CP_UTF8, 0, buffer, wn, 0, 0, 0, 0); | 121 int n = WideCharToMultiByte(CP_UTF8, 0, buffer, wn, 0, 0, 0, 0); |
107 if (n < 0) { | 122 if (n < 0) { |
124 if (pos != std::string::npos && lastLibraryName != "") { | 139 if (pos != std::string::npos && lastLibraryName != "") { |
125 s.replace(pos, 2, lastLibraryName); | 140 s.replace(pos, 2, lastLibraryName); |
126 } | 141 } |
127 return s; | 142 return s; |
128 } | 143 } |
144 | |
129 #define DLOPEN(a,b) LoadLibraryUTF8(a) | 145 #define DLOPEN(a,b) LoadLibraryUTF8(a) |
130 #define DLSYM(a,b) (void *)GetProcAddress((HINSTANCE)(a),(b).c_str()) | 146 #define DLSYM(a,b) (void *)GetProcAddress((HINSTANCE)(a),(b).c_str()) |
131 #define DLCLOSE(a) (!FreeLibrary((HINSTANCE)(a))) | 147 #define DLCLOSE(a) (!FreeLibrary((HINSTANCE)(a))) |
132 #define DLERROR() (GetErrorText()) | 148 #define DLERROR() (GetErrorText()) |
149 | |
133 #else | 150 #else |
151 | |
134 #include <dlfcn.h> | 152 #include <dlfcn.h> |
135 #define DLOPEN(a,b) dlopen((a).c_str(),(b)) | 153 #define DLOPEN(a,b) dlopen((a).c_str(),(b)) |
136 #define DLSYM(a,b) dlsym((a),(b).c_str()) | 154 #define DLSYM(a,b) dlsym((a),(b).c_str()) |
137 #define DLCLOSE(a) dlclose((a)) | 155 #define DLCLOSE(a) dlclose((a)) |
138 #define DLERROR() dlerror() | 156 #define DLERROR() dlerror() |
157 | |
139 #endif | 158 #endif |
140 | 159 |
141 //#include <unistd.h> | 160 //#include <unistd.h> |
142 | 161 |
143 using namespace std; | 162 using namespace std; |
144 | 163 |
145 string error() | 164 string error() |
146 { | 165 { |
147 string e = DLERROR(); | 166 return DLERROR(); |
148 if (e == "") return "(unknown error)"; | 167 } |
149 else return e; | 168 |
150 } | 169 struct Result { |
151 | 170 PluginCheckCode code; |
152 string checkLADSPAStyleDescriptorFn(void *f) | 171 string message; |
172 }; | |
173 | |
174 Result checkLADSPAStyleDescriptorFn(void *f) | |
153 { | 175 { |
154 typedef const void *(*DFn)(unsigned long); | 176 typedef const void *(*DFn)(unsigned long); |
155 DFn fn = DFn(f); | 177 DFn fn = DFn(f); |
156 unsigned long index = 0; | 178 unsigned long index = 0; |
157 while (fn(index)) ++index; | 179 while (fn(index)) ++index; |
158 if (index == 0) return "Library contains no plugins"; | 180 if (index == 0) return { PluginCheckCode::FAIL_NO_PLUGINS, "" }; |
159 return ""; | 181 return { PluginCheckCode::SUCCESS, "" }; |
160 } | 182 } |
161 | 183 |
162 string checkVampDescriptorFn(void *f) | 184 Result checkVampDescriptorFn(void *f) |
163 { | 185 { |
164 typedef const void *(*DFn)(unsigned int, unsigned int); | 186 typedef const void *(*DFn)(unsigned int, unsigned int); |
165 DFn fn = DFn(f); | 187 DFn fn = DFn(f); |
166 unsigned int index = 0; | 188 unsigned int index = 0; |
167 while (fn(2, index)) ++index; | 189 while (fn(2, index)) ++index; |
168 if (index == 0) return "Library contains no plugins"; | 190 if (index == 0) return { PluginCheckCode::FAIL_NO_PLUGINS, "" }; |
169 return ""; | 191 return { PluginCheckCode::SUCCESS, "" }; |
170 } | 192 } |
171 | 193 |
172 string check(string soname, string descriptor) | 194 Result check(string soname, string descriptor) |
173 { | 195 { |
174 void *handle = DLOPEN(soname, RTLD_NOW | RTLD_LOCAL); | 196 void *handle = DLOPEN(soname, RTLD_NOW | RTLD_LOCAL); |
175 if (!handle) { | 197 if (!handle) { |
176 return "Unable to open plugin library: " + error(); | 198 PluginCheckCode code = PluginCheckCode::FAIL_NOT_LOADABLE; |
177 } | 199 string message = error(); |
178 | 200 #ifdef _WIN32 |
179 string msg = ""; | 201 DWORD err = GetLastError(); |
202 if (err == ERROR_BAD_EXE_FORMAT) { | |
203 code = PluginCheckCode::FAIL_WRONG_ARCHITECTURE; | |
204 } else if (err == ERROR_MOD_NOT_FOUND) { | |
205 code = PluginCheckCode::FAIL_DEPENDENCY_MISSING; | |
206 } | |
207 #endif | |
208 return { code, message }; | |
209 } | |
210 | |
211 Result result { PluginCheckCode::SUCCESS, "" }; | |
180 | 212 |
181 void *fn = DLSYM(handle, descriptor); | 213 void *fn = DLSYM(handle, descriptor); |
182 if (!fn) { | 214 if (!fn) { |
183 msg = "Failed to find plugin descriptor " + descriptor + | 215 result = { PluginCheckCode::FAIL_DESCRIPTOR_MISSING, error() }; |
184 " in library: " + error(); | |
185 } else if (descriptor == "ladspa_descriptor") { | 216 } else if (descriptor == "ladspa_descriptor") { |
186 msg = checkLADSPAStyleDescriptorFn(fn); | 217 result = checkLADSPAStyleDescriptorFn(fn); |
187 } else if (descriptor == "dssi_descriptor") { | 218 } else if (descriptor == "dssi_descriptor") { |
188 msg = checkLADSPAStyleDescriptorFn(fn); | 219 result = checkLADSPAStyleDescriptorFn(fn); |
189 } else if (descriptor == "vampGetPluginDescriptor") { | 220 } else if (descriptor == "vampGetPluginDescriptor") { |
190 msg = checkVampDescriptorFn(fn); | 221 result = checkVampDescriptorFn(fn); |
191 } else { | 222 } else { |
192 cerr << "Note: no descriptor logic known for descriptor function \"" | 223 cerr << "Note: no descriptor logic known for descriptor function \"" |
193 << descriptor << "\"; not actually calling it" << endl; | 224 << descriptor << "\"; not actually calling it" << endl; |
194 } | 225 } |
195 | 226 |
196 DLCLOSE(handle); | 227 DLCLOSE(handle); |
197 | 228 |
198 return msg; | 229 return result; |
199 } | 230 } |
200 | 231 |
201 int main(int argc, char **argv) | 232 int main(int argc, char **argv) |
202 { | 233 { |
203 bool allGood = true; | 234 bool allGood = true; |
208 if (argc > 1) { | 239 if (argc > 1) { |
209 string opt = argv[1]; | 240 string opt = argv[1]; |
210 if (opt == "-?" || opt == "-h" || opt == "--help") { | 241 if (opt == "-?" || opt == "-h" || opt == "--help") { |
211 showUsage = true; | 242 showUsage = true; |
212 } else if (opt == "-v" || opt == "--version") { | 243 } else if (opt == "-v" || opt == "--version") { |
213 cout << CHECKER_VERSION << endl; | 244 cout << CHECKER_COMPATIBILITY_VERSION << endl; |
214 return 0; | 245 return 0; |
215 } | 246 } |
216 } | 247 } |
217 | 248 |
218 if (argc != 2 || showUsage) { | 249 if (argc != 2 || showUsage) { |
237 // fail anyway. | 268 // fail anyway. |
238 SetErrorMode(SEM_FAILCRITICALERRORS); | 269 SetErrorMode(SEM_FAILCRITICALERRORS); |
239 #endif | 270 #endif |
240 | 271 |
241 while (getline(cin, soname)) { | 272 while (getline(cin, soname)) { |
242 string report = check(soname, descriptor); | 273 Result result = check(soname, descriptor); |
243 if (report != "") { | 274 if (result.code == PluginCheckCode::SUCCESS) { |
244 cout << "FAILURE|" << soname << "|" << report << endl; | 275 cout << "SUCCESS|" << soname << "|" << endl; |
276 } else { | |
277 if (result.message == "") { | |
278 cout << "FAILURE|" << soname | |
279 << "|[" << int(result.code) << "]" << endl; | |
280 } else { | |
281 cout << "FAILURE|" << soname | |
282 << "|" << result.message << " [" | |
283 << int(result.code) << "]" << endl; | |
284 } | |
245 allGood = false; | 285 allGood = false; |
246 } else { | |
247 cout << "SUCCESS|" << soname << "|" << endl; | |
248 } | 286 } |
249 } | 287 } |
250 | 288 |
251 return allGood ? 0 : 1; | 289 return allGood ? 0 : 1; |
252 } | 290 } |