changeset 4913:c1b19f95e166

fix signature of OrthancPluginReceivedInstanceCallback for ABI compatibility
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 22 Feb 2022 22:12:43 +0100
parents 45d6ce72a84e
children 4b10cbf3ccc8
files OrthancFramework/Sources/MallocMemoryBuffer.cpp OrthancFramework/Sources/MallocMemoryBuffer.h OrthancServer/Plugins/Engine/OrthancPlugins.cpp OrthancServer/Plugins/Engine/OrthancPlugins.h OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h OrthancServer/Plugins/Samples/Sanitizer/Plugin.cpp OrthancServer/Sources/ServerContext.cpp
diffstat 7 files changed, 105 insertions(+), 117 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/MallocMemoryBuffer.cpp	Tue Feb 22 17:46:28 2022 +0100
+++ b/OrthancFramework/Sources/MallocMemoryBuffer.cpp	Tue Feb 22 22:12:43 2022 +0100
@@ -57,11 +57,23 @@
 
     
   void MallocMemoryBuffer::Assign(void* buffer,
-                                  size_t size,
+                                  uint64_t size,
                                   FreeFunction freeFunction)
   {
     Clear();
 
+    if (size != 0 &&
+        buffer == NULL)
+    {
+      throw OrthancException(ErrorCode_NullPointer);
+    }
+
+    if (static_cast<uint64_t>(static_cast<size_t>(size)) != size)
+    {
+      freeFunction(buffer);
+      throw OrthancException(ErrorCode_InternalError, "Buffer larger than 4GB, which is too large for Orthanc running in 32bits");
+    }
+
     buffer_ = buffer;
     size_ = size;
     free_ = freeFunction;
--- a/OrthancFramework/Sources/MallocMemoryBuffer.h	Tue Feb 22 17:46:28 2022 +0100
+++ b/OrthancFramework/Sources/MallocMemoryBuffer.h	Tue Feb 22 22:12:43 2022 +0100
@@ -50,7 +50,7 @@
     void Clear();
 
     void Assign(void* buffer,
-                size_t size,
+                uint64_t size,
                 FreeFunction freeFunction);
     
     virtual void MoveToString(std::string& target) ORTHANC_OVERRIDE;
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Tue Feb 22 17:46:28 2022 +0100
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Tue Feb 22 22:12:43 2022 +0100
@@ -1156,7 +1156,6 @@
     typedef std::list<OrthancPluginIncomingHttpRequestFilter2>  IncomingHttpRequestFilters2;
     typedef std::list<OrthancPluginIncomingDicomInstanceFilter>  IncomingDicomInstanceFilters;
     typedef std::list<OrthancPluginIncomingCStoreInstanceFilter>  IncomingCStoreInstanceFilters;
-    typedef std::list<OrthancPluginReceivedInstanceCallback>  ReceivedInstanceCallbacks;
     typedef std::list<OrthancPluginDecodeImageCallback>  DecodeImageCallbacks;
     typedef std::list<OrthancPluginTranscoderCallback>  TranscoderCallbacks;
     typedef std::list<OrthancPluginJobsUnserializer>  JobsUnserializers;
@@ -1180,7 +1179,7 @@
     IncomingHttpRequestFilters2 incomingHttpRequestFilters2_;
     IncomingDicomInstanceFilters  incomingDicomInstanceFilters_;
     IncomingCStoreInstanceFilters  incomingCStoreInstanceFilters_;  // New in Orthanc 1.10.0
-    ReceivedInstanceCallbacks  receivedInstanceCallbacks_;  // New in Orthanc 1.10.0
+    OrthancPluginReceivedInstanceCallback  receivedInstanceCallback_;  // New in Orthanc 1.10.0
     RefreshMetricsCallbacks refreshMetricsCallbacks_;
     StorageCommitmentScpCallbacks storageCommitmentScpCallbacks_;
     std::unique_ptr<StorageAreaFactory>  storageArea_;
@@ -1212,6 +1211,7 @@
       context_(NULL), 
       findCallback_(NULL),
       worklistCallback_(NULL),
+      receivedInstanceCallback_(NULL),
       argc_(1),
       argv_(NULL),
       databaseServerIdentifier_(databaseServerIdentifier),
@@ -2285,72 +2285,29 @@
   }
 
 
-  bool OrthancPlugins::ApplyReceivedInstanceCallbacks(const void* receivedDicom,
-                                                      size_t receivedDicomSize,
-                                                      void** modifiedDicomBufferData,
-                                                      size_t& modifiedDicomBufferSize)
+  OrthancPluginReceivedInstanceCallbackResult OrthancPlugins::ApplyReceivedInstanceCallbacks(
+    MallocMemoryBuffer& modified,
+    const void* receivedDicom,
+    size_t receivedDicomSize)
   {
-    uint64_t modifiedDicomSize64 = 0;
-    *modifiedDicomBufferData = NULL;
-
     boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_);
-    
-    for (PImpl::ReceivedInstanceCallbacks::const_iterator
-           callback = pimpl_->receivedInstanceCallbacks_.begin();
-         callback != pimpl_->receivedInstanceCallbacks_.end(); ++callback)
-    {
-      OrthancPluginReceivedInstanceCallbackResult callbackResult = (*callback) (receivedDicom,
-                                                                                receivedDicomSize,
-                                                                                modifiedDicomBufferData,
-                                                                                &modifiedDicomSize64);
-
-      if (callbackResult == OrthancPluginReceivedInstanceCallbackResult_Discard)
-      {
-        if (modifiedDicomSize64 > 0 || *modifiedDicomBufferData != NULL)
-        {
-          free(modifiedDicomBufferData);
-          throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback plugin is returning a modified buffer while it has discarded the instance");
-        }
-
-        CLOG(INFO, PLUGINS) << "A plugin has discarded the instance in its ReceivedInstanceCallback";        
-        return false;
-      }
-      else if (callbackResult == OrthancPluginReceivedInstanceCallbackResult_KeepAsIs)
-      {
-        if (modifiedDicomSize64 > 0 || *modifiedDicomBufferData != NULL)
-        {
-          free(modifiedDicomBufferData);
-          throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback plugin is returning a modified buffer while it has not modified the instance");
-        }
-        return true; 
-      }
-      else if (callbackResult == OrthancPluginReceivedInstanceCallbackResult_Modify)
-      {
-        if (modifiedDicomSize64 > 0 && modifiedDicomBufferData != NULL)
-        {
-          if (static_cast<size_t>(modifiedDicomSize64) != modifiedDicomSize64)  // Orthanc is running in 32bits and has received a > 4GB buffer
-          {
-            free(modifiedDicomBufferData);
-            throw OrthancException(ErrorCode_Plugin, "The Plugin has returned a > 4GB which is too large for Orthanc running in 32bits");
-          }
-
-          modifiedDicomBufferSize = static_cast<size_t>(modifiedDicomSize64);
-
-          CLOG(INFO, PLUGINS) << "A plugin has modified the instance in its ReceivedInstanceCallback";        
-          return true;
-        }
-        else
-        {
-          throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback plugin is not returning a modified buffer while it has modified the instance");
-        }
-      }
-      else
-      {
-        throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback has returned an invalid value");
-      }
-    }
-
-    return true;
+
+    if (pimpl_->receivedInstanceCallback_ == NULL)
+    {
+      return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs;
+    }
+    else
+    {
+      OrthancPluginReceivedInstanceCallbackResult callbackResult;
+      
+      {
+        OrthancPluginMemoryBuffer64 buffer;
+        callbackResult = (*pimpl_->receivedInstanceCallback_) (receivedDicom, receivedDicomSize, &buffer);
+        modified.Assign(buffer.data, buffer.size, ::free);
+      }
+
+      return callbackResult;
+    }
   }
 
   void OrthancPlugins::SignalChangeInternal(OrthancPluginChangeType changeType,
@@ -2584,8 +2541,16 @@
     const _OrthancPluginReceivedInstanceCallback& p = 
       *reinterpret_cast<const _OrthancPluginReceivedInstanceCallback*>(parameters);
 
-    CLOG(INFO, PLUGINS) << "Plugin has registered a received instance callback";
-    pimpl_->receivedInstanceCallbacks_.push_back(p.callback);
+    if (pimpl_->receivedInstanceCallback_ != NULL)
+    {
+      throw OrthancException(ErrorCode_Plugin,
+                             "Can only register one plugin callback to process received instances");
+    }
+    else
+    {
+      CLOG(INFO, PLUGINS) << "Plugin has registered a received instance callback";
+      pimpl_->receivedInstanceCallback_ = p.callback;
+    }
   }
 
   void OrthancPlugins::RegisterRefreshMetricsCallback(const void* parameters)
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.h	Tue Feb 22 17:46:28 2022 +0100
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.h	Tue Feb 22 22:12:43 2022 +0100
@@ -50,6 +50,7 @@
 #include "../../../OrthancFramework/Sources/HttpServer/IHttpHandler.h"
 #include "../../../OrthancFramework/Sources/HttpServer/IIncomingHttpRequestFilter.h"
 #include "../../../OrthancFramework/Sources/JobsEngine/IJob.h"
+#include "../../../OrthancFramework/Sources/MallocMemoryBuffer.h"
 #include "../../Sources/Database/IDatabaseWrapper.h"
 #include "../../Sources/IDicomImageDecoder.h"
 #include "../../Sources/IServerListener.h"
@@ -275,10 +276,9 @@
     virtual uint16_t FilterIncomingCStoreInstance(const DicomInstanceToStore& instance,
                                                   const Json::Value& simplified) ORTHANC_OVERRIDE;
 
-    virtual bool ApplyReceivedInstanceCallbacks(const void* receivedDicomBuffer,
-                                                size_t receivedDicomBufferSize,
-                                                void** modifiedDicomBufferData,
-                                                size_t& modifiedDicomBufferSize);
+    OrthancPluginReceivedInstanceCallbackResult ApplyReceivedInstanceCallbacks(MallocMemoryBuffer& modified,
+                                                                               const void* receivedDicomBuffer,
+                                                                               size_t receivedDicomBufferSize);
 
     bool HasStorageArea() const;
 
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Feb 22 17:46:28 2022 +0100
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Feb 22 22:12:43 2022 +0100
@@ -7780,19 +7780,19 @@
 
   /**
    * @brief Callback to filter incoming DICOM instances received by 
-   * Orthanc through C-Store.
+   * Orthanc through C-STORE.
    *
    * Signature of a callback function that is triggered whenever
    * Orthanc receives a new DICOM instance (through DICOM protocol), 
    * and that answers whether this DICOM instance should be accepted 
    * or discarded by Orthanc.  If the instance is discarded, the callback
-   * can specify the C-Store error code.
+   * can specify the C-STORE error code.
    *
    * Note that the metadata information is not available
    * (i.e. GetInstanceMetadata() should not be used on "instance").
    *
    * @param instance The received DICOM instance.
-   * @return 0 to accept the instance, any valid C-Store error code
+   * @return 0 to accept the instance, any valid C-STORE error code
    * to reject the instance, -1 if error.
    * @ingroup Callback
    **/
@@ -7807,7 +7807,7 @@
 
   /**
    * @brief Register a callback to filter incoming DICOM instances
-   * received by Orthanc through C-Store.
+   * received by Orthanc through C-STORE.
    *
    *
    * @warning Your callback function will be called synchronously with
@@ -7837,33 +7837,30 @@
 
   /**
    * @brief Callback to possibly modify a DICOM instance received
-   * by Orthanc through any source (C-Store or Rest API)
+   * by Orthanc from any source (C-STORE or REST API)
    *
    * Signature of a callback function that is triggered whenever
    * Orthanc receives a new DICOM instance (through DICOM protocol or 
-   * Rest API), and that answers a possibly modified version of the 
+   * REST API), and that answers a possibly modified version of the 
    * DICOM that should be stored in Orthanc.  
    *
-   * This callback is called immediately after receiption: before 
+   * This callback is called immediately after reception: before 
    * transcoding and before filtering (FilterIncomingInstance).
    *
    * @param receivedDicomBuffer A buffer containing the received DICOM (input).
    * @param receivedDicomBufferSize The size of the received DICOM (input)
    * @param modifiedDicomBuffer A buffer containing the modified DICOM (output).
-   *                            This buffer will be freed by the Orthanc Core and must have
-   *                            been allocated by malloc in your plugin or by Orthanc core through
-   *                            a plugin method.
-   * @param modifiedDicomBufferSize The size of the modified DICOM (output)
-   * @return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs to accept the instance as is
-   *         OrthancPluginReceivedInstanceCallbackResult_Modified to store the modified DICOM
-   *         OrthancPluginReceivedInstanceCallbackResult_Discard to tell Orthanc to discard the instance
+   * This buffer will be freed by the Orthanc core and must have been allocated 
+   * using OrthancPluginCreateMemoryBuffer64().
+   * @return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs to accept the instance as is,
+   *         OrthancPluginReceivedInstanceCallbackResult_Modified to store the modified DICOM,
+   *         OrthancPluginReceivedInstanceCallbackResult_Discard to tell Orthanc to discard the instance.
    * @ingroup Callback
    **/
   typedef OrthancPluginReceivedInstanceCallbackResult (*OrthancPluginReceivedInstanceCallback) (
     const void* receivedDicomBuffer,
     uint64_t receivedDicomBufferSize,
-    void** modifiedDicomBuffer,
-    uint64_t* modifiedDicomBufferSize
+    OrthancPluginMemoryBuffer64* modifiedDicomBuffer
     );
 
 
@@ -7874,7 +7871,7 @@
 
   /**
    * @brief Register a callback to possibly modify a DICOM instance received
-   * by Orthanc through any source (C-Store or Rest API)
+   * by Orthanc through any source (C-STORE or REST API)
    *
    *
    * @warning Your callback function will be called synchronously with
--- a/OrthancServer/Plugins/Samples/Sanitizer/Plugin.cpp	Tue Feb 22 17:46:28 2022 +0100
+++ b/OrthancServer/Plugins/Samples/Sanitizer/Plugin.cpp	Tue Feb 22 22:12:43 2022 +0100
@@ -35,8 +35,7 @@
 
 OrthancPluginReceivedInstanceCallbackResult ReceivedInstanceCallback(const void* receivedDicomBuffer,
                                                                      uint64_t receivedDicomBufferSize,
-                                                                     void** modifiedDicomBuffer,
-                                                                     uint64_t* modifiedDicomBufferSize)
+                                                                     OrthancPluginMemoryBuffer64* modifiedDicomBuffer)
 {
   Orthanc::ParsedDicomFile dicom(receivedDicomBuffer, receivedDicomBufferSize);
   std::string institutionName = "My institution";
@@ -45,12 +44,11 @@
   
   std::string modifiedDicom;
   dicom.SaveToMemoryBuffer(modifiedDicom);
-
-  *modifiedDicomBuffer = malloc(modifiedDicom.size());
-  *modifiedDicomBufferSize = modifiedDicom.size();
-  memcpy(*modifiedDicomBuffer, modifiedDicom.c_str(), modifiedDicom.size());
   
-  return OrthancPluginReceivedInstanceCallbackResult_Modify;
+  OrthancPluginCreateMemoryBuffer64(OrthancPlugins::GetGlobalContext(), modifiedDicomBuffer, modifiedDicom.size());
+  memcpy(modifiedDicomBuffer->data, modifiedDicom.c_str(), modifiedDicom.size());
+  
+  return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs;
 }
 
 
--- a/OrthancServer/Sources/ServerContext.cpp	Tue Feb 22 17:46:28 2022 +0100
+++ b/OrthancServer/Sources/ServerContext.cpp	Tue Feb 22 22:12:43 2022 +0100
@@ -687,34 +687,50 @@
                                                   StoreInstanceMode mode)
   { 
     DicomInstanceToStore* dicom = &receivedDicom;
+
+    // WARNING: The scope of "modifiedBuffer" and "modifiedDicom" must
+    // be the same as that of "dicom"
+    MallocMemoryBuffer modifiedBuffer;
     std::unique_ptr<DicomInstanceToStore> modifiedDicom;
 
-    std::unique_ptr<MallocMemoryBuffer> raii(new MallocMemoryBuffer);
-
 #if ORTHANC_ENABLE_PLUGINS == 1
     if (HasPlugins())
     {
-      void* modifiedDicomBuffer = NULL;
-      size_t modifiedDicomBufferSize = 0;
+      // New in Orthanc 1.10.0
 
-      bool store = GetPlugins().ApplyReceivedInstanceCallbacks(receivedDicom.GetBufferData(), 
-                                                               receivedDicom.GetBufferSize(),
-                                                               &modifiedDicomBuffer,
-                                                               modifiedDicomBufferSize);
-      raii->Assign(modifiedDicomBuffer, modifiedDicomBufferSize, ::free);
+      OrthancPluginReceivedInstanceCallbackResult action = GetPlugins().ApplyReceivedInstanceCallbacks(
+        modifiedBuffer, receivedDicom.GetBufferData(), receivedDicom.GetBufferSize());
 
-      if (!store)
+      switch (action)
       {
-        StoreResult result;
-        result.SetStatus(StoreStatus_FilteredOut);
-        return result;
-      }
+        case OrthancPluginReceivedInstanceCallbackResult_Discard:
+        {
+          CLOG(INFO, PLUGINS) << "A plugin has discarded the instance in its ReceivedInstanceCallback";
+          StoreResult result;
+          result.SetStatus(StoreStatus_FilteredOut);
+          return result;
+        }
+          
+        case OrthancPluginReceivedInstanceCallbackResult_KeepAsIs:
+          break;
 
-      if (modifiedDicomBufferSize > 0 && modifiedDicomBuffer != NULL)
-      {
-        modifiedDicom.reset(DicomInstanceToStore::CreateFromBuffer(modifiedDicomBuffer, modifiedDicomBufferSize));
-        modifiedDicom->SetOrigin(dicom->GetOrigin());
-        dicom = modifiedDicom.get();
+        case OrthancPluginReceivedInstanceCallbackResult_Modify:
+          if (modifiedBuffer.GetSize() > 0 &&
+              modifiedBuffer.GetData() != NULL)
+          {
+            CLOG(INFO, PLUGINS) << "A plugin has modified the instance in its ReceivedInstanceCallback";        
+            modifiedDicom.reset(DicomInstanceToStore::CreateFromBuffer(modifiedBuffer.GetData(), modifiedBuffer.GetSize()));
+            modifiedDicom->SetOrigin(dicom->GetOrigin());
+            dicom = modifiedDicom.get();
+          }
+          else
+          {
+            throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback plugin is not returning a modified buffer while it has modified the instance");
+          }
+          break;
+          
+        default:
+          throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback has returned an invalid value");
       }
     }
 #endif