diff 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
line wrap: on
line diff
--- a/src/helper.cpp	Tue Aug 28 14:33:41 2018 +0100
+++ b/src/helper.cpp	Wed Aug 29 17:40:22 2018 +0100
@@ -19,7 +19,17 @@
  * SUCCESS|/path/to/libname.so|
  * 
  * Output line for failed load of library libname.so:
- * FAILURE|/path/to/libname.so|Reason for failure if available
+ * FAILURE|/path/to/libname.so|Error message [failureCode]
+ *
+ * or:
+ * FAILURE|/path/to/libname.so|[failureCode]
+ *
+ * where the error message is an optional system-level message, such
+ * as may be returned from strerror or similar (which should be in the
+ * native language for the system ready to show the user), and the
+ * failureCode in square brackets is a mandatory number corresponding
+ * to one of the PluginCandidates::FailureCode values (requiring
+ * conversion to a translated string by the client).
  *
  * Although this program was written for use with Vamp audio analysis
  * plugins, it also works with other plugin formats. The program has
@@ -64,6 +74,8 @@
 
 #include "../version.h"
 
+#include "../checker/checkcode.h"
+
 static const char programName[] = "vamp-plugin-load-checker";
 
 #ifdef _WIN32
@@ -78,7 +90,9 @@
 #ifndef UNICODE
 #error "This must be compiled with UNICODE defined"
 #endif
+
 static std::string lastLibraryName = "";
+
 static HMODULE LoadLibraryUTF8(std::string name) {
     lastLibraryName = name;
     int n = name.size();
@@ -90,6 +104,7 @@
     delete[] wname;
     return h;
 }
+
 static std::string GetErrorText() {
     DWORD err = GetLastError();
     wchar_t *buffer;
@@ -99,7 +114,7 @@
         FORMAT_MESSAGE_IGNORE_INSERTS,
         NULL,
         err,
-        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+        MAKELANGID(LANG_USER_DEFAULT, SUBLANG_USER_DEFAULT),
         (LPWSTR) &buffer,
         0, NULL );
     int wn = wcslen(buffer);
@@ -126,16 +141,20 @@
     }
     return s;
 }
+
 #define DLOPEN(a,b)  LoadLibraryUTF8(a)
 #define DLSYM(a,b)   (void *)GetProcAddress((HINSTANCE)(a),(b).c_str())
 #define DLCLOSE(a)   (!FreeLibrary((HINSTANCE)(a)))
 #define DLERROR()    (GetErrorText())
+
 #else
+
 #include <dlfcn.h>
 #define DLOPEN(a,b)  dlopen((a).c_str(),(b))
 #define DLSYM(a,b)   dlsym((a),(b).c_str())
 #define DLCLOSE(a)   dlclose((a))
 #define DLERROR()    dlerror()
+
 #endif
 
 //#include <unistd.h>
@@ -144,50 +163,62 @@
 
 string error()
 {
-    string e = DLERROR();
-    if (e == "") return "(unknown error)";
-    else return e;
+    return DLERROR();
 }
 
-string checkLADSPAStyleDescriptorFn(void *f)
+struct Result {
+    PluginCheckCode code;
+    string message;
+};
+
+Result checkLADSPAStyleDescriptorFn(void *f)
 {
     typedef const void *(*DFn)(unsigned long);
     DFn fn = DFn(f);
     unsigned long index = 0;
     while (fn(index)) ++index;
-    if (index == 0) return "Library contains no plugins";
-    return "";
+    if (index == 0) return { PluginCheckCode::FAIL_NO_PLUGINS, "" };
+    return { PluginCheckCode::SUCCESS, "" };
 }
 
-string checkVampDescriptorFn(void *f)
+Result checkVampDescriptorFn(void *f)
 {
     typedef const void *(*DFn)(unsigned int, unsigned int);
     DFn fn = DFn(f);
     unsigned int index = 0;
     while (fn(2, index)) ++index;
-    if (index == 0) return "Library contains no plugins";
-    return "";
+    if (index == 0) return { PluginCheckCode::FAIL_NO_PLUGINS, "" };
+    return { PluginCheckCode::SUCCESS, "" };
 }
 
-string check(string soname, string descriptor)
+Result check(string soname, string descriptor)
 {
     void *handle = DLOPEN(soname, RTLD_NOW | RTLD_LOCAL);
     if (!handle) {
-        return "Unable to open plugin library: " + error();
+        PluginCheckCode code = PluginCheckCode::FAIL_NOT_LOADABLE;
+        string message = error();
+#ifdef _WIN32
+        DWORD err = GetLastError();
+        if (err == ERROR_BAD_EXE_FORMAT) {
+            code = PluginCheckCode::FAIL_WRONG_ARCHITECTURE;
+        } else if (err == ERROR_MOD_NOT_FOUND) {
+            code = PluginCheckCode::FAIL_DEPENDENCY_MISSING;
+        }
+#endif
+        return { code, message };
     }
 
-    string msg = "";
+    Result result { PluginCheckCode::SUCCESS, "" };
     
     void *fn = DLSYM(handle, descriptor);
     if (!fn) {
-        msg = "Failed to find plugin descriptor " + descriptor +
-            " in library: " + error();
+        result = { PluginCheckCode::FAIL_DESCRIPTOR_MISSING, error() };
     } else if (descriptor == "ladspa_descriptor") {
-        msg = checkLADSPAStyleDescriptorFn(fn);
+        result = checkLADSPAStyleDescriptorFn(fn);
     } else if (descriptor == "dssi_descriptor") {
-        msg = checkLADSPAStyleDescriptorFn(fn);
+        result = checkLADSPAStyleDescriptorFn(fn);
     } else if (descriptor == "vampGetPluginDescriptor") {
-        msg = checkVampDescriptorFn(fn);
+        result = checkVampDescriptorFn(fn);
     } else {
         cerr << "Note: no descriptor logic known for descriptor function \""
              << descriptor << "\"; not actually calling it" << endl;
@@ -195,7 +226,7 @@
 
     DLCLOSE(handle);
     
-    return msg;
+    return result;
 }
 
 int main(int argc, char **argv)
@@ -210,7 +241,7 @@
         if (opt == "-?" || opt == "-h" || opt == "--help") {
             showUsage = true;
         } else if (opt == "-v" || opt == "--version") {
-            cout << CHECKER_VERSION << endl;
+            cout << CHECKER_COMPATIBILITY_VERSION << endl;
             return 0;
         }
     } 
@@ -239,12 +270,19 @@
 #endif
 
     while (getline(cin, soname)) {
-        string report = check(soname, descriptor);
-        if (report != "") {
-            cout << "FAILURE|" << soname << "|" << report << endl;
+        Result result = check(soname, descriptor);
+        if (result.code == PluginCheckCode::SUCCESS) {
+            cout << "SUCCESS|" << soname << "|" << endl;
+        } else {
+            if (result.message == "") {
+                cout << "FAILURE|" << soname
+                     << "|[" << int(result.code) << "]" << endl;
+            } else {
+                cout << "FAILURE|" << soname
+                     << "|" << result.message << " ["
+                     << int(result.code) << "]" << endl;
+            }
             allGood = false;
-        } else {
-            cout << "SUCCESS|" << soname << "|" << endl;
         }
     }