changeset 330:0cfe173e428d

sync Orthanc + code model from mainline
author Alain Mazy <am@orthanc.team>
date Thu, 20 Aug 2026 17:36:31 +0200
parents abaaac21aac5
children 4e1efa5fbc61
files NEWS Resources/Orthanc/CMake/AutoGeneratedCode.cmake Resources/Orthanc/CMake/Compiler.cmake Resources/Orthanc/CMake/DownloadOrthancFramework.cmake Resources/Orthanc/CMake/DownloadPackage.cmake Resources/Orthanc/CMake/EmbedResources.py Resources/Orthanc/CMake/GoogleTestConfiguration.cmake Resources/Orthanc/OrthancPluginCodeModel.json Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h Resources/Orthanc/Plugins/OrthancPluginException.h Resources/Orthanc/Plugins/OrthancPluginsExports.cmake Resources/Orthanc/Toolchains/LinuxStandardBaseToolchain.cmake Resources/Orthanc/Toolchains/MinGW-W64-Toolchain32.cmake Resources/Orthanc/Toolchains/MinGW-W64-Toolchain64.cmake Resources/Orthanc/Toolchains/MinGWToolchain.cmake
diffstat 16 files changed, 518 insertions(+), 361 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Mon Aug 10 10:26:44 2026 +0200
+++ b/NEWS	Thu Aug 20 17:36:31 2026 +0200
@@ -1,6 +1,10 @@
 Pending changes in the mainline
 ===============================
 
+Note: the next version of this plugin will require Orthanc SDK 1.13.1
+to be released
+* wrapped DicomInsante.GetInstanceRemoteIp() & DicomInsante.GetInstanceCalledAet()
+
 
 Version 7.1 (2026-04-07)
 ========================
--- a/Resources/Orthanc/CMake/AutoGeneratedCode.cmake	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/CMake/AutoGeneratedCode.cmake	Thu Aug 20 17:36:31 2026 +0200
@@ -76,5 +76,5 @@
 
   list(APPEND AUTOGENERATED_SOURCES
     "${TARGET_BASE}.cpp"
-    ) 
+    )
 endmacro()
--- a/Resources/Orthanc/CMake/Compiler.cmake	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/CMake/Compiler.cmake	Thu Aug 20 17:36:31 2026 +0200
@@ -43,7 +43,7 @@
 include(CheckLibraryExists)
 
 if ((CMAKE_CROSSCOMPILING AND NOT
-      "${CMAKE_SYSTEM_VERSION}" STREQUAL "CrossToolNg") OR    
+      "${CMAKE_SYSTEM_VERSION}" STREQUAL "CrossToolNg") OR
     "${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
   # Cross-compilation necessarily implies standalone and static build
   SET(STATIC_BUILD ON)
@@ -70,7 +70,7 @@
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-long-long")
 
   # --std=c99 makes libcurl not to compile
-  # -pedantic gives a lot of warnings on OpenSSL 
+  # -pedantic gives a lot of warnings on OpenSSL
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-variadic-macros")
 
   if (CMAKE_CROSSCOMPILING)
@@ -85,12 +85,12 @@
   foreach(flag_var
     CMAKE_C_FLAGS_DEBUG
     CMAKE_CXX_FLAGS_DEBUG
-    CMAKE_C_FLAGS_RELEASE 
+    CMAKE_C_FLAGS_RELEASE
     CMAKE_CXX_FLAGS_RELEASE
-    CMAKE_C_FLAGS_MINSIZEREL 
-    CMAKE_CXX_FLAGS_MINSIZEREL 
-    CMAKE_C_FLAGS_RELWITHDEBINFO 
-    CMAKE_CXX_FLAGS_RELWITHDEBINFO) 
+    CMAKE_C_FLAGS_MINSIZEREL
+    CMAKE_CXX_FLAGS_MINSIZEREL
+    CMAKE_C_FLAGS_RELWITHDEBINFO
+    CMAKE_CXX_FLAGS_RELWITHDEBINFO)
     string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
     string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}")
   endforeach(flag_var)
@@ -109,7 +109,7 @@
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP")
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
   endif()
-    
+
   add_definitions(
     -D_CRT_SECURE_NO_WARNINGS=1
     -D_CRT_SECURE_NO_DEPRECATE=1
@@ -188,7 +188,7 @@
     # for LFS (Large File Support).
     # https://ohse.de/uwe/articles/lfs.html
     add_definitions(
-      -D_LARGEFILE64_SOURCE=1 
+      -D_LARGEFILE64_SOURCE=1
       -D_FILE_OFFSET_BITS=64
       )
   endif()
@@ -254,14 +254,14 @@
   add_definitions(
     -D_XOPEN_SOURCE=1
     )
-  
+
   # Linking with iconv breaks the Universal builds on modern compilers
   # link_libraries(iconv)
 
 elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
   message("Building using Emscripten (for WebAssembly or asm.js targets)")
   include(${CMAKE_CURRENT_LIST_DIR}/EmscriptenParameters.cmake)
-  
+
 elseif (CMAKE_SYSTEM_NAME STREQUAL "Android")
 
 else()
--- a/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake	Thu Aug 20 17:36:31 2026 +0200
@@ -177,6 +177,10 @@
         set(ORTHANC_FRAMEWORK_MD5 "66b5a2ee60706c4a502896083b9e1a01")
       elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.10")
         set(ORTHANC_FRAMEWORK_MD5 "d5e1ba442104c89a24013cb859a9d6bf")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.11")
+        set(ORTHANC_FRAMEWORK_MD5 "389b273b64b513ba8fc3233f34201cc1")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.13.0")
+        set(ORTHANC_FRAMEWORK_MD5 "cc95d3e509612b541e10e91c831fbfe3")
 
       # Below this point are development snapshots that were used to
       # release some plugin, before an official release of the Orthanc
@@ -236,6 +240,11 @@
         # for HttpClient that returns the answer body in case of HTTP error
         set(ORTHANC_FRAMEWORK_PRE_RELEASE ON)
         set(ORTHANC_FRAMEWORK_MD5 "665f8aa70d7c5091bc20da37cf664910")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "004b351797fe")
+        # PixelsMasker 0.1.2 (framework post-1.12.11)
+        # for ScopedThreadNameSetter
+        set(ORTHANC_FRAMEWORK_PRE_RELEASE ON)
+        set(ORTHANC_FRAMEWORK_MD5 "f078ca997217b831ab3f6741f08a8c07")
       endif()
     endif()
   endif()
@@ -255,7 +264,7 @@
 
 if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg")
   find_program(ORTHANC_FRAMEWORK_HG hg)
-  
+
   if (${ORTHANC_FRAMEWORK_HG} MATCHES "ORTHANC_FRAMEWORK_HG-NOTFOUND")
     message(FATAL_ERROR "Please install Mercurial")
   endif()
@@ -265,8 +274,8 @@
 if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "archive" OR
     ORTHANC_FRAMEWORK_SOURCE STREQUAL "web")
   if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
-    find_program(ORTHANC_FRAMEWORK_7ZIP 7z 
-      PATHS 
+    find_program(ORTHANC_FRAMEWORK_7ZIP 7z
+      PATHS
       "$ENV{ProgramFiles}/7-Zip"
       "$ENV{ProgramW6432}/7-Zip"
       )
@@ -294,7 +303,7 @@
       ORTHANC_FRAMEWORK_ROOT STREQUAL "")
     message(FATAL_ERROR "The variable ORTHANC_FRAMEWORK_ROOT must provide the path to the sources of Orthanc")
   endif()
-  
+
   if (NOT EXISTS ${ORTHANC_FRAMEWORK_ROOT})
     message(FATAL_ERROR "Non-existing directory: ${ORTHANC_FRAMEWORK_ROOT}")
   endif()
@@ -319,14 +328,14 @@
       COMMAND ${ORTHANC_FRAMEWORK_HG} pull
       WORKING_DIRECTORY ${ORTHANC_ROOT}
       RESULT_VARIABLE Failure
-      )    
+      )
   else()
     message("Forking the Orthanc source repository using Mercurial")
     execute_process(
       COMMAND ${ORTHANC_FRAMEWORK_HG} clone "https://orthanc.uclouvain.be/hg/orthanc/"
       WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
       RESULT_VARIABLE Failure
-      )    
+      )
   endif()
 
   if (Failure OR NOT EXISTS ${ORTHANC_ROOT})
@@ -389,14 +398,14 @@
     message("Downloading: ${ORTHANC_FRAMEWORK_URL}")
 
     file(DOWNLOAD
-      "${ORTHANC_FRAMEWORK_URL}" "${ORTHANC_FRAMEWORK_ARCHIVE}" 
+      "${ORTHANC_FRAMEWORK_URL}" "${ORTHANC_FRAMEWORK_ARCHIVE}"
       SHOW_PROGRESS EXPECTED_MD5 "${ORTHANC_FRAMEWORK_MD5}"
       TIMEOUT 60
       INACTIVITY_TIMEOUT 60
       )
   else()
     message("Using local copy of: ${ORTHANC_FRAMEWORK_URL}")
-  endif()  
+  endif()
 endif()
 
 
@@ -432,7 +441,7 @@
     if (NOT ORTHANC_FRAMEWORK_ARCHIVE MATCHES ".tar.gz$")
       message(FATAL_ERROR "Archive should have the \".tar.gz\" extension: ${ORTHANC_FRAMEWORK_ARCHIVE}")
     endif()
-    
+
     message("Uncompressing: ${ORTHANC_FRAMEWORK_ARCHIVE}")
 
     if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
@@ -445,7 +454,7 @@
         RESULT_VARIABLE Failure
         OUTPUT_QUIET
         )
-      
+
       if (Failure)
         message(FATAL_ERROR "Error while running the uncompression tool")
       endif()
@@ -467,7 +476,7 @@
         RESULT_VARIABLE Failure
         )
     endif()
-   
+
     if (Failure)
       message(FATAL_ERROR "Error while running the uncompression tool")
     endif()
@@ -533,10 +542,10 @@
     set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libstdc++")
     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++")
   endif()
-  
+
   include(CheckIncludeFile)
   include(CheckIncludeFileCXX)
-  
+
   if(CMAKE_VERSION VERSION_GREATER "3.11")
     find_package(Python REQUIRED COMPONENTS Interpreter)
     set(PYTHON_EXECUTABLE ${Python_EXECUTABLE})
@@ -544,7 +553,7 @@
     include(FindPythonInterp)
     find_package(PythonInterp REQUIRED)
   endif()
-  
+
   include(${CMAKE_CURRENT_LIST_DIR}/Compiler.cmake)
   include(${CMAKE_CURRENT_LIST_DIR}/DownloadPackage.cmake)
   include(${CMAKE_CURRENT_LIST_DIR}/AutoGeneratedCode.cmake)
@@ -605,19 +614,19 @@
   if (${ORTHANC_FRAMEWORK_INCLUDE_DIR} STREQUAL "ORTHANC_FRAMEWORK_INCLUDE_DIR-NOTFOUND")
     message(FATAL_ERROR "Cannot locate the OrthancFramework.h header")
   endif()
-  
+
   message("Orthanc framework include dir: ${ORTHANC_FRAMEWORK_INCLUDE_DIR}")
   include_directories(${ORTHANC_FRAMEWORK_INCLUDE_DIR})
 
   if (ORTHANC_FRAMEWORK_USE_SHARED)
     set(CMAKE_REQUIRED_INCLUDES "${ORTHANC_FRAMEWORK_INCLUDE_DIR}")
     set(CMAKE_REQUIRED_LIBRARIES "${ORTHANC_FRAMEWORK_LIBRARIES}")
-    
+
     check_cxx_symbol_exists("Orthanc::InitializeFramework" "OrthancFramework.h" HAVE_ORTHANC_FRAMEWORK)
     if (NOT HAVE_ORTHANC_FRAMEWORK)
       message(FATAL_ERROR "Cannot find the Orthanc framework")
     endif()
-    
+
     unset(CMAKE_REQUIRED_INCLUDES)
     unset(CMAKE_REQUIRED_LIBRARIES)
   endif()
--- a/Resources/Orthanc/CMake/DownloadPackage.cmake	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/CMake/DownloadPackage.cmake	Thu Aug 20 17:36:31 2026 +0200
@@ -59,8 +59,8 @@
 ##
 
 if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
-  find_program(ZIP_EXECUTABLE 7z 
-    PATHS 
+  find_program(ZIP_EXECUTABLE 7z
+    PATHS
     "$ENV{ProgramFiles}/7-Zip"
     "$ENV{ProgramW6432}/7-Zip"
     )
@@ -92,7 +92,7 @@
 
   set(TMP_PATH "${CMAKE_SOURCE_DIR}/ThirdPartyDownloads/${TMP_FILENAME}")
   if (NOT EXISTS "${TMP_PATH}")
-    message("Downloading ${Url}")
+    message("Downloading ${Url} since the file was not found in ${TMP_PATH}")
 
     # This fixes issue 6: "I think cmake shouldn't download the
     # packages which are not in the system, it should stop and let
@@ -124,7 +124,7 @@
       file(REMOVE ${TMP_PATH})
       message(FATAL_ERROR "Cannot download file: ${Url}")
     endif()
-    
+
   else()
     message("Using local copy of ${Url}")
 
@@ -143,7 +143,7 @@
 macro(DownloadPackage MD5 Url TargetDirectory)
   if (NOT IS_DIRECTORY "${TargetDirectory}")
     DownloadFile("${MD5}" "${Url}")
-    
+
     GetUrlExtension(TMP_EXTENSION "${Url}")
     #message(${TMP_EXTENSION})
     message("Uncompressing ${TMP_FILENAME}")
@@ -152,7 +152,7 @@
       # How to silently extract files using 7-zip
       # http://superuser.com/questions/331148/7zip-command-line-extract-silently-quietly
 
-      if (("${TMP_EXTENSION}" STREQUAL "gz") OR 
+      if (("${TMP_EXTENSION}" STREQUAL "gz") OR
           ("${TMP_EXTENSION}" STREQUAL "tgz") OR
           ("${TMP_EXTENSION}" STREQUAL "xz"))
         execute_process(
@@ -221,7 +221,7 @@
         message(FATAL_ERROR "Unsupported package extension: ${TMP_EXTENSION}")
       endif()
     endif()
-   
+
     if (Failure)
       message(FATAL_ERROR "Error while running the uncompression tool")
     endif()
@@ -237,7 +237,7 @@
 macro(DownloadCompressedFile MD5 Url TargetFile)
   if (NOT EXISTS "${TargetFile}")
     DownloadFile("${MD5}" "${Url}")
-    
+
     GetUrlExtension(TMP_EXTENSION "${Url}")
     #message(${TMP_EXTENSION})
     message("Uncompressing ${TMP_FILENAME}")
@@ -275,7 +275,7 @@
         message(FATAL_ERROR "Unsupported file extension: ${TMP_EXTENSION}")
       endif()
     endif()
-   
+
     if (Failure)
       message(FATAL_ERROR "Error while running the uncompression tool")
     endif()
--- a/Resources/Orthanc/CMake/EmbedResources.py	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/CMake/EmbedResources.py	Thu Aug 20 17:36:31 2026 +0200
@@ -90,7 +90,7 @@
 
     if resourceName in resources:
         raise Exception("Twice the same resource: " + resourceName)
-    
+
     if os.path.isdir(pathName):
         # The resource is a directory: Recursively explore its files
         content = {}
@@ -165,7 +165,7 @@
 
 for ns in NAMESPACE.split('.'):
     header.write('namespace %s {\n' % ns)
-    
+
 
 header.write("""
     enum FileResourceId
@@ -177,7 +177,7 @@
     if resources[name]['Type'] == 'File':
         if isFirst:
             isFirst = False
-        else:    
+        else:
             header.write(',\n')
         header.write('      %s' % name)
 
@@ -193,7 +193,7 @@
     if resources[name]['Type'] == 'Directory':
         if isFirst:
             isFirst = False
-        else:    
+        else:
             header.write(',\n')
         header.write('      %s' % name)
 
@@ -235,8 +235,8 @@
 
     # http://stackoverflow.com/a/1035360
     pos = 0
-    buffer = []  # instead of appending a few bytes at a time to the cpp file, 
-                 # we first append each chunk to a list, join it and write it 
+    buffer = []  # instead of appending a few bytes at a time to the cpp file,
+                 # we first append each chunk to a list, join it and write it
                  # to the file.  We've measured that it was 2-3 times faster in python3.
                  # Note that speed is important since if generation is too slow,
                  # cmake might try to compile the EmbeddedResources.cpp file while it is
--- a/Resources/Orthanc/CMake/GoogleTestConfiguration.cmake	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/CMake/GoogleTestConfiguration.cmake	Thu Aug 20 17:36:31 2026 +0200
@@ -70,11 +70,11 @@
   if (MSVC) # VS2012 does not support tuples correctly yet
     add_definitions(/D _VARIADIC_MAX=10)
   endif()
-  
+
   if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
     add_definitions(-DGTEST_HAS_CLONE=0)
   endif()
-  
+
   source_group(ThirdParty\\GoogleTest REGULAR_EXPRESSION ${GOOGLE_TEST_SOURCES_DIR}/.*)
 
 else()
--- a/Resources/Orthanc/OrthancPluginCodeModel.json	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/OrthancPluginCodeModel.json	Thu Aug 20 17:36:31 2026 +0200
@@ -86,6 +86,44 @@
                 },
                 {
                     "args": [],
+                    "c_function": "OrthancPluginGetInstanceCalledAet",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns the Called Application Entity Title (AET) that was used when this instance was sent to Orthanc."
+                        ],
+                        "return": "The AET if success, NULL if error.",
+                        "summary": "Get the Called AET of a DICOM instance."
+                    },
+                    "return_sdk_type": "const char *",
+                    "since_sdk": [
+                        1,
+                        13,
+                        1
+                    ]
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetInstanceRemoteIp",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns the IP of the modality that has sent this instance to Orthanc."
+                        ],
+                        "return": "The AET if success, NULL if error.",
+                        "summary": "Get the Remote IP of a DICOM instance."
+                    },
+                    "return_sdk_type": "const char *",
+                    "since_sdk": [
+                        1,
+                        13,
+                        1
+                    ]
+                },
+                {
+                    "args": [],
                     "c_function": "OrthancPluginGetInstanceSize",
                     "const": true,
                     "documentation": {
@@ -1526,7 +1564,8 @@
                             "size": "The size of the DICOM file."
                         },
                         "description": [
-                            "This function adds one worklist (encoded as a DICOM file) to the set of answers corresponding to some C-Find SCP request against modality worklists."
+                            "This function adds one worklist (encoded as a DICOM file) to the set of answers corresponding to some C-Find SCP request against modality worklists.",
+                            "Note that the provided worklist is still reprocessed by Orthanc, which matches the worklist again against the query and removes the fields that have not been requested by the SCU. Therefore, the returned worklist might have some parts removed, either because they were not requested or because Orthanc failed to match them against the query. For instance, Orthanc is currently not able to match both a ScheduledProcedureStepStartDate AND a ScheduledProcedureStepStartTime."
                         ],
                         "return": "0 if success, other value if error.",
                         "summary": "Add one answer to some modality worklist request."
@@ -1931,7 +1970,7 @@
             ]
         },
         {
-            "documentation": "The available modes to export a binary DICOM tag into a DICOMweb JSON or XML document.",
+            "documentation": "The available modes to export a binary DICOM tag into a DICOMweb JSON or XML document. Binary DICOM tags correspond to the tags whose value representation is \"other\" (OB, OD, OF, OL, OV, or OW).",
             "name": "OrthancPluginDicomWebBinaryMode",
             "since_sdk": [
                 1,
@@ -1953,6 +1992,16 @@
                     "documentation": "Use a bulk data URI field",
                     "key": "BulkDataUri",
                     "value": 2
+                },
+                {
+                    "documentation": "Encode the values as an array (not available for OB, new in Orthanc 1.13.0)",
+                    "key": "ArrayOfValues",
+                    "since_sdk": [
+                        1,
+                        13,
+                        0
+                    ],
+                    "value": 3
                 }
             ]
         },
@@ -3094,7 +3143,7 @@
                     "value": 0
                 },
                 {
-                    "documentation": "The file has already been stored/adopted (only if OverwriteInstances is set to false)",
+                    "documentation": "The file has already been stored/adopted (only if OverwriteInstances is set to \"Never\" or false)",
                     "key": "AlreadyStored",
                     "value": 1
                 },
@@ -3116,7 +3165,7 @@
             ]
         },
         {
-            "documentation": "The value representations present in the DICOM standard (version 2013).",
+            "documentation": "The value representations present in the DICOM standard.",
             "name": "OrthancPluginValueRepresentation",
             "values": [
                 {
@@ -3253,6 +3302,41 @@
                     "documentation": "Unlimited Text",
                     "key": "UT",
                     "value": 27
+                },
+                {
+                    "documentation": "Other Double           (new in Orthanc 1.13.0)",
+                    "key": "OD",
+                    "value": 28
+                },
+                {
+                    "documentation": "Other Long             (new in Orthanc 1.13.0)",
+                    "key": "OL",
+                    "value": 29
+                },
+                {
+                    "documentation": "Unlimited Characters   (new in Orthanc 1.13.0)",
+                    "key": "UC",
+                    "value": 30
+                },
+                {
+                    "documentation": "URI / URL              (new in Orthanc 1.13.0)",
+                    "key": "UR",
+                    "value": 31
+                },
+                {
+                    "documentation": "Other Very Long        (new in Orthanc 1.13.0)",
+                    "key": "OV",
+                    "value": 32
+                },
+                {
+                    "documentation": "Signed Very Long       (new in Orthanc 1.13.0)",
+                    "key": "SV",
+                    "value": 33
+                },
+                {
+                    "documentation": "Unsigned Very Long     (new in Orthanc 1.13.0)",
+                    "key": "UV",
+                    "value": 34
                 }
             ]
         }
@@ -5237,7 +5321,8 @@
                     "threadName": "The name of the current thread. A thread name cannot be longer than 16 characters."
                 },
                 "description": [
-                    "This function gives a name to the thread that is calling this function. This name is used in the Orthanc logs. This function must only be called from threads that the plugin has created itself."
+                    "This function gives a name to the thread that is calling this function. This name is used in the Orthanc logs. This function must only be called from threads that the plugin has created itself.",
+                    "At the end of the lifetime of the thread, OrthancPluginClearCurrentThreadName() must be called to release the allocated resources."
                 ],
                 "return": "0 if success, other value if error.",
                 "summary": "Set the name of the current thread."
@@ -5584,6 +5669,25 @@
                 12,
                 10
             ]
+        },
+        {
+            "args": [],
+            "c_function": "OrthancPluginClearCurrentThreadName",
+            "documentation": {
+                "args": {},
+                "description": [
+                    "This function releases the resources allocated to store the name of the current thread, after a call to OrthancPluginSetCurrentThreadName(). This function must only be called by threads created by the plugin itself, when they are reaching the end of their lifetime."
+                ],
+                "return": "0 if success, other value if error.",
+                "summary": "Clear the name of the current thread."
+            },
+            "return_sdk_enumeration": "OrthancPluginErrorCode",
+            "return_sdk_type": "enumeration",
+            "since_sdk": [
+                1,
+                13,
+                0
+            ]
         }
     ],
     "unwrapped_functions": [
--- a/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp	Thu Aug 20 17:36:31 2026 +0200
@@ -10,7 +10,7 @@
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation, either version 3 of the
  * License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -28,7 +28,7 @@
 #include <boost/move/unique_ptr.hpp>
 #include <boost/thread.hpp>
 #include <boost/algorithm/string/join.hpp>
-
+#include <limits>
 
 #include <json/reader.h>
 #include <json/version.h>
@@ -61,6 +61,13 @@
 #endif
 
 
+#ifdef _MSC_VER
+#  define ORTHANC_SCANF sscanf_s
+#else
+#  define ORTHANC_SCANF sscanf
+#endif
+
+
 namespace OrthancPlugins
 {
   static OrthancPluginContext* globalContext_ = NULL;
@@ -117,7 +124,7 @@
   }
 
 
-#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
+#if HAS_ORTHANC_PLUGINS_LOG_MESSAGE == 1
   void LogMessage(OrthancPluginLogLevel level,
                   const char* file,
                   uint32_t line,
@@ -125,7 +132,7 @@
   {
     if (HasGlobalContext())
     {
-#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
+#if HAS_ORTHANC_PLUGINS_LOG_MESSAGE == 1
       const char* pluginName = (pluginName_.empty() ? NULL : pluginName_.c_str());
       OrthancPluginLogMessage(GetGlobalContext(), message.c_str(), pluginName, file, line, OrthancPluginLogCategory_Generic, level);
 #else
@@ -184,7 +191,7 @@
       // Prevent using garbage information
       buffer_.data = NULL;
       buffer_.size = 0;
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
   }
 
@@ -209,7 +216,7 @@
     }
     else
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
   }
 
@@ -227,7 +234,7 @@
     {
       Clear();
     }
-    catch (ORTHANC_PLUGINS_EXCEPTION_CLASS&)
+    catch (ORTHANC_PLUGINS_EXCEPTION_CLASS&) // NOLINT(bugprone-empty-catch)
     {
       // Don't throw exceptions in destructors
     }
@@ -264,7 +271,7 @@
     }
     else
     {
-      if (size > 0)
+      if (buffer != NULL && size > 0)
       {
         memcpy(buffer_.data, buffer, size);
       }
@@ -365,7 +372,7 @@
   }
 
 
-#if (HAS_ORTHANC_PLUGIN_PEERS == 1) || (HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1) || (HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1)
+#if (HAS_ORTHANC_PLUGINS_PEERS == 1) || (HAS_ORTHANC_PLUGINS_HTTP_CLIENT == 1) || (HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1)
   static void DecodeHttpHeaders(HttpHeaders& target,
                                 const MemoryBuffer& source)
   {
@@ -411,7 +418,7 @@
       {
         headersKeys_.push_back(it->first.c_str());
         headersValues_.push_back(it->second.c_str());
-      }      
+      }
     }
 
     const char* const* GetKeys()
@@ -439,7 +446,7 @@
     PluginHttpHeaders headers(httpHeaders);
 
     return CheckHttp(OrthancPluginRestApiGet2(
-                       GetGlobalContext(), &buffer_, uri.c_str(), 
+                       GetGlobalContext(), &buffer_, uri.c_str(),
                        headers.GetSize(),
                        headers.GetKeys(),
                        headers.GetValues(), applyPlugins));
@@ -451,7 +458,7 @@
                                  bool applyPlugins)
   {
     Clear();
-    
+
     // Cast for compatibility with Orthanc SDK <= 1.5.6
     const char* b = reinterpret_cast<const char*>(body);
 
@@ -465,7 +472,7 @@
     }
   }
 
-#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+#if HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1
 
   bool MemoryBuffer::RestApiPost(const std::string& uri,
                                  const void* body,
@@ -478,7 +485,7 @@
 
     PluginHttpHeaders headers(httpHeaders);
 
-    return CheckHttp(OrthancPluginCallRestApi(GetGlobalContext(), 
+    return CheckHttp(OrthancPluginCallRestApi(GetGlobalContext(),
                                               &buffer_,
                                               *answerHeaders,
                                               &httpStatus,
@@ -534,10 +541,10 @@
 #else
     Json::CharReaderBuilder builder;
     builder.settings_["collectComments"] = collectComments;
-    
+
     const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
     assert(reader.get() != NULL);
-    
+
     JSONCPP_STRING err;
     if (reader->parse(reinterpret_cast<const char*>(buffer),
                       reinterpret_cast<const char*>(buffer) + size, &target, &err))
@@ -558,7 +565,7 @@
   {
     return ReadJson(target, source.empty() ? NULL : source.c_str(), source.size());
   }
-  
+
 
   bool ReadJson(Json::Value& target,
                 const void* buffer,
@@ -566,14 +573,14 @@
   {
     return ReadJsonInternal(target, buffer, size, true);
   }
-  
+
 
   bool ReadJsonWithoutComments(Json::Value& target,
                                const std::string& source)
   {
     return ReadJsonWithoutComments(target, source.empty() ? NULL : source.c_str(), source.size());
   }
-  
+
 
   bool ReadJsonWithoutComments(Json::Value& target,
                                const void* buffer,
@@ -595,7 +602,7 @@
     target = Json::writeString(builder, source);
 #endif
   }
-  
+
 
   void WriteStyledJson(std::string& target,
                        const Json::Value& source)
@@ -675,7 +682,7 @@
     {
       Clear();
     }
-    catch (ORTHANC_PLUGINS_EXCEPTION_CLASS&)
+    catch (ORTHANC_PLUGINS_EXCEPTION_CLASS&) // NOLINT(bugprone-empty-catch)
     {
       // Don't throw exceptions in destructors
     }
@@ -839,7 +846,7 @@
     }
     else
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(error);
     }
   }
 
@@ -862,7 +869,7 @@
       ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
     }
   }
-    
+
 
   OrthancConfiguration::OrthancConfiguration()
   {
@@ -977,7 +984,15 @@
         return true;
 
       case Json::uintValue:
-        target = configuration_[key].asUInt();
+        if (configuration_[key].asUInt() > static_cast<unsigned int>(std::numeric_limits<int>::max()))
+        {
+          ORTHANC_PLUGINS_LOG_ERROR("The configuration option \"" + GetPath(key) +
+                                    "\" is too large to fit in an integer");
+
+          ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat);
+        }
+
+        target = static_cast<int>(configuration_[key].asUInt());
         return true;
 
       default:
@@ -1338,7 +1353,7 @@
     {
       Clear();
     }
-    catch (ORTHANC_PLUGINS_EXCEPTION_CLASS&)
+    catch (ORTHANC_PLUGINS_EXCEPTION_CLASS&) // NOLINT(bugprone-empty-catch)
     {
       // Don't throw exceptions in destructors
     }
@@ -1473,7 +1488,7 @@
   }
 
 
-#if HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1
+#if HAS_ORTHANC_PLUGINS_FIND_MATCHER == 1
   FindMatcher::FindMatcher(const OrthancPluginWorklistQuery* worklist) :
     matcher_(NULL),
     worklist_(worklist)
@@ -1542,18 +1557,18 @@
     }
   }
 
-#endif /* HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 */
+#endif /* HAS_ORTHANC_PLUGINS_FIND_MATCHER == 1 */
 
   static void CheckAnswerSizeIsLessThan4GB(const std::string& answer)
   {
     if (answer.size() > static_cast<size_t>(std::numeric_limits<uint32_t>::max()))
     {
-  #if HAS_ORTHANC_EXCEPTION == 1
+#if HAS_ORTHANC_EXCEPTION == 1
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange, "Cannot send HTTP response larger than 4GB");
-  #else
+#else
       ORTHANC_PLUGINS_LOG_ERROR("Cannot send HTTP response larger than 4GB");
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);          
-  #endif
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
+#endif
     }
   }
 
@@ -1562,7 +1577,7 @@
   {
     std::string bodyString;
     WriteStyledJson(bodyString, value);
-    CheckAnswerSizeIsLessThan4GB(bodyString);    
+    CheckAnswerSizeIsLessThan4GB(bodyString);
     OrthancPluginAnswerBuffer(GetGlobalContext(), output, bodyString.c_str(), bodyString.size(), "application/json");
   }
 
@@ -1590,7 +1605,7 @@
                                output,
                                "content-type",
                                mimeType);
-                               
+
     OrthancPluginSendHttpStatus(GetGlobalContext(),
                                 output,
                                 httpError,
@@ -1726,7 +1741,7 @@
     }
   }
 
-#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+#if HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1
   bool RestApiPost(Json::Value& result,
                    const std::string& uri,
                    const Json::Value& body,
@@ -1821,7 +1836,7 @@
     }
     else
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(error);
     }
   }
 
@@ -1850,12 +1865,6 @@
       return true;
     }
 
-#ifdef _MSC_VER
-#define ORTHANC_SCANF sscanf_s
-#else
-#define ORTHANC_SCANF sscanf
-#endif
-
     // Parse the version
     int aa, bb, cc = 0;
     if ((ORTHANC_SCANF(version, "%4d.%4d.%4d", &aa, &bb, &cc) != 3 &&
@@ -1943,7 +1952,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_PEERS == 1
+#if HAS_ORTHANC_PLUGINS_PEERS == 1
   size_t OrthancPeers::GetPeerIndex(const std::string& name) const
   {
     size_t index;
@@ -1967,7 +1976,7 @@
 
     if (peers_ == NULL)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_Plugin);
     }
 
     uint32_t count = OrthancPluginGetPeersCount(GetGlobalContext(), peers_);
@@ -1978,7 +1987,7 @@
       if (name == NULL)
       {
         OrthancPluginFreePeers(GetGlobalContext(), peers_);
-        ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin);
+        ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_Plugin);
       }
 
       index_[name] = i;
@@ -2016,14 +2025,14 @@
   {
     if (index >= index_.size())
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
     }
     else
     {
       const char* s = OrthancPluginGetPeerName(GetGlobalContext(), peers_, static_cast<uint32_t>(index));
       if (s == NULL)
       {
-        ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin);
+        ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_Plugin);
       }
       else
       {
@@ -2037,14 +2046,14 @@
   {
     if (index >= index_.size())
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
     }
     else
     {
       const char* s = OrthancPluginGetPeerUrl(GetGlobalContext(), peers_, static_cast<uint32_t>(index));
       if (s == NULL)
       {
-        ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin);
+        ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_Plugin);
       }
       else
       {
@@ -2066,7 +2075,7 @@
   {
     if (index >= index_.size())
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
     }
     else
     {
@@ -2099,7 +2108,7 @@
   {
     if (index >= index_.size())
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
     }
 
     OrthancPlugins::MemoryBuffer answer;
@@ -2187,7 +2196,7 @@
                             size_t index,
                             const std::string& uri,
                             const std::string& body,
-                            const HttpHeaders& headers, 
+                            const HttpHeaders& headers,
                             unsigned int timeout) const
   {
     MemoryBuffer buffer;
@@ -2209,7 +2218,7 @@
                             size_t index,
                             const std::string& uri,
                             const std::string& body,
-                            const HttpHeaders& headers, 
+                            const HttpHeaders& headers,
                             unsigned int timeout) const
   {
     MemoryBuffer buffer;
@@ -2297,7 +2306,7 @@
   {
     if (index >= index_.size())
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
     }
 
     if (body.size() > 0xffffffffu)
@@ -2320,7 +2329,7 @@
     {
       target.Swap(answer);
       DecodeHttpHeaders(answerHeaders, answerHeadersBuffer);
-      
+
       return (status == 200);
     }
     else
@@ -2337,7 +2346,7 @@
   {
     if (index >= index_.size())
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
     }
 
     if (body.size() > 0xffffffffu)
@@ -2383,7 +2392,7 @@
   {
     if (index >= index_.size())
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
     }
 
     OrthancPlugins::MemoryBuffer answer;
@@ -2424,7 +2433,7 @@
    ** JOBS
    ******************************************************************/
 
-#if HAS_ORTHANC_PLUGIN_JOB == 1
+#if HAS_ORTHANC_PLUGINS_JOB == 1
   void OrthancJob::CallbackFinalize(void* job)
   {
     if (job != NULL)
@@ -2463,7 +2472,7 @@
       {
         memcpy(target->data, source.c_str(), source.size());
       }
-      
+
       return OrthancPluginErrorCode_Success;
     }
   }
@@ -2506,7 +2515,7 @@
   {
     assert(job != NULL);
     OrthancJob& that = *reinterpret_cast<OrthancJob*>(job);
-    
+
     if (that.hasSerialized_)
     {
       if (CopyStringToMemoryBuffer(target, that.serialized_) == OrthancPluginErrorCode_Success)
@@ -2622,7 +2631,7 @@
 
     if (content.type() != Json::objectValue)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_BadFileFormat);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_BadFileFormat);
     }
     else
     {
@@ -2642,7 +2651,7 @@
   {
     if (serialized.type() != Json::objectValue)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_BadFileFormat);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_BadFileFormat);
     }
     else
     {
@@ -2657,7 +2666,7 @@
     if (progress < 0 ||
         progress > 1)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
     }
 
     progress_ = progress;
@@ -2677,7 +2686,7 @@
   {
     if (job == NULL)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_NullPointer);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_NullPointer);
     }
 
     OrthancPluginJob* orthanc =
@@ -2692,7 +2701,7 @@
 
     if (orthanc == NULL)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_Plugin);
     }
     else
     {
@@ -2706,7 +2715,7 @@
   {
     if (job == NULL)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_NullPointer);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_NullPointer);
     }
 
     OrthancPluginJob* orthanc = Create(job);
@@ -2717,7 +2726,7 @@
     {
       ORTHANC_PLUGINS_LOG_ERROR("Plugin cannot submit job");
       OrthancPluginFreeJob(GetGlobalContext(), orthanc);
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_Plugin);
     }
     else
     {
@@ -2745,7 +2754,7 @@
           !status.isMember("State") ||
           status["State"].type() != Json::stringValue)
       {
-        ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_InexistentItem);        
+        ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_InexistentItem);
       }
 
       const std::string state = status["State"].asString();
@@ -2774,30 +2783,30 @@
         if (!status.isMember("ErrorCode") ||
             status["ErrorCode"].type() != Json::intValue)
         {
-          ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_InternalError);
+          ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_InternalError);
         }
         else
         {
           if (!status.isMember("ErrorDescription") ||
               status["ErrorDescription"].type() != Json::stringValue)
           {
-            ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(status["ErrorCode"].asInt());
+            ORTHANC_PLUGINS_THROW_ERROR_CODE(status["ErrorCode"].asInt());
           }
           else
           {
-  #if HAS_ORTHANC_EXCEPTION == 1
+#if HAS_ORTHANC_EXCEPTION == 1
             throw Orthanc::OrthancException(static_cast<Orthanc::ErrorCode>(status["ErrorCode"].asInt()),
                                             status["ErrorDescription"].asString());
-  #else
+#else
             ORTHANC_PLUGINS_LOG_ERROR("Exception while executing the job: " + status["ErrorDescription"].asString());
-            ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(status["ErrorCode"].asInt());          
-  #endif
+            ORTHANC_PLUGINS_THROW_ERROR_CODE(status["ErrorCode"].asInt());
+#endif
           }
         }
       }
       else
       {
-        ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_InternalError);
+        ORTHANC_PLUGINS_THROW_ERROR_CODE(OrthancPluginErrorCode_InternalError);
       }
     }
   }
@@ -2812,7 +2821,7 @@
     static const char* KEY_PRIORITY = "Priority";
 
     boost::movelib::unique_ptr<OrthancJob> protection(job);
-  
+
     if (body.type() != Json::objectValue)
     {
 #if HAS_ORTHANC_EXCEPTION == 1
@@ -2825,7 +2834,7 @@
     }
 
     bool synchronous = true;
-  
+
     if (body.isMember(KEY_SYNCHRONOUS))
     {
       if (body[KEY_SYNCHRONOUS].type() != Json::booleanValue)
@@ -2884,7 +2893,7 @@
         priority = !body[KEY_PRIORITY].asInt();
       }
     }
-  
+
     Json::Value result;
 
     if (synchronous)
@@ -2914,13 +2923,13 @@
    ** METRICS
    ******************************************************************/
 
-#if HAS_ORTHANC_PLUGIN_METRICS == 1
+#if HAS_ORTHANC_PLUGINS_METRICS == 1
   MetricsTimer::MetricsTimer(const char* name) :
     name_(name)
   {
     start_ = boost::posix_time::microsec_clock::universal_time();
   }
-  
+
   MetricsTimer::~MetricsTimer()
   {
     const boost::posix_time::ptime stop = boost::posix_time::microsec_clock::universal_time();
@@ -2937,7 +2946,7 @@
    ** HTTP CLIENT
    ******************************************************************/
 
-#if HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1
+#if HAS_ORTHANC_PLUGINS_HTTP_CLIENT == 1
   class HttpClient::RequestBodyWrapper : public boost::noncopyable
   {
   private:
@@ -2956,18 +2965,18 @@
       body_(body),
       done_(false)
     {
-    }      
+    }
 
     static uint8_t IsDone(void* body)
     {
       return GetObject(body).done_;
     }
-    
+
     static const void* GetChunkData(void* body)
     {
       return GetObject(body).chunk_.c_str();
     }
-    
+
     static uint32_t GetChunkSize(void* body)
     {
       return static_cast<uint32_t>(GetObject(body).chunk_.size());
@@ -2976,7 +2985,7 @@
     static OrthancPluginErrorCode Next(void* body)
     {
       RequestBodyWrapper& that = GetObject(body);
-        
+
       if (that.done_)
       {
         return OrthancPluginErrorCode_BadSequenceOfCalls;
@@ -2997,11 +3006,11 @@
           return OrthancPluginErrorCode_Plugin;
         }
       }
-    }    
+    }
   };
 
 
-#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1
+#if HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_CLIENT == 1
   static OrthancPluginErrorCode AnswerAddHeaderCallback(void* answer,
                                                         const char* key,
                                                         const char* value)
@@ -3025,7 +3034,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1
+#if HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_CLIENT == 1
   static OrthancPluginErrorCode AnswerAddChunkCallback(void* answer,
                                                        const void* data,
                                                        uint32_t size)
@@ -3069,7 +3078,7 @@
     }
   }
 
-  
+
   void HttpClient::SetCredentials(const std::string& username,
                                   const std::string& password)
   {
@@ -3077,7 +3086,7 @@
     password_ = password;
   }
 
-  
+
   void HttpClient::ClearCredentials()
   {
     username_.clear();
@@ -3094,7 +3103,7 @@
     certificateKeyPassword_ = keyPassword;
   }
 
-  
+
   void HttpClient::ClearCertificate()
   {
     certificateFile_.clear();
@@ -3109,21 +3118,21 @@
     chunkedBody_ = NULL;
   }
 
-  
+
   void HttpClient::SwapBody(std::string& body)
   {
     fullBody_.swap(body);
     chunkedBody_ = NULL;
   }
 
-  
+
   void HttpClient::SetBody(const std::string& body)
   {
     fullBody_ = body;
     chunkedBody_ = NULL;
   }
 
-  
+
   void HttpClient::SetBody(IRequestBody& body)
   {
     fullBody_.clear();
@@ -3289,7 +3298,7 @@
     };
 
 
-#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1
+#if HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_CLIENT == 1
     class MemoryAnswer : public HttpClient::IAnswer
     {
     private:
@@ -3323,7 +3332,7 @@
   }
 
 
-#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1
+#if HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_CLIENT == 1
   void HttpClient::ExecuteWithStream(uint16_t& httpStatus,
                                      IAnswer& answer,
                                      IRequestBody& body) const
@@ -3352,7 +3361,7 @@
     }
 
     RequestBodyWrapper request(body);
-        
+
     OrthancPluginErrorCode error = OrthancPluginChunkedHttpClient(
       GetGlobalContext(),
       &answer,
@@ -3379,10 +3388,10 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error);
-    }
-  }
-#endif    
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(error);
+    }
+  }
+#endif
 
   void HttpClient::ExecuteWithoutStream(uint16_t& httpStatus,
                                         HttpHeaders& answerHeaders,
@@ -3421,7 +3430,7 @@
 
     if (error != OrthancPluginErrorCode_Success)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(error);
     }
 
     DecodeHttpHeaders(answerHeaders, answerHeadersBuffer);
@@ -3431,7 +3440,7 @@
 
   void HttpClient::Execute(IAnswer& answer)
   {
-#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1
+#if HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_CLIENT == 1
     if (allowChunkedTransfers_)
     {
       if (chunkedBody_ != NULL)
@@ -3447,7 +3456,7 @@
       return;
     }
 #endif
-    
+
     // Compatibility mode for Orthanc SDK <= 1.5.6 or if chunked
     // transfers are disabled. This results in higher memory usage
     // (all chunks from the answer body are sent at once)
@@ -3456,10 +3465,10 @@
     std::string answerBody;
     Execute(answerHeaders, answerBody);
 
-    for (HttpHeaders::const_iterator it = answerHeaders.begin(); 
+    for (HttpHeaders::const_iterator it = answerHeaders.begin();
          it != answerHeaders.end(); ++it)
     {
-      answer.AddHeader(it->first, it->second);      
+      answer.AddHeader(it->first, it->second);
     }
 
     if (!answerBody.empty())
@@ -3472,7 +3481,7 @@
   void HttpClient::Execute(HttpHeaders& answerHeaders /* out */,
                            std::string& answerBody /* out */)
   {
-#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1
+#if HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_CLIENT == 1
     if (allowChunkedTransfers_)
     {
       MemoryAnswer answer;
@@ -3482,7 +3491,7 @@
       return;
     }
 #endif
-    
+
     // Compatibility mode for Orthanc SDK <= 1.5.6 or if chunked
     // transfers are disabled. This results in higher memory usage
     // (all chunks from the request body are sent at once)
@@ -3490,7 +3499,7 @@
     if (chunkedBody_ != NULL)
     {
       ChunkedBuffer buffer;
-      
+
       std::string chunk;
       while (chunkedBody_->ReadNextChunk(chunk))
       {
@@ -3514,7 +3523,7 @@
   {
     std::string body;
     Execute(answerHeaders, body);
-    
+
     if (!ReadJson(answerBody, body))
     {
       ORTHANC_PLUGINS_LOG_ERROR("Cannot convert HTTP answer body to JSON");
@@ -3530,7 +3539,7 @@
     Execute(answerHeaders, body);
   }
 
-#endif  /* HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1 */
+#endif  /* HAS_ORTHANC_PLUGINS_HTTP_CLIENT == 1 */
 
 
 
@@ -3547,7 +3556,7 @@
                           const OrthancPluginHttpRequest* request)
     {
     }
-  
+
     IChunkedRequestReader *NullChunkedRestCallback(const char* url,
                                                    const OrthancPluginHttpRequest* request)
     {
@@ -3555,7 +3564,7 @@
     }
 
 
-#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
+#if HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_SERVER == 1
 
     OrthancPluginErrorCode ChunkedRequestReaderAddChunk(
       OrthancPluginServerChunkedRequestReader* reader,
@@ -3586,7 +3595,7 @@
       }
     }
 
-    
+
     OrthancPluginErrorCode ChunkedRequestReaderExecute(
       OrthancPluginServerChunkedRequestReader* reader,
       OrthancPluginRestOutput*                 output)
@@ -3615,7 +3624,7 @@
       }
     }
 
-    
+
     void ChunkedRequestReaderFinalize(
       OrthancPluginServerChunkedRequestReader* reader)
     {
@@ -3626,7 +3635,7 @@
     }
 
 #else
-    
+
     OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output,
                                                     const char* url,
                                                     const OrthancPluginHttpRequest* request,
@@ -3650,7 +3659,7 @@
           {
             allowed += ",";
           }
-        
+
           allowed += "POST";
         }
 
@@ -3660,7 +3669,7 @@
           {
             allowed += ",";
           }
-        
+
           allowed += "DELETE";
         }
 
@@ -3670,10 +3679,10 @@
           {
             allowed += ",";
           }
-        
+
           allowed += "PUT";
         }
-      
+
         switch (request->method)
         {
           case OrthancPluginHttpMethod_Get:
@@ -3750,7 +3759,7 @@
       }
       catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
       {
-#if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS == 1
+#if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGINS_EXCEPTION_DETAILS == 1
         if (HasGlobalContext() &&
             e.HasDetails())
         {
@@ -3777,7 +3786,7 @@
   }
 
 
-#if HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP == 1
+#if HAS_ORTHANC_PLUGINS_STORAGE_COMMITMENT_SCP == 1
   OrthancPluginErrorCode IStorageCommitmentScpHandler::Lookup(
     OrthancPluginStorageCommitmentFailureReason* target,
     void* rawHandler,
@@ -3786,7 +3795,7 @@
   {
     assert(target != NULL &&
            rawHandler != NULL);
-      
+
     try
     {
       IStorageCommitmentScpHandler& handler = *reinterpret_cast<IStorageCommitmentScpHandler*>(rawHandler);
@@ -3805,7 +3814,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP == 1
+#if HAS_ORTHANC_PLUGINS_STORAGE_COMMITMENT_SCP == 1
   void IStorageCommitmentScpHandler::Destructor(void* rawHandler)
   {
     assert(rawHandler != NULL);
@@ -3814,7 +3823,7 @@
 #endif
 
 
-#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)    
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
   DicomInstance::DicomInstance(const OrthancPluginDicomInstance* instance) :
     toFree_(false),
     instance_(instance)
@@ -3855,7 +3864,7 @@
 #endif
   }
 
-  
+
   std::string DicomInstance::GetRemoteAet() const
   {
     const char* s = OrthancPluginGetInstanceRemoteAet(GetGlobalContext(), instance_);
@@ -3876,7 +3885,7 @@
     s.Assign(OrthancPluginGetInstanceJson(GetGlobalContext(), instance_));
     s.ToJson(target);
   }
-  
+
 
   void DicomInstance::GetSimplifiedJson(Json::Value& target) const
   {
@@ -3898,7 +3907,7 @@
   }
 #endif
 
-  
+
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
   bool DicomInstance::HasPixelData() const
   {
@@ -3915,7 +3924,7 @@
 #endif
 
 
-#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)  
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
   void DicomInstance::GetRawFrame(std::string& target,
                                   unsigned int frameIndex) const
   {
@@ -3929,13 +3938,13 @@
     }
     else
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
   }
 #endif
 
 
-#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)  
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
   OrthancImage* DicomInstance::GetDecodedFrame(unsigned int frameIndex) const
   {
     OrthancPluginImage* image = OrthancPluginGetInstanceDecodedFrame(
@@ -3950,7 +3959,7 @@
       return new OrthancImage(image);
     }
   }
-#endif  
+#endif
 
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
@@ -3966,11 +3975,11 @@
     }
     else
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
   }
 #endif
-  
+
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
   DicomInstance* DicomInstance::Transcode(const void* buffer,
@@ -4015,7 +4024,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_WEBDAV == 1
+#if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   static std::vector<std::string> WebDavConvertPath(uint32_t pathSize,
                                                     const char* const*  pathItems)
   {
@@ -4029,9 +4038,9 @@
     return result;
   }
 #endif
-  
-    
-#if HAS_ORTHANC_PLUGIN_WEBDAV == 1
+
+
+#if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   static OrthancPluginErrorCode WebDavIsExistingFolder(uint8_t*            isExisting,
                                                        uint32_t            pathSize,
                                                        const char* const*  pathItems,
@@ -4055,8 +4064,8 @@
   }
 #endif
 
-  
-#if HAS_ORTHANC_PLUGIN_WEBDAV == 1
+
+#if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   static OrthancPluginErrorCode WebDavListFolder(uint8_t*                        isExisting,
                                                  OrthancPluginWebDavCollection*  collection,
                                                  OrthancPluginWebDavAddFile      addFile,
@@ -4066,12 +4075,12 @@
                                                  void*                           payload)
   {
     IWebDavCollection& that = *reinterpret_cast<IWebDavCollection*>(payload);
-      
+
     try
     {
       std::list<IWebDavCollection::FileInfo> files;
       std::list<IWebDavCollection::FolderInfo> subfolders;
-      
+
       if (!that.ListFolder(files, subfolders, WebDavConvertPath(pathSize, pathItems)))
       {
         *isExisting = 0;
@@ -4079,33 +4088,33 @@
       else
       {
         *isExisting = 1;
-      
+
         for (std::list<IWebDavCollection::FileInfo>::const_iterator
                it = files.begin(); it != files.end(); ++it)
         {
           OrthancPluginErrorCode code = addFile(
             collection, it->GetName().c_str(), it->GetContentSize(),
             it->GetMimeType().c_str(), it->GetDateTime().c_str());
-        
+
           if (code != OrthancPluginErrorCode_Success)
           {
             return code;
           }
         }
-      
+
         for (std::list<IWebDavCollection::FolderInfo>::const_iterator it =
                subfolders.begin(); it != subfolders.end(); ++it)
         {
           OrthancPluginErrorCode code = addFolder(
             collection, it->GetName().c_str(), it->GetDateTime().c_str());
-        
+
           if (code != OrthancPluginErrorCode_Success)
           {
             return code;
           }
         }
       }
-      
+
       return OrthancPluginErrorCode_Success;
     }
     catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
@@ -4117,10 +4126,10 @@
       return OrthancPluginErrorCode_Plugin;
     }
   }
-#endif    
-
-
-#if HAS_ORTHANC_PLUGIN_WEBDAV == 1
+#endif
+
+
+#if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   static OrthancPluginErrorCode WebDavRetrieveFile(OrthancPluginWebDavCollection*   collection,
                                                    OrthancPluginWebDavRetrieveFile  retrieveFile,
                                                    uint32_t                         pathSize,
@@ -4132,7 +4141,7 @@
     try
     {
       std::string content, mime, dateTime;
-        
+
       if (that.GetFile(content, mime, dateTime, WebDavConvertPath(pathSize, pathItems)))
       {
         return retrieveFile(collection, content.empty() ? NULL : content.c_str(),
@@ -4152,11 +4161,11 @@
     {
       return OrthancPluginErrorCode_InternalError;
     }
-  }  
+  }
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_WEBDAV == 1
+#if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   static OrthancPluginErrorCode WebDavStoreFileCallback(uint8_t*            isReadOnly, /* out */
                                                         uint32_t            pathSize,
                                                         const char* const*  pathItems,
@@ -4172,7 +4181,7 @@
       {
         ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory);
       }
-      
+
       *isReadOnly = (that.StoreFile(WebDavConvertPath(pathSize, pathItems), data,
                                     static_cast<size_t>(size)) ? 1 : 0);
       return OrthancPluginErrorCode_Success;
@@ -4188,8 +4197,8 @@
   }
 #endif
 
-  
-#if HAS_ORTHANC_PLUGIN_WEBDAV == 1
+
+#if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   static OrthancPluginErrorCode WebDavCreateFolderCallback(uint8_t*            isReadOnly, /* out */
                                                            uint32_t            pathSize,
                                                            const char* const*  pathItems,
@@ -4212,9 +4221,9 @@
     }
   }
 #endif
-  
-  
-#if HAS_ORTHANC_PLUGIN_WEBDAV == 1
+
+
+#if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   static OrthancPluginErrorCode WebDavDeleteItemCallback(uint8_t*            isReadOnly, /* out */
                                                          uint32_t            pathSize,
                                                          const char* const*  pathItems,
@@ -4238,8 +4247,8 @@
   }
 #endif
 
-  
-#if HAS_ORTHANC_PLUGIN_WEBDAV == 1
+
+#if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   void IWebDavCollection::Register(const std::string& uri,
                                    IWebDavCollection& collection)
   {
@@ -4249,7 +4258,7 @@
 
     if (code != OrthancPluginErrorCode_Success)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
   }
 #endif
@@ -4261,7 +4270,7 @@
     for (uint32_t i = 0; i < request->getCount; ++i)
     {
       result[request->getKeys[i]] = request->getValues[i];
-    }    
+    }
   }
 
   void GetHttpHeaders(HttpHeaders& result, const OrthancPluginHttpRequest* request)
@@ -4271,7 +4280,7 @@
     for (uint32_t i = 0; i < request->headersCount; ++i)
     {
       result[request->headersKeys[i]] = request->headersValues[i];
-    }    
+    }
   }
 
   void SerializeGetArguments(std::string& output, const OrthancPluginHttpRequest* request)
@@ -4339,7 +4348,7 @@
   }
 
 
-#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+#if HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1
   RestApiClient::RestApiClient() :
     method_(OrthancPluginHttpMethod_Get),
     path_("/"),
@@ -4373,7 +4382,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+#if HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1
   void RestApiClient::AddRequestHeader(const std::string& key,
                                        const std::string& value)
   {
@@ -4389,7 +4398,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+#if HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1
   void RestApiClient::SetRequestHeader(const std::string& key,
                                        const std::string& value)
   {
@@ -4398,7 +4407,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+#if HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1
   bool RestApiClient::Execute()
   {
     if (requestBody_.size() > 0xffffffffu)
@@ -4440,7 +4449,7 @@
       }
       else
       {
-        ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+        ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
       }
     }
   }
@@ -4465,7 +4474,7 @@
           mimeType = h->second.c_str();
         }
       }
-      
+
       AnswerString(answerBody_, mimeType, output);
     }
     else
@@ -4481,7 +4490,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+#if HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1
   uint16_t RestApiClient::GetHttpStatus() const
   {
     if (httpStatus_ == 0)
@@ -4496,7 +4505,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+#if HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1
   bool RestApiClient::LookupAnswerHeader(std::string& value,
                                          const std::string& key) const
   {
@@ -4521,7 +4530,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+#if HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1
   const std::string& RestApiClient::GetAnswerBody() const
   {
     if (httpStatus_ == 0)
@@ -4536,7 +4545,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+#if HAS_ORTHANC_PLUGINS_KEY_VALUE_STORES == 1
   KeyValueStore::Iterator::Iterator(OrthancPluginKeysValuesIterator  *iterator) :
     iterator_(iterator)
   {
@@ -4548,7 +4557,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+#if HAS_ORTHANC_PLUGINS_KEY_VALUE_STORES == 1
   KeyValueStore::Iterator::~Iterator()
   {
     OrthancPluginFreeKeysValuesIterator(OrthancPlugins::GetGlobalContext(), iterator_);
@@ -4556,7 +4565,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+#if HAS_ORTHANC_PLUGINS_KEY_VALUE_STORES == 1
   bool KeyValueStore::Iterator::Next()
   {
     uint8_t done;
@@ -4564,7 +4573,7 @@
 
     if (code != OrthancPluginErrorCode_Success)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
     else
     {
@@ -4574,7 +4583,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+#if HAS_ORTHANC_PLUGINS_KEY_VALUE_STORES == 1
   std::string KeyValueStore::Iterator::GetKey() const
   {
     const char* s = OrthancPluginKeysValuesIteratorGetKey(OrthancPlugins::GetGlobalContext(), iterator_);
@@ -4590,7 +4599,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+#if HAS_ORTHANC_PLUGINS_KEY_VALUE_STORES == 1
   void KeyValueStore::Iterator::GetValue(std::string& value) const
   {
     OrthancPlugins::MemoryBuffer valueBuffer;
@@ -4598,7 +4607,7 @@
 
     if (code != OrthancPluginErrorCode_Success)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
     else
     {
@@ -4608,7 +4617,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+#if HAS_ORTHANC_PLUGINS_KEY_VALUE_STORES == 1
   void KeyValueStore::Store(const std::string& key,
                             const void* value,
                             size_t valueSize)
@@ -4622,13 +4631,13 @@
                                                              key.c_str(), value, static_cast<uint32_t>(valueSize));
     if (code != OrthancPluginErrorCode_Success)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
   }
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+#if HAS_ORTHANC_PLUGINS_KEY_VALUE_STORES == 1
   bool KeyValueStore::GetValue(std::string& value,
                                const std::string& key)
   {
@@ -4639,7 +4648,7 @@
 
     if (code != OrthancPluginErrorCode_Success)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
     else if (found)
     {
@@ -4654,7 +4663,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+#if HAS_ORTHANC_PLUGINS_KEY_VALUE_STORES == 1
   void KeyValueStore::DeleteKey(const std::string& key)
   {
     OrthancPluginErrorCode code = OrthancPluginDeleteKeyValue(OrthancPlugins::GetGlobalContext(),
@@ -4662,13 +4671,13 @@
 
     if (code != OrthancPluginErrorCode_Success)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
   }
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+#if HAS_ORTHANC_PLUGINS_KEY_VALUE_STORES == 1
   KeyValueStore::Iterator* KeyValueStore::CreateIterator()
   {
     return new Iterator(OrthancPluginCreateKeysValuesIterator(OrthancPlugins::GetGlobalContext(), storeId_.c_str()));
@@ -4676,7 +4685,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_QUEUES == 1
+#if HAS_ORTHANC_PLUGINS_QUEUES == 1
   void Queue::Enqueue(const void* value,
                       size_t valueSize)
   {
@@ -4690,13 +4699,13 @@
 
     if (code != OrthancPluginErrorCode_Success)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
   }
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_QUEUES == 1
+#if HAS_ORTHANC_PLUGINS_QUEUES == 1
   bool Queue::DequeueInternal(std::string& value,
                               OrthancPluginQueueOrigin origin)
   {
@@ -4711,7 +4720,7 @@
 
     if (code != OrthancPluginErrorCode_Success)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
     else if (found)
     {
@@ -4726,7 +4735,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_QUEUES == 1
+#if HAS_ORTHANC_PLUGINS_QUEUES == 1
   uint64_t Queue::GetSize()
   {
     uint64_t size = 0;
@@ -4734,7 +4743,7 @@
 
     if (code != OrthancPluginErrorCode_Success)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
     else
     {
@@ -4744,7 +4753,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_RESERVE_QUEUE_VALUE == 1
+#if HAS_ORTHANC_PLUGINS_RESERVE_QUEUE_VALUE == 1
   bool Queue::ReserveInternal(std::string& value, uint64_t& valueId, OrthancPluginQueueOrigin origin, uint32_t releaseTimeout)
   {
     uint8_t found = false;
@@ -4755,7 +4764,7 @@
 
     if (code != OrthancPluginErrorCode_Success)
     {
-      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+      ORTHANC_PLUGINS_THROW_ERROR_CODE(code);
     }
     else if (found)
     {
@@ -4770,7 +4779,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_RESERVE_QUEUE_VALUE == 1
+#if HAS_ORTHANC_PLUGINS_RESERVE_QUEUE_VALUE == 1
   bool Queue::ReserveBack(std::string& value, uint64_t& valueId, uint32_t releaseTimeout)
   {
     return ReserveInternal(value, valueId, OrthancPluginQueueOrigin_Back, releaseTimeout);
@@ -4778,7 +4787,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_RESERVE_QUEUE_VALUE == 1
+#if HAS_ORTHANC_PLUGINS_RESERVE_QUEUE_VALUE == 1
   bool Queue::ReserveFront(std::string& value, uint64_t& valueId, uint32_t releaseTimeout)
   {
     return ReserveInternal(value, valueId, OrthancPluginQueueOrigin_Front, releaseTimeout);
@@ -4786,7 +4795,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_RESERVE_QUEUE_VALUE == 1
+#if HAS_ORTHANC_PLUGINS_RESERVE_QUEUE_VALUE == 1
   void Queue::Acknowledge(uint64_t valueId)
   {
     OrthancPluginAcknowledgeQueueValue(OrthancPlugins::GetGlobalContext(), queueId_.c_str(), valueId);
--- a/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h	Thu Aug 20 17:36:31 2026 +0200
@@ -10,7 +10,7 @@
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation, either version 3 of the
  * License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -27,7 +27,6 @@
 
 #include <orthanc/OrthancCPlugin.h>
 #include <boost/noncopyable.hpp>
-#include <boost/lexical_cast.hpp>
 #include <boost/thread/mutex.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <json/value.h>
@@ -41,7 +40,7 @@
 /**
  * The definition of ORTHANC_PLUGINS_VERSION_IS_ABOVE below is for
  * backward compatibility with Orthanc SDK <= 1.3.0.
- * 
+ *
  *   $ hg diff -r Orthanc-1.3.0:Orthanc-1.3.1 ../../../Plugins/Include/orthanc/OrthancCPlugin.h
  *
  **/
@@ -67,98 +66,98 @@
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 2, 0)
 // The "OrthancPluginFindMatcher()" primitive was introduced in Orthanc 1.2.0
-#  define HAS_ORTHANC_PLUGIN_FIND_MATCHER  1
+#  define HAS_ORTHANC_PLUGINS_FIND_MATCHER  1
 #else
-#  define HAS_ORTHANC_PLUGIN_FIND_MATCHER  0
+#  define HAS_ORTHANC_PLUGINS_FIND_MATCHER  0
 #endif
 
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 4, 2)
-#  define HAS_ORTHANC_PLUGIN_PEERS  1
-#  define HAS_ORTHANC_PLUGIN_JOB    1
+#  define HAS_ORTHANC_PLUGINS_PEERS  1
+#  define HAS_ORTHANC_PLUGINS_JOB    1
 #else
-#  define HAS_ORTHANC_PLUGIN_PEERS  0
-#  define HAS_ORTHANC_PLUGIN_JOB    0
+#  define HAS_ORTHANC_PLUGINS_PEERS  0
+#  define HAS_ORTHANC_PLUGINS_JOB    0
 #endif
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0)
-#  define HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS  1
+#  define HAS_ORTHANC_PLUGINS_EXCEPTION_DETAILS  1
 #else
-#  define HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS  0
+#  define HAS_ORTHANC_PLUGINS_EXCEPTION_DETAILS  0
 #endif
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
-#  define HAS_ORTHANC_PLUGIN_METRICS  1
+#  define HAS_ORTHANC_PLUGINS_METRICS  1
 #else
-#  define HAS_ORTHANC_PLUGIN_METRICS  0
+#  define HAS_ORTHANC_PLUGINS_METRICS  0
 #endif
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 1, 0)
-#  define HAS_ORTHANC_PLUGIN_HTTP_CLIENT  1
+#  define HAS_ORTHANC_PLUGINS_HTTP_CLIENT  1
 #else
-#  define HAS_ORTHANC_PLUGIN_HTTP_CLIENT  0
+#  define HAS_ORTHANC_PLUGINS_HTTP_CLIENT  0
 #endif
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7)
-#  define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT  1
+#  define HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_CLIENT  1
 #else
-#  define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT  0
+#  define HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_CLIENT  0
 #endif
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7)
-#  define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER  1
+#  define HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_SERVER  1
 #else
-#  define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER  0
+#  define HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_SERVER  0
 #endif
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 0)
-#  define HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP  1
+#  define HAS_ORTHANC_PLUGINS_STORAGE_COMMITMENT_SCP  1
 #else
-#  define HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP  0
+#  define HAS_ORTHANC_PLUGINS_STORAGE_COMMITMENT_SCP  0
 #endif
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 9, 2)
-#  define HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API  1
+#  define HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API  1
 #else
-#  define HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API  0
+#  define HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API  0
 #endif
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 10, 1)
-#  define HAS_ORTHANC_PLUGIN_WEBDAV  1
+#  define HAS_ORTHANC_PLUGINS_WEBDAV  1
 #else
-#  define HAS_ORTHANC_PLUGIN_WEBDAV  0
+#  define HAS_ORTHANC_PLUGINS_WEBDAV  0
 #endif
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 4)
-#  define HAS_ORTHANC_PLUGIN_LOG_MESSAGE  1
+#  define HAS_ORTHANC_PLUGINS_LOG_MESSAGE  1
 #else
-#  define HAS_ORTHANC_PLUGIN_LOG_MESSAGE  0
+#  define HAS_ORTHANC_PLUGINS_LOG_MESSAGE  0
 #endif
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 8)
-#  define HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES  1
-#  define HAS_ORTHANC_PLUGIN_QUEUES            1
+#  define HAS_ORTHANC_PLUGINS_KEY_VALUE_STORES  1
+#  define HAS_ORTHANC_PLUGINS_QUEUES            1
 #else
-#  define HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES  0
-#  define HAS_ORTHANC_PLUGIN_QUEUES            0
+#  define HAS_ORTHANC_PLUGINS_KEY_VALUE_STORES  0
+#  define HAS_ORTHANC_PLUGINS_QUEUES            0
 #endif
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 10)
-#  define HAS_ORTHANC_PLUGIN_RESERVE_QUEUE_VALUE   1
+#  define HAS_ORTHANC_PLUGINS_RESERVE_QUEUE_VALUE   1
 #else
-#  define HAS_ORTHANC_PLUGIN_RESERVE_QUEUE_VALUE   0
+#  define HAS_ORTHANC_PLUGINS_RESERVE_QUEUE_VALUE   0
 #endif
 
 
 // Macro to tag a function as having been deprecated
 #if (__cplusplus >= 201402L)  // C++14
-#  define ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(f) [[deprecated]] f
+#  define ORTHANC_PLUGINS_CPP_WRAPPER_DEPRECATED(f) [[deprecated]] f
 #elif defined(__GNUC__) || defined(__clang__)
-#  define ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(f) f __attribute__((deprecated))
+#  define ORTHANC_PLUGINS_CPP_WRAPPER_DEPRECATED(f) f __attribute__((deprecated))
 #elif defined(_MSC_VER)
-#  define ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(f) __declspec(deprecated) f
+#  define ORTHANC_PLUGINS_CPP_WRAPPER_DEPRECATED(f) __declspec(deprecated) f
 #else
-#  define ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED
+#  define ORTHANC_PLUGINS_CPP_WRAPPER_DEPRECATED
 #endif
 
 
@@ -172,7 +171,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
+#if HAS_ORTHANC_PLUGINS_LOG_MESSAGE == 1
 #  define ORTHANC_PLUGINS_LOG_ERROR(msg)   ::OrthancPlugins::LogMessage(OrthancPluginLogLevel_Error, __ORTHANC_FILE__, __LINE__, msg)
 #  define ORTHANC_PLUGINS_LOG_WARNING(msg) ::OrthancPlugins::LogMessage(OrthancPluginLogLevel_Warning, __ORTHANC_FILE__, __LINE__, msg)
 #  define ORTHANC_PLUGINS_LOG_INFO(msg)    ::OrthancPlugins::LogMessage(OrthancPluginLogLevel_Info, __ORTHANC_FILE__, __LINE__, msg)
@@ -204,7 +203,7 @@
 
   OrthancPluginContext* GetGlobalContext();
 
-  
+
   class OrthancImage;
 
 
@@ -297,7 +296,7 @@
                      const Json::Value& body,
                      bool applyPlugins);
 
-#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+#if HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1
     bool RestApiPost(const std::string& uri,
                      const Json::Value& body,
                      const HttpHeaders& httpHeaders,
@@ -394,9 +393,9 @@
     void ToString(std::string& target) const;
 
     void ToJson(Json::Value& target) const;
-  
+
     void ToJsonWithoutComments(Json::Value& target) const;
-};
+  };
 
 
   class OrthancConfiguration : public boost::noncopyable
@@ -408,7 +407,7 @@
     std::string GetPath(const std::string& key) const;
 
     void LoadConfiguration();
-    
+
   public:
     OrthancConfiguration(); // loads the full Orthanc configuration
 
@@ -428,7 +427,7 @@
 
     bool LookupStringValue(std::string& target,
                            const std::string& key) const;
-    
+
     bool LookupIntegerValue(int& target,
                             const std::string& key) const;
 
@@ -511,7 +510,7 @@
     unsigned int GetHeight() const;
 
     unsigned int GetPitch() const;
-    
+
     void* GetBuffer() const;
 
     const OrthancPluginImage* GetObject() const
@@ -528,14 +527,14 @@
 
     void AnswerJpegImage(OrthancPluginRestOutput* output,
                          uint8_t quality) const;
-    
+
     void* GetWriteableBuffer();
 
     OrthancPluginImage* Release();
   };
 
 
-#if HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1
+#if HAS_ORTHANC_PLUGINS_FIND_MATCHER == 1
   class FindMatcher : public boost::noncopyable
   {
   private:
@@ -574,13 +573,13 @@
 
   bool ReadJson(Json::Value& target,
                 const std::string& source);
-  
+
   bool ReadJson(Json::Value& target,
                 const void* buffer,
                 size_t size);
 
   bool ReadJsonWithoutComments(Json::Value& target,
-                               const std::string& source);  
+                               const std::string& source);
 
   bool ReadJsonWithoutComments(Json::Value& target,
                                const void* buffer,
@@ -622,7 +621,7 @@
                    size_t bodySize,
                    bool applyPlugins);
 
-#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+#if HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1
   bool RestApiPost(Json::Value& result,
                    const std::string& uri,
                    const Json::Value& body,
@@ -701,30 +700,30 @@
   const char* AutodetectMimeType(const std::string& path);
 #endif
 
-#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
+#if HAS_ORTHANC_PLUGINS_LOG_MESSAGE == 1
   void LogMessage(OrthancPluginLogLevel level,
                   const char* file,
                   uint32_t line,
                   const std::string& message);
 #endif
 
-#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
+#if HAS_ORTHANC_PLUGINS_LOG_MESSAGE == 1
   // Use macro ORTHANC_PLUGINS_LOG_ERROR() instead
-  ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(void LogError(const std::string& message));
+  ORTHANC_PLUGINS_CPP_WRAPPER_DEPRECATED(void LogError(const std::string& message));
 #else
   void LogError(const std::string& message);
 #endif
 
-#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
+#if HAS_ORTHANC_PLUGINS_LOG_MESSAGE == 1
   // Use macro ORTHANC_PLUGINS_LOG_WARNING() instead
-  ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(void LogWarning(const std::string& message));
+  ORTHANC_PLUGINS_CPP_WRAPPER_DEPRECATED(void LogWarning(const std::string& message));
 #else
   void LogWarning(const std::string& message);
 #endif
 
-#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
+#if HAS_ORTHANC_PLUGINS_LOG_MESSAGE == 1
   // Use macro ORTHANC_PLUGINS_LOG_INFO() instead
-  ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(void LogInfo(const std::string& message));
+  ORTHANC_PLUGINS_CPP_WRAPPER_DEPRECATED(void LogInfo(const std::string& message));
 #else
   void LogInfo(const std::string& message);
 #endif
@@ -732,7 +731,7 @@
   void ReportMinimalOrthancVersion(unsigned int major,
                                    unsigned int minor,
                                    unsigned int revision);
-  
+
   bool CheckMinimalOrthancVersion(unsigned int major,
                                   unsigned int minor,
                                   unsigned int revision);
@@ -756,7 +755,7 @@
       }
       catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
       {
-#if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS == 1
+#if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGINS_EXCEPTION_DETAILS == 1
         if (HasGlobalContext() &&
             e.HasDetails())
         {
@@ -781,7 +780,7 @@
     }
   }
 
-  
+
   template <RestCallback Callback>
   void RegisterRestCallback(const std::string& uri,
                             bool isThreadSafe)
@@ -799,7 +798,7 @@
   }
 
 
-#if HAS_ORTHANC_PLUGIN_PEERS == 1
+#if HAS_ORTHANC_PLUGINS_PEERS == 1
   class OrthancPeers : public boost::noncopyable
   {
   private:
@@ -907,7 +906,7 @@
                 const std::string& body,
                 const HttpHeaders& headers,
                 unsigned int timeout) const;
-    
+
     bool DoPost(Json::Value& target,
                 HttpHeaders& answerHeaders,
                 size_t index,
@@ -944,7 +943,7 @@
 
 
 
-#if HAS_ORTHANC_PLUGIN_JOB == 1
+#if HAS_ORTHANC_PLUGINS_JOB == 1
   class OrthancJob : public boost::noncopyable
   {
   private:
@@ -990,10 +989,10 @@
     void UpdateSerialized(const Json::Value& serialized);
 
     void UpdateProgress(float progress);
-    
+
   public:
     explicit OrthancJob(const std::string& jobType);
-    
+
     virtual ~OrthancJob()
     {
     }
@@ -1001,7 +1000,7 @@
     virtual OrthancPluginJobStepStatus Step() = 0;
 
     virtual void Stop(OrthancPluginJobStopReason reason) = 0;
-    
+
     virtual void Reset() = 0;
 
     static OrthancPluginJob* Create(OrthancJob* job /* takes ownership */);
@@ -1023,7 +1022,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_METRICS == 1
+#if HAS_ORTHANC_PLUGINS_METRICS == 1
   inline void SetMetricsValue(const char* name,
                               float value)
   {
@@ -1043,7 +1042,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_METRICS == 1
+#if HAS_ORTHANC_PLUGINS_METRICS == 1
   class MetricsTimer : public boost::noncopyable
   {
   private:
@@ -1058,7 +1057,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1
+#if HAS_ORTHANC_PLUGINS_HTTP_CLIENT == 1
   class HttpClient : public boost::noncopyable
   {
   public:
@@ -1106,7 +1105,7 @@
     IRequestBody*            chunkedBody_;
     bool                     allowChunkedTransfers_;
 
-#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1
+#if HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_CLIENT == 1
     void ExecuteWithStream(uint16_t& httpStatus,  // out
                            IAnswer& answer,       // out
                            IRequestBody& body) const;
@@ -1116,7 +1115,7 @@
                               HttpHeaders& answerHeaders,  // out
                               std::string& answerBody,     // out
                               const std::string& body) const;
-    
+
   public:
     HttpClient();
 
@@ -1231,16 +1230,16 @@
     void NullRestCallback(OrthancPluginRestOutput* output,
                           const char* url,
                           const OrthancPluginHttpRequest* request);
-  
+
     IChunkedRequestReader *NullChunkedRestCallback(const char* url,
                                                    const OrthancPluginHttpRequest* request);
 
 
-#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
+#if HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_SERVER == 1
     template <ChunkedRestCallback Callback>
     static OrthancPluginErrorCode ChunkedProtect(OrthancPluginServerChunkedRequestReader** reader,
-                                                const char* url,
-                                                const OrthancPluginHttpRequest* request)
+                                                 const char* url,
+                                                 const OrthancPluginHttpRequest* request)
     {
       try
       {
@@ -1287,7 +1286,7 @@
     void ChunkedRequestReaderFinalize(
       OrthancPluginServerChunkedRequestReader* reader);
 
-#else  
+#else
 
     OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output,
                                                     const char* url,
@@ -1328,7 +1327,7 @@
   public:
     static void Apply(const std::string& uri)
     {
-#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
+#if HAS_ORTHANC_PLUGINS_CHUNKED_HTTP_SERVER == 1
       OrthancPluginRegisterChunkedRestCallback(
         GetGlobalContext(), uri.c_str(),
         GetHandler == Internals::NullRestCallback         ? NULL : Internals::Protect<GetHandler>,
@@ -1340,25 +1339,25 @@
         Internals::ChunkedRequestReaderFinalize);
 #else
       OrthancPluginRegisterRestCallbackNoLock(
-        GetGlobalContext(), uri.c_str(), 
+        GetGlobalContext(), uri.c_str(),
         Internals::ChunkedRestCompatibility<GetHandler, PostHandler, DeleteHandler, PutHandler>);
 #endif
     }
   };
 
-  
+
 
-#if HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP == 1
+#if HAS_ORTHANC_PLUGINS_STORAGE_COMMITMENT_SCP == 1
   class IStorageCommitmentScpHandler : public boost::noncopyable
   {
   public:
     virtual ~IStorageCommitmentScpHandler()
     {
     }
-    
+
     virtual OrthancPluginStorageCommitmentFailureReason Lookup(const std::string& sopClassUid,
                                                                const std::string& sopInstanceUid) = 0;
-    
+
     static OrthancPluginErrorCode Lookup(OrthancPluginStorageCommitmentFailureReason* target,
                                          void* rawHandler,
                                          const char* sopClassUid,
@@ -1374,14 +1373,14 @@
   private:
     bool toFree_;
 
-#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)    
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
     const OrthancPluginDicomInstance*  instance_;
 #else
     OrthancPluginDicomInstance*  instance_;
 #endif
-    
+
   public:
-#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)    
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
     explicit DicomInstance(const OrthancPluginDicomInstance* instance);
 #else
     explicit DicomInstance(OrthancPluginDicomInstance* instance);
@@ -1461,15 +1460,15 @@
   };
 
 // helper method to convert Http headers from the plugin SDK to a std::map
-void GetHttpHeaders(HttpHeaders& result, const OrthancPluginHttpRequest* request);
+  void GetHttpHeaders(HttpHeaders& result, const OrthancPluginHttpRequest* request);
 
 // helper method to re-serialize the get arguments from the SDK into a string
-void SerializeGetArguments(std::string& output, const OrthancPluginHttpRequest* request);
+  void SerializeGetArguments(std::string& output, const OrthancPluginHttpRequest* request);
 
 // helper method to convert Get arguments from the plugin SDK to a std::map
-void GetGetArguments(GetArguments& result, const OrthancPluginHttpRequest* request);
+  void GetGetArguments(GetArguments& result, const OrthancPluginHttpRequest* request);
 
-#if HAS_ORTHANC_PLUGIN_WEBDAV == 1
+#if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   class IWebDavCollection : public boost::noncopyable
   {
   public:
@@ -1516,7 +1515,7 @@
         return dateTime_;
       }
     };
-  
+
     class FolderInfo
     {
     private:
@@ -1541,7 +1540,7 @@
         return dateTime_;
       }
     };
-  
+
     virtual ~IWebDavCollection()
     {
     }
@@ -1551,7 +1550,7 @@
     virtual bool ListFolder(std::list<FileInfo>& files,
                             std::list<FolderInfo>& subfolders,
                             const std::vector<std::string>& path) = 0;
-  
+
     virtual bool GetFile(std::string& content /* out */,
                          std::string& mime /* out */,
                          std::string& dateTime /* out */,
@@ -1580,7 +1579,7 @@
                              const std::string& javascript);
 
 
-#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+#if HAS_ORTHANC_PLUGINS_GENERIC_CALL_REST_API == 1
   class RestApiClient : public boost::noncopyable
   {
   private:
@@ -1598,7 +1597,7 @@
 
   public:
     RestApiClient();
-    
+
     // used to forward a call from the plugin to the core
     RestApiClient(const char* url,
                   const OrthancPluginHttpRequest* request);
@@ -1680,7 +1679,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+#if HAS_ORTHANC_PLUGINS_KEY_VALUE_STORES == 1
   class KeyValueStore : public boost::noncopyable
   {
   public:
@@ -1735,7 +1734,7 @@
 #endif
 
 
-#if HAS_ORTHANC_PLUGIN_QUEUES == 1
+#if HAS_ORTHANC_PLUGINS_QUEUES == 1
   class Queue : public boost::noncopyable
   {
   private:
@@ -1743,7 +1742,7 @@
 
     bool DequeueInternal(std::string& value, OrthancPluginQueueOrigin origin);
 
-#if HAS_ORTHANC_PLUGIN_RESERVE_QUEUE_VALUE == 1
+#if HAS_ORTHANC_PLUGINS_RESERVE_QUEUE_VALUE == 1
     bool ReserveInternal(std::string& value, uint64_t& valueId, OrthancPluginQueueOrigin origin, uint32_t releaseTimeout);
 #endif
 
@@ -1766,7 +1765,7 @@
       Enqueue(value.empty() ? NULL : value.c_str(), value.size());
     }
 
-#if HAS_ORTHANC_PLUGIN_RESERVE_QUEUE_VALUE == 1
+#if HAS_ORTHANC_PLUGINS_RESERVE_QUEUE_VALUE == 1
     // Use ReserveBack() instead
     ORTHANC_PLUGIN_DEPRECATED
 #endif
@@ -1775,7 +1774,7 @@
       return DequeueInternal(value, OrthancPluginQueueOrigin_Back);
     }
 
-#if HAS_ORTHANC_PLUGIN_RESERVE_QUEUE_VALUE == 1
+#if HAS_ORTHANC_PLUGINS_RESERVE_QUEUE_VALUE == 1
     // Use ReserveFront() instead
     ORTHANC_PLUGIN_DEPRECATED
 #endif
@@ -1786,15 +1785,15 @@
 
     uint64_t GetSize();
 
-#if HAS_ORTHANC_PLUGIN_RESERVE_QUEUE_VALUE == 1
+#if HAS_ORTHANC_PLUGINS_RESERVE_QUEUE_VALUE == 1
     bool ReserveBack(std::string& value, uint64_t& valueId, uint32_t releaseTimeout);
 #endif
 
-#if HAS_ORTHANC_PLUGIN_RESERVE_QUEUE_VALUE == 1
+#if HAS_ORTHANC_PLUGINS_RESERVE_QUEUE_VALUE == 1
     bool ReserveFront(std::string& value, uint64_t& valueId, uint32_t releaseTimeout);
 #endif
 
-#if HAS_ORTHANC_PLUGIN_RESERVE_QUEUE_VALUE == 1
+#if HAS_ORTHANC_PLUGINS_RESERVE_QUEUE_VALUE == 1
     void Acknowledge(uint64_t valueId);
 #endif
   };
--- a/Resources/Orthanc/Plugins/OrthancPluginException.h	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/Plugins/OrthancPluginException.h	Thu Aug 20 17:36:31 2026 +0200
@@ -10,7 +10,7 @@
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation, either version 3 of the
  * License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -41,13 +41,45 @@
 #endif
 
 
-#define ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code)                   \
+#if HAS_ORTHANC_EXCEPTION == 1 && defined(__ORTHANC_FILE__)   // the OrthancException class accepts a "details" argument -> add the file and line number
+
+#  include <boost/lexical_cast.hpp>
+
+#  define ORTHANC_PLUGINS_EXCEPTION_STRINGIFY_LINE_HELPER(line) #line
+#  define ORTHANC_PLUGINS_EXCEPTION_STRINGIFY_LINE(line) ORTHANC_PLUGINS_EXCEPTION_STRINGIFY_LINE_HELPER(line)
+#  define ORTHANC_PLUGINS_THROW_WITH_FILE_AND_LINE_INFO_HELPER(errorCode, errorCodeStr) \
+  throw ::Orthanc::OrthancException(                                    \
+    errorCode, "Plugin error code " + errorCodeStr + " triggered from " __ORTHANC_FILE__ ":" \
+    ORTHANC_PLUGINS_EXCEPTION_STRINGIFY_LINE(__LINE__))
+
+#  define ORTHANC_PLUGINS_THROW_WITH_FILE_AND_LINE_INFO(errorCode)      \
+  throw ::Orthanc::OrthancException(                                    \
+    errorCode, #errorCode " triggered from " __ORTHANC_FILE__ ":"       \
+    ORTHANC_PLUGINS_EXCEPTION_STRINGIFY_LINE(__LINE__))
+
+#  define ORTHANC_PLUGINS_THROW_ERROR_CODE(code)                        \
+  ORTHANC_PLUGINS_THROW_WITH_FILE_AND_LINE_INFO_HELPER(                 \
+    static_cast<ORTHANC_PLUGINS_ERROR_ENUMERATION>(code),               \
+    boost::lexical_cast<std::string>(code))
+
+#  define ORTHANC_PLUGINS_THROW_EXCEPTION(code)                         \
+  ORTHANC_PLUGINS_THROW_WITH_FILE_AND_LINE_INFO_HELPER(                 \
+    ORTHANC_PLUGINS_GET_ERROR_CODE(code),                               \
+    boost::lexical_cast<std::string>(ORTHANC_PLUGINS_GET_ERROR_CODE(code)))
+
+#else // the PluginException does not accept a "details" argument
+
+#  define ORTHANC_PLUGINS_THROW_ERROR_CODE(code)                        \
   throw ORTHANC_PLUGINS_EXCEPTION_CLASS(static_cast<ORTHANC_PLUGINS_ERROR_ENUMERATION>(code));
 
+#  define ORTHANC_PLUGINS_THROW_WITH_FILE_AND_LINE_INFO(errorCode)      \
+  ORTHANC_PLUGINS_THROW_ERROR_CODE(errorCode)
 
-#define ORTHANC_PLUGINS_THROW_EXCEPTION(code)                           \
+#  define ORTHANC_PLUGINS_THROW_EXCEPTION(code)                         \
   throw ORTHANC_PLUGINS_EXCEPTION_CLASS(ORTHANC_PLUGINS_GET_ERROR_CODE(code));
-                                                  
+
+#endif
+
 
 #define ORTHANC_PLUGINS_CHECK_ERROR(code)                           \
   if (code != ORTHANC_PLUGINS_GET_ERROR_CODE(Success))              \
--- a/Resources/Orthanc/Plugins/OrthancPluginsExports.cmake	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/Plugins/OrthancPluginsExports.cmake	Thu Aug 20 17:36:31 2026 +0200
@@ -9,7 +9,7 @@
 # modify it under the terms of the GNU General Public License as
 # published by the Free Software Foundation, either version 3 of the
 # License, or (at your option) any later version.
-# 
+#
 # This program is distributed in the hope that it will be useful, but
 # WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
--- a/Resources/Orthanc/Toolchains/LinuxStandardBaseToolchain.cmake	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/Toolchains/LinuxStandardBaseToolchain.cmake	Thu Aug 20 17:36:31 2026 +0200
@@ -62,7 +62,7 @@
 # which compilers to use for C and C++
 SET(CMAKE_C_COMPILER ${LSB_PATH}/bin/lsbcc)
 
-if (${CMAKE_VERSION} VERSION_LESS "3.6.0") 
+if (${CMAKE_VERSION} VERSION_LESS "3.6.0")
   CMAKE_FORCE_CXX_COMPILER(${LSB_PATH}/bin/lsbc++ GNU)
 else()
   SET(CMAKE_CXX_COMPILER ${LSB_PATH}/bin/lsbc++)
@@ -72,7 +72,7 @@
 SET(CMAKE_FIND_ROOT_PATH ${LSB_PATH})
 
 # adjust the default behaviour of the FIND_XXX() commands:
-# search headers and libraries in the target environment, search 
+# search headers and libraries in the target environment, search
 # programs in the host environment
 SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
 SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
--- a/Resources/Orthanc/Toolchains/MinGW-W64-Toolchain32.cmake	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/Toolchains/MinGW-W64-Toolchain32.cmake	Thu Aug 20 17:36:31 2026 +0200
@@ -32,7 +32,7 @@
 set(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32)
 
 # adjust the default behaviour of the FIND_XXX() commands:
-# search headers and libraries in the target environment, search 
+# search headers and libraries in the target environment, search
 # programs in the host environment
 set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
 set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
--- a/Resources/Orthanc/Toolchains/MinGW-W64-Toolchain64.cmake	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/Toolchains/MinGW-W64-Toolchain64.cmake	Thu Aug 20 17:36:31 2026 +0200
@@ -32,7 +32,7 @@
 set(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32)
 
 # adjust the default behaviour of the FIND_XXX() commands:
-# search headers and libraries in the target environment, search 
+# search headers and libraries in the target environment, search
 # programs in the host environment
 set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
 set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
--- a/Resources/Orthanc/Toolchains/MinGWToolchain.cmake	Mon Aug 10 10:26:44 2026 +0200
+++ b/Resources/Orthanc/Toolchains/MinGWToolchain.cmake	Thu Aug 20 17:36:31 2026 +0200
@@ -32,7 +32,7 @@
 set(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc)
 
 # adjust the default behaviour of the FIND_XXX() commands:
-# search headers and libraries in the target environment, search 
+# search headers and libraries in the target environment, search
 # programs in the host environment
 set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
 set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)