changeset 855:7c72d67ad9af default tip

sync
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 09 Nov 2026 07:48:09 +0100
parents 02c3dce022b6
children
files MySQL/CMakeLists.txt PostgreSQL/CMakeLists.txt 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/CMake/OpenSslConfiguration.cmake Resources/Orthanc/CMake/ProtobufConfiguration.cmake 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 18 files changed, 215 insertions(+), 188 deletions(-) [+]
line wrap: on
line diff
--- a/MySQL/CMakeLists.txt	Wed Sep 23 11:38:45 2026 +0200
+++ b/MySQL/CMakeLists.txt	Mon Nov 09 07:48:09 2026 +0100
@@ -50,7 +50,7 @@
 include(${CMAKE_SOURCE_DIR}/../Resources/CMake/DatabasesPluginParameters.cmake)
 
 set(ENABLE_MYSQL_BACKEND ON)
-set(OPENSSL_STATIC_VERSION "3.0" CACHE STRING "Force the use of OpenSSL 3.0.x" FORCE)
+set(OPENSSL_STATIC_VERSION "default" CACHE STRING "Version of OpenSSL to be used in static builds (can be \"1.1.1\", \"3.1.4\", or \"default\")")
   
 include(${CMAKE_SOURCE_DIR}/../Resources/CMake/DatabasesPluginConfiguration.cmake)
 
--- a/PostgreSQL/CMakeLists.txt	Wed Sep 23 11:38:45 2026 +0200
+++ b/PostgreSQL/CMakeLists.txt	Mon Nov 09 07:48:09 2026 +0100
@@ -51,7 +51,7 @@
 include(${CMAKE_SOURCE_DIR}/../Resources/CMake/DatabasesPluginParameters.cmake)
 
 set(ENABLE_POSTGRESQL_BACKEND ON)
-set(OPENSSL_STATIC_VERSION "3.0" CACHE STRING "Force the use of OpenSSL 3.0.x" FORCE)
+set(OPENSSL_STATIC_VERSION "default" CACHE STRING "Version of OpenSSL to be used in static builds (can be \"1.1.1\", \"3.1.4\", or \"default\")")
 
 include(${CMAKE_SOURCE_DIR}/../Resources/CMake/DatabasesPluginConfiguration.cmake)
 
--- a/Resources/Orthanc/CMake/AutoGeneratedCode.cmake	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/CMake/AutoGeneratedCode.cmake	Mon Nov 09 07:48:09 2026 +0100
@@ -76,5 +76,5 @@
 
   list(APPEND AUTOGENERATED_SOURCES
     "${TARGET_BASE}.cpp"
-    ) 
+    )
 endmacro()
--- a/Resources/Orthanc/CMake/Compiler.cmake	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/CMake/Compiler.cmake	Mon Nov 09 07:48:09 2026 +0100
@@ -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)
@@ -79,21 +79,29 @@
   endif()
 
 elseif (MSVC)
-  # Use static runtime under Visual Studio
+  # Use static runtime under Visual Studio (i.e., inject the "/MT"
+  # compiler flag to get the "MultiThreaded" static CRT)
   # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace
   # http://stackoverflow.com/a/6510446
-  foreach(flag_var
-    CMAKE_C_FLAGS_DEBUG
-    CMAKE_CXX_FLAGS_DEBUG
-    CMAKE_C_FLAGS_RELEASE 
-    CMAKE_CXX_FLAGS_RELEASE
-    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)
+  if(CMAKE_VERSION VERSION_LESS "3.15")
+    # Legacy approach: mangle the flags directly (pre-CMP0091)
+    foreach(flag_var
+        CMAKE_C_FLAGS_DEBUG
+        CMAKE_CXX_FLAGS_DEBUG
+        CMAKE_C_FLAGS_RELEASE
+        CMAKE_CXX_FLAGS_RELEASE
+        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)
+  else()
+    # Modern approach: CMP0091 + CMAKE_MSVC_RUNTIME_LIBRARY (new in Orthanc 1.13.1)
+    cmake_policy(SET CMP0091 NEW)
+    set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+  endif()
 
   # Add /Zm256 compiler option to Visual Studio to fix PCH errors
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zm256")
@@ -109,7 +117,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 +196,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 +262,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	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake	Mon Nov 09 07:48:09 2026 +0100
@@ -34,6 +34,14 @@
   message(FATAL_ERROR "The variable ORTHANC_FRAMEWORK_SOURCE must be set to \"system\", \"hg\", \"web\", \"archive\" or \"path\"")
 endif()
 
+# make sure these variables are defined (this happens when called from a plugin of from the UnitTests project)
+if(NOT DEFINED THIRD_PARTY_DOWNLOADS_ROOT_URL)
+  set(THIRD_PARTY_DOWNLOADS_ROOT_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads")
+endif()
+if(NOT DEFINED ORTHANC_SOURCES_DOWNLOADS_ROOT_URL)
+  set(ORTHANC_SOURCES_DOWNLOADS_ROOT_URL "https://orthanc.uclouvain.be/downloads/sources/orthanc")
+endif()
+
 
 ##
 ## Detection of the requested version
@@ -245,6 +253,14 @@
         # for ScopedThreadNameSetter
         set(ORTHANC_FRAMEWORK_PRE_RELEASE ON)
         set(ORTHANC_FRAMEWORK_MD5 "f078ca997217b831ab3f6741f08a8c07")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "c1dcb63cde6f")
+        # framework post-1.13.0 for THIRD_PARTY_DOWNLOADS_ROOT_URL and ORTHANC_SOURCES_DOWNLOADS_ROOT_URL
+        set(ORTHANC_FRAMEWORK_PRE_RELEASE ON)
+        set(ORTHANC_FRAMEWORK_MD5 "6fcb0ceac5006a5e3a6e3efcf6aaba26")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1339e4ed9f7f")
+        # framework post-1.13.0 for Boost 1.92
+        set(ORTHANC_FRAMEWORK_PRE_RELEASE ON)
+        set(ORTHANC_FRAMEWORK_MD5 "5d05b769d01ceeacb9e8b31fdb175e3e")
       endif()
     endif()
   endif()
@@ -264,7 +280,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()
@@ -274,8 +290,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"
       )
@@ -303,7 +319,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()
@@ -328,14 +344,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})
@@ -382,9 +398,9 @@
     # Default case: Download from the official Web site
     set(ORTHANC_FRAMEMORK_FILENAME Orthanc-${ORTHANC_FRAMEWORK_VERSION}.tar.gz)
     if (ORTHANC_FRAMEWORK_PRE_RELEASE)
-      set(ORTHANC_FRAMEWORK_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/orthanc-framework/${ORTHANC_FRAMEMORK_FILENAME}")
+      set(ORTHANC_FRAMEWORK_URL "${THIRD_PARTY_DOWNLOADS_ROOT_URL}/orthanc-framework/${ORTHANC_FRAMEMORK_FILENAME}")
     else()
-      set(ORTHANC_FRAMEWORK_URL "https://orthanc.uclouvain.be/downloads/sources/orthanc/${ORTHANC_FRAMEMORK_FILENAME}")
+      set(ORTHANC_FRAMEWORK_URL "${ORTHANC_SOURCES_DOWNLOADS_ROOT_URL}/${ORTHANC_FRAMEMORK_FILENAME}")
     endif()
   endif()
 
@@ -398,14 +414,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()
 
 
@@ -441,7 +457,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")
@@ -454,7 +470,7 @@
         RESULT_VARIABLE Failure
         OUTPUT_QUIET
         )
-      
+
       if (Failure)
         message(FATAL_ERROR "Error while running the uncompression tool")
       endif()
@@ -476,7 +492,7 @@
         RESULT_VARIABLE Failure
         )
     endif()
-   
+
     if (Failure)
       message(FATAL_ERROR "Error while running the uncompression tool")
     endif()
@@ -542,10 +558,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})
@@ -553,7 +569,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)
@@ -614,19 +630,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	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/CMake/DownloadPackage.cmake	Mon Nov 09 07:48:09 2026 +0100
@@ -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"
     )
@@ -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	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/CMake/EmbedResources.py	Mon Nov 09 07:48:09 2026 +0100
@@ -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	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/CMake/GoogleTestConfiguration.cmake	Mon Nov 09 07:48:09 2026 +0100
@@ -51,7 +51,7 @@
 
 elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST)
   set(GOOGLE_TEST_SOURCES_DIR ${CMAKE_BINARY_DIR}/googletest-release-1.8.1)
-  set(GOOGLE_TEST_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/gtest-1.8.1.tar.gz")
+  set(GOOGLE_TEST_URL "${THIRD_PARTY_DOWNLOADS_ROOT_URL}/gtest-1.8.1.tar.gz")
   set(GOOGLE_TEST_MD5 "2e6fbeb6a91310a16efe181886c59596")
 
   DownloadPackage(${GOOGLE_TEST_MD5} ${GOOGLE_TEST_URL} "${GOOGLE_TEST_SOURCES_DIR}")
@@ -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/CMake/OpenSslConfiguration.cmake	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/CMake/OpenSslConfiguration.cmake	Mon Nov 09 07:48:09 2026 +0100
@@ -24,8 +24,10 @@
   if (OPENSSL_STATIC_VERSION STREQUAL "1.1.1")
     # Still used by orthanc-gcp (Google Cloud Platform) as of its release 1.0
     include(${CMAKE_CURRENT_LIST_DIR}/OpenSslConfigurationStatic-1.1.1.cmake)
-  elseif (OPENSSL_STATIC_VERSION STREQUAL "3.0")
-    include(${CMAKE_CURRENT_LIST_DIR}/OpenSslConfigurationStatic-3.0.cmake)
+  elseif (OPENSSL_STATIC_VERSION STREQUAL "3.1.4")
+    include(${CMAKE_CURRENT_LIST_DIR}/OpenSslConfigurationStatic-3.1.4.cmake)
+  elseif (OPENSSL_STATIC_VERSION STREQUAL "default")
+    include(${CMAKE_CURRENT_LIST_DIR}/OpenSslConfigurationStatic.cmake)
   else()
     message(FATAL_ERROR "Unsupported version of OpenSSL: ${OPENSSL_STATIC_VERSION}")
   endif()
@@ -43,7 +45,7 @@
   CHECK_LIBRARY_EXISTS(crypto "OPENSSL_init" "" HAVE_OPENSSL_CRYPTO_LIB)
   if (NOT HAVE_OPENSSL_CRYPTO_LIB)
     message(FATAL_ERROR "Please install the libopenssl package")
-  endif()  
+  endif()
 
   # The "SSL_library_init" is for OpenSSL <= 1.0.2, whereas
   # "OPENSSL_init_ssl" is for OpenSSL >= 1.1.0
@@ -52,9 +54,9 @@
     CHECK_LIBRARY_EXISTS(ssl "OPENSSL_init_ssl" "" HAVE_OPENSSL_SSL_LIB_2)
     if (NOT HAVE_OPENSSL_SSL_LIB_2)
       message(FATAL_ERROR "Please install the libopenssl package")
-    endif()  
-  endif()  
-  
+    endif()
+  endif()
+
   link_libraries(crypto ssl)
 
 else()
--- a/Resources/Orthanc/CMake/ProtobufConfiguration.cmake	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/CMake/ProtobufConfiguration.cmake	Mon Nov 09 07:48:09 2026 +0100
@@ -31,6 +31,7 @@
       CMAKE_ARGS
       -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
       -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}
+      -DTHIRD_PARTY_DOWNLOADS_ROOT_URL=${THIRD_PARTY_DOWNLOADS_ROOT_URL}
       )
 
     # The "protoc" compiler is built using "externalproject_add",
@@ -44,14 +45,14 @@
     set(PROTOC_EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/protoc${Suffix})
   endif()
 
-  include(${CMAKE_CURRENT_LIST_DIR}/../ProtocolBuffers/ProtobufLibrary.cmake)  
+  include(${CMAKE_CURRENT_LIST_DIR}/../ProtocolBuffers/ProtobufLibrary.cmake)
   source_group(ThirdParty\\Protobuf REGULAR_EXPRESSION ${PROTOBUF_SOURCE_DIR}/.*)
 
 else()
   if (CMAKE_CROSSCOMPILING)
     message(FATAL_ERROR "If cross-compiling, the static version of Protocol Buffers should be used to avoid version mismatch")
   endif()
-  
+
   if (ENABLE_PROTOBUF_COMPILER)
     find_program(PROTOC_EXECUTABLE protoc)
     if (${PROTOC_EXECUTABLE} MATCHES "PROTOC_EXECUTABLE-NOTFOUND")
@@ -59,7 +60,7 @@
     endif()
     add_custom_target(ProtobufCompiler)
   endif()
-  
+
   check_include_file_cxx(google/protobuf/any.h HAVE_PROTOBUF_H)
   if (NOT HAVE_PROTOBUF_H)
     message(FATAL_ERROR "Please install the libprotobuf-dev package")
@@ -67,7 +68,7 @@
 
   set(CMAKE_REQUIRED_LIBRARIES "protobuf")
 
-  include(CheckCXXSourceCompiles) 
+  include(CheckCXXSourceCompiles)
   check_cxx_source_compiles(
     "
 #include <google/protobuf/descriptor.h>
@@ -79,7 +80,7 @@
   if (NOT HAVE_PROTOBUF_LIB)
     message(FATAL_ERROR "Cannot find the protobuf library")
   endif()
-  
+
   unset(CMAKE_REQUIRED_LIBRARIES)
 
   link_libraries(protobuf)
--- a/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp	Mon Nov 09 07:48:09 2026 +0100
@@ -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
@@ -418,7 +418,7 @@
       {
         headersKeys_.push_back(it->first.c_str());
         headersValues_.push_back(it->second.c_str());
-      }      
+      }
     }
 
     const char* const* GetKeys()
@@ -446,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));
@@ -458,7 +458,7 @@
                                  bool applyPlugins)
   {
     Clear();
-    
+
     // Cast for compatibility with Orthanc SDK <= 1.5.6
     const char* b = reinterpret_cast<const char*>(body);
 
@@ -485,7 +485,7 @@
 
     PluginHttpHeaders headers(httpHeaders);
 
-    return CheckHttp(OrthancPluginCallRestApi(GetGlobalContext(), 
+    return CheckHttp(OrthancPluginCallRestApi(GetGlobalContext(),
                                               &buffer_,
                                               *answerHeaders,
                                               &httpStatus,
@@ -541,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))
@@ -565,7 +565,7 @@
   {
     return ReadJson(target, source.empty() ? NULL : source.c_str(), source.size());
   }
-  
+
 
   bool ReadJson(Json::Value& target,
                 const void* buffer,
@@ -573,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,
@@ -602,7 +602,7 @@
     target = Json::writeString(builder, source);
 #endif
   }
-  
+
 
   void WriteStyledJson(std::string& target,
                        const Json::Value& source)
@@ -869,7 +869,7 @@
       ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
     }
   }
-    
+
 
   OrthancConfiguration::OrthancConfiguration()
   {
@@ -989,7 +989,7 @@
           ORTHANC_PLUGINS_LOG_ERROR("The configuration option \"" + GetPath(key) +
                                     "\" is too large to fit in an integer");
 
-          ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat);          
+          ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat);
         }
 
         target = static_cast<int>(configuration_[key].asUInt());
@@ -1577,7 +1577,7 @@
   {
     std::string bodyString;
     WriteStyledJson(bodyString, value);
-    CheckAnswerSizeIsLessThan4GB(bodyString);    
+    CheckAnswerSizeIsLessThan4GB(bodyString);
     OrthancPluginAnswerBuffer(GetGlobalContext(), output, bodyString.c_str(), bodyString.size(), "application/json");
   }
 
@@ -1605,7 +1605,7 @@
                                output,
                                "content-type",
                                mimeType);
-                               
+
     OrthancPluginSendHttpStatus(GetGlobalContext(),
                                 output,
                                 httpError,
@@ -2196,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;
@@ -2218,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;
@@ -2329,7 +2329,7 @@
     {
       target.Swap(answer);
       DecodeHttpHeaders(answerHeaders, answerHeadersBuffer);
-      
+
       return (status == 200);
     }
     else
@@ -2472,7 +2472,7 @@
       {
         memcpy(target->data, source.c_str(), source.size());
       }
-      
+
       return OrthancPluginErrorCode_Success;
     }
   }
@@ -2515,7 +2515,7 @@
   {
     assert(job != NULL);
     OrthancJob& that = *reinterpret_cast<OrthancJob*>(job);
-    
+
     if (that.hasSerialized_)
     {
       if (CopyStringToMemoryBuffer(target, that.serialized_) == OrthancPluginErrorCode_Success)
@@ -2821,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
@@ -2834,7 +2834,7 @@
     }
 
     bool synchronous = true;
-  
+
     if (body.isMember(KEY_SYNCHRONOUS))
     {
       if (body[KEY_SYNCHRONOUS].type() != Json::booleanValue)
@@ -2893,7 +2893,7 @@
         priority = !body[KEY_PRIORITY].asInt();
       }
     }
-  
+
     Json::Value result;
 
     if (synchronous)
@@ -2929,7 +2929,7 @@
   {
     start_ = boost::posix_time::microsec_clock::universal_time();
   }
-  
+
   MetricsTimer::~MetricsTimer()
   {
     const boost::posix_time::ptime stop = boost::posix_time::microsec_clock::universal_time();
@@ -2965,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());
@@ -2985,7 +2985,7 @@
     static OrthancPluginErrorCode Next(void* body)
     {
       RequestBodyWrapper& that = GetObject(body);
-        
+
       if (that.done_)
       {
         return OrthancPluginErrorCode_BadSequenceOfCalls;
@@ -3006,7 +3006,7 @@
           return OrthancPluginErrorCode_Plugin;
         }
       }
-    }    
+    }
   };
 
 
@@ -3078,7 +3078,7 @@
     }
   }
 
-  
+
   void HttpClient::SetCredentials(const std::string& username,
                                   const std::string& password)
   {
@@ -3086,7 +3086,7 @@
     password_ = password;
   }
 
-  
+
   void HttpClient::ClearCredentials()
   {
     username_.clear();
@@ -3103,7 +3103,7 @@
     certificateKeyPassword_ = keyPassword;
   }
 
-  
+
   void HttpClient::ClearCertificate()
   {
     certificateFile_.clear();
@@ -3118,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();
@@ -3361,7 +3361,7 @@
     }
 
     RequestBodyWrapper request(body);
-        
+
     OrthancPluginErrorCode error = OrthancPluginChunkedHttpClient(
       GetGlobalContext(),
       &answer,
@@ -3391,7 +3391,7 @@
       ORTHANC_PLUGINS_THROW_ERROR_CODE(error);
     }
   }
-#endif    
+#endif
 
   void HttpClient::ExecuteWithoutStream(uint16_t& httpStatus,
                                         HttpHeaders& answerHeaders,
@@ -3456,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)
@@ -3465,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())
@@ -3491,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)
@@ -3499,7 +3499,7 @@
     if (chunkedBody_ != NULL)
     {
       ChunkedBuffer buffer;
-      
+
       std::string chunk;
       while (chunkedBody_->ReadNextChunk(chunk))
       {
@@ -3523,7 +3523,7 @@
   {
     std::string body;
     Execute(answerHeaders, body);
-    
+
     if (!ReadJson(answerBody, body))
     {
       ORTHANC_PLUGINS_LOG_ERROR("Cannot convert HTTP answer body to JSON");
@@ -3556,7 +3556,7 @@
                           const OrthancPluginHttpRequest* request)
     {
     }
-  
+
     IChunkedRequestReader *NullChunkedRestCallback(const char* url,
                                                    const OrthancPluginHttpRequest* request)
     {
@@ -3595,7 +3595,7 @@
       }
     }
 
-    
+
     OrthancPluginErrorCode ChunkedRequestReaderExecute(
       OrthancPluginServerChunkedRequestReader* reader,
       OrthancPluginRestOutput*                 output)
@@ -3624,7 +3624,7 @@
       }
     }
 
-    
+
     void ChunkedRequestReaderFinalize(
       OrthancPluginServerChunkedRequestReader* reader)
     {
@@ -3635,7 +3635,7 @@
     }
 
 #else
-    
+
     OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output,
                                                     const char* url,
                                                     const OrthancPluginHttpRequest* request,
@@ -3659,7 +3659,7 @@
           {
             allowed += ",";
           }
-        
+
           allowed += "POST";
         }
 
@@ -3669,7 +3669,7 @@
           {
             allowed += ",";
           }
-        
+
           allowed += "DELETE";
         }
 
@@ -3679,10 +3679,10 @@
           {
             allowed += ",";
           }
-        
+
           allowed += "PUT";
         }
-      
+
         switch (request->method)
         {
           case OrthancPluginHttpMethod_Get:
@@ -3795,7 +3795,7 @@
   {
     assert(target != NULL &&
            rawHandler != NULL);
-      
+
     try
     {
       IStorageCommitmentScpHandler& handler = *reinterpret_cast<IStorageCommitmentScpHandler*>(rawHandler);
@@ -3823,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)
@@ -3864,7 +3864,7 @@
 #endif
   }
 
-  
+
   std::string DicomInstance::GetRemoteAet() const
   {
     const char* s = OrthancPluginGetInstanceRemoteAet(GetGlobalContext(), instance_);
@@ -3885,7 +3885,7 @@
     s.Assign(OrthancPluginGetInstanceJson(GetGlobalContext(), instance_));
     s.ToJson(target);
   }
-  
+
 
   void DicomInstance::GetSimplifiedJson(Json::Value& target) const
   {
@@ -3907,7 +3907,7 @@
   }
 #endif
 
-  
+
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
   bool DicomInstance::HasPixelData() const
   {
@@ -3924,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
   {
@@ -3944,7 +3944,7 @@
 #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(
@@ -3959,7 +3959,7 @@
       return new OrthancImage(image);
     }
   }
-#endif  
+#endif
 
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
@@ -3979,7 +3979,7 @@
     }
   }
 #endif
-  
+
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
   DicomInstance* DicomInstance::Transcode(const void* buffer,
@@ -4038,8 +4038,8 @@
     return result;
   }
 #endif
-  
-    
+
+
 #if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   static OrthancPluginErrorCode WebDavIsExistingFolder(uint8_t*            isExisting,
                                                        uint32_t            pathSize,
@@ -4064,7 +4064,7 @@
   }
 #endif
 
-  
+
 #if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   static OrthancPluginErrorCode WebDavListFolder(uint8_t*                        isExisting,
                                                  OrthancPluginWebDavCollection*  collection,
@@ -4075,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;
@@ -4088,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)
@@ -4126,7 +4126,7 @@
       return OrthancPluginErrorCode_Plugin;
     }
   }
-#endif    
+#endif
 
 
 #if HAS_ORTHANC_PLUGINS_WEBDAV == 1
@@ -4141,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(),
@@ -4161,7 +4161,7 @@
     {
       return OrthancPluginErrorCode_InternalError;
     }
-  }  
+  }
 #endif
 
 
@@ -4181,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;
@@ -4197,7 +4197,7 @@
   }
 #endif
 
-  
+
 #if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   static OrthancPluginErrorCode WebDavCreateFolderCallback(uint8_t*            isReadOnly, /* out */
                                                            uint32_t            pathSize,
@@ -4221,8 +4221,8 @@
     }
   }
 #endif
-  
-  
+
+
 #if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   static OrthancPluginErrorCode WebDavDeleteItemCallback(uint8_t*            isReadOnly, /* out */
                                                          uint32_t            pathSize,
@@ -4247,7 +4247,7 @@
   }
 #endif
 
-  
+
 #if HAS_ORTHANC_PLUGINS_WEBDAV == 1
   void IWebDavCollection::Register(const std::string& uri,
                                    IWebDavCollection& collection)
@@ -4270,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)
@@ -4280,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)
@@ -4474,7 +4474,7 @@
           mimeType = h->second.c_str();
         }
       }
-      
+
       AnswerString(answerBody_, mimeType, output);
     }
     else
--- a/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h	Mon Nov 09 07:48:09 2026 +0100
@@ -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
@@ -40,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
  *
  **/
@@ -203,7 +203,7 @@
 
   OrthancPluginContext* GetGlobalContext();
 
-  
+
   class OrthancImage;
 
 
@@ -393,7 +393,7 @@
     void ToString(std::string& target) const;
 
     void ToJson(Json::Value& target) const;
-  
+
     void ToJsonWithoutComments(Json::Value& target) const;
   };
 
@@ -407,7 +407,7 @@
     std::string GetPath(const std::string& key) const;
 
     void LoadConfiguration();
-    
+
   public:
     OrthancConfiguration(); // loads the full Orthanc configuration
 
@@ -427,7 +427,7 @@
 
     bool LookupStringValue(std::string& target,
                            const std::string& key) const;
-    
+
     bool LookupIntegerValue(int& target,
                             const std::string& key) const;
 
@@ -510,7 +510,7 @@
     unsigned int GetHeight() const;
 
     unsigned int GetPitch() const;
-    
+
     void* GetBuffer() const;
 
     const OrthancPluginImage* GetObject() const
@@ -527,7 +527,7 @@
 
     void AnswerJpegImage(OrthancPluginRestOutput* output,
                          uint8_t quality) const;
-    
+
     void* GetWriteableBuffer();
 
     OrthancPluginImage* Release();
@@ -573,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,
@@ -731,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);
@@ -780,7 +780,7 @@
     }
   }
 
-  
+
   template <RestCallback Callback>
   void RegisterRestCallback(const std::string& uri,
                             bool isThreadSafe)
@@ -906,7 +906,7 @@
                 const std::string& body,
                 const HttpHeaders& headers,
                 unsigned int timeout) const;
-    
+
     bool DoPost(Json::Value& target,
                 HttpHeaders& answerHeaders,
                 size_t index,
@@ -989,10 +989,10 @@
     void UpdateSerialized(const Json::Value& serialized);
 
     void UpdateProgress(float progress);
-    
+
   public:
     explicit OrthancJob(const std::string& jobType);
-    
+
     virtual ~OrthancJob()
     {
     }
@@ -1000,7 +1000,7 @@
     virtual OrthancPluginJobStepStatus Step() = 0;
 
     virtual void Stop(OrthancPluginJobStopReason reason) = 0;
-    
+
     virtual void Reset() = 0;
 
     static OrthancPluginJob* Create(OrthancJob* job /* takes ownership */);
@@ -1115,7 +1115,7 @@
                               HttpHeaders& answerHeaders,  // out
                               std::string& answerBody,     // out
                               const std::string& body) const;
-    
+
   public:
     HttpClient();
 
@@ -1230,7 +1230,7 @@
     void NullRestCallback(OrthancPluginRestOutput* output,
                           const char* url,
                           const OrthancPluginHttpRequest* request);
-  
+
     IChunkedRequestReader *NullChunkedRestCallback(const char* url,
                                                    const OrthancPluginHttpRequest* request);
 
@@ -1286,7 +1286,7 @@
     void ChunkedRequestReaderFinalize(
       OrthancPluginServerChunkedRequestReader* reader);
 
-#else  
+#else
 
     OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output,
                                                     const char* url,
@@ -1339,13 +1339,13 @@
         Internals::ChunkedRequestReaderFinalize);
 #else
       OrthancPluginRegisterRestCallbackNoLock(
-        GetGlobalContext(), uri.c_str(), 
+        GetGlobalContext(), uri.c_str(),
         Internals::ChunkedRestCompatibility<GetHandler, PostHandler, DeleteHandler, PutHandler>);
 #endif
     }
   };
 
-  
+
 
 #if HAS_ORTHANC_PLUGINS_STORAGE_COMMITMENT_SCP == 1
   class IStorageCommitmentScpHandler : public boost::noncopyable
@@ -1354,10 +1354,10 @@
     virtual ~IStorageCommitmentScpHandler()
     {
     }
-    
+
     virtual OrthancPluginStorageCommitmentFailureReason Lookup(const std::string& sopClassUid,
                                                                const std::string& sopInstanceUid) = 0;
-    
+
     static OrthancPluginErrorCode Lookup(OrthancPluginStorageCommitmentFailureReason* target,
                                          void* rawHandler,
                                          const char* sopClassUid,
@@ -1373,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);
@@ -1515,7 +1515,7 @@
         return dateTime_;
       }
     };
-  
+
     class FolderInfo
     {
     private:
@@ -1540,7 +1540,7 @@
         return dateTime_;
       }
     };
-  
+
     virtual ~IWebDavCollection()
     {
     }
@@ -1550,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 */,
@@ -1597,7 +1597,7 @@
 
   public:
     RestApiClient();
-    
+
     // used to forward a call from the plugin to the core
     RestApiClient(const char* url,
                   const OrthancPluginHttpRequest* request);
--- a/Resources/Orthanc/Plugins/OrthancPluginException.h	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/Plugins/OrthancPluginException.h	Mon Nov 09 07:48:09 2026 +0100
@@ -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
@@ -78,7 +78,7 @@
 #  define ORTHANC_PLUGINS_THROW_EXCEPTION(code)                         \
   throw ORTHANC_PLUGINS_EXCEPTION_CLASS(ORTHANC_PLUGINS_GET_ERROR_CODE(code));
 
-#endif                                                  
+#endif
 
 
 #define ORTHANC_PLUGINS_CHECK_ERROR(code)                           \
--- a/Resources/Orthanc/Plugins/OrthancPluginsExports.cmake	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/Plugins/OrthancPluginsExports.cmake	Mon Nov 09 07:48:09 2026 +0100
@@ -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	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/Toolchains/LinuxStandardBaseToolchain.cmake	Mon Nov 09 07:48:09 2026 +0100
@@ -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	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/Toolchains/MinGW-W64-Toolchain32.cmake	Mon Nov 09 07:48:09 2026 +0100
@@ -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	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/Toolchains/MinGW-W64-Toolchain64.cmake	Mon Nov 09 07:48:09 2026 +0100
@@ -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	Wed Sep 23 11:38:45 2026 +0200
+++ b/Resources/Orthanc/Toolchains/MinGWToolchain.cmake	Mon Nov 09 07:48:09 2026 +0100
@@ -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)