changeset 6058:3f560fa6db5b attach-custom-data

removed the IStorageArea::ReadWhole() primitive
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 25 Mar 2025 20:41:02 +0100
parents 78f4c1da54d3
children ea2f3d9323e6
files OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp OrthancFramework/Sources/FileStorage/FilesystemStorage.h OrthancFramework/Sources/FileStorage/IStorageArea.h OrthancFramework/Sources/FileStorage/MemoryStorageArea.cpp OrthancFramework/Sources/FileStorage/MemoryStorageArea.h OrthancFramework/Sources/FileStorage/StorageAccessor.cpp OrthancFramework/UnitTestsSources/FileStorageTests.cpp OrthancServer/Plugins/Engine/OrthancPlugins.cpp OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h OrthancServer/Plugins/Samples/DelayedDeletion/Plugin.cpp OrthancServer/Sources/OrthancInitialization.cpp OrthancServer/Sources/ServerContext.cpp
diffstat 12 files changed, 134 insertions(+), 312 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp	Thu Mar 20 18:24:24 2025 +0100
+++ b/OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp	Tue Mar 25 20:41:02 2025 +0100
@@ -187,8 +187,8 @@
   }
 
 
-  IMemoryBuffer* FilesystemStorage::Read(const std::string& uuid,
-                                         FileContentType type)
+  IMemoryBuffer* FilesystemStorage::ReadWhole(const std::string& uuid,
+                                              FileContentType type)
   {
     Toolbox::ElapsedTimer timer;
     LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) 
@@ -221,12 +221,6 @@
   }
 
 
-  bool FilesystemStorage::HasReadRange() const
-  {
-    return true;
-  }
-
-
   uintmax_t FilesystemStorage::GetSize(const std::string& uuid) const
   {
     boost::filesystem::path path = GetPath(uuid);
--- a/OrthancFramework/Sources/FileStorage/FilesystemStorage.h	Thu Mar 20 18:24:24 2025 +0100
+++ b/OrthancFramework/Sources/FileStorage/FilesystemStorage.h	Tue Mar 25 20:41:02 2025 +0100
@@ -80,15 +80,19 @@
                         size_t size,
                         FileContentType type) ORTHANC_OVERRIDE;
 
-    virtual IMemoryBuffer* Read(const std::string& uuid,
-                                FileContentType type) ORTHANC_OVERRIDE;
+    // This flavor is only used in the "DelayedDeletion" plugin
+    IMemoryBuffer* ReadWhole(const std::string& uuid,
+                             FileContentType type);
 
     virtual IMemoryBuffer* ReadRange(const std::string& uuid,
                                      FileContentType type,
                                      uint64_t start /* inclusive */,
                                      uint64_t end /* exclusive */) ORTHANC_OVERRIDE;
 
-    virtual bool HasReadRange() const ORTHANC_OVERRIDE;
+    virtual bool HasEfficientReadRange() const ORTHANC_OVERRIDE
+    {
+      return true;
+    }
 
     virtual void Remove(const std::string& uuid,
                         FileContentType type) ORTHANC_OVERRIDE;
--- a/OrthancFramework/Sources/FileStorage/IStorageArea.h	Thu Mar 20 18:24:24 2025 +0100
+++ b/OrthancFramework/Sources/FileStorage/IStorageArea.h	Tue Mar 25 20:41:02 2025 +0100
@@ -51,17 +51,13 @@
                         CompressionType compression,
                         const DicomInstanceToStore* dicomInstance /* can be NULL if not a DICOM instance */) = 0;
 
-    virtual IMemoryBuffer* ReadWhole(const std::string& uuid,
-                                     FileContentType type,
-                                     const std::string& customData) = 0;
-
     virtual IMemoryBuffer* ReadRange(const std::string& uuid,
                                      FileContentType type,
                                      uint64_t start /* inclusive */,
                                      uint64_t end /* exclusive */,
                                      const std::string& customData) = 0;
 
-    virtual bool HasReadRange() const = 0;
+    virtual bool HasEfficientReadRange() const = 0;
 
     virtual void Remove(const std::string& uuid,
                         FileContentType type,
@@ -84,13 +80,6 @@
       Create(uuid, content, size, type);
     }
 
-    virtual IMemoryBuffer* ReadWhole(const std::string& uuid,
-                                     FileContentType type,
-                                     const std::string& customData) ORTHANC_OVERRIDE
-    {
-      return Read(uuid, type);
-    }
-
     virtual IMemoryBuffer* ReadRange(const std::string& uuid,
                                      FileContentType type,
                                      uint64_t start /* inclusive */,
@@ -112,9 +101,6 @@
                         size_t size,
                         FileContentType type) = 0;
 
-    virtual IMemoryBuffer* Read(const std::string& uuid,
-                                FileContentType type) = 0;
-
     virtual IMemoryBuffer* ReadRange(const std::string& uuid,
                                      FileContentType type,
                                      uint64_t start /* inclusive */,
--- a/OrthancFramework/Sources/FileStorage/MemoryStorageArea.cpp	Thu Mar 20 18:24:24 2025 +0100
+++ b/OrthancFramework/Sources/FileStorage/MemoryStorageArea.cpp	Tue Mar 25 20:41:02 2025 +0100
@@ -69,31 +69,6 @@
   }
 
   
-  IMemoryBuffer* MemoryStorageArea::Read(const std::string& uuid,
-                                         FileContentType type) 
-  {
-    LOG(INFO) << "Reading attachment \"" << uuid << "\" of \""
-              << static_cast<int>(type) << "\" content type";
-
-    Mutex::ScopedLock lock(mutex_);
-
-    Content::const_iterator found = content_.find(uuid);
-
-    if (found == content_.end())
-    {
-      throw OrthancException(ErrorCode_InexistentFile);
-    }
-    else if (found->second == NULL)
-    {
-      throw OrthancException(ErrorCode_InternalError);
-    }
-    else
-    {
-      return StringMemoryBuffer::CreateFromCopy(*found->second);
-    }
-  }
-      
-
   IMemoryBuffer* MemoryStorageArea::ReadRange(const std::string& uuid,
                                               FileContentType type,
                                               uint64_t start /* inclusive */,
@@ -143,12 +118,6 @@
   }
 
 
-  bool MemoryStorageArea::HasReadRange() const
-  {
-    return true;
-  }
-
-
   void MemoryStorageArea::Remove(const std::string& uuid,
                                  FileContentType type)
   {
--- a/OrthancFramework/Sources/FileStorage/MemoryStorageArea.h	Thu Mar 20 18:24:24 2025 +0100
+++ b/OrthancFramework/Sources/FileStorage/MemoryStorageArea.h	Tue Mar 25 20:41:02 2025 +0100
@@ -49,15 +49,15 @@
                         size_t size,
                         FileContentType type) ORTHANC_OVERRIDE;
 
-    virtual IMemoryBuffer* Read(const std::string& uuid,
-                                FileContentType type) ORTHANC_OVERRIDE;
-
     virtual IMemoryBuffer* ReadRange(const std::string& uuid,
                                      FileContentType type,
                                      uint64_t start /* inclusive */,
                                      uint64_t end /* exclusive */) ORTHANC_OVERRIDE;
     
-    virtual bool HasReadRange() const ORTHANC_OVERRIDE;
+    virtual bool HasEfficientReadRange() const ORTHANC_OVERRIDE
+    {
+      return true;
+    }
 
     virtual void Remove(const std::string& uuid,
                         FileContentType type) ORTHANC_OVERRIDE;
--- a/OrthancFramework/Sources/FileStorage/StorageAccessor.cpp	Thu Mar 20 18:24:24 2025 +0100
+++ b/OrthancFramework/Sources/FileStorage/StorageAccessor.cpp	Tue Mar 25 20:41:02 2025 +0100
@@ -439,7 +439,7 @@
 
         {
           MetricsTimer timer(*this, METRICS_READ_DURATION);
-          buffer.reset(area_.ReadWhole(info.GetUuid(), info.GetContentType(), info.GetCustomData()));
+          buffer.reset(area_.ReadRange(info.GetUuid(), info.GetContentType(), 0, info.GetCompressedSize(), info.GetCustomData()));
         }
 
         if (metrics_ != NULL)
@@ -460,7 +460,7 @@
         
         {
           MetricsTimer timer(*this, METRICS_READ_DURATION);
-          compressed.reset(area_.ReadWhole(info.GetUuid(), info.GetContentType(), info.GetCustomData()));
+          compressed.reset(area_.ReadRange(info.GetUuid(), info.GetContentType(), 0, info.GetCompressedSize(), info.GetCustomData()));
         }
         
         if (metrics_ != NULL)
@@ -519,7 +519,7 @@
 
     {
       MetricsTimer timer(*this, METRICS_READ_DURATION);
-      buffer.reset(area_.ReadWhole(info.GetUuid(), info.GetContentType(), info.GetCustomData()));
+      buffer.reset(area_.ReadRange(info.GetUuid(), info.GetContentType(), 0, info.GetCompressedSize(), info.GetCustomData()));
     }
 
     if (metrics_ != NULL)
@@ -688,7 +688,7 @@
       }
       else
       {
-        buffer.reset(area_.ReadWhole(info.GetUuid(), info.GetContentType(), info.GetCustomData()));
+        buffer.reset(area_.ReadRange(info.GetUuid(), info.GetContentType(), 0, info.GetCompressedSize(), info.GetCustomData()));
       }
 
       buffer->MoveToString(target);
--- a/OrthancFramework/UnitTestsSources/FileStorageTests.cpp	Thu Mar 20 18:24:24 2025 +0100
+++ b/OrthancFramework/UnitTestsSources/FileStorageTests.cpp	Tue Mar 25 20:41:02 2025 +0100
@@ -63,12 +63,18 @@
   s.Create(uid.c_str(), &data[0], data.size(), FileContentType_Unknown);
   std::string d;
   {
-    std::unique_ptr<IMemoryBuffer> buffer(s.Read(uid, FileContentType_Unknown));
+    std::unique_ptr<IMemoryBuffer> buffer(s.ReadWhole(uid, FileContentType_Unknown));
     buffer->MoveToString(d);    
   }
   ASSERT_EQ(d.size(), data.size());
   ASSERT_FALSE(memcmp(&d[0], &data[0], data.size()));
   ASSERT_EQ(s.GetSize(uid), data.size());
+  {
+    std::unique_ptr<IMemoryBuffer> buffer2(s.ReadRange(uid, FileContentType_Unknown, 0, uid.size()));
+    std::string d2;
+    buffer2->MoveToString(d2);
+    ASSERT_EQ(d, d2);
+  }
 }
 
 TEST(FilesystemStorage, Basic2)
@@ -81,12 +87,18 @@
   s.Create(uid.c_str(), &data[0], data.size(), FileContentType_Unknown);
   std::string d;
   {
-    std::unique_ptr<IMemoryBuffer> buffer(s.Read(uid, FileContentType_Unknown));
+    std::unique_ptr<IMemoryBuffer> buffer(s.ReadWhole(uid, FileContentType_Unknown));
     buffer->MoveToString(d);    
   }
   ASSERT_EQ(d.size(), data.size());
   ASSERT_FALSE(memcmp(&d[0], &data[0], data.size()));
   ASSERT_EQ(s.GetSize(uid), data.size());
+  {
+    std::unique_ptr<IMemoryBuffer> buffer2(s.ReadRange(uid, FileContentType_Unknown, 0, uid.size()));
+    std::string d2;
+    buffer2->MoveToString(d2);
+    ASSERT_EQ(d, d2);
+  }
 }
 
 TEST(FilesystemStorage, FileWithSameNameAsTopDirectory)
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Thu Mar 20 18:24:24 2025 +0100
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Tue Mar 25 20:41:02 2025 +0100
@@ -669,7 +669,46 @@
         }
       }
     };
-  
+
+
+    static IMemoryBuffer* GetRangeFromWhole(std::unique_ptr<MallocMemoryBuffer>& whole,
+                                            uint64_t start /* inclusive */,
+                                            uint64_t end /* exclusive */)
+    {
+      if (start > end)
+      {
+        throw OrthancException(ErrorCode_BadRange);
+      }
+      else if (start == end)
+      {
+        return new StringMemoryBuffer;  // Empty
+      }
+      else
+      {
+        if (start == 0 &&
+            end == whole->GetSize())
+        {
+          return whole.release();
+        }
+        else if (end > whole->GetSize())
+        {
+          throw OrthancException(ErrorCode_BadRange);
+        }
+        else
+        {
+          std::string range;
+          range.resize(end - start);
+          assert(!range.empty());
+
+          memcpy(&range[0], reinterpret_cast<const char*>(whole->GetData()) + start, range.size());
+
+          whole.reset(NULL);
+          return StringMemoryBuffer::CreateFromSwap(range);
+        }
+      }
+    }
+
+
     // "legacy" storage plugins don't store customData -> derive from ICoreStorageArea
     class PluginStorageAreaBase : public ICoreStorageArea
     {
@@ -684,46 +723,6 @@
         return errorDictionary_;
       }
 
-      IMemoryBuffer* RangeFromWhole(const std::string& uuid,
-                                    FileContentType type,
-                                    uint64_t start /* inclusive */,
-                                    uint64_t end /* exclusive */)
-      {
-        if (start > end)
-        {
-          throw OrthancException(ErrorCode_BadRange);
-        }
-        else if (start == end)
-        {
-          return new StringMemoryBuffer;  // Empty
-        }
-        else
-        {
-          std::unique_ptr<IMemoryBuffer> whole(Read(uuid, type));
-
-          if (start == 0 &&
-              end == whole->GetSize())
-          {
-            return whole.release();
-          }
-          else if (end > whole->GetSize())
-          {
-            throw OrthancException(ErrorCode_BadRange);
-          }
-          else
-          {
-            std::string range;
-            range.resize(end - start);
-            assert(!range.empty());
-            
-            memcpy(&range[0], reinterpret_cast<const char*>(whole->GetData()) + start, range.size());
-
-            whole.reset(NULL);
-            return StringMemoryBuffer::CreateFromSwap(range);
-          }
-        }
-      }      
-      
     public:
       PluginStorageAreaBase(OrthancPluginStorageCreate create,
                             OrthancPluginStorageRemove remove,
@@ -775,14 +774,6 @@
       OrthancPluginStorageRead   read_;
       OrthancPluginFree          free_;
       
-      void Free(void* buffer) const
-      {
-        if (buffer != NULL)
-        {
-          free_(buffer);
-        }
-      }
-
     public:
       PluginStorageArea(const _OrthancPluginRegisterStorageArea& callbacks,
                         PluginsErrorDictionary&  errorDictionary) :
@@ -796,21 +787,21 @@
         }
       }
 
-      virtual IMemoryBuffer* Read(const std::string& uuid,
-                                  FileContentType type) ORTHANC_OVERRIDE
-      {
-        std::unique_ptr<MallocMemoryBuffer> result(new MallocMemoryBuffer);
-
+      virtual IMemoryBuffer* ReadRange(const std::string& uuid,
+                                       FileContentType type,
+                                       uint64_t start /* inclusive */,
+                                       uint64_t end /* exclusive */) ORTHANC_OVERRIDE
+      {
         void* buffer = NULL;
         int64_t size = 0;
 
-        OrthancPluginErrorCode error = read_
-          (&buffer, &size, uuid.c_str(), Plugins::Convert(type));
+        OrthancPluginErrorCode error = read_(&buffer, &size, uuid.c_str(), Plugins::Convert(type));
 
         if (error == OrthancPluginErrorCode_Success)
         {
-          result->Assign(buffer, size, free_);
-          return result.release();
+          std::unique_ptr<MallocMemoryBuffer> whole(new MallocMemoryBuffer);
+          whole->Assign(buffer, size, free_);
+          return GetRangeFromWhole(whole, start, end);
         }
         else
         {
@@ -819,15 +810,7 @@
         }
       }
 
-      virtual IMemoryBuffer* ReadRange(const std::string& uuid,
-                                       FileContentType type,
-                                       uint64_t start /* inclusive */,
-                                       uint64_t end /* exclusive */) ORTHANC_OVERRIDE
-      {
-        return RangeFromWhole(uuid, type, start, end);
-      }
-
-      virtual bool HasReadRange() const ORTHANC_OVERRIDE
+      virtual bool HasEfficientReadRange() const ORTHANC_OVERRIDE
       {
         return false;
       }
@@ -854,29 +837,6 @@
         }
       }
 
-      virtual IMemoryBuffer* Read(const std::string& uuid,
-                                  FileContentType type) ORTHANC_OVERRIDE
-      {
-        std::unique_ptr<MallocMemoryBuffer> result(new MallocMemoryBuffer);
-
-        OrthancPluginMemoryBuffer64 buffer;
-        buffer.size = 0;
-        buffer.data = NULL;
-        
-        OrthancPluginErrorCode error = readWhole_(&buffer, uuid.c_str(), Plugins::Convert(type));
-
-        if (error == OrthancPluginErrorCode_Success)
-        {
-          result->Assign(buffer.data, buffer.size, ::free);
-          return result.release();
-        }
-        else
-        {
-          GetErrorDictionary().LogError(error, true);
-          throw OrthancException(static_cast<ErrorCode>(error));
-        }
-      }
-
       virtual IMemoryBuffer* ReadRange(const std::string& uuid,
                                        FileContentType type,
                                        uint64_t start /* inclusive */,
@@ -884,7 +844,23 @@
       {
         if (readRange_ == NULL)
         {
-          return RangeFromWhole(uuid, type, start, end);
+          OrthancPluginMemoryBuffer64 buffer;
+          buffer.size = 0;
+          buffer.data = NULL;
+
+          OrthancPluginErrorCode error = readWhole_(&buffer, uuid.c_str(), Plugins::Convert(type));
+
+          if (error == OrthancPluginErrorCode_Success)
+          {
+            std::unique_ptr<MallocMemoryBuffer> whole(new MallocMemoryBuffer);
+            whole->Assign(buffer.data, buffer.size, ::free);
+            return GetRangeFromWhole(whole, start, end);
+          }
+          else
+          {
+            GetErrorDictionary().LogError(error, true);
+            throw OrthancException(static_cast<ErrorCode>(error));
+          }
         }
         else
         {
@@ -922,7 +898,7 @@
         }
       }
       
-      virtual bool HasReadRange() const ORTHANC_OVERRIDE
+      virtual bool HasEfficientReadRange() const ORTHANC_OVERRIDE
       {
         return (readRange_ != NULL);
       }
@@ -934,7 +910,6 @@
     {
     private:
       OrthancPluginStorageCreate2     create_;
-      OrthancPluginStorageReadWhole2  readWhole2_;
       OrthancPluginStorageReadRange2  readRange2_;
       OrthancPluginStorageRemove2     remove2_;
 
@@ -946,58 +921,16 @@
         return errorDictionary_;
       }
 
-      IMemoryBuffer* RangeFromWhole(const std::string& uuid,
-                                    const std::string& customData,
-                                    FileContentType type,
-                                    uint64_t start /* inclusive */,
-                                    uint64_t end /* exclusive */)
-      {
-        if (start > end)
-        {
-          throw OrthancException(ErrorCode_BadRange);
-        }
-        else if (start == end)
-        {
-          return new StringMemoryBuffer;  // Empty
-        }
-        else
-        {
-          std::unique_ptr<IMemoryBuffer> whole(ReadWhole(uuid, type, customData));
-
-          if (start == 0 &&
-              end == whole->GetSize())
-          {
-            return whole.release();
-          }
-          else if (end > whole->GetSize())
-          {
-            throw OrthancException(ErrorCode_BadRange);
-          }
-          else
-          {
-            std::string range;
-            range.resize(end - start);
-            assert(!range.empty());
-            
-            memcpy(&range[0], reinterpret_cast<const char*>(whole->GetData()) + start, range.size());
-
-            whole.reset(NULL);
-            return StringMemoryBuffer::CreateFromSwap(range);
-          }
-        }
-      }      
-      
     public:
       PluginStorageArea3(const _OrthancPluginRegisterStorageArea3& callbacks,
                          PluginsErrorDictionary&  errorDictionary) :
         create_(callbacks.create),
-        readWhole2_(callbacks.readWhole),
         readRange2_(callbacks.readRange),
         remove2_(callbacks.remove),
         errorDictionary_(errorDictionary)
       {
         if (create_ == NULL ||
-            readWhole2_ == NULL ||
+            readRange2_ == NULL ||
             remove2_ == NULL)
         {
           throw OrthancException(ErrorCode_Plugin, "Storage area plugin doesn't implement all the required primitives (createInstance, remove, readWhole");
@@ -1051,78 +984,46 @@
         }
       }
 
-      virtual IMemoryBuffer* ReadWhole(const std::string& uuid,
-                                       FileContentType type,
-                                       const std::string& customData) ORTHANC_OVERRIDE
-      {
-        std::unique_ptr<MallocMemoryBuffer> result(new MallocMemoryBuffer);
-
-        OrthancPluginMemoryBuffer64 buffer;
-        buffer.size = 0;
-        buffer.data = NULL;
-        
-        OrthancPluginErrorCode error = readWhole2_(&buffer, uuid.c_str(), Plugins::Convert(type),
-                                                   customData.empty() ? NULL : customData.c_str(), customData.size());
-
-        if (error == OrthancPluginErrorCode_Success)
-        {
-          result->Assign(buffer.data, buffer.size, ::free);
-          return result.release();
-        }
-        else
-        {
-          GetErrorDictionary().LogError(error, true);
-          throw OrthancException(static_cast<ErrorCode>(error));
-        }
-      }
-
       virtual IMemoryBuffer* ReadRange(const std::string& uuid,
                                        FileContentType type,
                                        uint64_t start /* inclusive */,
                                        uint64_t end /* exclusive */,
                                        const std::string& customData) ORTHANC_OVERRIDE
       {
-        if (readRange2_ == NULL)
-        {
-          return RangeFromWhole(uuid, customData, type, start, end);
+        if (start > end)
+        {
+          throw OrthancException(ErrorCode_BadRange);
+        }
+        else if (start == end)
+        {
+          return new StringMemoryBuffer;
         }
         else
         {
-          if (start > end)
+          std::string range;
+          range.resize(end - start);
+          assert(!range.empty());
+
+          OrthancPluginMemoryBuffer64 buffer;
+          buffer.data = &range[0];
+          buffer.size = static_cast<uint64_t>(range.size());
+
+          OrthancPluginErrorCode error =
+            readRange2_(&buffer, uuid.c_str(), Plugins::Convert(type), start, customData.empty() ? NULL : customData.c_str(), customData.size());
+
+          if (error == OrthancPluginErrorCode_Success)
           {
-            throw OrthancException(ErrorCode_BadRange);
-          }
-          else if (start == end)
-          {
-            return new StringMemoryBuffer;
+            return StringMemoryBuffer::CreateFromSwap(range);
           }
           else
           {
-            std::string range;
-            range.resize(end - start);
-            assert(!range.empty());
-
-            OrthancPluginMemoryBuffer64 buffer;
-            buffer.data = &range[0];
-            buffer.size = static_cast<uint64_t>(range.size());
-
-            OrthancPluginErrorCode error =
-              readRange2_(&buffer, uuid.c_str(), Plugins::Convert(type), start, customData.empty() ? NULL : customData.c_str(), customData.size());
-
-            if (error == OrthancPluginErrorCode_Success)
-            {
-              return StringMemoryBuffer::CreateFromSwap(range);
-            }
-            else
-            {
-              GetErrorDictionary().LogError(error, true);
-              throw OrthancException(static_cast<ErrorCode>(error));
-            }
+            GetErrorDictionary().LogError(error, true);
+            throw OrthancException(static_cast<ErrorCode>(error));
           }
         }
       }
 
-      virtual bool HasReadRange() const ORTHANC_OVERRIDE
+      virtual bool HasEfficientReadRange() const ORTHANC_OVERRIDE
       {
         return (readRange2_ != NULL);
       }
@@ -5355,15 +5256,7 @@
       }
 
       case _OrthancPluginService_StorageAreaRead:
-      {
-        const _OrthancPluginStorageAreaRead& p =
-          *reinterpret_cast<const _OrthancPluginStorageAreaRead*>(parameters);
-        IStorageArea& storage = *reinterpret_cast<IStorageArea*>(p.storageArea);
-        std::string customDataNotUsed;
-        std::unique_ptr<IMemoryBuffer> content(storage.ReadWhole(p.uuid, Plugins::Convert(p.type), customDataNotUsed));
-        CopyToMemoryBuffer(*p.target, content->GetData(), content->GetSize());
-        return true;
-      }
+        throw OrthancException(ErrorCode_NotImplemented, "The SDK function OrthancPluginStorageAreaRead() is only available in Orthanc <= 1.12.6");
 
       case _OrthancPluginService_StorageAreaRemove:
       {
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Thu Mar 20 18:24:24 2025 +0100
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Mar 25 20:41:02 2025 +0100
@@ -1473,28 +1473,6 @@
 
 
   /**
-   * @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 customData The custom data of the file of interest.
-   * @param type The content type corresponding to this file.
-   * @ingroup Callbacks
-   **/
-  typedef OrthancPluginErrorCode (*OrthancPluginStorageReadWhole2) (
-    OrthancPluginMemoryBuffer64* target,
-    const char* uuid,
-    OrthancPluginContentType type,
-    const void* customData,
-    uint64_t customDataSize);
-
-
-
-  /**
    * @brief Callback for reading a range of a file from the storage area.
    *
    * Signature of a callback function that is triggered when Orthanc
@@ -5052,6 +5030,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,
@@ -9465,7 +9445,6 @@
   typedef struct
   {
     OrthancPluginStorageCreate2     create;
-    OrthancPluginStorageReadWhole2  readWhole;
     OrthancPluginStorageReadRange2  readRange;
     OrthancPluginStorageRemove2     remove;
   } _OrthancPluginRegisterStorageArea3;
@@ -9489,13 +9468,11 @@
   ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterStorageArea3(
     OrthancPluginContext*           context,
     OrthancPluginStorageCreate2     create,
-    OrthancPluginStorageReadWhole2  readWhole,
     OrthancPluginStorageReadRange2  readRange,
     OrthancPluginStorageRemove2     remove)
   {
     _OrthancPluginRegisterStorageArea3 params;
     params.create = create;
-    params.readWhole = readWhole;
     params.readRange = readRange;
     params.remove = remove;
     context->InvokeService(context, _OrthancPluginService_RegisterStorageArea3, &params);
--- a/OrthancServer/Plugins/Samples/DelayedDeletion/Plugin.cpp	Thu Mar 20 18:24:24 2025 +0100
+++ b/OrthancServer/Plugins/Samples/DelayedDeletion/Plugin.cpp	Tue Mar 25 20:41:02 2025 +0100
@@ -113,7 +113,7 @@
 {
   try
   {
-    std::unique_ptr<Orthanc::IMemoryBuffer> buffer(storage_->Read(uuid, Convert(type)));
+    std::unique_ptr<Orthanc::IMemoryBuffer> buffer(storage_->ReadWhole(uuid, Convert(type)));
 
     // copy from a buffer allocated on plugin's heap into a buffer allocated on core's heap
     if (OrthancPluginCreateMemoryBuffer64(OrthancPlugins::GetGlobalContext(), target, buffer->GetSize()) != OrthancPluginErrorCode_Success)
--- a/OrthancServer/Sources/OrthancInitialization.cpp	Thu Mar 20 18:24:24 2025 +0100
+++ b/OrthancServer/Sources/OrthancInitialization.cpp	Tue Mar 25 20:41:02 2025 +0100
@@ -476,19 +476,6 @@
         }
       }
 
-      virtual IMemoryBuffer* Read(const std::string& uuid,
-                                  FileContentType type) ORTHANC_OVERRIDE
-      {
-        if (type != FileContentType_Dicom)
-        {
-          return storage_.Read(uuid, type);
-        }
-        else
-        {
-          throw OrthancException(ErrorCode_UnknownResource);
-        }
-      }
-
       virtual IMemoryBuffer* ReadRange(const std::string& uuid,
                                        FileContentType type,
                                        uint64_t start /* inclusive */,
@@ -504,9 +491,9 @@
         }
       }
 
-      virtual bool HasReadRange() const ORTHANC_OVERRIDE
+      virtual bool HasEfficientReadRange() const ORTHANC_OVERRIDE
       {
-        return storage_.HasReadRange();
+        return storage_.HasEfficientReadRange();
       }
 
       virtual void Remove(const std::string& uuid,
--- a/OrthancServer/Sources/ServerContext.cpp	Thu Mar 20 18:24:24 2025 +0100
+++ b/OrthancServer/Sources/ServerContext.cpp	Tue Mar 25 20:41:02 2025 +0100
@@ -754,7 +754,7 @@
 
       FileInfo dicomUntilPixelData;
       if (hasPixelDataOffset &&
-          (!area_.HasReadRange() ||
+          (!area_.HasEfficientReadRange() ||
            compressionEnabled_))
       {
         dicomUntilPixelData = accessor.Write(dicom.GetBufferData(), pixelDataOffset, FileContentType_DicomUntilPixelData, compression, storeMD5_, NULL);
@@ -1248,7 +1248,7 @@
 
 
       if (hasPixelDataOffset &&
-          area_.HasReadRange() &&
+          area_.HasEfficientReadRange() &&
           LookupAttachment(attachment, FileContentType_Dicom, instanceAttachments) &&
           attachment.GetCompressionType() == CompressionType_None)
       {
@@ -1326,7 +1326,7 @@
             index_.OverwriteMetadata(instancePublicId, MetadataType_Instance_PixelDataOffset,
                                      boost::lexical_cast<std::string>(pixelDataOffset));
 
-            if (!area_.HasReadRange() ||
+            if (!area_.HasEfficientReadRange() ||
                 compressionEnabled_)
             {
               int64_t newRevision;
@@ -1401,7 +1401,7 @@
       return true;
     }
 
-    if (!area_.HasReadRange())
+    if (!area_.HasEfficientReadRange())
     {
       return false;
     }