changeset 1653:0c86b30bb8b2

merge
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 28 Sep 2015 13:49:48 +0200
parents 69f7822ee254 (current diff) 2e692c83e2f3 (diff)
children 3727a09e7b53
files
diffstat 16 files changed, 289 insertions(+), 77 deletions(-) [+]
line wrap: on
line diff
--- a/Core/Enumerations.cpp	Mon Sep 28 13:49:35 2015 +0200
+++ b/Core/Enumerations.cpp	Mon Sep 28 13:49:48 2015 +0200
@@ -44,6 +44,11 @@
   // "Resources/GenerateErrorCodes.py"
   const char* EnumerationToString(ErrorCode error)
   {
+    if (error >= ErrorCode_START_PLUGINS)
+    {
+      return "Error encountered within some plugin";
+    }
+
     switch (error)
     {
       case ErrorCode_InternalError:
--- a/Core/HttpServer/MongooseServer.cpp	Mon Sep 28 13:49:35 2015 +0200
+++ b/Core/HttpServer/MongooseServer.cpp	Mon Sep 28 13:49:48 2015 +0200
@@ -749,12 +749,11 @@
     catch (OrthancException& e)
     {
       // Using this candidate handler results in an exception
-      LOG(ERROR) << "Exception in the HTTP handler: " << e.What();
-
       try
       {
         if (that->GetExceptionFormatter() == NULL)
         {
+          LOG(ERROR) << "Exception in the HTTP handler: " << e.What();
           output.SendStatus(e.GetHttpStatus());
         }
         else
--- a/Core/Toolbox.cpp	Mon Sep 28 13:49:35 2015 +0200
+++ b/Core/Toolbox.cpp	Mon Sep 28 13:49:48 2015 +0200
@@ -527,6 +527,29 @@
   {
     result = base64_decode(data);
   }
+
+
+#  if BOOST_HAS_REGEX == 1
+  void Toolbox::DecodeDataUriScheme(std::string& mime,
+                                    std::string& content,
+                                    const std::string& source)
+  {
+    boost::regex pattern("data:([^;]+);base64,([a-zA-Z0-9=+/]*)",
+                         boost::regex::icase /* case insensitive search */);
+
+    boost::cmatch what;
+    if (regex_match(source.c_str(), what, pattern))
+    {
+      mime = what[1];
+      DecodeBase64(content, what[2]);
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+  }
+#  endif
+
 #endif
 
 
@@ -1009,28 +1032,6 @@
   }
 
 
-#if BOOST_HAS_REGEX == 1
-  void Toolbox::DecodeDataUriScheme(std::string& mime,
-                                    std::string& content,
-                                    const std::string& source)
-  {
-    boost::regex pattern("data:([^;]+);base64,([a-zA-Z0-9=+/]*)",
-                         boost::regex::icase /* case insensitive search */);
-
-    boost::cmatch what;
-    if (regex_match(source.c_str(), what, pattern))
-    {
-      mime = what[1];
-      DecodeBase64(content, what[2]);
-    }
-    else
-    {
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-  }
-#endif
-
-
   void Toolbox::MakeDirectory(const std::string& path)
   {
     if (boost::filesystem::exists(path))
--- a/Core/Toolbox.h	Mon Sep 28 13:49:35 2015 +0200
+++ b/Core/Toolbox.h	Mon Sep 28 13:49:48 2015 +0200
@@ -117,6 +117,12 @@
 
     void EncodeBase64(std::string& result, 
                       const std::string& data);
+
+#  if BOOST_HAS_REGEX == 1
+    void DecodeDataUriScheme(std::string& mime,
+                             std::string& content,
+                             const std::string& source);
+#  endif
 #endif
 
     std::string GetPathToExecutable();
@@ -153,12 +159,6 @@
                         const std::string& source,
                         char separator);
 
-#if BOOST_HAS_REGEX == 1
-    void DecodeDataUriScheme(std::string& mime,
-                             std::string& content,
-                             const std::string& source);
-#endif
-
     void MakeDirectory(const std::string& path);
 
     bool IsExistingFile(const std::string& path);
--- a/NEWS	Mon Sep 28 13:49:35 2015 +0200
+++ b/NEWS	Mon Sep 28 13:49:48 2015 +0200
@@ -4,6 +4,11 @@
 * Add ".dcm" suffix to files in ZIP archives (cf. URI ".../archive")
 * "/tools/create-dicom": Support of binary tags encoded using data URI scheme
 
+Plugins
+-------
+
+* New function "OrthancPluginRegisterErrorCode()" to declare custom error codes
+
 Maintenance
 -----------
 
--- a/OrthancServer/main.cpp	Mon Sep 28 13:49:35 2015 +0200
+++ b/OrthancServer/main.cpp	Mon Sep 28 13:49:48 2015 +0200
@@ -327,42 +327,61 @@
                       HttpMethod method,
                       const char* uri)
   {
-    if (!describeErrors_)
     {
-      output.SendStatus(exception.GetHttpStatus());
-      return;
-    }
+      bool isPlugin = false;
+
+#if ORTHANC_PLUGINS_ENABLED == 1
+      if (plugins_ != NULL)
+      {
+        plugins_->GetErrorDictionary().LogError(exception.GetErrorCode(), true);
+        isPlugin = true;
+      }
+#endif
+
+      if (!isPlugin)
+      {
+        LOG(ERROR) << "Exception in the HTTP handler: " << exception.What();
+      }
+    }      
 
     Json::Value message = Json::objectValue;
-    message["Method"] = EnumerationToString(method);
-    message["Uri"] = uri;
-
     ErrorCode errorCode = exception.GetErrorCode();
     HttpStatus httpStatus = exception.GetHttpStatus();
 
-    bool isPlugin = false;
+    {
+      bool isPlugin = false;
 
 #if ORTHANC_PLUGINS_ENABLED == 1
-    if (plugins_ != NULL &&
-        plugins_->GetErrorDictionary().Format(message, httpStatus, exception))
-    {
-      errorCode = ErrorCode_Plugin;
-      isPlugin = true;
-    }
+      if (plugins_ != NULL &&
+          plugins_->GetErrorDictionary().Format(message, httpStatus, exception))
+      {
+        errorCode = ErrorCode_Plugin;
+        isPlugin = true;
+      }
 #endif
 
-    if (!isPlugin)
-    {
-      message["Message"] = exception.What();
+      if (!isPlugin)
+      {
+        message["Message"] = exception.What();
+      }
     }
 
-    message["HttpError"] = EnumerationToString(httpStatus);
-    message["HttpStatus"] = httpStatus;
-    message["OrthancError"] = EnumerationToString(errorCode);
-    message["OrthancStatus"] = errorCode;
+    if (!describeErrors_)
+    {
+      output.SendStatus(httpStatus);
+    }
+    else
+    {
+      message["Method"] = EnumerationToString(method);
+      message["Uri"] = uri;
+      message["HttpError"] = EnumerationToString(httpStatus);
+      message["HttpStatus"] = httpStatus;
+      message["OrthancError"] = EnumerationToString(errorCode);
+      message["OrthancStatus"] = errorCode;
 
-    std::string info = message.toStyledString();
-    output.SendStatus(httpStatus, info);
+      std::string info = message.toStyledString();
+      output.SendStatus(httpStatus, info);
+    }
   }
 };
 
--- a/Plugins/Engine/OrthancPluginDatabase.cpp	Mon Sep 28 13:49:35 2015 +0200
+++ b/Plugins/Engine/OrthancPluginDatabase.cpp	Mon Sep 28 13:49:48 2015 +0200
@@ -194,11 +194,13 @@
 
 
   OrthancPluginDatabase::OrthancPluginDatabase(SharedLibrary& library,
+                                               PluginsErrorDictionary&  errorDictionary,
                                                const OrthancPluginDatabaseBackend& backend,
                                                const OrthancPluginDatabaseExtensions* extensions,
                                                size_t extensionsSize,
                                                void *payload) : 
     library_(library),
+    errorDictionary_(errorDictionary),
     type_(_OrthancPluginDatabaseAnswerType_None),
     backend_(backend),
     payload_(payload),
@@ -236,6 +238,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -248,6 +251,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -259,6 +263,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -270,6 +275,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -284,6 +290,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -298,6 +305,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -310,6 +318,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -321,6 +330,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -357,6 +367,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -379,6 +390,7 @@
 
       if (error != OrthancPluginErrorCode_Success)
       {
+        errorDictionary_.LogError(error, true);
         throw OrthancException(static_cast<ErrorCode>(error));
       }
 
@@ -432,6 +444,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -446,6 +459,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -462,6 +476,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -483,6 +498,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -500,6 +516,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -517,6 +534,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -532,6 +550,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -546,6 +565,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
     
@@ -566,6 +586,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -581,6 +602,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -596,6 +618,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -611,6 +634,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -626,6 +650,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -641,6 +666,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -657,6 +683,7 @@
  
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -688,6 +715,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -724,6 +752,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -746,6 +775,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -762,6 +792,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -792,6 +823,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -814,6 +846,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -830,6 +863,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -847,6 +881,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -863,6 +898,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -880,6 +916,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -909,6 +946,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -925,6 +963,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
 
@@ -940,6 +979,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -967,6 +1007,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -981,6 +1022,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -993,6 +1035,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
+      errorDictionary_.LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -1003,12 +1046,15 @@
   private:
     const OrthancPluginDatabaseBackend& backend_;
     void* payload_;
+    PluginsErrorDictionary&  errorDictionary_;
 
   public:
     Transaction(const OrthancPluginDatabaseBackend& backend,
-                void* payload) :
+                void* payload,
+                PluginsErrorDictionary&  errorDictionary) :
       backend_(backend),
-      payload_(payload)
+      payload_(payload),
+      errorDictionary_(errorDictionary)
     {
     }
 
@@ -1018,6 +1064,7 @@
 
       if (error != OrthancPluginErrorCode_Success)
       {
+        errorDictionary_.LogError(error, true);
         throw OrthancException(static_cast<ErrorCode>(error));
       }
     }
@@ -1028,6 +1075,7 @@
 
       if (error != OrthancPluginErrorCode_Success)
       {
+        errorDictionary_.LogError(error, true);
         throw OrthancException(static_cast<ErrorCode>(error));
       }
     }
@@ -1038,6 +1086,7 @@
 
       if (error != OrthancPluginErrorCode_Success)
       {
+        errorDictionary_.LogError(error, true);
         throw OrthancException(static_cast<ErrorCode>(error));
       }
     }
@@ -1046,7 +1095,7 @@
 
   SQLite::ITransaction* OrthancPluginDatabase::StartTransaction()
   {
-    return new Transaction(backend_, payload_);
+    return new Transaction(backend_, payload_, errorDictionary_);
   }
 
 
@@ -1093,6 +1142,7 @@
 
       if (error != OrthancPluginErrorCode_Success)
       {
+        errorDictionary_.LogError(error, true);
         throw OrthancException(static_cast<ErrorCode>(error));
       }
 
@@ -1119,6 +1169,7 @@
 
       if (error != OrthancPluginErrorCode_Success)
       {
+        errorDictionary_.LogError(error, true);
         throw OrthancException(static_cast<ErrorCode>(error));
       }
     }
--- a/Plugins/Engine/OrthancPluginDatabase.h	Mon Sep 28 13:49:35 2015 +0200
+++ b/Plugins/Engine/OrthancPluginDatabase.h	Mon Sep 28 13:49:48 2015 +0200
@@ -36,6 +36,7 @@
 
 #include "../../OrthancServer/IDatabaseWrapper.h"
 #include "../Include/orthanc/OrthancCDatabasePlugin.h"
+#include "PluginsErrorDictionary.h"
 #include "SharedLibrary.h"
 
 namespace Orthanc
@@ -48,6 +49,7 @@
     typedef std::pair<int64_t, ResourceType>  AnswerResource;
 
     SharedLibrary&  library_;
+    PluginsErrorDictionary&  errorDictionary_;
     _OrthancPluginDatabaseAnswerType type_;
     OrthancPluginDatabaseBackend backend_;
     OrthancPluginDatabaseExtensions extensions_;
@@ -82,6 +84,7 @@
 
   public:
     OrthancPluginDatabase(SharedLibrary& library,
+                          PluginsErrorDictionary&  errorDictionary,
                           const OrthancPluginDatabaseBackend& backend,
                           const OrthancPluginDatabaseExtensions* extensions,
                           size_t extensionsSize,
--- a/Plugins/Engine/OrthancPlugins.cpp	Mon Sep 28 13:49:35 2015 +0200
+++ b/Plugins/Engine/OrthancPlugins.cpp	Mon Sep 28 13:49:48 2015 +0200
@@ -66,6 +66,7 @@
     {
     private:
       _OrthancPluginRegisterStorageArea callbacks_;
+      PluginsErrorDictionary&  errorDictionary_;
 
       void Free(void* buffer) const
       {
@@ -76,7 +77,10 @@
       }
 
     public:
-      PluginStorageArea(const _OrthancPluginRegisterStorageArea& callbacks) : callbacks_(callbacks)
+      PluginStorageArea(const _OrthancPluginRegisterStorageArea& callbacks,
+                        PluginsErrorDictionary&  errorDictionary) : 
+        callbacks_(callbacks),
+        errorDictionary_(errorDictionary)
       {
       }
 
@@ -91,6 +95,7 @@
 
         if (error != OrthancPluginErrorCode_Success)
         {
+          errorDictionary_.LogError(error, true);
           throw OrthancException(static_cast<ErrorCode>(error));
         }
       }
@@ -108,6 +113,7 @@
 
         if (error != OrthancPluginErrorCode_Success)
         {
+          errorDictionary_.LogError(error, true);
           throw OrthancException(static_cast<ErrorCode>(error));
         }
 
@@ -138,6 +144,7 @@
 
         if (error != OrthancPluginErrorCode_Success)
         {
+          errorDictionary_.LogError(error, true);
           throw OrthancException(static_cast<ErrorCode>(error));
         }
       }
@@ -149,12 +156,15 @@
     private:
       SharedLibrary&   sharedLibrary_;
       _OrthancPluginRegisterStorageArea  callbacks_;
+      PluginsErrorDictionary&  errorDictionary_;
 
     public:
       StorageAreaFactory(SharedLibrary& sharedLibrary,
-                         const _OrthancPluginRegisterStorageArea& callbacks) :
+                         const _OrthancPluginRegisterStorageArea& callbacks,
+                         PluginsErrorDictionary&  errorDictionary) :
         sharedLibrary_(sharedLibrary),
-        callbacks_(callbacks)
+        callbacks_(callbacks),
+        errorDictionary_(errorDictionary)
       {
       }
 
@@ -165,7 +175,7 @@
 
       IStorageArea* Create() const
       {
-        return new PluginStorageArea(callbacks_);
+        return new PluginStorageArea(callbacks_, errorDictionary_);
       }
     };
   }
@@ -464,6 +474,7 @@
     }
     else
     {
+      GetErrorDictionary().LogError(error, true);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -485,6 +496,7 @@
 
       if (error != OrthancPluginErrorCode_Success)
       {
+        GetErrorDictionary().LogError(error, true);
         throw OrthancException(static_cast<ErrorCode>(error));
       }
     }
@@ -507,6 +519,7 @@
 
       if (error != OrthancPluginErrorCode_Success)
       {
+        GetErrorDictionary().LogError(error, true);
         throw OrthancException(static_cast<ErrorCode>(error));
       }
     }
@@ -1378,7 +1391,7 @@
         
         if (pimpl_->storageArea_.get() == NULL)
         {
-          pimpl_->storageArea_.reset(new StorageAreaFactory(plugin, p));
+          pimpl_->storageArea_.reset(new StorageAreaFactory(plugin, p, GetErrorDictionary()));
         }
         else
         {
@@ -1457,7 +1470,8 @@
 
         if (pimpl_->database_.get() == NULL)
         {
-          pimpl_->database_.reset(new OrthancPluginDatabase(plugin, *p.backend, NULL, 0, p.payload));
+          pimpl_->database_.reset(new OrthancPluginDatabase(plugin, GetErrorDictionary(), 
+                                                            *p.backend, NULL, 0, p.payload));
         }
         else
         {
@@ -1478,7 +1492,8 @@
 
         if (pimpl_->database_.get() == NULL)
         {
-          pimpl_->database_.reset(new OrthancPluginDatabase(plugin, *p.backend, p.extensions,
+          pimpl_->database_.reset(new OrthancPluginDatabase(plugin, GetErrorDictionary(),
+                                                            *p.backend, p.extensions,
                                                             p.extensionsSize, p.payload));
         }
         else
@@ -1674,6 +1689,14 @@
         return true;
       }
 
+      case _OrthancPluginService_RegisterErrorCode:
+      {
+        const _OrthancPluginRegisterErrorCode& p =
+          *reinterpret_cast<const _OrthancPluginRegisterErrorCode*>(parameters);
+        *(p.target) = pimpl_->dictionary_.Register(plugin, p.code, p.httpStatus, p.message);
+        return true;
+      }
+
       default:
       {
         // This service is unknown to the Orthanc plugin engine
--- a/Plugins/Engine/PluginsErrorDictionary.cpp	Mon Sep 28 13:49:35 2015 +0200
+++ b/Plugins/Engine/PluginsErrorDictionary.cpp	Mon Sep 28 13:49:48 2015 +0200
@@ -41,6 +41,7 @@
 
 #include "PluginsEnumerations.h"
 #include "PluginsManager.h"
+#include "../../Core/Logging.h"
 
 #include <memory>
 
@@ -62,16 +63,16 @@
   }
 
 
-  OrthancPluginErrorCode PluginsErrorDictionary::Register(const std::string& pluginName,
+  OrthancPluginErrorCode PluginsErrorDictionary::Register(SharedLibrary& library,
                                                           int32_t  pluginCode,
                                                           uint16_t httpStatus,
-                                                          const char* description)
+                                                          const char* message)
   {
     std::auto_ptr<Error> error(new Error);
 
-    error->pluginName_ = pluginName;
+    error->pluginName_ = PluginsManager::GetPluginName(library);
     error->pluginCode_ = pluginCode;
-    error->description_ = description;
+    error->message_ = message;
     error->httpStatus_ = static_cast<HttpStatus>(httpStatus);
 
     OrthancPluginErrorCode code;
@@ -87,7 +88,32 @@
   }
 
 
-  bool  PluginsErrorDictionary::Format(Json::Value& message,  /* out */
+  void  PluginsErrorDictionary::LogError(ErrorCode code,
+                                         bool ignoreBuiltinErrors)
+  {
+    if (code >= ErrorCode_START_PLUGINS)
+    {
+      boost::mutex::scoped_lock lock(mutex_);
+      Errors::const_iterator error = errors_.find(static_cast<int32_t>(code));
+      
+      if (error != errors_.end())
+      {
+        LOG(ERROR) << "Error code " << error->second->pluginCode_
+                   << " inside plugin \"" << error->second->pluginName_
+                   << "\": " << error->second->message_;
+        return;
+      }
+    }
+
+    if (!ignoreBuiltinErrors)
+    {
+      LOG(ERROR) << "Exception inside the plugin engine: "
+                 << EnumerationToString(code);
+    }
+  }
+
+
+  bool  PluginsErrorDictionary::Format(Json::Value& message,    /* out */
                                        HttpStatus& httpStatus,  /* out */
                                        const OrthancException& exception)
   {
@@ -101,7 +127,7 @@
         httpStatus = error->second->httpStatus_;
         message["PluginName"] = error->second->pluginName_;
         message["PluginCode"] = error->second->pluginCode_;
-        message["Message"] = error->second->description_;
+        message["Message"] = error->second->message_;
 
         return true;
       }
--- a/Plugins/Engine/PluginsErrorDictionary.h	Mon Sep 28 13:49:35 2015 +0200
+++ b/Plugins/Engine/PluginsErrorDictionary.h	Mon Sep 28 13:49:48 2015 +0200
@@ -36,6 +36,7 @@
 
 #include "../Include/orthanc/OrthancCPlugin.h"
 #include "../../Core/OrthancException.h"
+#include "SharedLibrary.h"
 
 #include <map>
 #include <string>
@@ -54,7 +55,7 @@
       std::string  pluginName_;
       int32_t      pluginCode_;
       HttpStatus   httpStatus_;
-      std::string  description_;
+      std::string  message_;
     };
     
     typedef std::map<int32_t, Error*>  Errors;
@@ -68,12 +69,21 @@
 
     ~PluginsErrorDictionary();
 
-    OrthancPluginErrorCode  Register(const std::string& pluginName,
+    OrthancPluginErrorCode  Register(SharedLibrary& library,
                                      int32_t  pluginCode,
                                      uint16_t httpStatus,
-                                     const char* description);
+                                     const char* message);
+
+    void  LogError(ErrorCode code,
+                   bool ignoreBuiltinErrors);
 
-    bool  Format(Json::Value& message,  /* out */
+    void  LogError(OrthancPluginErrorCode code,
+                   bool ignoreBuiltinErrors)
+    {
+      LogError(static_cast<ErrorCode>(code), ignoreBuiltinErrors);
+    }
+
+    bool  Format(Json::Value& message,    /* out */
                  HttpStatus& httpStatus,  /* out */
                  const OrthancException& exception);
   };
--- a/Plugins/Include/orthanc/OrthancCPlugin.h	Mon Sep 28 13:49:35 2015 +0200
+++ b/Plugins/Include/orthanc/OrthancCPlugin.h	Mon Sep 28 13:49:48 2015 +0200
@@ -383,6 +383,7 @@
     _OrthancPluginService_WriteFile = 16,
     _OrthancPluginService_GetErrorDescription = 17,
     _OrthancPluginService_CallHttpClient = 18,
+    _OrthancPluginService_RegisterErrorCode = 19,
 
     /* Registration of callbacks */
     _OrthancPluginService_RegisterRestCallback = 1000,
@@ -3598,7 +3599,6 @@
     OrthancPluginContentType    type;
   } _OrthancPluginStorageAreaRemove;
 
-
   /**
    * @brief Remove a file from the storage area.
    *
@@ -3628,6 +3628,55 @@
 
 
 
+  typedef struct
+  {
+    OrthancPluginErrorCode*  target;
+    int32_t                  code;
+    uint16_t                 httpStatus;
+    const char*              message;
+  } _OrthancPluginRegisterErrorCode;
+  
+  /**
+   * @brief Declare a custom error code for this plugin.
+   *
+   * This function declares a custom error code that can be generated
+   * by this plugin. This declaration is used to enrich the body of
+   * the HTTP answer in the case of an error, and to set the proper
+   * HTTP status code.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param code The error code that is internal to this plugin.
+   * @param httpStatus The HTTP status corresponding to this error.
+   * @param message The description of the error.
+   * @return The error code that has been assigned inside the Orthanc core.
+   * @ingroup Toolbox
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginRegisterErrorCode(
+    OrthancPluginContext*    context,
+    int32_t                  code,
+    uint16_t                 httpStatus,
+    const char*              message)
+  {
+    OrthancPluginErrorCode target;
+
+    _OrthancPluginRegisterErrorCode params;
+    params.target = &target;
+    params.code = code;
+    params.httpStatus = httpStatus;
+    params.message = message;
+
+    if (context->InvokeService(context, _OrthancPluginService_RegisterErrorCode, &params) == OrthancPluginErrorCode_Success)
+    {
+      return target;
+    }
+    else
+    {
+      /* There was an error while assigned the error. Use a generic code. */
+      return OrthancPluginErrorCode_Plugin;
+    }
+  }
+
+
 #ifdef  __cplusplus
 }
 #endif
--- a/Plugins/Samples/Basic/Plugin.c	Mon Sep 28 13:49:35 2015 +0200
+++ b/Plugins/Samples/Basic/Plugin.c	Mon Sep 28 13:49:48 2015 +0200
@@ -25,6 +25,8 @@
 
 static OrthancPluginContext* context = NULL;
 
+static OrthancPluginErrorCode customError;
+
 
 ORTHANC_PLUGINS_API int32_t Callback1(OrthancPluginRestOutput* output,
                                       const char* url,
@@ -401,6 +403,8 @@
   sprintf(info, "[ \"STORESCP\", \"localhost\", 2000 ]");
   OrthancPluginRestApiPut(context, &tmp, "/modalities/demo", info, strlen(info));
 
+  customError = OrthancPluginRegisterErrorCode(context, 4, 402, "Hello world");
+
   return 0;
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Samples/Common/ExportedSymbols.list	Mon Sep 28 13:49:48 2015 +0200
@@ -0,0 +1,7 @@
+# This is the list of the symbols that must be exported by Orthanc
+# plugins, if targeting OS X
+
+_OrthancPluginInitialize
+_OrthancPluginFinalize
+_OrthancPluginGetName
+_OrthancPluginGetVersion
--- a/Plugins/Samples/Common/OrthancPlugins.cmake	Mon Sep 28 13:49:35 2015 +0200
+++ b/Plugins/Samples/Common/OrthancPlugins.cmake	Mon Sep 28 13:49:48 2015 +0200
@@ -6,6 +6,7 @@
   link_libraries(uuid)
   SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread")
   SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pthread")
+
 elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
   link_libraries(rpcrt4 ws2_32 secur32)
   if (CMAKE_COMPILER_IS_GNUCXX)
@@ -21,8 +22,16 @@
 endif ()
 
 
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
+    ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR
+    ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
+  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script=${SAMPLES_ROOT}/Common/VersionScript.map -Wl,--no-undefined")
+elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
+  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -exported_symbols_list ${CMAKE_SOURCE_DIR}/Plugins/Samples/Common/ExportedSymbols.list")
+endif()
+
+
 if (CMAKE_COMPILER_IS_GNUCXX)
-  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script=${SAMPLES_ROOT}/Common/VersionScript.map -Wl,--no-undefined")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic")
 endif()
@@ -34,7 +43,6 @@
   link_libraries(dl rt)
 endif()
 
-
 include_directories(${SAMPLES_ROOT}/../Include/)
 
 if (MSVC)
--- a/Resources/CMake/Compiler.cmake	Mon Sep 28 13:49:35 2015 +0200
+++ b/Resources/CMake/Compiler.cmake	Mon Sep 28 13:49:48 2015 +0200
@@ -50,7 +50,7 @@
     ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR
     ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
   set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined")
-  set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
+  set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined -Wl,--version-script=${ORTHANC_ROOT}/Plugins/Samples/Common/VersionScript.map")
 
   # Remove the "-rdynamic" option
   # http://www.mail-archive.com/cmake@cmake.org/msg08837.html
@@ -108,6 +108,8 @@
   endif()
 
 elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
+  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -exported_symbols_list ${ORTHANC_ROOT}/Plugins/Samples/Common/ExportedSymbols.list")
+
   add_definitions(
     -D_XOPEN_SOURCE=1
     )