changeset 1582:bd1889029cbb

encoding of exceptions
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 25 Aug 2015 17:39:38 +0200
parents 357c4bb15701
children 9ea3d082b064
files Core/Compression/DeflateBaseCompressor.cpp Core/Compression/ZipWriter.cpp Core/Compression/ZlibCompressor.cpp Core/Enumerations.cpp Core/Enumerations.h Core/FileStorage/FilesystemStorage.cpp Core/HttpServer/FilesystemHttpHandler.cpp Core/HttpServer/MongooseServer.cpp Core/OrthancException.h Core/RestApi/RestApiOutput.cpp Core/SQLite/Connection.cpp Core/SQLite/FunctionContext.cpp Core/SQLite/Statement.cpp Core/SQLite/Statement.h Core/SQLite/StatementReference.cpp Core/SQLite/Transaction.cpp Core/Toolbox.cpp NEWS OrthancServer/DicomProtocol/DicomServer.cpp OrthancServer/DicomProtocol/DicomUserConnection.cpp OrthancServer/FromDcmtkBridge.cpp OrthancServer/OrthancFindRequestHandler.cpp OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp OrthancServer/Scheduler/ServerJob.cpp OrthancServer/ServerContext.cpp Plugins/Include/orthanc/OrthancCPlugin.h Resources/ErrorCodes.json Resources/GenerateErrorCodes.py UnitTestsSources/MultiThreadingTests.cpp
diffstat 29 files changed, 782 insertions(+), 248 deletions(-) [+]
line wrap: on
line diff
--- a/Core/Compression/DeflateBaseCompressor.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/Compression/DeflateBaseCompressor.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -34,6 +34,7 @@
 #include "DeflateBaseCompressor.h"
 
 #include "../OrthancException.h"
+#include "../Logging.h"
 
 #include <string.h>
 
@@ -43,7 +44,8 @@
   {
     if (level >= 10)
     {
-      throw OrthancException("Zlib compression level must be between 0 (no compression) and 9 (highest compression");
+      LOG(ERROR) << "Zlib compression level must be between 0 (no compression) and 9 (highest compression)";
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
 
     compressionLevel_ = level;
@@ -60,7 +62,8 @@
 
     if (compressedSize < sizeof(uint64_t))
     {
-      throw OrthancException("The compressed buffer is ill-formed");
+      LOG(ERROR) << "The compressed buffer is ill-formed";
+      throw OrthancException(ErrorCode_CorruptedFile);
     }
 
     uint64_t size;
--- a/Core/Compression/ZipWriter.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/Compression/ZipWriter.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -44,6 +44,7 @@
 
 #include "../../Resources/ThirdParty/minizip/zip.h"
 #include "../OrthancException.h"
+#include "../Logging.h"
 
 
 static void PrepareFileInfo(zip_fileinfo& zfi)
@@ -122,7 +123,8 @@
 
     if (path_.size() == 0)
     {
-      throw OrthancException("Please call SetOutputPath() before creating the file");
+      LOG(ERROR) << "Please call SetOutputPath() before creating the file";
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
     }
 
     hasFileInZip_ = false;
@@ -165,7 +167,8 @@
   {
     if (level >= 10)
     {
-      throw OrthancException("ZIP compression level must be between 0 (no compression) and 9 (highest compression");
+      LOG(ERROR) << "ZIP compression level must be between 0 (no compression) and 9 (highest compression)";
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
 
     Close();
@@ -224,7 +227,8 @@
   {
     if (!hasFileInZip_)
     {
-      throw OrthancException("Call first OpenFile()");
+      LOG(ERROR) << "Call first OpenFile()";
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
     }
 
     const size_t maxBytesInAStep = std::numeric_limits<int32_t>::max();
--- a/Core/Compression/ZlibCompressor.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/Compression/ZlibCompressor.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -145,7 +145,7 @@
       switch (error)
       {
       case Z_DATA_ERROR:
-        throw OrthancException("Zlib: Corrupted or incomplete compressed buffer");
+        throw OrthancException(ErrorCode_CorruptedFile);
 
       case Z_MEM_ERROR:
         throw OrthancException(ErrorCode_NotEnoughMemory);
--- a/Core/Enumerations.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/Enumerations.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -113,7 +113,7 @@
         return "The file storage is full";
 
       case ErrorCode_CorruptedFile:
-        return "Corrupted file (inconsistent MD5 hash)";
+        return "Corrupted file (e.g. inconsistent MD5 hash)";
 
       case ErrorCode_InexistentTag:
         return "Inexistent tag";
@@ -133,6 +133,144 @@
       case ErrorCode_UnknownPluginService:
         return "Plugin invoking an unknown service";
 
+      case ErrorCode_UnknownDicomTag:
+        return "Unknown DICOM tag";
+
+      case ErrorCode_SQLiteNotOpened:
+        return "SQLite: The database is not opened";
+
+      case ErrorCode_SQLiteAlreadyOpened:
+        return "SQLite: Connection is already open";
+
+      case ErrorCode_SQLiteCannotOpen:
+        return "SQLite: Unable to open the database";
+
+      case ErrorCode_SQLiteStatementAlreadyUsed:
+        return "SQLite: This cached statement is already being referred to";
+
+      case ErrorCode_SQLiteExecute:
+        return "SQLite: Cannot execute a command";
+
+      case ErrorCode_SQLiteRollbackWithoutTransaction:
+        return "SQLite: Rolling back a nonexistent transaction (have you called Begin()?)";
+
+      case ErrorCode_SQLiteCommitWithoutTransaction:
+        return "SQLite: Committing a nonexistent transaction";
+
+      case ErrorCode_SQLiteRegisterFunction:
+        return "SQLite: Unable to register a function";
+
+      case ErrorCode_SQLiteFlush:
+        return "SQLite: Unable to flush the database";
+
+      case ErrorCode_SQLiteCannotRun:
+        return "SQLite: Cannot run a cached statement";
+
+      case ErrorCode_SQLiteCannotStep:
+        return "SQLite: Cannot step over a cached statement";
+
+      case ErrorCode_SQLiteBindOutOfRange:
+        return "SQLite: Bing a value while out of range (serious error)";
+
+      case ErrorCode_SQLitePrepareStatement:
+        return "SQLite: Cannot prepare a cached statement";
+
+      case ErrorCode_SQLiteTransactionAlreadyStarted:
+        return "SQLite: Beginning the same transaction twice";
+
+      case ErrorCode_SQLiteTransactionCommit:
+        return "SQLite: Failure when committing the transaction";
+
+      case ErrorCode_SQLiteTransactionBegin:
+        return "SQLite: Cannot start a transaction";
+
+      case ErrorCode_DirectoryOverFile:
+        return "The directory to be created is already occupied by a regular file";
+
+      case ErrorCode_FileStorageCannotWrite:
+        return "Unable to create a subdirectory or a file in the file storage";
+
+      case ErrorCode_DirectoryExpected:
+        return "The specified path does not point to a directory";
+
+      case ErrorCode_HttpPortInUse:
+        return "The TCP port of the HTTP server is already in use";
+
+      case ErrorCode_DicomPortInUse:
+        return "The TCP port of the DICOM server is already in use";
+
+      case ErrorCode_BadHttpStatusInRest:
+        return "This HTTP status is not allowed in a REST API";
+
+      case ErrorCode_RegularFileExpected:
+        return "The specified path does not point to a regular file";
+
+      case ErrorCode_PathToExecutable:
+        return "Unable to get the path to the executable";
+
+      case ErrorCode_MakeDirectory:
+        return "Cannot create a directory";
+
+      case ErrorCode_BadApplicationEntityTitle:
+        return "An application entity title (AET) cannot be empty or be longer than 16 characters";
+
+      case ErrorCode_NoCFindHandler:
+        return "No request handler factory for DICOM C-FIND SCP";
+
+      case ErrorCode_NoCMoveHandler:
+        return "No request handler factory for DICOM C-MOVE SCP";
+
+      case ErrorCode_NoCStoreHandler:
+        return "No request handler factory for DICOM C-STORE SCP";
+
+      case ErrorCode_NoApplicationEntityFilter:
+        return "No application entity filter";
+
+      case ErrorCode_NoSopClassOrInstance:
+        return "DicomUserConnection: Unable to find the SOP class and instance";
+
+      case ErrorCode_NoPresentationContext:
+        return "DicomUserConnection: No acceptable presentation context for modality";
+
+      case ErrorCode_DicomFindUnavailable:
+        return "DicomUserConnection: The C-FIND command is not supported by the remote SCP";
+
+      case ErrorCode_DicomMoveUnavailable:
+        return "DicomUserConnection: The C-MOVE command is not supported by the remote SCP";
+
+      case ErrorCode_CannotStoreInstance:
+        return "Cannot store an instance";
+
+      case ErrorCode_CreateDicomNotString:
+        return "Only string values are supported when creating DICOM instances";
+
+      case ErrorCode_CreateDicomOverrideTag:
+        return "Trying to override a value inherited from a parent module";
+
+      case ErrorCode_CreateDicomUseContent:
+        return "Use \"Content\" to inject an image into a new DICOM instance";
+
+      case ErrorCode_CreateDicomNoPayload:
+        return "No payload is present for one instance in the series";
+
+      case ErrorCode_CreateDicomUseDataUriScheme:
+        return "The payload of the DICOM instance must be specified according to Data URI scheme";
+
+      case ErrorCode_CreateDicomBadParent:
+        return "Trying to attach a new DICOM instance to an inexistent resource";
+
+      case ErrorCode_CreateDicomParentIsInstance:
+        return "Trying to attach a new DICOM instance to an instance (must be a series, study or patient)";
+
+      case ErrorCode_CreateDicomParentEncoding:
+        return "Unable to get the encoding of the parent resource";
+
+      case ErrorCode_UnknownModality:
+        return "Unknown modality";
+
+      case ErrorCode_BadJobOrdering:
+        return "Bad ordering of filters in a job";
+
       default:
         return "Unknown error code";
     }
--- a/Core/Enumerations.h	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/Enumerations.h	Tue Aug 25 17:39:38 2015 +0200
@@ -67,13 +67,59 @@
     ErrorCode_UnknownResource = 17    /*!< Unknown resource */,
     ErrorCode_IncompatibleDatabaseVersion = 18    /*!< Incompatible version of the database */,
     ErrorCode_FullStorage = 19    /*!< The file storage is full */,
-    ErrorCode_CorruptedFile = 20    /*!< Corrupted file (inconsistent MD5 hash) */,
+    ErrorCode_CorruptedFile = 20    /*!< Corrupted file (e.g. inconsistent MD5 hash) */,
     ErrorCode_InexistentTag = 21    /*!< Inexistent tag */,
     ErrorCode_ReadOnly = 22    /*!< Cannot modify a read-only data structure */,
     ErrorCode_IncompatibleImageFormat = 23    /*!< Incompatible format of the images */,
     ErrorCode_IncompatibleImageSize = 24    /*!< Incompatible size of the images */,
     ErrorCode_SharedLibrary = 25    /*!< Error while using a shared library (plugin) */,
-    ErrorCode_UnknownPluginService = 26    /*!< Plugin invoking an unknown service */
+    ErrorCode_UnknownPluginService = 26    /*!< Plugin invoking an unknown service */,
+    ErrorCode_UnknownDicomTag = 27    /*!< Unknown DICOM tag */,
+    ErrorCode_SQLiteNotOpened = 1000    /*!< SQLite: The database is not opened */,
+    ErrorCode_SQLiteAlreadyOpened = 1001    /*!< SQLite: Connection is already open */,
+    ErrorCode_SQLiteCannotOpen = 1002    /*!< SQLite: Unable to open the database */,
+    ErrorCode_SQLiteStatementAlreadyUsed = 1003    /*!< SQLite: This cached statement is already being referred to */,
+    ErrorCode_SQLiteExecute = 1004    /*!< SQLite: Cannot execute a command */,
+    ErrorCode_SQLiteRollbackWithoutTransaction = 1005    /*!< SQLite: Rolling back a nonexistent transaction (have you called Begin()?) */,
+    ErrorCode_SQLiteCommitWithoutTransaction = 1006    /*!< SQLite: Committing a nonexistent transaction */,
+    ErrorCode_SQLiteRegisterFunction = 1007    /*!< SQLite: Unable to register a function */,
+    ErrorCode_SQLiteFlush = 1008    /*!< SQLite: Unable to flush the database */,
+    ErrorCode_SQLiteCannotRun = 1009    /*!< SQLite: Cannot run a cached statement */,
+    ErrorCode_SQLiteCannotStep = 1010    /*!< SQLite: Cannot step over a cached statement */,
+    ErrorCode_SQLiteBindOutOfRange = 1011    /*!< SQLite: Bing a value while out of range (serious error) */,
+    ErrorCode_SQLitePrepareStatement = 1012    /*!< SQLite: Cannot prepare a cached statement */,
+    ErrorCode_SQLiteTransactionAlreadyStarted = 1013    /*!< SQLite: Beginning the same transaction twice */,
+    ErrorCode_SQLiteTransactionCommit = 1014    /*!< SQLite: Failure when committing the transaction */,
+    ErrorCode_SQLiteTransactionBegin = 1015    /*!< SQLite: Cannot start a transaction */,
+    ErrorCode_DirectoryOverFile = 2000    /*!< The directory to be created is already occupied by a regular file */,
+    ErrorCode_FileStorageCannotWrite = 2001    /*!< Unable to create a subdirectory or a file in the file storage */,
+    ErrorCode_DirectoryExpected = 2002    /*!< The specified path does not point to a directory */,
+    ErrorCode_HttpPortInUse = 2003    /*!< The TCP port of the HTTP server is already in use */,
+    ErrorCode_DicomPortInUse = 2004    /*!< The TCP port of the DICOM server is already in use */,
+    ErrorCode_BadHttpStatusInRest = 2005    /*!< This HTTP status is not allowed in a REST API */,
+    ErrorCode_RegularFileExpected = 2006    /*!< The specified path does not point to a regular file */,
+    ErrorCode_PathToExecutable = 2007    /*!< Unable to get the path to the executable */,
+    ErrorCode_MakeDirectory = 2008    /*!< Cannot create a directory */,
+    ErrorCode_BadApplicationEntityTitle = 2009    /*!< An application entity title (AET) cannot be empty or be longer than 16 characters */,
+    ErrorCode_NoCFindHandler = 2010    /*!< No request handler factory for DICOM C-FIND SCP */,
+    ErrorCode_NoCMoveHandler = 2011    /*!< No request handler factory for DICOM C-MOVE SCP */,
+    ErrorCode_NoCStoreHandler = 2012    /*!< No request handler factory for DICOM C-STORE SCP */,
+    ErrorCode_NoApplicationEntityFilter = 2013    /*!< No application entity filter */,
+    ErrorCode_NoSopClassOrInstance = 2014    /*!< DicomUserConnection: Unable to find the SOP class and instance */,
+    ErrorCode_NoPresentationContext = 2015    /*!< DicomUserConnection: No acceptable presentation context for modality */,
+    ErrorCode_DicomFindUnavailable = 2016    /*!< DicomUserConnection: The C-FIND command is not supported by the remote SCP */,
+    ErrorCode_DicomMoveUnavailable = 2017    /*!< DicomUserConnection: The C-MOVE command is not supported by the remote SCP */,
+    ErrorCode_CannotStoreInstance = 2018    /*!< Cannot store an instance */,
+    ErrorCode_CreateDicomNotString = 2019    /*!< Only string values are supported when creating DICOM instances */,
+    ErrorCode_CreateDicomOverrideTag = 2020    /*!< Trying to override a value inherited from a parent module */,
+    ErrorCode_CreateDicomUseContent = 2021    /*!< Use \"Content\" to inject an image into a new DICOM instance */,
+    ErrorCode_CreateDicomNoPayload = 2022    /*!< No payload is present for one instance in the series */,
+    ErrorCode_CreateDicomUseDataUriScheme = 2023    /*!< The payload of the DICOM instance must be specified according to Data URI scheme */,
+    ErrorCode_CreateDicomBadParent = 2024    /*!< Trying to attach a new DICOM instance to an inexistent resource */,
+    ErrorCode_CreateDicomParentIsInstance = 2025    /*!< Trying to attach a new DICOM instance to an instance (must be a series, study or patient) */,
+    ErrorCode_CreateDicomParentEncoding = 2026    /*!< Unable to get the encoding of the parent resource */,
+    ErrorCode_UnknownModality = 2027    /*!< Unknown modality */,
+    ErrorCode_BadJobOrdering = 2028    /*!< Bad ordering of filters in a job */
   };
 
   enum LogLevel
--- a/Core/FileStorage/FilesystemStorage.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/FileStorage/FilesystemStorage.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -106,14 +106,14 @@
     {
       if (!boost::filesystem::is_directory(path.parent_path()))
       {
-        throw OrthancException("The subdirectory to be created is already occupied by a regular file");        
+        throw OrthancException(ErrorCode_DirectoryOverFile);
       }
     }
     else
     {
       if (!boost::filesystem::create_directories(path.parent_path()))
       {
-        throw OrthancException("Unable to create a subdirectory in the file storage");        
+        throw OrthancException(ErrorCode_FileStorageCannotWrite);
       }
     }
 
@@ -121,7 +121,7 @@
     f.open(path, std::ofstream::out | std::ios::binary);
     if (!f.good())
     {
-      throw OrthancException("Unable to create a new file in the file storage");
+      throw OrthancException(ErrorCode_FileStorageCannotWrite);
     }
 
     if (size != 0)
@@ -130,7 +130,7 @@
       if (!f.good())
       {
         f.close();
-        throw OrthancException("Unable to write to the new file in the file storage");
+        throw OrthancException(ErrorCode_FileStorageCannotWrite);
       }
     }
 
--- a/Core/HttpServer/FilesystemHttpHandler.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/HttpServer/FilesystemHttpHandler.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -119,7 +119,7 @@
     if (!fs::exists(pimpl_->root_) || 
         !fs::is_directory(pimpl_->root_))
     {
-      throw OrthancException("The path does not point to a directory");
+      throw OrthancException(ErrorCode_DirectoryExpected);
     }
   }
 
--- a/Core/HttpServer/MongooseServer.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/HttpServer/MongooseServer.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -896,7 +896,7 @@
 
       if (!pimpl_->context_)
       {
-        throw OrthancException("Unable to launch the Mongoose server");
+        throw OrthancException(ErrorCode_HttpPortInUse);
       }
     }
   }
--- a/Core/OrthancException.h	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/OrthancException.h	Tue Aug 25 17:39:38 2015 +0200
@@ -44,7 +44,6 @@
     HttpStatus httpStatus_;
     std::string custom_;
 
-  public:
     OrthancException(const std::string& custom) : 
       errorCode_(ErrorCode_Custom),
       httpStatus_(HttpStatus_500_InternalServerError),
@@ -52,6 +51,7 @@
     {
     }
 
+  public:
     OrthancException(ErrorCode errorCode) : 
       errorCode_(errorCode),
       httpStatus_(ConvertErrorCodeToHttpStatus(errorCode))
--- a/Core/RestApi/RestApiOutput.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/RestApi/RestApiOutput.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -144,7 +144,7 @@
         status != HttpStatus_500_InternalServerError &&
         status != HttpStatus_415_UnsupportedMediaType)
     {
-      throw OrthancException("This HTTP status is not allowed in a REST API");
+      throw OrthancException(ErrorCode_BadHttpStatusInRest);
     }
 
     CheckStatus();
--- a/Core/SQLite/Connection.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/SQLite/Connection.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -75,7 +75,7 @@
     {
       if (!db_)
       {
-        throw OrthancSQLiteException("SQLite: The database is not opened");
+        throw OrthancSQLiteException(ErrorCode_SQLiteNotOpened);
       }
     }
 
@@ -83,7 +83,7 @@
     {
       if (db_) 
       {
-        throw OrthancSQLiteException("SQLite: Connection is already open");
+        throw OrthancSQLiteException(ErrorCode_SQLiteAlreadyOpened);
       }
 
       int err = sqlite3_open(path.c_str(), &db_);
@@ -91,7 +91,7 @@
       {
         Close();
         db_ = NULL;
-        throw OrthancSQLiteException("SQLite: Unable to open the database");
+        throw OrthancSQLiteException(ErrorCode_SQLiteCannotOpen);
       }
 
       // Execute PRAGMAs at this point
@@ -137,7 +137,7 @@
       {
         if (i->second->GetReferenceCount() >= 1)
         {
-          throw OrthancSQLiteException("SQLite: This cached statement is already being referred to");
+          throw OrthancSQLiteException(ErrorCode_SQLiteStatementAlreadyUsed);
         }
 
         return *i->second;
@@ -162,7 +162,8 @@
       int error = sqlite3_exec(db_, sql, NULL, NULL, NULL);
       if (error == SQLITE_ERROR)
       {
-        throw OrthancSQLiteException("SQLite Execute error: " + std::string(sqlite3_errmsg(db_)));
+        LOG(ERROR) << "SQLite execute error: " << sqlite3_errmsg(db_);
+        throw OrthancSQLiteException(ErrorCode_SQLiteExecute);
       }
       else
       {
@@ -283,7 +284,7 @@
     {
       if (!transactionNesting_)
       {
-        throw OrthancSQLiteException("Rolling back a nonexistent transaction");
+        throw OrthancSQLiteException(ErrorCode_SQLiteRollbackWithoutTransaction);
       }
 
       transactionNesting_--;
@@ -302,7 +303,7 @@
     {
       if (!transactionNesting_) 
       {
-        throw OrthancSQLiteException("Committing a nonexistent transaction");
+        throw OrthancSQLiteException(ErrorCode_SQLiteCommitWithoutTransaction);
       }
       transactionNesting_--;
 
@@ -370,7 +371,7 @@
       if (err != SQLITE_OK)
       {
         delete func;
-        throw OrthancSQLiteException("SQLite: Unable to register a function");
+        throw OrthancSQLiteException(ErrorCode_SQLiteRegisterFunction);
       }
 
       return func;
@@ -387,7 +388,7 @@
 
       if (err != SQLITE_OK)
       {
-        throw OrthancSQLiteException("SQLite: Unable to flush the database");
+        throw OrthancSQLiteException(ErrorCode_SQLiteFlush);
       }
     }
   }
--- a/Core/SQLite/FunctionContext.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/SQLite/FunctionContext.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -64,7 +64,7 @@
     {
       if (index >= argc_)
       {
-        throw OrthancSQLiteException("Parameter out of range");
+        throw OrthancSQLiteException(ErrorCode_ParameterOutOfRange);
       }
     }
 
--- a/Core/SQLite/Statement.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/SQLite/Statement.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -60,31 +60,39 @@
 {
   namespace SQLite
   {
-    int Statement::CheckError(int err) const
+    int Statement::CheckError(int err, ErrorCode code) const
     {
       bool succeeded = (err == SQLITE_OK || err == SQLITE_ROW || err == SQLITE_DONE);
       if (!succeeded)
       {
+#if ORTHANC_SQLITE_STANDALONE != 1
         char buffer[128];
         snprintf(buffer, sizeof(buffer) - 1, "SQLite error code %d", err);
-        throw OrthancSQLiteException(buffer);
+        LOG(ERROR) << buffer;
+#endif
+
+        throw OrthancSQLiteException(code);
       }
 
       return err;
     }
 
-    void Statement::CheckOk(int err) const 
+    void Statement::CheckOk(int err, ErrorCode code) const 
     {
       if (err == SQLITE_RANGE)
       {
         // Binding to a non-existent variable is evidence of a serious error.
-        throw OrthancSQLiteException("Bind value out of range");
+        throw OrthancSQLiteException(ErrorCode_SQLiteBindOutOfRange);
       }
       else if (err != SQLITE_OK)
       {
+#if ORTHANC_SQLITE_STANDALONE != 1
         char buffer[128];
         snprintf(buffer, sizeof(buffer) - 1, "SQLite error code %d", err);
-        throw OrthancSQLiteException(buffer);
+        LOG(ERROR) << buffer;
+#endif
+
+        throw OrthancSQLiteException(code);
       }
     }
 
@@ -127,7 +135,7 @@
       VLOG(1) << "SQLite::Statement::Run " << sqlite3_sql(GetStatement());
 #endif
 
-      return CheckError(sqlite3_step(GetStatement())) == SQLITE_DONE;
+      return CheckError(sqlite3_step(GetStatement()), ErrorCode_SQLiteCannotRun) == SQLITE_DONE;
     }
 
     bool Statement::Step()
@@ -136,7 +144,7 @@
       VLOG(1) << "SQLite::Statement::Step " << sqlite3_sql(GetStatement());
 #endif
 
-      return CheckError(sqlite3_step(GetStatement())) == SQLITE_ROW;
+      return CheckError(sqlite3_step(GetStatement()), ErrorCode_SQLiteCannotStep) == SQLITE_ROW;
     }
 
     void Statement::Reset(bool clear_bound_vars) 
@@ -158,7 +166,8 @@
 
     void Statement::BindNull(int col)
     {
-      CheckOk(sqlite3_bind_null(GetStatement(), col + 1));
+      CheckOk(sqlite3_bind_null(GetStatement(), col + 1),
+              ErrorCode_BadParameterType);
     }
 
     void Statement::BindBool(int col, bool val) 
@@ -168,22 +177,26 @@
 
     void Statement::BindInt(int col, int val) 
     {
-      CheckOk(sqlite3_bind_int(GetStatement(), col + 1, val));
+      CheckOk(sqlite3_bind_int(GetStatement(), col + 1, val),
+              ErrorCode_BadParameterType);
     }
 
     void Statement::BindInt64(int col, int64_t val) 
     {
-      CheckOk(sqlite3_bind_int64(GetStatement(), col + 1, val));
+      CheckOk(sqlite3_bind_int64(GetStatement(), col + 1, val),
+              ErrorCode_BadParameterType);
     }
 
     void Statement::BindDouble(int col, double val) 
     {
-      CheckOk(sqlite3_bind_double(GetStatement(), col + 1, val));
+      CheckOk(sqlite3_bind_double(GetStatement(), col + 1, val),
+              ErrorCode_BadParameterType);
     }
 
     void Statement::BindCString(int col, const char* val) 
     {
-      CheckOk(sqlite3_bind_text(GetStatement(), col + 1, val, -1, SQLITE_TRANSIENT));
+      CheckOk(sqlite3_bind_text(GetStatement(), col + 1, val, -1, SQLITE_TRANSIENT),
+              ErrorCode_BadParameterType);
     }
 
     void Statement::BindString(int col, const std::string& val) 
@@ -192,7 +205,8 @@
                                 col + 1,
                                 val.data(),
                                 val.size(),
-                                SQLITE_TRANSIENT));
+                                SQLITE_TRANSIENT),
+              ErrorCode_BadParameterType);
     }
 
     /*void Statement::BindString16(int col, const string16& value) 
@@ -202,7 +216,8 @@
 
     void Statement::BindBlob(int col, const void* val, int val_len) 
     {
-      CheckOk(sqlite3_bind_blob(GetStatement(), col + 1, val, val_len, SQLITE_TRANSIENT));
+      CheckOk(sqlite3_bind_blob(GetStatement(), col + 1, val, val_len, SQLITE_TRANSIENT),
+              ErrorCode_BadParameterType);
     }
 
 
--- a/Core/SQLite/Statement.h	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/SQLite/Statement.h	Tue Aug 25 17:39:38 2015 +0200
@@ -81,9 +81,11 @@
     private:
       StatementReference  reference_;
 
-      int CheckError(int err) const;
+      int CheckError(int err, 
+                     ErrorCode code) const;
 
-      void CheckOk(int err) const;
+      void CheckOk(int err, 
+                   ErrorCode code) const;
 
       struct sqlite3_stmt* GetStatement() const
       {
--- a/Core/SQLite/StatementReference.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/SQLite/StatementReference.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -72,7 +72,7 @@
     {
       if (database == NULL || sql == NULL)
       {
-        throw OrthancSQLiteException("Parameter out of range");
+        throw OrthancSQLiteException(ErrorCode_ParameterOutOfRange);
       }
 
       root_ = NULL;
@@ -81,7 +81,11 @@
       int error = sqlite3_prepare_v2(database, sql, -1, &statement_, NULL);
       if (error != SQLITE_OK)
       {
-        throw OrthancSQLiteException("SQLite: " + std::string(sqlite3_errmsg(database)));
+#if ORTHANC_SQLITE_STANDALONE != 1
+        LOG(ERROR) << "SQLite: " << sqlite3_errmsg(database);
+#endif
+
+        throw OrthancSQLiteException(ErrorCode_SQLitePrepareStatement);
       }
 
       assert(IsRoot());
--- a/Core/SQLite/Transaction.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/SQLite/Transaction.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -64,13 +64,13 @@
     {
       if (isOpen_) 
       {
-        throw OrthancSQLiteException("SQLite: Beginning a transaction twice!");
+        throw OrthancSQLiteException(ErrorCode_SQLiteTransactionAlreadyStarted);
       }
 
       isOpen_ = connection_.BeginTransaction();
       if (!isOpen_)
       {
-        throw OrthancSQLiteException("SQLite: Unable to create a transaction");
+        throw OrthancSQLiteException(ErrorCode_SQLiteTransactionBegin);
       }
     }
 
@@ -78,8 +78,7 @@
     {
       if (!isOpen_) 
       {
-        throw OrthancSQLiteException("SQLite: Attempting to roll back a nonexistent transaction. "
-                                     "Did you remember to call Begin()?");
+        throw OrthancSQLiteException(ErrorCode_SQLiteRollbackWithoutTransaction);
       }
 
       isOpen_ = false;
@@ -91,15 +90,14 @@
     {
       if (!isOpen_) 
       {
-        throw OrthancSQLiteException("SQLite: Attempting to roll back a nonexistent transaction. "
-                                     "Did you remember to call Begin()?");
+        throw OrthancSQLiteException(ErrorCode_SQLiteRollbackWithoutTransaction);
       }
 
       isOpen_ = false;
 
       if (!connection_.CommitTransaction())
       {
-        throw OrthancSQLiteException("SQLite: Failure when committing the transaction");
+        throw OrthancSQLiteException(ErrorCode_SQLiteTransactionCommit);
       }
     }
   }
--- a/Core/Toolbox.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/Core/Toolbox.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -255,9 +255,13 @@
     if (boost::filesystem::exists(path))
     {
       if (boost::filesystem::is_regular_file(path))
+      {
         boost::filesystem::remove(path);
+      }
       else
-        throw OrthancException("The path is not a regular file: " + path);
+      {
+        throw OrthancException(ErrorCode_RegularFileExpected);
+      }
     }
   }
 
@@ -530,7 +534,7 @@
     ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1);
     if (bytes == 0)
     {
-      throw OrthancException("Unable to get the path to the executable");
+      throw OrthancException(ErrorCode_PathToExecutable);
     }
 
     return std::string(&buffer[0]);
@@ -1019,14 +1023,14 @@
     {
       if (!boost::filesystem::is_directory(path))
       {
-        throw OrthancException("Cannot create the directory over an existing file: " + path);
+        throw OrthancException(ErrorCode_DirectoryOverFile);
       }
     }
     else
     {
       if (!boost::filesystem::create_directories(path))
       {
-        throw OrthancException("Unable to create the directory: " + path);
+        throw OrthancException(ErrorCode_MakeDirectory);
       }
     }
   }
--- a/NEWS	Tue Aug 25 16:18:37 2015 +0200
+++ b/NEWS	Tue Aug 25 17:39:38 2015 +0200
@@ -24,6 +24,7 @@
 Maintenance
 -----------
 
+* Improved error codes
 * Many code refactorings
 * If error while calling the REST API, the answer body contains an error description
 * Upgrade to curl 7.44.0 for static and Windows builds
--- a/OrthancServer/DicomProtocol/DicomServer.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/OrthancServer/DicomProtocol/DicomServer.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -162,7 +162,7 @@
     if (cond.bad())
     {
       LOG(ERROR) << "cannot create network: " << cond.text();
-      throw OrthancException("Cannot create network");
+      throw OrthancException(ErrorCode_DicomPortInUse);
     }
 
     LOG(INFO) << "DICOM server started";
@@ -279,12 +279,12 @@
   {
     if (aet.size() == 0)
     {
-      throw OrthancException("Too short AET");
+      throw OrthancException(ErrorCode_BadApplicationEntityTitle);
     }
 
     if (aet.size() > 16)
     {
-      throw OrthancException("AET must be shorter than 16 characters");
+      throw OrthancException(ErrorCode_BadApplicationEntityTitle);
     }
 
     for (size_t i = 0; i < aet.size(); i++)
@@ -327,7 +327,7 @@
     }
     else
     {
-      throw OrthancException("No C-FIND request handler factory");
+      throw OrthancException(ErrorCode_NoCFindHandler);
     }
   }
 
@@ -350,7 +350,7 @@
     }
     else
     {
-      throw OrthancException("No C-MOVE request handler factory");
+      throw OrthancException(ErrorCode_NoCMoveHandler);
     }
   }
 
@@ -373,7 +373,7 @@
     }
     else
     {
-      throw OrthancException("No C-STORE request handler factory");
+      throw OrthancException(ErrorCode_NoCStoreHandler);
     }
   }
 
@@ -396,7 +396,7 @@
     }
     else
     {
-      throw OrthancException("No application entity filter");
+      throw OrthancException(ErrorCode_NoApplicationEntityFilter);
     }
   }
 
--- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/OrthancServer/DicomProtocol/DicomUserConnection.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -299,7 +299,7 @@
     DIC_UI sopInstance;
     if (!DU_findSOPClassAndInstanceInDataSet(dcmff.getDataset(), sopClass, sopInstance))
     {
-      throw OrthancException("DicomUserConnection: Unable to find the SOP class and instance");
+      throw OrthancException(ErrorCode_NoSopClassOrInstance);
     }
 
     // Figure out which of the accepted presentation contexts should be used
@@ -309,8 +309,7 @@
       const char *modalityName = dcmSOPClassUIDToModality(sopClass);
       if (!modalityName) modalityName = dcmFindNameOfUID(sopClass);
       if (!modalityName) modalityName = "unknown SOP class";
-      throw OrthancException("DicomUserConnection: No presentation context for modality " + 
-                             std::string(modalityName));
+      throw OrthancException(ErrorCode_NoPresentationContext);
     }
 
     // Prepare the transmission of data
@@ -552,7 +551,7 @@
     int presID = ASC_findAcceptedPresentationContextID(pimpl_->assoc_, sopClass);
     if (presID == 0)
     {
-      throw OrthancException("DicomUserConnection: The C-FIND command is not supported by the remote AET");
+      throw OrthancException(ErrorCode_DicomFindUnavailable);
     }
 
     T_DIMSE_C_FindRQ request;
@@ -625,7 +624,7 @@
     int presID = ASC_findAcceptedPresentationContextID(pimpl_->assoc_, sopClass);
     if (presID == 0)
     {
-      throw OrthancException("DicomUserConnection: The C-MOVE command is not supported by the remote AET");
+      throw OrthancException(ErrorCode_DicomMoveUnavailable);
     }
 
     T_DIMSE_C_MoveRQ request;
@@ -776,7 +775,7 @@
     {
       if (host.size() > HOST_NAME_MAX - 10)
       {
-        throw OrthancException("Remote host name is too long");
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
       }
 
       Close();
@@ -837,7 +836,7 @@
 
     if (ASC_countAcceptedPresentationContexts(pimpl_->params_) == 0)
     {
-      throw OrthancException("DicomUserConnection: No Acceptable Presentation Contexts");
+      throw OrthancException(ErrorCode_NoPresentationContext);
     }
   }
 
--- a/OrthancServer/FromDcmtkBridge.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/OrthancServer/FromDcmtkBridge.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -215,7 +215,8 @@
   {
     if (!element.isLeaf())
     {
-      throw OrthancException("Only applicable to leaf elements");
+      // This function is only applicable to leaf elements
+      throw OrthancException(ErrorCode_BadParameterType);
     }
 
     if (element.isaString())
@@ -594,7 +595,7 @@
     if (entry == NULL)
     {
       dcmDataDict.unlock();
-      throw OrthancException("Unknown DICOM tag");
+      throw OrthancException(ErrorCode_UnknownDicomTag);
     }
     else
     {
@@ -611,7 +612,7 @@
     }
     else
     {
-      throw OrthancException("Unknown DICOM tag");
+      throw OrthancException(ErrorCode_UnknownDicomTag);
     }
 #endif
   }
--- a/OrthancServer/OrthancFindRequestHandler.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/OrthancServer/OrthancFindRequestHandler.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -227,7 +227,7 @@
 
     if (!Configuration::LookupDicomModalityUsingAETitle(modality, remoteAet))
     {
-      throw OrthancException("Unknown modality");
+      throw OrthancException(ErrorCode_UnknownModality);
     }
 
     // ModalityManufacturer manufacturer = modality.GetManufacturer();
--- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -315,7 +315,8 @@
       std::string modifiedInstance;
       if (context.Store(modifiedInstance, toStore) != StoreStatus_Success)
       {
-        throw OrthancException("Error while storing a modified instance " + *it);
+        LOG(ERROR) << "Error while storing a modified instance " << *it;
+        throw OrthancException(ErrorCode_CannotStoreInstance);
       }
 
       // Sanity checks in debug mode
@@ -444,7 +445,7 @@
 
     if (status == StoreStatus_Failure)
     {
-      throw OrthancException("Error while storing a manually-created instance");
+      throw OrthancException(ErrorCode_CannotStoreInstance);
     }
   }
 
@@ -465,7 +466,7 @@
       const std::string& name = members[i];
       if (request[name].type() != Json::stringValue)
       {
-        throw OrthancException("Only string values are supported when creating DICOM instances");
+        throw OrthancException(ErrorCode_CreateDicomNotString);
       }
 
       std::string value = request[name].asString();
@@ -488,7 +489,7 @@
   {
     if (tags.type() != Json::objectValue)
     {
-      throw OrthancException("Bad syntax to specify the tags");
+      throw OrthancException(ErrorCode_BadRequest);
     }
 
     // Inject the user-specified tags
@@ -498,7 +499,7 @@
       const std::string& name = members[i];
       if (tags[name].type() != Json::stringValue)
       {
-        throw OrthancException("Only string values are supported when creating DICOM instances");
+        throw OrthancException(ErrorCode_CreateDicomNotString);
       }
 
       std::string value = tags[name].asString();
@@ -509,12 +510,12 @@
         if (tag != DICOM_TAG_PATIENT_ID &&
             dicom.HasTag(tag))
         {
-          throw OrthancException("Trying to override a value inherited from a parent module");
+          throw OrthancException(ErrorCode_CreateDicomOverrideTag);
         }
 
         if (tag == DICOM_TAG_PIXEL_DATA)
         {
-          throw OrthancException("Use \"Content\" to inject an image into a new DICOM instance");
+          throw OrthancException(ErrorCode_CreateDicomUseContent);
         }
         else
         {
@@ -553,7 +554,7 @@
         {
           if (!content[i].isMember("Content"))
           {
-            throw OrthancException("No payload is present for one instance in the series");
+            throw OrthancException(ErrorCode_CreateDicomNoPayload);
           }
 
           payload = &content[i]["Content"];
@@ -567,7 +568,7 @@
         if (payload == NULL ||
             payload->type() != Json::stringValue)
         {
-          throw OrthancException("The payload of the DICOM instance must be specified according to Data URI scheme");
+          throw OrthancException(ErrorCode_CreateDicomUseDataUriScheme);
         }
 
         dicom->EmbedContent(payload->asString());
@@ -621,7 +622,8 @@
         const char* tmp = request["Tags"]["SpecificCharacterSet"].asCString();
         if (!GetDicomEncoding(encoding, tmp))
         {
-          throw OrthancException("Unknown specific character set: " + std::string(tmp));
+          LOG(ERROR) << "Unknown specific character set: " << std::string(tmp);
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
         }
       }
       else
@@ -641,12 +643,12 @@
       std::string parent = request["Parent"].asString();
       if (!context.GetIndex().LookupResourceType(parentType, parent))
       {
-        throw OrthancException("Trying to attach a new DICOM instance to an inexistent resource: " + parent);
+        throw OrthancException(ErrorCode_CreateDicomBadParent);
       }
 
       if (parentType == ResourceType_Instance)
       {
-        throw OrthancException("Trying to attach a new DICOM instance to an instance (must be a series, study or patient): " + parent);
+        throw OrthancException(ErrorCode_CreateDicomParentIsInstance);
       }
 
       // Select one existing child instance of the parent resource, to
@@ -679,7 +681,7 @@
               siblingTags[SPECIFIC_CHARACTER_SET]["Value"].type() != Json::stringValue ||
               !GetDicomEncoding(encoding, siblingTags[SPECIFIC_CHARACTER_SET]["Value"].asCString()))
           {
-            throw OrthancException("Unable to get the encoding of the parent resource");
+            throw OrthancException(ErrorCode_CreateDicomParentEncoding);
           }
 
           dicom.SetEncoding(encoding);
@@ -783,7 +785,7 @@
       }
       else
       {
-        throw OrthancException("The payload of the DICOM instance must be specified according to Data URI scheme");
+        throw OrthancException(ErrorCode_CreateDicomUseDataUriScheme);
         return;
       }
     }
--- a/OrthancServer/Scheduler/ServerJob.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/OrthancServer/Scheduler/ServerJob.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -61,7 +61,7 @@
             index[*next] <= index[*it])
         {
           // You must reorder your calls to "ServerJob::AddCommand"
-          throw OrthancException("Bad ordering of filters in a job");
+          throw OrthancException(ErrorCode_BadJobOrdering);
         }
       }
     }
--- a/OrthancServer/ServerContext.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/OrthancServer/ServerContext.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -330,7 +330,7 @@
     Json::Reader reader;
     if (!reader.parse(s, result))
     {
-      throw OrthancException("Corrupted JSON file");
+      throw OrthancException(ErrorCode_CorruptedFile);
     }
   }
 
--- a/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Aug 25 16:18:37 2015 +0200
+++ b/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Aug 25 17:39:38 2015 +0200
@@ -182,13 +182,59 @@
     OrthancPluginErrorCode_UnknownResource = 17    /*!< Unknown resource */,
     OrthancPluginErrorCode_IncompatibleDatabaseVersion = 18    /*!< Incompatible version of the database */,
     OrthancPluginErrorCode_FullStorage = 19    /*!< The file storage is full */,
-    OrthancPluginErrorCode_CorruptedFile = 20    /*!< Corrupted file (inconsistent MD5 hash) */,
+    OrthancPluginErrorCode_CorruptedFile = 20    /*!< Corrupted file (e.g. inconsistent MD5 hash) */,
     OrthancPluginErrorCode_InexistentTag = 21    /*!< Inexistent tag */,
     OrthancPluginErrorCode_ReadOnly = 22    /*!< Cannot modify a read-only data structure */,
     OrthancPluginErrorCode_IncompatibleImageFormat = 23    /*!< Incompatible format of the images */,
     OrthancPluginErrorCode_IncompatibleImageSize = 24    /*!< Incompatible size of the images */,
     OrthancPluginErrorCode_SharedLibrary = 25    /*!< Error while using a shared library (plugin) */,
     OrthancPluginErrorCode_UnknownPluginService = 26    /*!< Plugin invoking an unknown service */,
+    OrthancPluginErrorCode_UnknownDicomTag = 27    /*!< Unknown DICOM tag */,
+    OrthancPluginErrorCode_SQLiteNotOpened = 1000    /*!< SQLite: The database is not opened */,
+    OrthancPluginErrorCode_SQLiteAlreadyOpened = 1001    /*!< SQLite: Connection is already open */,
+    OrthancPluginErrorCode_SQLiteCannotOpen = 1002    /*!< SQLite: Unable to open the database */,
+    OrthancPluginErrorCode_SQLiteStatementAlreadyUsed = 1003    /*!< SQLite: This cached statement is already being referred to */,
+    OrthancPluginErrorCode_SQLiteExecute = 1004    /*!< SQLite: Cannot execute a command */,
+    OrthancPluginErrorCode_SQLiteRollbackWithoutTransaction = 1005    /*!< SQLite: Rolling back a nonexistent transaction (have you called Begin()?) */,
+    OrthancPluginErrorCode_SQLiteCommitWithoutTransaction = 1006    /*!< SQLite: Committing a nonexistent transaction */,
+    OrthancPluginErrorCode_SQLiteRegisterFunction = 1007    /*!< SQLite: Unable to register a function */,
+    OrthancPluginErrorCode_SQLiteFlush = 1008    /*!< SQLite: Unable to flush the database */,
+    OrthancPluginErrorCode_SQLiteCannotRun = 1009    /*!< SQLite: Cannot run a cached statement */,
+    OrthancPluginErrorCode_SQLiteCannotStep = 1010    /*!< SQLite: Cannot step over a cached statement */,
+    OrthancPluginErrorCode_SQLiteBindOutOfRange = 1011    /*!< SQLite: Bing a value while out of range (serious error) */,
+    OrthancPluginErrorCode_SQLitePrepareStatement = 1012    /*!< SQLite: Cannot prepare a cached statement */,
+    OrthancPluginErrorCode_SQLiteTransactionAlreadyStarted = 1013    /*!< SQLite: Beginning the same transaction twice */,
+    OrthancPluginErrorCode_SQLiteTransactionCommit = 1014    /*!< SQLite: Failure when committing the transaction */,
+    OrthancPluginErrorCode_SQLiteTransactionBegin = 1015    /*!< SQLite: Cannot start a transaction */,
+    OrthancPluginErrorCode_DirectoryOverFile = 2000    /*!< The directory to be created is already occupied by a regular file */,
+    OrthancPluginErrorCode_FileStorageCannotWrite = 2001    /*!< Unable to create a subdirectory or a file in the file storage */,
+    OrthancPluginErrorCode_DirectoryExpected = 2002    /*!< The specified path does not point to a directory */,
+    OrthancPluginErrorCode_HttpPortInUse = 2003    /*!< The TCP port of the HTTP server is already in use */,
+    OrthancPluginErrorCode_DicomPortInUse = 2004    /*!< The TCP port of the DICOM server is already in use */,
+    OrthancPluginErrorCode_BadHttpStatusInRest = 2005    /*!< This HTTP status is not allowed in a REST API */,
+    OrthancPluginErrorCode_RegularFileExpected = 2006    /*!< The specified path does not point to a regular file */,
+    OrthancPluginErrorCode_PathToExecutable = 2007    /*!< Unable to get the path to the executable */,
+    OrthancPluginErrorCode_MakeDirectory = 2008    /*!< Cannot create a directory */,
+    OrthancPluginErrorCode_BadApplicationEntityTitle = 2009    /*!< An application entity title (AET) cannot be empty or be longer than 16 characters */,
+    OrthancPluginErrorCode_NoCFindHandler = 2010    /*!< No request handler factory for DICOM C-FIND SCP */,
+    OrthancPluginErrorCode_NoCMoveHandler = 2011    /*!< No request handler factory for DICOM C-MOVE SCP */,
+    OrthancPluginErrorCode_NoCStoreHandler = 2012    /*!< No request handler factory for DICOM C-STORE SCP */,
+    OrthancPluginErrorCode_NoApplicationEntityFilter = 2013    /*!< No application entity filter */,
+    OrthancPluginErrorCode_NoSopClassOrInstance = 2014    /*!< DicomUserConnection: Unable to find the SOP class and instance */,
+    OrthancPluginErrorCode_NoPresentationContext = 2015    /*!< DicomUserConnection: No acceptable presentation context for modality */,
+    OrthancPluginErrorCode_DicomFindUnavailable = 2016    /*!< DicomUserConnection: The C-FIND command is not supported by the remote SCP */,
+    OrthancPluginErrorCode_DicomMoveUnavailable = 2017    /*!< DicomUserConnection: The C-MOVE command is not supported by the remote SCP */,
+    OrthancPluginErrorCode_CannotStoreInstance = 2018    /*!< Cannot store an instance */,
+    OrthancPluginErrorCode_CreateDicomNotString = 2019    /*!< Only string values are supported when creating DICOM instances */,
+    OrthancPluginErrorCode_CreateDicomOverrideTag = 2020    /*!< Trying to override a value inherited from a parent module */,
+    OrthancPluginErrorCode_CreateDicomUseContent = 2021    /*!< Use \"Content\" to inject an image into a new DICOM instance */,
+    OrthancPluginErrorCode_CreateDicomNoPayload = 2022    /*!< No payload is present for one instance in the series */,
+    OrthancPluginErrorCode_CreateDicomUseDataUriScheme = 2023    /*!< The payload of the DICOM instance must be specified according to Data URI scheme */,
+    OrthancPluginErrorCode_CreateDicomBadParent = 2024    /*!< Trying to attach a new DICOM instance to an inexistent resource */,
+    OrthancPluginErrorCode_CreateDicomParentIsInstance = 2025    /*!< Trying to attach a new DICOM instance to an instance (must be a series, study or patient) */,
+    OrthancPluginErrorCode_CreateDicomParentEncoding = 2026    /*!< Unable to get the encoding of the parent resource */,
+    OrthancPluginErrorCode_UnknownModality = 2027    /*!< Unknown modality */,
+    OrthancPluginErrorCode_BadJobOrdering = 2028    /*!< Bad ordering of filters in a job */,
 
     _OrthancPluginErrorCode_INTERNAL = 0x7fffffff
   } OrthancPluginErrorCode;
--- a/Resources/ErrorCodes.json	Tue Aug 25 16:18:37 2015 +0200
+++ b/Resources/ErrorCodes.json	Tue Aug 25 17:39:38 2015 +0200
@@ -1,157 +1,427 @@
 [
-    {
-        "Code": -2, 
-        "Name": "Custom", 
-        "Description": "Custom error, see the attached error message"
-    }, 
-    {
-        "Code": -1, 
-        "Name": "InternalError", 
-        "Description": "Internal error"
-    }, 
-    {
-        "Code": 0, 
-        "HttpStatus": 200, 
-        "Name": "Success", 
-        "Description": "Success"
-    }, 
-    {
-        "Code": 1, 
-        "Name": "Plugin", 
-        "Description": "Error encountered within the plugin engine"
-    },
-    {
-        "Code": 2, 
-        "Name": "NotImplemented", 
-        "Description": "Not implemented yet"
-    }, 
-    {
-        "Code": 3, 
-        "HttpStatus": 400, 
-        "Name": "ParameterOutOfRange", 
-        "Description": "Parameter out of range"
-    }, 
-    {
-        "Code": 4, 
-        "Name": "NotEnoughMemory", 
-        "Description": "Not enough memory"
-    }, 
-    {
-        "Code": 5, 
-        "HttpStatus": 400, 
-        "Name": "BadParameterType", 
-        "Description": "Bad type for a parameter"
-    }, 
-    {
-        "Code": 6, 
-        "Name": "BadSequenceOfCalls", 
-        "Description": "Bad sequence of calls"
-    }, 
-    {
-        "Code": 7, 
-        "HttpStatus": 404, 
-        "Name": "InexistentItem", 
-        "Description": "Accessing an inexistent item"
-    }, 
-    {
-        "Code": 8, 
-        "HttpStatus": 400, 
-        "Name": "BadRequest", 
-        "Description": "Bad request"
-    }, 
-    {
-        "Code": 9, 
-        "Name": "NetworkProtocol", 
-        "Description": "Error in the network protocol"
-    }, 
-    {
-        "Code": 10, 
-        "Name": "SystemCommand", 
-        "Description": "Error while calling a system command"
-    }, 
-    {
-        "Code": 11, 
-        "Name": "Database", 
-        "Description": "Error with the database engine"
-    }, 
-    {
-        "Code": 12, 
-        "HttpStatus": 400, 
-        "Name": "UriSyntax", 
-        "Description": "Badly formatted URI"
-    }, 
-    {
-        "Code": 13, 
-        "HttpStatus": 404, 
-        "Name": "InexistentFile", 
-        "Description": "Inexistent file"
-    }, 
-    {
-        "Code": 14, 
-        "Name": "CannotWriteFile", 
-        "Description": "Cannot write to file"
-    }, 
-    {
-        "Code": 15, 
-        "HttpStatus": 400, 
-        "Name": "BadFileFormat", 
-        "Description": "Bad file format"
-    }, 
-    {
-        "Code": 16, 
-        "Name": "Timeout", 
-        "Description": "Timeout"
-    }, 
-    {
-        "Code": 17, 
-        "HttpStatus": 404, 
-        "Name": "UnknownResource", 
-        "Description": "Unknown resource"
-    }, 
-    {
-        "Code": 18, 
-        "Name": "IncompatibleDatabaseVersion", 
-        "Description": "Incompatible version of the database"
-    }, 
-    {
-        "Code": 19, 
-        "Name": "FullStorage", 
-        "Description": "The file storage is full"
-    }, 
-    {
-        "Code": 20, 
-        "Name": "CorruptedFile", 
-        "Description": "Corrupted file (e.g. inconsistent MD5 hash)"
-    }, 
-    {
-        "Code": 21, 
-        "HttpStatus": 404, 
-        "Name": "InexistentTag", 
-        "Description": "Inexistent tag"
-    }, 
-    {
-        "Code": 22, 
-        "Name": "ReadOnly", 
-        "Description": "Cannot modify a read-only data structure"
-    }, 
-    {
-        "Code": 23, 
-        "Name": "IncompatibleImageFormat", 
-        "Description": "Incompatible format of the images"
-    }, 
-    {
-        "Code": 24, 
-        "Name": "IncompatibleImageSize", 
-        "Description": "Incompatible size of the images"
-    }, 
-    {
-        "Code": 25, 
-        "Name": "SharedLibrary", 
-        "Description": "Error while using a shared library (plugin)"
-    }, 
-    {
-        "Code": 26, 
-        "Name": "UnknownPluginService", 
-        "Description": "Plugin invoking an unknown service"
-    }
+  /** Generic error codes **/
+
+  {
+    "Code": -2, 
+    "Name": "Custom", 
+    "Description": "Custom error, see the attached error message"
+  }, 
+  {
+    "Code": -1, 
+    "Name": "InternalError", 
+    "Description": "Internal error"
+  }, 
+  {
+    "Code": 0, 
+    "HttpStatus": 200, 
+    "Name": "Success", 
+    "Description": "Success"
+  }, 
+  {
+    "Code": 1, 
+    "Name": "Plugin", 
+    "Description": "Error encountered within the plugin engine"
+  },
+  {
+    "Code": 2, 
+    "Name": "NotImplemented", 
+    "Description": "Not implemented yet"
+  }, 
+  {
+    "Code": 3, 
+    "HttpStatus": 400, 
+    "Name": "ParameterOutOfRange", 
+    "Description": "Parameter out of range",
+    "SQLite": true
+  }, 
+  {
+    "Code": 4, 
+    "Name": "NotEnoughMemory", 
+    "Description": "Not enough memory"
+  }, 
+  {
+    "Code": 5, 
+    "HttpStatus": 400, 
+    "Name": "BadParameterType", 
+    "Description": "Bad type for a parameter",
+    "SQLite": true
+  }, 
+  {
+    "Code": 6, 
+    "Name": "BadSequenceOfCalls", 
+    "Description": "Bad sequence of calls"
+  }, 
+  {
+    "Code": 7, 
+    "HttpStatus": 404, 
+    "Name": "InexistentItem", 
+    "Description": "Accessing an inexistent item"
+  }, 
+  {
+    "Code": 8, 
+    "HttpStatus": 400, 
+    "Name": "BadRequest", 
+    "Description": "Bad request"
+  }, 
+  {
+    "Code": 9, 
+    "Name": "NetworkProtocol", 
+    "Description": "Error in the network protocol"
+  }, 
+  {
+    "Code": 10, 
+    "Name": "SystemCommand", 
+    "Description": "Error while calling a system command"
+  }, 
+  {
+    "Code": 11, 
+    "Name": "Database", 
+    "Description": "Error with the database engine"
+  }, 
+  {
+    "Code": 12, 
+    "HttpStatus": 400, 
+    "Name": "UriSyntax", 
+    "Description": "Badly formatted URI"
+  }, 
+  {
+    "Code": 13, 
+    "HttpStatus": 404, 
+    "Name": "InexistentFile", 
+    "Description": "Inexistent file"
+  }, 
+  {
+    "Code": 14, 
+    "Name": "CannotWriteFile", 
+    "Description": "Cannot write to file"
+  }, 
+  {
+    "Code": 15, 
+    "HttpStatus": 400, 
+    "Name": "BadFileFormat", 
+    "Description": "Bad file format"
+  }, 
+  {
+    "Code": 16, 
+    "Name": "Timeout", 
+    "Description": "Timeout"
+  }, 
+  {
+    "Code": 17, 
+    "HttpStatus": 404, 
+    "Name": "UnknownResource", 
+    "Description": "Unknown resource"
+  }, 
+  {
+    "Code": 18, 
+    "Name": "IncompatibleDatabaseVersion", 
+    "Description": "Incompatible version of the database"
+  }, 
+  {
+    "Code": 19, 
+    "Name": "FullStorage", 
+    "Description": "The file storage is full"
+  }, 
+  {
+    "Code": 20, 
+    "Name": "CorruptedFile", 
+    "Description": "Corrupted file (e.g. inconsistent MD5 hash)"
+  }, 
+  {
+    "Code": 21, 
+    "HttpStatus": 404, 
+    "Name": "InexistentTag", 
+    "Description": "Inexistent tag"
+  }, 
+  {
+    "Code": 22, 
+    "Name": "ReadOnly", 
+    "Description": "Cannot modify a read-only data structure"
+  }, 
+  {
+    "Code": 23, 
+    "Name": "IncompatibleImageFormat", 
+    "Description": "Incompatible format of the images"
+  }, 
+  {
+    "Code": 24, 
+    "Name": "IncompatibleImageSize", 
+    "Description": "Incompatible size of the images"
+  }, 
+  {
+    "Code": 25, 
+    "Name": "SharedLibrary", 
+    "Description": "Error while using a shared library (plugin)"
+  }, 
+  {
+    "Code": 26, 
+    "Name": "UnknownPluginService", 
+    "Description": "Plugin invoking an unknown service"
+  }, 
+  {
+    "Code": 27, 
+    "Name": "UnknownDicomTag", 
+    "Description": "Unknown DICOM tag"
+  },
+
+
+
+
+
+
+  /** SQLite **/
+
+
+  {
+    "Code": 1000, 
+    "Name": "SQLiteNotOpened",
+    "Description": "SQLite: The database is not opened",
+    "SQLite": true
+  },
+  {
+    "Code": 1001, 
+    "Name": "SQLiteAlreadyOpened", 
+    "Description": "SQLite: Connection is already open",
+    "SQLite": true
+  },
+  {
+    "Code": 1002, 
+    "Name": "SQLiteCannotOpen", 
+    "Description": "SQLite: Unable to open the database",
+    "SQLite": true
+  },
+  {
+    "Code": 1003, 
+    "Name": "SQLiteStatementAlreadyUsed", 
+    "Description": "SQLite: This cached statement is already being referred to",
+    "SQLite": true
+  },
+  {
+    "Code": 1004, 
+    "Name": "SQLiteExecute", 
+    "Description": "SQLite: Cannot execute a command",
+    "SQLite": true
+  },
+  {
+    "Code": 1005, 
+    "Name": "SQLiteRollbackWithoutTransaction", 
+    "Description": "SQLite: Rolling back a nonexistent transaction (have you called Begin()?)",
+    "SQLite": true
+  },
+  {
+    "Code": 1006, 
+    "Name": "SQLiteCommitWithoutTransaction", 
+    "Description": "SQLite: Committing a nonexistent transaction",
+    "SQLite": true
+  },
+  {
+    "Code": 1007, 
+    "Name": "SQLiteRegisterFunction", 
+    "Description": "SQLite: Unable to register a function",
+    "SQLite": true
+  },
+  {
+    "Code": 1008, 
+    "Name": "SQLiteFlush", 
+    "Description": "SQLite: Unable to flush the database",
+    "SQLite": true
+  },
+  {
+    "Code": 1009, 
+    "Name": "SQLiteCannotRun", 
+    "Description": "SQLite: Cannot run a cached statement",
+    "SQLite": true
+  },
+  {
+    "Code": 1010, 
+    "Name": "SQLiteCannotStep", 
+    "Description": "SQLite: Cannot step over a cached statement",
+    "SQLite": true
+  },
+  {
+    "Code": 1011, 
+    "Name": "SQLiteBindOutOfRange", 
+    "Description": "SQLite: Bing a value while out of range (serious error)",
+    "SQLite": true
+  },
+  {
+    "Code": 1012, 
+    "Name": "SQLitePrepareStatement", 
+    "Description": "SQLite: Cannot prepare a cached statement",
+    "SQLite": true
+  },
+  {
+    "Code": 1013, 
+    "Name": "SQLiteTransactionAlreadyStarted", 
+    "Description": "SQLite: Beginning the same transaction twice",
+    "SQLite": true
+  },
+  {
+    "Code": 1014, 
+    "Name": "SQLiteTransactionCommit", 
+    "Description": "SQLite: Failure when committing the transaction",
+    "SQLite": true
+  },
+  {
+    "Code": 1015, 
+    "Name": "SQLiteTransactionBegin", 
+    "Description": "SQLite: Cannot start a transaction",
+    "SQLite": true
+  },
+
+
+
+
+
+
+
+
+  /** Specific error codes **/
+
+  
+  {
+    "Code": 2000, 
+    "Name": "DirectoryOverFile", 
+    "Description": "The directory to be created is already occupied by a regular file"
+  },
+  {
+    "Code": 2001, 
+    "Name": "FileStorageCannotWrite", 
+    "Description": "Unable to create a subdirectory or a file in the file storage"
+  },
+  {
+    "Code": 2002, 
+    "Name": "DirectoryExpected", 
+    "Description": "The specified path does not point to a directory"
+  },
+  {
+    "Code": 2003, 
+    "Name": "HttpPortInUse", 
+    "Description": "The TCP port of the HTTP server is already in use"
+  },
+  {
+    "Code": 2004, 
+    "Name": "DicomPortInUse", 
+    "Description": "The TCP port of the DICOM server is already in use"
+  },
+  {
+    "Code": 2005, 
+    "Name": "BadHttpStatusInRest", 
+    "Description": "This HTTP status is not allowed in a REST API"
+  },
+  {
+    "Code": 2006, 
+    "Name": "RegularFileExpected", 
+    "Description": "The specified path does not point to a regular file"
+  },
+  {
+    "Code": 2007, 
+    "Name": "PathToExecutable", 
+    "Description": "Unable to get the path to the executable"
+  },
+  {
+    "Code": 2008, 
+    "Name": "MakeDirectory", 
+    "Description": "Cannot create a directory"
+  },
+  {
+    "Code": 2009, 
+    "Name": "BadApplicationEntityTitle", 
+    "Description": "An application entity title (AET) cannot be empty or be longer than 16 characters"
+  },
+  {
+    "Code": 2010, 
+    "Name": "NoCFindHandler", 
+    "Description": "No request handler factory for DICOM C-FIND SCP"
+  },
+  {
+    "Code": 2011, 
+    "Name": "NoCMoveHandler", 
+    "Description": "No request handler factory for DICOM C-MOVE SCP"
+  },
+  {
+    "Code": 2012, 
+    "Name": "NoCStoreHandler", 
+    "Description": "No request handler factory for DICOM C-STORE SCP"
+  },
+  {
+    "Code": 2013, 
+    "Name": "NoApplicationEntityFilter", 
+    "Description": "No application entity filter"
+  },
+  {
+    "Code": 2014, 
+    "Name": "NoSopClassOrInstance", 
+    "Description": "DicomUserConnection: Unable to find the SOP class and instance"
+  },
+  {
+    "Code": 2015, 
+    "Name": "NoPresentationContext", 
+    "Description": "DicomUserConnection: No acceptable presentation context for modality"
+  },
+  {
+    "Code": 2016, 
+    "Name": "DicomFindUnavailable", 
+    "Description": "DicomUserConnection: The C-FIND command is not supported by the remote SCP"
+  },
+  {
+    "Code": 2017, 
+    "Name": "DicomMoveUnavailable", 
+    "Description": "DicomUserConnection: The C-MOVE command is not supported by the remote SCP"
+  },
+  {
+    "Code": 2018, 
+    "Name": "CannotStoreInstance", 
+    "Description": "Cannot store an instance"
+  },
+  {
+    "Code": 2019, 
+    "Name": "CreateDicomNotString", 
+    "Description": "Only string values are supported when creating DICOM instances"
+  },
+  {
+    "Code": 2020, 
+    "Name": "CreateDicomOverrideTag", 
+    "Description": "Trying to override a value inherited from a parent module"
+  },
+  {
+    "Code": 2021, 
+    "Name": "CreateDicomUseContent", 
+    "Description": "Use \\\"Content\\\" to inject an image into a new DICOM instance"
+  },
+  {
+    "Code": 2022, 
+    "Name": "CreateDicomNoPayload", 
+    "Description": "No payload is present for one instance in the series"
+  },
+  {
+    "Code": 2023, 
+    "Name": "CreateDicomUseDataUriScheme", 
+    "Description": "The payload of the DICOM instance must be specified according to Data URI scheme"
+  },
+  {
+    "Code": 2024, 
+    "Name": "CreateDicomBadParent", 
+    "Description": "Trying to attach a new DICOM instance to an inexistent resource"
+  },
+  {
+    "Code": 2025, 
+    "Name": "CreateDicomParentIsInstance", 
+    "Description": "Trying to attach a new DICOM instance to an instance (must be a series, study or patient)"
+  },
+  {
+    "Code": 2026, 
+    "Name": "CreateDicomParentEncoding", 
+    "Description": "Unable to get the encoding of the parent resource"
+  },
+  {
+    "Code": 2027, 
+    "Name": "UnknownModality", 
+    "Description": "Unknown modality"
+  },
+  {
+    "Code": 2028, 
+    "Name": "BadJobOrdering", 
+    "Description": "Bad ordering of filters in a job"
+  }
 ]
--- a/Resources/GenerateErrorCodes.py	Tue Aug 25 16:18:37 2015 +0200
+++ b/Resources/GenerateErrorCodes.py	Tue Aug 25 17:39:38 2015 +0200
@@ -43,7 +43,7 @@
 ##
 
 with open(os.path.join(BASE, 'Resources', 'ErrorCodes.json'), 'r') as f:
-    ERRORS = json.loads(f.read())
+    ERRORS = json.loads(re.sub('/\*.*?\*/', '', f.read()))
 
 with open(os.path.join(BASE, 'Core', 'Enumerations.h'), 'r') as f:
     a = f.read()
--- a/UnitTestsSources/MultiThreadingTests.cpp	Tue Aug 25 16:18:37 2015 +0200
+++ b/UnitTestsSources/MultiThreadingTests.cpp	Tue Aug 25 17:39:38 2015 +0200
@@ -96,7 +96,7 @@
     SharedMessageQueue q;
     q.Enqueue(new DynamicInteger(10, s));
     q.Enqueue(new DynamicInteger(20, s));  
-    throw OrthancException("Nope");
+    throw OrthancException(ErrorCode_Custom);
   }
   catch (OrthancException&)
   {