changeset 6794:2ec15c5ef4bd

reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sun, 17 May 2026 19:22:11 +0200
parents 4514943d9239
children 7872e2d293bb
files OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake OrthancFramework/Sources/DataSource/DicomDataSource.cpp OrthancFramework/Sources/DataSource/DicomDataSource.h OrthancFramework/UnitTestsSources/JobsTests.cpp
diffstat 4 files changed, 320 insertions(+), 219 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake	Sun May 17 19:00:37 2026 +0200
+++ b/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake	Sun May 17 19:22:11 2026 +0200
@@ -549,6 +549,7 @@
   endif()
 
   set(ORTHANC_DICOM_SOURCES_INTERNAL
+    ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DataSource/DicomDataSource.cpp
     ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomNetworking/DicomFindAnswers.cpp
     ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomParsing/DicomModification.cpp
     ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomParsing/DicomWebJsonVisitor.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Sources/DataSource/DicomDataSource.cpp	Sun May 17 19:22:11 2026 +0200
@@ -0,0 +1,214 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, 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 "DicomDataSource.h"
+
+#include "../DicomParsing/ParsedDicomFile.h"
+#include "../OrthancException.h"
+#include "DataSourceReader.h"
+#include "StorageAreaDataSource.h"
+
+#include <boost/lexical_cast.hpp>
+
+
+namespace Orthanc
+{
+  class DicomDataSource::BaseIdentifier : public IDataIdentifier
+  {
+  public:
+    virtual StorageAreaDataSource::Range* ReadRange(DataSourceReader& reader) const = 0;
+  };
+
+
+  class DicomDataSource::WholeIdentifier : public DicomDataSource::BaseIdentifier
+  {
+  private:
+    FileInfo  attachment_;
+    bool      checkMD5_;
+
+  public:
+    explicit WholeIdentifier(const FileInfo& attachment,
+                             bool checkMD5) :
+      attachment_(attachment),
+      checkMD5_(checkMD5)
+    {
+    }
+
+    virtual bool GetCacheKey(std::string& key) const ORTHANC_OVERRIDE
+    {
+      key = (attachment_.GetUuid() + "|" +
+             boost::lexical_cast<std::string>(attachment_.GetContentType()));
+      return true;
+    }
+
+    virtual bool EstimateValueSize(size_t& target) const ORTHANC_OVERRIDE
+    {
+      target = attachment_.GetUncompressedSize();
+      return true;
+    }
+
+    virtual StorageAreaDataSource::Range* ReadRange(DataSourceReader& reader) const ORTHANC_OVERRIDE
+    {
+      return StorageAreaDataSource::ReadAttachment(reader, attachment_, true /* uncompress */, checkMD5_);
+    }
+  };
+
+
+  class DicomDataSource::BeginningIdentifier : public DicomDataSource::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 DicomDataSource::Value : public IDynamicObject
+  {
+  private:
+    std::unique_ptr<ParsedDicomFile>  dicom_;
+    size_t                            size_;
+
+  public:
+    Value(ParsedDicomFile* dicom,
+          size_t size) :
+      dicom_(dicom),
+      size_(size)
+    {
+      if (dicom == NULL)
+      {
+        throw OrthancException(ErrorCode_NullPointer);
+      }
+    }
+
+    ParsedDicomFile& GetDicom() const
+    {
+      return *dicom_;
+    }
+
+    size_t GetSize() const
+    {
+      return size_;
+    }
+  };
+
+
+  DicomDataSource::DicomDataSource(const boost::shared_ptr<DataSourceReader>& storageAreaReader) :
+    storageAreaReader_(storageAreaReader)
+  {
+    if (storageAreaReader == NULL)
+    {
+      throw OrthancException(ErrorCode_NullPointer);
+    }
+  }
+
+
+  IDynamicObject* DicomDataSource::Load(const IDataIdentifier& obj)
+  {
+    const BaseIdentifier& id = dynamic_cast<const BaseIdentifier&>(obj);
+
+    std::unique_ptr<StorageAreaDataSource::Range> range(id.ReadRange(*storageAreaReader_));
+
+    // 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()), range->GetSize());
+  }
+
+  size_t DicomDataSource::GetValueSize(const IDynamicObject& obj) const
+  {
+    const Value& value = dynamic_cast<const Value&>(obj);
+    return value.GetSize();
+  }
+
+
+  DicomDataSource::Dicom::Dicom(const boost::shared_ptr<IDynamicObject>& value) :
+    value_(value)
+  {
+    if (value.get() == NULL)
+    {
+      throw OrthancException(ErrorCode_NullPointer);
+    }
+  }
+
+
+  ParsedDicomFile& DicomDataSource::Dicom::Lock::GetContent() const
+  {
+    return dynamic_cast<const Value&>(*that_.value_).GetDicom();
+  }
+
+
+  DicomDataSource::Dicom* DicomDataSource::ReadWhole(DataSourceReader& reader,
+                                                     const FileInfo& attachment,
+                                                     bool checkMD5)
+  {
+    std::unique_ptr<IDataIdentifier> id(new WholeIdentifier(attachment, checkMD5));
+    boost::shared_ptr<IDynamicObject> value = reader.ReadSingle(id.release());
+    return new Dicom(value);
+  }
+
+
+  DicomDataSource::Dicom* DicomDataSource::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);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Sources/DataSource/DicomDataSource.h	Sun May 17 19:22:11 2026 +0200
@@ -0,0 +1,105 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, 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
+
+#if !defined(ORTHANC_ENABLE_DCMTK)
+#  error The macro ORTHANC_ENABLE_DCMTK must be defined
+#endif
+
+#if ORTHANC_ENABLE_DCMTK != 1
+#  error The macro ORTHANC_ENABLE_DCMTK must be set to 1 to use this file
+#endif
+
+#include "../Compatibility.h"
+#include "../FileStorage/FileInfo.h"
+#include "IDataIdentifier.h"
+#include "IDataSource.h"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/thread/mutex.hpp>
+
+
+namespace Orthanc
+{
+  class DataSourceReader;
+  class ParsedDicomFile;
+
+  class DicomDataSource : public IDataSource
+  {
+  private:
+    class BaseIdentifier;
+    class WholeIdentifier;
+    class BeginningIdentifier;
+    class Value;
+
+    boost::shared_ptr<DataSourceReader>  storageAreaReader_;
+
+  public:
+    explicit DicomDataSource(const boost::shared_ptr<DataSourceReader>& storageAreaReader);
+
+    virtual IDynamicObject* Load(const IDataIdentifier& obj) ORTHANC_OVERRIDE;
+
+    virtual size_t GetValueSize(const IDynamicObject& obj) const ORTHANC_OVERRIDE;
+
+    class Dicom : public boost::noncopyable
+    {
+    private:
+      boost::mutex                       mutex_;
+      boost::shared_ptr<IDynamicObject>  value_;
+
+    public:
+      explicit Dicom(const boost::shared_ptr<IDynamicObject>& value);
+
+      /**
+       * Access to the DICOM value must be protected by a mutex, as it
+       * could be shared by multiple threads if caching is enabled in
+       * the DataSourceReader.
+       **/
+      class Lock : public boost::noncopyable
+      {
+      private:
+        Dicom&                     that_;
+        boost::mutex::scoped_lock  lock_;
+
+      public:
+        explicit Lock(Dicom& that) :
+          that_(that),
+          lock_(that.mutex_)
+        {
+        }
+
+        ParsedDicomFile& GetContent() const;
+      };
+    };
+
+    static Dicom* ReadWhole(DataSourceReader& reader,
+                            const FileInfo& attachment,
+                            bool checkMD5);
+
+    static Dicom* ReadUntilPixelData(DataSourceReader& reader,
+                                     const FileInfo& attachment,
+                                     size_t pixelDataOffset);
+  };
+}
--- a/OrthancFramework/UnitTestsSources/JobsTests.cpp	Sun May 17 19:00:37 2026 +0200
+++ b/OrthancFramework/UnitTestsSources/JobsTests.cpp	Sun May 17 19:22:11 2026 +0200
@@ -1903,222 +1903,3 @@
 
   ASSERT_EQ(11u, counter_);
 }
-
-
-
-#include "../Sources/DataSource/DataSourceReader.h"
-#include "../Sources/DataSource/StorageAreaDataSource.h"
-#include "../Sources/FileStorage/FilesystemStorage.h"
-#include "../Sources/FileStorage/PluginStorageAreaAdapter.h"
-#include "../Sources/MultiThreading/ThreadPool.h"
-
-#include <dcmtk/dcmdata/dcfilefo.h>
-
-
-class DicomDataSource : public IDataSource
-{
-private:
-  boost::shared_ptr<DataSourceReader>  storageAreaReader_;
-  bool                                 checkMD5_;
-
-  class BaseIdentifier : public IDataIdentifier
-  {
-  public:
-    virtual StorageAreaDataSource::Range* ReadRange(DataSourceReader& reader) const = 0;
-  };
-
-  class WholeIdentifier : public BaseIdentifier
-  {
-  private:
-    FileInfo  attachment_;
-
-  public:
-    explicit WholeIdentifier(const FileInfo& attachment) :
-      attachment_(attachment)
-    {
-    }
-
-    virtual bool GetCacheKey(std::string& key) const ORTHANC_OVERRIDE
-    {
-      key = (attachment_.GetUuid() + "|" +
-             boost::lexical_cast<std::string>(attachment_.GetContentType()));
-      return true;
-    }
-
-    virtual bool EstimateValueSize(size_t& target) const ORTHANC_OVERRIDE
-    {
-      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:
-    std::unique_ptr<ParsedDicomFile>  dicom_;
-    size_t                            size_;
-
-  public:
-    Value(ParsedDicomFile* dicom,
-          size_t size) :
-      dicom_(dicom),
-      size_(size)
-    {
-      if (dicom == NULL)
-      {
-        throw OrthancException(ErrorCode_NullPointer);
-      }
-    }
-
-    ParsedDicomFile& GetDicom() const
-    {
-      return *dicom_;
-    }
-
-    size_t GetSize() const
-    {
-      return size_;
-    }
-  };
-
-public:
-  explicit DicomDataSource(const boost::shared_ptr<DataSourceReader>& storageAreaReader) :
-    storageAreaReader_(storageAreaReader),
-    checkMD5_(false)
-  {
-    if (storageAreaReader == NULL)
-    {
-      throw OrthancException(ErrorCode_NullPointer);
-    }
-  }
-
-  void SetCheckMD5(bool check)
-  {
-    checkMD5_ = check;
-  }
-
-  virtual IDynamicObject* Load(const IDataIdentifier& obj) ORTHANC_OVERRIDE
-  {
-    const BaseIdentifier& id = dynamic_cast<const BaseIdentifier&>(obj);
-
-    std::unique_ptr<StorageAreaDataSource::Range> range(id.ReadRange(*storageAreaReader_));
-
-    // 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()), range->GetSize());
-  }
-
-  virtual size_t GetValueSize(const IDynamicObject& obj) const ORTHANC_OVERRIDE
-  {
-    const Value& value = dynamic_cast<const Value&>(obj);
-    return value.GetSize();
-  }
-
-
-  class Dicom : public boost::noncopyable
-  {
-  private:
-    boost::mutex                       mutex_;
-    boost::shared_ptr<IDynamicObject>  value_;
-
-  public:
-    explicit Dicom(const boost::shared_ptr<IDynamicObject>& value) :
-      value_(value)
-    {
-      if (value.get() == NULL)
-      {
-        throw OrthancException(ErrorCode_NullPointer);
-      }
-    }
-
-    /**
-     * Access to the DICOM value must be protected by a mutex, as it
-     * could be shared by multiple threads if caching is enabled in
-     * the DataSourceReader.
-     **/
-    class Lock : public boost::noncopyable
-    {
-    private:
-      Dicom&                     that_;
-      boost::mutex::scoped_lock  lock_;
-
-    public:
-      explicit Lock(Dicom& that) :
-        that_(that),
-        lock_(that.mutex_)
-      {
-      }
-
-      ParsedDicomFile& GetContent() const
-      {
-        return dynamic_cast<const Value&>(*that_.value_).GetDicom();
-      }
-    };
-  };
-
-  static Dicom* ReadWhole(DataSourceReader& reader,
-                          const FileInfo& attachment)
-  {
-    std::unique_ptr<IDataIdentifier> id(new WholeIdentifier(attachment));
-    boost::shared_ptr<IDynamicObject> value = reader.ReadSingle(id.release());
-    return new Dicom(value);
-  }
-
-  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);
-  }
-};