changeset 196:b0bd22077cd8

sharing code with orthanc-stone
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 01 Jul 2020 17:57:38 +0200
parents fda17c92d784
children e5964793a790
files Applications/CMakeLists.txt Applications/DicomToTiff.cpp Framework/Inputs/DicomPyramid.cpp Framework/Inputs/DicomPyramid.h Framework/Inputs/DicomPyramidInstance.cpp Framework/Inputs/DicomPyramidInstance.h Framework/Inputs/DicomPyramidLevel.cpp Framework/Inputs/DicomPyramidLevel.h Framework/Inputs/Orthanc/DicomDatasetReader.cpp Framework/Inputs/Orthanc/DicomDatasetReader.h Framework/Inputs/Orthanc/DicomPath.cpp Framework/Inputs/Orthanc/DicomPath.h Framework/Inputs/Orthanc/DicomTag.cpp Framework/Inputs/Orthanc/DicomTag.h Framework/Inputs/Orthanc/FullOrthancDataset.cpp Framework/Inputs/Orthanc/FullOrthancDataset.h Framework/Inputs/Orthanc/IDicomDataset.h Framework/Inputs/Orthanc/IOrthancConnection.cpp Framework/Inputs/Orthanc/IOrthancConnection.h Framework/Inputs/Orthanc/OrthancHttpConnection.cpp Framework/Inputs/Orthanc/OrthancHttpConnection.h Framework/Inputs/Orthanc/OrthancPluginConnection.cpp Framework/Inputs/Orthanc/OrthancPluginConnection.h Framework/Targets/OrthancTarget.cpp Framework/Targets/OrthancTarget.h Resources/Orthanc/DownloadOrthancFramework.cmake Resources/Orthanc/Stone/DicomDatasetReader.cpp Resources/Orthanc/Stone/DicomDatasetReader.h Resources/Orthanc/Stone/DicomPath.cpp Resources/Orthanc/Stone/DicomPath.h Resources/Orthanc/Stone/FullOrthancDataset.cpp Resources/Orthanc/Stone/FullOrthancDataset.h Resources/Orthanc/Stone/IDicomDataset.h Resources/Orthanc/Stone/IOrthancConnection.cpp Resources/Orthanc/Stone/IOrthancConnection.h Resources/Orthanc/Stone/OrthancHttpConnection.cpp Resources/Orthanc/Stone/OrthancHttpConnection.h Resources/SyncOrthancFolder.py ViewerPlugin/CMakeLists.txt ViewerPlugin/DicomPyramidCache.cpp ViewerPlugin/DicomPyramidCache.h ViewerPlugin/OrthancPluginConnection.cpp ViewerPlugin/OrthancPluginConnection.h ViewerPlugin/Plugin.cpp
diffstat 44 files changed, 1305 insertions(+), 1494 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/CMakeLists.txt	Tue Jun 30 18:11:30 2020 +0200
+++ b/Applications/CMakeLists.txt	Wed Jul 01 17:57:38 2020 +0200
@@ -150,14 +150,11 @@
   ${AUTOGENERATED_SOURCES}
   ${BOOST_EXTENDED_SOURCES}
 
-  ${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/DicomDatasetReader.cpp
-  ${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/DicomPath.cpp
-  ${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/DicomTag.cpp
-  ${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/FullOrthancDataset.cpp
-  ${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/IOrthancConnection.cpp
-  ${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/OrthancHttpConnection.cpp
-  #${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/OrthancPluginConnection.cpp  # For plugins only
-  #${ORTHANC_WSI_DIR}/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp  # For plugins only
+  ${ORTHANC_WSI_DIR}/Resources/Orthanc/Stone/DicomDatasetReader.cpp
+  ${ORTHANC_WSI_DIR}/Resources/Orthanc/Stone/DicomPath.cpp
+  ${ORTHANC_WSI_DIR}/Resources/Orthanc/Stone/FullOrthancDataset.cpp
+  ${ORTHANC_WSI_DIR}/Resources/Orthanc/Stone/IOrthancConnection.cpp
+  ${ORTHANC_WSI_DIR}/Resources/Orthanc/Stone/OrthancHttpConnection.cpp
 
   # Mandatory components
   ${LIBTIFF_SOURCES}
--- a/Applications/DicomToTiff.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ b/Applications/DicomToTiff.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -22,9 +22,9 @@
 #include "../Framework/DicomToolbox.h"
 #include "../Framework/ImageToolbox.h"
 #include "../Framework/Inputs/DicomPyramid.h"
-#include "../Framework/Inputs/Orthanc/OrthancHttpConnection.h"
 #include "../Framework/Inputs/TiledPyramidStatistics.h"
 #include "../Framework/Outputs/HierarchicalTiffWriter.h"
+#include "../Resources/Orthanc/Stone/OrthancHttpConnection.h"
 
 #include <Logging.h>
 #include <OrthancException.h>
@@ -318,7 +318,7 @@
 
       OrthancWSI::ApplicationToolbox::SetupRestApi(params, options);
 
-      OrthancPlugins::OrthancHttpConnection orthanc(params);
+      OrthancStone::OrthancHttpConnection orthanc(params);
       OrthancWSI::DicomPyramid source(orthanc, options[OPTION_INPUT].as<std::string>(), 
                                       false /* don't use cached metadata */);
 
--- a/Framework/Inputs/DicomPyramid.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ b/Framework/Inputs/DicomPyramid.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -65,7 +65,7 @@
                                        bool useCache)
   {
     Json::Value series;
-    OrthancPlugins::IOrthancConnection::RestApiGet(series, orthanc_, "/series/" + seriesId);
+    OrthancStone::IOrthancConnection::RestApiGet(series, orthanc_, "/series/" + seriesId);
 
     if (series.type() != Json::objectValue ||
         !series.isMember("Instances") ||
@@ -139,7 +139,7 @@
   }
 
 
-  DicomPyramid::DicomPyramid(OrthancPlugins::IOrthancConnection& orthanc,
+  DicomPyramid::DicomPyramid(OrthancStone::IOrthancConnection& orthanc,
                              const std::string& seriesId,
                              bool useCache) :
     orthanc_(orthanc),
--- a/Framework/Inputs/DicomPyramid.h	Tue Jun 30 18:11:30 2020 +0200
+++ b/Framework/Inputs/DicomPyramid.h	Wed Jul 01 17:57:38 2020 +0200
@@ -32,10 +32,10 @@
   private:
     struct Comparator;
 
-    OrthancPlugins::IOrthancConnection&  orthanc_;
-    std::string                          seriesId_;
-    std::vector<DicomPyramidInstance*>   instances_;
-    std::vector<DicomPyramidLevel*>      levels_;
+    OrthancStone::IOrthancConnection&   orthanc_;
+    std::string                         seriesId_;
+    std::vector<DicomPyramidInstance*>  instances_;
+    std::vector<DicomPyramidLevel*>     levels_;
 
     void Clear();
 
@@ -47,7 +47,7 @@
     void CheckLevel(size_t level) const;
 
   public:
-    DicomPyramid(OrthancPlugins::IOrthancConnection& orthanc,
+    DicomPyramid(OrthancStone::IOrthancConnection& orthanc,
                  const std::string& seriesId,
                  bool useCache);
 
--- a/Framework/Inputs/DicomPyramidInstance.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ b/Framework/Inputs/DicomPyramidInstance.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -23,8 +23,8 @@
 #include "DicomPyramidInstance.h"
 
 #include "../DicomToolbox.h"
-#include "Orthanc/DicomDatasetReader.h"
-#include "Orthanc/FullOrthancDataset.h"
+#include "../../Resources/Orthanc/Stone/DicomDatasetReader.h"
+#include "../../Resources/Orthanc/Stone/FullOrthancDataset.h"
 
 #include <Logging.h>
 #include <OrthancException.h>
@@ -35,18 +35,26 @@
 
 #define SERIALIZED_METADATA  "4200"
 
+
 namespace OrthancWSI
 {
-  static ImageCompression DetectImageCompression(OrthancPlugins::IOrthancConnection& orthanc,
+  static const Orthanc::DicomTag DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021e);
+  static const Orthanc::DicomTag DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE(0x5200, 0x9230);
+  static const Orthanc::DicomTag DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE(0x0048, 0x021a);
+  static const Orthanc::DicomTag DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021f);
+  static const Orthanc::DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS(0x0048, 0x0006);
+  static const Orthanc::DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS(0x0048, 0x0007);
+
+  static ImageCompression DetectImageCompression(OrthancStone::IOrthancConnection& orthanc,
                                                  const std::string& instanceId)
   {
-    using namespace OrthancPlugins;
+    using namespace OrthancStone;
 
     FullOrthancDataset dataset(orthanc, "/instances/" + instanceId + "/header");
     DicomDatasetReader header(dataset);
 
     std::string s = Orthanc::Toolbox::StripSpaces
-      (header.GetMandatoryStringValue(DICOM_TAG_TRANSFER_SYNTAX_UID));
+      (header.GetMandatoryStringValue(Orthanc::DICOM_TAG_TRANSFER_SYNTAX_UID));
 
     if (s == "1.2.840.10008.1.2" ||
         s == "1.2.840.10008.1.2.1")
@@ -72,12 +80,12 @@
 
   static void DetectPixelFormat(Orthanc::PixelFormat& format,
                                 Orthanc::PhotometricInterpretation& photometric,
-                                OrthancPlugins::DicomDatasetReader& reader)
+                                OrthancStone::DicomDatasetReader& reader)
   {
-    using namespace OrthancPlugins;
+    using namespace OrthancStone;
 
     std::string p = Orthanc::Toolbox::StripSpaces
-      (reader.GetMandatoryStringValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION));
+      (reader.GetMandatoryStringValue(Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION));
     
     photometric = Orthanc::StringToPhotometricInterpretation(p.c_str());
 
@@ -89,9 +97,9 @@
 
     unsigned int bitsStored, samplesPerPixel, tmp;
 
-    if (!reader.GetUnsignedIntegerValue(bitsStored, DICOM_TAG_BITS_STORED) ||
-        !reader.GetUnsignedIntegerValue(samplesPerPixel, DICOM_TAG_SAMPLES_PER_PIXEL) ||
-        !reader.GetUnsignedIntegerValue(tmp, DICOM_TAG_PIXEL_REPRESENTATION))
+    if (!reader.GetUnsignedIntegerValue(bitsStored, Orthanc::DICOM_TAG_BITS_STORED) ||
+        !reader.GetUnsignedIntegerValue(samplesPerPixel, Orthanc::DICOM_TAG_SAMPLES_PER_PIXEL) ||
+        !reader.GetUnsignedIntegerValue(tmp, Orthanc::DICOM_TAG_PIXEL_REPRESENTATION))
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentTag);
     }
@@ -117,7 +125,7 @@
   }
 
 
-  ImageCompression  DicomPyramidInstance::GetImageCompression(OrthancPlugins::IOrthancConnection& orthanc)
+  ImageCompression  DicomPyramidInstance::GetImageCompression(OrthancStone::IOrthancConnection& orthanc)
   {
     /**
      * Lazy detection of the image compression using the transfer
@@ -138,16 +146,16 @@
   }
 
   
-  void DicomPyramidInstance::Load(OrthancPlugins::IOrthancConnection&  orthanc,
+  void DicomPyramidInstance::Load(OrthancStone::IOrthancConnection&  orthanc,
                                   const std::string& instanceId)
   {
-    using namespace OrthancPlugins;
+    using namespace OrthancStone;
 
     FullOrthancDataset dataset(orthanc, "/instances/" + instanceId + "/tags");
     DicomDatasetReader reader(dataset);
 
-    if (reader.GetMandatoryStringValue(DICOM_TAG_SOP_CLASS_UID) != "1.2.840.10008.5.1.4.1.1.77.1.6" ||
-        reader.GetMandatoryStringValue(DICOM_TAG_MODALITY) != "SM")
+    if (reader.GetMandatoryStringValue(Orthanc::DICOM_TAG_SOP_CLASS_UID) != "1.2.840.10008.5.1.4.1.1.77.1.6" ||
+        reader.GetMandatoryStringValue(Orthanc::DICOM_TAG_MODALITY) != "SM")
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
@@ -156,11 +164,11 @@
     DetectPixelFormat(format_, photometric_, reader);
 
     unsigned int tmp;
-    if (!reader.GetUnsignedIntegerValue(tileWidth_, DICOM_TAG_COLUMNS) ||
-        !reader.GetUnsignedIntegerValue(tileHeight_, DICOM_TAG_ROWS) ||
+    if (!reader.GetUnsignedIntegerValue(tileWidth_, Orthanc::DICOM_TAG_COLUMNS) ||
+        !reader.GetUnsignedIntegerValue(tileHeight_, Orthanc::DICOM_TAG_ROWS) ||
         !reader.GetUnsignedIntegerValue(totalWidth_, DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS) ||
         !reader.GetUnsignedIntegerValue(totalHeight_, DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS) ||
-        !reader.GetUnsignedIntegerValue(tmp, DICOM_TAG_NUMBER_OF_FRAMES))
+        !reader.GetUnsignedIntegerValue(tmp, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES))
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
     }
@@ -221,7 +229,7 @@
   }
 
 
-  DicomPyramidInstance::DicomPyramidInstance(OrthancPlugins::IOrthancConnection&  orthanc,
+  DicomPyramidInstance::DicomPyramidInstance(OrthancStone::IOrthancConnection&  orthanc,
                                              const std::string& instanceId,
                                              bool useCache) :
     instanceId_(instanceId),
@@ -313,7 +321,7 @@
     hasCompression_ = false;
 
     Json::Value content;
-    OrthancPlugins::IOrthancConnection::ParseJson(content, s);
+    OrthancStone::IOrthancConnection::ParseJson(content, s);
 
     if (content.type() != Json::objectValue ||
         !content.isMember("Frames") ||
--- a/Framework/Inputs/DicomPyramidInstance.h	Tue Jun 30 18:11:30 2020 +0200
+++ b/Framework/Inputs/DicomPyramidInstance.h	Wed Jul 01 17:57:38 2020 +0200
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "../Enumerations.h"
-#include "Orthanc/IOrthancConnection.h"
+#include "../../Resources/Orthanc/Stone/IOrthancConnection.h"
 
 #include <boost/noncopyable.hpp>
 #include <vector>
@@ -45,13 +45,13 @@
     std::vector<FrameLocation>  frames_;
     Orthanc::PhotometricInterpretation  photometric_;
 
-    void Load(OrthancPlugins::IOrthancConnection&  orthanc,
+    void Load(OrthancStone::IOrthancConnection&  orthanc,
               const std::string& instanceId);
 
     void Deserialize(const std::string& content);
 
   public:
-    DicomPyramidInstance(OrthancPlugins::IOrthancConnection&  orthanc,
+    DicomPyramidInstance(OrthancStone::IOrthancConnection&  orthanc,
                          const std::string& instanceId,
                          bool useCache);
 
@@ -60,7 +60,7 @@
       return instanceId_;
     }
 
-    ImageCompression GetImageCompression(OrthancPlugins::IOrthancConnection& orthanc);
+    ImageCompression GetImageCompression(OrthancStone::IOrthancConnection& orthanc);
 
     Orthanc::PixelFormat GetPixelFormat() const
     {
--- a/Framework/Inputs/DicomPyramidLevel.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ b/Framework/Inputs/DicomPyramidLevel.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -120,7 +120,7 @@
   bool DicomPyramidLevel::DownloadRawTile(std::string& raw /* out */,
                                           Orthanc::PixelFormat& format /* out */,
                                           ImageCompression& compression /* out */,
-                                          OrthancPlugins::IOrthancConnection& orthanc,
+                                          OrthancStone::IOrthancConnection& orthanc,
                                           unsigned int tileX,
                                           unsigned int tileY) const
   {
--- a/Framework/Inputs/DicomPyramidLevel.h	Tue Jun 30 18:11:30 2020 +0200
+++ b/Framework/Inputs/DicomPyramidLevel.h	Wed Jul 01 17:57:38 2020 +0200
@@ -88,7 +88,7 @@
     bool DownloadRawTile(std::string& raw /* out */,
                          Orthanc::PixelFormat& format /* out */,
                          ImageCompression& compression /* out */,
-                         OrthancPlugins::IOrthancConnection& orthanc,
+                         OrthancStone::IOrthancConnection& orthanc,
                          unsigned int tileX,
                          unsigned int tileY) const;
   };
--- a/Framework/Inputs/Orthanc/DicomDatasetReader.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "DicomDatasetReader.h"
-
-#include <OrthancException.h>
-
-#include <boost/lexical_cast.hpp>
-
-namespace OrthancPlugins
-{
-  // This function is copied-pasted from "../../../Core/Toolbox.cpp",
-  // in order to avoid the dependency of plugins against the Orthanc core
-  static std::string StripSpaces(const std::string& source)
-  {
-    size_t first = 0;
-
-    while (first < source.length() &&
-           isspace(source[first]))
-    {
-      first++;
-    }
-
-    if (first == source.length())
-    {
-      // String containing only spaces
-      return "";
-    }
-
-    size_t last = source.length();
-    while (last > first &&
-           isspace(source[last - 1]))
-    {
-      last--;
-    }          
-    
-    assert(first <= last);
-    return source.substr(first, last - first);
-  }
-
-
-  DicomDatasetReader::DicomDatasetReader(const IDicomDataset& dataset) :
-    dataset_(dataset)
-  {
-  }
-  
-
-  std::string DicomDatasetReader::GetStringValue(const DicomPath& path,
-                                                 const std::string& defaultValue) const
-  {
-    std::string s;
-    if (dataset_.GetStringValue(s, path))
-    {
-      return s;
-    }
-    else
-    {
-      return defaultValue;
-    }
-  }
-
-
-  std::string DicomDatasetReader::GetMandatoryStringValue(const DicomPath& path) const
-  {
-    std::string s;
-    if (dataset_.GetStringValue(s, path))
-    {
-      return s;
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentTag);
-    }
-  }
-
-
-  template <typename T>
-  static bool GetValueInternal(T& target,
-                               const IDicomDataset& dataset,
-                               const DicomPath& path)
-  {
-    try
-    {
-      std::string s;
-
-      if (dataset.GetStringValue(s, path))
-      {
-        target = boost::lexical_cast<T>(StripSpaces(s));
-        return true;
-      }
-      else
-      {
-        return false;
-      }
-    }
-    catch (boost::bad_lexical_cast&)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);        
-    }
-  }
-
-
-  bool DicomDatasetReader::GetIntegerValue(int& target,
-                                           const DicomPath& path) const
-  {
-    return GetValueInternal<int>(target, dataset_, path);
-  }
-
-
-  bool DicomDatasetReader::GetUnsignedIntegerValue(unsigned int& target,
-                                                   const DicomPath& path) const
-  {
-    int value;
-
-    if (!GetIntegerValue(value, path))
-    {
-      return false;
-    }
-    else if (value >= 0)
-    {
-      target = static_cast<unsigned int>(value);
-      return true;
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-
-  bool DicomDatasetReader::GetFloatValue(float& target,
-                                         const DicomPath& path) const
-  {
-    return GetValueInternal<float>(target, dataset_, path);
-  }
-
-
-  bool DicomDatasetReader::GetDoubleValue(double& target,
-                                          const DicomPath& path) const
-  {
-    return GetValueInternal<double>(target, dataset_, path);
-  }
-}
--- a/Framework/Inputs/Orthanc/DicomDatasetReader.h	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "IDicomDataset.h"
-
-#include <memory>
-#include <vector>
-
-namespace OrthancPlugins
-{
-  class DicomDatasetReader : public boost::noncopyable
-  {
-  private:
-    const IDicomDataset&  dataset_;
-
-  public:
-    DicomDatasetReader(const IDicomDataset& dataset);
-
-    const IDicomDataset& GetDataset() const
-    {
-      return dataset_;
-    }
-
-    std::string GetStringValue(const DicomPath& path,
-                               const std::string& defaultValue) const;
-
-    std::string GetMandatoryStringValue(const DicomPath& path) const;
-
-    bool GetIntegerValue(int& target,
-                         const DicomPath& path) const;
-
-    bool GetUnsignedIntegerValue(unsigned int& target,
-                                 const DicomPath& path) const;
-
-    bool GetFloatValue(float& target,
-                       const DicomPath& path) const;
-
-    bool GetDoubleValue(double& target,
-                        const DicomPath& path) const;
-  };
-}
--- a/Framework/Inputs/Orthanc/DicomPath.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "DicomPath.h"
-
-#include <OrthancException.h>
-
-#include <boost/lexical_cast.hpp>
-
-namespace OrthancPlugins
-{
-  const DicomPath::Prefix& DicomPath::GetPrefixItem(size_t depth) const
-  {
-    if (depth >= prefix_.size())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-    else
-    {
-      return prefix_[depth];
-    }
-  }
-
-
-  DicomPath::Prefix& DicomPath::GetPrefixItem(size_t depth)
-  {
-    if (depth >= prefix_.size())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-    else
-    {
-      return prefix_[depth];
-    }
-  }
-
-
-  DicomPath::DicomPath(const DicomTag& sequence,
-                       size_t index,
-                       const DicomTag& tag) :
-    finalTag_(tag)
-  {
-    AddToPrefix(sequence, index);
-  }
-
-
-  DicomPath::DicomPath(const DicomTag& sequence1,
-                       size_t index1,
-                       const DicomTag& sequence2,
-                       size_t index2,
-                       const DicomTag& tag) :
-    finalTag_(tag)
-  {
-    AddToPrefix(sequence1, index1);
-    AddToPrefix(sequence2, index2);
-  }
-
-
-  DicomPath::DicomPath(const DicomTag& sequence1,
-                       size_t index1,
-                       const DicomTag& sequence2,
-                       size_t index2,
-                       const DicomTag& sequence3,
-                       size_t index3,
-                       const DicomTag& tag) :
-    finalTag_(tag)
-  {
-    AddToPrefix(sequence1, index1);
-    AddToPrefix(sequence2, index2);
-    AddToPrefix(sequence3, index3);
-  }
-
-
-  std::string DicomPath::Format() const
-  {
-    std::string s;
-      
-    for (size_t i = 0; i < GetPrefixLength(); i++)
-    {
-      s += (GetPrefixTag(i).FormatHexadecimal() + " / " +
-            boost::lexical_cast<std::string>(i) + " / ");
-    }
-
-    return s + GetFinalTag().FormatHexadecimal();
-  }
-}
--- a/Framework/Inputs/Orthanc/DicomPath.h	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "DicomTag.h"
-
-#include <vector>
-#include <stddef.h>
-
-namespace OrthancPlugins
-{
-  class DicomPath
-  {
-  private:
-    typedef std::pair<DicomTag, size_t>  Prefix;
-
-    std::vector<Prefix>  prefix_;
-    DicomTag             finalTag_;
-
-    const Prefix& GetPrefixItem(size_t depth) const;
-
-    Prefix& GetPrefixItem(size_t depth);
-
-  public:
-    DicomPath(const DicomTag& finalTag) :
-    finalTag_(finalTag)
-    {
-    }
-
-    DicomPath(const DicomTag& sequence,
-              size_t index,
-              const DicomTag& tag);
-
-    DicomPath(const DicomTag& sequence1,
-              size_t index1,
-              const DicomTag& sequence2,
-              size_t index2,
-              const DicomTag& tag);
-
-    DicomPath(const DicomTag& sequence1,
-              size_t index1,
-              const DicomTag& sequence2,
-              size_t index2,
-              const DicomTag& sequence3,
-              size_t index3,
-              const DicomTag& tag);
-
-    void AddToPrefix(const DicomTag& tag,
-                     size_t position)
-    {
-      prefix_.push_back(std::make_pair(tag, position));
-    }
-
-    size_t GetPrefixLength() const
-    {
-      return prefix_.size();
-    }
-    
-    DicomTag GetPrefixTag(size_t depth) const
-    {
-      return GetPrefixItem(depth).first;
-    }
-
-    size_t GetPrefixIndex(size_t depth) const
-    {
-      return GetPrefixItem(depth).second;
-    }
-
-    void SetPrefixIndex(size_t depth,
-                        size_t value)
-    {
-      GetPrefixItem(depth).second = value;
-    }
-    
-    const DicomTag& GetFinalTag() const
-    {
-      return finalTag_;
-    }
-
-    void SetFinalTag(const DicomTag& tag)
-    {
-      finalTag_ = tag;
-    }
-
-    std::string Format() const;
-  };
-}
--- a/Framework/Inputs/Orthanc/DicomTag.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "DicomTag.h"
-
-#include <OrthancException.h>
-
-namespace OrthancPlugins
-{
-  const char* DicomTag::GetName() const
-  {
-    if (*this == DICOM_TAG_BITS_STORED)
-    {
-      return "BitsStored";
-    }
-    else if (*this == DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX)
-    {
-      return "ColumnPositionInTotalImagePixelMatrix";
-    }
-    else if (*this == DICOM_TAG_COLUMNS)
-    {
-      return "Columns";
-    }
-    else if (*this == DICOM_TAG_MODALITY)
-    {
-      return "Modality";
-    }
-    else if (*this == DICOM_TAG_NUMBER_OF_FRAMES)
-    {
-      return "NumberOfFrames";
-    }
-    else if (*this == DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE)
-    {
-      return "PerFrameFunctionalGroupsSequence";
-    }
-    else if (*this == DICOM_TAG_PHOTOMETRIC_INTERPRETATION)
-    {
-      return "PhotometricInterpretation";
-    }
-    else if (*this == DICOM_TAG_PIXEL_REPRESENTATION)
-    {
-      return "PixelRepresentation";
-    }
-    else if (*this == DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE)
-    {
-      return "PlanePositionSlideSequence";
-    }
-    else if (*this == DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX)
-    {
-      return "RowPositionInTotalImagePixelMatrix";
-    }
-    else if (*this == DICOM_TAG_ROWS)
-    {
-      return "Rows";
-    }
-    else if (*this == DICOM_TAG_SOP_CLASS_UID)
-    {
-      return "SOPClassUID";
-    }
-    else if (*this == DICOM_TAG_SAMPLES_PER_PIXEL)
-    {
-      return "SamplesPerPixel";
-    }
-    else if (*this == DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS)
-    {
-      return "TotalPixelMatrixColumns";
-    }
-    else if (*this == DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS)
-    {
-      return "TotalPixelMatrixRows";
-    }
-    else if (*this == DICOM_TAG_TRANSFER_SYNTAX_UID)
-    {
-      return "TransferSyntaxUID";
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
-    }
-  }
-
-
-  std::string DicomTag::FormatHexadecimal() const
-  {
-    char buf[16];
-    sprintf(buf, "(%04x,%04x)", group_, element_);
-    return buf;
-  }
-}
--- a/Framework/Inputs/Orthanc/DicomTag.h	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include <stdint.h>
-#include <string>
-
-namespace OrthancPlugins
-{
-  class DicomTag
-  {
-  private:
-    uint16_t  group_;
-    uint16_t  element_;
-
-    DicomTag();  // Forbidden
-
-  public:
-    DicomTag(uint16_t group,
-             uint16_t element) :
-      group_(group),
-      element_(element)
-    {
-    }
-
-    uint16_t GetGroup() const
-    {
-      return group_;
-    }
-
-    uint16_t GetElement() const
-    {
-      return element_;
-    }
-
-    const char* GetName() const;
-
-    bool operator== (const DicomTag& other) const
-    {
-      return group_ == other.group_ && element_ == other.element_;
-    }
-
-    bool operator!= (const DicomTag& other) const
-    {
-      return !(*this == other);
-    }
-
-    std::string FormatHexadecimal() const;
-  };
-
-
-  static const DicomTag DICOM_TAG_BITS_STORED(0x0028, 0x0101);
-  static const DicomTag DICOM_TAG_COLUMNS(0x0028, 0x0011);
-  static const DicomTag DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021e);
-  static const DicomTag DICOM_TAG_IMAGE_ORIENTATION_PATIENT(0x0020, 0x0037);
-  static const DicomTag DICOM_TAG_IMAGE_POSITION_PATIENT(0x0020, 0x0032);
-  static const DicomTag DICOM_TAG_MODALITY(0x0008, 0x0060);
-  static const DicomTag DICOM_TAG_NUMBER_OF_FRAMES(0x0028, 0x0008);
-  static const DicomTag DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE(0x5200, 0x9230);
-  static const DicomTag DICOM_TAG_PHOTOMETRIC_INTERPRETATION(0x0028, 0x0004);
-  static const DicomTag DICOM_TAG_PIXEL_REPRESENTATION(0x0028, 0x0103);
-  static const DicomTag DICOM_TAG_PIXEL_SPACING(0x0028, 0x0030);
-  static const DicomTag DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE(0x0048, 0x021a);
-  static const DicomTag DICOM_TAG_RESCALE_INTERCEPT(0x0028, 0x1052);
-  static const DicomTag DICOM_TAG_RESCALE_SLOPE(0x0028, 0x1053);
-  static const DicomTag DICOM_TAG_ROWS(0x0028, 0x0010);
-  static const DicomTag DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021f);
-  static const DicomTag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002);
-  static const DicomTag DICOM_TAG_SERIES_INSTANCE_UID(0x0020, 0x000e);
-  static const DicomTag DICOM_TAG_SLICE_THICKNESS(0x0018, 0x0050);
-  static const DicomTag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016);
-  static const DicomTag DICOM_TAG_SOP_INSTANCE_UID(0x0008, 0x0018);
-  static const DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS(0x0048, 0x0006);
-  static const DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS(0x0048, 0x0007);
-  static const DicomTag DICOM_TAG_TRANSFER_SYNTAX_UID(0x0002, 0x0010);
-  static const DicomTag DICOM_TAG_WINDOW_CENTER(0x0028, 0x1050);
-  static const DicomTag DICOM_TAG_WINDOW_WIDTH(0x0028, 0x1051);
-}
--- a/Framework/Inputs/Orthanc/FullOrthancDataset.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,203 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "FullOrthancDataset.h"
-
-#include <OrthancException.h>
-
-#include <stdio.h>
-#include <cassert>
-
-namespace OrthancPlugins
-{
-  static const Json::Value* AccessTag(const Json::Value& dataset,
-                                      const DicomTag& tag) 
-  {
-    if (dataset.type() != Json::objectValue)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-
-    char name[16];
-    sprintf(name, "%04x,%04x", tag.GetGroup(), tag.GetElement());
-
-    if (!dataset.isMember(name))
-    {
-      return NULL;
-    }
-
-    const Json::Value& value = dataset[name];
-    if (value.type() != Json::objectValue ||
-        !value.isMember("Name") ||
-        !value.isMember("Type") ||
-        !value.isMember("Value") ||
-        value["Name"].type() != Json::stringValue ||
-        value["Type"].type() != Json::stringValue)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-
-    return &value;
-  }
-
-
-  static const Json::Value& GetSequenceContent(const Json::Value& sequence)
-  {
-    assert(sequence.type() == Json::objectValue);
-    assert(sequence.isMember("Type"));
-    assert(sequence.isMember("Value"));
-
-    const Json::Value& value = sequence["Value"];
-      
-    if (sequence["Type"].asString() != "Sequence" ||
-        value.type() != Json::arrayValue)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-    else
-    {
-      return value;
-    }
-  }
-
-
-  static bool GetStringInternal(std::string& result,
-                                const Json::Value& tag)
-  {
-    assert(tag.type() == Json::objectValue);
-    assert(tag.isMember("Type"));
-    assert(tag.isMember("Value"));
-
-    const Json::Value& value = tag["Value"];
-      
-    if (tag["Type"].asString() != "String" ||
-        value.type() != Json::stringValue)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-    else
-    {
-      result = value.asString();
-      return true;
-    }
-  }
-
-
-  const Json::Value* FullOrthancDataset::LookupPath(const DicomPath& path) const
-  {
-    const Json::Value* content = &root_;
-                                  
-    for (unsigned int depth = 0; depth < path.GetPrefixLength(); depth++)
-    {
-      const Json::Value* sequence = AccessTag(*content, path.GetPrefixTag(depth));
-      if (sequence == NULL)
-      {
-        return NULL;
-      }
-
-      const Json::Value& nextContent = GetSequenceContent(*sequence);
-
-      size_t index = path.GetPrefixIndex(depth);
-      if (index >= nextContent.size())
-      {
-        return NULL;
-      }
-      else
-      {
-        content = &nextContent[static_cast<Json::Value::ArrayIndex>(index)];
-      }
-    }
-
-    return AccessTag(*content, path.GetFinalTag());
-  }
-
-
-  void FullOrthancDataset::CheckRoot() const
-  {
-    if (root_.type() != Json::objectValue)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-  }
-
-
-  FullOrthancDataset::FullOrthancDataset(IOrthancConnection& orthanc,
-                                         const std::string& uri)
-  {
-    IOrthancConnection::RestApiGet(root_, orthanc, uri);
-    CheckRoot();
-  }
-
-
-  FullOrthancDataset::FullOrthancDataset(const std::string& content)
-  {
-    IOrthancConnection::ParseJson(root_, content);
-    CheckRoot();
-  }
-
-
-  FullOrthancDataset::FullOrthancDataset(const void* content,
-                                         size_t size)
-  {
-    IOrthancConnection::ParseJson(root_, content, size);
-    CheckRoot();
-  }
-
-
-  FullOrthancDataset::FullOrthancDataset(const Json::Value& root) :
-    root_(root)
-  {
-    CheckRoot();
-  }
-
-
-  bool FullOrthancDataset::GetStringValue(std::string& result,
-                                          const DicomPath& path) const
-  {
-    const Json::Value* value = LookupPath(path);
-
-    if (value == NULL)
-    {
-      return false;
-    }
-    else
-    {
-      return GetStringInternal(result, *value);
-    }
-  }
-
-
-  bool FullOrthancDataset::GetSequenceSize(size_t& size,
-                                           const DicomPath& path) const
-  {
-    const Json::Value* sequence = LookupPath(path);
-
-    if (sequence == NULL)
-    {
-      return false;
-    }
-    else
-    {
-      size = GetSequenceContent(*sequence).size();
-      return true;
-    }
-  }
-}
--- a/Framework/Inputs/Orthanc/FullOrthancDataset.h	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "IOrthancConnection.h"
-#include "IDicomDataset.h"
-
-#include <json/value.h>
-
-namespace OrthancPlugins
-{
-  class FullOrthancDataset : public IDicomDataset
-  {
-  private:
-    Json::Value   root_;
-
-    const Json::Value* LookupPath(const DicomPath& path) const;
-
-    void CheckRoot() const;
-
-  public:
-    FullOrthancDataset(IOrthancConnection& orthanc,
-                       const std::string& uri);
-
-    FullOrthancDataset(const std::string& content);
-
-    FullOrthancDataset(const void* content,
-                       size_t size);
-
-    FullOrthancDataset(const Json::Value& root);
-
-    virtual bool GetStringValue(std::string& result,
-                                const DicomPath& path) const;
-
-    virtual bool GetSequenceSize(size_t& size,
-                                 const DicomPath& path) const;
-
-    FullOrthancDataset* Clone() const
-    {
-      return new FullOrthancDataset(this->root_);
-    }
-  };
-}
--- a/Framework/Inputs/Orthanc/IDicomDataset.h	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "DicomPath.h"
-
-#include <boost/noncopyable.hpp>
-#include <string>
-
-namespace OrthancPlugins
-{
-  class IDicomDataset : public boost::noncopyable
-  {
-  public:
-    virtual ~IDicomDataset()
-    {
-    }
-
-    virtual bool GetStringValue(std::string& result,
-                                const DicomPath& path) const = 0;
-
-    virtual bool GetSequenceSize(size_t& size,
-                                 const DicomPath& path) const = 0;
-  };
-}
--- a/Framework/Inputs/Orthanc/IOrthancConnection.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "IOrthancConnection.h"
-
-#include <OrthancException.h>
-
-#include <json/reader.h>
-
-namespace OrthancPlugins
-{
-  void IOrthancConnection::ParseJson(Json::Value& result,
-                                     const std::string& content)
-  {
-    Json::Reader reader;
-    
-    if (!reader.parse(content, result))
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-  }
-
-
-  void IOrthancConnection::ParseJson(Json::Value& result,
-                                     const void* content,
-                                     size_t size)
-  {
-    Json::Reader reader;
-    
-    if (!reader.parse(reinterpret_cast<const char*>(content),
-                      reinterpret_cast<const char*>(content) + size, result))
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-  }
-
-
-  void IOrthancConnection::RestApiGet(Json::Value& result,
-                                      IOrthancConnection& orthanc,
-                                      const std::string& uri)
-  {
-    std::string content;
-    orthanc.RestApiGet(content, uri);
-    ParseJson(result, content);
-  }
-
-
-  void IOrthancConnection::RestApiPost(Json::Value& result,
-                                       IOrthancConnection& orthanc,
-                                       const std::string& uri,
-                                       const std::string& body)
-  {
-    std::string content;
-    orthanc.RestApiPost(content, uri, body);
-    ParseJson(result, content);
-  }
-
-
-  void IOrthancConnection::RestApiPut(Json::Value& result,
-                                      IOrthancConnection& orthanc,
-                                      const std::string& uri,
-                                      const std::string& body)
-  {
-    std::string content;
-    orthanc.RestApiPut(content, uri, body);
-    ParseJson(result, content);
-  }
-}
--- a/Framework/Inputs/Orthanc/IOrthancConnection.h	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "DicomPath.h"
-
-#include <boost/noncopyable.hpp>
-#include <string>
-#include <json/value.h>
-
-namespace OrthancPlugins
-{
-  class IOrthancConnection : public boost::noncopyable
-  {
-  public:
-    virtual ~IOrthancConnection()
-    {
-    }
-
-    virtual void RestApiGet(std::string& result,
-                            const std::string& uri) = 0;
-
-    virtual void RestApiPost(std::string& result,
-                             const std::string& uri,
-                             const std::string& body) = 0;
-
-    virtual void RestApiPut(std::string& result,
-                            const std::string& uri,
-                            const std::string& body) = 0;
-
-    virtual void RestApiDelete(const std::string& uri) = 0;
-
-    static void ParseJson(Json::Value& result,
-                          const std::string& content);
-
-    static void ParseJson(Json::Value& result,
-                          const void* content,
-                          size_t size);
-
-    static void RestApiGet(Json::Value& result,
-                           IOrthancConnection& orthanc,
-                           const std::string& uri);
-
-    static void RestApiPost(Json::Value& result,
-                            IOrthancConnection& orthanc,
-                            const std::string& uri,
-                            const std::string& body);
-
-    static void RestApiPut(Json::Value& result,
-                           IOrthancConnection& orthanc,
-                           const std::string& uri,
-                           const std::string& body);
-  };
-}
--- a/Framework/Inputs/Orthanc/OrthancHttpConnection.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "OrthancHttpConnection.h"
-
-namespace OrthancPlugins
-{
-  void OrthancHttpConnection::Setup()
-  {
-    url_ = client_.GetUrl();
-
-    // Don't follow 3xx HTTP (avoid redirections to "unsupported.png" in Orthanc)
-    client_.SetRedirectionFollowed(false);  
-  }
-
-
-  OrthancHttpConnection::OrthancHttpConnection() :
-    client_(Orthanc::WebServiceParameters(), "")
-  {
-    Setup();
-  }
-
-
-  OrthancHttpConnection::OrthancHttpConnection(const Orthanc::WebServiceParameters& parameters) :
-    client_(parameters, "")
-  {
-    Setup();
-  }
-
-
-  void OrthancHttpConnection::RestApiGet(std::string& result,
-                                         const std::string& uri)
-  {
-    boost::mutex::scoped_lock lock(mutex_);
-
-    client_.SetMethod(Orthanc::HttpMethod_Get);
-    client_.SetUrl(url_ + uri);
-    client_.ApplyAndThrowException(result);
-  }
-
-
-  void OrthancHttpConnection::RestApiPost(std::string& result,
-                                          const std::string& uri,
-                                          const std::string& body)
-  {
-    boost::mutex::scoped_lock lock(mutex_);
-
-    client_.SetMethod(Orthanc::HttpMethod_Post);
-    client_.SetUrl(url_ + uri);
-    client_.SetBody(body);
-    client_.ApplyAndThrowException(result);
-  }
-
-
-  void OrthancHttpConnection::RestApiPut(std::string& result,
-                                         const std::string& uri,
-                                         const std::string& body)
-  {
-    boost::mutex::scoped_lock lock(mutex_);
-
-    client_.SetMethod(Orthanc::HttpMethod_Put);
-    client_.SetUrl(url_ + uri);
-    client_.SetBody(body);
-    client_.ApplyAndThrowException(result);
-  }
-
-
-  void OrthancHttpConnection::RestApiDelete(const std::string& uri)
-  {
-    boost::mutex::scoped_lock lock(mutex_);
-
-    std::string result;
-
-    client_.SetMethod(Orthanc::HttpMethod_Delete);
-    client_.SetUrl(url_ + uri);
-    client_.ApplyAndThrowException(result);
-  }
-}
--- a/Framework/Inputs/Orthanc/OrthancHttpConnection.h	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "IOrthancConnection.h"
-
-#include <HttpClient.h>
-
-#include <boost/thread/mutex.hpp>
-
-namespace OrthancPlugins
-{
-  // This class is thread-safe
-  class OrthancHttpConnection : public IOrthancConnection
-  {
-  private:
-    boost::mutex         mutex_;
-    Orthanc::HttpClient  client_;
-    std::string          url_;
-
-    void Setup();
-
-  public:
-    OrthancHttpConnection();
-
-    OrthancHttpConnection(const Orthanc::WebServiceParameters& parameters);
-
-    virtual void RestApiGet(std::string& result,
-                            const std::string& uri);
-
-    virtual void RestApiPost(std::string& result,
-                             const std::string& uri,
-                             const std::string& body);
-
-    virtual void RestApiPut(std::string& result,
-                            const std::string& uri,
-                            const std::string& body);
-
-    virtual void RestApiDelete(const std::string& uri);
-  };
-}
--- a/Framework/Inputs/Orthanc/OrthancPluginConnection.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "OrthancPluginConnection.h"
-
-#include "../../../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h"
-
-#include <OrthancException.h>
-
-namespace OrthancPlugins
-{
-  void OrthancPluginConnection::RestApiGet(std::string& result,
-                                           const std::string& uri) 
-  {
-    OrthancPlugins::MemoryBuffer buffer;
-
-    if (buffer.RestApiGet(uri, false))
-    {
-      buffer.ToString(result);
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
-    }
-  }
-
-
-  void OrthancPluginConnection::RestApiPost(std::string& result,
-                                            const std::string& uri,
-                                            const std::string& body)
-  {
-    OrthancPlugins::MemoryBuffer buffer;
-
-    if (buffer.RestApiPost(uri, body.c_str(), body.size(), false))
-    {
-      buffer.ToString(result);
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
-    }
-  }
-
-
-  void OrthancPluginConnection::RestApiPut(std::string& result,
-                                           const std::string& uri,
-                                           const std::string& body)
-  {
-    OrthancPlugins::MemoryBuffer buffer;
-
-    if (buffer.RestApiPut(uri, body.c_str(), body.size(), false))
-    {
-      buffer.ToString(result);
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
-    }
-  }
-
-
-  void OrthancPluginConnection::RestApiDelete(const std::string& uri)
-  {
-    OrthancPlugins::MemoryBuffer buffer;
-
-    if (!::OrthancPlugins::RestApiDelete(uri, false))
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
-    }
-  }
-}
--- a/Framework/Inputs/Orthanc/OrthancPluginConnection.h	Tue Jun 30 18:11:30 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero 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
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "IOrthancConnection.h"
-
-#include <orthanc/OrthancCPlugin.h>
-
-namespace OrthancPlugins
-{
-  // This class is thread-safe
-  class OrthancPluginConnection : public IOrthancConnection
-  {
-  public:
-    virtual void RestApiGet(std::string& result,
-                            const std::string& uri);
-
-    virtual void RestApiPost(std::string& result,
-                             const std::string& uri,
-                             const std::string& body);
-
-    virtual void RestApiPut(std::string& result,
-                            const std::string& uri,
-                            const std::string& body);
-
-    virtual void RestApiDelete(const std::string& uri);
-  };
-}
--- a/Framework/Targets/OrthancTarget.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ b/Framework/Targets/OrthancTarget.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -23,7 +23,7 @@
 #include "OrthancTarget.h"
 
 #include "../DicomToolbox.h"
-#include "../Inputs/Orthanc/OrthancHttpConnection.h"
+#include "../../Resources/Orthanc/Stone/OrthancHttpConnection.h"
 
 #include <OrthancException.h>
 #include <Logging.h>
@@ -32,7 +32,7 @@
 namespace OrthancWSI
 {
   OrthancTarget::OrthancTarget(const Orthanc::WebServiceParameters& parameters) :
-    orthanc_(new OrthancPlugins::OrthancHttpConnection(parameters)),
+    orthanc_(new OrthancStone::OrthancHttpConnection(parameters)),
     first_(true)
   {
   }
@@ -41,7 +41,7 @@
   void OrthancTarget::Write(const std::string& file)
   {
     Json::Value result;
-    OrthancPlugins::IOrthancConnection::RestApiPost(result, *orthanc_, "/instances", file);
+    OrthancStone::IOrthancConnection::RestApiPost(result, *orthanc_, "/instances", file);
 
     if (result.type() != Json::objectValue ||
         !result.isMember("ID") ||
@@ -55,7 +55,7 @@
     if (first_)
     {
       Json::Value instance;
-      OrthancPlugins::IOrthancConnection::RestApiGet(instance, *orthanc_, "/instances/" + instanceId);
+      OrthancStone::IOrthancConnection::RestApiGet(instance, *orthanc_, "/instances/" + instanceId);
 
       if (instance.type() != Json::objectValue ||
           !instance.isMember("ParentSeries") ||
--- a/Framework/Targets/OrthancTarget.h	Tue Jun 30 18:11:30 2020 +0200
+++ b/Framework/Targets/OrthancTarget.h	Wed Jul 01 17:57:38 2020 +0200
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "IFileTarget.h"
-#include "../Inputs/Orthanc/IOrthancConnection.h"
+#include "../../Resources/Orthanc/Stone/IOrthancConnection.h"
 
 #include <WebServiceParameters.h>
 
@@ -33,13 +33,13 @@
   class OrthancTarget : public IFileTarget
   {
   private:
-    std::auto_ptr<OrthancPlugins::IOrthancConnection>  orthanc_;
+    std::auto_ptr<OrthancStone::IOrthancConnection>  orthanc_;
     bool  first_;
 
   public:
     explicit OrthancTarget(const Orthanc::WebServiceParameters& parameters);
 
-    explicit OrthancTarget(OrthancPlugins::IOrthancConnection* orthanc) :   // Takes ownership
+    explicit OrthancTarget(OrthancStone::IOrthancConnection* orthanc) :   // Takes ownership
       orthanc_(orthanc),
       first_(true)
     {
--- a/Resources/Orthanc/DownloadOrthancFramework.cmake	Tue Jun 30 18:11:30 2020 +0200
+++ b/Resources/Orthanc/DownloadOrthancFramework.cmake	Wed Jul 01 17:57:38 2020 +0200
@@ -505,28 +505,36 @@
       ${ORTHANC_FRAMEWORK_ROOT}
       )
   endif()
+
+  if (${ORTHANC_FRAMEWORK_INCLUDE_DIR} STREQUAL "ORTHANC_FRAMEWORK_INCLUDE_DIR-NOTFOUND")
+    message(FATAL_ERROR "Cannot locate the OrthancFramework.h header")
+  endif()
   
   message("Orthanc framework include dir: ${ORTHANC_FRAMEWORK_INCLUDE_DIR}")
   include_directories(${ORTHANC_FRAMEWORK_INCLUDE_DIR})
   
-  set(CMAKE_REQUIRED_INCLUDES "${ORTHANC_FRAMEWORK_INCLUDE_DIR}")
+  if ("${ORTHANC_FRAMEWORK_LIBDIR}" STREQUAL "")
+    set(ORTHANC_FRAMEWORK_LIBRARIES OrthancFramework)
+  else()
+    if (MSVC)
+      set(Suffix ".lib")
+      set(Prefix "")
+    else()
+      list(GET CMAKE_FIND_LIBRARY_PREFIXES 0 Prefix)
+      list(GET CMAKE_FIND_LIBRARY_SUFFIXES 0 Suffix)
+    endif()
+    set(ORTHANC_FRAMEWORK_LIBRARIES ${ORTHANC_FRAMEWORK_LIBDIR}/${Prefix}OrthancFramework${Suffix})
+  endif()
 
-  if (NOT "${ORTHANC_FRAMEWORK_LIBDIR}" STREQUAL "")
-    set(CMAKE_REQUIRED_LIBRARIES "-L${ORTHANC_FRAMEWORK_LIBDIR} -lOrthancFramework")
-  else()
-    set(CMAKE_REQUIRED_LIBRARIES "OrthancFramework")
-  endif()
+  set(CMAKE_REQUIRED_INCLUDES "${ORTHANC_FRAMEWORK_INCLUDE_DIR}")
+  set(CMAKE_REQUIRED_LIBRARIES "${ORTHANC_FRAMEWORK_LIBRARIES}")
   
   check_cxx_symbol_exists("Orthanc::InitializeFramework" "OrthancFramework.h" HAVE_ORTHANC_FRAMEWORK)
-  if(NOT HAVE_ORTHANC_FRAMEWORK)
+  if (NOT HAVE_ORTHANC_FRAMEWORK)
     message(FATAL_ERROR "Cannot find the Orthanc framework")
   endif()
 
   if (NOT "${ORTHANC_FRAMEWORK_ROOT}" STREQUAL "")
     include_directories(${ORTHANC_FRAMEWORK_ROOT})
   endif()
-
-  if (NOT "${ORTHANC_FRAMEWORK_LIBDIR}" STREQUAL "")
-    link_directories(${ORTHANC_FRAMEWORK_LIBDIR})
-  endif()
 endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Stone/DicomDatasetReader.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,132 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "DicomDatasetReader.h"
+
+#include <OrthancException.h>
+#include <Toolbox.h>
+
+#include <boost/lexical_cast.hpp>
+
+namespace OrthancStone
+{
+  DicomDatasetReader::DicomDatasetReader(const IDicomDataset& dataset) :
+    dataset_(dataset)
+  {
+  }
+  
+
+  std::string DicomDatasetReader::GetStringValue(const DicomPath& path,
+                                                 const std::string& defaultValue) const
+  {
+    std::string s;
+    if (dataset_.GetStringValue(s, path))
+    {
+      return s;
+    }
+    else
+    {
+      return defaultValue;
+    }
+  }
+
+
+  std::string DicomDatasetReader::GetMandatoryStringValue(const DicomPath& path) const
+  {
+    std::string s;
+    if (dataset_.GetStringValue(s, path))
+    {
+      return s;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentTag);
+    }
+  }
+
+
+  template <typename T>
+  static bool GetValueInternal(T& target,
+                               const IDicomDataset& dataset,
+                               const DicomPath& path)
+  {
+    try
+    {
+      std::string s;
+
+      if (dataset.GetStringValue(s, path))
+      {
+        target = boost::lexical_cast<T>(Orthanc::Toolbox::StripSpaces(s));
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+    catch (boost::bad_lexical_cast&)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);        
+    }
+  }
+
+
+  bool DicomDatasetReader::GetIntegerValue(int& target,
+                                           const DicomPath& path) const
+  {
+    return GetValueInternal<int>(target, dataset_, path);
+  }
+
+
+  bool DicomDatasetReader::GetUnsignedIntegerValue(unsigned int& target,
+                                                   const DicomPath& path) const
+  {
+    int value;
+
+    if (!GetIntegerValue(value, path))
+    {
+      return false;
+    }
+    else if (value >= 0)
+    {
+      target = static_cast<unsigned int>(value);
+      return true;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
+  bool DicomDatasetReader::GetFloatValue(float& target,
+                                         const DicomPath& path) const
+  {
+    return GetValueInternal<float>(target, dataset_, path);
+  }
+
+
+  bool DicomDatasetReader::GetDoubleValue(double& target,
+                                          const DicomPath& path) const
+  {
+    return GetValueInternal<double>(target, dataset_, path);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Stone/DicomDatasetReader.h	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,61 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "IDicomDataset.h"
+
+#include <memory>
+#include <vector>
+
+namespace OrthancStone
+{
+  class DicomDatasetReader : public boost::noncopyable
+  {
+  private:
+    const IDicomDataset&  dataset_;
+
+  public:
+    DicomDatasetReader(const IDicomDataset& dataset);
+
+    const IDicomDataset& GetDataset() const
+    {
+      return dataset_;
+    }
+
+    std::string GetStringValue(const DicomPath& path,
+                               const std::string& defaultValue) const;
+
+    std::string GetMandatoryStringValue(const DicomPath& path) const;
+
+    bool GetIntegerValue(int& target,
+                         const DicomPath& path) const;
+
+    bool GetUnsignedIntegerValue(unsigned int& target,
+                                 const DicomPath& path) const;
+
+    bool GetFloatValue(float& target,
+                       const DicomPath& path) const;
+
+    bool GetDoubleValue(double& target,
+                        const DicomPath& path) const;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Stone/DicomPath.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,112 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "DicomPath.h"
+
+#include <OrthancException.h>
+
+#include <boost/lexical_cast.hpp>
+
+namespace OrthancStone
+{
+  const DicomPath::Prefix& DicomPath::GetPrefixItem(size_t depth) const
+  {
+    if (depth >= prefix_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      return prefix_[depth];
+    }
+  }
+
+
+  DicomPath::Prefix& DicomPath::GetPrefixItem(size_t depth)
+  {
+    if (depth >= prefix_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      return prefix_[depth];
+    }
+  }
+
+
+  DicomPath::DicomPath(const Orthanc::DicomTag& sequence,
+                       size_t index,
+                       const Orthanc::DicomTag& tag) :
+    finalTag_(tag)
+  {
+    AddToPrefix(sequence, index);
+  }
+
+
+  DicomPath::DicomPath(const Orthanc::DicomTag& sequence1,
+                       size_t index1,
+                       const Orthanc::DicomTag& sequence2,
+                       size_t index2,
+                       const Orthanc::DicomTag& tag) :
+    finalTag_(tag)
+  {
+    AddToPrefix(sequence1, index1);
+    AddToPrefix(sequence2, index2);
+  }
+
+
+  DicomPath::DicomPath(const Orthanc::DicomTag& sequence1,
+                       size_t index1,
+                       const Orthanc::DicomTag& sequence2,
+                       size_t index2,
+                       const Orthanc::DicomTag& sequence3,
+                       size_t index3,
+                       const Orthanc::DicomTag& tag) :
+    finalTag_(tag)
+  {
+    AddToPrefix(sequence1, index1);
+    AddToPrefix(sequence2, index2);
+    AddToPrefix(sequence3, index3);
+  }
+
+
+  static std::string FormatHexadecimal(const Orthanc::DicomTag& tag)
+  {
+    char buf[16];
+    sprintf(buf, "(%04x,%04x)", tag.GetGroup(), tag.GetElement());
+    return buf;
+  }
+  
+
+  std::string DicomPath::Format() const
+  {
+    std::string s;
+      
+    for (size_t i = 0; i < GetPrefixLength(); i++)
+    {
+      s += (FormatHexadecimal(GetPrefixTag(i)) + " / " +
+            boost::lexical_cast<std::string>(i) + " / ");
+    }
+
+    return s + FormatHexadecimal(GetFinalTag());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Stone/DicomPath.h	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,106 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include <DicomFormat/DicomTag.h>
+
+#include <vector>
+#include <stddef.h>
+
+namespace OrthancStone
+{
+  class DicomPath
+  {
+  private:
+    typedef std::pair<Orthanc::DicomTag, size_t>  Prefix;
+
+    std::vector<Prefix>  prefix_;
+    Orthanc::DicomTag    finalTag_;
+
+    const Prefix& GetPrefixItem(size_t depth) const;
+
+    Prefix& GetPrefixItem(size_t depth);
+
+  public:
+    DicomPath(const Orthanc::DicomTag& finalTag) :
+      finalTag_(finalTag)
+    {
+    }
+
+    DicomPath(const Orthanc::DicomTag& sequence,
+              size_t index,
+              const Orthanc::DicomTag& tag);
+
+    DicomPath(const Orthanc::DicomTag& sequence1,
+              size_t index1,
+              const Orthanc::DicomTag& sequence2,
+              size_t index2,
+              const Orthanc::DicomTag& tag);
+
+    DicomPath(const Orthanc::DicomTag& sequence1,
+              size_t index1,
+              const Orthanc::DicomTag& sequence2,
+              size_t index2,
+              const Orthanc::DicomTag& sequence3,
+              size_t index3,
+              const Orthanc::DicomTag& tag);
+
+    void AddToPrefix(const Orthanc::DicomTag& tag,
+                     size_t position)
+    {
+      prefix_.push_back(std::make_pair(tag, position));
+    }
+
+    size_t GetPrefixLength() const
+    {
+      return prefix_.size();
+    }
+    
+    Orthanc::DicomTag GetPrefixTag(size_t depth) const
+    {
+      return GetPrefixItem(depth).first;
+    }
+
+    size_t GetPrefixIndex(size_t depth) const
+    {
+      return GetPrefixItem(depth).second;
+    }
+
+    void SetPrefixIndex(size_t depth,
+                        size_t value)
+    {
+      GetPrefixItem(depth).second = value;
+    }
+    
+    const Orthanc::DicomTag& GetFinalTag() const
+    {
+      return finalTag_;
+    }
+
+    void SetFinalTag(const Orthanc::DicomTag& tag)
+    {
+      finalTag_ = tag;
+    }
+
+    std::string Format() const;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Stone/FullOrthancDataset.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,203 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "FullOrthancDataset.h"
+
+#include <OrthancException.h>
+
+#include <stdio.h>
+#include <cassert>
+
+namespace OrthancStone
+{
+  static const Json::Value* AccessTag(const Json::Value& dataset,
+                                      const Orthanc::DicomTag& tag) 
+  {
+    if (dataset.type() != Json::objectValue)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
+
+    char name[16];
+    sprintf(name, "%04x,%04x", tag.GetGroup(), tag.GetElement());
+
+    if (!dataset.isMember(name))
+    {
+      return NULL;
+    }
+
+    const Json::Value& value = dataset[name];
+    if (value.type() != Json::objectValue ||
+        !value.isMember("Name") ||
+        !value.isMember("Type") ||
+        !value.isMember("Value") ||
+        value["Name"].type() != Json::stringValue ||
+        value["Type"].type() != Json::stringValue)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
+
+    return &value;
+  }
+
+
+  static const Json::Value& GetSequenceContent(const Json::Value& sequence)
+  {
+    assert(sequence.type() == Json::objectValue);
+    assert(sequence.isMember("Type"));
+    assert(sequence.isMember("Value"));
+
+    const Json::Value& value = sequence["Value"];
+      
+    if (sequence["Type"].asString() != "Sequence" ||
+        value.type() != Json::arrayValue)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
+    else
+    {
+      return value;
+    }
+  }
+
+
+  static bool GetStringInternal(std::string& result,
+                                const Json::Value& tag)
+  {
+    assert(tag.type() == Json::objectValue);
+    assert(tag.isMember("Type"));
+    assert(tag.isMember("Value"));
+
+    const Json::Value& value = tag["Value"];
+      
+    if (tag["Type"].asString() != "String" ||
+        value.type() != Json::stringValue)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
+    else
+    {
+      result = value.asString();
+      return true;
+    }
+  }
+
+
+  const Json::Value* FullOrthancDataset::LookupPath(const DicomPath& path) const
+  {
+    const Json::Value* content = &root_;
+                                  
+    for (unsigned int depth = 0; depth < path.GetPrefixLength(); depth++)
+    {
+      const Json::Value* sequence = AccessTag(*content, path.GetPrefixTag(depth));
+      if (sequence == NULL)
+      {
+        return NULL;
+      }
+
+      const Json::Value& nextContent = GetSequenceContent(*sequence);
+
+      size_t index = path.GetPrefixIndex(depth);
+      if (index >= nextContent.size())
+      {
+        return NULL;
+      }
+      else
+      {
+        content = &nextContent[static_cast<Json::Value::ArrayIndex>(index)];
+      }
+    }
+
+    return AccessTag(*content, path.GetFinalTag());
+  }
+
+
+  void FullOrthancDataset::CheckRoot() const
+  {
+    if (root_.type() != Json::objectValue)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
+  }
+
+
+  FullOrthancDataset::FullOrthancDataset(IOrthancConnection& orthanc,
+                                         const std::string& uri)
+  {
+    IOrthancConnection::RestApiGet(root_, orthanc, uri);
+    CheckRoot();
+  }
+
+
+  FullOrthancDataset::FullOrthancDataset(const std::string& content)
+  {
+    IOrthancConnection::ParseJson(root_, content);
+    CheckRoot();
+  }
+
+
+  FullOrthancDataset::FullOrthancDataset(const void* content,
+                                         size_t size)
+  {
+    IOrthancConnection::ParseJson(root_, content, size);
+    CheckRoot();
+  }
+
+
+  FullOrthancDataset::FullOrthancDataset(const Json::Value& root) :
+    root_(root)
+  {
+    CheckRoot();
+  }
+
+
+  bool FullOrthancDataset::GetStringValue(std::string& result,
+                                          const DicomPath& path) const
+  {
+    const Json::Value* value = LookupPath(path);
+
+    if (value == NULL)
+    {
+      return false;
+    }
+    else
+    {
+      return GetStringInternal(result, *value);
+    }
+  }
+
+
+  bool FullOrthancDataset::GetSequenceSize(size_t& size,
+                                           const DicomPath& path) const
+  {
+    const Json::Value* sequence = LookupPath(path);
+
+    if (sequence == NULL)
+    {
+      return false;
+    }
+    else
+    {
+      size = GetSequenceContent(*sequence).size();
+      return true;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Stone/FullOrthancDataset.h	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,62 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "IOrthancConnection.h"
+#include "IDicomDataset.h"
+
+#include <json/value.h>
+
+namespace OrthancStone
+{
+  class FullOrthancDataset : public IDicomDataset
+  {
+  private:
+    Json::Value   root_;
+
+    const Json::Value* LookupPath(const DicomPath& path) const;
+
+    void CheckRoot() const;
+
+  public:
+    FullOrthancDataset(IOrthancConnection& orthanc,
+                       const std::string& uri);
+
+    FullOrthancDataset(const std::string& content);
+
+    FullOrthancDataset(const void* content,
+                       size_t size);
+
+    FullOrthancDataset(const Json::Value& root);
+
+    virtual bool GetStringValue(std::string& result,
+                                const DicomPath& path) const;
+
+    virtual bool GetSequenceSize(size_t& size,
+                                 const DicomPath& path) const;
+
+    FullOrthancDataset* Clone() const
+    {
+      return new FullOrthancDataset(this->root_);
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Stone/IDicomDataset.h	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,44 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "DicomPath.h"
+
+#include <boost/noncopyable.hpp>
+#include <string>
+
+namespace OrthancStone
+{
+  class IDicomDataset : public boost::noncopyable
+  {
+  public:
+    virtual ~IDicomDataset()
+    {
+    }
+
+    virtual bool GetStringValue(std::string& result,
+                                const DicomPath& path) const = 0;
+
+    virtual bool GetSequenceSize(size_t& size,
+                                 const DicomPath& path) const = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Stone/IOrthancConnection.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,86 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "IOrthancConnection.h"
+
+#include <OrthancException.h>
+
+#include <json/reader.h>
+
+namespace OrthancStone
+{
+  void IOrthancConnection::ParseJson(Json::Value& result,
+                                     const std::string& content)
+  {
+    Json::Reader reader;
+    
+    if (!reader.parse(content, result))
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
+  }
+
+
+  void IOrthancConnection::ParseJson(Json::Value& result,
+                                     const void* content,
+                                     size_t size)
+  {
+    Json::Reader reader;
+    
+    if (!reader.parse(reinterpret_cast<const char*>(content),
+                      reinterpret_cast<const char*>(content) + size, result))
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
+  }
+
+
+  void IOrthancConnection::RestApiGet(Json::Value& result,
+                                      IOrthancConnection& orthanc,
+                                      const std::string& uri)
+  {
+    std::string content;
+    orthanc.RestApiGet(content, uri);
+    ParseJson(result, content);
+  }
+
+
+  void IOrthancConnection::RestApiPost(Json::Value& result,
+                                       IOrthancConnection& orthanc,
+                                       const std::string& uri,
+                                       const std::string& body)
+  {
+    std::string content;
+    orthanc.RestApiPost(content, uri, body);
+    ParseJson(result, content);
+  }
+
+
+  void IOrthancConnection::RestApiPut(Json::Value& result,
+                                      IOrthancConnection& orthanc,
+                                      const std::string& uri,
+                                      const std::string& body)
+  {
+    std::string content;
+    orthanc.RestApiPut(content, uri, body);
+    ParseJson(result, content);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Stone/IOrthancConnection.h	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,73 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "DicomPath.h"
+
+#include <boost/noncopyable.hpp>
+#include <string>
+#include <json/value.h>
+
+namespace OrthancStone
+{
+  class IOrthancConnection : public boost::noncopyable
+  {
+  public:
+    virtual ~IOrthancConnection()
+    {
+    }
+
+    virtual void RestApiGet(std::string& result,
+                            const std::string& uri) = 0;
+
+    virtual void RestApiPost(std::string& result,
+                             const std::string& uri,
+                             const std::string& body) = 0;
+
+    virtual void RestApiPut(std::string& result,
+                            const std::string& uri,
+                            const std::string& body) = 0;
+
+    virtual void RestApiDelete(const std::string& uri) = 0;
+
+    static void ParseJson(Json::Value& result,
+                          const std::string& content);
+
+    static void ParseJson(Json::Value& result,
+                          const void* content,
+                          size_t size);
+
+    static void RestApiGet(Json::Value& result,
+                           IOrthancConnection& orthanc,
+                           const std::string& uri);
+
+    static void RestApiPost(Json::Value& result,
+                            IOrthancConnection& orthanc,
+                            const std::string& uri,
+                            const std::string& body);
+
+    static void RestApiPut(Json::Value& result,
+                           IOrthancConnection& orthanc,
+                           const std::string& uri,
+                           const std::string& body);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Stone/OrthancHttpConnection.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,96 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "OrthancHttpConnection.h"
+
+namespace OrthancStone
+{
+  void OrthancHttpConnection::Setup()
+  {
+    url_ = client_.GetUrl();
+
+    // Don't follow 3xx HTTP (avoid redirections to "unsupported.png" in Orthanc)
+    client_.SetRedirectionFollowed(false);  
+  }
+
+
+  OrthancHttpConnection::OrthancHttpConnection() :
+    client_(Orthanc::WebServiceParameters(), "")
+  {
+    Setup();
+  }
+
+
+  OrthancHttpConnection::OrthancHttpConnection(const Orthanc::WebServiceParameters& parameters) :
+    client_(parameters, "")
+  {
+    Setup();
+  }
+
+
+  void OrthancHttpConnection::RestApiGet(std::string& result,
+                                         const std::string& uri)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+
+    client_.SetMethod(Orthanc::HttpMethod_Get);
+    client_.SetUrl(url_ + uri);
+    client_.ApplyAndThrowException(result);
+  }
+
+
+  void OrthancHttpConnection::RestApiPost(std::string& result,
+                                          const std::string& uri,
+                                          const std::string& body)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+
+    client_.SetMethod(Orthanc::HttpMethod_Post);
+    client_.SetUrl(url_ + uri);
+    client_.SetBody(body);
+    client_.ApplyAndThrowException(result);
+  }
+
+
+  void OrthancHttpConnection::RestApiPut(std::string& result,
+                                         const std::string& uri,
+                                         const std::string& body)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+
+    client_.SetMethod(Orthanc::HttpMethod_Put);
+    client_.SetUrl(url_ + uri);
+    client_.SetBody(body);
+    client_.ApplyAndThrowException(result);
+  }
+
+
+  void OrthancHttpConnection::RestApiDelete(const std::string& uri)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+
+    std::string result;
+
+    client_.SetMethod(Orthanc::HttpMethod_Delete);
+    client_.SetUrl(url_ + uri);
+    client_.ApplyAndThrowException(result);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Stone/OrthancHttpConnection.h	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,60 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "IOrthancConnection.h"
+
+#include <HttpClient.h>
+
+#include <boost/thread/mutex.hpp>
+
+namespace OrthancStone
+{
+  // This class is thread-safe
+  class OrthancHttpConnection : public IOrthancConnection
+  {
+  private:
+    boost::mutex         mutex_;
+    Orthanc::HttpClient  client_;
+    std::string          url_;
+
+    void Setup();
+
+  public:
+    OrthancHttpConnection();
+
+    OrthancHttpConnection(const Orthanc::WebServiceParameters& parameters);
+
+    virtual void RestApiGet(std::string& result,
+                            const std::string& uri);
+
+    virtual void RestApiPost(std::string& result,
+                             const std::string& uri,
+                             const std::string& body);
+
+    virtual void RestApiPut(std::string& result,
+                            const std::string& uri,
+                            const std::string& body);
+
+    virtual void RestApiDelete(const std::string& uri);
+  };
+}
--- a/Resources/SyncOrthancFolder.py	Tue Jun 30 18:11:30 2020 +0200
+++ b/Resources/SyncOrthancFolder.py	Wed Jul 01 17:57:38 2020 +0200
@@ -12,17 +12,30 @@
 
 TARGET = os.path.join(os.path.dirname(__file__), 'Orthanc')
 PLUGIN_SDK_VERSION = '1.0.0'
-REPOSITORY = 'https://hg.orthanc-server.com/orthanc/raw-file'
+REPOSITORY = 'https://hg.orthanc-server.com/%s/raw-file'
 
 FILES = [
-    ('OrthancFramework/Resources/CMake/DownloadOrthancFramework.cmake', '.'),
-    ('OrthancFramework/Resources/Toolchains/LinuxStandardBaseToolchain.cmake', '.'),
-    ('OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain32.cmake', '.'),
-    ('OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain64.cmake', '.'),
-    ('OrthancFramework/Resources/Toolchains/MinGWToolchain.cmake', '.'),
-    ('OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp', 'Plugins'),
-    ('OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h', 'Plugins'),
-    ('OrthancServer/Plugins/Samples/Common/OrthancPluginException.h', 'Plugins'),
+    ('orthanc', 'OrthancFramework/Resources/CMake/DownloadOrthancFramework.cmake', '.'),
+    ('orthanc', 'OrthancFramework/Resources/Toolchains/LinuxStandardBaseToolchain.cmake', '.'),
+    ('orthanc', 'OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain32.cmake', '.'),
+    ('orthanc', 'OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain64.cmake', '.'),
+    ('orthanc', 'OrthancFramework/Resources/Toolchains/MinGWToolchain.cmake', '.'),
+
+    ('orthanc', 'OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp', 'Plugins'),
+    ('orthanc', 'OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h', 'Plugins'),
+    ('orthanc', 'OrthancServer/Plugins/Samples/Common/OrthancPluginException.h', 'Plugins'),
+
+    ('orthanc-stone', 'Framework/Toolbox/OrthancDatasets/DicomDatasetReader.cpp', 'Stone'),
+    ('orthanc-stone', 'Framework/Toolbox/OrthancDatasets/DicomDatasetReader.h', 'Stone'),
+    ('orthanc-stone', 'Framework/Toolbox/OrthancDatasets/DicomPath.cpp', 'Stone'),
+    ('orthanc-stone', 'Framework/Toolbox/OrthancDatasets/DicomPath.h', 'Stone'),
+    ('orthanc-stone', 'Framework/Toolbox/OrthancDatasets/FullOrthancDataset.cpp', 'Stone'),
+    ('orthanc-stone', 'Framework/Toolbox/OrthancDatasets/FullOrthancDataset.h', 'Stone'),
+    ('orthanc-stone', 'Framework/Toolbox/OrthancDatasets/IDicomDataset.h', 'Stone'),
+    ('orthanc-stone', 'Framework/Toolbox/OrthancDatasets/IOrthancConnection.cpp', 'Stone'),
+    ('orthanc-stone', 'Framework/Toolbox/OrthancDatasets/IOrthancConnection.h', 'Stone'),
+    ('orthanc-stone', 'Framework/Toolbox/OrthancDatasets/OrthancHttpConnection.cpp', 'Stone'),
+    ('orthanc-stone', 'Framework/Toolbox/OrthancDatasets/OrthancHttpConnection.h', 'Stone'),
 ]
 
 SDK = [
@@ -31,9 +44,10 @@
 
 
 def Download(x):
-    branch = x[0]
-    source = x[1]
-    target = os.path.join(TARGET, x[2])
+    repository = x[0]
+    branch = x[1]
+    source = x[2]
+    target = os.path.join(TARGET, x[3])
     print target
 
     try:
@@ -41,21 +55,27 @@
     except:
         pass
 
-    url = '%s/%s/%s' % (REPOSITORY, branch, source)
+    url = '%s/%s/%s' % (REPOSITORY % repository, branch, source)
 
     with open(target, 'w') as f:
-        f.write(urllib2.urlopen(url).read())
+        try:
+            f.write(urllib2.urlopen(url).read())
+        except:
+            print('ERROR: %s' % url)
+            raise
 
 
 commands = []
 
 for f in FILES:
-    commands.append([ 'default',
-                      f[0],
-                      os.path.join(f[1], os.path.basename(f[0])) ])
+    commands.append([ f[0],
+                      'default',
+                      f[1],
+                      os.path.join(f[2], os.path.basename(f[1])) ])
 
 for f in SDK:
     commands.append([
+        'orthanc',
         'Orthanc-%s' % PLUGIN_SDK_VERSION, 
         'Plugins/Include/%s' % f,
         'Sdk-%s/%s' % (PLUGIN_SDK_VERSION, f) 
--- a/ViewerPlugin/CMakeLists.txt	Tue Jun 30 18:11:30 2020 +0200
+++ b/ViewerPlugin/CMakeLists.txt	Wed Jul 01 17:57:38 2020 +0200
@@ -146,6 +146,7 @@
 
 set(ORTHANC_WSI_SOURCES
   DicomPyramidCache.cpp
+  OrthancPluginConnection.cpp
   Plugin.cpp
 
   ${ORTHANC_WSI_DIR}/Framework/DicomToolbox.cpp
@@ -154,17 +155,15 @@
   ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramid.cpp
   ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramidInstance.cpp
   ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramidLevel.cpp
-  ${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/DicomDatasetReader.cpp
-  ${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/DicomPath.cpp
-  ${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/DicomTag.cpp
-  ${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/FullOrthancDataset.cpp
-  ${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/IOrthancConnection.cpp
-  ${ORTHANC_WSI_DIR}/Framework/Inputs/Orthanc/OrthancPluginConnection.cpp
   ${ORTHANC_WSI_DIR}/Framework/Inputs/PyramidWithRawTiles.cpp
   ${ORTHANC_WSI_DIR}/Framework/Jpeg2000Reader.cpp
   ${ORTHANC_WSI_DIR}/Framework/Jpeg2000Writer.cpp
 
-  ${CMAKE_SOURCE_DIR}/../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp
+  ${ORTHANC_WSI_DIR}/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp
+  ${ORTHANC_WSI_DIR}/Resources/Orthanc/Stone/DicomDatasetReader.cpp
+  ${ORTHANC_WSI_DIR}/Resources/Orthanc/Stone/DicomPath.cpp
+  ${ORTHANC_WSI_DIR}/Resources/Orthanc/Stone/FullOrthancDataset.cpp
+  ${ORTHANC_WSI_DIR}/Resources/Orthanc/Stone/IOrthancConnection.cpp
   )
 
 
--- a/ViewerPlugin/DicomPyramidCache.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ b/ViewerPlugin/DicomPyramidCache.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -109,7 +109,7 @@
   }
 
 
-  DicomPyramidCache::DicomPyramidCache(OrthancPlugins::IOrthancConnection& orthanc,
+  DicomPyramidCache::DicomPyramidCache(OrthancStone::IOrthancConnection& orthanc,
                                        size_t maxSize) :
     orthanc_(orthanc),
     maxSize_(maxSize)
--- a/ViewerPlugin/DicomPyramidCache.h	Tue Jun 30 18:11:30 2020 +0200
+++ b/ViewerPlugin/DicomPyramidCache.h	Wed Jul 01 17:57:38 2020 +0200
@@ -34,10 +34,10 @@
   private:
     typedef Orthanc::LeastRecentlyUsedIndex<std::string, DicomPyramid*>  Cache;
 
-    boost::mutex                         mutex_;
-    OrthancPlugins::IOrthancConnection&  orthanc_;
-    size_t                               maxSize_;
-    Cache                                cache_;
+    boost::mutex                       mutex_;
+    OrthancStone::IOrthancConnection&  orthanc_;
+    size_t                             maxSize_;
+    Cache                              cache_;
 
 
     DicomPyramid* GetCachedPyramid(const std::string& seriesId);
@@ -46,7 +46,7 @@
                              boost::mutex::scoped_lock& lock);
 
   public:
-    DicomPyramidCache(OrthancPlugins::IOrthancConnection& orthanc,
+    DicomPyramidCache(OrthancStone::IOrthancConnection& orthanc,
                       size_t maxSize);
 
     ~DicomPyramidCache();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ViewerPlugin/OrthancPluginConnection.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,89 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "OrthancPluginConnection.h"
+
+#include "../../../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h"
+
+#include <OrthancException.h>
+
+namespace OrthancWSI
+{
+  void OrthancPluginConnection::RestApiGet(std::string& result,
+                                           const std::string& uri) 
+  {
+    OrthancPlugins::MemoryBuffer buffer;
+
+    if (buffer.RestApiGet(uri, false))
+    {
+      buffer.ToString(result);
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
+    }
+  }
+
+
+  void OrthancPluginConnection::RestApiPost(std::string& result,
+                                            const std::string& uri,
+                                            const std::string& body)
+  {
+    OrthancPlugins::MemoryBuffer buffer;
+
+    if (buffer.RestApiPost(uri, body.c_str(), body.size(), false))
+    {
+      buffer.ToString(result);
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
+    }
+  }
+
+
+  void OrthancPluginConnection::RestApiPut(std::string& result,
+                                           const std::string& uri,
+                                           const std::string& body)
+  {
+    OrthancPlugins::MemoryBuffer buffer;
+
+    if (buffer.RestApiPut(uri, body.c_str(), body.size(), false))
+    {
+      buffer.ToString(result);
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
+    }
+  }
+
+
+  void OrthancPluginConnection::RestApiDelete(const std::string& uri)
+  {
+    OrthancPlugins::MemoryBuffer buffer;
+
+    if (!::OrthancPlugins::RestApiDelete(uri, false))
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ViewerPlugin/OrthancPluginConnection.h	Wed Jul 01 17:57:38 2020 +0200
@@ -0,0 +1,51 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "../Resources/Orthanc/Stone/IOrthancConnection.h"
+
+#include <orthanc/OrthancCPlugin.h>
+
+namespace OrthancWSI
+{
+  /**
+   * This file was originally part of the Orthanc repository, in
+   * releases up to 1.7.1 (in folder "Plugins/Samples/Common/"). This
+   * class is thread-safe.
+   **/
+  class OrthancPluginConnection : public OrthancStone::IOrthancConnection
+  {
+  public:
+    virtual void RestApiGet(std::string& result,
+                            const std::string& uri);
+
+    virtual void RestApiPost(std::string& result,
+                             const std::string& uri,
+                             const std::string& body);
+
+    virtual void RestApiPut(std::string& result,
+                            const std::string& uri,
+                            const std::string& body);
+
+    virtual void RestApiDelete(const std::string& uri);
+  };
+}
--- a/ViewerPlugin/Plugin.cpp	Tue Jun 30 18:11:30 2020 +0200
+++ b/ViewerPlugin/Plugin.cpp	Wed Jul 01 17:57:38 2020 +0200
@@ -21,9 +21,9 @@
 
 #include "../Framework/PrecompiledHeadersWSI.h"
 
+#include "../Framework/Jpeg2000Reader.h"
 #include "DicomPyramidCache.h"
-#include "../Framework/Jpeg2000Reader.h"
-#include "../Framework/Inputs/Orthanc/OrthancPluginConnection.h"
+#include "OrthancPluginConnection.h"
 
 #include <Logging.h>
 #include <Images/ImageProcessing.h>
@@ -38,9 +38,9 @@
 
 #include <cassert>
 
-std::auto_ptr<OrthancPlugins::OrthancPluginConnection>  orthanc_;
-std::auto_ptr<OrthancWSI::DicomPyramidCache>            cache_;
-std::auto_ptr<Orthanc::Semaphore>                       transcoderSemaphore_;
+std::auto_ptr<OrthancWSI::OrthancPluginConnection>  orthanc_;
+std::auto_ptr<OrthancWSI::DicomPyramidCache>        cache_;
+std::auto_ptr<Orthanc::Semaphore>                   transcoderSemaphore_;
 
 
 static void AnswerSparseTile(OrthancPluginRestOutput* output,
@@ -329,7 +329,7 @@
 
     OrthancPluginSetDescription(context, "Provides a Web viewer of whole-slide microscopic images within Orthanc.");
 
-    orthanc_.reset(new OrthancPlugins::OrthancPluginConnection);
+    orthanc_.reset(new OrthancWSI::OrthancPluginConnection);
     cache_.reset(new OrthancWSI::DicomPyramidCache(*orthanc_, 10 /* Number of pyramids to be cached - TODO parameter */));
 
     OrthancPluginRegisterOnChangeCallback(OrthancPlugins::GetGlobalContext(), OnChangeCallback);