changeset 260:4975b53dc688

sync and temporarily revert to 1.12.6
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 12 Aug 2025 07:59:46 +0200
parents 8a7d921253c0
children 4724fbdf46e9
files CodeAnalysis/FunctionBody.mustache OrthancSDKVersion.cmake Resources/Orthanc/CMake/Compiler.cmake Resources/Orthanc/CMake/DownloadOrthancFramework.cmake Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h Resources/Orthanc/Sdk-1.12.9/orthanc/OrthancCPlugin.h Resources/SyncOrthancFolder.py Sources/Autogenerated/orthanc.pyi Sources/Autogenerated/sdk.cpp Sources/Autogenerated/sdk.h Sources/Autogenerated/sdk_GlobalFunctions.impl.h Sources/Autogenerated/sdk_OrthancPluginCompressionType.impl.h Sources/Autogenerated/sdk_OrthancPluginDicomInstance.methods.h Sources/Autogenerated/sdk_OrthancPluginStorageArea.methods.h Sources/Autogenerated/sdk_OrthancPluginWorklistQuery.methods.h
diffstat 16 files changed, 1732 insertions(+), 603 deletions(-) [+]
line wrap: on
line diff
--- a/CodeAnalysis/FunctionBody.mustache	Mon Aug 11 13:03:13 2025 +0200
+++ b/CodeAnalysis/FunctionBody.mustache	Tue Aug 12 07:59:46 2025 +0200
@@ -119,7 +119,7 @@
   {{#args}}{{release}}{{/args}}
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
--- a/OrthancSDKVersion.cmake	Mon Aug 11 13:03:13 2025 +0200
+++ b/OrthancSDKVersion.cmake	Tue Aug 12 07:59:46 2025 +0200
@@ -1,1 +1,1 @@
-set(ORTHANC_SDK_VERSION "1.12.9")
+set(ORTHANC_SDK_VERSION "1.12.6")
--- a/Resources/Orthanc/CMake/Compiler.cmake	Mon Aug 11 13:03:13 2025 +0200
+++ b/Resources/Orthanc/CMake/Compiler.cmake	Tue Aug 12 07:59:46 2025 +0200
@@ -22,6 +22,16 @@
 
 # This file sets all the compiler-related flags
 
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
+  # Since Orthanc 1.12.7 that allows CMake 4.0, builds for macOS
+  # require the C++ standard to be explicitly set to C++11. Do *not*
+  # do this on GNU/Linux, as third-party system libraries could have
+  # been compiled with higher versions of the C++ standard.
+  set(CMAKE_CXX_STANDARD 11)
+  set(CMAKE_CXX_STANDARD_REQUIRED ON)
+  set(CMAKE_CXX_EXTENSIONS OFF)
+endif()
+
 
 # Save the current compiler flags to the cache every time cmake configures the project
 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "compiler flags" FORCE)
--- a/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake	Mon Aug 11 13:03:13 2025 +0200
+++ b/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake	Tue Aug 12 07:59:46 2025 +0200
@@ -169,6 +169,12 @@
         set(ORTHANC_FRAMEWORK_MD5 "5bb69f092981fdcfc11dec0a0f9a7db3")
       elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.6")
         set(ORTHANC_FRAMEWORK_MD5 "0e971f32f4f3e4951e0f3b5de49a3da6")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.7")
+        set(ORTHANC_FRAMEWORK_MD5 "f27c27d7a7a694dab1fd7f0a99d9715a")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.8")
+        set(ORTHANC_FRAMEWORK_MD5 "eb1c719234338e8277b80d3453563e9f")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.9")
+        set(ORTHANC_FRAMEWORK_MD5 "66b5a2ee60706c4a502896083b9e1a01")
 
       # Below this point are development snapshots that were used to
       # release some plugin, before an official release of the Orthanc
@@ -501,11 +507,18 @@
   
   include(CheckIncludeFile)
   include(CheckIncludeFileCXX)
-  include(FindPythonInterp)
+  
+  if(CMAKE_VERSION VERSION_GREATER "3.11")
+    find_package(Python REQUIRED COMPONENTS Interpreter)
+    set(PYTHON_EXECUTABLE ${Python_EXECUTABLE})
+  else()
+    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)
-  set(EMBED_RESOURCES_PYTHON ${CMAKE_CURRENT_LIST_DIR}/EmbedResources.py)
 
   if (ORTHANC_FRAMEWORK_USE_SHARED)
     list(GET CMAKE_FIND_LIBRARY_PREFIXES 0 Prefix)
--- a/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp	Mon Aug 11 13:03:13 2025 +0200
+++ b/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp	Tue Aug 12 07:59:46 2025 +0200
@@ -26,6 +26,7 @@
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/move/unique_ptr.hpp>
 #include <boost/thread.hpp>
+#include <boost/algorithm/string/join.hpp>
 
 
 #include <json/reader.h>
@@ -219,28 +220,6 @@
   }
 
 
-#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
-  MemoryBuffer::MemoryBuffer(const void* buffer,
-                             size_t size)
-  {
-    uint32_t s = static_cast<uint32_t>(size);
-    if (static_cast<size_t>(s) != size)
-    {
-      ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory);
-    }
-    else if (OrthancPluginCreateMemoryBuffer(GetGlobalContext(), &buffer_, s) !=
-             OrthancPluginErrorCode_Success)
-    {
-      ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory);
-    }
-    else
-    {
-      memcpy(buffer_.data, buffer, size);
-    }
-  }
-#endif
-
-
   void MemoryBuffer::Clear()
   {
     if (buffer_.data != NULL)
@@ -252,6 +231,51 @@
   }
 
 
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
+  void MemoryBuffer::Assign(const void* buffer,
+                            size_t size)
+  {
+    uint32_t s = static_cast<uint32_t>(size);
+    if (static_cast<size_t>(s) != size)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory);
+    }
+
+    Clear();
+
+    if (OrthancPluginCreateMemoryBuffer(GetGlobalContext(), &buffer_, s) !=
+        OrthancPluginErrorCode_Success)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory);
+    }
+    else
+    {
+      if (size > 0)
+      {
+        memcpy(buffer_.data, buffer, size);
+      }
+    }
+  }
+#endif
+
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
+  void MemoryBuffer::Assign(const std::string& s)
+  {
+    Assign(s.empty() ? NULL : s.c_str(), s.size());
+  }
+#endif
+
+
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
+  void MemoryBuffer::AssignJson(const Json::Value& value)
+  {
+    std::string s;
+    WriteFastJson(s, value);
+    Assign(s);
+  }
+#endif
+
+
   void MemoryBuffer::Assign(OrthancPluginMemoryBuffer& other)
   {
     Clear();
@@ -672,7 +696,7 @@
   {
     OrthancString str;
     str.Assign(OrthancPluginDicomBufferToJson
-               (GetGlobalContext(), GetData(), GetSize(), format, flags, maxStringLength));
+               (GetGlobalContext(), reinterpret_cast<const char*>(GetData()), GetSize(), format, flags, maxStringLength));
     str.ToJson(target);
   }
 
@@ -1565,7 +1589,7 @@
     {
       if (!answer.IsEmpty())
       {
-        result.assign(answer.GetData(), answer.GetSize());
+        result.assign(reinterpret_cast<const char*>(answer.GetData()), answer.GetSize());
       }
       return true;
     }
@@ -2051,6 +2075,26 @@
             DoPost(target, index, uri, body, headers));
   }
 
+  bool OrthancPeers::DoPost(Json::Value& target,
+                            size_t index,
+                            const std::string& uri,
+                            const std::string& body,
+                            const HttpHeaders& headers, 
+                            unsigned int timeout) const
+  {
+    MemoryBuffer buffer;
+
+    if (DoPost(buffer, index, uri, body, headers, timeout))
+    {
+      buffer.ToJson(target);
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
 
   bool OrthancPeers::DoPost(Json::Value& target,
                             size_t index,
@@ -2098,6 +2142,17 @@
                             const std::string& body,
                             const HttpHeaders& headers) const
   {
+    return DoPost(target, index, uri, body, headers, timeout_);
+  }
+
+
+  bool OrthancPeers::DoPost(MemoryBuffer& target,
+                            size_t index,
+                            const std::string& uri,
+                            const std::string& body,
+                            const HttpHeaders& headers,
+                            unsigned int timeout) const
+  {
     if (index >= index_.size())
     {
       ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
@@ -2116,7 +2171,7 @@
     OrthancPluginErrorCode code = OrthancPluginCallPeerApi
       (GetGlobalContext(), *answer, NULL, &status, peers_,
        static_cast<uint32_t>(index), OrthancPluginHttpMethod_Post, uri.c_str(),
-       pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), body.empty() ? NULL : body.c_str(), body.size(), timeout_);
+       pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), body.empty() ? NULL : body.c_str(), body.size(), timeout);
 
     if (code == OrthancPluginErrorCode_Success)
     {
@@ -4067,6 +4122,16 @@
   }
 #endif
 
+  void GetGetArguments(GetArguments& result, const OrthancPluginHttpRequest* request)
+  {
+    result.clear();
+
+    for (uint32_t i = 0; i < request->getCount; ++i)
+    {
+      result[request->getKeys[i]] = request->getValues[i];
+    }    
+  }
+
   void GetHttpHeaders(HttpHeaders& result, const OrthancPluginHttpRequest* request)
   {
     result.clear();
@@ -4077,6 +4142,26 @@
     }    
   }
 
+  void SerializeGetArguments(std::string& output, const OrthancPluginHttpRequest* request)
+  {
+    output.clear();
+    std::vector<std::string> arguments;
+    for (uint32_t i = 0; i < request->getCount; ++i)
+    {
+      if (request->getValues[i] && strlen(request->getValues[i]) > 0)
+      {
+        arguments.push_back(std::string(request->getKeys[i]) + "=" + std::string(request->getValues[i]));
+      }
+      else
+      {
+        arguments.push_back(std::string(request->getKeys[i]));
+      }
+    }
+
+    output = boost::algorithm::join(arguments, "&");
+  }
+
+
 #if !ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 4)
   static void SetPluginProperty(const std::string& pluginIdentifier,
                                 _OrthancPluginProperty property,
@@ -4130,6 +4215,29 @@
     httpStatus_(0)
   {
   }
+
+  RestApiClient::RestApiClient(const char* url,
+                               const OrthancPluginHttpRequest* request) :
+    method_(request->method),
+    path_(url),
+    afterPlugins_(false),
+    httpStatus_(0)
+  {
+    OrthancPlugins::GetHttpHeaders(requestHeaders_, request);
+
+    std::string getArguments;
+    OrthancPlugins::SerializeGetArguments(getArguments, request);
+
+    if (!getArguments.empty())
+    {
+      path_ += "?" + getArguments;
+    }
+
+    if (request->bodySize > 0 && request->body != NULL)
+    {
+      requestBody_.assign(reinterpret_cast<const char*>(request->body), request->bodySize);
+    }
+  }
 #endif
 
 
@@ -4150,6 +4258,15 @@
 
 
 #if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+  void RestApiClient::SetRequestHeader(const std::string& key,
+                                       const std::string& value)
+  {
+    requestHeaders_[key] = value;
+  }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
   bool RestApiClient::Execute()
   {
     if (requestBody_.size() > 0xffffffffu)
@@ -4195,6 +4312,40 @@
       }
     }
   }
+
+  void RestApiClient::ExecuteAndForwardAnswer(OrthancPluginContext* context, OrthancPluginRestOutput* output)
+  {
+    if (Execute())
+    {
+      ForwardAnswer(context, output);
+    }
+  }
+
+  void RestApiClient::ForwardAnswer(OrthancPluginContext* context, OrthancPluginRestOutput* output)
+  {
+    if (httpStatus_ == 200)
+    {
+      const char* mimeType = NULL;
+      for (HttpHeaders::const_iterator h = answerHeaders_.begin(); h != answerHeaders_.end(); ++h)
+      {
+        if (h->first == "content-type")
+        {
+          mimeType = h->second.c_str();
+        }
+      }
+      
+      AnswerString(answerBody_, mimeType, output);
+    }
+    else
+    {
+      AnswerHttpError(httpStatus_, output);
+    }
+  }
+
+  bool RestApiClient::GetAnswerJson(Json::Value& output) const
+  {
+    return ReadJson(output, answerBody_);
+  }
 #endif
 
 
@@ -4251,4 +4402,209 @@
     }
   }
 #endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+  KeyValueStore::Iterator::Iterator(OrthancPluginKeysValuesIterator  *iterator) :
+    iterator_(iterator)
+  {
+    if (iterator_ == NULL)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
+    }
+  }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+  KeyValueStore::Iterator::~Iterator()
+  {
+    OrthancPluginFreeKeysValuesIterator(OrthancPlugins::GetGlobalContext(), iterator_);
+  }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+  bool KeyValueStore::Iterator::Next()
+  {
+    uint8_t done;
+    OrthancPluginErrorCode code = OrthancPluginKeysValuesIteratorNext(OrthancPlugins::GetGlobalContext(), &done, iterator_);
+
+    if (code != OrthancPluginErrorCode_Success)
+    {
+      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+    }
+    else
+    {
+      return (done != 0);
+    }
+  }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+  std::string KeyValueStore::Iterator::GetKey() const
+  {
+    const char* s = OrthancPluginKeysValuesIteratorGetKey(OrthancPlugins::GetGlobalContext(), iterator_);
+    if (s == NULL)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
+    }
+    else
+    {
+      return s;
+    }
+  }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+  void KeyValueStore::Iterator::GetValue(std::string& value) const
+  {
+    OrthancPlugins::MemoryBuffer valueBuffer;
+    OrthancPluginErrorCode code = OrthancPluginKeysValuesIteratorGetValue(OrthancPlugins::GetGlobalContext(), *valueBuffer, iterator_);
+
+    if (code != OrthancPluginErrorCode_Success)
+    {
+      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+    }
+    else
+    {
+      valueBuffer.ToString(value);
+    }
+  }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+  void KeyValueStore::Store(const std::string& key,
+                            const void* value,
+                            size_t valueSize)
+  {
+    if (static_cast<size_t>(static_cast<uint32_t>(valueSize)) != valueSize)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory);
+    }
+
+    OrthancPluginErrorCode code = OrthancPluginStoreKeyValue(OrthancPlugins::GetGlobalContext(), storeId_.c_str(),
+                                                             key.c_str(), value, static_cast<uint32_t>(valueSize));
+    if (code != OrthancPluginErrorCode_Success)
+    {
+      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+    }
+  }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+  bool KeyValueStore::GetValue(std::string& value,
+                               const std::string& key)
+  {
+    uint8_t found = false;
+    OrthancPlugins::MemoryBuffer valueBuffer;
+    OrthancPluginErrorCode code = OrthancPluginGetKeyValue(OrthancPlugins::GetGlobalContext(), &found,
+                                                           *valueBuffer, storeId_.c_str(), key.c_str());
+
+    if (code != OrthancPluginErrorCode_Success)
+    {
+      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+    }
+    else if (found)
+    {
+      valueBuffer.ToString(value);
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+  void KeyValueStore::DeleteKey(const std::string& key)
+  {
+    OrthancPluginErrorCode code = OrthancPluginDeleteKeyValue(OrthancPlugins::GetGlobalContext(),
+                                                              storeId_.c_str(), key.c_str());
+
+    if (code != OrthancPluginErrorCode_Success)
+    {
+      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+    }
+  }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+  KeyValueStore::Iterator* KeyValueStore::CreateIterator()
+  {
+    return new Iterator(OrthancPluginCreateKeysValuesIterator(OrthancPlugins::GetGlobalContext(), storeId_.c_str()));
+  }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_QUEUES == 1
+  void Queue::Enqueue(const void* value,
+                      size_t valueSize)
+  {
+    if (static_cast<size_t>(static_cast<uint32_t>(valueSize)) != valueSize)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory);
+    }
+
+    OrthancPluginErrorCode code = OrthancPluginEnqueueValue(OrthancPlugins::GetGlobalContext(),
+                                                            queueId_.c_str(), value, static_cast<uint32_t>(valueSize));
+
+    if (code != OrthancPluginErrorCode_Success)
+    {
+      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+    }
+  }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_QUEUES == 1
+  bool Queue::DequeueInternal(std::string& value,
+                              OrthancPluginQueueOrigin origin)
+  {
+    uint8_t found = false;
+    OrthancPlugins::MemoryBuffer valueBuffer;
+
+    OrthancPluginErrorCode code = OrthancPluginDequeueValue(OrthancPlugins::GetGlobalContext(), &found,
+                                                            *valueBuffer, queueId_.c_str(), origin);
+
+    if (code != OrthancPluginErrorCode_Success)
+    {
+      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+    }
+    else if (found)
+    {
+      valueBuffer.ToString(value);
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_QUEUES == 1
+  uint64_t Queue::GetSize()
+  {
+    uint64_t size = 0;
+    OrthancPluginErrorCode code = OrthancPluginGetQueueSize(OrthancPlugins::GetGlobalContext(), queueId_.c_str(), &size);
+
+    if (code != OrthancPluginErrorCode_Success)
+    {
+      ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+    }
+    else
+    {
+      return size;
+    }
+  }
+#endif
 }
--- a/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h	Mon Aug 11 13:03:13 2025 +0200
+++ b/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h	Tue Aug 12 07:59:46 2025 +0200
@@ -134,6 +134,14 @@
 #  define HAS_ORTHANC_PLUGIN_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
+#else
+#  define HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES  0
+#  define HAS_ORTHANC_PLUGIN_QUEUES            0
+#endif
+
 
 // Macro to tag a function as having been deprecated
 #if (__cplusplus >= 201402L)  // C++14
@@ -172,6 +180,8 @@
 {
   typedef std::map<std::string, std::string>  HttpHeaders;
 
+  typedef std::map<std::string, std::string>  GetArguments;
+
   typedef void (*RestCallback) (OrthancPluginRestOutput* output,
                                 const char* url,
                                 const OrthancPluginHttpRequest* request);
@@ -203,13 +213,6 @@
   public:
     MemoryBuffer();
 
-#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
-    // This constructor makes a copy of the given buffer in the memory
-    // handled by the Orthanc core
-    MemoryBuffer(const void* buffer,
-                 size_t size);
-#endif
-
     ~MemoryBuffer()
     {
       Clear();
@@ -220,6 +223,20 @@
       return &buffer_;
     }
 
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
+    // Copy of the given buffer into the memory managed by the Orthanc core
+    void Assign(const void* buffer,
+                size_t size);
+#endif
+
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
+    void Assign(const std::string& s);
+#endif
+
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
+    void AssignJson(const Json::Value& value);
+#endif
+
     // This transfers ownership from "other" to "this"
     void Assign(OrthancPluginMemoryBuffer& other);
 
@@ -227,11 +244,11 @@
 
     OrthancPluginMemoryBuffer Release();
 
-    const char* GetData() const
+    const void* GetData() const
     {
       if (buffer_.size > 0)
       {
-        return reinterpret_cast<const char*>(buffer_.data);
+        return buffer_.data;
       }
       else
       {
@@ -855,6 +872,13 @@
                 const HttpHeaders& headers) const;
 
     bool DoPost(MemoryBuffer& target,
+                size_t index,
+                const std::string& uri,
+                const std::string& body,
+                const HttpHeaders& headers,
+                unsigned int timeout) const;
+
+    bool DoPost(MemoryBuffer& target,
                 const std::string& name,
                 const std::string& uri,
                 const std::string& body,
@@ -867,6 +891,13 @@
                 const HttpHeaders& headers) const;
 
     bool DoPost(Json::Value& target,
+                size_t index,
+                const std::string& uri,
+                const std::string& body,
+                const HttpHeaders& headers,
+                unsigned int timeout) const;
+
+    bool DoPost(Json::Value& target,
                 const std::string& name,
                 const std::string& uri,
                 const std::string& body,
@@ -1399,6 +1430,12 @@
 // helper method to convert Http headers from the plugin SDK to a std::map
 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);
+
+// helper method to convert Get arguments from the plugin SDK to a std::map
+void GetGetArguments(GetArguments& result, const OrthancPluginHttpRequest* request);
+
 #if HAS_ORTHANC_PLUGIN_WEBDAV == 1
   class IWebDavCollection : public boost::noncopyable
   {
@@ -1528,6 +1565,10 @@
 
   public:
     RestApiClient();
+    
+    // used to forward a call from the plugin to the core
+    RestApiClient(const char* url,
+                  const OrthancPluginHttpRequest* request);
 
     void SetMethod(OrthancPluginHttpMethod method)
     {
@@ -1552,6 +1593,9 @@
     void AddRequestHeader(const std::string& key,
                           const std::string& value);
 
+    void SetRequestHeader(const std::string& key,
+                          const std::string& value);
+
     const HttpHeaders& GetRequestHeaders() const
     {
       return requestHeaders_;
@@ -1582,14 +1626,120 @@
       return requestBody_;
     }
 
+    // Execute only
     bool Execute();
 
+    // Forward response as is
+    void ForwardAnswer(OrthancPluginContext* context, OrthancPluginRestOutput* output);
+
+    // Execute and forward the response as is
+    void ExecuteAndForwardAnswer(OrthancPluginContext* context, OrthancPluginRestOutput* output);
+
     uint16_t GetHttpStatus() const;
 
     bool LookupAnswerHeader(std::string& value,
                             const std::string& key) const;
 
     const std::string& GetAnswerBody() const;
+
+    bool GetAnswerJson(Json::Value& output) const;
+  };
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+  class KeyValueStore : public boost::noncopyable
+  {
+  public:
+    class Iterator : public boost::noncopyable
+    {
+    private:
+      OrthancPluginKeysValuesIterator  *iterator_;
+
+    public:
+      explicit Iterator(OrthancPluginKeysValuesIterator *iterator);
+
+      ~Iterator();
+
+      bool Next();
+
+      std::string GetKey() const;
+
+      void GetValue(std::string& target) const;
+    };
+
+  private:
+    std::string storeId_;
+
+  public:
+    explicit KeyValueStore(const std::string& storeId) :
+      storeId_(storeId)
+    {
+    }
+
+    const std::string& GetStoreId() const
+    {
+      return storeId_;
+    }
+
+    void Store(const std::string& key,
+               const void* value,
+               size_t valueSize);
+
+    void Store(const std::string& key,
+               const std::string& value)
+    {
+      Store(key, value.empty() ? NULL : value.c_str(), value.size());
+    }
+
+    bool GetValue(std::string& value,
+                  const std::string& key);
+
+    void DeleteKey(const std::string& key);
+
+    Iterator* CreateIterator();
+  };
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_QUEUES == 1
+  class Queue : public boost::noncopyable
+  {
+  private:
+    std::string queueId_;
+
+    bool DequeueInternal(std::string& value, OrthancPluginQueueOrigin origin);
+
+  public:
+    explicit Queue(const std::string& queueId) :
+      queueId_(queueId)
+    {
+    }
+
+    const std::string& GetQueueId() const
+    {
+      return queueId_;
+    }
+
+    void Enqueue(const void* value,
+                 size_t valueSize);
+
+    void Enqueue(const std::string& value)
+    {
+      Enqueue(value.empty() ? NULL : value.c_str(), value.size());
+    }
+
+    bool DequeueBack(std::string& value)
+    {
+      return DequeueInternal(value, OrthancPluginQueueOrigin_Back);
+    }
+
+    bool DequeueFront(std::string& value)
+    {
+      return DequeueInternal(value, OrthancPluginQueueOrigin_Front);
+    }
+
+    uint64_t GetSize();
   };
 #endif
 }
--- a/Resources/Orthanc/Sdk-1.12.9/orthanc/OrthancCPlugin.h	Mon Aug 11 13:03:13 2025 +0200
+++ b/Resources/Orthanc/Sdk-1.12.9/orthanc/OrthancCPlugin.h	Tue Aug 12 07:59:46 2025 +0200
@@ -16,7 +16,7 @@
  *    - Register all its REST callbacks using ::OrthancPluginRegisterRestCallback().
  *    - Possibly register its callback for received DICOM instances using ::OrthancPluginRegisterOnStoredInstanceCallback().
  *    - Possibly register its callback for changes to the DICOM store using ::OrthancPluginRegisterOnChangeCallback().
- *    - Possibly register a custom storage area using ::OrthancPluginRegisterStorageArea2().
+ *    - Possibly register a custom storage area using ::OrthancPluginRegisterStorageArea3().
  *    - Possibly register a custom database back-end area using OrthancPluginRegisterDatabaseBackendV4().
  *    - Possibly register a handler for C-Find SCP using OrthancPluginRegisterFindCallback().
  *    - Possibly register a handler for C-Find SCP against DICOM worklists using OrthancPluginRegisterWorklistCallback().
@@ -31,6 +31,8 @@
  *    - Possibly register a custom transcoder for DICOM images using OrthancPluginRegisterTranscoderCallback().
  *    - Possibly register a callback to discard instances received through DICOM C-STORE using OrthancPluginRegisterIncomingCStoreInstanceFilter().
  *    - Possibly register a callback to branch a WebDAV virtual filesystem using OrthancPluginRegisterWebDavCollection().
+ *    - Possibly register a callback to authenticate HTTP requests using OrthancPluginRegisterHttpAuthentication().
+ *    - Possibly register a callback to store audit logs using OrthancPluginRegisterAuditLogHandler().
  * -# <tt>void OrthancPluginFinalize()</tt>:
  *    This function is invoked by Orthanc during its shutdown. The plugin
  *    must free all its memory.
@@ -121,7 +123,7 @@
 
 #define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER     1
 #define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER     12
-#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  6
+#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  9
 
 
 #if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)
@@ -182,6 +184,21 @@
 #endif
 
 
+#ifndef ORTHANC_PLUGIN_SINCE_SDK
+/**
+ * This macro is used by the code model generator that produces the
+ * "OrthancPluginCodeModel.json" file. The code model is notably used
+ * to generate the Python and Java wrappers. Primitives that are not
+ * tagged with this macro were introduced before Orthanc 1.0.0.
+ **/
+#  if defined(__clang__)
+#    define ORTHANC_PLUGIN_SINCE_SDK(version) __attribute__ ((annotate("ORTHANC_PLUGIN_SINCE_SDK " version)))
+#  else
+#    define ORTHANC_PLUGIN_SINCE_SDK(version)
+#  endif
+#endif
+
+
 
 /********************************************************************
  ** Inclusion of standard libraries.
@@ -418,10 +435,27 @@
      **/
     const char* const*      headersValues;
 
+
+    /* --------------------------------------------------
+       New in version 1.12.9
+       -------------------------------------------------- */
+
+    /**
+     * @brief If a HTTP authentication callback is registered, the
+     * content of the custom payload generated by the callback.
+     **/
+    const void*             authenticationPayload;
+
+    /**
+     * @brief The size of the custom authentication payload (0 if no
+     * authentication callback is registered).
+     **/
+    uint32_t                authenticationPayloadSize;
+
   } OrthancPluginHttpRequest;
 
 
-  typedef enum 
+  typedef enum
   {
     /* Generic services */
     _OrthancPluginService_LogInfo = 1,
@@ -469,7 +503,22 @@
     _OrthancPluginService_SetMetricsIntegerValue = 43,              /* New in Orthanc 1.12.1 */
     _OrthancPluginService_SetCurrentThreadName = 44,                /* New in Orthanc 1.12.2 */
     _OrthancPluginService_LogMessage = 45,                          /* New in Orthanc 1.12.4 */
-
+    _OrthancPluginService_AdoptDicomInstance = 46,                  /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_GetAttachmentCustomData = 47,             /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_SetAttachmentCustomData = 48,             /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_StoreKeyValue = 49,                       /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_DeleteKeyValue = 50,                      /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_GetKeyValue = 51,                         /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_CreateKeysValuesIterator = 52,            /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_FreeKeysValuesIterator = 53,              /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_KeysValuesIteratorNext = 54,              /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_KeysValuesIteratorGetKey = 55,            /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_KeysValuesIteratorGetValue = 56,          /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_EnqueueValue = 57,                        /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_DequeueValue = 58,                        /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_GetQueueSize = 59,                        /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_SetStableStatus = 60,                     /* New in Orthanc 1.12.9 */
+    _OrthancPluginService_EmitAuditLog = 61,                        /* New in Orthanc 1.12.9 */
 
     /* Registration of callbacks */
     _OrthancPluginService_RegisterRestCallback = 1000,
@@ -485,13 +534,16 @@
     _OrthancPluginService_RegisterIncomingHttpRequestFilter2 = 1010,
     _OrthancPluginService_RegisterRefreshMetricsCallback = 1011,
     _OrthancPluginService_RegisterChunkedRestCallback = 1012,  /* New in Orthanc 1.5.7 */
-    _OrthancPluginService_RegisterStorageCommitmentScpCallback = 1013,
-    _OrthancPluginService_RegisterIncomingDicomInstanceFilter = 1014,
+    _OrthancPluginService_RegisterStorageCommitmentScpCallback = 1013, /* New in Orthanc 1.6.0 */
+    _OrthancPluginService_RegisterIncomingDicomInstanceFilter = 1014,  /* New in Orthanc 1.6.1 */
     _OrthancPluginService_RegisterTranscoderCallback = 1015,   /* New in Orthanc 1.7.0 */
     _OrthancPluginService_RegisterStorageArea2 = 1016,         /* New in Orthanc 1.9.0 */
     _OrthancPluginService_RegisterIncomingCStoreInstanceFilter = 1017,  /* New in Orthanc 1.10.0 */
     _OrthancPluginService_RegisterReceivedInstanceCallback = 1018,  /* New in Orthanc 1.10.0 */
     _OrthancPluginService_RegisterWebDavCollection = 1019,     /* New in Orthanc 1.10.1 */
+    _OrthancPluginService_RegisterStorageArea3 = 1020,         /* New in Orthanc 1.12.8 */
+    _OrthancPluginService_RegisterHttpAuthentication = 1021,   /* New in Orthanc 1.12.9 */
+    _OrthancPluginService_RegisterAuditLogHandler = 1022,      /* New in Orthanc 1.12.9 */
 
     /* Sending answers to REST calls */
     _OrthancPluginService_AnswerBuffer = 2000,
@@ -562,7 +614,7 @@
     _OrthancPluginService_StorageAreaRemove = 5005,
     _OrthancPluginService_RegisterDatabaseBackendV3 = 5006,  /* New in Orthanc 1.9.2 */
     _OrthancPluginService_RegisterDatabaseBackendV4 = 5007,  /* New in Orthanc 1.12.0 */
-    
+
     /* Primitives for handling images */
     _OrthancPluginService_GetImagePixelFormat = 6000,
     _OrthancPluginService_GetImageWidth = 6001,
@@ -680,7 +732,7 @@
      * This format describes a color image. The pixels are stored in 6
      * consecutive bytes. The memory layout is RRGGBB.
      **/
-    OrthancPluginPixelFormat_RGB48 = 7,
+    OrthancPluginPixelFormat_RGB48 ORTHANC_PLUGIN_SINCE_SDK("1.3.1") = 7,
 
     /**
      * @brief Graylevel, unsigned 32bpp image.
@@ -688,7 +740,7 @@
      * The image is graylevel. Each pixel is unsigned and stored in
      * four bytes.
      **/
-    OrthancPluginPixelFormat_Grayscale32 = 8,
+    OrthancPluginPixelFormat_Grayscale32 ORTHANC_PLUGIN_SINCE_SDK("1.3.1") = 8,
 
     /**
      * @brief Graylevel, floating-point 32bpp image.
@@ -696,7 +748,7 @@
      * The image is graylevel. Each pixel is floating-point and stored
      * in four bytes.
      **/
-    OrthancPluginPixelFormat_Float32 = 9,
+    OrthancPluginPixelFormat_Float32 ORTHANC_PLUGIN_SINCE_SDK("1.3.1") = 9,
 
     /**
      * @brief Color image in BGRA32 format.
@@ -704,7 +756,7 @@
      * This format describes a color image. The pixels are stored in 4
      * consecutive bytes. The memory layout is BGRA.
      **/
-    OrthancPluginPixelFormat_BGRA32 = 10,
+    OrthancPluginPixelFormat_BGRA32 ORTHANC_PLUGIN_SINCE_SDK("1.3.1") = 10,
 
     /**
      * @brief Graylevel, unsigned 64bpp image.
@@ -712,7 +764,7 @@
      * The image is graylevel. Each pixel is unsigned and stored in
      * eight bytes.
      **/
-    OrthancPluginPixelFormat_Grayscale64 = 11,
+    OrthancPluginPixelFormat_Grayscale64 ORTHANC_PLUGIN_SINCE_SDK("1.4.0") = 11,
 
     _OrthancPluginPixelFormat_INTERNAL = 0x7fffffff
   } OrthancPluginPixelFormat;
@@ -727,7 +779,7 @@
     OrthancPluginContentType_Unknown = 0,             /*!< Unknown content type */
     OrthancPluginContentType_Dicom = 1,               /*!< DICOM */
     OrthancPluginContentType_DicomAsJson = 2,         /*!< JSON summary of a DICOM file */
-    OrthancPluginContentType_DicomUntilPixelData = 3, /*!< DICOM Header till pixel data */
+    OrthancPluginContentType_DicomUntilPixelData ORTHANC_PLUGIN_SINCE_SDK("1.9.2") = 3, /*!< DICOM Header till pixel data */
 
     _OrthancPluginContentType_INTERNAL = 0x7fffffff
   } OrthancPluginContentType;
@@ -752,7 +804,7 @@
 
   /**
    * The supported types of changes that can be signaled to the change callback.
-   * Note: this enum is not used to store changes in the DB !
+   * Note: This enumeration is not used to store changes in the database!
    * @ingroup Callbacks
    **/
   typedef enum
@@ -771,11 +823,11 @@
     OrthancPluginChangeType_OrthancStopped = 11,    /*!< Orthanc is stopping */
     OrthancPluginChangeType_UpdatedAttachment = 12, /*!< Some user-defined attachment has changed for this resource */
     OrthancPluginChangeType_UpdatedMetadata = 13,   /*!< Some user-defined metadata has changed for this resource */
-    OrthancPluginChangeType_UpdatedPeers = 14,      /*!< The list of Orthanc peers has changed */
-    OrthancPluginChangeType_UpdatedModalities = 15, /*!< The list of DICOM modalities has changed */
-    OrthancPluginChangeType_JobSubmitted = 16,      /*!< New Job submitted */
-    OrthancPluginChangeType_JobSuccess = 17,        /*!< A Job has completed successfully */
-    OrthancPluginChangeType_JobFailure = 18,        /*!< A Job has failed */
+    OrthancPluginChangeType_UpdatedPeers ORTHANC_PLUGIN_SINCE_SDK("1.4.2") = 14,      /*!< The list of Orthanc peers has changed */
+    OrthancPluginChangeType_UpdatedModalities ORTHANC_PLUGIN_SINCE_SDK("1.4.2") = 15, /*!< The list of DICOM modalities has changed */
+    OrthancPluginChangeType_JobSubmitted ORTHANC_PLUGIN_SINCE_SDK("1.7.2") = 16,      /*!< New Job submitted */
+    OrthancPluginChangeType_JobSuccess ORTHANC_PLUGIN_SINCE_SDK("1.7.2") = 17,        /*!< A Job has completed successfully */
+    OrthancPluginChangeType_JobFailure ORTHANC_PLUGIN_SINCE_SDK("1.7.2") = 18,        /*!< A Job has failed */
 
     _OrthancPluginChangeType_INTERNAL = 0x7fffffff
   } OrthancPluginChangeType;
@@ -791,6 +843,7 @@
     OrthancPluginCompressionType_ZlibWithSize = 1,  /*!< zlib, prefixed with uncompressed size (uint64_t) */
     OrthancPluginCompressionType_Gzip = 2,          /*!< Standard gzip compression */
     OrthancPluginCompressionType_GzipWithSize = 3,  /*!< gzip, prefixed with uncompressed size (uint64_t) */
+    OrthancPluginCompressionType_None ORTHANC_PLUGIN_SINCE_SDK("1.12.8") = 4,  /*!< No compression (new in Orthanc 1.12.8) */
 
     _OrthancPluginCompressionType_INTERNAL = 0x7fffffff
   } OrthancPluginCompressionType;
@@ -877,8 +930,8 @@
     OrthancPluginDicomToJsonFlags_IncludePixelData      = (1 << 3),  /*!< Include the pixel data */
     OrthancPluginDicomToJsonFlags_ConvertBinaryToAscii  = (1 << 4),  /*!< Output binary tags as-is, dropping non-ASCII */
     OrthancPluginDicomToJsonFlags_ConvertBinaryToNull   = (1 << 5),  /*!< Signal binary tags as null values */
-    OrthancPluginDicomToJsonFlags_StopAfterPixelData    = (1 << 6),  /*!< Stop processing after pixel data (new in 1.9.1) */
-    OrthancPluginDicomToJsonFlags_SkipGroupLengths      = (1 << 7),  /*!< Skip tags whose element is zero (new in 1.9.1) */
+    OrthancPluginDicomToJsonFlags_StopAfterPixelData ORTHANC_PLUGIN_SINCE_SDK("1.9.1") = (1 << 6),  /*!< Stop processing after pixel data (new in 1.9.1) */
+    OrthancPluginDicomToJsonFlags_SkipGroupLengths ORTHANC_PLUGIN_SINCE_SDK("1.9.1")   = (1 << 7),  /*!< Skip tags whose element is zero (new in 1.9.1) */
 
     _OrthancPluginDicomToJsonFlags_INTERNAL = 0x7fffffff
   } OrthancPluginDicomToJsonFlags;
@@ -891,7 +944,7 @@
    **/
   typedef enum
   {
-    OrthancPluginCreateDicomFlags_None                  = 0,         /*!< Default mode */
+    OrthancPluginCreateDicomFlags_None ORTHANC_PLUGIN_SINCE_SDK("1.2.0") = 0,  /*!< Default mode */
     OrthancPluginCreateDicomFlags_DecodeDataUriScheme   = (1 << 0),  /*!< Decode fields encoded using data URI scheme */
     OrthancPluginCreateDicomFlags_GenerateIdentifiers   = (1 << 1),  /*!< Automatically generate DICOM identifiers */
 
@@ -941,7 +994,7 @@
     OrthancPluginInstanceOrigin_RestApi = 3,        /*!< Instance received through REST API of Orthanc */
     OrthancPluginInstanceOrigin_Plugin = 4,         /*!< Instance added to Orthanc by a plugin */
     OrthancPluginInstanceOrigin_Lua = 5,            /*!< Instance added to Orthanc by a Lua script */
-    OrthancPluginInstanceOrigin_WebDav = 6,         /*!< Instance received through WebDAV (new in 1.8.0) */
+    OrthancPluginInstanceOrigin_WebDav ORTHANC_PLUGIN_SINCE_SDK("1.8.0") = 6,  /*!< Instance received through WebDAV (new in 1.8.0) */
 
     _OrthancPluginInstanceOrigin_INTERNAL = 0x7fffffff
   } OrthancPluginInstanceOrigin;
@@ -950,7 +1003,7 @@
   /**
    * The possible status for one single step of a job.
    **/
-  typedef enum
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   {
     OrthancPluginJobStepStatus_Success = 1,   /*!< The job has successfully executed all its steps */
     OrthancPluginJobStepStatus_Failure = 2,   /*!< The job has failed while executing this step */
@@ -964,7 +1017,7 @@
    * the "paused" condition and the "final" conditions (success,
    * failure, or canceled).
    **/
-  typedef enum
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   {
     OrthancPluginJobStopReason_Success = 1,  /*!< The job has succeeded */
     OrthancPluginJobStopReason_Paused = 2,   /*!< The job was paused, and will be resumed later */
@@ -976,7 +1029,7 @@
   /**
    * The available types of metrics.
    **/
-  typedef enum
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.5.4")
   {
     OrthancPluginMetricsType_Default = 0,   /*!< Default metrics */
 
@@ -993,7 +1046,7 @@
    * The available modes to export a binary DICOM tag into a DICOMweb
    * JSON or XML document.
    **/
-  typedef enum
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.5.4")
   {
     OrthancPluginDicomWebBinaryMode_Ignore = 0,        /*!< Don't include binary tags */
     OrthancPluginDicomWebBinaryMode_InlineBinary = 1,  /*!< Inline encoding using Base64 */
@@ -1006,7 +1059,7 @@
    * storage commitment.
    * http://dicom.nema.org/medical/dicom/2019e/output/chtml/part03/sect_C.14.html#sect_C.14.1.1
    **/
-  typedef enum
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.6.0")
   {
     /**
      * Success: The DICOM instance is properly stored in the SCP
@@ -1054,7 +1107,7 @@
   /**
    * The action to be taken after ReceivedInstanceCallback is triggered
    **/
-  typedef enum
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.10.0")
   {
     OrthancPluginReceivedInstanceAction_KeepAsIs = 1, /*!< Keep the instance as is */
     OrthancPluginReceivedInstanceAction_Modify = 2,   /*!< Modify the instance */
@@ -1068,7 +1121,7 @@
    * Mode specifying how to load a DICOM instance.
    * @see OrthancPluginLoadDicomInstance()
    **/
-  typedef enum
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.12.1")
   {
     /**
      * Load the whole DICOM file, including pixel data
@@ -1098,7 +1151,7 @@
    * These values must match those of enumeration "LogLevel" in the
    * Orthanc Core.
    **/
-  typedef enum
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.12.4")
   {
     OrthancPluginLogLevel_Error = 0,    /*!< Error log level */
     OrthancPluginLogLevel_Warning = 1,  /*!< Warning log level */
@@ -1115,7 +1168,7 @@
    * These values must match those of enumeration "LogCategory" in the
    * Orthanc Core.
    **/
-  typedef enum
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.12.4")
   {
     OrthancPluginLogCategory_Generic = (1 << 0),  /*!< Generic (default) category */
     OrthancPluginLogCategory_Plugins = (1 << 1),  /*!< Plugin engine related logs (shall not be used by plugins) */
@@ -1130,6 +1183,59 @@
 
 
   /**
+   * The store status related to the adoption of a DICOM instance.
+   **/
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  {
+    OrthancPluginStoreStatus_Success = 0,         /*!< The file has been stored/adopted */
+    OrthancPluginStoreStatus_AlreadyStored = 1,   /*!< The file has already been stored/adopted (only if OverwriteInstances is set to false)*/
+    OrthancPluginStoreStatus_Failure = 2,         /*!< The file could not be stored/adopted */
+    OrthancPluginStoreStatus_FilteredOut = 3,     /*!< The file has been filtered out by a Lua script or a plugin */
+    OrthancPluginStoreStatus_StorageFull = 4,     /*!< The storage is full (only if MaximumStorageSize/MaximumPatientCount is set and MaximumStorageMode is Reject)*/
+
+    _OrthancPluginStoreStatus_INTERNAL = 0x7fffffff
+  } OrthancPluginStoreStatus;
+
+
+  /**
+   * The supported modes to remove an element from a queue.
+   **/
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  {
+    OrthancPluginQueueOrigin_Front = 0,    /*!< Dequeue from the front of the queue */
+    OrthancPluginQueueOrigin_Back = 1,     /*!< Dequeue from the back of the queue */
+
+    _OrthancPluginQueueOrigin_INTERNAL = 0x7fffffff
+  } OrthancPluginQueueOrigin;
+
+
+  /**
+   * The "Stable" status of a resource.
+   **/
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.12.9")
+  {
+    OrthancPluginStableStatus_Stable = 0,     /*!< The resource is stable */
+    OrthancPluginStableStatus_Unstable = 1,   /*!< The resource is unstable */
+
+    _OrthancPluginStableStatus_INTERNAL = 0x7fffffff
+  } OrthancPluginStableStatus;
+
+
+  /**
+   * Status associated with the authentication of a HTTP request.
+   **/
+  typedef enum ORTHANC_PLUGIN_SINCE_SDK("1.12.9")
+  {
+    OrthancPluginHttpAuthenticationStatus_Granted = 0,       /*!< The authentication has been granted */
+    OrthancPluginHttpAuthenticationStatus_Unauthorized = 1,  /*!< The authentication has failed (401 HTTP status) */
+    OrthancPluginHttpAuthenticationStatus_Forbidden = 2,     /*!< The authorization has failed (403 HTTP status) */
+    OrthancPluginHttpAuthenticationStatus_Redirect = 3,      /*!< Redirect to another path (307 HTTP status, e.g., for login) */
+
+    _OrthancPluginHttpAuthenticationStatus_INTERNAL = 0x7fffffff
+  } OrthancPluginHttpAuthenticationStatus;
+
+
+  /**
    * @brief A 32-bit memory buffer allocated by the core system of Orthanc.
    *
    * A memory buffer allocated by the core system of Orthanc. When the
@@ -1158,7 +1264,7 @@
    * content of the buffer is not useful anymore, it must be free by a
    * call to ::OrthancPluginFreeMemoryBuffer64().
    **/
-  typedef struct
+  ORTHANC_PLUGIN_SINCE_SDK("1.9.0") typedef struct
   {
     /**
      * @brief The content of the buffer.
@@ -1226,7 +1332,8 @@
    * @brief Opaque structure to an object that represents a C-Find query.
    * @ingroup DicomCallbacks
    **/
-  typedef struct _OrthancPluginFindQuery_t OrthancPluginFindQuery;
+  typedef struct ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
+    _OrthancPluginFindQuery_t OrthancPluginFindQuery;
 
 
 
@@ -1234,7 +1341,8 @@
    * @brief Opaque structure to an object that represents the answers to a C-Find query for worklists.
    * @ingroup DicomCallbacks
    **/
-  typedef struct _OrthancPluginFindAnswers_t OrthancPluginFindAnswers;
+  typedef struct ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
+    _OrthancPluginFindAnswers_t OrthancPluginFindAnswers;
 
 
 
@@ -1242,7 +1350,8 @@
    * @brief Opaque structure to an object that can be used to check whether a DICOM instance matches a C-Find query.
    * @ingroup Toolbox
    **/
-  typedef struct _OrthancPluginFindMatcher_t OrthancPluginFindMatcher;
+  typedef struct ORTHANC_PLUGIN_SINCE_SDK("1.2.0")
+    _OrthancPluginFindMatcher_t OrthancPluginFindMatcher;
 
 
   
@@ -1250,7 +1359,8 @@
    * @brief Opaque structure to the set of remote Orthanc Peers that are known to the local Orthanc server.
    * @ingroup Toolbox
    **/
-  typedef struct _OrthancPluginPeers_t OrthancPluginPeers;
+  typedef struct ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
+    _OrthancPluginPeers_t OrthancPluginPeers;
 
 
 
@@ -1258,7 +1368,8 @@
    * @brief Opaque structure to a job to be executed by Orthanc.
    * @ingroup Toolbox
    **/
-  typedef struct _OrthancPluginJob_t OrthancPluginJob;  
+  typedef struct ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
+    _OrthancPluginJob_t OrthancPluginJob;
 
 
 
@@ -1267,7 +1378,8 @@
    * document used in DICOMweb.
    * @ingroup Toolbox
    **/
-  typedef struct _OrthancPluginDicomWebNode_t OrthancPluginDicomWebNode;
+  typedef struct ORTHANC_PLUGIN_SINCE_SDK("1.5.4")
+    _OrthancPluginDicomWebNode_t OrthancPluginDicomWebNode;
 
   
 
@@ -1277,7 +1389,7 @@
    **/
   typedef OrthancPluginErrorCode (*OrthancPluginRestCallback) (
     OrthancPluginRestOutput* output,
-    const char* url,
+    const char* uri,
     const OrthancPluginHttpRequest* request);
 
 
@@ -1367,8 +1479,7 @@
    * @param type The content type corresponding to this file. 
    * @return 0 if success, other value if error.
    * @ingroup Callbacks
-   * @deprecated New plugins should use OrthancPluginStorageRead2
-   * 
+   *
    * @warning The "content" buffer *must* have been allocated using
    * the "malloc()" function of your C standard library (i.e. nor
    * "new[]", neither a pointer to a buffer). The "free()" function of
@@ -1443,6 +1554,83 @@
 
 
   /**
+   * @brief Callback for writing to the storage area.
+   *
+   * Signature of a callback function that is triggered when Orthanc writes a file to the storage area.
+   *
+   * @param customData Custom, plugin-specific data associated with the attachment (out).
+   * It must be allocated by the plugin using OrthancPluginCreateMemoryBuffer(). The core of Orthanc will free it.
+   * If the plugin does not generate custom data, leave `customData` unchanged; it will default to an empty value.
+   * @param uuid The UUID of the file.
+   * @param content The content of the file (might be compressed data).
+   * @param size The size of the file.
+   * @param type The content type corresponding to this file.
+   * @param compressionType The compression algorithm that was used to encode `content`
+   * (the absence of compression is indicated using `OrthancPluginCompressionType_None`).
+   * @param dicomInstance The DICOM instance being stored. Equals `NULL` if not storing a DICOM instance.
+   * @return 0 if success, other value if error.
+   * @ingroup Callbacks
+   **/
+  typedef OrthancPluginErrorCode (*OrthancPluginStorageCreate2) (
+    OrthancPluginMemoryBuffer* customData,
+    const char* uuid,
+    const void* content,
+    uint64_t size,
+    OrthancPluginContentType type,
+    OrthancPluginCompressionType compressionType,
+    const OrthancPluginDicomInstance* dicomInstance);
+
+
+
+  /**
+   * @brief Callback for reading a range of a file from the storage area.
+   *
+   * Signature of a callback function that is triggered when Orthanc
+   * reads a portion of a file from the storage area. Orthanc
+   * indicates the start position and the length of the range.
+   *
+   * @param target Memory buffer where to store the content of the range.
+   * The memory buffer is allocated and freed by Orthanc. The length of the range
+   * of interest corresponds to the size of this buffer.
+   * @param uuid The UUID of the file of interest.
+   * @param type The content type corresponding to this file.
+   * @param rangeStart Start position of the requested range in the file.
+   * @param customData The custom data of the file of interest.
+   * @param customDataSize The size of the custom data.
+   * @return 0 if success, other value if error.
+   * @ingroup Callbacks
+   **/
+  typedef OrthancPluginErrorCode (*OrthancPluginStorageReadRange2) (
+    OrthancPluginMemoryBuffer64* target,
+    const char* uuid,
+    OrthancPluginContentType type,
+    uint64_t rangeStart,
+    const void* customData,
+    uint32_t customDataSize);
+
+
+
+  /**
+   * @brief Callback for removing a file from the storage area.
+   *
+   * Signature of a callback function that is triggered when Orthanc
+   * deletes a file from the storage area.
+   *
+   * @param uuid The UUID of the file to be removed.
+   * @param type The content type corresponding to this file.
+   * @param customData The custom data of the file to be removed.
+   * @param customDataSize The size of the custom data.
+   * @return 0 if success, other value if error.
+   * @ingroup Callbacks
+   **/
+  typedef OrthancPluginErrorCode (*OrthancPluginStorageRemove2) (
+    const char* uuid,
+    OrthancPluginContentType type,
+    const void* customData,
+    uint32_t customDataSize);
+
+
+  /**
    * @brief Callback to handle the C-Find SCP requests for worklists.
    *
    * Signature of a callback function that is triggered when Orthanc
@@ -1509,6 +1697,10 @@
    * concurrently by different threads of the Web server of
    * Orthanc. You must implement proper locking if applicable.
    *
+   * Note that if you are using HTTP basic authentication, you can
+   * extract the username from the "Authorization" HTTP header. The
+   * value of that header contains username:pwd encoded in base64.
+   *
    * @param method The HTTP method used by the request.
    * @param uri The URI of interest.
    * @param ip The IP address of the HTTP client.
@@ -1984,6 +2176,7 @@
    * @see OrthancPluginCheckVersion()
    * @ingroup Callbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.4.0")
   ORTHANC_PLUGIN_INLINE int32_t  OrthancPluginCheckVersionAdvanced(
     OrthancPluginContext* context,
     int32_t expectedMajor,
@@ -2010,13 +2203,19 @@
         sizeof(int32_t) != sizeof(OrthancPluginIdentifierConstraint) ||
         sizeof(int32_t) != sizeof(OrthancPluginInstanceOrigin) ||
         sizeof(int32_t) != sizeof(OrthancPluginJobStepStatus) ||
+        sizeof(int32_t) != sizeof(OrthancPluginJobStopReason) ||
         sizeof(int32_t) != sizeof(OrthancPluginConstraintType) ||
         sizeof(int32_t) != sizeof(OrthancPluginMetricsType) ||
         sizeof(int32_t) != sizeof(OrthancPluginDicomWebBinaryMode) ||
         sizeof(int32_t) != sizeof(OrthancPluginStorageCommitmentFailureReason) ||
+        sizeof(int32_t) != sizeof(OrthancPluginReceivedInstanceAction) ||
         sizeof(int32_t) != sizeof(OrthancPluginLoadDicomInstanceMode) ||
         sizeof(int32_t) != sizeof(OrthancPluginLogLevel) ||
-        sizeof(int32_t) != sizeof(OrthancPluginLogCategory))
+        sizeof(int32_t) != sizeof(OrthancPluginLogCategory) ||
+        sizeof(int32_t) != sizeof(OrthancPluginStoreStatus) ||
+        sizeof(int32_t) != sizeof(OrthancPluginQueueOrigin) ||
+        sizeof(int32_t) != sizeof(OrthancPluginStableStatus) ||
+        sizeof(int32_t) != sizeof(OrthancPluginHttpAuthenticationStatus))
     {
       /* Mismatch in the size of the enumerations */
       return 0;
@@ -2128,6 +2327,7 @@
    * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
    * @param buffer The memory buffer to release.
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.9.0")
   ORTHANC_PLUGIN_INLINE void  OrthancPluginFreeMemoryBuffer64(
     OrthancPluginContext* context, 
     OrthancPluginMemoryBuffer64* buffer)
@@ -3323,7 +3523,7 @@
    * @param read The callback function to read a file from the custom storage area.
    * @param remove The callback function to remove a file from the custom storage area.
    * @ingroup Callbacks
-   * @deprecated Please use OrthancPluginRegisterStorageArea2()
+   * @deprecated New plugins should use OrthancPluginRegisterStorageArea3()
    **/
   ORTHANC_PLUGIN_DEPRECATED ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterStorageArea(
     OrthancPluginContext*       context,
@@ -4911,6 +5111,8 @@
    * @ingroup Callbacks
    * @deprecated This function should not be used anymore. Use "OrthancPluginRestApiPut()" on
    * "/{patients|studies|series|instances}/{id}/attachments/{name}" instead.
+   * @warning This function will result in a "not implemented" error on versions of the
+   * Orthanc core above 1.12.6.
    **/
   ORTHANC_PLUGIN_DEPRECATED ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginStorageAreaCreate(
     OrthancPluginContext*       context,
@@ -4955,6 +5157,8 @@
    * @ingroup Callbacks
    * @deprecated This function should not be used anymore. Use "OrthancPluginRestApiGet()" on
    * "/{patients|studies|series|instances}/{id}/attachments/{name}" instead.
+   * @warning This function will result in a "not implemented" error on versions of the
+   * Orthanc core above 1.12.6.
    **/
   ORTHANC_PLUGIN_DEPRECATED ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginStorageAreaRead(
     OrthancPluginContext*       context,
@@ -4994,6 +5198,8 @@
    * @ingroup Callbacks
    * @deprecated This function should not be used anymore. Use "OrthancPluginRestApiDelete()" on
    * "/{patients|studies|series|instances}/{id}/attachments/{name}" instead.
+   * @warning This function will result in a "not implemented" error on versions of the
+   * Orthanc core above 1.12.6.
    **/
   ORTHANC_PLUGIN_DEPRECATED ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginStorageAreaRemove(
     OrthancPluginContext*       context,
@@ -5143,6 +5349,7 @@
    * @see OrthancPluginRegisterDictionaryTag()
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.2.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginRegisterPrivateDictionaryTag(
     OrthancPluginContext*             context,
     uint16_t                          group,
@@ -5935,6 +6142,7 @@
    * @see OrthancPluginSendMultipartItem()
    * @ingroup REST
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.0.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSendMultipartItem2(
     OrthancPluginContext*    context,
     OrthancPluginRestOutput* output,
@@ -5973,6 +6181,7 @@
    * @ingroup Callbacks
    * @deprecated Please instead use OrthancPluginRegisterIncomingHttpRequestFilter2()
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
   ORTHANC_PLUGIN_DEPRECATED ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterIncomingHttpRequestFilter(
     OrthancPluginContext*                   context,
     OrthancPluginIncomingHttpRequestFilter  callback)
@@ -6048,6 +6257,7 @@
    * @see OrthancPluginCallPeerApi()
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginHttpClient(
     OrthancPluginContext*       context,
     OrthancPluginMemoryBuffer*  answerBody,
@@ -6103,6 +6313,7 @@
    * containing the UUID. This string must be freed by OrthancPluginFreeString().
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
   ORTHANC_PLUGIN_INLINE char* OrthancPluginGenerateUuid(
     OrthancPluginContext*  context)
   {
@@ -6142,6 +6353,7 @@
    * @return 0 if success, other value if error.
    * @ingroup DicomCallbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterFindCallback(
     OrthancPluginContext*      context,
     OrthancPluginFindCallback  callback)
@@ -6181,6 +6393,7 @@
    * @ingroup DicomCallbacks
    * @see OrthancPluginCreateDicom()
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginFindAddAnswer(
     OrthancPluginContext*      context,
     OrthancPluginFindAnswers*  answers,
@@ -6210,6 +6423,7 @@
    * @return 0 if success, other value if error.
    * @ingroup DicomCallbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginFindMarkIncomplete(
     OrthancPluginContext*      context,
     OrthancPluginFindAnswers*  answers)
@@ -6234,6 +6448,7 @@
    * @return The number of tags.
    * @ingroup DicomCallbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
   ORTHANC_PLUGIN_INLINE uint32_t  OrthancPluginGetFindQuerySize(
     OrthancPluginContext*          context,
     const OrthancPluginFindQuery*  query)
@@ -6271,6 +6486,7 @@
    * @return 0 if success, other value if error.
    * @ingroup DicomCallbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginGetFindQueryTag(
     OrthancPluginContext*          context,
     uint16_t*                      group,
@@ -6302,6 +6518,7 @@
    * @return 0 if success, other value if error.
    * @ingroup DicomCallbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
   ORTHANC_PLUGIN_INLINE char*  OrthancPluginGetFindQueryTagName(
     OrthancPluginContext*          context,
     const OrthancPluginFindQuery*  query,
@@ -6340,6 +6557,7 @@
    * @return 0 if success, other value if error.
    * @ingroup DicomCallbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
   ORTHANC_PLUGIN_INLINE char*  OrthancPluginGetFindQueryValue(
     OrthancPluginContext*          context,
     const OrthancPluginFindQuery*  query,
@@ -6388,6 +6606,7 @@
    * @return 0 if success, other value if error.
    * @ingroup DicomCallbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.1.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterMoveCallback(
     OrthancPluginContext*       context,
     OrthancPluginMoveCallback   callback,
@@ -6427,6 +6646,7 @@
    * @return The newly allocated matcher. It must be freed with OrthancPluginFreeFindMatcher().
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.2.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginFindMatcher* OrthancPluginCreateFindMatcher(
     OrthancPluginContext*  context,
     const void*            query,
@@ -6465,6 +6685,7 @@
    * @param matcher The matcher of interest.
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.2.0")
   ORTHANC_PLUGIN_INLINE void  OrthancPluginFreeFindMatcher(
     OrthancPluginContext*     context, 
     OrthancPluginFindMatcher* matcher)
@@ -6498,6 +6719,7 @@
    * @return 1 if the DICOM instance matches the query, 0 otherwise.
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.2.0")
   ORTHANC_PLUGIN_INLINE int32_t  OrthancPluginFindMatcherIsMatch(
     OrthancPluginContext*            context,
     const OrthancPluginFindMatcher*  matcher,
@@ -6540,6 +6762,7 @@
    * @return 0 if success, other value if error.
    * @ingroup Callbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.3.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterIncomingHttpRequestFilter2(
     OrthancPluginContext*                   context,
     OrthancPluginIncomingHttpRequestFilter2 callback)
@@ -6568,6 +6791,7 @@
    * This structure must be freed with OrthancPluginFreePeers().
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   ORTHANC_PLUGIN_INLINE OrthancPluginPeers* OrthancPluginGetPeers(
     OrthancPluginContext*  context)
   {
@@ -6602,6 +6826,7 @@
    * @param peers The data structure describing the Orthanc peers.
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   ORTHANC_PLUGIN_INLINE void  OrthancPluginFreePeers(
     OrthancPluginContext*     context, 
     OrthancPluginPeers* peers)
@@ -6632,6 +6857,7 @@
    * @result The number of peers. 
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   ORTHANC_PLUGIN_INLINE uint32_t OrthancPluginGetPeersCount(
     OrthancPluginContext*      context,
     const OrthancPluginPeers*  peers)
@@ -6680,6 +6906,7 @@
    * @result The symbolic name, or NULL in the case of an error.
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetPeerName(
     OrthancPluginContext*      context,
     const OrthancPluginPeers*  peers,
@@ -6721,6 +6948,7 @@
    * @result The URL, or NULL in the case of an error.
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetPeerUrl(
     OrthancPluginContext*      context,
     const OrthancPluginPeers*  peers,
@@ -6767,6 +6995,7 @@
    * @result The value of the user property, or NULL if it is not defined.
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetPeerUserProperty(
     OrthancPluginContext*      context,
     const OrthancPluginPeers*  peers,
@@ -6848,6 +7077,7 @@
    * @see OrthancPluginHttpClient()
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginCallPeerApi(
     OrthancPluginContext*       context,
     OrthancPluginMemoryBuffer*  answerBody,
@@ -6934,6 +7164,7 @@
    * @ingroup Toolbox
    * @deprecated This signature should not be used anymore since Orthanc SDK 1.11.3.
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   ORTHANC_PLUGIN_DEPRECATED ORTHANC_PLUGIN_INLINE OrthancPluginJob *OrthancPluginCreateJob(
     OrthancPluginContext           *context,
     void                           *job,
@@ -7020,6 +7251,7 @@
    * as long as it is not submitted with OrthancPluginSubmitJob().
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.11.3")
   ORTHANC_PLUGIN_INLINE OrthancPluginJob *OrthancPluginCreateJob2(
     OrthancPluginContext           *context,
     void                           *job,
@@ -7075,6 +7307,7 @@
    * @param job The job.
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   ORTHANC_PLUGIN_INLINE void  OrthancPluginFreeJob(
     OrthancPluginContext* context, 
     OrthancPluginJob*     job)
@@ -7107,6 +7340,7 @@
    * @return ID of the newly-submitted job. This string must be freed by OrthancPluginFreeString().
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   ORTHANC_PLUGIN_INLINE char *OrthancPluginSubmitJob(
     OrthancPluginContext   *context,
     OrthancPluginJob       *job,
@@ -7152,6 +7386,7 @@
    * @param unserializer The job unserializer.
    * @ingroup Callbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.4.2")
   ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterJobsUnserializer(
     OrthancPluginContext*          context,
     OrthancPluginJobsUnserializer  unserializer)
@@ -7188,6 +7423,7 @@
    * @param log Whether to also write the detailed error to the Orthanc logs.
    * @ingroup REST
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.5.0")
   ORTHANC_PLUGIN_INLINE void OrthancPluginSetHttpErrorDetails(
     OrthancPluginContext*    context,
     OrthancPluginRestOutput* output,
@@ -7220,6 +7456,7 @@
    * string, do not free it.
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.5.0")
   ORTHANC_PLUGIN_INLINE const char* OrthancPluginAutodetectMimeType(
     OrthancPluginContext*  context,
     const char*            path)
@@ -7266,6 +7503,7 @@
    * @ingroup Toolbox
    * @see OrthancPluginSetMetricsIntegerValue()
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.5.4")
   ORTHANC_PLUGIN_INLINE void OrthancPluginSetMetricsValue(
     OrthancPluginContext*     context,
     const char*               name,
@@ -7297,6 +7535,7 @@
    * @param callback The callback function to handle the refresh.
    * @ingroup Callbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.5.4")
   ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterRefreshMetricsCallback(
     OrthancPluginContext*               context,
     OrthancPluginRefreshMetricsCallback callback)
@@ -7333,6 +7572,7 @@
    * @deprecated OrthancPluginEncodeDicomWebJson2()
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.5.4")
   ORTHANC_PLUGIN_DEPRECATED ORTHANC_PLUGIN_INLINE char* OrthancPluginEncodeDicomWebJson(
     OrthancPluginContext*                context,
     const void*                          dicom,
@@ -7375,6 +7615,7 @@
    * @deprecated OrthancPluginEncodeDicomWebXml2()
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.5.4")
   ORTHANC_PLUGIN_DEPRECATED ORTHANC_PLUGIN_INLINE char* OrthancPluginEncodeDicomWebXml(
     OrthancPluginContext*                context,
     const void*                          dicom,
@@ -7427,6 +7668,7 @@
    * @see OrthancPluginCreateDicom()
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE char* OrthancPluginEncodeDicomWebJson2(
     OrthancPluginContext*                 context,
     const void*                           dicom,
@@ -7471,6 +7713,7 @@
    * @see OrthancPluginCreateDicom()
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE char* OrthancPluginEncodeDicomWebXml2(
     OrthancPluginContext*                 context,
     const void*                           dicom,
@@ -7684,6 +7927,7 @@
    * @see OrthancPluginHttpClient()
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.5.7")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginChunkedHttpClient(
     OrthancPluginContext*                          context,
     void*                                          answer,
@@ -7745,7 +7989,8 @@
    * @brief Opaque structure that reads the content of a HTTP request body during a chunked HTTP transfer.
    * @ingroup Callbacks
    **/
-  typedef struct _OrthancPluginServerChunkedRequestReader_t OrthancPluginServerChunkedRequestReader;
+  typedef struct ORTHANC_PLUGIN_SINCE_SDK("1.5.7")
+    _OrthancPluginServerChunkedRequestReader_t OrthancPluginServerChunkedRequestReader;
 
 
 
@@ -7760,13 +8005,13 @@
    * 
    * @see OrthancPluginRegisterChunkedRestCallback()
    * @param reader Memory location that must be filled with the newly-created reader.
-   * @param url The URI that is accessed.
+   * @param uri The URI that is accessed.
    * @param request The body of the HTTP request. Note that "body" and "bodySize" are not used.
    * @return 0 if success, or the error code if failure.
    **/
   typedef OrthancPluginErrorCode (*OrthancPluginServerChunkedRequestReaderFactory) (
     OrthancPluginServerChunkedRequestReader**  reader,
-    const char*                                url,
+    const char*                                uri,
     const OrthancPluginHttpRequest*            request);
 
   
@@ -7866,6 +8111,7 @@
    *
    * @ingroup Callbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.5.7")
   ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterChunkedRestCallback(
     OrthancPluginContext*                            context,
     const char*                                      pathRegularExpression,
@@ -7917,6 +8163,7 @@
    * OrthancPluginFreeString().
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.5.7")
   ORTHANC_PLUGIN_INLINE char* OrthancPluginGetTagName(
     OrthancPluginContext*  context,
     uint16_t               group,
@@ -8042,6 +8289,7 @@
    * @return 0 if success, other value if error.
    * @ingroup DicomCallbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.6.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterStorageCommitmentScpCallback(
     OrthancPluginContext*                     context,
     OrthancPluginStorageCommitmentFactory     factory,
@@ -8103,6 +8351,7 @@
    * @return 0 if success, other value if error.
    * @ingroup Callbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.6.1")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterIncomingDicomInstanceFilter(
     OrthancPluginContext*                     context,
     OrthancPluginIncomingDicomInstanceFilter  callback)
@@ -8166,6 +8415,7 @@
    * @return 0 if success, other value if error.
    * @ingroup Callbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.10.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterIncomingCStoreInstanceFilter(
     OrthancPluginContext*                      context,
     OrthancPluginIncomingCStoreInstanceFilter  callback)
@@ -8243,6 +8493,7 @@
    * @return 0 if success, other value if error.
    * @ingroup Callbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.10.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterReceivedInstanceCallback(
     OrthancPluginContext*                     context,
     OrthancPluginReceivedInstanceCallback     callback)
@@ -8266,6 +8517,7 @@
    * transfer syntax UID. This string must be freed by OrthancPluginFreeString().
    * @ingroup DicomInstance
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.6.1")
   ORTHANC_PLUGIN_INLINE char* OrthancPluginGetInstanceTransferSyntaxUid(
     OrthancPluginContext*              context,
     const OrthancPluginDicomInstance*  instance)
@@ -8301,6 +8553,7 @@
    * the tag is missing, or "-1" in the case of an error.
    * @ingroup DicomInstance
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.6.1")
   ORTHANC_PLUGIN_INLINE int32_t OrthancPluginHasInstancePixelData(
     OrthancPluginContext*             context,
     const OrthancPluginDicomInstance* instance)
@@ -8351,6 +8604,7 @@
    * @return The newly allocated DICOM instance. It must be freed with OrthancPluginFreeDicomInstance().
    * @ingroup DicomInstance
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginDicomInstance* OrthancPluginCreateDicomInstance(
     OrthancPluginContext*  context,
     const void*            buffer,
@@ -8389,6 +8643,7 @@
    * @param dicom The DICOM instance.
    * @ingroup DicomInstance
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE void  OrthancPluginFreeDicomInstance(
     OrthancPluginContext*        context, 
     OrthancPluginDicomInstance*  dicom)
@@ -8426,6 +8681,7 @@
    * @return The number of frames (will be zero in the case of an error).
    * @ingroup DicomInstance
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE uint32_t OrthancPluginGetInstanceFramesCount(
     OrthancPluginContext*             context,
     const OrthancPluginDicomInstance* instance)
@@ -8466,6 +8722,7 @@
    * @return 0 if success, or the error code if failure.
    * @ingroup DicomInstance
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginGetInstanceRawFrame(
     OrthancPluginContext*             context,
     OrthancPluginMemoryBuffer*        target,
@@ -8494,6 +8751,7 @@
    * @return The uncompressed image. It must be freed with OrthancPluginFreeImage().
    * @ingroup DicomInstance
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginImage* OrthancPluginGetInstanceDecodedFrame(
     OrthancPluginContext*             context,
     const OrthancPluginDicomInstance* instance,
@@ -8533,6 +8791,7 @@
    * @return The newly allocated DICOM instance. It must be freed with OrthancPluginFreeDicomInstance().
    * @ingroup DicomInstance
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginDicomInstance* OrthancPluginTranscodeDicomInstance(
     OrthancPluginContext*  context,
     const void*            buffer,
@@ -8571,6 +8830,7 @@
    * @return 0 if success, or the error code if failure.
    * @ingroup DicomInstance
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSerializeDicomInstance(
     OrthancPluginContext*             context,
     OrthancPluginMemoryBuffer*        target,
@@ -8603,6 +8863,7 @@
    * @ingroup DicomInstance
    * @see OrthancPluginDicomBufferToJson()
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE char* OrthancPluginGetInstanceAdvancedJson(
     OrthancPluginContext*              context,
     const OrthancPluginDicomInstance*  instance,
@@ -8646,6 +8907,7 @@
    * be freed by OrthancPluginFreeString().
    * @ingroup DicomInstance
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE char* OrthancPluginGetInstanceDicomWebJson(
     OrthancPluginContext*                 context,
     const OrthancPluginDicomInstance*     instance,
@@ -8686,6 +8948,7 @@
    * be freed by OrthancPluginFreeString().
    * @ingroup DicomInstance
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE char* OrthancPluginGetInstanceDicomWebXml(
     OrthancPluginContext*                 context,
     const OrthancPluginDicomInstance*     instance,
@@ -8758,6 +9021,7 @@
    * @return 0 if success, other value if error.
    * @ingroup Callbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterTranscoderCallback(
     OrthancPluginContext*            context,
     OrthancPluginTranscoderCallback  callback)
@@ -8793,6 +9057,7 @@
    * @return 0 if success, or the error code if failure.
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.7.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginCreateMemoryBuffer(
     OrthancPluginContext*       context,
     OrthancPluginMemoryBuffer*  target,
@@ -8831,6 +9096,7 @@
    * This string must be freed by OrthancPluginFreeString().
    * @ingroup Orthanc
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.8.1")
   ORTHANC_PLUGIN_INLINE char* OrthancPluginGenerateRestApiAuthorizationToken(
     OrthancPluginContext*  context)
   {
@@ -8877,6 +9143,7 @@
    * @return 0 if success, or the error code if failure.
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.9.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginCreateMemoryBuffer64(
     OrthancPluginContext*         context,
     OrthancPluginMemoryBuffer64*  target,
@@ -8913,7 +9180,9 @@
    * If this feature is not supported by the plugin, this value can be set to NULL.
    * @param remove The callback function to remove a file from the custom storage area.
    * @ingroup Callbacks
-   **/
+   * @deprecated New plugins should use OrthancPluginRegisterStorageArea3()
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.9.0")
   ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterStorageArea2(
     OrthancPluginContext*          context,
     OrthancPluginStorageCreate     create,
@@ -8961,6 +9230,7 @@
    * @see OrthancPluginCreateDicom()
    * @see OrthancPluginDicomBufferToJson()
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.9.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginCreateDicom2(
     OrthancPluginContext*          context,
     OrthancPluginMemoryBuffer*     target,
@@ -9029,6 +9299,7 @@
    * @see OrthancPluginRestApiGet2(), OrthancPluginRestApiPost(), OrthancPluginRestApiPut(), OrthancPluginRestApiDelete()
    * @ingroup Orthanc
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.9.2")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginCallRestApi(
     OrthancPluginContext*       context,
     OrthancPluginMemoryBuffer*  answerBody,
@@ -9067,7 +9338,8 @@
    * @brief Opaque structure that represents a WebDAV collection.
    * @ingroup Callbacks
    **/
-  typedef struct _OrthancPluginWebDavCollection_t OrthancPluginWebDavCollection;
+  typedef struct ORTHANC_PLUGIN_SINCE_SDK("1.10.1")
+    _OrthancPluginWebDavCollection_t OrthancPluginWebDavCollection;
 
 
   /**
@@ -9310,6 +9582,7 @@
    * @return 0 if success, other value if error.
    * @ingroup Callbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.10.1")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterWebDavCollection(
     OrthancPluginContext*                        context,
     const char*                                  uri,
@@ -9343,6 +9616,7 @@
    * string, do not free it.
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.11.1")
   ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetDatabaseServerIdentifier(
     OrthancPluginContext*  context)
   {
@@ -9364,6 +9638,41 @@
   }
 
 
+  typedef struct
+  {
+    OrthancPluginStorageCreate2     create;
+    OrthancPluginStorageReadRange2  readRange;
+    OrthancPluginStorageRemove2     remove;
+  } _OrthancPluginRegisterStorageArea3;
+
+  /**
+   * @brief Register a custom storage area, with support for custom data.
+   *
+   * This function registers a custom storage area, to replace the
+   * built-in way Orthanc stores its files on the filesystem. This
+   * function must be called during the initialization of the plugin,
+   * i.e. inside the OrthancPluginInitialize() public function.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param create The callback function to store a file on the custom storage area.
+   * @param readRange The callback function to read some range of a file from the custom storage area.
+   * @param remove The callback function to remove a file from the custom storage area.
+   * @ingroup Callbacks
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterStorageArea3(
+    OrthancPluginContext*           context,
+    OrthancPluginStorageCreate2     create,
+    OrthancPluginStorageReadRange2  readRange,
+    OrthancPluginStorageRemove2     remove)
+  {
+    _OrthancPluginRegisterStorageArea3 params;
+    params.create = create;
+    params.readRange = readRange;
+    params.remove = remove;
+    context->InvokeService(context, _OrthancPluginService_RegisterStorageArea3, &params);
+  }
+
   /**
    * @brief Signature of a callback function that is triggered when
    * the Orthanc core requests an operation from the database plugin.
@@ -9408,6 +9717,7 @@
    * @return 0 if success, other value if error.
    * @ingroup Callbacks
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.0")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterDatabaseBackendV4(
     OrthancPluginContext*                   context,
     void*                                   backend,
@@ -9445,6 +9755,7 @@
    * @return The newly allocated DICOM instance. It must be freed with OrthancPluginFreeDicomInstance().
    * @ingroup DicomInstance
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.1")
   ORTHANC_PLUGIN_INLINE OrthancPluginDicomInstance* OrthancPluginLoadDicomInstance(
     OrthancPluginContext*               context,
     const char*                         instanceId,
@@ -9491,6 +9802,7 @@
    * @ingroup Toolbox
    * @see OrthancPluginSetMetricsValue()
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.1")
   ORTHANC_PLUGIN_INLINE void OrthancPluginSetMetricsIntegerValue(
     OrthancPluginContext*     context,
     const char*               name,
@@ -9518,6 +9830,7 @@
    * @return 0 if success, other value if error.
    * @ingroup Toolbox
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.2")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSetCurrentThreadName(
     OrthancPluginContext*  context,
     const char*            threadName)
@@ -9551,6 +9864,7 @@
    * @param category The category.
    * @param level The level of the message.
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.4")
   ORTHANC_PLUGIN_INLINE void OrthancPluginLogMessage(
     OrthancPluginContext* context,
     const char* message,
@@ -9589,6 +9903,7 @@
    * @see OrthancPluginSendStreamChunk()
    * @ingroup REST
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.6")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginStartStreamAnswer(
     OrthancPluginContext*    context,
     OrthancPluginRestOutput* output,
@@ -9616,6 +9931,7 @@
    * @see OrthancPluginStartStreamAnswer()
    * @ingroup REST
    **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.6")
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSendStreamChunk(
     OrthancPluginContext*    context,
     OrthancPluginRestOutput* output,
@@ -9631,10 +9947,765 @@
   }
 
 
+  typedef struct
+  {
+    OrthancPluginMemoryBuffer*    instanceId;
+    OrthancPluginMemoryBuffer*    attachmentUuid;
+    OrthancPluginStoreStatus*     storeStatus;
+    const void*                   dicom;
+    uint64_t                      dicomSize;
+    const void*                   customData;
+    uint32_t                      customDataSize;
+  } _OrthancPluginAdoptDicomInstance;
+
+  /**
+   * @brief Adopt a DICOM instance read from the filesystem.
+   *
+   * This function requests Orthanc to create a DICOM resource at the
+   * "Instance" level in its database, using the content of a DICOM
+   * instance read from the filesystem. The newly created DICOM
+   * resource is associated with an attachment whose content type is
+   * "OrthancPluginContentType_Dicom". The attachment is associated
+   * with the provided custom data.
+   *
+   * This function should only be used in combination with a custom
+   * storage area featuring support for custom data (i.e., installed
+   * using OrthancPluginRegisterStorageArea3()). The custom storage
+   * area is responsible for *not* duplicating the DICOM file into the
+   * storage area of Orthanc, hence the name "Adopt". The support for
+   * custom data is necessary for the custom storage area to
+   * distinguish between adopted and non-adopted DICOM instances.
+   *
+   * Check out the "AdoptDicomInstance" plugin in the source
+   * distribution of Orthanc for a working sample:
+   * https://orthanc.uclouvain.be/hg/orthanc/file/default/OrthancServer/Plugins/Samples/AdoptDicomInstance/
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param instanceId The target memory buffer that will be filled by
+   * the Orthanc core with the public identifier of the newly created
+   * instance. It must be freed with OrthancPluginFreeMemoryBuffer().
+   * @param attachmentUuid The target memory buffer that will be
+   * filled by the Orthanc core with the UUID of the newly created
+   * attachment corresponding to the adopted DICOM instance. It must
+   * be freed with OrthancPluginFreeMemoryBuffer().
+   * @param storeStatus Variable that will be filled by the Orthanc core
+   * with the status of store operation.
+   * @param dicom Pointer to the DICOM instance read from the filesystem.
+   * @param dicomSize Size of the DICOM instance.
+   * @param customData The custom data to associated with the attachment.
+   * @param customDataSize The size of the custom data.
+   * @return 0 if success, other value if error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginAdoptDicomInstance(
+    OrthancPluginContext*         context,
+    OrthancPluginMemoryBuffer*    instanceId,        /* out */
+    OrthancPluginMemoryBuffer*    attachmentUuid,    /* out */
+    OrthancPluginStoreStatus*     storeStatus,       /* out */
+    const void*                   dicom,
+    uint64_t                      dicomSize,
+    const void*                   customData,
+    uint32_t                      customDataSize)
+  {
+    _OrthancPluginAdoptDicomInstance params;
+    params.instanceId = instanceId;
+    params.attachmentUuid = attachmentUuid;
+    params.storeStatus = storeStatus;
+    params.dicom = dicom;
+    params.dicomSize = dicomSize;
+    params.customData = customData;
+    params.customDataSize = customDataSize;
+
+    return context->InvokeService(context, _OrthancPluginService_AdoptDicomInstance, &params);
+  }
+
+
+  typedef struct
+  {
+    OrthancPluginMemoryBuffer*    customData;
+    const char*                   attachmentUuid;
+  } _OrthancPluginGetAttachmentCustomData;
+
+  /**
+   * @brief Retrieve the custom data associated with an attachment in the Orthanc database.
+   *
+   * If no custom data is associated with the attachment of interest,
+   * the target memory buffer is filled with the NULL value and a zero size.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param customData Memory buffer where to store the retrieved value. It must be freed
+   * by the plugin by calling OrthancPluginFreeMemoryBuffer().
+   * @param attachmentUuid The UUID of the attachment of interest.
+   * @return 0 if success, other value if error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginGetAttachmentCustomData(
+    OrthancPluginContext*         context,
+    OrthancPluginMemoryBuffer*    customData,     /* out */
+    const char*                   attachmentUuid  /* in */)
+  {
+    _OrthancPluginGetAttachmentCustomData params;
+    params.customData = customData;
+    params.attachmentUuid = attachmentUuid;
+
+    return context->InvokeService(context, _OrthancPluginService_GetAttachmentCustomData, &params);
+  }
+
+
+  typedef struct
+  {
+    const char*  attachmentUuid;
+    const void*  customData;
+    uint32_t     customDataSize;
+  } _OrthancPluginSetAttachmentCustomData;
+
+  /**
+   * @brief Update the custom data associated with an attachment in the Orthanc database.
+   *
+   * This function is notably used in the "orthanc-advanced-storage"
+   * when the plugin moves an attachment.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param attachmentUuid The UUID of the attachment of interest.
+   * @param customData The value to store.
+   * @param customDataSize The size of the value to store.
+   * @return 0 if success, other value if error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSetAttachmentCustomData(
+    OrthancPluginContext*         context,
+    const char*                   attachmentUuid, /* in */
+    const void*                   customData,     /* in */
+    uint32_t                      customDataSize  /* in */)
+  {
+    _OrthancPluginSetAttachmentCustomData params;
+    params.attachmentUuid = attachmentUuid;
+    params.customData = customData;
+    params.customDataSize = customDataSize;
+
+    return context->InvokeService(context, _OrthancPluginService_SetAttachmentCustomData, &params);
+  }
+
+
+  typedef struct
+  {
+    const char*                   storeId;
+    const char*                   key;
+    const void*                   value;
+    uint32_t                      valueSize;
+  } _OrthancPluginStoreKeyValue;
+
+  /**
+   * @brief Store a key-value pair in the Orthanc database.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param storeId A unique identifier identifying both the plugin and the key-value store.
+   * @param key The key of the value to store (note: storeId + key must be unique).
+   * @param value The value to store.
+   * @param valueSize The length of the value to store.
+   * @return 0 if success, other value if error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginStoreKeyValue(
+    OrthancPluginContext*         context,
+    const char*                   storeId,  /* in */
+    const char*                   key,      /* in */
+    const void*                   value,    /* in */
+    uint32_t                      valueSize /* in */)
+  {
+    _OrthancPluginStoreKeyValue params;
+    params.storeId = storeId;
+    params.key = key;
+    params.value = value;
+    params.valueSize = valueSize;
+
+    return context->InvokeService(context, _OrthancPluginService_StoreKeyValue, &params);
+  }
+
+
+  typedef struct
+  {
+    const char*                   storeId;
+    const char*                   key;
+  } _OrthancPluginDeleteKeyValue;
+
+  /**
+   * @brief Delete a key-value pair from the Orthanc database.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param storeId A unique identifier identifying both the plugin and the key-value store.
+   * @param key The key of the value to store (note: storeId + key must be unique).
+   * @return 0 if success, other value if error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginDeleteKeyValue(
+    OrthancPluginContext*         context,
+    const char*                   storeId, /* in */
+    const char*                   key      /* in */)
+  {
+    _OrthancPluginDeleteKeyValue params;
+    params.storeId = storeId;
+    params.key = key;
+
+    return context->InvokeService(context, _OrthancPluginService_DeleteKeyValue, &params);
+  }
+
+
+  typedef struct
+  {
+    uint8_t*                      found;
+    OrthancPluginMemoryBuffer*    target;
+    const char*                   storeId;
+    const char*                   key;
+  } _OrthancPluginGetKeyValue;
+
+  /**
+   * @brief Get the value associated with a key in the Orthanc key-value store.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param found Pointer to a Boolean that is set to "true" iff. the key exists in the key-value store.
+   * @param target Memory buffer where to store the retrieved value. It must be freed
+   * by the plugin by calling OrthancPluginFreeMemoryBuffer().
+   * @param storeId A unique identifier identifying both the plugin and the key-value store.
+   * @param key The key of the value to retrieve from the store (note: storeId + key must be unique).
+   * @return 0 if success, other value if error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginGetKeyValue(
+    OrthancPluginContext*         context,
+    uint8_t*                      found,   /* out */
+    OrthancPluginMemoryBuffer*    target,  /* out */
+    const char*                   storeId, /* in */
+    const char*                   key      /* in */)
+  {
+    _OrthancPluginGetKeyValue params;
+    params.found = found;
+    params.target = target;
+    params.storeId = storeId;
+    params.key = key;
+
+    return context->InvokeService(context, _OrthancPluginService_GetKeyValue, &params);
+  }
+
+
+  /**
+   * @brief Opaque structure that represents an iterator over the keys and values of
+   * a key-value store.
+   * @ingroup Callbacks
+   **/
+  typedef struct ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+    _OrthancPluginKeysValuesIterator_t OrthancPluginKeysValuesIterator;
+
+
+  typedef struct
+  {
+    OrthancPluginKeysValuesIterator**  target;
+    const char*                        storeId;
+  } _OrthancPluginCreateKeysValuesIterator;
+
+
+  /**
+   * @brief Create an iterator over the key-value pairs of a key-value store in the Orthanc database.
+   *
+   * The iterator loops over the keys according to the lexicographical order.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param storeId A unique identifier identifying both the plugin and the key-value store.
+   * @return The newly allocated iterator, or NULL in the case of an error.
+   * The iterator must be freed by calling OrthancPluginFreeKeysValuesIterator().
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE OrthancPluginKeysValuesIterator* OrthancPluginCreateKeysValuesIterator(
+    OrthancPluginContext*  context,
+    const char*            storeId)
+  {
+    OrthancPluginKeysValuesIterator* target = NULL;
+
+    _OrthancPluginCreateKeysValuesIterator params;
+    params.target = &target;
+    params.storeId = storeId;
+
+    if (context->InvokeService(context, _OrthancPluginService_CreateKeysValuesIterator, &params) != OrthancPluginErrorCode_Success)
+    {
+      return NULL;
+    }
+    else
+    {
+      return target;
+    }
+  }
+
+
+  typedef struct
+  {
+    OrthancPluginKeysValuesIterator*   iterator;
+  } _OrthancPluginFreeKeysValuesIterator;
+
+  /**
+   * @brief Free an iterator over a key-value store.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param iterator The iterator of interest.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE void  OrthancPluginFreeKeysValuesIterator(
+    OrthancPluginContext*             context,
+    OrthancPluginKeysValuesIterator*  iterator)
+  {
+    _OrthancPluginFreeKeysValuesIterator params;
+    params.iterator = iterator;
+
+    context->InvokeService(context, _OrthancPluginService_FreeKeysValuesIterator, &params);
+  }
+
+
+  typedef struct
+  {
+    uint8_t*                          done;
+    OrthancPluginKeysValuesIterator*  iterator;
+  } _OrthancPluginKeysValuesIteratorNext;
+
+  /**
+   * @brief Read the next element of an iterator over a key-value store.
+  *
+   * The iterator loops over the keys according to the lexicographical order.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param done Pointer to a Boolean that is set to "true" iff. the iterator has reached the end of the store.
+   * @param iterator The iterator of interest.
+   * @return 0 if success, other value if error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginKeysValuesIteratorNext(
+    OrthancPluginContext*             context,
+    uint8_t*                          done,     /* out */
+    OrthancPluginKeysValuesIterator*  iterator  /* in */)
+  {
+    _OrthancPluginKeysValuesIteratorNext params;
+    params.done = done;
+    params.iterator = iterator;
+
+    return context->InvokeService(context, _OrthancPluginService_KeysValuesIteratorNext, &params);
+  }
+
+
+  typedef struct
+  {
+    const char**                      target;
+    OrthancPluginKeysValuesIterator*  iterator;
+  } _OrthancPluginKeysValuesIteratorGetKey;
+
+  /**
+   * @brief Get the current key of an iterator over a key-value store.
+   *
+   * Before using this function, the function OrthancPluginKeysValuesIteratorNext()
+   * must have been called at least once.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param iterator The iterator of interest.
+   * @return The current key, or NULL in the case of an error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE const char* OrthancPluginKeysValuesIteratorGetKey(
+    OrthancPluginContext*             context,
+    OrthancPluginKeysValuesIterator*  iterator)
+  {
+    const char* target = NULL;
+
+    _OrthancPluginKeysValuesIteratorGetKey params;
+    params.target = &target;
+    params.iterator = iterator;
+
+    if (context->InvokeService(context, _OrthancPluginService_KeysValuesIteratorGetKey, &params) == OrthancPluginErrorCode_Success)
+    {
+      return target;
+    }
+    else
+    {
+      return NULL;
+    }
+  }
+
+
+  typedef struct
+  {
+    OrthancPluginMemoryBuffer*        target;
+    OrthancPluginKeysValuesIterator*  iterator;
+  } _OrthancPluginKeysValuesIteratorGetValue;
+
+  /**
+   * @brief Get the current value of an iterator over a key-value store.
+   *
+   * Before using this function, the function OrthancPluginKeysValuesIteratorNext()
+   * must have been called at least once.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param target Memory buffer where to store the value that has been retrieved from the key-value store.
+   * It must be freed with OrthancPluginFreeMemoryBuffer().
+   * @param iterator The iterator of interest.
+   * @return The current value, or NULL in the case of an error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginKeysValuesIteratorGetValue(
+    OrthancPluginContext*             context,
+    OrthancPluginMemoryBuffer*        target   /* out */,
+    OrthancPluginKeysValuesIterator*  iterator /* in */)
+  {
+    _OrthancPluginKeysValuesIteratorGetValue params;
+    params.target = target;
+    params.iterator = iterator;
+
+    return context->InvokeService(context, _OrthancPluginService_KeysValuesIteratorGetValue, &params);
+  }
+
+
+  typedef struct
+  {
+    const char*                   queueId;
+    const void*                   value;
+    uint32_t                      valueSize;
+  } _OrthancPluginEnqueueValue;
+
+  /**
+   * @brief Append a value to the back of a queue.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param queueId A unique identifier identifying both the plugin and the queue.
+   * @param value The value to store.
+   * @param valueSize The size of the value to store.
+   * @return 0 if success, other value if error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginEnqueueValue(
+    OrthancPluginContext*         context,
+    const char*                   queueId,  /* in */
+    const void*                   value,    /* in */
+    uint32_t                      valueSize /* in */)
+  {
+    _OrthancPluginEnqueueValue params;
+    params.queueId = queueId;
+    params.value = value;
+    params.valueSize = valueSize;
+
+    return context->InvokeService(context, _OrthancPluginService_EnqueueValue, &params);
+  }
+
+
+  typedef struct
+  {
+    uint8_t*                      found;
+    OrthancPluginMemoryBuffer*    target;
+    const char*                   queueId;
+    OrthancPluginQueueOrigin      origin;
+  } _OrthancPluginDequeueValue;
+
+  /**
+   * @brief Dequeue a value from a queue.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param found Pointer to a Boolean that is set to "true" iff. a value has been dequeued.
+   * @param target Memory buffer where to store the value that has been retrieved from the queue.
+   * It must be freed with OrthancPluginFreeMemoryBuffer().
+   * @param queueId A unique identifier identifying both the plugin and the queue.
+   * @param origin The position from where the value is dequeued (back for LIFO, front for FIFO).
+   * @return 0 if success, other value if error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginDequeueValue(
+    OrthancPluginContext*         context,
+    uint8_t*                      found,    /* out */
+    OrthancPluginMemoryBuffer*    target,   /* out */
+    const char*                   queueId,  /* in */
+    OrthancPluginQueueOrigin      origin    /* in */)
+  {
+    _OrthancPluginDequeueValue params;
+    params.found = found;
+    params.target = target;
+    params.queueId = queueId;
+    params.origin = origin;
+
+    return context->InvokeService(context, _OrthancPluginService_DequeueValue, &params);
+  }
+
+
+  typedef struct
+  {
+    const char*                   queueId;
+    uint64_t*                     size;
+  } _OrthancPluginGetQueueSize;
+
+  /**
+   * @brief Get the number of elements in a queue.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param queueId A unique identifier identifying both the plugin and the queue.
+   * @param size The number of elements in the queue.
+   * @return 0 if success, other value if error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.8")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginGetQueueSize(
+    OrthancPluginContext*         context,
+    const char*                   queueId, /* in */
+    uint64_t*                     size /* out */)
+  {
+    _OrthancPluginGetQueueSize params;
+    params.queueId = queueId;
+    params.size = size;
+
+    return context->InvokeService(context, _OrthancPluginService_GetQueueSize, &params);
+  }
+
+
+  typedef struct
+  {
+    const char*                   resourceId;
+    OrthancPluginStableStatus     stableStatus;
+    uint8_t*                      statusHasChanged;
+  } _OrthancPluginSetStableStatus;
+
+  /**
+   * @brief Change the "Stable" status of a resource.
+   *
+   * Forcing a resource to "Stable" if it is currently "Unstable" will
+   * change its "Stable" status AND trigger a new "Stable" change,
+   * which will also trigger listener callbacks.
+   *
+   * Forcing a resource to "Stable" if it is already "Stable" has no
+   * effect (no-op).
+   *
+   * Forcing a resource to "Unstable" will change its "Stable" status
+   * to "Unstable" AND reset its stabilization period, no matter its
+   * initial state.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param statusHasChanged Whether the status has changed (1) or not (0) during the execution of this command.
+   * @param resourceId The Orthanc identifier of the DICOM resource of interest.
+   * @param stableStatus The new stable status of the resource of interest.
+   * @return 0 if success, other value if error.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.9")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSetStableStatus(
+    OrthancPluginContext*         context,
+    uint8_t*                      statusHasChanged,  /* out */
+    const char*                   resourceId,  /* in */
+    OrthancPluginStableStatus     stableStatus /* in */)
+  {
+    _OrthancPluginSetStableStatus params;
+    params.resourceId = resourceId;
+    params.stableStatus= stableStatus;
+    params.statusHasChanged = statusHasChanged;
+
+    return context->InvokeService(context, _OrthancPluginService_SetStableStatus, &params);
+  }
+
+
+  /**
+   * @brief Callback to authenticate a HTTP request.
+   *
+   * Signature of a callback function that authenticates every incoming HTTP request.
+   *
+   * @param status The output status of the authentication.
+   * @param customPayload If status is `OrthancPluginHttpAuthenticationStatus_Granted`,
+   * a custom payload that will be provided to the HTTP handler callback.
+   * @param redirection If status is `OrthancPluginHttpAuthenticationStatus_Redirect`,
+   * a buffer filled with the path where to redirect the user (typically, a login page).
+   * The path is relative to the root of the Web server of Orthanc.
+   * @param uri The URI of interest (without the possible GET arguments).
+   * @param ip The IP address of the HTTP client.
+   * @param headersCount The number of HTTP headers.
+   * @param headersKeys The keys of the HTTP headers (always converted to low-case).
+   * @param headersValues The values of the HTTP headers.
+   * @param getCount For a GET request, the number of GET parameters.
+   * @param getKeys For a GET request, the keys of the GET parameters.
+   * @param getValues For a GET request, the values of the GET parameters.
+   * @return 0 if success, other value if error.
+   * @ingroup Callbacks
+   **/
+  typedef OrthancPluginErrorCode (*OrthancPluginHttpAuthentication) (
+    OrthancPluginHttpAuthenticationStatus*  status,         /* out */
+    OrthancPluginMemoryBuffer*              customPayload,  /* out */
+    OrthancPluginMemoryBuffer*              redirection,    /* out */
+    const char*                             uri,
+    const char*                             ip,
+    uint32_t                                headersCount,
+    const char* const*                      headersKeys,
+    const char* const*                      headersValues,
+    uint32_t                                getCount,
+    const char* const*                      getKeys,
+    const char* const*                      getValues);
+
+
+  typedef struct
+  {
+    OrthancPluginHttpAuthentication  callback;
+  } _OrthancPluginHttpAuthentication;
+
+  /**
+   * @brief Register a callback to handle HTTP authentication (and
+   * possibly HTTP authorization).
+   *
+   * This function installs a callback that is executed for each
+   * incoming HTTP request to handle HTTP authentication. At most one
+   * plugin can register such a callback. This gives the opportunity
+   * to the plugin to validate access tokens (such as a JWT), possibly
+   * redirecting the user to a login page. The authentication callback
+   * can generate a custom payload that will be provided to the
+   * subsequent REST handling callback (cf. `authenticationPayload` in
+   * `OrthancPluginHttpRequest`).
+   *
+   * If one plugin installs a HTTP authentication callback, the
+   * built-in HTTP authentication of Orthanc is disabled. This means
+   * that the "RegisteredUsers" and "AuthenticationEnabled"
+   * configuration options of Orthanc are totally ignored. In
+   * addition, tokens generated by
+   * OrthancPluginGenerateRestApiAuthorizationToken() become
+   * ineffective.
+   *
+   * This HTTP authentication callback can notably be used if some
+   * resource in the REST API must be available for public access, if
+   * the "RemoteAccessAllowed" configuration option is set to "true"
+   * (which necessitates bypassing the built-in HTTP authentication of
+   * Orthanc).
+   *
+   * In addition, the callback can handle HTTP authorization
+   * simultaneously with HTTP authentication, by reporting the
+   * "OrthancPluginHttpAuthenticationStatus_Forbidden" status. This
+   * corresponds to the behavior of callbacks installed using
+   * OrthancPluginRegisterIncomingHttpRequestFilter2(), but the latter
+   * callbacks do not provide access to the authentication payload.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param callback The HTTP authentication callback.
+   * @return 0 if success, other value if error.
+   * @ingroup Callbacks
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.9")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterHttpAuthentication(
+    OrthancPluginContext*            context,
+    OrthancPluginHttpAuthentication  callback)
+  {
+    _OrthancPluginHttpAuthentication params;
+    params.callback = callback;
+
+    return context->InvokeService(context, _OrthancPluginService_RegisterHttpAuthentication, &params);
+  }
+
+
+  typedef struct
+  {
+    const char*               sourcePlugin;
+    const char*               userId;
+    OrthancPluginResourceType resourceType;
+    const char*               resourceId;
+    const char*               action;
+    const void*               logData;
+    uint32_t                  logDataSize;
+  } _OrthancPluginEmitAuditLog;
+
+
+  /**
+   * @brief Generate an audit log to signal security-related events.
+   *
+   * Generate an audit log that will be broadcasted to all the plugins
+   * that have registered a callback handler using
+   * OrthancPluginRegisterAuditLogHandler(). If no plugin has
+   * registered such a callback, the audit log is ignored.
+   *
+   * A typical handler would record the audit log in a database and/or
+   * relay the audit log to a message broker.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param sourcePlugin The name of the source plugin, to properly interpret the
+   * content of "action" and "logData".
+   * @param userId A string that uniquely identifies the user or
+   * entity that is executing the action on the resource.
+   * @param resourceType The type of the resource this audit log relates to.
+   * @param resourceId The resource this audit log relates to.
+   * @param action The action that was performed on the resource.
+   * @param logData A pointer to custom log data.
+   * @param logDataSize The size of the custom log data.
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.9")
+  ORTHANC_PLUGIN_INLINE void OrthancPluginEmitAuditLog(
+    OrthancPluginContext*     context,
+    const char*               sourcePlugin,
+    const char*               userId,
+    OrthancPluginResourceType resourceType,
+    const char*               resourceId,
+    const char*               action,
+    const void*               logData,
+    uint32_t                  logDataSize)
+  {
+    _OrthancPluginEmitAuditLog m;
+    m.sourcePlugin = sourcePlugin;
+    m.userId = userId;
+    m.resourceType = resourceType;
+    m.resourceId = resourceId;
+    m.action = action;
+    m.logData = logData;
+    m.logDataSize = logDataSize;
+    context->InvokeService(context, _OrthancPluginService_EmitAuditLog, &m);
+  }
+
+
+  /**
+   * @brief Callback to handle an audit log.
+   *
+   * Signature of a callback function that handles an audit log
+   * emitted by a source plugin.
+   *
+   * @param sourcePlugin The name of the source plugin. This information can
+   * be used to properly interpret the content of the "action" and
+   * "logData" arguments.
+   * @param userId A string uniquely identifying the user or entity that is executing the action on the resource.
+   * @param resourceType The type of the resource this log relates to.
+   * @param resourceId The resource this log relates to.
+   * @param action The action that is performed on the resource.
+   * @param logData A pointer to custom log data.
+   * @param logDataSize The size of the custom log data.
+   * @return 0 if success, other value if error.
+   * @ingroup Callbacks
+   **/
+  typedef OrthancPluginErrorCode (*OrthancPluginAuditLogHandler) (
+    const char*               sourcePlugin,
+    const char*               userId,
+    OrthancPluginResourceType resourceType,
+    const char*               resourceId,
+    const char*               action,
+    const void*               logData,
+    uint32_t                  logDataSize);
+
+  typedef struct
+  {
+    OrthancPluginAuditLogHandler  handler;
+  } _OrthancPluginAuditLogHandler;
+
+  /**
+   * @brief Register a callback to handle audit logs.
+   *
+   * This function installs a callback to listen to each audit log
+   * that is generated by some other plugin.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param handler The audit log handler.
+   * @return 0 if success, other value if error.
+   * @ingroup Callbacks
+   **/
+  ORTHANC_PLUGIN_SINCE_SDK("1.12.9")
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterAuditLogHandler(
+    OrthancPluginContext*            context,
+    OrthancPluginAuditLogHandler     handler)
+  {
+    _OrthancPluginAuditLogHandler params;
+    params.handler = handler;
+
+    return context->InvokeService(context, _OrthancPluginService_RegisterAuditLogHandler, &params);
+  }
+
+
 #ifdef  __cplusplus
 }
 #endif
 
 
 /** @} */
-
--- a/Resources/SyncOrthancFolder.py	Mon Aug 11 13:03:13 2025 +0200
+++ b/Resources/SyncOrthancFolder.py	Tue Aug 12 07:59:46 2025 +0200
@@ -37,14 +37,9 @@
 import urllib.request
 
 TARGET = os.path.join(os.path.dirname(__file__), 'Orthanc')
-ORTHANC_JAVA_VERSION = 'default'
-ORTHANC_CORE_REPOSITORY = 'https://orthanc.uclouvain.be/hg/orthanc/raw-file'
-ORTHANC_JAVA_REPOSITORY = 'https://orthanc.uclouvain.be/hg/orthanc-java/raw-file'
-
-with open(os.path.join(os.path.dirname(__file__), '..', 'OrthancSDKVersion.cmake'), 'r') as f:
-    m = re.match('^set\(ORTHANC_SDK_VERSION "([0-9.]+)"\)$', f.read(), re.MULTILINE)
-    assert(m != None)
-    PLUGIN_SDK_VERSION = m.group(1)
+REPOSITORY = 'https://orthanc.uclouvain.be/hg/orthanc/raw-file'
+PLUGIN_SDK_VERSIONS = [ '1.12.6', '1.12.9' ]
+PLUGIN_CODE_MODEL_VERSION = '1.12.9'
 
 
 FILES = [
@@ -66,12 +61,17 @@
     ('OrthancServer/Plugins/Samples/Common/VersionScriptPlugins.map', 'Plugins'),
 ]
 
+SDK = [
+    'orthanc/OrthancCPlugin.h',
+]
+
+CODE_MODEL = 'orthanc/OrthancPluginCodeModel.json'
+
 
 def Download(x):
-    repository = x[0]
-    branch = x[1]
-    source = x[2]
-    target = os.path.join(TARGET, x[3])
+    branch = x[0]
+    source = x[1]
+    target = os.path.join(TARGET, x[2])
     print(target)
 
     try:
@@ -79,7 +79,7 @@
     except:
         pass
 
-    url = '%s/%s/%s' % (repository, branch, source)
+    url = '%s/%s/%s' % (REPOSITORY, branch, source)
 
     with open(target, 'wb') as f:
         try:
@@ -93,35 +93,25 @@
 
 for f in FILES:
     commands.append([
-        ORTHANC_CORE_REPOSITORY,
         'default',
         f[0],
         os.path.join(f[1], os.path.basename(f[0]))
     ])
 
+for f in SDK:
+    for version in PLUGIN_SDK_VERSIONS:
+        commands.append([
+            'Orthanc-%s' % version,
+            'OrthancServer/Plugins/Include/%s' % f,
+            'Sdk-%s/%s' % (version, f)
+        ])
 
 commands.append([
-    ORTHANC_JAVA_REPOSITORY,
-    ORTHANC_JAVA_VERSION,
-    'Resources/Orthanc/Sdk-%s/orthanc/OrthancCPlugin.h' % PLUGIN_SDK_VERSION,
-    'Sdk-%s/orthanc/OrthancCPlugin.h' % PLUGIN_SDK_VERSION,
+    'Orthanc-%s' % version,
+    'OrthancServer/Plugins/Include/%s' % CODE_MODEL,
+    'Sdk-%s/%s' % (version, CODE_MODEL)
 ])
 
 
-for f in [
-        ('ClassDocumentation.json',         'CodeGeneration/ClassDocumentation.json'),
-        ('ClassDocumentation.json.license', 'CodeGeneration/ClassDocumentation.json.license'),
-        ('CodeModel.json',                  'Resources/CodeModel-%s.json' % PLUGIN_SDK_VERSION),
-        ('CodeModel.json.license',          'Resources/CodeModel-%s.json.license' % PLUGIN_SDK_VERSION),
-        ]:
-    commands.append([
-        ORTHANC_JAVA_REPOSITORY,
-        ORTHANC_JAVA_VERSION,
-        f[1],
-        'Sdk-%s/%s' % (PLUGIN_SDK_VERSION, f[0]),
-    ])
-
-
-
 pool = multiprocessing.Pool(10)  # simultaneous downloads
 pool.map(Download, commands)
--- a/Sources/Autogenerated/orthanc.pyi	Mon Aug 11 13:03:13 2025 +0200
+++ b/Sources/Autogenerated/orthanc.pyi	Tue Aug 12 07:59:46 2025 +0200
@@ -31,7 +31,7 @@
 
 class ChangeType():
     """
-    The supported types of changes that can be signaled to the change callback. Note: This enumeration is not used to store changes in the database!
+    The supported types of changes that can be signaled to the change callback. Note: this enum is not used to store changes in the DB !
     """
 
     """
@@ -154,11 +154,6 @@
     """
     GZIP_WITH_SIZE: int = 3,
 
-    """
-    No compression (new in Orthanc 1.12.8)
-    """
-    NONE: int = 4,
-
 class ConstraintType():
     """
     The constraints on the tags (main DICOM tags and identifier tags) that must be supported by the database plugins.
@@ -889,31 +884,6 @@
     """
     UNSUPPORTED_MEDIA_TYPE: int = 3000,
 
-class HttpAuthenticationStatus():
-    """
-    Status associated with the authentication of a HTTP request.
-    """
-
-    """
-    The authentication has been granted
-    """
-    GRANTED: int = 0,
-
-    """
-    The authentication has failed (401 HTTP status)
-    """
-    UNAUTHORIZED: int = 1,
-
-    """
-    The authorization has failed (403 HTTP status)
-    """
-    FORBIDDEN: int = 2,
-
-    """
-    Redirect to another path (307 HTTP status, e.g., for login)
-    """
-    REDIRECT: int = 3,
-
 class HttpMethod():
     """
     The various HTTP methods for a REST call.
@@ -1224,21 +1194,6 @@
     """
     GRAYSCALE64: int = 11,
 
-class QueueOrigin():
-    """
-    The supported modes to remove an element from a queue.
-    """
-
-    """
-    Dequeue from the front of the queue
-    """
-    FRONT: int = 0,
-
-    """
-    Dequeue from the back of the queue
-    """
-    BACK: int = 1,
-
 class ReceivedInstanceAction():
     """
     The action to be taken after ReceivedInstanceCallback is triggered
@@ -1289,21 +1244,6 @@
     """
     NONE: int = 4,
 
-class StableStatus():
-    """
-    The "Stable" status of a resource.
-    """
-
-    """
-    The resource is stable
-    """
-    STABLE: int = 0,
-
-    """
-    The resource is unstable
-    """
-    UNSTABLE: int = 1,
-
 class StorageCommitmentFailureReason():
     """
     The available values for the Failure Reason (0008,1197) during storage commitment. http://dicom.nema.org/medical/dicom/2019e/output/chtml/part03/sect_C.14.html#sect_C.14.1.1
@@ -1344,36 +1284,6 @@
     """
     DUPLICATE_TRANSACTION_UID: int = 6,
 
-class StoreStatus():
-    """
-    The store status related to the adoption of a DICOM instance.
-    """
-
-    """
-    The file has been stored/adopted
-    """
-    SUCCESS: int = 0,
-
-    """
-    The file has already been stored/adopted (only if OverwriteInstances is set to false)
-    """
-    ALREADY_STORED: int = 1,
-
-    """
-    The file could not be stored/adopted
-    """
-    FAILURE: int = 2,
-
-    """
-    The file has been filtered out by a Lua script or a plugin
-    """
-    FILTERED_OUT: int = 3,
-
-    """
-    The storage is full (only if MaximumStorageSize/MaximumPatientCount is set and MaximumStorageMode is Reject)
-    """
-    STORAGE_FULL: int = 4,
-
 class ValueRepresentation():
     """
     The value representations present in the DICOM standard (version 2013).
@@ -1704,19 +1614,6 @@
     """
     ...
 
-# The iterator loops over the keys according to the lexicographical order
-def CreateKeysValuesIterator(store_id: str) -> KeysValuesIterator:
-    """
-    The iterator loops over the keys according to the lexicographical order.
-
-    Args:
-      store_id (str): A unique identifier identifying both the plugin and the key-value store.
-
-    Returns:
-      KeysValuesIterator: The newly allocated iterator, or NULL in the case of an error. The iterator must be freed by calling OrthancPluginFreeKeysValuesIterator().
-    """
-    ...
-
 # This function decodes one frame of a DICOM image that is stored in a memory buffer
 def DecodeDicomImage(buffer: bytes, frame_index: int) -> Image:
     """
@@ -1731,15 +1628,6 @@
     """
     ...
 
-def DeleteKeyValue(store_id: str, key: str) -> None:
-    """
-
-    Args:
-      store_id (str): A unique identifier identifying both the plugin and the key-value store.
-      key (str): The key of the value to store (note: storeId + key must be unique).
-    """
-    ...
-
 # This function takes as input a memory buffer containing a DICOM file, and outputs a JSON string representing the tags of this DICOM file
 def DicomBufferToJson(buffer: bytes, format: DicomToJsonFormat, flags: DicomToJsonFlags, max_string_length: int) -> str:
     """
@@ -1772,31 +1660,6 @@
     """
     ...
 
-# Generate an audit log that will be broadcasted to all the plugins that have registered a callback handler using OrthancPluginRegisterAuditLogHandler()
-def EmitAuditLog(source_plugin: str, user_id: str, resource_type: ResourceType, resource_id: str, action: str, log_data: bytes) -> None:
-    """
-    Generate an audit log that will be broadcasted to all the plugins that have registered a callback handler using OrthancPluginRegisterAuditLogHandler(). If no plugin has registered such a callback, the audit log is ignored.
-    A typical handler would record the audit log in a database and/or relay the audit log to a message broker.
-
-    Args:
-      source_plugin (str): The name of the source plugin, to properly interpret the content of "action" and "logData".
-      user_id (str): A string that uniquely identifies the user or entity that is executing the action on the resource.
-      resource_type (ResourceType): The type of the resource this audit log relates to.
-      resource_id (str): The resource this audit log relates to.
-      action (str): The action that was performed on the resource.
-      log_data (bytes): A pointer to custom log data.
-    """
-    ...
-
-def EnqueueValue(queue_id: str, value: bytes) -> None:
-    """
-
-    Args:
-      queue_id (str): A unique identifier identifying both the plugin and the queue.
-      value (bytes): The value to store.
-    """
-    ...
-
 # Add JavaScript code to customize the default behavior of Orthanc Explorer
 def ExtendOrthancExplorer(javascript: str) -> None:
     """
@@ -1840,19 +1703,6 @@
     """
     ...
 
-# If no custom data is associated with the attachment of interest, the target memory buffer is filled with the NULL value and a zero size
-def GetAttachmentCustomData(attachment_uuid: str) -> bytes:
-    """
-    If no custom data is associated with the attachment of interest, the target memory buffer is filled with the NULL value and a zero size.
-
-    Args:
-      attachment_uuid (str): The UUID of the attachment of interest.
-
-    Returns:
-      bytes: 0 if success, other value if error.
-    """
-    ...
-
 # Get the value of one of the command-line arguments that were used to launch Orthanc
 def GetCommandLineArgument(argument: int) -> str:
     """
@@ -2384,17 +2234,6 @@
     """
     ...
 
-# This function is notably used in the "orthanc-advanced-storage" when the plugin moves an attachment
-def SetAttachmentCustomData(attachment_uuid: str, custom_data: bytes) -> None:
-    """
-    This function is notably used in the "orthanc-advanced-storage" when the plugin moves an attachment.
-
-    Args:
-      attachment_uuid (str): The UUID of the attachment of interest.
-      custom_data (bytes): The value to store.
-    """
-    ...
-
 # This function gives a name to the thread that is calling this function
 def SetCurrentThreadName(thread_name: str) -> None:
     """
@@ -2470,16 +2309,6 @@
     """
     ...
 
-def StoreKeyValue(store_id: str, key: str, value: bytes) -> None:
-    """
-
-    Args:
-      store_id (str): A unique identifier identifying both the plugin and the key-value store.
-      key (str): The key of the value to store (note: storeId + key must be unique).
-      value (bytes): The value to store.
-    """
-    ...
-
 # This function parses a memory buffer that contains a DICOM file, then transcodes it to the given transfer syntax
 def TranscodeDicomInstance(buffer: bytes, transfer_syntax: str) -> DicomInstance:
     """
@@ -3163,33 +2992,6 @@
         """
         ...
 
-class KeysValuesIterator:
-    """
-    Key-Value store iterator
-    """
-    ...
-
-    
-    # Before using this function, the function OrthancPluginKeysValuesIteratorNext() must have been called at least once
-    def KeysValuesIteratorGetKey(self) -> str:
-        """
-        Before using this function, the function OrthancPluginKeysValuesIteratorNext() must have been called at least once.
-
-        Returns:
-          str: The current key, or NULL in the case of an error.
-        """
-        ...
-    
-    # Before using this function, the function OrthancPluginKeysValuesIteratorNext() must have been called at least once
-    def KeysValuesIteratorGetValue(self) -> bytes:
-        """
-        Before using this function, the function OrthancPluginKeysValuesIteratorNext() must have been called at least once.
-
-        Returns:
-          bytes: The current value, or NULL in the case of an error.
-        """
-        ...
-
 class Peers:
     """
     Orthanc peer
@@ -3442,7 +3244,6 @@
     def StorageAreaCreate(self, uuid: str, content: bytes, size: int, type: ContentType) -> None:
         """
         This function creates a new file inside the storage area that is currently used by Orthanc.
-        Warning: This function will result in a "not implemented" error on versions of the Orthanc core above 1.12.6.
 
         Args:
           uuid (str): The identifier of the file to be created.
@@ -3456,7 +3257,6 @@
     def StorageAreaRead(self, uuid: str, type: ContentType) -> bytes:
         """
         This function reads the content of a given file from the storage area that is currently used by Orthanc.
-        Warning: This function will result in a "not implemented" error on versions of the Orthanc core above 1.12.6.
 
         Args:
           uuid (str): The identifier of the file to be read.
@@ -3471,7 +3271,6 @@
     def StorageAreaRemove(self, uuid: str, type: ContentType) -> None:
         """
         This function removes a given file from the storage area that is currently used by Orthanc.
-        Warning: This function will result in a "not implemented" error on versions of the Orthanc core above 1.12.6.
 
         Args:
           uuid (str): The identifier of the file to be removed.
--- a/Sources/Autogenerated/sdk.cpp	Mon Aug 11 13:03:13 2025 +0200
+++ b/Sources/Autogenerated/sdk.cpp	Tue Aug 12 07:59:46 2025 +0200
@@ -43,7 +43,6 @@
 #include "./sdk_OrthancPluginDicomToJsonFormat.impl.h"
 #include "./sdk_OrthancPluginDicomWebBinaryMode.impl.h"
 #include "./sdk_OrthancPluginErrorCode.impl.h"
-#include "./sdk_OrthancPluginHttpAuthenticationStatus.impl.h"
 #include "./sdk_OrthancPluginHttpMethod.impl.h"
 #include "./sdk_OrthancPluginIdentifierConstraint.impl.h"
 #include "./sdk_OrthancPluginImageFormat.impl.h"
@@ -55,12 +54,9 @@
 #include "./sdk_OrthancPluginLogLevel.impl.h"
 #include "./sdk_OrthancPluginMetricsType.impl.h"
 #include "./sdk_OrthancPluginPixelFormat.impl.h"
-#include "./sdk_OrthancPluginQueueOrigin.impl.h"
 #include "./sdk_OrthancPluginReceivedInstanceAction.impl.h"
 #include "./sdk_OrthancPluginResourceType.impl.h"
-#include "./sdk_OrthancPluginStableStatus.impl.h"
 #include "./sdk_OrthancPluginStorageCommitmentFailureReason.impl.h"
-#include "./sdk_OrthancPluginStoreStatus.impl.h"
 #include "./sdk_OrthancPluginValueRepresentation.impl.h"
 
 #include "./sdk_OrthancPluginDicomInstance.impl.h"
@@ -70,7 +66,6 @@
 #include "./sdk_OrthancPluginFindQuery.impl.h"
 #include "./sdk_OrthancPluginImage.impl.h"
 #include "./sdk_OrthancPluginJob.impl.h"
-#include "./sdk_OrthancPluginKeysValuesIterator.impl.h"
 #include "./sdk_OrthancPluginPeers.impl.h"
 #include "./sdk_OrthancPluginRestOutput.impl.h"
 #include "./sdk_OrthancPluginServerChunkedRequestReader.impl.h"
@@ -88,7 +83,6 @@
 #include "./sdk_OrthancPluginFindQuery.methods.h"
 #include "./sdk_OrthancPluginImage.methods.h"
 #include "./sdk_OrthancPluginJob.methods.h"
-#include "./sdk_OrthancPluginKeysValuesIterator.methods.h"
 #include "./sdk_OrthancPluginPeers.methods.h"
 #include "./sdk_OrthancPluginRestOutput.methods.h"
 #include "./sdk_OrthancPluginServerChunkedRequestReader.methods.h"
@@ -108,7 +102,6 @@
   RegisterOrthancPluginDicomToJsonFormatEnumeration(module);
   RegisterOrthancPluginDicomWebBinaryModeEnumeration(module);
   RegisterOrthancPluginErrorCodeEnumeration(module);
-  RegisterOrthancPluginHttpAuthenticationStatusEnumeration(module);
   RegisterOrthancPluginHttpMethodEnumeration(module);
   RegisterOrthancPluginIdentifierConstraintEnumeration(module);
   RegisterOrthancPluginImageFormatEnumeration(module);
@@ -120,12 +113,9 @@
   RegisterOrthancPluginLogLevelEnumeration(module);
   RegisterOrthancPluginMetricsTypeEnumeration(module);
   RegisterOrthancPluginPixelFormatEnumeration(module);
-  RegisterOrthancPluginQueueOriginEnumeration(module);
   RegisterOrthancPluginReceivedInstanceActionEnumeration(module);
   RegisterOrthancPluginResourceTypeEnumeration(module);
-  RegisterOrthancPluginStableStatusEnumeration(module);
   RegisterOrthancPluginStorageCommitmentFailureReasonEnumeration(module);
-  RegisterOrthancPluginStoreStatusEnumeration(module);
   RegisterOrthancPluginValueRepresentationEnumeration(module);
 
   RegisterOrthancPluginDicomInstanceClass(module);
@@ -135,7 +125,6 @@
   RegisterOrthancPluginFindQueryClass(module);
   RegisterOrthancPluginImageClass(module);
   RegisterOrthancPluginJobClass(module);
-  RegisterOrthancPluginKeysValuesIteratorClass(module);
   RegisterOrthancPluginPeersClass(module);
   RegisterOrthancPluginRestOutputClass(module);
   RegisterOrthancPluginServerChunkedRequestReaderClass(module);
--- a/Sources/Autogenerated/sdk.h	Mon Aug 11 13:03:13 2025 +0200
+++ b/Sources/Autogenerated/sdk.h	Tue Aug 12 07:59:46 2025 +0200
@@ -41,7 +41,6 @@
 PyTypeObject* GetOrthancPluginFindQueryType();
 PyTypeObject* GetOrthancPluginImageType();
 PyTypeObject* GetOrthancPluginJobType();
-PyTypeObject* GetOrthancPluginKeysValuesIteratorType();
 PyTypeObject* GetOrthancPluginPeersType();
 PyTypeObject* GetOrthancPluginRestOutputType();
 PyTypeObject* GetOrthancPluginServerChunkedRequestReaderType();
@@ -120,15 +119,6 @@
   PyObject_HEAD
 
   /* Type-specific fields go here. */
-  OrthancPluginKeysValuesIterator* object_;
-  bool borrowed_;
-} sdk_OrthancPluginKeysValuesIterator_Object;
-
-typedef struct
-{
-  PyObject_HEAD
-
-  /* Type-specific fields go here. */
   OrthancPluginPeers* object_;
   bool borrowed_;
 } sdk_OrthancPluginPeers_Object;
--- a/Sources/Autogenerated/sdk_GlobalFunctions.impl.h	Mon Aug 11 13:03:13 2025 +0200
+++ b/Sources/Autogenerated/sdk_GlobalFunctions.impl.h	Tue Aug 12 07:59:46 2025 +0200
@@ -98,7 +98,7 @@
   PyBuffer_Release(&arg0);
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -171,7 +171,7 @@
   PyBuffer_Release(&arg4);
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -205,7 +205,7 @@
   PyBuffer_Release(&arg4);
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -301,7 +301,7 @@
   
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -340,7 +340,7 @@
   
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -450,39 +450,6 @@
   }
 }
 
-static PyObject* sdk_OrthancPluginCreateKeysValuesIterator(PyObject* module, PyObject* args)
-{
-  PythonLock::LogCall("Calling Python global function: OrthancPluginCreateKeysValuesIterator()");
-
-  const char* arg0 = NULL;
-
-  if (!PyArg_ParseTuple(args, "s", &arg0))
-  {
-    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
-    return NULL;
-  }
-
-  // This is the case of a constructor
-  OrthancPluginKeysValuesIterator* obj;
-  {
-    PythonThreadsAllower allower;
-    obj = OrthancPluginCreateKeysValuesIterator(OrthancPlugins::GetGlobalContext(), arg0);
-  }
-  
-  if (obj == NULL)
-  {
-    PythonLock::RaiseException(OrthancPluginErrorCode_InternalError);
-    return NULL;  
-  }
-  else
-  {
-    PyObject *argList = Py_BuildValue("Lb", obj, false /* not borrowed */);
-    PyObject *python = PyObject_CallObject((PyObject *) &sdk_OrthancPluginKeysValuesIterator_Type, argList);
-    Py_DECREF(argList);
-    return python;
-  }
-}
-
 static PyObject* sdk_OrthancPluginDecodeDicomImage(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginDecodeDicomImage()");
@@ -517,38 +484,6 @@
   }
 }
 
-static PyObject* sdk_OrthancPluginDeleteKeyValue(PyObject* module, PyObject* args)
-{
-  PythonLock::LogCall("Calling Python global function: OrthancPluginDeleteKeyValue()");
-
-  const char* arg0 = NULL;
-  const char* arg1 = NULL;
-
-  if (!PyArg_ParseTuple(args, "ss", &arg0, &arg1))
-  {
-    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
-    return NULL;
-  }
-
-  OrthancPluginErrorCode code;
-  {
-    PythonThreadsAllower allower;
-    code = OrthancPluginDeleteKeyValue(OrthancPlugins::GetGlobalContext(), arg0, arg1);
-  }
-  
-
-  if (code == OrthancPluginErrorCode_Success)
-  {
-    Py_INCREF(Py_None);
-    return Py_None;
-  }
-  else
-  {
-    PythonLock::RaiseException(code);
-    return NULL;
-  }
-}
-
 static PyObject* sdk_OrthancPluginDicomBufferToJson(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginDicomBufferToJson()");
@@ -613,65 +548,6 @@
   }
 }
 
-static PyObject* sdk_OrthancPluginEmitAuditLog(PyObject* module, PyObject* args)
-{
-  PythonLock::LogCall("Calling Python global function: OrthancPluginEmitAuditLog()");
-
-  const char* arg0 = NULL;
-  const char* arg1 = NULL;
-  long int arg2 = 0;
-  const char* arg3 = NULL;
-  const char* arg4 = NULL;
-  Py_buffer arg5;
-
-  if (!PyArg_ParseTuple(args, "sslssz*", &arg0, &arg1, &arg2, &arg3, &arg4, &arg5))
-  {
-    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (6 arguments expected)");
-    return NULL;
-  }
-
-  {
-    PythonThreadsAllower allower;
-    OrthancPluginEmitAuditLog(OrthancPlugins::GetGlobalContext(), arg0, arg1, static_cast<OrthancPluginResourceType>(arg2), arg3, arg4, (arg5.len > 0 ? arg5.buf : NULL), (arg5.len > 0 ? arg5.len : 0));
-  }
-  PyBuffer_Release(&arg5);
-
-  Py_INCREF(Py_None);
-  return Py_None;
-}
-
-static PyObject* sdk_OrthancPluginEnqueueValue(PyObject* module, PyObject* args)
-{
-  PythonLock::LogCall("Calling Python global function: OrthancPluginEnqueueValue()");
-
-  const char* arg0 = NULL;
-  Py_buffer arg1;
-
-  if (!PyArg_ParseTuple(args, "sz*", &arg0, &arg1))
-  {
-    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
-    return NULL;
-  }
-
-  OrthancPluginErrorCode code;
-  {
-    PythonThreadsAllower allower;
-    code = OrthancPluginEnqueueValue(OrthancPlugins::GetGlobalContext(), arg0, (arg1.len > 0 ? arg1.buf : NULL), (arg1.len > 0 ? arg1.len : 0));
-  }
-  PyBuffer_Release(&arg1);
-
-  if (code == OrthancPluginErrorCode_Success)
-  {
-    Py_INCREF(Py_None);
-    return Py_None;
-  }
-  else
-  {
-    PythonLock::RaiseException(code);
-    return NULL;
-  }
-}
-
 static PyObject* sdk_OrthancPluginExtendOrthancExplorer(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginExtendOrthancExplorer()");
@@ -763,36 +639,6 @@
   }
 }
 
-static PyObject* sdk_OrthancPluginGetAttachmentCustomData(PyObject* module, PyObject* args)
-{
-  PythonLock::LogCall("Calling Python global function: OrthancPluginGetAttachmentCustomData()");
-
-  const char* arg0 = NULL;
-
-  if (!PyArg_ParseTuple(args, "s", &arg0))
-  {
-    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
-    return NULL;
-  }
-
-  OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code;
-  {
-    PythonThreadsAllower allower;
-    code = OrthancPluginGetAttachmentCustomData(OrthancPlugins::GetGlobalContext(), *buffer, arg0);
-  }
-  
-  if (code == OrthancPluginErrorCode_Success)
-  {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
-  }
-  else
-  {
-    PythonLock::RaiseException(code);
-    return NULL;  
-  }
-}
-
 static PyObject* sdk_OrthancPluginGetCommandLineArgument(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginGetCommandLineArgument()");
@@ -927,7 +773,7 @@
   
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -1235,7 +1081,7 @@
   
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -1268,7 +1114,7 @@
   PyBuffer_Release(&arg1);
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -1301,7 +1147,7 @@
   PyBuffer_Release(&arg1);
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -1603,7 +1449,7 @@
   
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -1801,7 +1647,7 @@
   
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -1831,7 +1677,7 @@
   
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -1862,7 +1708,7 @@
   PyBuffer_Release(&arg1);
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -1893,7 +1739,7 @@
   PyBuffer_Release(&arg1);
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -1924,7 +1770,7 @@
   PyBuffer_Release(&arg1);
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -1955,7 +1801,7 @@
   PyBuffer_Release(&arg1);
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -1964,38 +1810,6 @@
   }
 }
 
-static PyObject* sdk_OrthancPluginSetAttachmentCustomData(PyObject* module, PyObject* args)
-{
-  PythonLock::LogCall("Calling Python global function: OrthancPluginSetAttachmentCustomData()");
-
-  const char* arg0 = NULL;
-  Py_buffer arg1;
-
-  if (!PyArg_ParseTuple(args, "sz*", &arg0, &arg1))
-  {
-    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
-    return NULL;
-  }
-
-  OrthancPluginErrorCode code;
-  {
-    PythonThreadsAllower allower;
-    code = OrthancPluginSetAttachmentCustomData(OrthancPlugins::GetGlobalContext(), arg0, (arg1.len > 0 ? arg1.buf : NULL), (arg1.len > 0 ? arg1.len : 0));
-  }
-  PyBuffer_Release(&arg1);
-
-  if (code == OrthancPluginErrorCode_Success)
-  {
-    Py_INCREF(Py_None);
-    return Py_None;
-  }
-  else
-  {
-    PythonLock::RaiseException(code);
-    return NULL;
-  }
-}
-
 static PyObject* sdk_OrthancPluginSetCurrentThreadName(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginSetCurrentThreadName()");
@@ -2173,39 +1987,6 @@
   return Py_None;
 }
 
-static PyObject* sdk_OrthancPluginStoreKeyValue(PyObject* module, PyObject* args)
-{
-  PythonLock::LogCall("Calling Python global function: OrthancPluginStoreKeyValue()");
-
-  const char* arg0 = NULL;
-  const char* arg1 = NULL;
-  Py_buffer arg2;
-
-  if (!PyArg_ParseTuple(args, "ssz*", &arg0, &arg1, &arg2))
-  {
-    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (3 arguments expected)");
-    return NULL;
-  }
-
-  OrthancPluginErrorCode code;
-  {
-    PythonThreadsAllower allower;
-    code = OrthancPluginStoreKeyValue(OrthancPlugins::GetGlobalContext(), arg0, arg1, (arg2.len > 0 ? arg2.buf : NULL), (arg2.len > 0 ? arg2.len : 0));
-  }
-  PyBuffer_Release(&arg2);
-
-  if (code == OrthancPluginErrorCode_Success)
-  {
-    Py_INCREF(Py_None);
-    return Py_None;
-  }
-  else
-  {
-    PythonLock::RaiseException(code);
-    return NULL;
-  }
-}
-
 static PyObject* sdk_OrthancPluginTranscodeDicomInstance(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginTranscodeDicomInstance()");
@@ -2335,20 +2116,12 @@
     "Generated from C function OrthancPluginCreateFindMatcher()" },
   { "CreateImage", sdk_OrthancPluginCreateImage, METH_VARARGS,
     "Generated from C function OrthancPluginCreateImage()" },
-  { "CreateKeysValuesIterator", sdk_OrthancPluginCreateKeysValuesIterator, METH_VARARGS,
-    "Generated from C function OrthancPluginCreateKeysValuesIterator()" },
   { "DecodeDicomImage", sdk_OrthancPluginDecodeDicomImage, METH_VARARGS,
     "Generated from C function OrthancPluginDecodeDicomImage()" },
-  { "DeleteKeyValue", sdk_OrthancPluginDeleteKeyValue, METH_VARARGS,
-    "Generated from C function OrthancPluginDeleteKeyValue()" },
   { "DicomBufferToJson", sdk_OrthancPluginDicomBufferToJson, METH_VARARGS,
     "Generated from C function OrthancPluginDicomBufferToJson()" },
   { "DicomInstanceToJson", sdk_OrthancPluginDicomInstanceToJson, METH_VARARGS,
     "Generated from C function OrthancPluginDicomInstanceToJson()" },
-  { "EmitAuditLog", sdk_OrthancPluginEmitAuditLog, METH_VARARGS,
-    "Generated from C function OrthancPluginEmitAuditLog()" },
-  { "EnqueueValue", sdk_OrthancPluginEnqueueValue, METH_VARARGS,
-    "Generated from C function OrthancPluginEnqueueValue()" },
   { "ExtendOrthancExplorer", sdk_OrthancPluginExtendOrthancExplorer, METH_VARARGS,
     "Generated from C function OrthancPluginExtendOrthancExplorer()" },
   { "ExtendOrthancExplorer2", sdk_OrthancPluginExtendOrthancExplorer2, METH_VARARGS,
@@ -2357,8 +2130,6 @@
     "Generated from C function OrthancPluginGenerateRestApiAuthorizationToken()" },
   { "GenerateUuid", sdk_OrthancPluginGenerateUuid, METH_VARARGS,
     "Generated from C function OrthancPluginGenerateUuid()" },
-  { "GetAttachmentCustomData", sdk_OrthancPluginGetAttachmentCustomData, METH_VARARGS,
-    "Generated from C function OrthancPluginGetAttachmentCustomData()" },
   { "GetCommandLineArgument", sdk_OrthancPluginGetCommandLineArgument, METH_VARARGS,
     "Generated from C function OrthancPluginGetCommandLineArgument()" },
   { "GetCommandLineArgumentsCount", sdk_OrthancPluginGetCommandLineArgumentsCount, METH_VARARGS,
@@ -2443,8 +2214,6 @@
     "Generated from C function OrthancPluginRestApiPut()" },
   { "RestApiPutAfterPlugins", sdk_OrthancPluginRestApiPutAfterPlugins, METH_VARARGS,
     "Generated from C function OrthancPluginRestApiPutAfterPlugins()" },
-  { "SetAttachmentCustomData", sdk_OrthancPluginSetAttachmentCustomData, METH_VARARGS,
-    "Generated from C function OrthancPluginSetAttachmentCustomData()" },
   { "SetCurrentThreadName", sdk_OrthancPluginSetCurrentThreadName, METH_VARARGS,
     "Generated from C function OrthancPluginSetCurrentThreadName()" },
   { "SetDescription", sdk_OrthancPluginSetDescription, METH_VARARGS,
@@ -2459,8 +2228,6 @@
     "Generated from C function OrthancPluginSetRootUri()" },
   { "SetRootUri2", sdk_OrthancPluginSetRootUri2, METH_VARARGS,
     "Generated from C function OrthancPluginSetRootUri2()" },
-  { "StoreKeyValue", sdk_OrthancPluginStoreKeyValue, METH_VARARGS,
-    "Generated from C function OrthancPluginStoreKeyValue()" },
   { "TranscodeDicomInstance", sdk_OrthancPluginTranscodeDicomInstance, METH_VARARGS,
     "Generated from C function OrthancPluginTranscodeDicomInstance()" },
   { "UncompressImage", sdk_OrthancPluginUncompressImage, METH_VARARGS,
--- a/Sources/Autogenerated/sdk_OrthancPluginCompressionType.impl.h	Mon Aug 11 13:03:13 2025 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginCompressionType.impl.h	Tue Aug 12 07:59:46 2025 +0200
@@ -97,12 +97,6 @@
     Py_DECREF(tmp);
   }
 
-  {
-    PyObject* tmp = PyLong_FromLong(4);
-    PyDict_SetItemString(sdk_OrthancPluginCompressionType_Type.tp_dict, "NONE", tmp);
-    Py_DECREF(tmp);
-  }
-
 
   Py_INCREF(&sdk_OrthancPluginCompressionType_Type);
   if (PyModule_AddObject(module, "CompressionType", (PyObject *)&sdk_OrthancPluginCompressionType_Type) < 0)
--- a/Sources/Autogenerated/sdk_OrthancPluginDicomInstance.methods.h	Mon Aug 11 13:03:13 2025 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginDicomInstance.methods.h	Tue Aug 12 07:59:46 2025 +0200
@@ -328,7 +328,7 @@
   
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
@@ -399,7 +399,7 @@
   
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
--- a/Sources/Autogenerated/sdk_OrthancPluginStorageArea.methods.h	Mon Aug 11 13:03:13 2025 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginStorageArea.methods.h	Tue Aug 12 07:59:46 2025 +0200
@@ -98,7 +98,7 @@
   
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {
--- a/Sources/Autogenerated/sdk_OrthancPluginWorklistQuery.methods.h	Mon Aug 11 13:03:13 2025 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginWorklistQuery.methods.h	Tue Aug 12 07:59:46 2025 +0200
@@ -78,7 +78,7 @@
   
   if (code == OrthancPluginErrorCode_Success)
   {
-    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+    return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(buffer.GetData()), buffer.GetSize());
   }
   else
   {