changeset 4440:eddb212b2df9

New functions in the SDK: OrthancPluginCreateMemoryBuffer64() and OrthancPluginRegisterStorageArea2()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 08 Jan 2021 18:53:33 +0100
parents 5209a9ff6e38
children 453cd3a5a0da
files NEWS OrthancServer/Plugins/Engine/OrthancPlugins.cpp OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h
diffstat 3 files changed, 452 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Thu Jan 07 18:18:39 2021 +0100
+++ b/NEWS	Fri Jan 08 18:53:33 2021 +0100
@@ -13,6 +13,13 @@
   - "UseDicomTls" in "DicomModalities" to enable DICOM TLS in outgoing SCU on a per-modality basis
 * New command-line option: "--openapi" to write the OpenAPI documentation of the REST API to a file
 
+Plugins
+-------
+
+* New functions in the SDK:
+  - OrthancPluginCreateMemoryBuffer64()
+  - OrthancPluginRegisterStorageArea2()
+
 Maintenance
 -----------
 
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Thu Jan 07 18:18:39 2021 +0100
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Fri Jan 08 18:53:33 2021 +0100
@@ -153,35 +153,125 @@
 
   namespace
   {
-    class PluginStorageArea : public IStorageArea
+    class MemoryBufferRaii : public boost::noncopyable
+    {
+    private:
+      OrthancPluginMemoryBuffer  buffer_;
+
+    public:
+      MemoryBufferRaii()
+      {
+        buffer_.size = 0;
+        buffer_.data = NULL;
+      }
+
+      ~MemoryBufferRaii()
+      {
+        if (buffer_.size != 0)
+        {
+          free(buffer_.data);
+        }
+      }
+
+      OrthancPluginMemoryBuffer* GetObject()
+      {
+        return &buffer_;
+      }
+
+      void ToString(std::string& target) const
+      {
+        if ((buffer_.data == NULL && buffer_.size != 0) ||
+            (buffer_.data != NULL && buffer_.size == 0))
+        {
+          throw OrthancException(ErrorCode_Plugin);
+        }
+        else
+        {
+          target.resize(buffer_.size);
+        
+          if (buffer_.size != 0)
+          {
+            memcpy(&target[0], buffer_.data, buffer_.size);
+          }
+        }
+      }
+    };
+  
+
+    class MemoryBuffer64Raii : public boost::noncopyable
     {
     private:
-      _OrthancPluginRegisterStorageArea callbacks_;
-      PluginsErrorDictionary&  errorDictionary_;
-
-      void Free(void* buffer) const
-      {
-        if (buffer != NULL)
-        {
-          callbacks_.free(buffer);
-        }
-      }
+      OrthancPluginMemoryBuffer64  buffer_;
 
     public:
-      PluginStorageArea(const _OrthancPluginRegisterStorageArea& callbacks,
-                        PluginsErrorDictionary&  errorDictionary) : 
-        callbacks_(callbacks),
+      MemoryBuffer64Raii()
+      {
+        buffer_.size = 0;
+        buffer_.data = NULL;
+      }
+
+      ~MemoryBuffer64Raii()
+      {
+        if (buffer_.size != 0)
+        {
+          free(buffer_.data);
+        }
+      }
+
+      OrthancPluginMemoryBuffer64* GetObject()
+      {
+        return &buffer_;
+      }
+
+      void ToString(std::string& target) const
+      {
+        if ((buffer_.data == NULL && buffer_.size != 0) ||
+            (buffer_.data != NULL && buffer_.size == 0))
+        {
+          throw OrthancException(ErrorCode_Plugin);
+        }
+        else
+        {
+          target.resize(buffer_.size);
+        
+          if (buffer_.size != 0)
+          {
+            memcpy(&target[0], buffer_.data, buffer_.size);
+          }
+        }
+      }
+    };
+  
+
+    class StorageAreaBase : public IStorageArea
+    {
+    private:
+      OrthancPluginStorageCreate create_;
+      OrthancPluginStorageRemove remove_;
+      PluginsErrorDictionary&    errorDictionary_;
+
+    protected:
+      PluginsErrorDictionary& GetErrorDictionary() const
+      {
+        return errorDictionary_;
+      }
+      
+    public:
+      StorageAreaBase(OrthancPluginStorageCreate create,
+                      OrthancPluginStorageRemove remove,
+                      PluginsErrorDictionary&  errorDictionary) : 
+        create_(create),
+        remove_(remove),
         errorDictionary_(errorDictionary)
       {
       }
 
-
       virtual void Create(const std::string& uuid,
                           const void* content, 
                           size_t size,
-                          FileContentType type)
-      {
-        OrthancPluginErrorCode error = callbacks_.create
+                          FileContentType type) ORTHANC_OVERRIDE
+      {
+        OrthancPluginErrorCode error = create_
           (uuid.c_str(), content, size, Plugins::Convert(type));
 
         if (error != OrthancPluginErrorCode_Success)
@@ -191,20 +281,57 @@
         }
       }
 
+      virtual void Remove(const std::string& uuid,
+                          FileContentType type) ORTHANC_OVERRIDE
+      {
+        OrthancPluginErrorCode error = remove_
+          (uuid.c_str(), Plugins::Convert(type));
+
+        if (error != OrthancPluginErrorCode_Success)
+        {
+          errorDictionary_.LogError(error, true);
+          throw OrthancException(static_cast<ErrorCode>(error));
+        }
+      }
+    };
+
+
+    class PluginStorageArea : public StorageAreaBase
+    {
+    private:
+      OrthancPluginStorageRead   read_;
+      OrthancPluginFree          free_;
+      
+      void Free(void* buffer) const
+      {
+        if (buffer != NULL)
+        {
+          free_(buffer);
+        }
+      }
+
+    public:
+      PluginStorageArea(const _OrthancPluginRegisterStorageArea& callbacks,
+                        PluginsErrorDictionary&  errorDictionary) :
+        StorageAreaBase(callbacks.create, callbacks.remove, errorDictionary),
+        read_(callbacks.read),
+        free_(callbacks.free)
+      {
+      }
 
       virtual void Read(std::string& content,
                         const std::string& uuid,
-                        FileContentType type)
+                        FileContentType type) ORTHANC_OVERRIDE
       {
         void* buffer = NULL;
         int64_t size = 0;
 
-        OrthancPluginErrorCode error = callbacks_.read
+        OrthancPluginErrorCode error = read_
           (&buffer, &size, uuid.c_str(), Plugins::Convert(type));
 
         if (error != OrthancPluginErrorCode_Success)
         {
-          errorDictionary_.LogError(error, true);
+          GetErrorDictionary().LogError(error, true);
           throw OrthancException(static_cast<ErrorCode>(error));
         }
 
@@ -225,19 +352,45 @@
 
         Free(buffer);
       }
-
-
-      virtual void Remove(const std::string& uuid,
-                          FileContentType type) 
-      {
-        OrthancPluginErrorCode error = callbacks_.remove
-          (uuid.c_str(), Plugins::Convert(type));
+    };
+
+
+    // New in Orthanc 1.9.0
+    class PluginStorageArea2 : public StorageAreaBase
+    {
+    private:
+      OrthancPluginStorageReadWhole  readWhole_;
+      OrthancPluginStorageReadRange  readRange_;
+
+    public:
+      PluginStorageArea2(const _OrthancPluginRegisterStorageArea2& callbacks,
+                         PluginsErrorDictionary&  errorDictionary) :
+        StorageAreaBase(callbacks.create, callbacks.remove, errorDictionary),
+        readWhole_(callbacks.readWhole),
+        readRange_(callbacks.readRange)
+      {
+        if (readRange_)
+        {
+          LOG(WARNING) << "Performance warning: The storage area plugin doesn't implement reading of file ranges";
+        }
+      }
+
+      virtual void Read(std::string& content,
+                        const std::string& uuid,
+                        FileContentType type) ORTHANC_OVERRIDE
+      {
+        MemoryBuffer64Raii buffer;
+        
+        OrthancPluginErrorCode error = readWhole_
+          (buffer.GetObject(), uuid.c_str(), Plugins::Convert(type));
 
         if (error != OrthancPluginErrorCode_Success)
         {
-          errorDictionary_.LogError(error, true);
+          GetErrorDictionary().LogError(error, true);
           throw OrthancException(static_cast<ErrorCode>(error));
         }
+
+        buffer.ToString(content);
       }
     };
 
@@ -245,18 +398,39 @@
     class StorageAreaFactory : public boost::noncopyable
     {
     private:
-      SharedLibrary&   sharedLibrary_;
-      _OrthancPluginRegisterStorageArea  callbacks_;
-      PluginsErrorDictionary&  errorDictionary_;
+      enum Version
+      {
+        Version1,
+        Version2
+      };
+      
+      SharedLibrary&                      sharedLibrary_;
+      Version                             version_;
+      _OrthancPluginRegisterStorageArea   callbacks_;
+      _OrthancPluginRegisterStorageArea2  callbacks2_;
+      PluginsErrorDictionary&             errorDictionary_;
 
     public:
       StorageAreaFactory(SharedLibrary& sharedLibrary,
                          const _OrthancPluginRegisterStorageArea& callbacks,
                          PluginsErrorDictionary&  errorDictionary) :
         sharedLibrary_(sharedLibrary),
+        version_(Version1),
         callbacks_(callbacks),
         errorDictionary_(errorDictionary)
       {
+        LOG(WARNING) << "Performance warning: The storage area plugin doesn't "
+                     << "use OrthancPluginRegisterStorageArea2()";
+      }
+
+      StorageAreaFactory(SharedLibrary& sharedLibrary,
+                         const _OrthancPluginRegisterStorageArea2& callbacks,
+                         PluginsErrorDictionary&  errorDictionary) :
+        sharedLibrary_(sharedLibrary),
+        version_(Version2),
+        callbacks2_(callbacks),
+        errorDictionary_(errorDictionary)
+      {
       }
 
       SharedLibrary&  GetSharedLibrary()
@@ -266,7 +440,17 @@
 
       IStorageArea* Create() const
       {
-        return new PluginStorageArea(callbacks_, errorDictionary_);
+        switch (version_)
+        {
+          case Version1:
+            return new PluginStorageArea(callbacks_, errorDictionary_);
+
+          case Version2:
+            return new PluginStorageArea2(callbacks2_, errorDictionary_);
+
+          default:
+            throw OrthancException(ErrorCode_InternalError);
+        }
       }
     };
 
@@ -977,7 +1161,7 @@
                         const std::string& remoteIp,
                         const std::string& remoteAet,
                         const std::string& calledAet,
-                        ModalityManufacturer manufacturer)
+                        ModalityManufacturer manufacturer) ORTHANC_OVERRIDE
     {
       {
         static const char* LUA_CALLBACK = "IncomingWorklistRequestFilter";
@@ -1098,7 +1282,7 @@
                         const std::string& remoteIp,
                         const std::string& remoteAet,
                         const std::string& calledAet,
-                        ModalityManufacturer manufacturer)
+                        ModalityManufacturer manufacturer) ORTHANC_OVERRIDE
     {
       DicomMap tmp;
       tmp.Assign(input);
@@ -1217,12 +1401,12 @@
         }
       }
 
-      virtual unsigned int GetSubOperationCount() const
+      virtual unsigned int GetSubOperationCount() const ORTHANC_OVERRIDE
       {
         return count_;
       }
 
-      virtual Status DoNext()
+      virtual Status DoNext() ORTHANC_OVERRIDE
       {
         if (pos_ >= count_)
         {
@@ -1288,7 +1472,7 @@
                                          const std::string& originatorIp,
                                          const std::string& originatorAet,
                                          const std::string& calledAet,
-                                         uint16_t originatorId)
+                                         uint16_t originatorId) ORTHANC_OVERRIDE
     {
       std::string levelString = ReadTag(input, DICOM_TAG_QUERY_RETRIEVE_LEVEL);
       std::string patientId = ReadTag(input, DICOM_TAG_PATIENT_ID);
@@ -4411,19 +4595,44 @@
         const _OrthancPluginCreateMemoryBuffer& p =
           *reinterpret_cast<const _OrthancPluginCreateMemoryBuffer*>(parameters);
 
-        p.target->size = p.size;
+        p.target->data = NULL;
+        p.target->size = 0;
         
-        if (p.size == 0)
-        {
-          p.target->data = NULL;
-        }
-        else
+        if (p.size != 0)
         {
           p.target->data = malloc(p.size);
+          if (p.target->data == NULL)
+          {
+            throw OrthancException(ErrorCode_NotEnoughMemory);
+          }
+
+          p.target->size = p.size;
         }          
         
         return true;
       }
+
+      case _OrthancPluginService_CreateMemoryBuffer64:
+      {
+        const _OrthancPluginCreateMemoryBuffer64& p =
+          *reinterpret_cast<const _OrthancPluginCreateMemoryBuffer64*>(parameters);
+
+        p.target->data = NULL;
+        p.target->size = 0;
+        
+        if (p.size != 0)
+        {
+          p.target->data = malloc(p.size);
+          if (p.target->data == NULL)
+          {
+            throw OrthancException(ErrorCode_NotEnoughMemory);
+          }
+
+          p.target->size = p.size;
+        }          
+
+        return true;
+      }
         
       case _OrthancPluginService_RegisterIncomingHttpRequestFilter:
         RegisterIncomingHttpRequestFilter(parameters);
@@ -4507,14 +4716,28 @@
         return true;
 
       case _OrthancPluginService_RegisterStorageArea:
+      case _OrthancPluginService_RegisterStorageArea2:
       {
         CLOG(INFO, PLUGINS) << "Plugin has registered a custom storage area";
-        const _OrthancPluginRegisterStorageArea& p = 
-          *reinterpret_cast<const _OrthancPluginRegisterStorageArea*>(parameters);
         
         if (pimpl_->storageArea_.get() == NULL)
         {
-          pimpl_->storageArea_.reset(new StorageAreaFactory(plugin, p, GetErrorDictionary()));
+          if (service == _OrthancPluginService_RegisterStorageArea)
+          {
+            const _OrthancPluginRegisterStorageArea& p = 
+              *reinterpret_cast<const _OrthancPluginRegisterStorageArea*>(parameters);
+            pimpl_->storageArea_.reset(new StorageAreaFactory(plugin, p, GetErrorDictionary()));
+          }
+          else if (service == _OrthancPluginService_RegisterStorageArea2)
+          {
+            const _OrthancPluginRegisterStorageArea2& p = 
+              *reinterpret_cast<const _OrthancPluginRegisterStorageArea2*>(parameters);
+            pimpl_->storageArea_.reset(new StorageAreaFactory(plugin, p, GetErrorDictionary()));
+          }
+          else
+          {
+            throw OrthancException(ErrorCode_InternalError);
+          }
         }
         else
         {
@@ -5197,43 +5420,6 @@
   }
 
 
-  class MemoryBufferRaii : public boost::noncopyable
-  {
-  private:
-    OrthancPluginMemoryBuffer  buffer_;
-
-  public:
-    MemoryBufferRaii()
-    {
-      buffer_.size = 0;
-      buffer_.data = NULL;
-    }
-
-    ~MemoryBufferRaii()
-    {
-      if (buffer_.size != 0)
-      {
-        free(buffer_.data);
-      }
-    }
-
-    OrthancPluginMemoryBuffer* GetObject()
-    {
-      return &buffer_;
-    }
-
-    void ToString(std::string& target) const
-    {
-      target.resize(buffer_.size);
-
-      if (buffer_.size != 0)
-      {
-        memcpy(&target[0], buffer_.data, buffer_.size);
-      }
-    }
-  };
-  
-
   bool OrthancPlugins::TranscodeBuffer(std::string& target,
                                        const void* buffer,
                                        size_t size,
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Thu Jan 07 18:18:39 2021 +0100
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Fri Jan 08 18:53:33 2021 +0100
@@ -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 ::OrthancPluginRegisterStorageArea().
+ *    - Possibly register a custom storage area using ::OrthancPluginRegisterStorageArea2().
  *    - Possibly register a custom database back-end area using OrthancPluginRegisterDatabaseBackendV2().
  *    - Possibly register a handler for C-Find SCP using OrthancPluginRegisterFindCallback().
  *    - Possibly register a handler for C-Find SCP against DICOM worklists using OrthancPluginRegisterWorklistCallback().
@@ -116,8 +116,8 @@
 #endif
 
 #define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER     1
-#define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER     8
-#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  1
+#define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER     9
+#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  0
 
 
 #if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)
@@ -437,6 +437,7 @@
     _OrthancPluginService_EncodeDicomWebXml2 = 37,   /* New in Orthanc 1.7.0 */
     _OrthancPluginService_CreateMemoryBuffer = 38,   /* New in Orthanc 1.7.0 */
     _OrthancPluginService_GenerateRestApiAuthorizationToken = 39,   /* New in Orthanc 1.8.1 */
+    _OrthancPluginService_CreateMemoryBuffer64 = 40, /* New in Orthanc 1.9.0 */
     
     /* Registration of callbacks */
     _OrthancPluginService_RegisterRestCallback = 1000,
@@ -455,6 +456,7 @@
     _OrthancPluginService_RegisterStorageCommitmentScpCallback = 1013,
     _OrthancPluginService_RegisterIncomingDicomInstanceFilter = 1014,
     _OrthancPluginService_RegisterTranscoderCallback = 1015,   /* New in Orthanc 1.7.0 */
+    _OrthancPluginService_RegisterStorageArea2 = 1016,         /* New in Orthanc 1.9.0 */
     
     /* Sending answers to REST calls */
     _OrthancPluginService_AnswerBuffer = 2000,
@@ -991,7 +993,7 @@
   
 
   /**
-   * @brief A memory buffer allocated by the core system of Orthanc.
+   * @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
    * content of the buffer is not useful anymore, it must be free by a
@@ -1012,6 +1014,28 @@
 
 
 
+  /**
+   * @brief A 64-bit memory buffer allocated by the core system of Orthanc.
+   *
+   * A memory buffer allocated by the core system of Orthanc. When the
+   * content of the buffer is not useful anymore, it must be free by a
+   * call to ::OrthancPluginFreeMemoryBuffer64().
+   **/
+  typedef struct
+  {
+    /**
+     * @brief The content of the buffer.
+     **/
+    void*      data;
+
+    /**
+     * @brief The number of bytes in the buffer.
+     **/
+    uint64_t   size;
+  } OrthancPluginMemoryBuffer64;
+
+
+
 
   /**
    * @brief Opaque structure that represents the HTTP connection to the client application.
@@ -1206,6 +1230,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
@@ -1222,6 +1247,50 @@
 
 
   /**
+   * @brief Callback for reading a whole file from the storage area.
+   *
+   * Signature of a callback function that is triggered when Orthanc
+   * reads a whole file from the storage area.
+   *
+   * @param target Memory buffer where to store the content of the file. It must be allocated by the
+   * plugin using OrthancPluginCreateMemoryBuffer64(). The core of Orthanc will free it.
+   * @param uuid The UUID of the file of interest.
+   * @param type The content type corresponding to this file. 
+   * @ingroup Callbacks
+   **/
+  typedef OrthancPluginErrorCode (*OrthancPluginStorageReadWhole) (
+    OrthancPluginMemoryBuffer64* target,
+    const char* uuid,
+    OrthancPluginContentType type);
+
+
+
+  /**
+   * @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. It must be allocated by the
+   * plugin using OrthancPluginCreateMemoryBuffer64(). The core of Orthanc will free it.
+   * @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 rangeSize Length of the range of interest.
+   * @return 0 if success, other value if error.
+   * @ingroup Callbacks
+   **/
+  typedef OrthancPluginErrorCode (*OrthancPluginStorageReadRange) (
+    OrthancPluginMemoryBuffer64* target,
+    const char* uuid,
+    OrthancPluginContentType type,
+    uint64_t rangeStart,
+    uint64_t rangeSize);
+
+
+
+  /**
    * @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.
@@ -1869,6 +1938,22 @@
 
 
   /**
+   * @brief Free a memory buffer.
+   * 
+   * Free a memory buffer that was allocated by the core system of Orthanc.
+   * 
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param buffer The memory buffer to release.
+   **/
+  ORTHANC_PLUGIN_INLINE void  OrthancPluginFreeMemoryBuffer64(
+    OrthancPluginContext* context, 
+    OrthancPluginMemoryBuffer64* buffer)
+  {
+    context->Free(buffer->data);
+  }
+
+
+  /**
    * @brief Log an error.
    *
    * Log an error message using the Orthanc logging system.
@@ -3055,6 +3140,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()
    **/
   ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterStorageArea(
     OrthancPluginContext*       context,
@@ -4554,6 +4640,8 @@
    * @param type The type of the file content.
    * @return 0 if success, other value if error.
    * @ingroup Callbacks
+   * @deprecated This function should not be used anymore. Use "OrthancPluginRestApiPut()" on
+   * "/{patients|studies|series|instances}/{id}/attachments/{name}" instead.
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginStorageAreaCreate(
     OrthancPluginContext*       context,
@@ -4596,6 +4684,8 @@
    * @param type The type of the file content.
    * @return 0 if success, other value if error.
    * @ingroup Callbacks
+   * @deprecated This function should not be used anymore. Use "OrthancPluginRestApiGet()" on
+   * "/{patients|studies|series|instances}/{id}/attachments/{name}" instead.
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginStorageAreaRead(
     OrthancPluginContext*       context,
@@ -4633,6 +4723,8 @@
    * @param type The type of the file content.
    * @return 0 if success, other value if error.
    * @ingroup Callbacks
+   * @deprecated This function should not be used anymore. Use "OrthancPluginRestApiDelete()" on
+   * "/{patients|studies|series|instances}/{id}/attachments/{name}" instead.
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginStorageAreaRemove(
     OrthancPluginContext*       context,
@@ -8178,7 +8270,7 @@
   } _OrthancPluginCreateMemoryBuffer;
 
   /**
-   * @brief Create a memory buffer.
+   * @brief Create a 32-bit memory buffer.
    *
    * This function creates a memory buffer that is managed by the
    * Orthanc core. The main use case of this function is for plugins
@@ -8252,6 +8344,84 @@
       return result;
     }
   }
+
+
+
+  typedef struct
+  {
+    OrthancPluginMemoryBuffer64*  target;
+    uint64_t                      size;
+  } _OrthancPluginCreateMemoryBuffer64;
+
+  /**
+   * @brief Create a 64-bit memory buffer.
+   *
+   * This function creates a 64-bit memory buffer that is managed by
+   * the Orthanc core. The main use case of this function is for
+   * plugins that read files from the storage area.
+   * 
+   * Your plugin should never call "free()" on the resulting memory
+   * buffer, as the C library that is used by the plugin is in general
+   * not the same as the one used by the Orthanc core.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().
+   * @param size Size of the memory buffer to be created.
+   * @return 0 if success, or the error code if failure.
+   * @ingroup Toolbox
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginCreateMemoryBuffer64(
+    OrthancPluginContext*         context,
+    OrthancPluginMemoryBuffer64*  target,
+    uint64_t                      size)
+  {
+    _OrthancPluginCreateMemoryBuffer64 params;
+    params.target = target;
+    params.size = size;
+
+    return context->InvokeService(context, _OrthancPluginService_CreateMemoryBuffer64, &params);
+  }
+  
+
+  typedef struct
+  {
+    OrthancPluginStorageCreate    create;
+    OrthancPluginStorageReadWhole readWhole;
+    OrthancPluginStorageReadRange readRange;
+    OrthancPluginStorageRemove    remove;
+  } _OrthancPluginRegisterStorageArea2;
+
+  /**
+   * @brief Register a custom storage area, with support for range request.
+   *
+   * 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 readWhole The callback function to read a whole file from the custom storage area.
+   * @param readRange The callback function to read some range of a file from the custom storage area.
+   * 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
+   **/
+  ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterStorageArea2(
+    OrthancPluginContext*          context,
+    OrthancPluginStorageCreate     create,
+    OrthancPluginStorageReadWhole  readWhole,
+    OrthancPluginStorageReadRange  readRange,
+    OrthancPluginStorageRemove     remove)
+  {
+    _OrthancPluginRegisterStorageArea2 params;
+    params.create = create;
+    params.readWhole = readWhole;
+    params.readRange = readRange;
+    params.remove = remove;
+    context->InvokeService(context, _OrthancPluginService_RegisterStorageArea2, &params);
+  }
+
 #ifdef  __cplusplus
 }
 #endif