changeset 6792:323f93009cc8

added DicomDataSource::ReadUntilPixelData()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sun, 17 May 2026 18:54:12 +0200
parents ebd42c3fb06a
children 4514943d9239
files OrthancFramework/Sources/DataSource/StorageAreaDataSource.cpp OrthancFramework/Sources/DataSource/StorageAreaDataSource.h OrthancFramework/UnitTestsSources/JobsTests.cpp
diffstat 3 files changed, 116 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/DataSource/StorageAreaDataSource.cpp	Sun May 17 18:10:27 2026 +0200
+++ b/OrthancFramework/Sources/DataSource/StorageAreaDataSource.cpp	Sun May 17 18:54:12 2026 +0200
@@ -88,6 +88,12 @@
       {
         throw OrthancException(ErrorCode_ParameterOutOfRange);
       }
+
+      uint64_t size = end - start;
+      if (static_cast<uint64_t>(static_cast<size_t>(size)) != size)
+      {
+        throw OrthancException(ErrorCode_NotEnoughMemory);  // For 32bit architectures
+      }
     }
 
     Value* Read(IPluginStorageArea& area) const
@@ -190,6 +196,15 @@
                                                                       bool uncompress,
                                                                       bool checkMD5)
   {
+    if (attachment.GetCompressionType() == CompressionType_None)
+    {
+      if (attachment.GetCompressedMD5() != attachment.GetUncompressedMD5() ||
+          attachment.GetCompressedSize() != attachment.GetUncompressedSize())
+      {
+        throw OrthancException(ErrorCode_CorruptedFile);
+      }
+    }
+
     std::unique_ptr<StorageAreaDataSource::Range> range(ReadRange(reader,
                                                                   attachment.GetUuid(),
                                                                   attachment.GetContentType(),
@@ -249,4 +264,29 @@
       return range.release();
     }
   }
+
+
+  StorageAreaDataSource::Range* StorageAreaDataSource::ReadBeginning(DataSourceReader& reader,
+                                                                     const FileInfo& attachment,
+                                                                     size_t untilPosition)
+  {
+    if (attachment.GetCompressionType() != CompressionType_None)
+    {
+      throw OrthancException(ErrorCode_BadParameterType);
+    }
+
+    if (attachment.GetCompressedMD5() != attachment.GetUncompressedMD5() ||
+        attachment.GetCompressedSize() != attachment.GetUncompressedSize())
+    {
+      throw OrthancException(ErrorCode_CorruptedFile);
+    }
+
+    if (untilPosition > attachment.GetUncompressedSize())
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+
+    return ReadRange(reader, attachment.GetUuid(), attachment.GetContentType(),
+                     0, untilPosition, attachment.GetCustomData());
+  }
 }
--- a/OrthancFramework/Sources/DataSource/StorageAreaDataSource.h	Sun May 17 18:10:27 2026 +0200
+++ b/OrthancFramework/Sources/DataSource/StorageAreaDataSource.h	Sun May 17 18:54:12 2026 +0200
@@ -84,5 +84,9 @@
                                  const FileInfo& attachment,
                                  bool uncompress,
                                  bool checkMD5);
+
+    static Range* ReadBeginning(DataSourceReader& reader,
+                                const FileInfo& attachment,
+                                size_t untilPosition);
   };
 }
--- a/OrthancFramework/UnitTestsSources/JobsTests.cpp	Sun May 17 18:10:27 2026 +0200
+++ b/OrthancFramework/UnitTestsSources/JobsTests.cpp	Sun May 17 18:54:12 2026 +0200
@@ -1921,25 +1921,25 @@
   boost::shared_ptr<DataSourceReader>  storageAreaReader_;
   bool                                 checkMD5_;
 
-  class Identifier : public IDataIdentifier
+  class BaseIdentifier : public IDataIdentifier
+  {
+  public:
+    virtual StorageAreaDataSource::Range* ReadRange(DataSourceReader& reader) const = 0;
+  };
+
+  class WholeIdentifier : public BaseIdentifier
   {
   private:
     FileInfo  attachment_;
 
   public:
-    explicit Identifier(const FileInfo& attachment) :
+    explicit WholeIdentifier(const FileInfo& attachment) :
       attachment_(attachment)
     {
     }
 
-    const FileInfo& GetAttachment() const
-    {
-      return attachment_;
-    }
-
     virtual bool GetCacheKey(std::string& key) const ORTHANC_OVERRIDE
     {
-      // TODO - Support "read until pixel data"
       key = (attachment_.GetUuid() + "|" +
              boost::lexical_cast<std::string>(attachment_.GetContentType()));
       return true;
@@ -1947,12 +1947,54 @@
 
     virtual bool EstimateValueSize(size_t& target) const ORTHANC_OVERRIDE
     {
-      // TODO - Support "read until pixel data"
       target = attachment_.GetUncompressedSize();
       return true;
     }
+
+    virtual StorageAreaDataSource::Range* ReadRange(DataSourceReader& reader) const ORTHANC_OVERRIDE
+    {
+      return StorageAreaDataSource::ReadAttachment(reader, attachment_, true /* uncompress */, true /* check MD5 */);
+    }
   };
 
+
+  class BeginningIdentifier : public BaseIdentifier
+  {
+  private:
+    FileInfo  attachment_;
+    bool      hasPixelDataOffset_;
+    size_t    pixelDataOffset_;
+
+  public:
+    BeginningIdentifier(const FileInfo& attachment,
+                        size_t pixelDataOffset) :
+      attachment_(attachment),
+      hasPixelDataOffset_(true),
+      pixelDataOffset_(pixelDataOffset)
+    {
+    }
+
+    virtual bool GetCacheKey(std::string& key) const ORTHANC_OVERRIDE
+    {
+      key = (attachment_.GetUuid() + "|" +
+             boost::lexical_cast<std::string>(attachment_.GetContentType()) + "|" +
+             boost::lexical_cast<std::string>(pixelDataOffset_));
+      return true;
+    }
+
+    virtual bool EstimateValueSize(size_t& target) const ORTHANC_OVERRIDE
+    {
+      target = pixelDataOffset_;
+      return true;
+    }
+
+    virtual StorageAreaDataSource::Range* ReadRange(DataSourceReader& reader) const ORTHANC_OVERRIDE
+    {
+      return StorageAreaDataSource::ReadBeginning(reader, attachment_, pixelDataOffset_);
+    }
+  };
+
+
   class Value : public IDynamicObject
   {
   private:
@@ -2000,12 +2042,19 @@
 
   virtual IDynamicObject* Load(const IDataIdentifier& obj) ORTHANC_OVERRIDE
   {
-    const Identifier& id = dynamic_cast<const Identifier&>(obj);
+    const BaseIdentifier& id = dynamic_cast<const BaseIdentifier&>(obj);
+
+    std::unique_ptr<StorageAreaDataSource::Range> range(id.ReadRange(*storageAreaReader_));
 
-    std::unique_ptr<StorageAreaDataSource::Range> range(
-      StorageAreaDataSource::ReadAttachment(*storageAreaReader_, id.GetAttachment(), true /* uncompress */, true /* check MD5 */));
+    // Sanity check
+    size_t size;
+    if (!obj.EstimateValueSize(size) ||
+        size != range->GetSize())
+    {
+      throw OrthancException(ErrorCode_InternalError);
+    }
 
-    return new Value(new ParsedDicomFile(range->GetData(), range->GetSize()), id.GetAttachment().GetUncompressedSize());
+    return new Value(new ParsedDicomFile(range->GetData(), range->GetSize()), range->GetSize());
   }
 
   virtual size_t GetValueSize(const IDynamicObject& obj) const ORTHANC_OVERRIDE
@@ -2037,16 +2086,19 @@
     }
   };
 
-  static Dicom* ReadDicom(DataSourceReader& reader,
+  static Dicom* ReadWhole(DataSourceReader& reader,
                           const FileInfo& attachment)
   {
-    if (attachment.GetCompressionType() == CompressionType_None &&
-        attachment.GetCompressedMD5() != attachment.GetUncompressedMD5())
-    {
-      throw OrthancException(ErrorCode_CorruptedFile);
-    }
+    std::unique_ptr<IDataIdentifier> id(new WholeIdentifier(attachment));
+    boost::shared_ptr<IDynamicObject> value = reader.ReadSingle(id.release());
+    return new Dicom(value);
+  }
 
-    std::unique_ptr<IDataIdentifier> id(new Identifier(attachment));
+  static Dicom* ReadUntilPixelData(DataSourceReader& reader,
+                                   const FileInfo& attachment,
+                                   size_t pixelDataOffset)
+  {
+    std::unique_ptr<IDataIdentifier> id(new BeginningIdentifier(attachment, pixelDataOffset));
     boost::shared_ptr<IDynamicObject> value = reader.ReadSingle(id.release());
     return new Dicom(value);
   }