changeset 4484:64f06e7d5fc7

new abstraction IMemoryBuffer to avoid unnecessary copies of std::string buffers
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 28 Jan 2021 19:03:19 +0100
parents a926f8995d0b
children f19de27a2465
files OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake 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/Sources/IMemoryBuffer.h OrthancFramework/Sources/MallocMemoryBuffer.cpp OrthancFramework/Sources/MallocMemoryBuffer.h OrthancFramework/Sources/StringMemoryBuffer.cpp OrthancFramework/Sources/StringMemoryBuffer.h OrthancFramework/UnitTestsSources/FileStorageTests.cpp OrthancServer/Plugins/Engine/OrthancPlugins.cpp OrthancServer/Sources/OrthancInitialization.cpp
diffstat 15 files changed, 408 insertions(+), 118 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake	Thu Jan 28 16:59:40 2021 +0100
+++ b/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake	Thu Jan 28 19:03:19 2021 +0100
@@ -158,11 +158,13 @@
   ${CMAKE_CURRENT_LIST_DIR}/../../Sources/HttpServer/MultipartStreamReader.cpp
   ${CMAKE_CURRENT_LIST_DIR}/../../Sources/HttpServer/StringMatcher.cpp
   ${CMAKE_CURRENT_LIST_DIR}/../../Sources/Logging.cpp
+  ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MallocMemoryBuffer.cpp
   ${CMAKE_CURRENT_LIST_DIR}/../../Sources/OrthancException.cpp
   ${CMAKE_CURRENT_LIST_DIR}/../../Sources/OrthancFramework.cpp
   ${CMAKE_CURRENT_LIST_DIR}/../../Sources/RestApi/RestApiHierarchy.cpp
   ${CMAKE_CURRENT_LIST_DIR}/../../Sources/RestApi/RestApiPath.cpp
   ${CMAKE_CURRENT_LIST_DIR}/../../Sources/SerializationToolbox.cpp
+  ${CMAKE_CURRENT_LIST_DIR}/../../Sources/StringMemoryBuffer.cpp
   ${CMAKE_CURRENT_LIST_DIR}/../../Sources/Toolbox.cpp
   ${CMAKE_CURRENT_LIST_DIR}/../../Sources/WebServiceParameters.cpp
   )
--- a/OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp	Thu Jan 28 16:59:40 2021 +0100
+++ b/OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp	Thu Jan 28 19:03:19 2021 +0100
@@ -28,8 +28,9 @@
 
 #include "../Logging.h"
 #include "../OrthancException.h"
+#include "../StringMemoryBuffer.h"
+#include "../SystemToolbox.h"
 #include "../Toolbox.h"
-#include "../SystemToolbox.h"
 
 #include <boost/filesystem/fstream.hpp>
 
@@ -150,15 +151,16 @@
   }
 
 
-  void FilesystemStorage::Read(std::string& content,
-                               const std::string& uuid,
-                               FileContentType type)
+  IMemoryBuffer* FilesystemStorage::Read(const std::string& uuid,
+                                         FileContentType type)
   {
     LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) 
               << "\" content type";
 
-    content.clear();
+    std::string content;
     SystemToolbox::ReadFile(content, GetPath(uuid).string());
+
+    return StringMemoryBuffer::CreateFromSwap(content);
   }
 
 
@@ -282,4 +284,15 @@
     Setup(root);
   }
 #endif
+
+
+#if ORTHANC_BUILDING_FRAMEWORK_LIBRARY == 1
+  void FilesystemStorage::Read(std::string& content,
+                               const std::string& uuid,
+                               FileContentType type)
+  {
+    std::unique_ptr<IMemoryBuffer> buffer(Read(uuid, type));
+    buffer->MoveToString(content);
+  }
+#endif
 }
--- a/OrthancFramework/Sources/FileStorage/FilesystemStorage.h	Thu Jan 28 16:59:40 2021 +0100
+++ b/OrthancFramework/Sources/FileStorage/FilesystemStorage.h	Thu Jan 28 19:03:19 2021 +0100
@@ -60,6 +60,13 @@
     explicit FilesystemStorage(std::string root);
 #endif
 
+#if ORTHANC_BUILDING_FRAMEWORK_LIBRARY == 1
+    // Binary compatibility with Orthanc Framework <= 1.8.2
+    void Read(std::string& content,
+              const std::string& uuid,
+              FileContentType type);
+#endif
+
   public:
     explicit FilesystemStorage(const std::string& root);
 
@@ -71,9 +78,8 @@
                         size_t size,
                         FileContentType type) ORTHANC_OVERRIDE;
 
-    virtual void Read(std::string& content,
-                      const std::string& uuid,
-                      FileContentType type) ORTHANC_OVERRIDE;
+    virtual IMemoryBuffer* Read(const std::string& uuid,
+                                FileContentType type) ORTHANC_OVERRIDE;
 
     virtual void Remove(const std::string& uuid,
                         FileContentType type) ORTHANC_OVERRIDE;
--- a/OrthancFramework/Sources/FileStorage/IStorageArea.h	Thu Jan 28 16:59:40 2021 +0100
+++ b/OrthancFramework/Sources/FileStorage/IStorageArea.h	Thu Jan 28 19:03:19 2021 +0100
@@ -22,10 +22,10 @@
 
 #pragma once
 
+#include "../IMemoryBuffer.h"
 #include "../Enumerations.h"
 
 #include <string>
-#include <boost/noncopyable.hpp>
 
 namespace Orthanc
 {
@@ -41,9 +41,8 @@
                         size_t size,
                         FileContentType type) = 0;
 
-    virtual void Read(std::string& content,
-                      const std::string& uuid,
-                      FileContentType type) = 0;
+    virtual IMemoryBuffer* Read(const std::string& uuid,
+                                FileContentType type) = 0;
 
     virtual void Remove(const std::string& uuid,
                         FileContentType type) = 0;
--- a/OrthancFramework/Sources/FileStorage/MemoryStorageArea.cpp	Thu Jan 28 16:59:40 2021 +0100
+++ b/OrthancFramework/Sources/FileStorage/MemoryStorageArea.cpp	Thu Jan 28 19:03:19 2021 +0100
@@ -23,8 +23,9 @@
 #include "../PrecompiledHeaders.h"
 #include "MemoryStorageArea.h"
 
+#include "../Logging.h"
 #include "../OrthancException.h"
-#include "../Logging.h"
+#include "../StringMemoryBuffer.h"
 
 namespace Orthanc
 {
@@ -65,9 +66,8 @@
   }
 
   
-  void MemoryStorageArea::Read(std::string& content,
-                               const std::string& uuid,
-                               FileContentType type)
+  IMemoryBuffer* MemoryStorageArea::Read(const std::string& uuid,
+                                         FileContentType type) 
   {
     LOG(INFO) << "Reading attachment \"" << uuid << "\" of \""
               << static_cast<int>(type) << "\" content type";
@@ -86,7 +86,7 @@
     }
     else
     {
-      content.assign(*found->second);
+      return StringMemoryBuffer::CreateFromCopy(*found->second);
     }
   }
       
--- a/OrthancFramework/Sources/FileStorage/MemoryStorageArea.h	Thu Jan 28 16:59:40 2021 +0100
+++ b/OrthancFramework/Sources/FileStorage/MemoryStorageArea.h	Thu Jan 28 19:03:19 2021 +0100
@@ -47,9 +47,8 @@
                         size_t size,
                         FileContentType type) ORTHANC_OVERRIDE;
 
-    virtual void Read(std::string& content,
-                      const std::string& uuid,
-                      FileContentType type) ORTHANC_OVERRIDE;
+    virtual IMemoryBuffer* Read(const std::string& uuid,
+                                FileContentType type) ORTHANC_OVERRIDE;
 
     virtual void Remove(const std::string& uuid,
                         FileContentType type) ORTHANC_OVERRIDE;
--- a/OrthancFramework/Sources/FileStorage/StorageAccessor.cpp	Thu Jan 28 16:59:40 2021 +0100
+++ b/OrthancFramework/Sources/FileStorage/StorageAccessor.cpp	Thu Jan 28 19:03:19 2021 +0100
@@ -147,10 +147,12 @@
   {
     switch (info.GetCompressionType())
     {
-    case CompressionType_None:
-    {
-      MetricsTimer timer(*this, METRICS_READ);
-      area_.Read(content, info.GetUuid(), info.GetContentType());
+      case CompressionType_None:
+      {
+        MetricsTimer timer(*this, METRICS_READ);
+
+        std::unique_ptr<IMemoryBuffer> buffer(area_.Read(info.GetUuid(), info.GetContentType()));
+        buffer->MoveToString(content);        
         break;
       }
 
@@ -158,14 +160,14 @@
       {
         ZlibCompressor zlib;
 
-        std::string compressed;
+        std::unique_ptr<IMemoryBuffer> compressed;
 
         {
           MetricsTimer timer(*this, METRICS_READ);
-          area_.Read(compressed, info.GetUuid(), info.GetContentType());
+          compressed.reset(area_.Read(info.GetUuid(), info.GetContentType()));
         }
 
-        IBufferCompressor::Uncompress(content, zlib, compressed);
+        zlib.Uncompress(content, compressed->GetData(), compressed->GetSize());
         break;
       }
 
@@ -183,7 +185,9 @@
                                 const FileInfo& info)
   {
     MetricsTimer timer(*this, METRICS_READ);
-    area_.Read(content, info.GetUuid(), info.GetContentType());
+
+    std::unique_ptr<IMemoryBuffer> buffer(area_.Read(info.GetUuid(), info.GetContentType()));
+    buffer->MoveToString(content);        
   }
 
 
@@ -206,7 +210,8 @@
   {
     {
       MetricsTimer timer(*this, METRICS_READ);
-      area_.Read(sender.GetBuffer(), info.GetUuid(), info.GetContentType());
+      std::unique_ptr<IMemoryBuffer> buffer(area_.Read(info.GetUuid(), info.GetContentType()));
+      buffer->MoveToString(sender.GetBuffer());
     }
 
     sender.SetContentType(mime);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Sources/IMemoryBuffer.h	Thu Jan 28 19:03:19 2021 +0100
@@ -0,0 +1,48 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2021 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include <string>
+#include <boost/noncopyable.hpp>
+
+namespace Orthanc
+{
+  /**
+   * This class abstracts a memory buffer and its memory unallocation
+   * function.
+   **/
+  class IMemoryBuffer : public boost::noncopyable
+  {
+  public:
+    virtual ~IMemoryBuffer()
+    {
+    }
+
+    // The content of the memory buffer will emptied after this call
+    virtual void MoveToString(std::string& target) = 0;
+
+    virtual const void* GetData() const = 0;
+
+    virtual size_t GetSize() const = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Sources/MallocMemoryBuffer.cpp	Thu Jan 28 19:03:19 2021 +0100
@@ -0,0 +1,87 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2021 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "PrecompiledHeaders.h"
+#include "MallocMemoryBuffer.h"
+
+#include "OrthancException.h"
+
+#include <string.h>
+
+
+namespace Orthanc
+{
+  MallocMemoryBuffer::MallocMemoryBuffer() :
+    buffer_(NULL),
+    size_(0),
+    free_(NULL)
+  {
+  }
+
+
+  void MallocMemoryBuffer::Clear()
+  {
+    if (size_ != 0)
+    {
+      if (free_ == NULL)
+      {
+        throw OrthancException(ErrorCode_InternalError);
+      }
+        
+      free_(buffer_);
+      buffer_ = NULL;
+      size_ = 0;
+      free_ = NULL;
+    }
+  }
+
+    
+  void MallocMemoryBuffer::Assign(void* buffer,
+                                  size_t size,
+                                  FreeFunction freeFunction)
+  {
+    Clear();
+
+    buffer_ = buffer;
+    size_ = size;
+    free_ = freeFunction;
+
+    if (size_ != 0 &&
+        free_ == NULL)
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange, "No valid free() function provided");
+    }
+  }
+
+    
+  void MallocMemoryBuffer::MoveToString(std::string& target)
+  {
+    target.resize(size_);
+
+    if (size_ != 0)
+    {
+      memcpy(&target[0], buffer_, size_);
+    }
+
+    Clear();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Sources/MallocMemoryBuffer.h	Thu Jan 28 19:03:19 2021 +0100
@@ -0,0 +1,67 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2021 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "IMemoryBuffer.h"
+#include "Compatibility.h"
+
+
+namespace Orthanc
+{
+  class MallocMemoryBuffer : public IMemoryBuffer
+  {
+  public:
+    typedef void (*FreeFunction) (void* buffer);
+    
+  private:
+    void*         buffer_;
+    size_t        size_;
+    FreeFunction  free_;
+
+  public:
+    MallocMemoryBuffer();
+
+    virtual ~MallocMemoryBuffer()
+    {
+      Clear();
+    }
+
+    void Clear();
+
+    void Assign(void* buffer,
+                size_t size,
+                FreeFunction freeFunction);
+    
+    virtual void MoveToString(std::string& target) ORTHANC_OVERRIDE;
+
+    virtual const void* GetData() const ORTHANC_OVERRIDE
+    {
+      return buffer_;
+    }
+
+    virtual size_t GetSize() const ORTHANC_OVERRIDE
+    {
+      return size_;
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Sources/StringMemoryBuffer.cpp	Thu Jan 28 19:03:19 2021 +0100
@@ -0,0 +1,50 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2021 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "PrecompiledHeaders.h"
+#include "StringMemoryBuffer.h"
+
+
+namespace Orthanc
+{
+  void StringMemoryBuffer::MoveToString(std::string& target)
+  {
+    buffer_.swap(target);
+    buffer_.clear();
+  }
+
+
+  IMemoryBuffer* StringMemoryBuffer::CreateFromSwap(std::string& buffer)
+  {
+    std::unique_ptr<StringMemoryBuffer> result(new StringMemoryBuffer);
+    result->Swap(buffer);
+    return result.release();
+  }
+
+    
+  IMemoryBuffer* StringMemoryBuffer::CreateFromCopy(const std::string& buffer)
+  {
+    std::unique_ptr<StringMemoryBuffer> result(new StringMemoryBuffer);
+    result->Copy(buffer);
+    return result.release();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Sources/StringMemoryBuffer.h	Thu Jan 28 19:03:19 2021 +0100
@@ -0,0 +1,62 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2021 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "IMemoryBuffer.h"
+#include "Compatibility.h"
+
+namespace Orthanc
+{
+  class StringMemoryBuffer : public IMemoryBuffer
+  {
+  private:
+    std::string   buffer_;
+
+  public:
+    void Copy(const std::string& buffer)
+    {
+      buffer_ = buffer;
+    }
+
+    void Swap(std::string& buffer)
+    {
+      buffer_.swap(buffer);
+    }
+
+    virtual void MoveToString(std::string& target) ORTHANC_OVERRIDE;
+
+    virtual const void* GetData() const ORTHANC_OVERRIDE
+    {
+      return (buffer_.empty() ? NULL : buffer_.c_str());
+    }
+
+    virtual size_t GetSize() const ORTHANC_OVERRIDE
+    {
+      return buffer_.size();
+    }
+
+    static IMemoryBuffer* CreateFromSwap(std::string& buffer);
+
+    static IMemoryBuffer* CreateFromCopy(const std::string& buffer);
+  };
+}
--- a/OrthancFramework/UnitTestsSources/FileStorageTests.cpp	Thu Jan 28 16:59:40 2021 +0100
+++ b/OrthancFramework/UnitTestsSources/FileStorageTests.cpp	Thu Jan 28 19:03:19 2021 +0100
@@ -58,7 +58,10 @@
   std::string uid = Toolbox::GenerateUuid();
   s.Create(uid.c_str(), &data[0], data.size(), FileContentType_Unknown);
   std::string d;
-  s.Read(d, uid, FileContentType_Unknown);
+  {
+    std::unique_ptr<IMemoryBuffer> buffer(s.Read(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());
@@ -73,7 +76,10 @@
   std::string uid = Toolbox::GenerateUuid();
   s.Create(uid.c_str(), &data[0], data.size(), FileContentType_Unknown);
   std::string d;
-  s.Read(d, uid, FileContentType_Unknown);
+  {
+    std::unique_ptr<IMemoryBuffer> buffer(s.Read(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());
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Thu Jan 28 16:59:40 2021 +0100
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Thu Jan 28 19:03:19 2021 +0100
@@ -59,6 +59,7 @@
 #include "../../../OrthancFramework/Sources/Images/PngWriter.h"
 #include "../../../OrthancFramework/Sources/Logging.h"
 #include "../../../OrthancFramework/Sources/Lua/LuaFunctionCall.h"
+#include "../../../OrthancFramework/Sources/MallocMemoryBuffer.h"
 #include "../../../OrthancFramework/Sources/MetricsRegistry.h"
 #include "../../../OrthancFramework/Sources/OrthancException.h"
 #include "../../../OrthancFramework/Sources/SerializationToolbox.h"
@@ -198,51 +199,6 @@
     };
   
 
-    class MemoryBuffer64Raii : public boost::noncopyable
-    {
-    private:
-      OrthancPluginMemoryBuffer64  buffer_;
-
-    public:
-      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:
@@ -328,38 +284,27 @@
         }
       }
 
-      virtual void Read(std::string& content,
-                        const std::string& uuid,
-                        FileContentType type) ORTHANC_OVERRIDE
-      {
+      virtual IMemoryBuffer* Read(const std::string& uuid,
+                                  FileContentType type) ORTHANC_OVERRIDE
+      {
+        std::unique_ptr<MallocMemoryBuffer> result(new MallocMemoryBuffer);
+
         void* buffer = NULL;
         int64_t size = 0;
 
         OrthancPluginErrorCode error = read_
           (&buffer, &size, uuid.c_str(), Plugins::Convert(type));
 
-        if (error != OrthancPluginErrorCode_Success)
+        if (error == OrthancPluginErrorCode_Success)
+        {
+          result->Assign(buffer, size, free_);
+          return result.release();
+        }
+        else
         {
           GetErrorDictionary().LogError(error, true);
           throw OrthancException(static_cast<ErrorCode>(error));
         }
-
-        try
-        {
-          content.resize(static_cast<size_t>(size));
-        }
-        catch (...)
-        {
-          Free(buffer);
-          throw OrthancException(ErrorCode_NotEnoughMemory);
-        }
-
-        if (size > 0)
-        {
-          memcpy(&content[0], buffer, static_cast<size_t>(size));
-        }
-
-        Free(buffer);
       }
     };
 
@@ -384,22 +329,25 @@
         }
       }
 
-      virtual void Read(std::string& content,
-                        const std::string& uuid,
-                        FileContentType type) ORTHANC_OVERRIDE
-      {
-        MemoryBuffer64Raii buffer;
+      virtual IMemoryBuffer* Read(const std::string& uuid,
+                                  FileContentType type) ORTHANC_OVERRIDE
+      {
+        std::unique_ptr<MallocMemoryBuffer> result(new MallocMemoryBuffer);
+
+        OrthancPluginMemoryBuffer64 buffer;
         
-        OrthancPluginErrorCode error = readWhole_
-          (buffer.GetObject(), uuid.c_str(), Plugins::Convert(type));
-
-        if (error != OrthancPluginErrorCode_Success)
+        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));
         }
-
-        buffer.ToString(content);
       }
     };
 
@@ -4196,9 +4144,8 @@
         const _OrthancPluginStorageAreaRead& p =
           *reinterpret_cast<const _OrthancPluginStorageAreaRead*>(parameters);
         IStorageArea& storage = *reinterpret_cast<IStorageArea*>(p.storageArea);
-        std::string content;
-        storage.Read(content, p.uuid, Plugins::Convert(p.type));
-        CopyToMemoryBuffer(*p.target, content);
+        std::unique_ptr<IMemoryBuffer> content(storage.Read(p.uuid, Plugins::Convert(p.type)));
+        CopyToMemoryBuffer(*p.target, content->GetData(), content->GetSize());
         return true;
       }
 
--- a/OrthancServer/Sources/OrthancInitialization.cpp	Thu Jan 28 16:59:40 2021 +0100
+++ b/OrthancServer/Sources/OrthancInitialization.cpp	Thu Jan 28 19:03:19 2021 +0100
@@ -359,7 +359,7 @@
       virtual void Create(const std::string& uuid,
                           const void* content, 
                           size_t size,
-                          FileContentType type)
+                          FileContentType type) ORTHANC_OVERRIDE
       {
         if (type != FileContentType_Dicom)
         {
@@ -367,13 +367,12 @@
         }
       }
 
-      virtual void Read(std::string& content,
-                        const std::string& uuid,
-                        FileContentType type)
+      virtual IMemoryBuffer* Read(const std::string& uuid,
+                                  FileContentType type) ORTHANC_OVERRIDE
       {
         if (type != FileContentType_Dicom)
         {
-          storage_.Read(content, uuid, type);
+          return storage_.Read(uuid, type);
         }
         else
         {
@@ -382,7 +381,7 @@
       }
 
       virtual void Remove(const std::string& uuid,
-                          FileContentType type) 
+                          FileContentType type) ORTHANC_OVERRIDE
       {
         if (type != FileContentType_Dicom)
         {