changeset 116:a18bfe1fdd62

sync
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 04 Jan 2018 10:49:34 +0100
parents a51dee6a1515
children 28bd1b119c4d
files Applications/ApplicationToolbox.cpp Applications/CMakeLists.txt Applications/Dicomizer.cpp Framework/Outputs/DicomPyramidWriter.cpp Resources/Orthanc/Core/Cache/LeastRecentlyUsedIndex.h Resources/Orthanc/Core/ChunkedBuffer.cpp Resources/Orthanc/Core/ChunkedBuffer.h Resources/Orthanc/Core/DicomFormat/DicomArray.cpp Resources/Orthanc/Core/DicomFormat/DicomArray.h Resources/Orthanc/Core/DicomFormat/DicomElement.h Resources/Orthanc/Core/DicomFormat/DicomMap.cpp Resources/Orthanc/Core/DicomFormat/DicomMap.h Resources/Orthanc/Core/DicomFormat/DicomTag.cpp Resources/Orthanc/Core/DicomFormat/DicomTag.h Resources/Orthanc/Core/DicomFormat/DicomValue.cpp Resources/Orthanc/Core/DicomFormat/DicomValue.h Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.cpp Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.h Resources/Orthanc/Core/DicomParsing/ToDcmtkBridge.cpp Resources/Orthanc/Core/DicomParsing/ToDcmtkBridge.h Resources/Orthanc/Core/Endianness.h Resources/Orthanc/Core/EnumerationDictionary.h Resources/Orthanc/Core/Enumerations.cpp Resources/Orthanc/Core/Enumerations.h Resources/Orthanc/Core/HttpClient.cpp Resources/Orthanc/Core/HttpClient.h Resources/Orthanc/Core/ICommand.h Resources/Orthanc/Core/IDynamicObject.h Resources/Orthanc/Core/Images/IImageWriter.cpp Resources/Orthanc/Core/Images/IImageWriter.h Resources/Orthanc/Core/Images/Image.cpp Resources/Orthanc/Core/Images/Image.h Resources/Orthanc/Core/Images/ImageAccessor.cpp Resources/Orthanc/Core/Images/ImageAccessor.h Resources/Orthanc/Core/Images/ImageBuffer.cpp Resources/Orthanc/Core/Images/ImageBuffer.h Resources/Orthanc/Core/Images/ImageProcessing.cpp Resources/Orthanc/Core/Images/ImageProcessing.h Resources/Orthanc/Core/Images/JpegErrorManager.cpp Resources/Orthanc/Core/Images/JpegErrorManager.h Resources/Orthanc/Core/Images/JpegReader.cpp Resources/Orthanc/Core/Images/JpegReader.h Resources/Orthanc/Core/Images/JpegWriter.cpp Resources/Orthanc/Core/Images/JpegWriter.h Resources/Orthanc/Core/Images/PngReader.cpp Resources/Orthanc/Core/Images/PngReader.h Resources/Orthanc/Core/Images/PngWriter.cpp Resources/Orthanc/Core/Images/PngWriter.h Resources/Orthanc/Core/Logging.cpp Resources/Orthanc/Core/Logging.h Resources/Orthanc/Core/MultiThreading/BagOfTasks.h Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.cpp Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h Resources/Orthanc/Core/MultiThreading/Semaphore.cpp Resources/Orthanc/Core/MultiThreading/Semaphore.h Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.cpp Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.h Resources/Orthanc/Core/OrthancException.h Resources/Orthanc/Core/PrecompiledHeaders.cpp Resources/Orthanc/Core/PrecompiledHeaders.h Resources/Orthanc/Core/SystemToolbox.cpp Resources/Orthanc/Core/SystemToolbox.h Resources/Orthanc/Core/TemporaryFile.cpp Resources/Orthanc/Core/TemporaryFile.h Resources/Orthanc/Core/Toolbox.cpp Resources/Orthanc/Core/Toolbox.h Resources/Orthanc/Core/WebServiceParameters.cpp Resources/Orthanc/Core/WebServiceParameters.h Resources/Orthanc/OrthancServer/FromDcmtkBridge.cpp Resources/Orthanc/OrthancServer/FromDcmtkBridge.h Resources/Orthanc/OrthancServer/PrecompiledHeadersServer.h Resources/Orthanc/OrthancServer/ServerEnumerations.cpp Resources/Orthanc/OrthancServer/ServerEnumerations.h Resources/Orthanc/OrthancServer/ToDcmtkBridge.cpp Resources/Orthanc/OrthancServer/ToDcmtkBridge.h Resources/Orthanc/Plugins/Engine/SharedLibrary.cpp Resources/Orthanc/Plugins/Engine/SharedLibrary.h Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp Resources/Orthanc/Plugins/Samples/Common/DicomPath.h Resources/Orthanc/Plugins/Samples/Common/DicomTag.cpp Resources/Orthanc/Plugins/Samples/Common/DicomTag.h Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.cpp Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.cpp Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.cpp Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.cpp Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.h Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h Resources/Orthanc/Plugins/Samples/Common/OrthancPluginException.h Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.h Resources/Orthanc/Resources/CMake/BoostConfiguration.cmake Resources/Orthanc/Resources/CMake/Compiler.cmake Resources/Orthanc/Resources/CMake/DcmtkConfiguration.cmake Resources/Orthanc/Resources/CMake/JsonCppConfiguration.cmake Resources/Orthanc/Resources/CMake/LibCurlConfiguration.cmake Resources/Orthanc/Resources/CMake/OpenSslConfiguration.cmake Resources/Orthanc/Resources/CMake/UuidConfiguration.cmake Resources/Orthanc/Resources/CMake/VisualStudioPrecompiledHeaders.cmake Resources/Orthanc/Resources/EmbedResources.py Resources/Orthanc/Resources/Patches/boost-1.65.1-linux-standard-base.patch Resources/Orthanc/Resources/Patches/curl-7.57.0-cmake.patch Resources/Orthanc/Resources/WindowsResources.py Resources/SyncOrthancFolder.py ViewerPlugin/CMakeLists.txt
diffstat 111 files changed, 4217 insertions(+), 3693 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/ApplicationToolbox.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Applications/ApplicationToolbox.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -26,7 +26,7 @@
 #include "../Resources/Orthanc/Core/Logging.h"
 #include "../Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h"
 #include "../Resources/Orthanc/Core/SystemToolbox.h"
-#include "../Resources/Orthanc/OrthancServer/FromDcmtkBridge.h"
+#include "../Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.h"
 
 #include <boost/filesystem.hpp>
 #include <boost/lexical_cast.hpp>
--- a/Applications/CMakeLists.txt	Tue Jan 02 10:01:35 2018 +0100
+++ b/Applications/CMakeLists.txt	Thu Jan 04 10:49:34 2018 +0100
@@ -33,8 +33,9 @@
 SET(USE_SYSTEM_LIBTIFF ON CACHE BOOL "Use the system version of libtiff")
 SET(USE_SYSTEM_OPENJPEG ON CACHE BOOL "Use the system version of OpenJpeg")
 SET(USE_SYSTEM_OPENSSL ON CACHE BOOL "Use the system version of OpenSSL")
+SET(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK")
 SET(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib")
-SET(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK")
+set(USE_SYSTEM_UUID ON CACHE BOOL "Use the system version of the uuid library from e2fsprogs")
 
 SET(DCMTK_DICTIONARY_DIR "" CACHE PATH "Directory containing the DCMTK dictionaries \"dicom.dic\" and \"private.dic\" (only when using system version of DCMTK)") 
 
@@ -57,9 +58,11 @@
 SET(USE_DCMTK_361_PRIVATE_DIC OFF)  # No need for private tags
 
 include(CheckFunctionExists)
+include(CheckIncludeFile)
 include(CheckIncludeFiles)
 include(CheckIncludeFileCXX)
 include(CheckLibraryExists)
+include(CheckStructHasMember)
 include(FindPythonInterp)
 include(FindPkgConfig)
 include(CheckSymbolExists)
@@ -76,6 +79,7 @@
 include(${ORTHANC_ROOT}/Resources/CMake/LibIconvConfiguration.cmake)
 include(${ORTHANC_ROOT}/Resources/CMake/LibJpegConfiguration.cmake)
 include(${ORTHANC_ROOT}/Resources/CMake/LibPngConfiguration.cmake)
+include(${ORTHANC_ROOT}/Resources/CMake/UuidConfiguration.cmake)
 include(${ORTHANC_ROOT}/Resources/CMake/ZlibConfiguration.cmake)
 
 # Include components specific to WSI
@@ -85,11 +89,15 @@
 include(${ORTHANC_WSI_DIR}/Resources/CMake/LibTiffConfiguration.cmake)
 
 add_definitions(
+  -DHAS_ORTHANC_EXCEPTION=1
   -DORTHANC_BUILD_UNIT_TESTS=0  # For FromDcmtkBridge
+  -DORTHANC_DEFAULT_DICOM_ENCODING=Encoding_Latin1
   -DORTHANC_ENABLE_BASE64=1
   -DORTHANC_ENABLE_CURL=1
   -DORTHANC_ENABLE_DCMTK=1
-  -DORTHANC_ENABLE_JPEG=0       # Disable DCMTK's support for JPEG
+  -DORTHANC_ENABLE_DCMTK_JPEG=0           # Disable DCMTK's support for JPEG
+  -DORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS=0  # Disable DCMTK's support for JPEG-LS
+  -DORTHANC_ENABLE_JPEG=1
   -DORTHANC_ENABLE_LOCALE=1
   -DORTHANC_ENABLE_LOGGING=1
   -DORTHANC_ENABLE_LOGGING_PLUGIN=0
@@ -97,9 +105,10 @@
   -DORTHANC_ENABLE_MD5=0
   -DORTHANC_ENABLE_PKCS11=0
   -DORTHANC_ENABLE_PLUGINS=1    # To enable class Orthanc::SharedLibrary
+  -DORTHANC_ENABLE_PNG=1
   -DORTHANC_ENABLE_PUGIXML=0
+  -DORTHANC_MAXIMUM_TAG_LENGTH=256
   -DORTHANC_SANDBOXED=0
-  -DHAS_ORTHANC_EXCEPTION=1
   )
 
 
@@ -172,6 +181,8 @@
   ${ORTHANC_ROOT}/Core/DicomFormat/DicomMap.cpp
   ${ORTHANC_ROOT}/Core/DicomFormat/DicomTag.cpp
   ${ORTHANC_ROOT}/Core/DicomFormat/DicomValue.cpp
+  ${ORTHANC_ROOT}/Core/DicomParsing/FromDcmtkBridge.cpp
+  ${ORTHANC_ROOT}/Core/DicomParsing/ToDcmtkBridge.cpp
   ${ORTHANC_ROOT}/Core/Enumerations.cpp
   ${ORTHANC_ROOT}/Core/HttpClient.cpp
   ${ORTHANC_ROOT}/Core/Images/IImageWriter.cpp
@@ -191,9 +202,6 @@
   ${ORTHANC_ROOT}/Core/TemporaryFile.cpp
   ${ORTHANC_ROOT}/Core/Toolbox.cpp
   ${ORTHANC_ROOT}/Core/WebServiceParameters.cpp
-  ${ORTHANC_ROOT}/OrthancServer/FromDcmtkBridge.cpp
-  ${ORTHANC_ROOT}/OrthancServer/ServerEnumerations.cpp
-  ${ORTHANC_ROOT}/OrthancServer/ToDcmtkBridge.cpp
 
   ${ORTHANC_ROOT}/Plugins/Engine/SharedLibrary.cpp
   ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
@@ -253,6 +261,7 @@
   ${LIBPNG_SOURCES}
   ${LIBTIFF_SOURCES}
   ${OPENJPEG_SOURCES}
+  ${UUID_SOURCES}
   ${ZLIB_SOURCES}
 
   # Optional components
--- a/Applications/Dicomizer.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Applications/Dicomizer.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -36,7 +36,7 @@
 #include "../Resources/Orthanc/Core/Logging.h"
 #include "../Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h"
 #include "../Resources/Orthanc/Core/SystemToolbox.h"
-#include "../Resources/Orthanc/OrthancServer/FromDcmtkBridge.h"
+#include "../Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.h"
 
 #include "ApplicationToolbox.h"
 
--- a/Framework/Outputs/DicomPyramidWriter.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Framework/Outputs/DicomPyramidWriter.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -26,7 +26,7 @@
 
 #include "../../Resources/Orthanc/Core/Logging.h"
 #include "../../Resources/Orthanc/Core/OrthancException.h"
-#include "../../Resources/Orthanc/OrthancServer/FromDcmtkBridge.h"
+#include "../../Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.h"
 
 #include <dcmtk/dcmdata/dcdeftag.h>
 #include <boost/lexical_cast.hpp>
--- a/Resources/Orthanc/Core/Cache/LeastRecentlyUsedIndex.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Cache/LeastRecentlyUsedIndex.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/ChunkedBuffer.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/ChunkedBuffer.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/ChunkedBuffer.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/ChunkedBuffer.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/DicomFormat/DicomArray.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/DicomFormat/DicomArray.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/DicomFormat/DicomArray.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/DicomFormat/DicomArray.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/DicomFormat/DicomElement.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/DicomFormat/DicomElement.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/DicomFormat/DicomMap.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/DicomFormat/DicomMap.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -36,7 +36,9 @@
 
 #include <stdio.h>
 #include <memory>
+
 #include "../Endianness.h"
+#include "../Logging.h"
 #include "../OrthancException.h"
 
 
@@ -781,4 +783,193 @@
 
     return true;
   }
+
+
+  static std::string ValueAsString(const DicomMap& summary,
+                                   const DicomTag& tag)
+  {
+    const DicomValue& value = summary.GetValue(tag);
+    if (value.IsNull())
+    {
+      return "(null)";
+    }
+    else
+    {
+      return value.GetContent();
+    }
+  }
+
+
+  void DicomMap::LogMissingTagsForStore() const
+  {
+    std::string s, t;
+
+    if (HasTag(DICOM_TAG_PATIENT_ID))
+    {
+      if (t.size() > 0)
+        t += ", ";
+      t += "PatientID=" + ValueAsString(*this, DICOM_TAG_PATIENT_ID);
+    }
+    else
+    {
+      if (s.size() > 0)
+        s += ", ";
+      s += "PatientID";
+    }
+
+    if (HasTag(DICOM_TAG_STUDY_INSTANCE_UID))
+    {
+      if (t.size() > 0)
+        t += ", ";
+      t += "StudyInstanceUID=" + ValueAsString(*this, DICOM_TAG_STUDY_INSTANCE_UID);
+    }
+    else
+    {
+      if (s.size() > 0)
+        s += ", ";
+      s += "StudyInstanceUID";
+    }
+
+    if (HasTag(DICOM_TAG_SERIES_INSTANCE_UID))
+    {
+      if (t.size() > 0)
+        t += ", ";
+      t += "SeriesInstanceUID=" + ValueAsString(*this, DICOM_TAG_SERIES_INSTANCE_UID);
+    }
+    else
+    {
+      if (s.size() > 0)
+        s += ", ";
+      s += "SeriesInstanceUID";
+    }
+
+    if (HasTag(DICOM_TAG_SOP_INSTANCE_UID))
+    {
+      if (t.size() > 0)
+        t += ", ";
+      t += "SOPInstanceUID=" + ValueAsString(*this, DICOM_TAG_SOP_INSTANCE_UID);
+    }
+    else
+    {
+      if (s.size() > 0)
+        s += ", ";
+      s += "SOPInstanceUID";
+    }
+
+    if (t.size() == 0)
+    {
+      LOG(ERROR) << "Store has failed because all the required tags (" << s << ") are missing (is it a DICOMDIR file?)";
+    }
+    else
+    {
+      LOG(ERROR) << "Store has failed because required tags (" << s << ") are missing for the following instance: " << t;
+    }
+  }
+
+
+  bool DicomMap::CopyToString(std::string& result,
+                              const DicomTag& tag,
+                              bool allowBinary) const
+  {
+    const DicomValue* value = TestAndGetValue(tag);
+
+    if (value == NULL)
+    {
+      return false;
+    }
+    else
+    {
+      return value->CopyToString(result, allowBinary);
+    }
+  }
+    
+  bool DicomMap::ParseInteger32(int32_t& result,
+                                const DicomTag& tag) const
+  {
+    const DicomValue* value = TestAndGetValue(tag);
+
+    if (value == NULL)
+    {
+      return false;
+    }
+    else
+    {
+      return value->ParseInteger32(result);
+    }
+  }
+
+  bool DicomMap::ParseInteger64(int64_t& result,
+                                const DicomTag& tag) const
+  {
+    const DicomValue* value = TestAndGetValue(tag);
+
+    if (value == NULL)
+    {
+      return false;
+    }
+    else
+    {
+      return value->ParseInteger64(result);
+    }
+  }
+
+  bool DicomMap::ParseUnsignedInteger32(uint32_t& result,
+                                        const DicomTag& tag) const
+  {
+    const DicomValue* value = TestAndGetValue(tag);
+
+    if (value == NULL)
+    {
+      return false;
+    }
+    else
+    {
+      return value->ParseUnsignedInteger32(result);
+    }
+  }
+
+  bool DicomMap::ParseUnsignedInteger64(uint64_t& result,
+                                        const DicomTag& tag) const
+  {
+    const DicomValue* value = TestAndGetValue(tag);
+
+    if (value == NULL)
+    {
+      return false;
+    }
+    else
+    {
+      return value->ParseUnsignedInteger64(result);
+    }
+  }
+
+  bool DicomMap::ParseFloat(float& result,
+                            const DicomTag& tag) const
+  {
+    const DicomValue* value = TestAndGetValue(tag);
+
+    if (value == NULL)
+    {
+      return false;
+    }
+    else
+    {
+      return value->ParseFloat(result);
+    }
+  }
+
+  bool DicomMap::ParseDouble(double& result,
+                             const DicomTag& tag) const
+  {
+    const DicomValue* value = TestAndGetValue(tag);
+
+    if (value == NULL)
+    {
+      return false;
+    }
+    else
+    {
+      return value->ParseDouble(result);
+    }
+  }
 }
--- a/Resources/Orthanc/Core/DicomFormat/DicomMap.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/DicomFormat/DicomMap.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -181,5 +181,29 @@
     static bool ParseDicomMetaInformation(DicomMap& result,
                                           const char* dicom,
                                           size_t size);
+
+    void LogMissingTagsForStore() const;
+
+    bool CopyToString(std::string& result,
+                      const DicomTag& tag,
+                      bool allowBinary) const;
+    
+    bool ParseInteger32(int32_t& result,
+                        const DicomTag& tag) const;
+
+    bool ParseInteger64(int64_t& result,
+                        const DicomTag& tag) const;                                
+
+    bool ParseUnsignedInteger32(uint32_t& result,
+                                const DicomTag& tag) const;
+
+    bool ParseUnsignedInteger64(uint64_t& result,
+                                const DicomTag& tag) const;                                
+
+    bool ParseFloat(float& result,
+                    const DicomTag& tag) const;                                
+
+    bool ParseDouble(double& result,
+                     const DicomTag& tag) const;                                
   };
 }
--- a/Resources/Orthanc/Core/DicomFormat/DicomTag.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/DicomFormat/DicomTag.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/DicomFormat/DicomTag.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/DicomFormat/DicomTag.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -173,6 +173,17 @@
   static const DicomTag DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION(0x0018, 0x1400);
   static const DicomTag DICOM_TAG_CONTRAST_BOLUS_AGENT(0x0018, 0x0010);
 
+  // Tags used within the Stone of Orthanc
+  static const DicomTag DICOM_TAG_FRAME_INCREMENT_POINTER(0x0028, 0x0009);
+  static const DicomTag DICOM_TAG_GRID_FRAME_OFFSET_VECTOR(0x3004, 0x000c);
+  static const DicomTag DICOM_TAG_PIXEL_SPACING(0x0028, 0x0030);
+  static const DicomTag DICOM_TAG_RESCALE_INTERCEPT(0x0028, 0x1052);
+  static const DicomTag DICOM_TAG_RESCALE_SLOPE(0x0028, 0x1053);
+  static const DicomTag DICOM_TAG_SLICE_THICKNESS(0x0018, 0x0050);
+  static const DicomTag DICOM_TAG_WINDOW_CENTER(0x0028, 0x1050);
+  static const DicomTag DICOM_TAG_WINDOW_WIDTH(0x0028, 0x1051);
+  static const DicomTag DICOM_TAG_DOSE_GRID_SCALING(0x3004, 0x000e);
+                                    
   // Counting patients, studies and series
   // https://www.medicalconnections.co.uk/kb/Counting_Studies_Series_and_Instances
   static const DicomTag DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES(0x0020, 0x1200);  
--- a/Resources/Orthanc/Core/DicomFormat/DicomValue.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/DicomFormat/DicomValue.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -37,6 +37,8 @@
 #include "../OrthancException.h"
 #include "../Toolbox.h"
 
+#include <boost/lexical_cast.hpp>
+
 namespace Orthanc
 {
   DicomValue::DicomValue(const DicomValue& other) : 
@@ -91,4 +93,104 @@
   }
 #endif
 
+
+  template <typename T,
+            bool allowSigned>
+  static bool ParseValue(T& result,
+                         const DicomValue& source)
+  {
+    if (source.IsBinary() ||
+        source.IsNull())
+    {
+      return false;
+    }
+    
+    try
+    {
+      std::string value = Toolbox::StripSpaces(source.GetContent());
+      if (value.empty())
+      {
+        return false;
+      }
+
+      if (!allowSigned &&
+          value[0] == '-')
+      {
+        return false;
+      }
+      
+      result = boost::lexical_cast<T>(value);
+      return true;
+    }
+    catch (boost::bad_lexical_cast&)
+    {
+      return false;
+    }
+  }
+
+  bool DicomValue::ParseInteger32(int32_t& result) const
+  {
+    int64_t tmp;
+    if (ParseValue<int64_t, true>(tmp, *this))
+    {
+      result = static_cast<int32_t>(tmp);
+      return (tmp == static_cast<int64_t>(result));  // Check no overflow occurs
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+  bool DicomValue::ParseInteger64(int64_t& result) const
+  {
+    return ParseValue<int64_t, true>(result, *this);
+  }
+
+  bool DicomValue::ParseUnsignedInteger32(uint32_t& result) const
+  {
+    uint64_t tmp;
+    if (ParseValue<uint64_t, false>(tmp, *this))
+    {
+      result = static_cast<uint32_t>(tmp);
+      return (tmp == static_cast<uint64_t>(result));  // Check no overflow occurs
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+  bool DicomValue::ParseUnsignedInteger64(uint64_t& result) const
+  {
+    return ParseValue<uint64_t, false>(result, *this);
+  }
+
+  bool DicomValue::ParseFloat(float& result) const
+  {
+    return ParseValue<float, true>(result, *this);
+  }
+
+  bool DicomValue::ParseDouble(double& result) const
+  {
+    return ParseValue<double, true>(result, *this);
+  }
+
+  bool DicomValue::CopyToString(std::string& result,
+                                bool allowBinary) const
+  {
+    if (IsNull())
+    {
+      return false;
+    }
+    else if (IsBinary() && !allowBinary)
+    {
+      return false;
+    }
+    else
+    {
+      result.assign(content_);
+      return true;
+    }
+  }    
 }
--- a/Resources/Orthanc/Core/DicomFormat/DicomValue.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/DicomFormat/DicomValue.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -33,6 +33,7 @@
 
 #pragma once
 
+#include <stdint.h>
 #include <string>
 #include <boost/noncopyable.hpp>
 
@@ -93,5 +94,20 @@
       FormatDataUriScheme(target, "application/octet-stream");
     }
 #endif
+
+    bool CopyToString(std::string& result,
+                      bool allowBinary) const;
+    
+    bool ParseInteger32(int32_t& result) const;
+
+    bool ParseInteger64(int64_t& result) const;                                
+
+    bool ParseUnsignedInteger32(uint32_t& result) const;
+
+    bool ParseUnsignedInteger64(uint64_t& result) const;                                
+
+    bool ParseFloat(float& result) const;                                
+
+    bool ParseDouble(double& result) const;                                
   };
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -0,0 +1,2098 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#include "FromDcmtkBridge.h"
+#include "ToDcmtkBridge.h"
+#include "../Logging.h"
+#include "../SystemToolbox.h"
+#include "../Toolbox.h"
+#include "../TemporaryFile.h"
+#include "../OrthancException.h"
+
+#include <list>
+#include <limits>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+
+#include <dcmtk/dcmdata/dcdeftag.h>
+#include <dcmtk/dcmdata/dcdicent.h>
+#include <dcmtk/dcmdata/dcdict.h>
+#include <dcmtk/dcmdata/dcfilefo.h>
+#include <dcmtk/dcmdata/dcostrmb.h>
+#include <dcmtk/dcmdata/dcpixel.h>
+#include <dcmtk/dcmdata/dcuid.h>
+#include <dcmtk/dcmdata/dcistrmb.h>
+
+#include <dcmtk/dcmdata/dcvrae.h>
+#include <dcmtk/dcmdata/dcvras.h>
+#include <dcmtk/dcmdata/dcvrat.h>
+#include <dcmtk/dcmdata/dcvrcs.h>
+#include <dcmtk/dcmdata/dcvrda.h>
+#include <dcmtk/dcmdata/dcvrds.h>
+#include <dcmtk/dcmdata/dcvrdt.h>
+#include <dcmtk/dcmdata/dcvrfd.h>
+#include <dcmtk/dcmdata/dcvrfl.h>
+#include <dcmtk/dcmdata/dcvris.h>
+#include <dcmtk/dcmdata/dcvrlo.h>
+#include <dcmtk/dcmdata/dcvrlt.h>
+#include <dcmtk/dcmdata/dcvrpn.h>
+#include <dcmtk/dcmdata/dcvrsh.h>
+#include <dcmtk/dcmdata/dcvrsl.h>
+#include <dcmtk/dcmdata/dcvrss.h>
+#include <dcmtk/dcmdata/dcvrst.h>
+#include <dcmtk/dcmdata/dcvrtm.h>
+#include <dcmtk/dcmdata/dcvrui.h>
+#include <dcmtk/dcmdata/dcvrul.h>
+#include <dcmtk/dcmdata/dcvrus.h>
+#include <dcmtk/dcmdata/dcvrut.h>
+
+#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1
+#  include <EmbeddedResources.h>
+#endif
+
+#if ORTHANC_ENABLE_DCMTK_JPEG == 1
+#  include <dcmtk/dcmjpeg/djdecode.h>
+#endif
+
+#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1
+#  include <dcmtk/dcmjpls/djdecode.h>
+#endif
+
+
+namespace Orthanc
+{
+  static inline uint16_t GetCharValue(char c)
+  {
+    if (c >= '0' && c <= '9')
+      return c - '0';
+    else if (c >= 'a' && c <= 'f')
+      return c - 'a' + 10;
+    else if (c >= 'A' && c <= 'F')
+      return c - 'A' + 10;
+    else
+      return 0;
+  }
+
+  static inline uint16_t GetTagValue(const char* c)
+  {
+    return ((GetCharValue(c[0]) << 12) + 
+            (GetCharValue(c[1]) << 8) + 
+            (GetCharValue(c[2]) << 4) + 
+            GetCharValue(c[3]));
+  }
+
+
+#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1
+  static void LoadEmbeddedDictionary(DcmDataDictionary& dictionary,
+                                     EmbeddedResources::FileResourceId resource)
+  {
+    std::string content;
+    EmbeddedResources::GetFileResource(content, resource);
+
+    TemporaryFile tmp;
+    tmp.Write(content);
+
+    if (!dictionary.loadDictionary(tmp.GetPath().c_str()))
+    {
+      LOG(ERROR) << "Cannot read embedded dictionary. Under Windows, make sure that " 
+                 << "your TEMP directory does not contain special characters.";
+      throw OrthancException(ErrorCode_InternalError);
+    }
+  }
+                             
+#else
+  static void LoadExternalDictionary(DcmDataDictionary& dictionary,
+                                     const std::string& directory,
+                                     const std::string& filename)
+  {
+    boost::filesystem::path p = directory;
+    p = p / filename;
+
+    LOG(WARNING) << "Loading the external DICOM dictionary " << p;
+
+    if (!dictionary.loadDictionary(p.string().c_str()))
+    {
+      throw OrthancException(ErrorCode_InternalError);
+    }
+  }
+#endif
+
+
+  namespace
+  {
+    class DictionaryLocker
+    {
+    private:
+      DcmDataDictionary& dictionary_;
+
+    public:
+      DictionaryLocker() : dictionary_(dcmDataDict.wrlock())
+      {
+      }
+
+      ~DictionaryLocker()
+      {
+        dcmDataDict.unlock();
+      }
+
+      DcmDataDictionary& operator*()
+      {
+        return dictionary_;
+      }
+
+      DcmDataDictionary* operator->()
+      {
+        return &dictionary_;
+      }
+    };
+  }
+
+
+  void FromDcmtkBridge::InitializeDictionary(bool loadPrivateDictionary)
+  {
+    LOG(INFO) << "Using DCTMK version: " << DCMTK_VERSION_NUMBER;
+    
+    {
+      DictionaryLocker locker;
+
+      locker->clear();
+
+#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1
+      LOG(WARNING) << "Loading the embedded dictionaries";
+      /**
+       * Do not load DICONDE dictionary, it breaks the other tags. The
+       * command "strace storescu 2>&1 |grep dic" shows that DICONDE
+       * dictionary is not loaded by storescu.
+       **/
+      //LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICONDE);
+
+      LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICOM);
+
+      if (loadPrivateDictionary)
+      {
+        LOG(INFO) << "Loading the embedded dictionary of private tags";
+        LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_PRIVATE);
+      }
+      else
+      {
+        LOG(INFO) << "The dictionary of private tags has not been loaded";
+      }
+
+#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+      std::string path = DCMTK_DICTIONARY_DIR;
+
+      const char* env = std::getenv(DCM_DICT_ENVIRONMENT_VARIABLE);
+      if (env != NULL)
+      {
+        path = std::string(env);
+      }
+
+      LoadExternalDictionary(*locker, path, "dicom.dic");
+
+      if (loadPrivateDictionary)
+      {
+        LoadExternalDictionary(*locker, path, "private.dic");
+      }
+      else
+      {
+        LOG(INFO) << "The dictionary of private tags has not been loaded";
+      }
+
+#else
+#error Support your platform here
+#endif
+    }
+
+    /* make sure data dictionary is loaded */
+    if (!dcmDataDict.isDictionaryLoaded())
+    {
+      LOG(ERROR) << "No DICOM dictionary loaded, check environment variable: " << DCM_DICT_ENVIRONMENT_VARIABLE;
+      throw OrthancException(ErrorCode_InternalError);
+    }
+
+    {
+      // Test the dictionary with a simple DICOM tag
+      DcmTag key(0x0010, 0x1030); // This is PatientWeight
+      if (key.getEVR() != EVR_DS)
+      {
+        LOG(ERROR) << "The DICOM dictionary has not been correctly read";
+        throw OrthancException(ErrorCode_InternalError);
+      }
+    }
+  }
+
+
+  void FromDcmtkBridge::RegisterDictionaryTag(const DicomTag& tag,
+                                              ValueRepresentation vr,
+                                              const std::string& name,
+                                              unsigned int minMultiplicity,
+                                              unsigned int maxMultiplicity,
+                                              const std::string& privateCreator)
+  {
+    if (minMultiplicity < 1)
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+
+    bool arbitrary = false;
+    if (maxMultiplicity == 0)
+    {
+      maxMultiplicity = DcmVariableVM;
+      arbitrary = true;
+    }
+    else if (maxMultiplicity < minMultiplicity)
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+    
+    DcmEVR evr = ToDcmtkBridge::Convert(vr);
+
+    LOG(INFO) << "Registering tag in dictionary: " << tag << " " << (DcmVR(evr).getValidVRName()) << " " 
+              << name << " (multiplicity: " << minMultiplicity << "-" 
+              << (arbitrary ? "n" : boost::lexical_cast<std::string>(maxMultiplicity)) << ")";
+
+    std::auto_ptr<DcmDictEntry>  entry;
+    if (privateCreator.empty())
+    {
+      if (tag.GetGroup() % 2 == 1)
+      {
+        char buf[128];
+        sprintf(buf, "Warning: You are registering a private tag (%04x,%04x), "
+                "but no private creator was associated with it", 
+                tag.GetGroup(), tag.GetElement());
+        LOG(WARNING) << buf;
+      }
+
+      entry.reset(new DcmDictEntry(tag.GetGroup(),
+                                   tag.GetElement(),
+                                   evr, name.c_str(),
+                                   static_cast<int>(minMultiplicity),
+                                   static_cast<int>(maxMultiplicity),
+                                   NULL    /* version */,
+                                   OFTrue  /* doCopyString */,
+                                   NULL    /* private creator */));
+    }
+    else
+    {
+      // "Private Data Elements have an odd Group Number that is not
+      // (0001,eeee), (0003,eeee), (0005,eeee), (0007,eeee), or
+      // (FFFF,eeee)."
+      if (tag.GetGroup() % 2 == 0 /* even */ ||
+          tag.GetGroup() == 0x0001 ||
+          tag.GetGroup() == 0x0003 ||
+          tag.GetGroup() == 0x0005 ||
+          tag.GetGroup() == 0x0007 ||
+          tag.GetGroup() == 0xffff)
+      {
+        char buf[128];
+        sprintf(buf, "Trying to register private tag (%04x,%04x), but it must have an odd group >= 0x0009",
+                tag.GetGroup(), tag.GetElement());
+        LOG(ERROR) << buf;
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+
+      entry.reset(new DcmDictEntry(tag.GetGroup(),
+                                   tag.GetElement(),
+                                   evr, name.c_str(),
+                                   static_cast<int>(minMultiplicity),
+                                   static_cast<int>(maxMultiplicity),
+                                   "private" /* version */,
+                                   OFTrue    /* doCopyString */,
+                                   privateCreator.c_str()));
+    }
+
+    entry->setGroupRangeRestriction(DcmDictRange_Unspecified);
+    entry->setElementRangeRestriction(DcmDictRange_Unspecified);
+
+    {
+      DictionaryLocker locker;
+
+      if (locker->findEntry(name.c_str()))
+      {
+        LOG(ERROR) << "Cannot register two tags with the same symbolic name \"" << name << "\"";
+        throw OrthancException(ErrorCode_AlreadyExistingTag);
+      }
+
+      locker->addEntry(entry.release());
+    }
+  }
+
+
+  Encoding FromDcmtkBridge::DetectEncoding(DcmItem& dataset,
+                                           Encoding defaultEncoding)
+  {
+    Encoding encoding = defaultEncoding;
+
+    OFString tmp;
+    if (dataset.findAndGetOFString(DCM_SpecificCharacterSet, tmp).good())
+    {
+      std::string characterSet = Toolbox::StripSpaces(std::string(tmp.c_str()));
+
+      if (characterSet.empty())
+      {
+        // Empty specific character set tag: Use the default encoding
+      }
+      else if (GetDicomEncoding(encoding, characterSet.c_str()))
+      {
+        // The specific character set is supported by the Orthanc core
+      }
+      else
+      {
+        LOG(WARNING) << "Value of Specific Character Set (0008,0005) is not supported: " << characterSet
+                     << ", fallback to ASCII (remove all special characters)";
+        encoding = Encoding_Ascii;
+      }
+    }
+    else
+    {
+      // No specific character set tag: Use the default encoding
+    }
+
+    return encoding;
+  }
+
+
+  void FromDcmtkBridge::ExtractDicomSummary(DicomMap& target, 
+                                            DcmItem& dataset,
+                                            unsigned int maxStringLength,
+                                            Encoding defaultEncoding)
+  {
+    std::set<DicomTag> ignoreTagLength;
+    
+    Encoding encoding = DetectEncoding(dataset, defaultEncoding);
+
+    target.Clear();
+    for (unsigned long i = 0; i < dataset.card(); i++)
+    {
+      DcmElement* element = dataset.getElement(i);
+      if (element && element->isLeaf())
+      {
+        target.SetValue(element->getTag().getGTag(),
+                        element->getTag().getETag(),
+                        ConvertLeafElement(*element, DicomToJsonFlags_Default,
+                                           maxStringLength, encoding, ignoreTagLength));
+      }
+    }
+  }
+
+
+  DicomTag FromDcmtkBridge::Convert(const DcmTag& tag)
+  {
+    return DicomTag(tag.getGTag(), tag.getETag());
+  }
+
+
+  DicomTag FromDcmtkBridge::GetTag(const DcmElement& element)
+  {
+    return DicomTag(element.getGTag(), element.getETag());
+  }
+
+
+  DicomValue* FromDcmtkBridge::ConvertLeafElement(DcmElement& element,
+                                                  DicomToJsonFlags flags,
+                                                  unsigned int maxStringLength,
+                                                  Encoding encoding,
+                                                  const std::set<DicomTag>& ignoreTagLength)
+  {
+    if (!element.isLeaf())
+    {
+      // This function is only applicable to leaf elements
+      throw OrthancException(ErrorCode_BadParameterType);
+    }
+
+    char *c = NULL;
+    if (element.isaString() &&
+        element.getString(c).good())
+    {
+      if (c == NULL)  // This case corresponds to the empty string
+      {
+        return new DicomValue("", false);
+      }
+      else
+      {
+        std::string s(c);
+        std::string utf8 = Toolbox::ConvertToUtf8(s, encoding);
+
+        if (maxStringLength != 0 &&
+            utf8.size() > maxStringLength &&
+            ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end())
+        {
+          return new DicomValue;  // Too long, create a NULL value
+        }
+        else
+        {
+          return new DicomValue(utf8, false);
+        }
+      }
+    }
+
+
+    if (element.getVR() == EVR_UN)
+    {
+      // Unknown value representation: Lookup in the dictionary. This
+      // is notably the case for private tags registered with the
+      // "Dictionary" configuration option.
+      DictionaryLocker locker;
+      
+      const DcmDictEntry* entry = locker->findEntry(element.getTag().getXTag(), 
+                                                    element.getTag().getPrivateCreator());
+      if (entry != NULL && 
+          entry->getVR().isaString())
+      {
+        Uint8* data = NULL;
+
+        // At (*), we do not try and convert to UTF-8, as nothing says
+        // the encoding of the private tag is the same as that of the
+        // remaining of the DICOM dataset. Only go for ASCII strings.
+
+        if (element.getUint8Array(data) == EC_Normal &&
+            Toolbox::IsAsciiString(data, element.getLength()))   // (*)
+        {
+          if (data == NULL)
+          {
+            return new DicomValue("", false);   // Empty string
+          }
+          else if (maxStringLength != 0 &&
+                   element.getLength() > maxStringLength &&
+                   ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end())
+          {
+            return new DicomValue;  // Too long, create a NULL value
+          }
+          else
+          {
+            std::string s(reinterpret_cast<const char*>(data), element.getLength());
+            return new DicomValue(s, false);
+          }
+        }
+      }
+    }
+
+    
+    try
+    {
+      // http://support.dcmtk.org/docs/dcvr_8h-source.html
+      switch (element.getVR())
+      {
+
+        /**
+         * Deal with binary data (including PixelData).
+         **/
+
+        case EVR_OB:  // other byte
+        case EVR_OF:  // other float
+        case EVR_OW:  // other word
+        case EVR_UN:  // unknown value representation
+        case EVR_ox:  // OB or OW depending on context
+        case EVR_DS:  // decimal string
+        case EVR_IS:  // integer string
+        case EVR_AS:  // age string
+        case EVR_DA:  // date string
+        case EVR_DT:  // date time string
+        case EVR_TM:  // time string
+        case EVR_AE:  // application entity title
+        case EVR_CS:  // code string
+        case EVR_SH:  // short string
+        case EVR_LO:  // long string
+        case EVR_ST:  // short text
+        case EVR_LT:  // long text
+        case EVR_UT:  // unlimited text
+        case EVR_PN:  // person name
+        case EVR_UI:  // unique identifier
+        case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR)
+        case EVR_UNKNOWN2B:  // used internally for elements with unknown VR with 2-byte length field in explicit VR
+        {
+          if (!(flags & DicomToJsonFlags_ConvertBinaryToNull))
+          {
+            Uint8* data = NULL;
+            if (element.getUint8Array(data) == EC_Normal)
+            {
+              return new DicomValue(reinterpret_cast<const char*>(data), element.getLength(), true);
+            }
+          }
+
+          return new DicomValue;
+        }
+    
+        /**
+         * Numeric types
+         **/ 
+      
+        case EVR_SL:  // signed long
+        {
+          Sint32 f;
+          if (dynamic_cast<DcmSignedLong&>(element).getSint32(f).good())
+            return new DicomValue(boost::lexical_cast<std::string>(f), false);
+          else
+            return new DicomValue;
+        }
+
+        case EVR_SS:  // signed short
+        {
+          Sint16 f;
+          if (dynamic_cast<DcmSignedShort&>(element).getSint16(f).good())
+            return new DicomValue(boost::lexical_cast<std::string>(f), false);
+          else
+            return new DicomValue;
+        }
+
+        case EVR_UL:  // unsigned long
+        {
+          Uint32 f;
+          if (dynamic_cast<DcmUnsignedLong&>(element).getUint32(f).good())
+            return new DicomValue(boost::lexical_cast<std::string>(f), false);
+          else
+            return new DicomValue;
+        }
+
+        case EVR_US:  // unsigned short
+        {
+          Uint16 f;
+          if (dynamic_cast<DcmUnsignedShort&>(element).getUint16(f).good())
+            return new DicomValue(boost::lexical_cast<std::string>(f), false);
+          else
+            return new DicomValue;
+        }
+
+        case EVR_FL:  // float single-precision
+        {
+          Float32 f;
+          if (dynamic_cast<DcmFloatingPointSingle&>(element).getFloat32(f).good())
+            return new DicomValue(boost::lexical_cast<std::string>(f), false);
+          else
+            return new DicomValue;
+        }
+
+        case EVR_FD:  // float double-precision
+        {
+          Float64 f;
+          if (dynamic_cast<DcmFloatingPointDouble&>(element).getFloat64(f).good())
+            return new DicomValue(boost::lexical_cast<std::string>(f), false);
+          else
+            return new DicomValue;
+        }
+
+
+        /**
+         * Attribute tag.
+         **/
+
+        case EVR_AT:
+        {
+          DcmTagKey tag;
+          if (dynamic_cast<DcmAttributeTag&>(element).getTagVal(tag, 0).good())
+          {
+            DicomTag t(tag.getGroup(), tag.getElement());
+            return new DicomValue(t.Format(), false);
+          }
+          else
+          {
+            return new DicomValue;
+          }
+        }
+
+
+        /**
+         * Sequence types, should never occur at this point because of
+         * "element.isLeaf()".
+         **/
+
+        case EVR_SQ:  // sequence of items
+          return new DicomValue;
+
+
+          /**
+           * Internal to DCMTK.
+           **/ 
+
+        case EVR_xs:  // SS or US depending on context
+        case EVR_lt:  // US, SS or OW depending on context, used for LUT Data (thus the name)
+        case EVR_na:  // na="not applicable", for data which has no VR
+        case EVR_up:  // up="unsigned pointer", used internally for DICOMDIR suppor
+        case EVR_item:  // used internally for items
+        case EVR_metainfo:  // used internally for meta info datasets
+        case EVR_dataset:  // used internally for datasets
+        case EVR_fileFormat:  // used internally for DICOM files
+        case EVR_dicomDir:  // used internally for DICOMDIR objects
+        case EVR_dirRecord:  // used internally for DICOMDIR records
+        case EVR_pixelSQ:  // used internally for pixel sequences in a compressed image
+        case EVR_pixelItem:  // used internally for pixel items in a compressed image
+        case EVR_PixelData:  // used internally for uncompressed pixeld data
+        case EVR_OverlayData:  // used internally for overlay data
+          return new DicomValue;
+
+
+          /**
+           * Default case.
+           **/ 
+
+        default:
+          return new DicomValue;
+      }
+    }
+    catch (boost::bad_lexical_cast)
+    {
+      return new DicomValue;
+    }
+    catch (std::bad_cast)
+    {
+      return new DicomValue;
+    }
+  }
+
+
+  static Json::Value& PrepareNode(Json::Value& parent,
+                                  DcmElement& element,
+                                  DicomToJsonFormat format)
+  {
+    assert(parent.type() == Json::objectValue);
+
+    DicomTag tag(FromDcmtkBridge::GetTag(element));
+    const std::string formattedTag = tag.Format();
+
+    if (format == DicomToJsonFormat_Short)
+    {
+      parent[formattedTag] = Json::nullValue;
+      return parent[formattedTag];
+    }
+
+    // This code gives access to the name of the private tags
+    std::string tagName = FromDcmtkBridge::GetTagName(element);
+    
+    switch (format)
+    {
+      case DicomToJsonFormat_Human:
+        parent[tagName] = Json::nullValue;
+        return parent[tagName];
+
+      case DicomToJsonFormat_Full:
+      {
+        parent[formattedTag] = Json::objectValue;
+        Json::Value& node = parent[formattedTag];
+
+        if (element.isLeaf())
+        {
+          node["Name"] = tagName;
+
+          if (element.getTag().getPrivateCreator() != NULL)
+          {
+            node["PrivateCreator"] = element.getTag().getPrivateCreator();
+          }
+
+          return node;
+        }
+        else
+        {
+          node["Name"] = tagName;
+          node["Type"] = "Sequence";
+          node["Value"] = Json::nullValue;
+          return node["Value"];
+        }
+      }
+
+      default:
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
+  static void LeafValueToJson(Json::Value& target,
+                              const DicomValue& value,
+                              DicomToJsonFormat format,
+                              DicomToJsonFlags flags,
+                              unsigned int maxStringLength)
+  {
+    Json::Value* targetValue = NULL;
+    Json::Value* targetType = NULL;
+
+    switch (format)
+    {
+      case DicomToJsonFormat_Short:
+      case DicomToJsonFormat_Human:
+      {
+        assert(target.type() == Json::nullValue);
+        targetValue = &target;
+        break;
+      }      
+
+      case DicomToJsonFormat_Full:
+      {
+        assert(target.type() == Json::objectValue);
+        target["Value"] = Json::nullValue;
+        target["Type"] = Json::nullValue;
+        targetType = &target["Type"];
+        targetValue = &target["Value"];
+        break;
+      }
+
+      default:
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+
+    assert(targetValue != NULL);
+    assert(targetValue->type() == Json::nullValue);
+    assert(targetType == NULL || targetType->type() == Json::nullValue);
+
+    if (value.IsNull())
+    {
+      if (targetType != NULL)
+      {
+        *targetType = "Null";
+      }
+    }
+    else if (value.IsBinary())
+    {
+      if (flags & DicomToJsonFlags_ConvertBinaryToAscii)
+      {
+        *targetValue = Toolbox::ConvertToAscii(value.GetContent());
+      }
+      else
+      {
+        std::string s;
+        value.FormatDataUriScheme(s);
+        *targetValue = s;
+      }
+
+      if (targetType != NULL)
+      {
+        *targetType = "Binary";
+      }
+    }
+    else if (maxStringLength == 0 ||
+             value.GetContent().size() <= maxStringLength)
+    {
+      *targetValue = value.GetContent();
+
+      if (targetType != NULL)
+      {
+        *targetType = "String";
+      }
+    }
+    else
+    {
+      if (targetType != NULL)
+      {
+        *targetType = "TooLong";
+      }
+    }
+  }                              
+
+
+  void FromDcmtkBridge::ElementToJson(Json::Value& parent,
+                                      DcmElement& element,
+                                      DicomToJsonFormat format,
+                                      DicomToJsonFlags flags,
+                                      unsigned int maxStringLength,
+                                      Encoding encoding,
+                                      const std::set<DicomTag>& ignoreTagLength)
+  {
+    if (parent.type() == Json::nullValue)
+    {
+      parent = Json::objectValue;
+    }
+
+    assert(parent.type() == Json::objectValue);
+    Json::Value& target = PrepareNode(parent, element, format);
+
+    if (element.isLeaf())
+    {
+      // The "0" below lets "LeafValueToJson()" take care of "TooLong" values
+      std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement
+                                  (element, flags, 0, encoding, ignoreTagLength));
+
+      if (ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end())
+      {
+        LeafValueToJson(target, *v, format, flags, maxStringLength);
+      }
+      else
+      {
+        LeafValueToJson(target, *v, format, flags, 0);
+      }
+    }
+    else
+    {
+      assert(target.type() == Json::nullValue);
+      target = Json::arrayValue;
+
+      // "All subclasses of DcmElement except for DcmSequenceOfItems
+      // are leaf nodes, while DcmSequenceOfItems, DcmItem, DcmDataset
+      // etc. are not." The following dynamic_cast is thus OK.
+      DcmSequenceOfItems& sequence = dynamic_cast<DcmSequenceOfItems&>(element);
+
+      for (unsigned long i = 0; i < sequence.card(); i++)
+      {
+        DcmItem* child = sequence.getItem(i);
+        Json::Value& v = target.append(Json::objectValue);
+        DatasetToJson(v, *child, format, flags, maxStringLength, encoding, ignoreTagLength);
+      }
+    }
+  }
+
+
+  void FromDcmtkBridge::DatasetToJson(Json::Value& parent,
+                                      DcmItem& item,
+                                      DicomToJsonFormat format,
+                                      DicomToJsonFlags flags,
+                                      unsigned int maxStringLength,
+                                      Encoding encoding,
+                                      const std::set<DicomTag>& ignoreTagLength)
+  {
+    assert(parent.type() == Json::objectValue);
+
+    for (unsigned long i = 0; i < item.card(); i++)
+    {
+      DcmElement* element = item.getElement(i);
+      if (element == NULL)
+      {
+        throw OrthancException(ErrorCode_InternalError);
+      }
+
+      DicomTag tag(FromDcmtkBridge::Convert(element->getTag()));
+
+      /*element->getTag().isPrivate()*/
+      if (tag.IsPrivate() &&
+          !(flags & DicomToJsonFlags_IncludePrivateTags))    
+      {
+        continue;
+      }
+
+      if (!(flags & DicomToJsonFlags_IncludeUnknownTags))
+      {
+        DictionaryLocker locker;
+        if (locker->findEntry(element->getTag(), NULL) == NULL)
+        {
+          continue;
+        }
+      }
+
+      DcmEVR evr = element->getTag().getEVR();
+      if (evr == EVR_OB ||
+          evr == EVR_OF ||
+          evr == EVR_OW ||
+          evr == EVR_UN ||
+          evr == EVR_ox)
+      {
+        // This is a binary tag
+        if ((tag == DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludePixelData)) ||
+            (tag != DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludeBinary)))
+        {
+          continue;
+        }
+      }
+
+      FromDcmtkBridge::ElementToJson(parent, *element, format, flags,
+                                     maxStringLength, encoding, ignoreTagLength);
+    }
+  }
+
+
+  void FromDcmtkBridge::ExtractDicomAsJson(Json::Value& target, 
+                                           DcmDataset& dataset,
+                                           DicomToJsonFormat format,
+                                           DicomToJsonFlags flags,
+                                           unsigned int maxStringLength,
+                                           Encoding defaultEncoding,
+                                           const std::set<DicomTag>& ignoreTagLength)
+  {
+    Encoding encoding = DetectEncoding(dataset, defaultEncoding);
+
+    target = Json::objectValue;
+    DatasetToJson(target, dataset, format, flags, maxStringLength, encoding, ignoreTagLength);
+  }
+
+
+  void FromDcmtkBridge::ExtractHeaderAsJson(Json::Value& target, 
+                                            DcmMetaInfo& dataset,
+                                            DicomToJsonFormat format,
+                                            DicomToJsonFlags flags,
+                                            unsigned int maxStringLength)
+  {
+    std::set<DicomTag> ignoreTagLength;
+    target = Json::objectValue;
+    DatasetToJson(target, dataset, format, flags, maxStringLength, Encoding_Ascii, ignoreTagLength);
+  }
+
+
+
+  static std::string GetTagNameInternal(DcmTag& tag)
+  {
+    {
+      // Some patches for important tags because of different DICOM
+      // dictionaries between DCMTK versions
+      DicomTag tmp(tag.getGroup(), tag.getElement());
+      std::string n = tmp.GetMainTagsName();
+      if (n.size() != 0)
+      {
+        return n;
+      }
+      // End of patches
+    }
+
+#if 0
+    // This version explicitly calls the dictionary
+    const DcmDataDictionary& dict = dcmDataDict.rdlock();
+    const DcmDictEntry* entry = dict.findEntry(tag, NULL);
+
+    std::string s(DcmTag_ERROR_TagName);
+    if (entry != NULL)
+    {
+      s = std::string(entry->getTagName());
+    }
+
+    dcmDataDict.unlock();
+    return s;
+#else
+    const char* name = tag.getTagName();
+    if (name == NULL)
+    {
+      return DcmTag_ERROR_TagName;
+    }
+    else
+    {
+      return std::string(name);
+    }
+#endif
+  }
+
+
+  std::string FromDcmtkBridge::GetTagName(const DicomTag& t,
+                                          const std::string& privateCreator)
+  {
+    DcmTag tag(t.GetGroup(), t.GetElement());
+
+    if (!privateCreator.empty())
+    {
+      tag.setPrivateCreator(privateCreator.c_str());
+    }
+
+    return GetTagNameInternal(tag);
+  }
+
+
+  std::string FromDcmtkBridge::GetTagName(const DcmElement& element)
+  {
+    // Copy the tag to ensure const-correctness of DcmElement. Note
+    // that the private creator information is also copied.
+    DcmTag tag(element.getTag());  
+
+    return GetTagNameInternal(tag);
+  }
+
+
+
+  DicomTag FromDcmtkBridge::ParseTag(const char* name)
+  {
+    if (strlen(name) == 9 &&
+        isxdigit(name[0]) &&
+        isxdigit(name[1]) &&
+        isxdigit(name[2]) &&
+        isxdigit(name[3]) &&
+        (name[4] == '-' || name[4] == ',') &&
+        isxdigit(name[5]) &&
+        isxdigit(name[6]) &&
+        isxdigit(name[7]) &&
+        isxdigit(name[8]))        
+    {
+      uint16_t group = GetTagValue(name);
+      uint16_t element = GetTagValue(name + 5);
+      return DicomTag(group, element);
+    }
+
+    if (strlen(name) == 8 &&
+        isxdigit(name[0]) &&
+        isxdigit(name[1]) &&
+        isxdigit(name[2]) &&
+        isxdigit(name[3]) &&
+        isxdigit(name[4]) &&
+        isxdigit(name[5]) &&
+        isxdigit(name[6]) &&
+        isxdigit(name[7]))        
+    {
+      uint16_t group = GetTagValue(name);
+      uint16_t element = GetTagValue(name + 4);
+      return DicomTag(group, element);
+    }
+
+#if 0
+    const DcmDataDictionary& dict = dcmDataDict.rdlock();
+    const DcmDictEntry* entry = dict.findEntry(name);
+
+    if (entry == NULL)
+    {
+      dcmDataDict.unlock();
+      throw OrthancException(ErrorCode_UnknownDicomTag);
+    }
+    else
+    {
+      DcmTagKey key = entry->getKey();
+      DicomTag tag(key.getGroup(), key.getElement());
+      dcmDataDict.unlock();
+      return tag;
+    }
+#else
+    DcmTag tag;
+    if (DcmTag::findTagFromName(name, tag).good())
+    {
+      return DicomTag(tag.getGTag(), tag.getETag());
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_UnknownDicomTag);
+    }
+#endif
+  }
+
+
+  bool FromDcmtkBridge::IsUnknownTag(const DicomTag& tag)
+  {
+    DcmTag tmp(tag.GetGroup(), tag.GetElement());
+    return tmp.isUnknownVR();
+  }
+
+
+  void FromDcmtkBridge::ToJson(Json::Value& result,
+                               const DicomMap& values,
+                               bool simplify)
+  {
+    if (result.type() != Json::objectValue)
+    {
+      throw OrthancException(ErrorCode_BadParameterType);
+    }
+
+    result.clear();
+
+    for (DicomMap::Map::const_iterator 
+           it = values.map_.begin(); it != values.map_.end(); ++it)
+    {
+      // TODO Inject PrivateCreator if some is available in the DicomMap?
+      const std::string tagName = GetTagName(it->first, "");
+
+      if (simplify)
+      {
+        if (it->second->IsNull())
+        {
+          result[tagName] = Json::nullValue;
+        }
+        else
+        {
+          // TODO IsBinary
+          result[tagName] = it->second->GetContent();
+        }
+      }
+      else
+      {
+        Json::Value value = Json::objectValue;
+
+        value["Name"] = tagName;
+
+        if (it->second->IsNull())
+        {
+          value["Type"] = "Null";
+          value["Value"] = Json::nullValue;
+        }
+        else
+        {
+          // TODO IsBinary
+          value["Type"] = "String";
+          value["Value"] = it->second->GetContent();
+        }
+
+        result[it->first.Format()] = value;
+      }
+    }
+  }
+
+
+  std::string FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType level)
+  {
+    char uid[100];
+
+    switch (level)
+    {
+      case ResourceType_Patient:
+        // The "PatientID" field is of type LO (Long String), 64
+        // Bytes Maximum. An UUID is of length 36, thus it can be used
+        // as a random PatientID.
+        return SystemToolbox::GenerateUuid();
+
+      case ResourceType_Instance:
+        return dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT);
+
+      case ResourceType_Series:
+        return dcmGenerateUniqueIdentifier(uid, SITE_SERIES_UID_ROOT);
+
+      case ResourceType_Study:
+        return dcmGenerateUniqueIdentifier(uid, SITE_STUDY_UID_ROOT);
+
+      default:
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+  bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer,
+                                           DcmDataset& dataSet)
+  {
+    // Determine the transfer syntax which shall be used to write the
+    // information to the file. We always switch to the Little Endian
+    // syntax, with explicit length.
+
+    // http://support.dcmtk.org/docs/dcxfer_8h-source.html
+
+
+    /**
+     * Note that up to Orthanc 0.7.1 (inclusive), the
+     * "EXS_LittleEndianExplicit" was always used to save the DICOM
+     * dataset into memory. We now keep the original transfer syntax
+     * (if available).
+     **/
+    E_TransferSyntax xfer = dataSet.getOriginalXfer();
+    if (xfer == EXS_Unknown)
+    {
+      // No information about the original transfer syntax: This is
+      // most probably a DICOM dataset that was read from memory.
+      xfer = EXS_LittleEndianExplicit;
+    }
+
+    E_EncodingType encodingType = /*opt_sequenceType*/ EET_ExplicitLength;
+
+    // Create the meta-header information
+    DcmFileFormat ff(&dataSet);
+    ff.validateMetaInfo(xfer);
+    ff.removeInvalidGroups();
+
+    // Create a memory buffer with the proper size
+    {
+      const uint32_t estimatedSize = ff.calcElementLength(xfer, encodingType);  // (*)
+      buffer.resize(estimatedSize);
+    }
+
+    DcmOutputBufferStream ob(&buffer[0], buffer.size());
+
+    // Fill the memory buffer with the meta-header and the dataset
+    ff.transferInit();
+    OFCondition c = ff.write(ob, xfer, encodingType, NULL,
+                             /*opt_groupLength*/ EGL_recalcGL,
+                             /*opt_paddingType*/ EPD_withoutPadding);
+    ff.transferEnd();
+
+    if (c.good())
+    {
+      // The DICOM file is successfully written, truncate the target
+      // buffer if its size was overestimated by (*)
+      ob.flush();
+
+      size_t effectiveSize = static_cast<size_t>(ob.tell());
+      if (effectiveSize < buffer.size())
+      {
+        buffer.resize(effectiveSize);
+      }
+
+      return true;
+    }
+    else
+    {
+      // Error
+      buffer.clear();
+      return false;
+    }
+  }
+
+
+  ValueRepresentation FromDcmtkBridge::LookupValueRepresentation(const DicomTag& tag)
+  {
+    DcmTag t(tag.GetGroup(), tag.GetElement());
+    return Convert(t.getEVR());
+  }
+
+  ValueRepresentation FromDcmtkBridge::Convert(const DcmEVR vr)
+  {
+    switch (vr)
+    {
+      case EVR_AE:
+        return ValueRepresentation_ApplicationEntity;
+
+      case EVR_AS:
+        return ValueRepresentation_AgeString;
+
+      case EVR_AT:
+        return ValueRepresentation_AttributeTag;
+
+      case EVR_CS:
+        return ValueRepresentation_CodeString;
+
+      case EVR_DA:
+        return ValueRepresentation_Date;
+
+      case EVR_DS:
+        return ValueRepresentation_DecimalString;
+
+      case EVR_DT:
+        return ValueRepresentation_DateTime;
+
+      case EVR_FL:
+        return ValueRepresentation_FloatingPointSingle;
+
+      case EVR_FD:
+        return ValueRepresentation_FloatingPointDouble;
+
+      case EVR_IS:
+        return ValueRepresentation_IntegerString;
+
+      case EVR_LO:
+        return ValueRepresentation_LongString;
+
+      case EVR_LT:
+        return ValueRepresentation_LongText;
+
+      case EVR_OB:
+        return ValueRepresentation_OtherByte;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case EVR_OD:
+          return ValueRepresentation_OtherDouble;*/
+
+      case EVR_OF:
+        return ValueRepresentation_OtherFloat;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case EVR_OL:
+          return ValueRepresentation_OtherLong;*/
+
+      case EVR_OW:
+        return ValueRepresentation_OtherWord;
+
+      case EVR_PN:
+        return ValueRepresentation_PersonName;
+
+      case EVR_SH:
+        return ValueRepresentation_ShortString;
+
+      case EVR_SL:
+        return ValueRepresentation_SignedLong;
+
+      case EVR_SQ:
+        return ValueRepresentation_Sequence;
+
+      case EVR_SS:
+        return ValueRepresentation_SignedShort;
+
+      case EVR_ST:
+        return ValueRepresentation_ShortText;
+
+      case EVR_TM:
+        return ValueRepresentation_Time;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case EVR_UC:
+          return ValueRepresentation_UnlimitedCharacters;*/
+
+      case EVR_UI:
+        return ValueRepresentation_UniqueIdentifier;
+
+      case EVR_UL:
+        return ValueRepresentation_UnsignedLong;
+
+      case EVR_UN:
+        return ValueRepresentation_Unknown;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case EVR_UR:
+          return ValueRepresentation_UniversalResource;*/
+
+      case EVR_US:
+        return ValueRepresentation_UnsignedShort;
+
+      case EVR_UT:
+        return ValueRepresentation_UnlimitedText;
+
+      default:
+        return ValueRepresentation_NotSupported;
+    }
+  }
+
+
+  static bool IsBinaryTag(const DcmTag& key)
+  {
+    return (key.isUnknownVR() || 
+            key.getEVR() == EVR_OB ||
+            key.getEVR() == EVR_OF ||
+            key.getEVR() == EVR_OW ||
+            key.getEVR() == EVR_UN ||
+            key.getEVR() == EVR_ox);
+  }
+
+
+  DcmElement* FromDcmtkBridge::CreateElementForTag(const DicomTag& tag)
+  {
+    DcmTag key(tag.GetGroup(), tag.GetElement());
+
+    if (tag.IsPrivate() ||
+        IsBinaryTag(key))
+    {
+      return new DcmOtherByteOtherWord(key);
+    }
+
+    switch (key.getEVR())
+    {
+      // http://support.dcmtk.org/docs/dcvr_8h-source.html
+
+      /**
+       * Binary types, handled above
+       **/
+    
+      case EVR_OB:  // other byte
+      case EVR_OF:  // other float
+      case EVR_OW:  // other word
+      case EVR_UN:  // unknown value representation
+      case EVR_ox:  // OB or OW depending on context
+        throw OrthancException(ErrorCode_InternalError);
+
+
+      /**
+       * String types.
+       * http://support.dcmtk.org/docs/classDcmByteString.html
+       **/
+      
+      case EVR_AS:  // age string
+        return new DcmAgeString(key);
+
+      case EVR_AE:  // application entity title
+        return new DcmApplicationEntity(key);
+
+      case EVR_CS:  // code string
+        return new DcmCodeString(key);        
+
+      case EVR_DA:  // date string
+        return new DcmDate(key);
+        
+      case EVR_DT:  // date time string
+        return new DcmDateTime(key);
+
+      case EVR_DS:  // decimal string
+        return new DcmDecimalString(key);
+
+      case EVR_IS:  // integer string
+        return new DcmIntegerString(key);
+
+      case EVR_TM:  // time string
+        return new DcmTime(key);
+
+      case EVR_UI:  // unique identifier
+        return new DcmUniqueIdentifier(key);
+
+      case EVR_ST:  // short text
+        return new DcmShortText(key);
+
+      case EVR_LO:  // long string
+        return new DcmLongString(key);
+
+      case EVR_LT:  // long text
+        return new DcmLongText(key);
+
+      case EVR_UT:  // unlimited text
+        return new DcmUnlimitedText(key);
+
+      case EVR_SH:  // short string
+        return new DcmShortString(key);
+
+      case EVR_PN:  // person name
+        return new DcmPersonName(key);
+
+        
+      /**
+       * Numerical types
+       **/ 
+      
+      case EVR_SL:  // signed long
+        return new DcmSignedLong(key);
+
+      case EVR_SS:  // signed short
+        return new DcmSignedShort(key);
+
+      case EVR_UL:  // unsigned long
+        return new DcmUnsignedLong(key);
+
+      case EVR_US:  // unsigned short
+        return new DcmUnsignedShort(key);
+
+      case EVR_FL:  // float single-precision
+        return new DcmFloatingPointSingle(key);
+
+      case EVR_FD:  // float double-precision
+        return new DcmFloatingPointDouble(key);
+
+
+      /**
+       * Sequence types, should never occur at this point.
+       **/
+
+      case EVR_SQ:  // sequence of items
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+
+
+      /**
+       * TODO
+       **/
+
+      case EVR_AT:  // attribute tag
+        throw OrthancException(ErrorCode_NotImplemented);
+
+
+      /**
+       * Internal to DCMTK.
+       **/ 
+
+      case EVR_xs:  // SS or US depending on context
+      case EVR_lt:  // US, SS or OW depending on context, used for LUT Data (thus the name)
+      case EVR_na:  // na="not applicable", for data which has no VR
+      case EVR_up:  // up="unsigned pointer", used internally for DICOMDIR suppor
+      case EVR_item:  // used internally for items
+      case EVR_metainfo:  // used internally for meta info datasets
+      case EVR_dataset:  // used internally for datasets
+      case EVR_fileFormat:  // used internally for DICOM files
+      case EVR_dicomDir:  // used internally for DICOMDIR objects
+      case EVR_dirRecord:  // used internally for DICOMDIR records
+      case EVR_pixelSQ:  // used internally for pixel sequences in a compressed image
+      case EVR_pixelItem:  // used internally for pixel items in a compressed image
+      case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR)
+      case EVR_PixelData:  // used internally for uncompressed pixeld data
+      case EVR_OverlayData:  // used internally for overlay data
+      case EVR_UNKNOWN2B:  // used internally for elements with unknown VR with 2-byte length field in explicit VR
+      default:
+        break;
+    }
+
+    throw OrthancException(ErrorCode_InternalError);          
+  }
+
+
+
+  void FromDcmtkBridge::FillElementWithString(DcmElement& element,
+                                              const DicomTag& tag,
+                                              const std::string& utf8Value,
+                                              bool decodeDataUriScheme,
+                                              Encoding dicomEncoding)
+  {
+    std::string binary;
+    const std::string* decoded = &utf8Value;
+
+    if (decodeDataUriScheme &&
+        boost::starts_with(utf8Value, "data:application/octet-stream;base64,"))
+    {
+      std::string mime;
+      if (!Toolbox::DecodeDataUriScheme(mime, binary, utf8Value))
+      {
+        throw OrthancException(ErrorCode_BadFileFormat);
+      }
+
+      decoded = &binary;
+    }
+    else if (dicomEncoding != Encoding_Utf8)
+    {
+      binary = Toolbox::ConvertFromUtf8(utf8Value, dicomEncoding);
+      decoded = &binary;
+    }
+
+    DcmTag key(tag.GetGroup(), tag.GetElement());
+
+    if (tag.IsPrivate() ||
+        IsBinaryTag(key))
+    {
+      if (element.putUint8Array((const Uint8*) decoded->c_str(), decoded->size()).good())
+      {
+        return;
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_InternalError);
+      }
+    }
+
+    bool ok = false;
+    
+    try
+    {
+      switch (key.getEVR())
+      {
+        // http://support.dcmtk.org/docs/dcvr_8h-source.html
+
+        /**
+         * TODO.
+         **/
+
+        case EVR_OB:  // other byte
+        case EVR_OF:  // other float
+        case EVR_OW:  // other word
+        case EVR_AT:  // attribute tag
+          throw OrthancException(ErrorCode_NotImplemented);
+    
+        case EVR_UN:  // unknown value representation
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
+
+
+        /**
+         * String types.
+         **/
+      
+        case EVR_DS:  // decimal string
+        case EVR_IS:  // integer string
+        case EVR_AS:  // age string
+        case EVR_DA:  // date string
+        case EVR_DT:  // date time string
+        case EVR_TM:  // time string
+        case EVR_AE:  // application entity title
+        case EVR_CS:  // code string
+        case EVR_SH:  // short string
+        case EVR_LO:  // long string
+        case EVR_ST:  // short text
+        case EVR_LT:  // long text
+        case EVR_UT:  // unlimited text
+        case EVR_PN:  // person name
+        case EVR_UI:  // unique identifier
+        {
+          ok = element.putString(decoded->c_str()).good();
+          break;
+        }
+
+        
+        /**
+         * Numerical types
+         **/ 
+      
+        case EVR_SL:  // signed long
+        {
+          ok = element.putSint32(boost::lexical_cast<Sint32>(*decoded)).good();
+          break;
+        }
+
+        case EVR_SS:  // signed short
+        {
+          ok = element.putSint16(boost::lexical_cast<Sint16>(*decoded)).good();
+          break;
+        }
+
+        case EVR_UL:  // unsigned long
+        {
+          ok = element.putUint32(boost::lexical_cast<Uint32>(*decoded)).good();
+          break;
+        }
+
+        case EVR_US:  // unsigned short
+        {
+          ok = element.putUint16(boost::lexical_cast<Uint16>(*decoded)).good();
+          break;
+        }
+
+        case EVR_FL:  // float single-precision
+        {
+          ok = element.putFloat32(boost::lexical_cast<float>(*decoded)).good();
+          break;
+        }
+
+        case EVR_FD:  // float double-precision
+        {
+          ok = element.putFloat64(boost::lexical_cast<double>(*decoded)).good();
+          break;
+        }
+
+
+        /**
+         * Sequence types, should never occur at this point.
+         **/
+
+        case EVR_SQ:  // sequence of items
+        {
+          ok = false;
+          break;
+        }
+
+
+        /**
+         * Internal to DCMTK.
+         **/ 
+
+        case EVR_ox:  // OB or OW depending on context
+        case EVR_xs:  // SS or US depending on context
+        case EVR_lt:  // US, SS or OW depending on context, used for LUT Data (thus the name)
+        case EVR_na:  // na="not applicable", for data which has no VR
+        case EVR_up:  // up="unsigned pointer", used internally for DICOMDIR suppor
+        case EVR_item:  // used internally for items
+        case EVR_metainfo:  // used internally for meta info datasets
+        case EVR_dataset:  // used internally for datasets
+        case EVR_fileFormat:  // used internally for DICOM files
+        case EVR_dicomDir:  // used internally for DICOMDIR objects
+        case EVR_dirRecord:  // used internally for DICOMDIR records
+        case EVR_pixelSQ:  // used internally for pixel sequences in a compressed image
+        case EVR_pixelItem:  // used internally for pixel items in a compressed image
+        case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR)
+        case EVR_PixelData:  // used internally for uncompressed pixeld data
+        case EVR_OverlayData:  // used internally for overlay data
+        case EVR_UNKNOWN2B:  // used internally for elements with unknown VR with 2-byte length field in explicit VR
+        default:
+          break;
+      }
+    }
+    catch (boost::bad_lexical_cast&)
+    {
+      ok = false;
+    }
+
+    if (!ok)
+    {
+      LOG(ERROR) << "While creating a DICOM instance, tag (" << tag.Format()
+                 << ") has out-of-range value: \"" << *decoded << "\"";
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+  }
+
+
+  DcmElement* FromDcmtkBridge::FromJson(const DicomTag& tag,
+                                        const Json::Value& value,
+                                        bool decodeDataUriScheme,
+                                        Encoding dicomEncoding)
+  {
+    std::auto_ptr<DcmElement> element;
+
+    switch (value.type())
+    {
+      case Json::stringValue:
+        element.reset(CreateElementForTag(tag));
+        FillElementWithString(*element, tag, value.asString(), decodeDataUriScheme, dicomEncoding);
+        break;
+
+      case Json::nullValue:
+        element.reset(CreateElementForTag(tag));
+        FillElementWithString(*element, tag, "", decodeDataUriScheme, dicomEncoding);
+        break;
+
+      case Json::arrayValue:
+      {
+        DcmTag key(tag.GetGroup(), tag.GetElement());
+        if (key.getEVR() != EVR_SQ)
+        {
+          throw OrthancException(ErrorCode_BadParameterType);
+        }
+
+        DcmSequenceOfItems* sequence = new DcmSequenceOfItems(key);
+        element.reset(sequence);
+        
+        for (Json::Value::ArrayIndex i = 0; i < value.size(); i++)
+        {
+          std::auto_ptr<DcmItem> item(new DcmItem);
+
+          Json::Value::Members members = value[i].getMemberNames();
+          for (Json::Value::ArrayIndex j = 0; j < members.size(); j++)
+          {
+            item->insert(FromJson(ParseTag(members[j]), value[i][members[j]], decodeDataUriScheme, dicomEncoding));
+          }
+
+          sequence->append(item.release());
+        }
+
+        break;
+      }
+
+      default:
+        throw OrthancException(ErrorCode_BadParameterType);
+    }
+
+    return element.release();
+  }
+
+
+  DcmPixelSequence* FromDcmtkBridge::GetPixelSequence(DcmDataset& dataset)
+  {
+    DcmElement *element = NULL;
+    if (!dataset.findAndGetElement(DCM_PixelData, element).good())
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    DcmPixelData& pixelData = dynamic_cast<DcmPixelData&>(*element);
+    DcmPixelSequence* pixelSequence = NULL;
+    if (!pixelData.getEncapsulatedRepresentation
+        (dataset.getOriginalXfer(), NULL, pixelSequence).good())
+    {
+      return NULL;
+    }
+    else
+    {
+      return pixelSequence;
+    }
+  }
+
+
+  Encoding FromDcmtkBridge::ExtractEncoding(const Json::Value& json,
+                                            Encoding defaultEncoding)
+  {
+    if (json.type() != Json::objectValue)
+    {
+      throw OrthancException(ErrorCode_BadParameterType);
+    }
+
+    Encoding encoding = defaultEncoding;
+
+    const Json::Value::Members tags = json.getMemberNames();
+    
+    // Look for SpecificCharacterSet (0008,0005) in the JSON file
+    for (size_t i = 0; i < tags.size(); i++)
+    {
+      DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]);
+      if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET)
+      {
+        const Json::Value& value = json[tags[i]];
+        if (value.type() != Json::stringValue ||
+            (value.asString().length() != 0 &&
+             !GetDicomEncoding(encoding, value.asCString())))
+        {
+          LOG(ERROR) << "Unknown encoding while creating DICOM from JSON: " << value;
+          throw OrthancException(ErrorCode_BadRequest);
+        }
+
+        if (value.asString().length() == 0)
+        {
+          return defaultEncoding;
+        }
+      }
+    }
+
+    return encoding;
+  } 
+
+
+  static void SetString(DcmDataset& target,
+                        const DcmTag& tag,
+                        const std::string& value)
+  {
+    if (!target.putAndInsertString(tag, value.c_str()).good())
+    {
+      throw OrthancException(ErrorCode_InternalError);
+    }
+  }
+
+
+  DcmDataset* FromDcmtkBridge::FromJson(const Json::Value& json,  // Encoded using UTF-8
+                                        bool generateIdentifiers,
+                                        bool decodeDataUriScheme,
+                                        Encoding defaultEncoding)
+  {
+    std::auto_ptr<DcmDataset> result(new DcmDataset);
+    Encoding encoding = ExtractEncoding(json, defaultEncoding);
+
+    SetString(*result, DCM_SpecificCharacterSet, GetDicomSpecificCharacterSet(encoding));
+
+    const Json::Value::Members tags = json.getMemberNames();
+    
+    bool hasPatientId = false;
+    bool hasStudyInstanceUid = false;
+    bool hasSeriesInstanceUid = false;
+    bool hasSopInstanceUid = false;
+
+    for (size_t i = 0; i < tags.size(); i++)
+    {
+      DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]);
+      const Json::Value& value = json[tags[i]];
+
+      if (tag == DICOM_TAG_PATIENT_ID)
+      {
+        hasPatientId = true;
+      }
+      else if (tag == DICOM_TAG_STUDY_INSTANCE_UID)
+      {
+        hasStudyInstanceUid = true;
+      }
+      else if (tag == DICOM_TAG_SERIES_INSTANCE_UID)
+      {
+        hasSeriesInstanceUid = true;
+      }
+      else if (tag == DICOM_TAG_SOP_INSTANCE_UID)
+      {
+        hasSopInstanceUid = true;
+      }
+
+      if (tag != DICOM_TAG_SPECIFIC_CHARACTER_SET)
+      {
+        std::auto_ptr<DcmElement> element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding));
+        const DcmTagKey& tag = element->getTag();
+
+        result->findAndDeleteElement(tag);
+
+        DcmElement* tmp = element.release();
+        if (!result->insert(tmp, false, false).good())
+        {
+          delete tmp;
+          throw OrthancException(ErrorCode_InternalError);
+        }
+      }
+    }
+
+    if (!hasPatientId &&
+        generateIdentifiers)
+    {
+      SetString(*result, DCM_PatientID, GenerateUniqueIdentifier(ResourceType_Patient));
+    }
+
+    if (!hasStudyInstanceUid &&
+        generateIdentifiers)
+    {
+      SetString(*result, DCM_StudyInstanceUID, GenerateUniqueIdentifier(ResourceType_Study));
+    }
+
+    if (!hasSeriesInstanceUid &&
+        generateIdentifiers)
+    {
+      SetString(*result, DCM_SeriesInstanceUID, GenerateUniqueIdentifier(ResourceType_Series));
+    }
+
+    if (!hasSopInstanceUid &&
+        generateIdentifiers)
+    {
+      SetString(*result, DCM_SOPInstanceUID, GenerateUniqueIdentifier(ResourceType_Instance));
+    }
+
+    return result.release();
+  }
+
+
+  DcmFileFormat* FromDcmtkBridge::LoadFromMemoryBuffer(const void* buffer,
+                                                       size_t size)
+  {
+    DcmInputBufferStream is;
+    if (size > 0)
+    {
+      is.setBuffer(buffer, size);
+    }
+    is.setEos();
+
+    std::auto_ptr<DcmFileFormat> result(new DcmFileFormat);
+
+    result->transferInit();
+    if (!result->read(is).good())
+    {
+      LOG(ERROR) << "Cannot parse an invalid DICOM file (size: " << size << " bytes)";
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    result->loadAllDataIntoMemory();
+    result->transferEnd();
+
+    return result.release();
+  }
+
+
+  void FromDcmtkBridge::FromJson(DicomMap& target,
+                                 const Json::Value& source)
+  {
+    if (source.type() != Json::objectValue)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    target.Clear();
+
+    Json::Value::Members members = source.getMemberNames();
+
+    for (size_t i = 0; i < members.size(); i++)
+    {
+      const Json::Value& value = source[members[i]];
+
+      if (value.type() != Json::stringValue)
+      {
+        throw OrthancException(ErrorCode_BadFileFormat);
+      }
+      
+      target.SetValue(ParseTag(members[i]), value.asString(), false);
+    }
+  }
+
+
+  void FromDcmtkBridge::ChangeStringEncoding(DcmItem& dataset,
+                                             Encoding source,
+                                             Encoding target)
+  {
+    // Recursive exploration of a dataset to change the encoding of
+    // each string-like element
+
+    if (source == target)
+    {
+      return;
+    }
+
+    for (unsigned long i = 0; i < dataset.card(); i++)
+    {
+      DcmElement* element = dataset.getElement(i);
+      if (element)
+      {
+        if (element->isLeaf())
+        {
+          char *c = NULL;
+          if (element->isaString() &&
+              element->getString(c).good() && 
+              c != NULL)
+          {
+            std::string a = Toolbox::ConvertToUtf8(c, source);
+            std::string b = Toolbox::ConvertFromUtf8(a, target);
+            element->putString(b.c_str());
+          }
+        }
+        else
+        {
+          // "All subclasses of DcmElement except for DcmSequenceOfItems
+          // are leaf nodes, while DcmSequenceOfItems, DcmItem, DcmDataset
+          // etc. are not." The following dynamic_cast is thus OK.
+          DcmSequenceOfItems& sequence = dynamic_cast<DcmSequenceOfItems&>(*element);
+
+          for (unsigned long j = 0; j < sequence.card(); j++)
+          {
+            ChangeStringEncoding(*sequence.getItem(j), source, target);
+          }
+        }
+      }
+    }
+  }
+
+
+  bool FromDcmtkBridge::LookupTransferSyntax(std::string& result,
+                                             DcmFileFormat& dicom)
+  {
+    const char* value = NULL;
+
+    if (dicom.getMetaInfo() != NULL &&
+        dicom.getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, value).good() &&
+        value != NULL)
+    {
+      result.assign(value);
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+#if ORTHANC_ENABLE_LUA == 1
+  void FromDcmtkBridge::ExecuteToDicom(DicomMap& target,
+                                       LuaFunctionCall& call)
+  {
+    Json::Value output;
+    call.ExecuteToJson(output, true /* keep strings */);
+
+    target.Clear();
+
+    if (output.type() == Json::arrayValue &&
+        output.size() == 0)
+    {
+      // This case happens for empty tables
+      return;
+    }
+
+    if (output.type() != Json::objectValue)
+    {
+      LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table";
+      throw OrthancException(ErrorCode_LuaBadOutput);
+    }
+
+    Json::Value::Members members = output.getMemberNames();
+
+    for (size_t i = 0; i < members.size(); i++)
+    {
+      if (output[members[i]].type() != Json::stringValue)
+      {
+        LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table mapping names of DICOM tags to strings";
+        throw OrthancException(ErrorCode_LuaBadOutput);
+      }
+
+      DicomTag tag(ParseTag(members[i]));
+      target.SetValue(tag, output[members[i]].asString(), false);
+    }
+  }
+#endif
+
+
+  void FromDcmtkBridge::ExtractDicomSummary(DicomMap& target, 
+                                            DcmItem& dataset)
+  {
+    ExtractDicomSummary(target, dataset,
+                        ORTHANC_MAXIMUM_TAG_LENGTH,
+                        GetDefaultDicomEncoding());
+  }
+
+  
+  void FromDcmtkBridge::ExtractDicomAsJson(Json::Value& target, 
+                                           DcmDataset& dataset,
+                                           const std::set<DicomTag>& ignoreTagLength)
+  {
+    ExtractDicomAsJson(target, dataset, 
+                       DicomToJsonFormat_Full,
+                       DicomToJsonFlags_Default, 
+                       ORTHANC_MAXIMUM_TAG_LENGTH,
+                       GetDefaultDicomEncoding(),
+                       ignoreTagLength);
+  }
+
+
+  void FromDcmtkBridge::InitializeCodecs()
+  {
+#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1
+    LOG(WARNING) << "Registering JPEG Lossless codecs in DCMTK";
+    DJLSDecoderRegistration::registerCodecs();    
+#endif
+
+#if ORTHANC_ENABLE_DCMTK_JPEG == 1
+    LOG(WARNING) << "Registering JPEG codecs in DCMTK";
+    DJDecoderRegistration::registerCodecs(); 
+#endif
+  }
+
+
+  void FromDcmtkBridge::FinalizeCodecs()
+  {
+#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1
+    // Unregister JPEG-LS codecs
+    DJLSDecoderRegistration::cleanup();
+#endif
+
+#if ORTHANC_ENABLE_DCMTK_JPEG == 1
+    // Unregister JPEG codecs
+    DJDecoderRegistration::cleanup();
+#endif
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.h	Thu Jan 04 10:49:34 2018 +0100
@@ -0,0 +1,244 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "../DicomFormat/DicomElement.h"
+#include "../DicomFormat/DicomMap.h"
+
+#include <dcmtk/dcmdata/dcdatset.h>
+#include <dcmtk/dcmdata/dcmetinf.h>
+#include <dcmtk/dcmdata/dcpixseq.h>
+#include <dcmtk/dcmdata/dcfilefo.h>
+#include <json/json.h>
+
+#if !defined(ORTHANC_ENABLE_LUA)
+#  error The macro ORTHANC_ENABLE_LUA must be defined
+#endif
+
+#if ORTHANC_ENABLE_DCMTK != 1
+#  error The macro ORTHANC_ENABLE_DCMTK must be set to 1
+#endif
+
+#if ORTHANC_BUILD_UNIT_TESTS == 1
+#  include <gtest/gtest_prod.h>
+#endif
+
+#if ORTHANC_ENABLE_LUA == 1
+#  include "../Lua/LuaFunctionCall.h"
+#endif
+
+#if !defined(ORTHANC_ENABLE_DCMTK_JPEG)
+#  error The macro ORTHANC_ENABLE_DCMTK_JPEG must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS)
+#  error The macro ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS must be defined
+#endif
+
+
+namespace Orthanc
+{
+  class FromDcmtkBridge : public boost::noncopyable
+  {
+#if ORTHANC_BUILD_UNIT_TESTS == 1
+    FRIEND_TEST(FromDcmtkBridge, FromJson);
+#endif
+
+    friend class ParsedDicomFile;
+
+  private:
+    FromDcmtkBridge();  // Pure static class
+
+    static void ExtractDicomSummary(DicomMap& target, 
+                                    DcmItem& dataset,
+                                    unsigned int maxStringLength,
+                                    Encoding defaultEncoding);
+
+    static void DatasetToJson(Json::Value& parent,
+                              DcmItem& item,
+                              DicomToJsonFormat format,
+                              DicomToJsonFlags flags,
+                              unsigned int maxStringLength,
+                              Encoding encoding,
+                              const std::set<DicomTag>& ignoreTagLength);
+
+    static void ElementToJson(Json::Value& parent,
+                              DcmElement& element,
+                              DicomToJsonFormat format,
+                              DicomToJsonFlags flags,
+                              unsigned int maxStringLength,
+                              Encoding dicomEncoding,
+                              const std::set<DicomTag>& ignoreTagLength);
+
+    static void ExtractDicomAsJson(Json::Value& target, 
+                                   DcmDataset& dataset,
+                                   DicomToJsonFormat format,
+                                   DicomToJsonFlags flags,
+                                   unsigned int maxStringLength,
+                                   Encoding defaultEncoding,
+                                   const std::set<DicomTag>& ignoreTagLength);
+
+    static void ChangeStringEncoding(DcmItem& dataset,
+                                     Encoding source,
+                                     Encoding target);
+
+  public:
+    static void InitializeDictionary(bool loadPrivateDictionary);
+
+    static void RegisterDictionaryTag(const DicomTag& tag,
+                                      ValueRepresentation vr,
+                                      const std::string& name,
+                                      unsigned int minMultiplicity,
+                                      unsigned int maxMultiplicity,
+                                      const std::string& privateCreator);
+
+    static Encoding DetectEncoding(DcmItem& dataset,
+                                   Encoding defaultEncoding);
+
+    static DicomTag Convert(const DcmTag& tag);
+
+    static DicomTag GetTag(const DcmElement& element);
+
+    static bool IsUnknownTag(const DicomTag& tag);
+
+    static DicomValue* ConvertLeafElement(DcmElement& element,
+                                          DicomToJsonFlags flags,
+                                          unsigned int maxStringLength,
+                                          Encoding encoding,
+                                          const std::set<DicomTag>& ignoreTagLength);
+
+    static void ExtractHeaderAsJson(Json::Value& target, 
+                                    DcmMetaInfo& header,
+                                    DicomToJsonFormat format,
+                                    DicomToJsonFlags flags,
+                                    unsigned int maxStringLength);
+
+    static std::string GetTagName(const DicomTag& tag,
+                                  const std::string& privateCreator);
+
+    static std::string GetTagName(const DcmElement& element);
+
+    static std::string GetTagName(const DicomElement& element)
+    {
+      return GetTagName(element.GetTag(), "");
+    }
+
+    static DicomTag ParseTag(const char* name);
+
+    static DicomTag ParseTag(const std::string& name)
+    {
+      return ParseTag(name.c_str());
+    }
+
+    static bool HasTag(const DicomMap& fields,
+                       const std::string& tagName)
+    {
+      return fields.HasTag(ParseTag(tagName));
+    }
+
+    static const DicomValue& GetValue(const DicomMap& fields,
+                                      const std::string& tagName)
+    {
+      return fields.GetValue(ParseTag(tagName));
+    }
+
+    static void SetValue(DicomMap& target,
+                         const std::string& tagName,
+                         DicomValue* value)
+    {
+      target.SetValue(ParseTag(tagName), value);
+    }
+
+    static void ToJson(Json::Value& result,
+                       const DicomMap& values,
+                       bool simplify);
+
+    static std::string GenerateUniqueIdentifier(ResourceType level);
+
+    static bool SaveToMemoryBuffer(std::string& buffer,
+                                   DcmDataset& dataSet);
+
+    static ValueRepresentation Convert(DcmEVR vr);
+
+    static ValueRepresentation LookupValueRepresentation(const DicomTag& tag);
+
+    static DcmElement* CreateElementForTag(const DicomTag& tag);
+    
+    static void FillElementWithString(DcmElement& element,
+                                      const DicomTag& tag,
+                                      const std::string& utf8alue,  // Encoded using UTF-8
+                                      bool decodeDataUriScheme,
+                                      Encoding dicomEncoding);
+
+    static DcmElement* FromJson(const DicomTag& tag,
+                                const Json::Value& element,  // Encoded using UTF-8
+                                bool decodeDataUriScheme,
+                                Encoding dicomEncoding);
+
+    static DcmPixelSequence* GetPixelSequence(DcmDataset& dataset);
+
+    static Encoding ExtractEncoding(const Json::Value& json,
+                                    Encoding defaultEncoding);
+
+    static DcmDataset* FromJson(const Json::Value& json,  // Encoded using UTF-8
+                                bool generateIdentifiers,
+                                bool decodeDataUriScheme,
+                                Encoding defaultEncoding);
+
+    static DcmFileFormat* LoadFromMemoryBuffer(const void* buffer,
+                                               size_t size);
+
+    static void FromJson(DicomMap& values,
+                         const Json::Value& result);
+
+    static bool LookupTransferSyntax(std::string& result,
+                                     DcmFileFormat& dicom);
+
+#if ORTHANC_ENABLE_LUA == 1
+    static void ExecuteToDicom(DicomMap& target,
+                               LuaFunctionCall& call);
+#endif
+
+    static void ExtractDicomSummary(DicomMap& target, 
+                                    DcmItem& dataset);
+
+    static void ExtractDicomAsJson(Json::Value& target, 
+                                   DcmDataset& dataset,
+                                   const std::set<DicomTag>& ignoreTagLength);
+
+    static void InitializeCodecs();
+
+    static void FinalizeCodecs();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Core/DicomParsing/ToDcmtkBridge.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -0,0 +1,150 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "ToDcmtkBridge.h"
+
+#include <memory>
+#include <dcmtk/dcmnet/diutil.h>
+
+#include "../OrthancException.h"
+
+
+namespace Orthanc
+{
+  DcmEVR ToDcmtkBridge::Convert(ValueRepresentation vr)
+  {
+    switch (vr)
+    {
+      case ValueRepresentation_ApplicationEntity:
+        return EVR_AE;
+
+      case ValueRepresentation_AgeString:
+        return EVR_AS;
+
+      case ValueRepresentation_AttributeTag:
+        return EVR_AT;
+
+      case ValueRepresentation_CodeString:
+        return EVR_CS;
+
+      case ValueRepresentation_Date:
+        return EVR_DA;
+
+      case ValueRepresentation_DecimalString:
+        return EVR_DS;
+
+      case ValueRepresentation_DateTime:
+        return EVR_DT;
+
+      case ValueRepresentation_FloatingPointSingle:
+        return EVR_FL;
+
+      case ValueRepresentation_FloatingPointDouble:
+        return EVR_FD;
+
+      case ValueRepresentation_IntegerString:
+        return EVR_IS;
+
+      case ValueRepresentation_LongString:
+        return EVR_LO;
+
+      case ValueRepresentation_LongText:
+        return EVR_LT;
+
+      case ValueRepresentation_OtherByte:
+        return EVR_OB;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case ValueRepresentation_OtherDouble:
+          return EVR_OD;*/
+
+      case ValueRepresentation_OtherFloat:
+        return EVR_OF;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case ValueRepresentation_OtherLong:
+          return EVR_OL;*/
+
+      case ValueRepresentation_OtherWord:
+        return EVR_OW;
+
+      case ValueRepresentation_PersonName:
+        return EVR_PN;
+
+      case ValueRepresentation_ShortString:
+        return EVR_SH;
+
+      case ValueRepresentation_SignedLong:
+        return EVR_SL;
+
+      case ValueRepresentation_Sequence:
+        return EVR_SQ;
+
+      case ValueRepresentation_SignedShort:
+        return EVR_SS;
+
+      case ValueRepresentation_ShortText:
+        return EVR_ST;
+
+      case ValueRepresentation_Time:
+        return EVR_TM;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case ValueRepresentation_UnlimitedCharacters:
+          return EVR_UC;*/
+
+      case ValueRepresentation_UniqueIdentifier:
+        return EVR_UI;
+
+      case ValueRepresentation_UnsignedLong:
+        return EVR_UL;
+
+      case ValueRepresentation_Unknown:
+        return EVR_UN;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case ValueRepresentation_UniversalResource:
+          return EVR_UR;*/
+
+      case ValueRepresentation_UnsignedShort:
+        return EVR_US;
+
+      case ValueRepresentation_UnlimitedText:
+        return EVR_UT;
+
+      default:
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Core/DicomParsing/ToDcmtkBridge.h	Thu Jan 04 10:49:34 2018 +0100
@@ -0,0 +1,55 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#if ORTHANC_ENABLE_DCMTK != 1
+#  error The macro ORTHANC_ENABLE_DCMTK must be set to 1
+#endif
+
+#include "../DicomFormat/DicomMap.h"
+#include <dcmtk/dcmdata/dcdatset.h>
+
+namespace Orthanc
+{
+  class ToDcmtkBridge
+  {
+  public:
+    static DcmTagKey Convert(const DicomTag& tag)
+    {
+      return DcmTagKey(tag.GetGroup(), tag.GetElement());
+    }
+
+    static DcmEVR Convert(ValueRepresentation vr);
+  };
+}
--- a/Resources/Orthanc/Core/Endianness.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Endianness.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -35,10 +35,15 @@
 
 
 /********************************************************************
- ** LINUX ARCHITECTURES
+ ** LINUX-LIKE ARCHITECTURES
  ********************************************************************/
 
-#if defined(__linux__)
+#if defined(__LSB_VERSION__)
+// Linux Standard Base (LSB) does not come with be16toh, be32toh, and
+// be64toh
+#  define ORTHANC_HAS_BUILTIN_BYTE_SWAP 0
+#  include <endian.h>
+#elif defined(__linux__) || defined(__EMSCRIPTEN__)
 #  define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1
 #  include <endian.h>
 #endif
@@ -155,4 +160,38 @@
           static_cast<uint64_t>(p[7]));
 }
 
+#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+#    define be16toh(x) __orthanc_bswap16(x)
+#    define be32toh(x) __orthanc_bswap32(x)
+#    define be64toh(x) __orthanc_bswap64(x)
+#    define htobe16(x) __orthanc_bswap16(x)
+#    define htobe32(x) __orthanc_bswap32(x)
+#    define htobe64(x) __orthanc_bswap64(x)
+#    define htole16(x) x
+#    define htole32(x) x
+#    define htole64(x) x
+#    define le16toh(x) x
+#    define le32toh(x) x
+#    define le64toh(x) x
+#  elif __BYTE_ORDER == __BIG_ENDIAN
+#    define be16toh(x) x
+#    define be32toh(x) x
+#    define be64toh(x) x
+#    define htobe16(x) x
+#    define htobe32(x) x
+#    define htobe64(x) x
+#    define htole16(x) __orthanc_bswap16(x)
+#    define htole32(x) __orthanc_bswap32(x)
+#    define htole64(x) __orthanc_bswap64(x)
+#    define le16toh(x) __orthanc_bswap16(x)
+#    define le32toh(x) __orthanc_bswap32(x)
+#    define le64toh(x) __orthanc_bswap64(x)
+#  else
+#    error Please support your platform here
+#  endif
+#else
+#  error Please support your platform here
 #endif
+
+#endif
--- a/Resources/Orthanc/Core/EnumerationDictionary.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/EnumerationDictionary.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Enumerations.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Enumerations.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -38,6 +38,7 @@
 #include "Toolbox.h"
 #include "Logging.h"
 
+#include <boost/thread/mutex.hpp>
 #include <string.h>
 #include <cassert>
 
@@ -752,12 +753,128 @@
       case PixelFormat_Float32:
         return "Grayscale (float 32bpp)";
 
+      case PixelFormat_Grayscale32:
+        return "Grayscale (unsigned 32bpp)";
+
+      case PixelFormat_RGB48:
+        return "RGB48";
+
       default:
         throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
   }
 
 
+  const char* EnumerationToString(ModalityManufacturer manufacturer)
+  {
+    switch (manufacturer)
+    {
+      case ModalityManufacturer_Generic:
+        return "Generic";
+
+      case ModalityManufacturer_GenericNoWildcardInDates:
+        return "GenericNoWildcardInDates";
+
+      case ModalityManufacturer_GenericNoUniversalWildcard:
+        return "GenericNoUniversalWildcard";
+
+      case ModalityManufacturer_StoreScp:
+        return "StoreScp";
+      
+      case ModalityManufacturer_ClearCanvas:
+        return "ClearCanvas";
+      
+      case ModalityManufacturer_Dcm4Chee:
+        return "Dcm4Chee";
+      
+      case ModalityManufacturer_Vitrea:
+        return "Vitrea";
+      
+      default:
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
+  const char* EnumerationToString(DicomRequestType type)
+  {
+    switch (type)
+    {
+      case DicomRequestType_Echo:
+        return "Echo";
+        break;
+
+      case DicomRequestType_Find:
+        return "Find";
+        break;
+
+      case DicomRequestType_Get:
+        return "Get";
+        break;
+
+      case DicomRequestType_Move:
+        return "Move";
+        break;
+
+      case DicomRequestType_Store:
+        return "Store";
+        break;
+
+      default: 
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
+  const char* EnumerationToString(TransferSyntax syntax)
+  {
+    switch (syntax)
+    {
+      case TransferSyntax_Deflated:
+        return "Deflated";
+
+      case TransferSyntax_Jpeg:
+        return "JPEG";
+
+      case TransferSyntax_Jpeg2000:
+        return "JPEG2000";
+
+      case TransferSyntax_JpegLossless:
+        return "JPEG Lossless";
+
+      case TransferSyntax_Jpip:
+        return "JPIP";
+
+      case TransferSyntax_Mpeg2:
+        return "MPEG2";
+
+      case TransferSyntax_Rle:
+        return "RLE";
+
+      default: 
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
+  const char* EnumerationToString(DicomVersion version)
+  {
+    switch (version)
+    {
+      case DicomVersion_2008:
+        return "2008";
+        break;
+
+      case DicomVersion_2017c:
+        return "2017c";
+        break;
+
+      default: 
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
   Encoding StringToEncoding(const char* encoding)
   {
     std::string s(encoding);
@@ -1127,6 +1244,86 @@
   }
   
 
+  ModalityManufacturer StringToModalityManufacturer(const std::string& manufacturer)
+  {
+    ModalityManufacturer result;
+    bool obsolete = false;
+    
+    if (manufacturer == "Generic")
+    {
+      return ModalityManufacturer_Generic;
+    }
+    else if (manufacturer == "GenericNoWildcardInDates")
+    {
+      return ModalityManufacturer_GenericNoWildcardInDates;
+    }
+    else if (manufacturer == "GenericNoUniversalWildcard")
+    {
+      return ModalityManufacturer_GenericNoUniversalWildcard;
+    }
+    else if (manufacturer == "ClearCanvas")
+    {
+      return ModalityManufacturer_ClearCanvas;
+    }
+    else if (manufacturer == "StoreScp")
+    {
+      return ModalityManufacturer_StoreScp;
+    }
+    else if (manufacturer == "Dcm4Chee")
+    {
+      return ModalityManufacturer_Dcm4Chee;
+    }
+    else if (manufacturer == "Vitrea")
+    {
+      return ModalityManufacturer_Vitrea;
+    }
+    else if (manufacturer == "AgfaImpax" ||
+             manufacturer == "SyngoVia")
+    {
+      result = ModalityManufacturer_GenericNoWildcardInDates;
+      obsolete = true;
+    }
+    else if (manufacturer == "EFilm2" ||
+             manufacturer == "MedInria")
+    {
+      result = ModalityManufacturer_Generic;
+      obsolete = true;
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+
+    if (obsolete)
+    {
+      LOG(WARNING) << "The \"" << manufacturer << "\" manufacturer is obsolete since "
+                   << "Orthanc 1.3.0. To guarantee compatibility with future Orthanc "
+                   << "releases, you should replace it by \""
+                   << EnumerationToString(result)
+                   << "\" in your configuration file.";
+    }
+
+    return result;
+  }
+
+
+  DicomVersion StringToDicomVersion(const std::string& version)
+  {
+    if (version == "2008")
+    {
+      return DicomVersion_2008;
+    }
+    else if (version == "2017c")
+    {
+      return DicomVersion_2017c;
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
   unsigned int GetBytesPerPixel(PixelFormat format)
   {
     switch (format)
@@ -1143,12 +1340,16 @@
 
       case PixelFormat_RGBA32:
       case PixelFormat_BGRA32:
+      case PixelFormat_Grayscale32:
         return 4;
 
       case PixelFormat_Float32:
         assert(sizeof(float) == 4);
         return 4;
 
+      case PixelFormat_RGB48:
+        return 6;
+
       default:
         throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
@@ -1225,8 +1426,15 @@
     {
       encoding = Encoding_Japanese;
     }
-    else if (s == "GB18030")
+    else if (s == "GB18030" || s == "GBK")
     {
+      /**
+       * According to tumashu@163.com, "In China, many dicom file's
+       * 0008,0005 tag is set as "GBK", instead of "GB18030", GBK is a
+       * subset of GB18030, and which is used frequently in China,
+       * suggest support it."
+       * https://groups.google.com/d/msg/orthanc-users/WMM8LMbjpUc/02-1f_yFCgAJ
+       **/
       encoding = Encoding_Chinese;
     }
     /*
@@ -1475,5 +1683,28 @@
       default:
         throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
+  }  
+
+
+  static boost::mutex  defaultEncodingMutex_;  // Should not be necessary
+  static Encoding      defaultEncoding_ = ORTHANC_DEFAULT_DICOM_ENCODING;
+  
+  Encoding GetDefaultDicomEncoding()
+  {
+    boost::mutex::scoped_lock lock(defaultEncodingMutex_);
+    return defaultEncoding_;
   }
+
+  void SetDefaultDicomEncoding(Encoding encoding)
+  {
+    std::string name = EnumerationToString(encoding);
+    
+    {
+      boost::mutex::scoped_lock lock(defaultEncodingMutex_);
+      defaultEncoding_ = encoding;
+    }
+
+    LOG(INFO) << "Default encoding for DICOM was changed to: " << name;
+  }
+
 }
--- a/Resources/Orthanc/Core/Enumerations.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Enumerations.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -199,8 +199,21 @@
      **/
     PixelFormat_Float32 = 6,
 
-    // This is the memory layout for Cairo
-    PixelFormat_BGRA32 = 7
+    // This is the memory layout for Cairo (for internal use in Stone of Orthanc)
+    PixelFormat_BGRA32 = 7,
+
+    /**
+     * {summary}{Graylevel, unsigned 32bpp image.}
+     * {description}{The image is graylevel. Each pixel is unsigned and stored in 4 bytes.}
+     **/
+    PixelFormat_Grayscale32 = 8,
+    
+    /**
+     * {summary}{Color image in RGB48 format.}
+     * {description}{This format describes a color image. The pixels are stored in 6
+     * consecutive bytes. The memory layout is RGB.}
+     **/
+    PixelFormat_RGB48 = 9
   };
 
 
@@ -443,6 +456,81 @@
     ValueRepresentation_NotSupported               // Not supported by Orthanc, or tag not in dictionary
   };
 
+  enum DicomReplaceMode
+  {
+    DicomReplaceMode_InsertIfAbsent,
+    DicomReplaceMode_ThrowIfAbsent,
+    DicomReplaceMode_IgnoreIfAbsent
+  };
+
+  enum DicomToJsonFormat
+  {
+    DicomToJsonFormat_Full,
+    DicomToJsonFormat_Short,
+    DicomToJsonFormat_Human
+  };
+
+  enum DicomToJsonFlags
+  {
+    DicomToJsonFlags_IncludeBinary         = (1 << 0),
+    DicomToJsonFlags_IncludePrivateTags    = (1 << 1),
+    DicomToJsonFlags_IncludeUnknownTags    = (1 << 2),
+    DicomToJsonFlags_IncludePixelData      = (1 << 3),
+    DicomToJsonFlags_ConvertBinaryToAscii  = (1 << 4),
+    DicomToJsonFlags_ConvertBinaryToNull   = (1 << 5),
+
+    // Some predefined combinations
+    DicomToJsonFlags_None     = 0,
+    DicomToJsonFlags_Default  = (DicomToJsonFlags_IncludeBinary |
+                                 DicomToJsonFlags_IncludePixelData | 
+                                 DicomToJsonFlags_IncludePrivateTags | 
+                                 DicomToJsonFlags_IncludeUnknownTags | 
+                                 DicomToJsonFlags_ConvertBinaryToNull)
+  };
+  
+  enum DicomFromJsonFlags
+  {
+    DicomFromJsonFlags_DecodeDataUriScheme = (1 << 0),
+    DicomFromJsonFlags_GenerateIdentifiers = (1 << 1)
+  };
+  
+  enum DicomVersion
+  {
+    DicomVersion_2008,
+    DicomVersion_2017c
+  };
+
+  enum ModalityManufacturer
+  {
+    ModalityManufacturer_Generic,
+    ModalityManufacturer_GenericNoWildcardInDates,
+    ModalityManufacturer_GenericNoUniversalWildcard,
+    ModalityManufacturer_StoreScp,
+    ModalityManufacturer_ClearCanvas,
+    ModalityManufacturer_Dcm4Chee,
+    ModalityManufacturer_Vitrea
+  };
+
+  enum DicomRequestType
+  {
+    DicomRequestType_Echo,
+    DicomRequestType_Find,
+    DicomRequestType_Get,
+    DicomRequestType_Move,
+    DicomRequestType_Store
+  };
+
+  enum TransferSyntax
+  {
+    TransferSyntax_Deflated,
+    TransferSyntax_Jpeg,
+    TransferSyntax_Jpeg2000,
+    TransferSyntax_JpegLossless,
+    TransferSyntax_Jpip,
+    TransferSyntax_Mpeg2,
+    TransferSyntax_Rle
+  };
+
 
   /**
    * WARNING: Do not change the explicit values in the enumerations
@@ -513,6 +601,14 @@
 
   const char* EnumerationToString(PixelFormat format);
 
+  const char* EnumerationToString(ModalityManufacturer manufacturer);
+
+  const char* EnumerationToString(DicomRequestType type);
+
+  const char* EnumerationToString(TransferSyntax syntax);
+
+  const char* EnumerationToString(DicomVersion version);
+
   Encoding StringToEncoding(const char* encoding);
 
   ResourceType StringToResourceType(const char* type);
@@ -525,6 +621,10 @@
                                                   bool throwIfUnsupported);
 
   PhotometricInterpretation StringToPhotometricInterpretation(const char* value);
+
+  ModalityManufacturer StringToModalityManufacturer(const std::string& manufacturer);
+
+  DicomVersion StringToDicomVersion(const std::string& version);
   
   unsigned int GetBytesPerPixel(PixelFormat format);
 
@@ -544,4 +644,8 @@
   bool IsUserContentType(FileContentType type);
 
   bool IsBinaryValueRepresentation(ValueRepresentation vr);
+  
+  Encoding GetDefaultDicomEncoding();
+
+  void SetDefaultDicomEncoding(Encoding encoding);
 }
--- a/Resources/Orthanc/Core/HttpClient.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/HttpClient.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/HttpClient.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/HttpClient.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/ICommand.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/ICommand.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/IDynamicObject.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/IDynamicObject.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/IImageWriter.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/IImageWriter.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/IImageWriter.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/IImageWriter.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/Image.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/Image.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/Image.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/Image.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/ImageAccessor.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/ImageAccessor.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -218,6 +218,10 @@
         ToMatlabStringInternal<uint16_t>(buffer, *this);
         break;
 
+      case PixelFormat_Grayscale32:
+        ToMatlabStringInternal<uint32_t>(buffer, *this);
+        break;
+
       case PixelFormat_SignedGrayscale16:
         ToMatlabStringInternal<int16_t>(buffer, *this);
         break;
--- a/Resources/Orthanc/Core/Images/ImageAccessor.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/ImageAccessor.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/ImageBuffer.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/ImageBuffer.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/ImageBuffer.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/ImageBuffer.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/ImageProcessing.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/ImageProcessing.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -413,6 +413,13 @@
     }
 
     if (target.GetFormat() == PixelFormat_Float32 &&
+        source.GetFormat() == PixelFormat_Grayscale32)
+    {
+      ConvertGrayscaleToFloat<uint32_t>(target, source);
+      return;
+    }
+
+    if (target.GetFormat() == PixelFormat_Float32 &&
         source.GetFormat() == PixelFormat_SignedGrayscale16)
     {
       ConvertGrayscaleToFloat<int16_t>(target, source);
@@ -561,6 +568,26 @@
       return;
     }
 
+    if (target.GetFormat() == PixelFormat_RGB24 &&
+        source.GetFormat() == PixelFormat_RGB48)
+    {
+      for (unsigned int y = 0; y < source.GetHeight(); y++)
+      {
+        const uint16_t* p = reinterpret_cast<const uint16_t*>(source.GetConstRow(y));
+        uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
+        for (unsigned int x = 0; x < source.GetWidth(); x++)
+        {
+          q[0] = p[0] >> 8;
+          q[1] = p[1] >> 8;
+          q[2] = p[2] >> 8;
+          p += 3;
+          q += 3;
+        }
+      }
+
+      return;
+    }
+
     throw OrthancException(ErrorCode_NotImplemented);
   }
 
@@ -579,6 +606,10 @@
         SetInternal<uint16_t>(image, value);
         return;
 
+      case PixelFormat_Grayscale32:
+        SetInternal<uint32_t>(image, value);
+        return;
+
       case PixelFormat_SignedGrayscale16:
         SetInternal<int16_t>(image, value);
         return;
@@ -664,9 +695,9 @@
   }
 
 
-  void ImageProcessing::GetMinMaxValue(int64_t& minValue,
-                                       int64_t& maxValue,
-                                       const ImageAccessor& image)
+  void ImageProcessing::GetMinMaxIntegerValue(int64_t& minValue,
+                                              int64_t& maxValue,
+                                              const ImageAccessor& image)
   {
     switch (image.GetFormat())
     {
@@ -688,6 +719,15 @@
         break;
       }
 
+      case PixelFormat_Grayscale32:
+      {
+        uint32_t a, b;
+        GetMinMaxValueInternal<uint32_t>(a, b, image);
+        minValue = a;
+        maxValue = b;
+        break;
+      }
+
       case PixelFormat_SignedGrayscale16:
       {
         int16_t a, b;
@@ -703,6 +743,28 @@
   }
 
 
+  void ImageProcessing::GetMinMaxFloatValue(float& minValue,
+                                            float& maxValue,
+                                            const ImageAccessor& image)
+  {
+    switch (image.GetFormat())
+    {
+      case PixelFormat_Float32:
+      {
+        assert(sizeof(float) == 32);
+        float a, b;
+        GetMinMaxValueInternal<float>(a, b, image);
+        minValue = a;
+        maxValue = b;
+        break;
+      }
+
+      default:
+        throw OrthancException(ErrorCode_NotImplemented);
+    }
+  }
+
+
 
   void ImageProcessing::AddConstant(ImageAccessor& image,
                                     int64_t value)
--- a/Resources/Orthanc/Core/Images/ImageProcessing.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/ImageProcessing.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -60,9 +60,13 @@
     static void ShiftRight(ImageAccessor& target,
                            unsigned int shift);
 
-    static void GetMinMaxValue(int64_t& minValue,
-                               int64_t& maxValue,
-                               const ImageAccessor& image);
+    static void GetMinMaxIntegerValue(int64_t& minValue,
+                                      int64_t& maxValue,
+                                      const ImageAccessor& image);
+
+    static void GetMinMaxFloatValue(float& minValue,
+                                    float& maxValue,
+                                    const ImageAccessor& image);
 
     static void AddConstant(ImageAccessor& image,
                             int64_t value);
--- a/Resources/Orthanc/Core/Images/JpegErrorManager.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/JpegErrorManager.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/JpegErrorManager.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/JpegErrorManager.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -32,6 +32,14 @@
 
 #pragma once
 
+#if !defined(ORTHANC_ENABLE_JPEG)
+#  error The macro ORTHANC_ENABLE_JPEG must be defined
+#endif
+
+#if ORTHANC_ENABLE_JPEG != 1
+#  error JPEG support must be enabled to include this file
+#endif
+
 #include <string.h>
 #include <stdio.h>
 #include <jpeglib.h>
--- a/Resources/Orthanc/Core/Images/JpegReader.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/JpegReader.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/JpegReader.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/JpegReader.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -33,15 +33,23 @@
 
 #pragma once
 
+#if !defined(ORTHANC_SANDBOXED)
+#  error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_JPEG)
+#  error The macro ORTHANC_ENABLE_JPEG must be defined
+#endif
+
+#if ORTHANC_ENABLE_JPEG != 1
+#  error JPEG support must be enabled to include this file
+#endif
+
 #include "ImageAccessor.h"
 
 #include <string>
 #include <boost/noncopyable.hpp>
 
-#if !defined(ORTHANC_SANDBOXED)
-#  error The macro ORTHANC_SANDBOXED must be defined
-#endif
-
 namespace Orthanc
 {
   class JpegReader : 
--- a/Resources/Orthanc/Core/Images/JpegWriter.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/JpegWriter.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -162,6 +162,7 @@
 #endif
 
 
+#if ORTHANC_SANDBOXED == 0
   void JpegWriter::WriteToMemoryInternal(std::string& jpeg,
                                          unsigned int width,
                                          unsigned int height,
@@ -206,4 +207,5 @@
     jpeg.assign(reinterpret_cast<const char*>(data), size);
     free(data);
   }
+#endif
 }
--- a/Resources/Orthanc/Core/Images/JpegWriter.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/JpegWriter.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -33,6 +33,14 @@
 
 #pragma once
 
+#if !defined(ORTHANC_ENABLE_JPEG)
+#  error The macro ORTHANC_ENABLE_JPEG must be defined
+#endif
+
+#if ORTHANC_ENABLE_JPEG != 1
+#  error JPEG support must be enabled to include this file
+#endif
+
 #include "IImageWriter.h"
 
 namespace Orthanc
--- a/Resources/Orthanc/Core/Images/PngReader.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/PngReader.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/PngReader.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/PngReader.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -33,6 +33,14 @@
 
 #pragma once
 
+#if !defined(ORTHANC_ENABLE_PNG)
+#  error The macro ORTHANC_ENABLE_PNG must be defined
+#endif
+
+#if ORTHANC_ENABLE_PNG != 1
+#  error PNG support must be enabled to include this file
+#endif
+
 #include "ImageAccessor.h"
 
 #include "../Enumerations.h"
--- a/Resources/Orthanc/Core/Images/PngWriter.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/PngWriter.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -248,6 +248,7 @@
 
 
 
+#if ORTHANC_SANDBOXED == 0
   void PngWriter::WriteToMemoryInternal(std::string& png,
                                         unsigned int width,
                                         unsigned int height,
@@ -271,4 +272,5 @@
 
     chunks.Flatten(png);
   }
+#endif
 }
--- a/Resources/Orthanc/Core/Images/PngWriter.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Images/PngWriter.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -33,6 +33,14 @@
 
 #pragma once
 
+#if !defined(ORTHANC_ENABLE_PNG)
+#  error The macro ORTHANC_ENABLE_PNG must be defined
+#endif
+
+#if ORTHANC_ENABLE_PNG != 1
+#  error PNG support must be enabled to include this file
+#endif
+
 #include "IImageWriter.h"
 
 #include <boost/shared_ptr.hpp>
--- a/Resources/Orthanc/Core/Logging.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Logging.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Logging.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Logging.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/BagOfTasks.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/MultiThreading/BagOfTasks.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/Semaphore.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/MultiThreading/Semaphore.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/Semaphore.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/MultiThreading/Semaphore.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/OrthancException.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/OrthancException.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/PrecompiledHeaders.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/PrecompiledHeaders.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/PrecompiledHeaders.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/PrecompiledHeaders.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -50,7 +50,7 @@
 #include <json/value.h>
 
 #if ORTHANC_ENABLE_PUGIXML == 1
-#include <pugixml.hpp>
+#  include <pugixml.hpp>
 #endif
 
 #include "Enumerations.h"
@@ -58,4 +58,21 @@
 #include "OrthancException.h"
 #include "Toolbox.h"
 
+#if ORTHANC_ENABLE_DCMTK == 1
+#  include "DicomParsing/ParsedDicomFile.h"
+
+// Headers from DCMTK used in Orthanc headers 
+#  include <dcmtk/dcmdata/dcdatset.h>
+#  include <dcmtk/dcmdata/dcfilefo.h>
+#  include <dcmtk/dcmdata/dcmetinf.h>
+#  include <dcmtk/dcmdata/dcpixseq.h>
 #endif
+
+#if ORTHANC_ENABLE_DCMTK_NETWORKING == 1
+#  include "DicomNetworking/DicomServer.h"
+
+// Headers from DCMTK used in Orthanc headers 
+#  include <dcmtk/dcmnet/dimse.h>
+#endif
+
+#endif
--- a/Resources/Orthanc/Core/SystemToolbox.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/SystemToolbox.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/SystemToolbox.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/SystemToolbox.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/TemporaryFile.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/TemporaryFile.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/TemporaryFile.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/TemporaryFile.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Toolbox.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Toolbox.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -397,6 +397,7 @@
 #endif
 
 
+#if ORTHANC_ENABLE_LOCALE == 1
   static const char* GetBoostLocaleEncoding(const Encoding sourceEncoding)
   {
     switch (sourceEncoding)
@@ -463,6 +464,7 @@
         throw OrthancException(ErrorCode_NotImplemented);
     }
   }
+#endif
 
 
 #if ORTHANC_ENABLE_LOCALE == 1
@@ -532,7 +534,7 @@
 
     for (size_t i = 0; i < size; i++, p++)
     {
-      if (*p > 127 || (*p != 0 && iscntrl(*p)))
+      if (*p > 127 || *p == 0 || iscntrl(*p))
       {
         return false;
       }
@@ -542,6 +544,12 @@
   }
 
 
+  bool Toolbox::IsAsciiString(const std::string& s)
+  {
+    return IsAsciiString(s.c_str(), s.size());
+  }
+  
+
   std::string Toolbox::ConvertToAscii(const std::string& source)
   {
     std::string result;
--- a/Resources/Orthanc/Core/Toolbox.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/Toolbox.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -152,6 +152,8 @@
     bool IsAsciiString(const void* data,
                        size_t size);
 
+    bool IsAsciiString(const std::string& s);
+
     std::string ConvertToAscii(const std::string& source);
 
     std::string StripSpaces(const std::string& source);
--- a/Resources/Orthanc/Core/WebServiceParameters.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/WebServiceParameters.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/WebServiceParameters.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Core/WebServiceParameters.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/OrthancServer/FromDcmtkBridge.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2020 +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 Osimis, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * In addition, as a special exception, the copyright holders of this
- * program give permission to link the code of its release with the
- * OpenSSL project's "OpenSSL" library (or with modified versions of it
- * that use the same license as the "OpenSSL" library), and distribute
- * the linked executables. You must obey the GNU General Public License
- * in all respects for all of the code used other than "OpenSSL". If you
- * modify file(s) with this exception, you may extend this exception to
- * your version of the file(s), but you are not obligated to do so. If
- * you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files
- * in the program, then also delete it here.
- * 
- * 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "PrecompiledHeadersServer.h"
-
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-
-#include "FromDcmtkBridge.h"
-#include "ToDcmtkBridge.h"
-#include "../Core/Logging.h"
-#include "../Core/SystemToolbox.h"
-#include "../Core/Toolbox.h"
-#include "../Core/TemporaryFile.h"
-#include "../Core/OrthancException.h"
-
-#include <list>
-#include <limits>
-
-#include <boost/lexical_cast.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/algorithm/string/predicate.hpp>
-
-#include <dcmtk/dcmdata/dcdeftag.h>
-#include <dcmtk/dcmdata/dcdicent.h>
-#include <dcmtk/dcmdata/dcdict.h>
-#include <dcmtk/dcmdata/dcfilefo.h>
-#include <dcmtk/dcmdata/dcostrmb.h>
-#include <dcmtk/dcmdata/dcpixel.h>
-#include <dcmtk/dcmdata/dcuid.h>
-#include <dcmtk/dcmdata/dcistrmb.h>
-
-#include <dcmtk/dcmdata/dcvrae.h>
-#include <dcmtk/dcmdata/dcvras.h>
-#include <dcmtk/dcmdata/dcvrat.h>
-#include <dcmtk/dcmdata/dcvrcs.h>
-#include <dcmtk/dcmdata/dcvrda.h>
-#include <dcmtk/dcmdata/dcvrds.h>
-#include <dcmtk/dcmdata/dcvrdt.h>
-#include <dcmtk/dcmdata/dcvrfd.h>
-#include <dcmtk/dcmdata/dcvrfl.h>
-#include <dcmtk/dcmdata/dcvris.h>
-#include <dcmtk/dcmdata/dcvrlo.h>
-#include <dcmtk/dcmdata/dcvrlt.h>
-#include <dcmtk/dcmdata/dcvrpn.h>
-#include <dcmtk/dcmdata/dcvrsh.h>
-#include <dcmtk/dcmdata/dcvrsl.h>
-#include <dcmtk/dcmdata/dcvrss.h>
-#include <dcmtk/dcmdata/dcvrst.h>
-#include <dcmtk/dcmdata/dcvrtm.h>
-#include <dcmtk/dcmdata/dcvrui.h>
-#include <dcmtk/dcmdata/dcvrul.h>
-#include <dcmtk/dcmdata/dcvrus.h>
-#include <dcmtk/dcmdata/dcvrut.h>
-
-
-#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1
-#include <EmbeddedResources.h>
-#endif
-
-
-namespace Orthanc
-{
-  static inline uint16_t GetCharValue(char c)
-  {
-    if (c >= '0' && c <= '9')
-      return c - '0';
-    else if (c >= 'a' && c <= 'f')
-      return c - 'a' + 10;
-    else if (c >= 'A' && c <= 'F')
-      return c - 'A' + 10;
-    else
-      return 0;
-  }
-
-  static inline uint16_t GetTagValue(const char* c)
-  {
-    return ((GetCharValue(c[0]) << 12) + 
-            (GetCharValue(c[1]) << 8) + 
-            (GetCharValue(c[2]) << 4) + 
-            GetCharValue(c[3]));
-  }
-
-
-#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1
-  static void LoadEmbeddedDictionary(DcmDataDictionary& dictionary,
-                                     EmbeddedResources::FileResourceId resource)
-  {
-    std::string content;
-    EmbeddedResources::GetFileResource(content, resource);
-
-    TemporaryFile tmp;
-    tmp.Write(content);
-
-    if (!dictionary.loadDictionary(tmp.GetPath().c_str()))
-    {
-      LOG(ERROR) << "Cannot read embedded dictionary. Under Windows, make sure that " 
-                 << "your TEMP directory does not contain special characters.";
-      throw OrthancException(ErrorCode_InternalError);
-    }
-  }
-                             
-#else
-  static void LoadExternalDictionary(DcmDataDictionary& dictionary,
-                                     const std::string& directory,
-                                     const std::string& filename)
-  {
-    boost::filesystem::path p = directory;
-    p = p / filename;
-
-    LOG(WARNING) << "Loading the external DICOM dictionary " << p;
-
-    if (!dictionary.loadDictionary(p.string().c_str()))
-    {
-      throw OrthancException(ErrorCode_InternalError);
-    }
-  }
-#endif
-
-
-  namespace
-  {
-    class DictionaryLocker
-    {
-    private:
-      DcmDataDictionary& dictionary_;
-
-    public:
-      DictionaryLocker() : dictionary_(dcmDataDict.wrlock())
-      {
-      }
-
-      ~DictionaryLocker()
-      {
-        dcmDataDict.unlock();
-      }
-
-      DcmDataDictionary& operator*()
-      {
-        return dictionary_;
-      }
-
-      DcmDataDictionary* operator->()
-      {
-        return &dictionary_;
-      }
-    };
-  }
-
-
-  void FromDcmtkBridge::InitializeDictionary(bool loadPrivateDictionary)
-  {
-    LOG(INFO) << "Using DCTMK version: " << DCMTK_VERSION_NUMBER;
-    
-    {
-      DictionaryLocker locker;
-
-      locker->clear();
-
-#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1
-      LOG(WARNING) << "Loading the embedded dictionaries";
-      /**
-       * Do not load DICONDE dictionary, it breaks the other tags. The
-       * command "strace storescu 2>&1 |grep dic" shows that DICONDE
-       * dictionary is not loaded by storescu.
-       **/
-      //LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICONDE);
-
-      LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICOM);
-
-      if (loadPrivateDictionary)
-      {
-        LOG(INFO) << "Loading the embedded dictionary of private tags";
-        LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_PRIVATE);
-      }
-      else
-      {
-        LOG(INFO) << "The dictionary of private tags has not been loaded";
-      }
-
-#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__)
-      std::string path = DCMTK_DICTIONARY_DIR;
-
-      const char* env = std::getenv(DCM_DICT_ENVIRONMENT_VARIABLE);
-      if (env != NULL)
-      {
-        path = std::string(env);
-      }
-
-      LoadExternalDictionary(*locker, path, "dicom.dic");
-
-      if (loadPrivateDictionary)
-      {
-        LoadExternalDictionary(*locker, path, "private.dic");
-      }
-      else
-      {
-        LOG(INFO) << "The dictionary of private tags has not been loaded";
-      }
-
-#else
-#error Support your platform here
-#endif
-    }
-
-    /* make sure data dictionary is loaded */
-    if (!dcmDataDict.isDictionaryLoaded())
-    {
-      LOG(ERROR) << "No DICOM dictionary loaded, check environment variable: " << DCM_DICT_ENVIRONMENT_VARIABLE;
-      throw OrthancException(ErrorCode_InternalError);
-    }
-
-    {
-      // Test the dictionary with a simple DICOM tag
-      DcmTag key(0x0010, 0x1030); // This is PatientWeight
-      if (key.getEVR() != EVR_DS)
-      {
-        LOG(ERROR) << "The DICOM dictionary has not been correctly read";
-        throw OrthancException(ErrorCode_InternalError);
-      }
-    }
-  }
-
-
-  void FromDcmtkBridge::RegisterDictionaryTag(const DicomTag& tag,
-                                              ValueRepresentation vr,
-                                              const std::string& name,
-                                              unsigned int minMultiplicity,
-                                              unsigned int maxMultiplicity,
-                                              const std::string& privateCreator)
-  {
-    if (minMultiplicity < 1)
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-
-    bool arbitrary = false;
-    if (maxMultiplicity == 0)
-    {
-      maxMultiplicity = DcmVariableVM;
-      arbitrary = true;
-    }
-    else if (maxMultiplicity < minMultiplicity)
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-    
-    DcmEVR evr = ToDcmtkBridge::Convert(vr);
-
-    LOG(INFO) << "Registering tag in dictionary: " << tag << " " << (DcmVR(evr).getValidVRName()) << " " 
-              << name << " (multiplicity: " << minMultiplicity << "-" 
-              << (arbitrary ? "n" : boost::lexical_cast<std::string>(maxMultiplicity)) << ")";
-
-    std::auto_ptr<DcmDictEntry>  entry;
-    if (privateCreator.empty())
-    {
-      if (tag.GetGroup() % 2 == 1)
-      {
-        char buf[128];
-        sprintf(buf, "Warning: You are registering a private tag (%04x,%04x), "
-                "but no private creator was associated with it", 
-                tag.GetGroup(), tag.GetElement());
-        LOG(WARNING) << buf;
-      }
-
-      entry.reset(new DcmDictEntry(tag.GetGroup(),
-                                   tag.GetElement(),
-                                   evr, name.c_str(),
-                                   static_cast<int>(minMultiplicity),
-                                   static_cast<int>(maxMultiplicity),
-                                   NULL    /* version */,
-                                   OFTrue  /* doCopyString */,
-                                   NULL    /* private creator */));
-    }
-    else
-    {
-      // "Private Data Elements have an odd Group Number that is not
-      // (0001,eeee), (0003,eeee), (0005,eeee), (0007,eeee), or
-      // (FFFF,eeee)."
-      if (tag.GetGroup() % 2 == 0 /* even */ ||
-          tag.GetGroup() == 0x0001 ||
-          tag.GetGroup() == 0x0003 ||
-          tag.GetGroup() == 0x0005 ||
-          tag.GetGroup() == 0x0007 ||
-          tag.GetGroup() == 0xffff)
-      {
-        char buf[128];
-        sprintf(buf, "Trying to register private tag (%04x,%04x), but it must have an odd group >= 0x0009",
-                tag.GetGroup(), tag.GetElement());
-        LOG(ERROR) << buf;
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-      }
-
-      entry.reset(new DcmDictEntry(tag.GetGroup(),
-                                   tag.GetElement(),
-                                   evr, name.c_str(),
-                                   static_cast<int>(minMultiplicity),
-                                   static_cast<int>(maxMultiplicity),
-                                   "private" /* version */,
-                                   OFTrue    /* doCopyString */,
-                                   privateCreator.c_str()));
-    }
-
-    entry->setGroupRangeRestriction(DcmDictRange_Unspecified);
-    entry->setElementRangeRestriction(DcmDictRange_Unspecified);
-
-    {
-      DictionaryLocker locker;
-
-      if (locker->findEntry(name.c_str()))
-      {
-        LOG(ERROR) << "Cannot register two tags with the same symbolic name \"" << name << "\"";
-        throw OrthancException(ErrorCode_AlreadyExistingTag);
-      }
-
-      locker->addEntry(entry.release());
-    }
-  }
-
-
-  Encoding FromDcmtkBridge::DetectEncoding(DcmItem& dataset,
-                                           Encoding defaultEncoding)
-  {
-    Encoding encoding = defaultEncoding;
-
-    OFString tmp;
-    if (dataset.findAndGetOFString(DCM_SpecificCharacterSet, tmp).good())
-    {
-      std::string characterSet = Toolbox::StripSpaces(std::string(tmp.c_str()));
-
-      if (characterSet.empty())
-      {
-        // Empty specific character set tag: Use the default encoding
-      }
-      else if (GetDicomEncoding(encoding, characterSet.c_str()))
-      {
-        // The specific character set is supported by the Orthanc core
-      }
-      else
-      {
-        LOG(WARNING) << "Value of Specific Character Set (0008,0005) is not supported: " << characterSet
-                     << ", fallback to ASCII (remove all special characters)";
-        encoding = Encoding_Ascii;
-      }
-    }
-    else
-    {
-      // No specific character set tag: Use the default encoding
-    }
-
-    return encoding;
-  }
-
-
-  void FromDcmtkBridge::ExtractDicomSummary(DicomMap& target, 
-                                            DcmItem& dataset,
-                                            unsigned int maxStringLength,
-                                            Encoding defaultEncoding)
-  {
-    Encoding encoding = DetectEncoding(dataset, defaultEncoding);
-
-    target.Clear();
-    for (unsigned long i = 0; i < dataset.card(); i++)
-    {
-      DcmElement* element = dataset.getElement(i);
-      if (element && element->isLeaf())
-      {
-        target.SetValue(element->getTag().getGTag(),
-                        element->getTag().getETag(),
-                        ConvertLeafElement(*element, DicomToJsonFlags_Default, maxStringLength, encoding));
-      }
-    }
-  }
-
-
-  DicomTag FromDcmtkBridge::Convert(const DcmTag& tag)
-  {
-    return DicomTag(tag.getGTag(), tag.getETag());
-  }
-
-
-  DicomTag FromDcmtkBridge::GetTag(const DcmElement& element)
-  {
-    return DicomTag(element.getGTag(), element.getETag());
-  }
-
-
-  DicomValue* FromDcmtkBridge::ConvertLeafElement(DcmElement& element,
-                                                  DicomToJsonFlags flags,
-                                                  unsigned int maxStringLength,
-                                                  Encoding encoding)
-  {
-    if (!element.isLeaf())
-    {
-      // This function is only applicable to leaf elements
-      throw OrthancException(ErrorCode_BadParameterType);
-    }
-
-    char *c = NULL;
-    if (element.isaString() &&
-        element.getString(c).good())
-    {
-      if (c == NULL)  // This case corresponds to the empty string
-      {
-        return new DicomValue("", false);
-      }
-      else
-      {
-        std::string s(c);
-        std::string utf8 = Toolbox::ConvertToUtf8(s, encoding);
-
-        if (maxStringLength != 0 &&
-            utf8.size() > maxStringLength)
-        {
-          return new DicomValue;  // Too long, create a NULL value
-        }
-        else
-        {
-          return new DicomValue(utf8, false);
-        }
-      }
-    }
-
-
-    if (element.getVR() == EVR_UN)
-    {
-      // Unknown value representation: Lookup in the dictionary. This
-      // is notably the case for private tags registered with the
-      // "Dictionary" configuration option.
-      DictionaryLocker locker;
-      
-      const DcmDictEntry* entry = locker->findEntry(element.getTag().getXTag(), 
-                                                    element.getTag().getPrivateCreator());
-      if (entry != NULL && 
-          entry->getVR().isaString())
-      {
-        Uint8* data = NULL;
-
-        // At (*), we do not try and convert to UTF-8, as nothing says
-        // the encoding of the private tag is the same as that of the
-        // remaining of the DICOM dataset. Only go for ASCII strings.
-
-        if (element.getUint8Array(data) == EC_Normal &&
-            Toolbox::IsAsciiString(data, element.getLength()))   // (*)
-        {
-          if (data == NULL)
-          {
-            return new DicomValue("", false);   // Empty string
-          }
-          else if (maxStringLength != 0 &&
-                   element.getLength() > maxStringLength)
-          {
-            return new DicomValue;  // Too long, create a NULL value
-          }
-          else
-          {
-            std::string s(reinterpret_cast<const char*>(data), element.getLength());
-            return new DicomValue(s, false);
-          }
-        }
-      }
-    }
-
-
-    try
-    {
-      // http://support.dcmtk.org/docs/dcvr_8h-source.html
-      switch (element.getVR())
-      {
-
-        /**
-         * Deal with binary data (including PixelData).
-         **/
-
-        case EVR_OB:  // other byte
-        case EVR_OF:  // other float
-        case EVR_OW:  // other word
-        case EVR_UN:  // unknown value representation
-        case EVR_ox:  // OB or OW depending on context
-        case EVR_DS:  // decimal string
-        case EVR_IS:  // integer string
-        case EVR_AS:  // age string
-        case EVR_DA:  // date string
-        case EVR_DT:  // date time string
-        case EVR_TM:  // time string
-        case EVR_AE:  // application entity title
-        case EVR_CS:  // code string
-        case EVR_SH:  // short string
-        case EVR_LO:  // long string
-        case EVR_ST:  // short text
-        case EVR_LT:  // long text
-        case EVR_UT:  // unlimited text
-        case EVR_PN:  // person name
-        case EVR_UI:  // unique identifier
-        case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR)
-        case EVR_UNKNOWN2B:  // used internally for elements with unknown VR with 2-byte length field in explicit VR
-        {
-          if (!(flags & DicomToJsonFlags_ConvertBinaryToNull))
-          {
-            Uint8* data = NULL;
-            if (element.getUint8Array(data) == EC_Normal)
-            {
-              return new DicomValue(reinterpret_cast<const char*>(data), element.getLength(), true);
-            }
-          }
-
-          return new DicomValue;
-        }
-    
-        /**
-         * Numeric types
-         **/ 
-      
-        case EVR_SL:  // signed long
-        {
-          Sint32 f;
-          if (dynamic_cast<DcmSignedLong&>(element).getSint32(f).good())
-            return new DicomValue(boost::lexical_cast<std::string>(f), false);
-          else
-            return new DicomValue;
-        }
-
-        case EVR_SS:  // signed short
-        {
-          Sint16 f;
-          if (dynamic_cast<DcmSignedShort&>(element).getSint16(f).good())
-            return new DicomValue(boost::lexical_cast<std::string>(f), false);
-          else
-            return new DicomValue;
-        }
-
-        case EVR_UL:  // unsigned long
-        {
-          Uint32 f;
-          if (dynamic_cast<DcmUnsignedLong&>(element).getUint32(f).good())
-            return new DicomValue(boost::lexical_cast<std::string>(f), false);
-          else
-            return new DicomValue;
-        }
-
-        case EVR_US:  // unsigned short
-        {
-          Uint16 f;
-          if (dynamic_cast<DcmUnsignedShort&>(element).getUint16(f).good())
-            return new DicomValue(boost::lexical_cast<std::string>(f), false);
-          else
-            return new DicomValue;
-        }
-
-        case EVR_FL:  // float single-precision
-        {
-          Float32 f;
-          if (dynamic_cast<DcmFloatingPointSingle&>(element).getFloat32(f).good())
-            return new DicomValue(boost::lexical_cast<std::string>(f), false);
-          else
-            return new DicomValue;
-        }
-
-        case EVR_FD:  // float double-precision
-        {
-          Float64 f;
-          if (dynamic_cast<DcmFloatingPointDouble&>(element).getFloat64(f).good())
-            return new DicomValue(boost::lexical_cast<std::string>(f), false);
-          else
-            return new DicomValue;
-        }
-
-
-        /**
-         * Attribute tag.
-         **/
-
-        case EVR_AT:
-        {
-          DcmTagKey tag;
-          if (dynamic_cast<DcmAttributeTag&>(element).getTagVal(tag, 0).good())
-          {
-            DicomTag t(tag.getGroup(), tag.getElement());
-            return new DicomValue(t.Format(), false);
-          }
-          else
-          {
-            return new DicomValue;
-          }
-        }
-
-
-        /**
-         * Sequence types, should never occur at this point because of
-         * "element.isLeaf()".
-         **/
-
-        case EVR_SQ:  // sequence of items
-          return new DicomValue;
-
-
-          /**
-           * Internal to DCMTK.
-           **/ 
-
-        case EVR_xs:  // SS or US depending on context
-        case EVR_lt:  // US, SS or OW depending on context, used for LUT Data (thus the name)
-        case EVR_na:  // na="not applicable", for data which has no VR
-        case EVR_up:  // up="unsigned pointer", used internally for DICOMDIR suppor
-        case EVR_item:  // used internally for items
-        case EVR_metainfo:  // used internally for meta info datasets
-        case EVR_dataset:  // used internally for datasets
-        case EVR_fileFormat:  // used internally for DICOM files
-        case EVR_dicomDir:  // used internally for DICOMDIR objects
-        case EVR_dirRecord:  // used internally for DICOMDIR records
-        case EVR_pixelSQ:  // used internally for pixel sequences in a compressed image
-        case EVR_pixelItem:  // used internally for pixel items in a compressed image
-        case EVR_PixelData:  // used internally for uncompressed pixeld data
-        case EVR_OverlayData:  // used internally for overlay data
-          return new DicomValue;
-
-
-          /**
-           * Default case.
-           **/ 
-
-        default:
-          return new DicomValue;
-      }
-    }
-    catch (boost::bad_lexical_cast)
-    {
-      return new DicomValue;
-    }
-    catch (std::bad_cast)
-    {
-      return new DicomValue;
-    }
-  }
-
-
-  static Json::Value& PrepareNode(Json::Value& parent,
-                                  DcmElement& element,
-                                  DicomToJsonFormat format)
-  {
-    assert(parent.type() == Json::objectValue);
-
-    DicomTag tag(FromDcmtkBridge::GetTag(element));
-    const std::string formattedTag = tag.Format();
-
-    if (format == DicomToJsonFormat_Short)
-    {
-      parent[formattedTag] = Json::nullValue;
-      return parent[formattedTag];
-    }
-
-    // This code gives access to the name of the private tags
-    std::string tagName = FromDcmtkBridge::GetTagName(element);
-    
-    switch (format)
-    {
-      case DicomToJsonFormat_Human:
-        parent[tagName] = Json::nullValue;
-        return parent[tagName];
-
-      case DicomToJsonFormat_Full:
-      {
-        parent[formattedTag] = Json::objectValue;
-        Json::Value& node = parent[formattedTag];
-
-        if (element.isLeaf())
-        {
-          node["Name"] = tagName;
-
-          if (element.getTag().getPrivateCreator() != NULL)
-          {
-            node["PrivateCreator"] = element.getTag().getPrivateCreator();
-          }
-
-          return node;
-        }
-        else
-        {
-          node["Name"] = tagName;
-          node["Type"] = "Sequence";
-          node["Value"] = Json::nullValue;
-          return node["Value"];
-        }
-      }
-
-      default:
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-
-  static void LeafValueToJson(Json::Value& target,
-                              const DicomValue& value,
-                              DicomToJsonFormat format,
-                              DicomToJsonFlags flags,
-                              unsigned int maxStringLength)
-  {
-    Json::Value* targetValue = NULL;
-    Json::Value* targetType = NULL;
-
-    switch (format)
-    {
-      case DicomToJsonFormat_Short:
-      case DicomToJsonFormat_Human:
-      {
-        assert(target.type() == Json::nullValue);
-        targetValue = &target;
-        break;
-      }      
-
-      case DicomToJsonFormat_Full:
-      {
-        assert(target.type() == Json::objectValue);
-        target["Value"] = Json::nullValue;
-        target["Type"] = Json::nullValue;
-        targetType = &target["Type"];
-        targetValue = &target["Value"];
-        break;
-      }
-
-      default:
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-
-    assert(targetValue != NULL);
-    assert(targetValue->type() == Json::nullValue);
-    assert(targetType == NULL || targetType->type() == Json::nullValue);
-
-    if (value.IsNull())
-    {
-      if (targetType != NULL)
-      {
-        *targetType = "Null";
-      }
-    }
-    else if (value.IsBinary())
-    {
-      if (flags & DicomToJsonFlags_ConvertBinaryToAscii)
-      {
-        *targetValue = Toolbox::ConvertToAscii(value.GetContent());
-      }
-      else
-      {
-        std::string s;
-        value.FormatDataUriScheme(s);
-        *targetValue = s;
-      }
-
-      if (targetType != NULL)
-      {
-        *targetType = "Binary";
-      }
-    }
-    else if (maxStringLength == 0 ||
-             value.GetContent().size() <= maxStringLength)
-    {
-      *targetValue = value.GetContent();
-
-      if (targetType != NULL)
-      {
-        *targetType = "String";
-      }
-    }
-    else
-    {
-      if (targetType != NULL)
-      {
-        *targetType = "TooLong";
-      }
-    }
-  }                              
-
-
-  void FromDcmtkBridge::ElementToJson(Json::Value& parent,
-                                      DcmElement& element,
-                                      DicomToJsonFormat format,
-                                      DicomToJsonFlags flags,
-                                      unsigned int maxStringLength,
-                                      Encoding encoding)
-  {
-    if (parent.type() == Json::nullValue)
-    {
-      parent = Json::objectValue;
-    }
-
-    assert(parent.type() == Json::objectValue);
-    Json::Value& target = PrepareNode(parent, element, format);
-
-    if (element.isLeaf())
-    {
-      // The "0" below lets "LeafValueToJson()" take care of "TooLong" values
-      std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(element, flags, 0, encoding));
-      LeafValueToJson(target, *v, format, flags, maxStringLength);
-    }
-    else
-    {
-      assert(target.type() == Json::nullValue);
-      target = Json::arrayValue;
-
-      // "All subclasses of DcmElement except for DcmSequenceOfItems
-      // are leaf nodes, while DcmSequenceOfItems, DcmItem, DcmDataset
-      // etc. are not." The following dynamic_cast is thus OK.
-      DcmSequenceOfItems& sequence = dynamic_cast<DcmSequenceOfItems&>(element);
-
-      for (unsigned long i = 0; i < sequence.card(); i++)
-      {
-        DcmItem* child = sequence.getItem(i);
-        Json::Value& v = target.append(Json::objectValue);
-        DatasetToJson(v, *child, format, flags, maxStringLength, encoding);
-      }
-    }
-  }
-
-
-  void FromDcmtkBridge::DatasetToJson(Json::Value& parent,
-                                      DcmItem& item,
-                                      DicomToJsonFormat format,
-                                      DicomToJsonFlags flags,
-                                      unsigned int maxStringLength,
-                                      Encoding encoding)
-  {
-    assert(parent.type() == Json::objectValue);
-
-    for (unsigned long i = 0; i < item.card(); i++)
-    {
-      DcmElement* element = item.getElement(i);
-      if (element == NULL)
-      {
-        throw OrthancException(ErrorCode_InternalError);
-      }
-
-      DicomTag tag(FromDcmtkBridge::Convert(element->getTag()));
-
-      /*element->getTag().isPrivate()*/
-      if (tag.IsPrivate() &&
-          !(flags & DicomToJsonFlags_IncludePrivateTags))    
-      {
-        continue;
-      }
-
-      if (!(flags & DicomToJsonFlags_IncludeUnknownTags))
-      {
-        DictionaryLocker locker;
-        if (locker->findEntry(element->getTag(), NULL) == NULL)
-        {
-          continue;
-        }
-      }
-
-      DcmEVR evr = element->getTag().getEVR();
-      if (evr == EVR_OB ||
-          evr == EVR_OF ||
-          evr == EVR_OW ||
-          evr == EVR_UN ||
-          evr == EVR_ox)
-      {
-        // This is a binary tag
-        if ((tag == DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludePixelData)) ||
-            (tag != DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludeBinary)))
-        {
-          continue;
-        }
-      }
-
-      FromDcmtkBridge::ElementToJson(parent, *element, format, flags, maxStringLength, encoding);
-    }
-  }
-
-
-  void FromDcmtkBridge::ExtractDicomAsJson(Json::Value& target, 
-                                           DcmDataset& dataset,
-                                           DicomToJsonFormat format,
-                                           DicomToJsonFlags flags,
-                                           unsigned int maxStringLength,
-                                           Encoding defaultEncoding)
-  {
-    Encoding encoding = DetectEncoding(dataset, defaultEncoding);
-
-    target = Json::objectValue;
-    DatasetToJson(target, dataset, format, flags, maxStringLength, encoding);
-  }
-
-
-  void FromDcmtkBridge::ExtractHeaderAsJson(Json::Value& target, 
-                                            DcmMetaInfo& dataset,
-                                            DicomToJsonFormat format,
-                                            DicomToJsonFlags flags,
-                                            unsigned int maxStringLength)
-  {
-    target = Json::objectValue;
-    DatasetToJson(target, dataset, format, flags, maxStringLength, Encoding_Ascii);
-  }
-
-
-
-  static std::string GetTagNameInternal(DcmTag& tag)
-  {
-    {
-      // Some patches for important tags because of different DICOM
-      // dictionaries between DCMTK versions
-      DicomTag tmp(tag.getGroup(), tag.getElement());
-      std::string n = tmp.GetMainTagsName();
-      if (n.size() != 0)
-      {
-        return n;
-      }
-      // End of patches
-    }
-
-#if 0
-    // This version explicitly calls the dictionary
-    const DcmDataDictionary& dict = dcmDataDict.rdlock();
-    const DcmDictEntry* entry = dict.findEntry(tag, NULL);
-
-    std::string s(DcmTag_ERROR_TagName);
-    if (entry != NULL)
-    {
-      s = std::string(entry->getTagName());
-    }
-
-    dcmDataDict.unlock();
-    return s;
-#else
-    const char* name = tag.getTagName();
-    if (name == NULL)
-    {
-      return DcmTag_ERROR_TagName;
-    }
-    else
-    {
-      return std::string(name);
-    }
-#endif
-  }
-
-
-  std::string FromDcmtkBridge::GetTagName(const DicomTag& t,
-                                          const std::string& privateCreator)
-  {
-    DcmTag tag(t.GetGroup(), t.GetElement());
-
-    if (!privateCreator.empty())
-    {
-      tag.setPrivateCreator(privateCreator.c_str());
-    }
-
-    return GetTagNameInternal(tag);
-  }
-
-
-  std::string FromDcmtkBridge::GetTagName(const DcmElement& element)
-  {
-    // Copy the tag to ensure const-correctness of DcmElement. Note
-    // that the private creator information is also copied.
-    DcmTag tag(element.getTag());  
-
-    return GetTagNameInternal(tag);
-  }
-
-
-
-  DicomTag FromDcmtkBridge::ParseTag(const char* name)
-  {
-    if (strlen(name) == 9 &&
-        isxdigit(name[0]) &&
-        isxdigit(name[1]) &&
-        isxdigit(name[2]) &&
-        isxdigit(name[3]) &&
-        (name[4] == '-' || name[4] == ',') &&
-        isxdigit(name[5]) &&
-        isxdigit(name[6]) &&
-        isxdigit(name[7]) &&
-        isxdigit(name[8]))        
-    {
-      uint16_t group = GetTagValue(name);
-      uint16_t element = GetTagValue(name + 5);
-      return DicomTag(group, element);
-    }
-
-    if (strlen(name) == 8 &&
-        isxdigit(name[0]) &&
-        isxdigit(name[1]) &&
-        isxdigit(name[2]) &&
-        isxdigit(name[3]) &&
-        isxdigit(name[4]) &&
-        isxdigit(name[5]) &&
-        isxdigit(name[6]) &&
-        isxdigit(name[7]))        
-    {
-      uint16_t group = GetTagValue(name);
-      uint16_t element = GetTagValue(name + 4);
-      return DicomTag(group, element);
-    }
-
-#if 0
-    const DcmDataDictionary& dict = dcmDataDict.rdlock();
-    const DcmDictEntry* entry = dict.findEntry(name);
-
-    if (entry == NULL)
-    {
-      dcmDataDict.unlock();
-      throw OrthancException(ErrorCode_UnknownDicomTag);
-    }
-    else
-    {
-      DcmTagKey key = entry->getKey();
-      DicomTag tag(key.getGroup(), key.getElement());
-      dcmDataDict.unlock();
-      return tag;
-    }
-#else
-    DcmTag tag;
-    if (DcmTag::findTagFromName(name, tag).good())
-    {
-      return DicomTag(tag.getGTag(), tag.getETag());
-    }
-    else
-    {
-      throw OrthancException(ErrorCode_UnknownDicomTag);
-    }
-#endif
-  }
-
-
-  bool FromDcmtkBridge::IsUnknownTag(const DicomTag& tag)
-  {
-    DcmTag tmp(tag.GetGroup(), tag.GetElement());
-    return tmp.isUnknownVR();
-  }
-
-
-  void FromDcmtkBridge::ToJson(Json::Value& result,
-                               const DicomMap& values,
-                               bool simplify)
-  {
-    if (result.type() != Json::objectValue)
-    {
-      throw OrthancException(ErrorCode_BadParameterType);
-    }
-
-    result.clear();
-
-    for (DicomMap::Map::const_iterator 
-           it = values.map_.begin(); it != values.map_.end(); ++it)
-    {
-      // TODO Inject PrivateCreator if some is available in the DicomMap?
-      const std::string tagName = GetTagName(it->first, "");
-
-      if (simplify)
-      {
-        if (it->second->IsNull())
-        {
-          result[tagName] = Json::nullValue;
-        }
-        else
-        {
-          // TODO IsBinary
-          result[tagName] = it->second->GetContent();
-        }
-      }
-      else
-      {
-        Json::Value value = Json::objectValue;
-
-        value["Name"] = tagName;
-
-        if (it->second->IsNull())
-        {
-          value["Type"] = "Null";
-          value["Value"] = Json::nullValue;
-        }
-        else
-        {
-          // TODO IsBinary
-          value["Type"] = "String";
-          value["Value"] = it->second->GetContent();
-        }
-
-        result[it->first.Format()] = value;
-      }
-    }
-  }
-
-
-  std::string FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType level)
-  {
-    char uid[100];
-
-    switch (level)
-    {
-      case ResourceType_Patient:
-        // The "PatientID" field is of type LO (Long String), 64
-        // Bytes Maximum. An UUID is of length 36, thus it can be used
-        // as a random PatientID.
-        return SystemToolbox::GenerateUuid();
-
-      case ResourceType_Instance:
-        return dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT);
-
-      case ResourceType_Series:
-        return dcmGenerateUniqueIdentifier(uid, SITE_SERIES_UID_ROOT);
-
-      case ResourceType_Study:
-        return dcmGenerateUniqueIdentifier(uid, SITE_STUDY_UID_ROOT);
-
-      default:
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-  bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer,
-                                           DcmDataset& dataSet)
-  {
-    // Determine the transfer syntax which shall be used to write the
-    // information to the file. We always switch to the Little Endian
-    // syntax, with explicit length.
-
-    // http://support.dcmtk.org/docs/dcxfer_8h-source.html
-
-
-    /**
-     * Note that up to Orthanc 0.7.1 (inclusive), the
-     * "EXS_LittleEndianExplicit" was always used to save the DICOM
-     * dataset into memory. We now keep the original transfer syntax
-     * (if available).
-     **/
-    E_TransferSyntax xfer = dataSet.getOriginalXfer();
-    if (xfer == EXS_Unknown)
-    {
-      // No information about the original transfer syntax: This is
-      // most probably a DICOM dataset that was read from memory.
-      xfer = EXS_LittleEndianExplicit;
-    }
-
-    E_EncodingType encodingType = /*opt_sequenceType*/ EET_ExplicitLength;
-
-    // Create the meta-header information
-    DcmFileFormat ff(&dataSet);
-    ff.validateMetaInfo(xfer);
-    ff.removeInvalidGroups();
-
-    // Create a memory buffer with the proper size
-    {
-      const uint32_t estimatedSize = ff.calcElementLength(xfer, encodingType);  // (*)
-      buffer.resize(estimatedSize);
-    }
-
-    DcmOutputBufferStream ob(&buffer[0], buffer.size());
-
-    // Fill the memory buffer with the meta-header and the dataset
-    ff.transferInit();
-    OFCondition c = ff.write(ob, xfer, encodingType, NULL,
-                             /*opt_groupLength*/ EGL_recalcGL,
-                             /*opt_paddingType*/ EPD_withoutPadding);
-    ff.transferEnd();
-
-    if (c.good())
-    {
-      // The DICOM file is successfully written, truncate the target
-      // buffer if its size was overestimated by (*)
-      ob.flush();
-
-      size_t effectiveSize = static_cast<size_t>(ob.tell());
-      if (effectiveSize < buffer.size())
-      {
-        buffer.resize(effectiveSize);
-      }
-
-      return true;
-    }
-    else
-    {
-      // Error
-      buffer.clear();
-      return false;
-    }
-  }
-
-
-  ValueRepresentation FromDcmtkBridge::LookupValueRepresentation(const DicomTag& tag)
-  {
-    DcmTag t(tag.GetGroup(), tag.GetElement());
-    return Convert(t.getEVR());
-  }
-
-  ValueRepresentation FromDcmtkBridge::Convert(const DcmEVR vr)
-  {
-    switch (vr)
-    {
-      case EVR_AE:
-        return ValueRepresentation_ApplicationEntity;
-
-      case EVR_AS:
-        return ValueRepresentation_AgeString;
-
-      case EVR_AT:
-        return ValueRepresentation_AttributeTag;
-
-      case EVR_CS:
-        return ValueRepresentation_CodeString;
-
-      case EVR_DA:
-        return ValueRepresentation_Date;
-
-      case EVR_DS:
-        return ValueRepresentation_DecimalString;
-
-      case EVR_DT:
-        return ValueRepresentation_DateTime;
-
-      case EVR_FL:
-        return ValueRepresentation_FloatingPointSingle;
-
-      case EVR_FD:
-        return ValueRepresentation_FloatingPointDouble;
-
-      case EVR_IS:
-        return ValueRepresentation_IntegerString;
-
-      case EVR_LO:
-        return ValueRepresentation_LongString;
-
-      case EVR_LT:
-        return ValueRepresentation_LongText;
-
-      case EVR_OB:
-        return ValueRepresentation_OtherByte;
-
-        // Not supported as of DCMTK 3.6.0
-        /*case EVR_OD:
-          return ValueRepresentation_OtherDouble;*/
-
-      case EVR_OF:
-        return ValueRepresentation_OtherFloat;
-
-        // Not supported as of DCMTK 3.6.0
-        /*case EVR_OL:
-          return ValueRepresentation_OtherLong;*/
-
-      case EVR_OW:
-        return ValueRepresentation_OtherWord;
-
-      case EVR_PN:
-        return ValueRepresentation_PersonName;
-
-      case EVR_SH:
-        return ValueRepresentation_ShortString;
-
-      case EVR_SL:
-        return ValueRepresentation_SignedLong;
-
-      case EVR_SQ:
-        return ValueRepresentation_Sequence;
-
-      case EVR_SS:
-        return ValueRepresentation_SignedShort;
-
-      case EVR_ST:
-        return ValueRepresentation_ShortText;
-
-      case EVR_TM:
-        return ValueRepresentation_Time;
-
-        // Not supported as of DCMTK 3.6.0
-        /*case EVR_UC:
-          return ValueRepresentation_UnlimitedCharacters;*/
-
-      case EVR_UI:
-        return ValueRepresentation_UniqueIdentifier;
-
-      case EVR_UL:
-        return ValueRepresentation_UnsignedLong;
-
-      case EVR_UN:
-        return ValueRepresentation_Unknown;
-
-        // Not supported as of DCMTK 3.6.0
-        /*case EVR_UR:
-          return ValueRepresentation_UniversalResource;*/
-
-      case EVR_US:
-        return ValueRepresentation_UnsignedShort;
-
-      case EVR_UT:
-        return ValueRepresentation_UnlimitedText;
-
-      default:
-        return ValueRepresentation_NotSupported;
-    }
-  }
-
-
-  static bool IsBinaryTag(const DcmTag& key)
-  {
-    return (key.isUnknownVR() || 
-            key.getEVR() == EVR_OB ||
-            key.getEVR() == EVR_OF ||
-            key.getEVR() == EVR_OW ||
-            key.getEVR() == EVR_UN ||
-            key.getEVR() == EVR_ox);
-  }
-
-
-  DcmElement* FromDcmtkBridge::CreateElementForTag(const DicomTag& tag)
-  {
-    DcmTag key(tag.GetGroup(), tag.GetElement());
-
-    if (tag.IsPrivate() ||
-        IsBinaryTag(key))
-    {
-      return new DcmOtherByteOtherWord(key);
-    }
-
-    switch (key.getEVR())
-    {
-      // http://support.dcmtk.org/docs/dcvr_8h-source.html
-
-      /**
-       * Binary types, handled above
-       **/
-    
-      case EVR_OB:  // other byte
-      case EVR_OF:  // other float
-      case EVR_OW:  // other word
-      case EVR_UN:  // unknown value representation
-      case EVR_ox:  // OB or OW depending on context
-        throw OrthancException(ErrorCode_InternalError);
-
-
-      /**
-       * String types.
-       * http://support.dcmtk.org/docs/classDcmByteString.html
-       **/
-      
-      case EVR_AS:  // age string
-        return new DcmAgeString(key);
-
-      case EVR_AE:  // application entity title
-        return new DcmApplicationEntity(key);
-
-      case EVR_CS:  // code string
-        return new DcmCodeString(key);        
-
-      case EVR_DA:  // date string
-        return new DcmDate(key);
-        
-      case EVR_DT:  // date time string
-        return new DcmDateTime(key);
-
-      case EVR_DS:  // decimal string
-        return new DcmDecimalString(key);
-
-      case EVR_IS:  // integer string
-        return new DcmIntegerString(key);
-
-      case EVR_TM:  // time string
-        return new DcmTime(key);
-
-      case EVR_UI:  // unique identifier
-        return new DcmUniqueIdentifier(key);
-
-      case EVR_ST:  // short text
-        return new DcmShortText(key);
-
-      case EVR_LO:  // long string
-        return new DcmLongString(key);
-
-      case EVR_LT:  // long text
-        return new DcmLongText(key);
-
-      case EVR_UT:  // unlimited text
-        return new DcmUnlimitedText(key);
-
-      case EVR_SH:  // short string
-        return new DcmShortString(key);
-
-      case EVR_PN:  // person name
-        return new DcmPersonName(key);
-
-        
-      /**
-       * Numerical types
-       **/ 
-      
-      case EVR_SL:  // signed long
-        return new DcmSignedLong(key);
-
-      case EVR_SS:  // signed short
-        return new DcmSignedShort(key);
-
-      case EVR_UL:  // unsigned long
-        return new DcmUnsignedLong(key);
-
-      case EVR_US:  // unsigned short
-        return new DcmUnsignedShort(key);
-
-      case EVR_FL:  // float single-precision
-        return new DcmFloatingPointSingle(key);
-
-      case EVR_FD:  // float double-precision
-        return new DcmFloatingPointDouble(key);
-
-
-      /**
-       * Sequence types, should never occur at this point.
-       **/
-
-      case EVR_SQ:  // sequence of items
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-
-
-      /**
-       * TODO
-       **/
-
-      case EVR_AT:  // attribute tag
-        throw OrthancException(ErrorCode_NotImplemented);
-
-
-      /**
-       * Internal to DCMTK.
-       **/ 
-
-      case EVR_xs:  // SS or US depending on context
-      case EVR_lt:  // US, SS or OW depending on context, used for LUT Data (thus the name)
-      case EVR_na:  // na="not applicable", for data which has no VR
-      case EVR_up:  // up="unsigned pointer", used internally for DICOMDIR suppor
-      case EVR_item:  // used internally for items
-      case EVR_metainfo:  // used internally for meta info datasets
-      case EVR_dataset:  // used internally for datasets
-      case EVR_fileFormat:  // used internally for DICOM files
-      case EVR_dicomDir:  // used internally for DICOMDIR objects
-      case EVR_dirRecord:  // used internally for DICOMDIR records
-      case EVR_pixelSQ:  // used internally for pixel sequences in a compressed image
-      case EVR_pixelItem:  // used internally for pixel items in a compressed image
-      case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR)
-      case EVR_PixelData:  // used internally for uncompressed pixeld data
-      case EVR_OverlayData:  // used internally for overlay data
-      case EVR_UNKNOWN2B:  // used internally for elements with unknown VR with 2-byte length field in explicit VR
-      default:
-        break;
-    }
-
-    throw OrthancException(ErrorCode_InternalError);          
-  }
-
-
-
-  void FromDcmtkBridge::FillElementWithString(DcmElement& element,
-                                              const DicomTag& tag,
-                                              const std::string& utf8Value,
-                                              bool decodeDataUriScheme,
-                                              Encoding dicomEncoding)
-  {
-    std::string binary;
-    const std::string* decoded = &utf8Value;
-
-    if (decodeDataUriScheme &&
-        boost::starts_with(utf8Value, "data:application/octet-stream;base64,"))
-    {
-      std::string mime;
-      if (!Toolbox::DecodeDataUriScheme(mime, binary, utf8Value))
-      {
-        throw OrthancException(ErrorCode_BadFileFormat);
-      }
-
-      decoded = &binary;
-    }
-    else if (dicomEncoding != Encoding_Utf8)
-    {
-      binary = Toolbox::ConvertFromUtf8(utf8Value, dicomEncoding);
-      decoded = &binary;
-    }
-
-    DcmTag key(tag.GetGroup(), tag.GetElement());
-
-    if (tag.IsPrivate() ||
-        IsBinaryTag(key))
-    {
-      if (element.putUint8Array((const Uint8*) decoded->c_str(), decoded->size()).good())
-      {
-        return;
-      }
-      else
-      {
-        throw OrthancException(ErrorCode_InternalError);
-      }
-    }
-
-    bool ok = false;
-    
-    try
-    {
-      switch (key.getEVR())
-      {
-        // http://support.dcmtk.org/docs/dcvr_8h-source.html
-
-        /**
-         * TODO.
-         **/
-
-        case EVR_OB:  // other byte
-        case EVR_OF:  // other float
-        case EVR_OW:  // other word
-        case EVR_AT:  // attribute tag
-          throw OrthancException(ErrorCode_NotImplemented);
-    
-        case EVR_UN:  // unknown value representation
-          throw OrthancException(ErrorCode_ParameterOutOfRange);
-
-
-        /**
-         * String types.
-         **/
-      
-        case EVR_DS:  // decimal string
-        case EVR_IS:  // integer string
-        case EVR_AS:  // age string
-        case EVR_DA:  // date string
-        case EVR_DT:  // date time string
-        case EVR_TM:  // time string
-        case EVR_AE:  // application entity title
-        case EVR_CS:  // code string
-        case EVR_SH:  // short string
-        case EVR_LO:  // long string
-        case EVR_ST:  // short text
-        case EVR_LT:  // long text
-        case EVR_UT:  // unlimited text
-        case EVR_PN:  // person name
-        case EVR_UI:  // unique identifier
-        {
-          ok = element.putString(decoded->c_str()).good();
-          break;
-        }
-
-        
-        /**
-         * Numerical types
-         **/ 
-      
-        case EVR_SL:  // signed long
-        {
-          ok = element.putSint32(boost::lexical_cast<Sint32>(*decoded)).good();
-          break;
-        }
-
-        case EVR_SS:  // signed short
-        {
-          ok = element.putSint16(boost::lexical_cast<Sint16>(*decoded)).good();
-          break;
-        }
-
-        case EVR_UL:  // unsigned long
-        {
-          ok = element.putUint32(boost::lexical_cast<Uint32>(*decoded)).good();
-          break;
-        }
-
-        case EVR_US:  // unsigned short
-        {
-          ok = element.putUint16(boost::lexical_cast<Uint16>(*decoded)).good();
-          break;
-        }
-
-        case EVR_FL:  // float single-precision
-        {
-          ok = element.putFloat32(boost::lexical_cast<float>(*decoded)).good();
-          break;
-        }
-
-        case EVR_FD:  // float double-precision
-        {
-          ok = element.putFloat64(boost::lexical_cast<double>(*decoded)).good();
-          break;
-        }
-
-
-        /**
-         * Sequence types, should never occur at this point.
-         **/
-
-        case EVR_SQ:  // sequence of items
-        {
-          ok = false;
-          break;
-        }
-
-
-        /**
-         * Internal to DCMTK.
-         **/ 
-
-        case EVR_ox:  // OB or OW depending on context
-        case EVR_xs:  // SS or US depending on context
-        case EVR_lt:  // US, SS or OW depending on context, used for LUT Data (thus the name)
-        case EVR_na:  // na="not applicable", for data which has no VR
-        case EVR_up:  // up="unsigned pointer", used internally for DICOMDIR suppor
-        case EVR_item:  // used internally for items
-        case EVR_metainfo:  // used internally for meta info datasets
-        case EVR_dataset:  // used internally for datasets
-        case EVR_fileFormat:  // used internally for DICOM files
-        case EVR_dicomDir:  // used internally for DICOMDIR objects
-        case EVR_dirRecord:  // used internally for DICOMDIR records
-        case EVR_pixelSQ:  // used internally for pixel sequences in a compressed image
-        case EVR_pixelItem:  // used internally for pixel items in a compressed image
-        case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR)
-        case EVR_PixelData:  // used internally for uncompressed pixeld data
-        case EVR_OverlayData:  // used internally for overlay data
-        case EVR_UNKNOWN2B:  // used internally for elements with unknown VR with 2-byte length field in explicit VR
-        default:
-          break;
-      }
-    }
-    catch (boost::bad_lexical_cast&)
-    {
-      ok = false;
-    }
-
-    if (!ok)
-    {
-      LOG(ERROR) << "While creating a DICOM instance, tag (" << tag.Format()
-                 << ") has out-of-range value: \"" << *decoded << "\"";
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-  }
-
-
-  DcmElement* FromDcmtkBridge::FromJson(const DicomTag& tag,
-                                        const Json::Value& value,
-                                        bool decodeDataUriScheme,
-                                        Encoding dicomEncoding)
-  {
-    std::auto_ptr<DcmElement> element;
-
-    switch (value.type())
-    {
-      case Json::stringValue:
-        element.reset(CreateElementForTag(tag));
-        FillElementWithString(*element, tag, value.asString(), decodeDataUriScheme, dicomEncoding);
-        break;
-
-      case Json::nullValue:
-        element.reset(CreateElementForTag(tag));
-        FillElementWithString(*element, tag, "", decodeDataUriScheme, dicomEncoding);
-        break;
-
-      case Json::arrayValue:
-      {
-        DcmTag key(tag.GetGroup(), tag.GetElement());
-        if (key.getEVR() != EVR_SQ)
-        {
-          throw OrthancException(ErrorCode_BadParameterType);
-        }
-
-        DcmSequenceOfItems* sequence = new DcmSequenceOfItems(key);
-        element.reset(sequence);
-        
-        for (Json::Value::ArrayIndex i = 0; i < value.size(); i++)
-        {
-          std::auto_ptr<DcmItem> item(new DcmItem);
-
-          Json::Value::Members members = value[i].getMemberNames();
-          for (Json::Value::ArrayIndex j = 0; j < members.size(); j++)
-          {
-            item->insert(FromJson(ParseTag(members[j]), value[i][members[j]], decodeDataUriScheme, dicomEncoding));
-          }
-
-          sequence->append(item.release());
-        }
-
-        break;
-      }
-
-      default:
-        throw OrthancException(ErrorCode_BadParameterType);
-    }
-
-    return element.release();
-  }
-
-
-  DcmPixelSequence* FromDcmtkBridge::GetPixelSequence(DcmDataset& dataset)
-  {
-    DcmElement *element = NULL;
-    if (!dataset.findAndGetElement(DCM_PixelData, element).good())
-    {
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-
-    DcmPixelData& pixelData = dynamic_cast<DcmPixelData&>(*element);
-    DcmPixelSequence* pixelSequence = NULL;
-    if (!pixelData.getEncapsulatedRepresentation
-        (dataset.getOriginalXfer(), NULL, pixelSequence).good())
-    {
-      return NULL;
-    }
-    else
-    {
-      return pixelSequence;
-    }
-  }
-
-
-  Encoding FromDcmtkBridge::ExtractEncoding(const Json::Value& json,
-                                            Encoding defaultEncoding)
-  {
-    if (json.type() != Json::objectValue)
-    {
-      throw OrthancException(ErrorCode_BadParameterType);
-    }
-
-    Encoding encoding = defaultEncoding;
-
-    const Json::Value::Members tags = json.getMemberNames();
-    
-    // Look for SpecificCharacterSet (0008,0005) in the JSON file
-    for (size_t i = 0; i < tags.size(); i++)
-    {
-      DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]);
-      if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET)
-      {
-        const Json::Value& value = json[tags[i]];
-        if (value.type() != Json::stringValue ||
-            (value.asString().length() != 0 &&
-             !GetDicomEncoding(encoding, value.asCString())))
-        {
-          LOG(ERROR) << "Unknown encoding while creating DICOM from JSON: " << value;
-          throw OrthancException(ErrorCode_BadRequest);
-        }
-
-        if (value.asString().length() == 0)
-        {
-          return defaultEncoding;
-        }
-      }
-    }
-
-    return encoding;
-  } 
-
-
-  static void SetString(DcmDataset& target,
-                        const DcmTag& tag,
-                        const std::string& value)
-  {
-    if (!target.putAndInsertString(tag, value.c_str()).good())
-    {
-      throw OrthancException(ErrorCode_InternalError);
-    }
-  }
-
-
-  DcmDataset* FromDcmtkBridge::FromJson(const Json::Value& json,  // Encoded using UTF-8
-                                        bool generateIdentifiers,
-                                        bool decodeDataUriScheme,
-                                        Encoding defaultEncoding)
-  {
-    std::auto_ptr<DcmDataset> result(new DcmDataset);
-    Encoding encoding = ExtractEncoding(json, defaultEncoding);
-
-    SetString(*result, DCM_SpecificCharacterSet, GetDicomSpecificCharacterSet(encoding));
-
-    const Json::Value::Members tags = json.getMemberNames();
-    
-    bool hasPatientId = false;
-    bool hasStudyInstanceUid = false;
-    bool hasSeriesInstanceUid = false;
-    bool hasSopInstanceUid = false;
-
-    for (size_t i = 0; i < tags.size(); i++)
-    {
-      DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]);
-      const Json::Value& value = json[tags[i]];
-
-      if (tag == DICOM_TAG_PATIENT_ID)
-      {
-        hasPatientId = true;
-      }
-      else if (tag == DICOM_TAG_STUDY_INSTANCE_UID)
-      {
-        hasStudyInstanceUid = true;
-      }
-      else if (tag == DICOM_TAG_SERIES_INSTANCE_UID)
-      {
-        hasSeriesInstanceUid = true;
-      }
-      else if (tag == DICOM_TAG_SOP_INSTANCE_UID)
-      {
-        hasSopInstanceUid = true;
-      }
-
-      if (tag != DICOM_TAG_SPECIFIC_CHARACTER_SET)
-      {
-        std::auto_ptr<DcmElement> element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding));
-        const DcmTagKey& tag = element->getTag();
-
-        result->findAndDeleteElement(tag);
-
-        DcmElement* tmp = element.release();
-        if (!result->insert(tmp, false, false).good())
-        {
-          delete tmp;
-          throw OrthancException(ErrorCode_InternalError);
-        }
-      }
-    }
-
-    if (!hasPatientId &&
-        generateIdentifiers)
-    {
-      SetString(*result, DCM_PatientID, GenerateUniqueIdentifier(ResourceType_Patient));
-    }
-
-    if (!hasStudyInstanceUid &&
-        generateIdentifiers)
-    {
-      SetString(*result, DCM_StudyInstanceUID, GenerateUniqueIdentifier(ResourceType_Study));
-    }
-
-    if (!hasSeriesInstanceUid &&
-        generateIdentifiers)
-    {
-      SetString(*result, DCM_SeriesInstanceUID, GenerateUniqueIdentifier(ResourceType_Series));
-    }
-
-    if (!hasSopInstanceUid &&
-        generateIdentifiers)
-    {
-      SetString(*result, DCM_SOPInstanceUID, GenerateUniqueIdentifier(ResourceType_Instance));
-    }
-
-    return result.release();
-  }
-
-
-  DcmFileFormat* FromDcmtkBridge::LoadFromMemoryBuffer(const void* buffer,
-                                                       size_t size)
-  {
-    DcmInputBufferStream is;
-    if (size > 0)
-    {
-      is.setBuffer(buffer, size);
-    }
-    is.setEos();
-
-    std::auto_ptr<DcmFileFormat> result(new DcmFileFormat);
-
-    result->transferInit();
-    if (!result->read(is).good())
-    {
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-
-    result->loadAllDataIntoMemory();
-    result->transferEnd();
-
-    return result.release();
-  }
-
-
-  void FromDcmtkBridge::FromJson(DicomMap& target,
-                                 const Json::Value& source)
-  {
-    if (source.type() != Json::objectValue)
-    {
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-
-    target.Clear();
-
-    Json::Value::Members members = source.getMemberNames();
-
-    for (size_t i = 0; i < members.size(); i++)
-    {
-      const Json::Value& value = source[members[i]];
-
-      if (value.type() != Json::stringValue)
-      {
-        throw OrthancException(ErrorCode_BadFileFormat);
-      }
-      
-      target.SetValue(ParseTag(members[i]), value.asString(), false);
-    }
-  }
-
-
-  void FromDcmtkBridge::ChangeStringEncoding(DcmItem& dataset,
-                                             Encoding source,
-                                             Encoding target)
-  {
-    // Recursive exploration of a dataset to change the encoding of
-    // each string-like element
-
-    if (source == target)
-    {
-      return;
-    }
-
-    for (unsigned long i = 0; i < dataset.card(); i++)
-    {
-      DcmElement* element = dataset.getElement(i);
-      if (element)
-      {
-        if (element->isLeaf())
-        {
-          char *c = NULL;
-          if (element->isaString() &&
-              element->getString(c).good() && 
-              c != NULL)
-          {
-            std::string a = Toolbox::ConvertToUtf8(c, source);
-            std::string b = Toolbox::ConvertFromUtf8(a, target);
-            element->putString(b.c_str());
-          }
-        }
-        else
-        {
-          // "All subclasses of DcmElement except for DcmSequenceOfItems
-          // are leaf nodes, while DcmSequenceOfItems, DcmItem, DcmDataset
-          // etc. are not." The following dynamic_cast is thus OK.
-          DcmSequenceOfItems& sequence = dynamic_cast<DcmSequenceOfItems&>(*element);
-
-          for (unsigned long j = 0; j < sequence.card(); j++)
-          {
-            ChangeStringEncoding(*sequence.getItem(j), source, target);
-          }
-        }
-      }
-    }
-  }
-
-
-  bool FromDcmtkBridge::LookupTransferSyntax(std::string& result,
-                                             DcmFileFormat& dicom)
-  {
-    const char* value = NULL;
-
-    if (dicom.getMetaInfo() != NULL &&
-        dicom.getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, value).good() &&
-        value != NULL)
-    {
-      result.assign(value);
-      return true;
-    }
-    else
-    {
-      return false;
-    }
-  }
-
-
-#if ORTHANC_ENABLE_LUA == 1
-  void FromDcmtkBridge::ExecuteToDicom(DicomMap& target,
-                                       LuaFunctionCall& call)
-  {
-    Json::Value output;
-    call.ExecuteToJson(output, true /* keep strings */);
-
-    target.Clear();
-
-    if (output.type() == Json::arrayValue &&
-        output.size() == 0)
-    {
-      // This case happens for empty tables
-      return;
-    }
-
-    if (output.type() != Json::objectValue)
-    {
-      LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table";
-      throw OrthancException(ErrorCode_LuaBadOutput);
-    }
-
-    Json::Value::Members members = output.getMemberNames();
-
-    for (size_t i = 0; i < members.size(); i++)
-    {
-      if (output[members[i]].type() != Json::stringValue)
-      {
-        LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table mapping names of DICOM tags to strings";
-        throw OrthancException(ErrorCode_LuaBadOutput);
-      }
-
-      DicomTag tag(ParseTag(members[i]));
-      target.SetValue(tag, output[members[i]].asString(), false);
-    }
-  }
-#endif
-}
--- a/Resources/Orthanc/OrthancServer/FromDcmtkBridge.h	Tue Jan 02 10:01:35 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,224 +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 Osimis, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * In addition, as a special exception, the copyright holders of this
- * program give permission to link the code of its release with the
- * OpenSSL project's "OpenSSL" library (or with modified versions of it
- * that use the same license as the "OpenSSL" library), and distribute
- * the linked executables. You must obey the GNU General Public License
- * in all respects for all of the code used other than "OpenSSL". If you
- * modify file(s) with this exception, you may extend this exception to
- * your version of the file(s), but you are not obligated to do so. If
- * you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files
- * in the program, then also delete it here.
- * 
- * 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "ServerEnumerations.h"
-
-#include "../Core/DicomFormat/DicomElement.h"
-#include "../Core/DicomFormat/DicomMap.h"
-
-#include <dcmtk/dcmdata/dcdatset.h>
-#include <dcmtk/dcmdata/dcmetinf.h>
-#include <dcmtk/dcmdata/dcpixseq.h>
-#include <dcmtk/dcmdata/dcfilefo.h>
-#include <json/json.h>
-
-#if !defined(ORTHANC_BUILD_UNIT_TESTS)
-#  error The macro ORTHANC_BUILD_UNIT_TESTS must be defined
-#endif
-
-#if !defined(ORTHANC_ENABLE_LUA)
-#  error The macro ORTHANC_ENABLE_LUA must be defined
-#endif
-
-#if ORTHANC_BUILD_UNIT_TESTS == 1
-#  include <gtest/gtest_prod.h>
-#endif
-
-#if ORTHANC_ENABLE_LUA == 1
-#  include "../Core/Lua/LuaFunctionCall.h"
-#endif
-
-
-namespace Orthanc
-{
-  class FromDcmtkBridge : public boost::noncopyable
-  {
-#if ORTHANC_BUILD_UNIT_TESTS == 1
-    FRIEND_TEST(FromDcmtkBridge, FromJson);
-#endif
-
-    friend class ParsedDicomFile;
-    friend class Configuration;
-
-  private:
-    FromDcmtkBridge();  // Pure static class
-
-    static void ExtractDicomSummary(DicomMap& target, 
-                                    DcmItem& dataset,
-                                    unsigned int maxStringLength,
-                                    Encoding defaultEncoding);
-
-    static void DatasetToJson(Json::Value& parent,
-                              DcmItem& item,
-                              DicomToJsonFormat format,
-                              DicomToJsonFlags flags,
-                              unsigned int maxStringLength,
-                              Encoding encoding);
-
-    static void ElementToJson(Json::Value& parent,
-                              DcmElement& element,
-                              DicomToJsonFormat format,
-                              DicomToJsonFlags flags,
-                              unsigned int maxStringLength,
-                              Encoding dicomEncoding);
-
-    static void ExtractDicomAsJson(Json::Value& target, 
-                                   DcmDataset& dataset,
-                                   DicomToJsonFormat format,
-                                   DicomToJsonFlags flags,
-                                   unsigned int maxStringLength,
-                                   Encoding defaultEncoding);
-
-    static void ChangeStringEncoding(DcmItem& dataset,
-                                     Encoding source,
-                                     Encoding target);
-
-  public:
-    static void InitializeDictionary(bool loadPrivateDictionary);
-
-    static void RegisterDictionaryTag(const DicomTag& tag,
-                                      ValueRepresentation vr,
-                                      const std::string& name,
-                                      unsigned int minMultiplicity,
-                                      unsigned int maxMultiplicity,
-                                      const std::string& privateCreator);
-
-    static Encoding DetectEncoding(DcmItem& dataset,
-                                   Encoding defaultEncoding);
-
-    static DicomTag Convert(const DcmTag& tag);
-
-    static DicomTag GetTag(const DcmElement& element);
-
-    static bool IsUnknownTag(const DicomTag& tag);
-
-    static DicomValue* ConvertLeafElement(DcmElement& element,
-                                          DicomToJsonFlags flags,
-                                          unsigned int maxStringLength,
-                                          Encoding encoding);
-
-    static void ExtractHeaderAsJson(Json::Value& target, 
-                                    DcmMetaInfo& header,
-                                    DicomToJsonFormat format,
-                                    DicomToJsonFlags flags,
-                                    unsigned int maxStringLength);
-
-    static std::string GetTagName(const DicomTag& tag,
-                                  const std::string& privateCreator);
-
-    static std::string GetTagName(const DcmElement& element);
-
-    static std::string GetTagName(const DicomElement& element)
-    {
-      return GetTagName(element.GetTag(), "");
-    }
-
-    static DicomTag ParseTag(const char* name);
-
-    static DicomTag ParseTag(const std::string& name)
-    {
-      return ParseTag(name.c_str());
-    }
-
-    static bool HasTag(const DicomMap& fields,
-                       const std::string& tagName)
-    {
-      return fields.HasTag(ParseTag(tagName));
-    }
-
-    static const DicomValue& GetValue(const DicomMap& fields,
-                                      const std::string& tagName)
-    {
-      return fields.GetValue(ParseTag(tagName));
-    }
-
-    static void SetValue(DicomMap& target,
-                         const std::string& tagName,
-                         DicomValue* value)
-    {
-      target.SetValue(ParseTag(tagName), value);
-    }
-
-    static void ToJson(Json::Value& result,
-                       const DicomMap& values,
-                       bool simplify);
-
-    static std::string GenerateUniqueIdentifier(ResourceType level);
-
-    static bool SaveToMemoryBuffer(std::string& buffer,
-                                   DcmDataset& dataSet);
-
-    static ValueRepresentation Convert(DcmEVR vr);
-
-    static ValueRepresentation LookupValueRepresentation(const DicomTag& tag);
-
-    static DcmElement* CreateElementForTag(const DicomTag& tag);
-    
-    static void FillElementWithString(DcmElement& element,
-                                      const DicomTag& tag,
-                                      const std::string& utf8alue,  // Encoded using UTF-8
-                                      bool decodeDataUriScheme,
-                                      Encoding dicomEncoding);
-
-    static DcmElement* FromJson(const DicomTag& tag,
-                                const Json::Value& element,  // Encoded using UTF-8
-                                bool decodeDataUriScheme,
-                                Encoding dicomEncoding);
-
-    static DcmPixelSequence* GetPixelSequence(DcmDataset& dataset);
-
-    static Encoding ExtractEncoding(const Json::Value& json,
-                                    Encoding defaultEncoding);
-
-    static DcmDataset* FromJson(const Json::Value& json,  // Encoded using UTF-8
-                                bool generateIdentifiers,
-                                bool decodeDataUriScheme,
-                                Encoding defaultEncoding);
-
-    static DcmFileFormat* LoadFromMemoryBuffer(const void* buffer,
-                                               size_t size);
-
-    static void FromJson(DicomMap& values,
-                         const Json::Value& result);
-
-    static bool LookupTransferSyntax(std::string& result,
-                                     DcmFileFormat& dicom);
-
-#if ORTHANC_ENABLE_LUA == 1
-    static void ExecuteToDicom(DicomMap& target,
-                               LuaFunctionCall& call);
-#endif
-  };
-}
--- a/Resources/Orthanc/OrthancServer/PrecompiledHeadersServer.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/OrthancServer/PrecompiledHeadersServer.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -37,42 +37,6 @@
 
 #if ORTHANC_USE_PRECOMPILED_HEADERS == 1
 
-// DCMTK
-#include <dcmtk/dcmdata/dcchrstr.h>
-#include <dcmtk/dcmdata/dcdeftag.h>
-#include <dcmtk/dcmdata/dcdicent.h>
-#include <dcmtk/dcmdata/dcdict.h>
-#include <dcmtk/dcmdata/dcfilefo.h>
-#include <dcmtk/dcmdata/dcistrmb.h>
-#include <dcmtk/dcmdata/dcistrmf.h>
-#include <dcmtk/dcmdata/dcmetinf.h>
-#include <dcmtk/dcmdata/dcostrmb.h>
-#include <dcmtk/dcmdata/dcpixel.h>
-#include <dcmtk/dcmdata/dcpixseq.h>
-#include <dcmtk/dcmdata/dcpxitem.h>
-#include <dcmtk/dcmdata/dcuid.h>
-#include <dcmtk/dcmdata/dcvrae.h>
-#include <dcmtk/dcmdata/dcvras.h>
-#include <dcmtk/dcmdata/dcvrcs.h>
-#include <dcmtk/dcmdata/dcvrda.h>
-#include <dcmtk/dcmdata/dcvrds.h>
-#include <dcmtk/dcmdata/dcvrdt.h>
-#include <dcmtk/dcmdata/dcvrfd.h>
-#include <dcmtk/dcmdata/dcvrfl.h>
-#include <dcmtk/dcmdata/dcvris.h>
-#include <dcmtk/dcmdata/dcvrlo.h>
-#include <dcmtk/dcmdata/dcvrlt.h>
-#include <dcmtk/dcmdata/dcvrpn.h>
-#include <dcmtk/dcmdata/dcvrsh.h>
-#include <dcmtk/dcmdata/dcvrsl.h>
-#include <dcmtk/dcmdata/dcvrss.h>
-#include <dcmtk/dcmdata/dcvrst.h>
-#include <dcmtk/dcmdata/dcvrtm.h>
-#include <dcmtk/dcmdata/dcvrui.h>
-#include <dcmtk/dcmdata/dcvrul.h>
-#include <dcmtk/dcmdata/dcvrus.h>
-#include <dcmtk/dcmdata/dcvrut.h>
-#include <dcmtk/dcmnet/dcasccfg.h>
-#include <dcmtk/dcmnet/diutil.h>
+#include "ServerContext.h"
 
 #endif
--- a/Resources/Orthanc/OrthancServer/ServerEnumerations.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,517 +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 Osimis, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * In addition, as a special exception, the copyright holders of this
- * program give permission to link the code of its release with the
- * OpenSSL project's "OpenSSL" library (or with modified versions of it
- * that use the same license as the "OpenSSL" library), and distribute
- * the linked executables. You must obey the GNU General Public License
- * in all respects for all of the code used other than "OpenSSL". If you
- * modify file(s) with this exception, you may extend this exception to
- * your version of the file(s), but you are not obligated to do so. If
- * you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files
- * in the program, then also delete it here.
- * 
- * 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "PrecompiledHeadersServer.h"
-#include "ServerEnumerations.h"
-
-#include "../Core/OrthancException.h"
-#include "../Core/EnumerationDictionary.h"
-#include "../Core/Logging.h"
-#include "../Core/Toolbox.h"
-
-#include <boost/thread.hpp>
-
-namespace Orthanc
-{
-  typedef std::map<FileContentType, std::string>  MimeTypes;
-
-  static boost::mutex enumerationsMutex_;
-  static Toolbox::EnumerationDictionary<MetadataType> dictMetadataType_;
-  static Toolbox::EnumerationDictionary<FileContentType> dictContentType_;
-  static MimeTypes  mimeTypes_;
-
-  void InitializeServerEnumerations()
-  {
-    boost::mutex::scoped_lock lock(enumerationsMutex_);
-
-    dictMetadataType_.Clear();
-    dictContentType_.Clear();
-    
-    dictMetadataType_.Add(MetadataType_Instance_IndexInSeries, "IndexInSeries");
-    dictMetadataType_.Add(MetadataType_Instance_ReceptionDate, "ReceptionDate");
-    dictMetadataType_.Add(MetadataType_Instance_RemoteAet, "RemoteAET");
-    dictMetadataType_.Add(MetadataType_Series_ExpectedNumberOfInstances, "ExpectedNumberOfInstances");
-    dictMetadataType_.Add(MetadataType_ModifiedFrom, "ModifiedFrom");
-    dictMetadataType_.Add(MetadataType_AnonymizedFrom, "AnonymizedFrom");
-    dictMetadataType_.Add(MetadataType_LastUpdate, "LastUpdate");
-    dictMetadataType_.Add(MetadataType_Instance_Origin, "Origin");
-    dictMetadataType_.Add(MetadataType_Instance_TransferSyntax, "TransferSyntax");
-    dictMetadataType_.Add(MetadataType_Instance_SopClassUid, "SopClassUid");
-
-    dictContentType_.Add(FileContentType_Dicom, "dicom");
-    dictContentType_.Add(FileContentType_DicomAsJson, "dicom-as-json");
-  }
-
-  void RegisterUserMetadata(int metadata,
-                            const std::string& name)
-  {
-    boost::mutex::scoped_lock lock(enumerationsMutex_);
-
-    MetadataType type = static_cast<MetadataType>(metadata);
-
-    if (metadata < 0 || 
-        !IsUserMetadata(type))
-    {
-      LOG(ERROR) << "A user content type must have index between "
-                 << static_cast<int>(MetadataType_StartUser) << " and "
-                 << static_cast<int>(MetadataType_EndUser) << ", but \""
-                 << name << "\" has index " << metadata;
-        
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-
-    if (dictMetadataType_.Contains(type))
-    {
-      LOG(ERROR) << "Cannot associate user content type \""
-                 << name << "\" with index " << metadata 
-                 << ", as this index is already used";
-        
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-
-    dictMetadataType_.Add(type, name);
-  }
-
-  std::string EnumerationToString(MetadataType type)
-  {
-    // This function MUST return a "std::string" and not "const
-    // char*", as the result is not a static string
-    boost::mutex::scoped_lock lock(enumerationsMutex_);
-    return dictMetadataType_.Translate(type);
-  }
-
-  MetadataType StringToMetadata(const std::string& str)
-  {
-    boost::mutex::scoped_lock lock(enumerationsMutex_);
-    return dictMetadataType_.Translate(str);
-  }
-
-  void RegisterUserContentType(int contentType,
-                               const std::string& name,
-                               const std::string& mime)
-  {
-    boost::mutex::scoped_lock lock(enumerationsMutex_);
-
-    FileContentType type = static_cast<FileContentType>(contentType);
-
-    if (contentType < 0 || 
-        !IsUserContentType(type))
-    {
-      LOG(ERROR) << "A user content type must have index between "
-                 << static_cast<int>(FileContentType_StartUser) << " and "
-                 << static_cast<int>(FileContentType_EndUser) << ", but \""
-                 << name << "\" has index " << contentType;
-        
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-
-    if (dictContentType_.Contains(type))
-    {
-      LOG(ERROR) << "Cannot associate user content type \""
-                 << name << "\" with index " << contentType 
-                 << ", as this index is already used";
-        
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-
-    dictContentType_.Add(type, name);
-    mimeTypes_[type] = mime;
-  }
-
-  std::string EnumerationToString(FileContentType type)
-  {
-    // This function MUST return a "std::string" and not "const
-    // char*", as the result is not a static string
-    boost::mutex::scoped_lock lock(enumerationsMutex_);
-    return dictContentType_.Translate(type);
-  }
-
-  std::string GetFileContentMime(FileContentType type)
-  {
-    if (type >= FileContentType_StartUser &&
-        type <= FileContentType_EndUser)
-    {
-      boost::mutex::scoped_lock lock(enumerationsMutex_);
-      
-      MimeTypes::const_iterator it = mimeTypes_.find(type);
-      if (it != mimeTypes_.end())
-      {
-        return it->second;
-      }
-    }
-
-    switch (type)
-    {
-      case FileContentType_Dicom:
-        return "application/dicom";
-
-      case FileContentType_DicomAsJson:
-        return "application/json";
-
-      default:
-        return "application/octet-stream";
-    }
-  }
-
-  FileContentType StringToContentType(const std::string& str)
-  {
-    boost::mutex::scoped_lock lock(enumerationsMutex_);
-    return dictContentType_.Translate(str);
-  }
-
-  std::string GetBasePath(ResourceType type,
-                          const std::string& publicId)
-  {
-    switch (type)
-    {
-      case ResourceType_Patient:
-        return "/patients/" + publicId;
-
-      case ResourceType_Study:
-        return "/studies/" + publicId;
-
-      case ResourceType_Series:
-        return "/series/" + publicId;
-
-      case ResourceType_Instance:
-        return "/instances/" + publicId;
-      
-      default:
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-  const char* EnumerationToString(SeriesStatus status)
-  {
-    switch (status)
-    {
-      case SeriesStatus_Complete:
-        return "Complete";
-
-      case SeriesStatus_Missing:
-        return "Missing";
-
-      case SeriesStatus_Inconsistent:
-        return "Inconsistent";
-
-      case SeriesStatus_Unknown:
-        return "Unknown";
-
-      default:
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-  const char* EnumerationToString(StoreStatus status)
-  {
-    switch (status)
-    {
-      case StoreStatus_Success:
-        return "Success";
-
-      case StoreStatus_AlreadyStored:
-        return "AlreadyStored";
-
-      case StoreStatus_Failure:
-        return "Failure";
-
-      case StoreStatus_FilteredOut:
-        return "FilteredOut";
-
-      default:
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-
-  const char* EnumerationToString(ChangeType type)
-  {
-    switch (type)
-    {
-      case ChangeType_CompletedSeries:
-        return "CompletedSeries";
-
-      case ChangeType_NewInstance:
-        return "NewInstance";
-
-      case ChangeType_NewPatient:
-        return "NewPatient";
-
-      case ChangeType_NewSeries:
-        return "NewSeries";
-
-      case ChangeType_NewStudy:
-        return "NewStudy";
-
-      case ChangeType_AnonymizedStudy:
-        return "AnonymizedStudy";
-
-      case ChangeType_AnonymizedSeries:
-        return "AnonymizedSeries";
-
-      case ChangeType_ModifiedStudy:
-        return "ModifiedStudy";
-
-      case ChangeType_ModifiedSeries:
-        return "ModifiedSeries";
-
-      case ChangeType_AnonymizedPatient:
-        return "AnonymizedPatient";
-
-      case ChangeType_ModifiedPatient:
-        return "ModifiedPatient";
-
-      case ChangeType_StablePatient:
-        return "StablePatient";
-
-      case ChangeType_StableStudy:
-        return "StableStudy";
-
-      case ChangeType_StableSeries:
-        return "StableSeries";
-
-      case ChangeType_Deleted:
-        return "Deleted";
-
-      case ChangeType_NewChildInstance:
-        return "NewChildInstance";
-
-      case ChangeType_UpdatedAttachment:
-        return "UpdatedAttachment";
-
-      case ChangeType_UpdatedMetadata:
-        return "UpdatedMetadata";
-
-      default:
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-
-  const char* EnumerationToString(ModalityManufacturer manufacturer)
-  {
-    switch (manufacturer)
-    {
-      case ModalityManufacturer_Generic:
-        return "Generic";
-
-      case ModalityManufacturer_GenericNoWildcardInDates:
-        return "GenericNoWildcardInDates";
-
-      case ModalityManufacturer_GenericNoUniversalWildcard:
-        return "GenericNoUniversalWildcard";
-
-      case ModalityManufacturer_StoreScp:
-        return "StoreScp";
-      
-      case ModalityManufacturer_ClearCanvas:
-        return "ClearCanvas";
-      
-      case ModalityManufacturer_Dcm4Chee:
-        return "Dcm4Chee";
-      
-      case ModalityManufacturer_Vitrea:
-        return "Vitrea";
-      
-      default:
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-
-  const char* EnumerationToString(DicomRequestType type)
-  {
-    switch (type)
-    {
-      case DicomRequestType_Echo:
-        return "Echo";
-        break;
-
-      case DicomRequestType_Find:
-        return "Find";
-        break;
-
-      case DicomRequestType_Get:
-        return "Get";
-        break;
-
-      case DicomRequestType_Move:
-        return "Move";
-        break;
-
-      case DicomRequestType_Store:
-        return "Store";
-        break;
-
-      default: 
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-
-
-  ModalityManufacturer StringToModalityManufacturer(const std::string& manufacturer)
-  {
-    ModalityManufacturer result;
-    bool obsolete = false;
-    
-    if (manufacturer == "Generic")
-    {
-      return ModalityManufacturer_Generic;
-    }
-    else if (manufacturer == "GenericNoWildcardInDates")
-    {
-      return ModalityManufacturer_GenericNoWildcardInDates;
-    }
-    else if (manufacturer == "GenericNoUniversalWildcard")
-    {
-      return ModalityManufacturer_GenericNoUniversalWildcard;
-    }
-    else if (manufacturer == "ClearCanvas")
-    {
-      return ModalityManufacturer_ClearCanvas;
-    }
-    else if (manufacturer == "StoreScp")
-    {
-      return ModalityManufacturer_StoreScp;
-    }
-    else if (manufacturer == "Dcm4Chee")
-    {
-      return ModalityManufacturer_Dcm4Chee;
-    }
-    else if (manufacturer == "Vitrea")
-    {
-      return ModalityManufacturer_Vitrea;
-    }
-    else if (manufacturer == "AgfaImpax" ||
-             manufacturer == "SyngoVia")
-    {
-      result = ModalityManufacturer_GenericNoWildcardInDates;
-      obsolete = true;
-    }
-    else if (manufacturer == "EFilm2" ||
-             manufacturer == "MedInria")
-    {
-      result = ModalityManufacturer_Generic;
-      obsolete = true;
-    }
-    else
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-
-    if (obsolete)
-    {
-      LOG(WARNING) << "The \"" << manufacturer << "\" manufacturer is obsolete since "
-                   << "Orthanc 1.3.0. To guarantee compatibility with future Orthanc "
-                   << "releases, you should replace it by \""
-                   << EnumerationToString(result)
-                   << "\" in your configuration file.";
-    }
-
-    return result;
-  }
-
-
-  const char* EnumerationToString(TransferSyntax syntax)
-  {
-    switch (syntax)
-    {
-      case TransferSyntax_Deflated:
-        return "Deflated";
-
-      case TransferSyntax_Jpeg:
-        return "JPEG";
-
-      case TransferSyntax_Jpeg2000:
-        return "JPEG2000";
-
-      case TransferSyntax_JpegLossless:
-        return "JPEG Lossless";
-
-      case TransferSyntax_Jpip:
-        return "JPIP";
-
-      case TransferSyntax_Mpeg2:
-        return "MPEG2";
-
-      case TransferSyntax_Rle:
-        return "RLE";
-
-      default: 
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-
-  const char* EnumerationToString(DicomVersion version)
-  {
-    switch (version)
-    {
-      case DicomVersion_2008:
-        return "2008";
-        break;
-
-      case DicomVersion_2017c:
-        return "2017c";
-        break;
-
-      default: 
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-
-  DicomVersion StringToDicomVersion(const std::string& version)
-  {
-    if (version == "2008")
-    {
-      return DicomVersion_2008;
-    }
-    else if (version == "2017c")
-    {
-      return DicomVersion_2017c;
-    }
-    else
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-  
-  bool IsUserMetadata(MetadataType metadata)
-  {
-    return (metadata >= MetadataType_StartUser &&
-            metadata <= MetadataType_EndUser);
-  }
-}
--- a/Resources/Orthanc/OrthancServer/ServerEnumerations.h	Tue Jan 02 10:01:35 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,244 +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 Osimis, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * In addition, as a special exception, the copyright holders of this
- * program give permission to link the code of its release with the
- * OpenSSL project's "OpenSSL" library (or with modified versions of it
- * that use the same license as the "OpenSSL" library), and distribute
- * the linked executables. You must obey the GNU General Public License
- * in all respects for all of the code used other than "OpenSSL". If you
- * modify file(s) with this exception, you may extend this exception to
- * your version of the file(s), but you are not obligated to do so. If
- * you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files
- * in the program, then also delete it here.
- * 
- * 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#pragma once
-
-#include <string>
-#include <map>
-
-#include "../Core/Enumerations.h"
-#include "../Core/DicomFormat/DicomTag.h"
-
-namespace Orthanc
-{
-  enum SeriesStatus
-  {
-    SeriesStatus_Complete,
-    SeriesStatus_Missing,
-    SeriesStatus_Inconsistent,
-    SeriesStatus_Unknown
-  };
-
-  enum StoreStatus
-  {
-    StoreStatus_Success,
-    StoreStatus_AlreadyStored,
-    StoreStatus_Failure,
-    StoreStatus_FilteredOut     // Removed by NewInstanceFilter
-  };
-
-  enum ModalityManufacturer
-  {
-    ModalityManufacturer_Generic,
-    ModalityManufacturer_GenericNoWildcardInDates,
-    ModalityManufacturer_GenericNoUniversalWildcard,
-    ModalityManufacturer_StoreScp,
-    ModalityManufacturer_ClearCanvas,
-    ModalityManufacturer_Dcm4Chee,
-    ModalityManufacturer_Vitrea
-  };
-
-  enum DicomRequestType
-  {
-    DicomRequestType_Echo,
-    DicomRequestType_Find,
-    DicomRequestType_Get,
-    DicomRequestType_Move,
-    DicomRequestType_Store
-  };
-
-  enum DicomReplaceMode
-  {
-    DicomReplaceMode_InsertIfAbsent,
-    DicomReplaceMode_ThrowIfAbsent,
-    DicomReplaceMode_IgnoreIfAbsent
-  };
-
-  enum TransferSyntax
-  {
-    TransferSyntax_Deflated,
-    TransferSyntax_Jpeg,
-    TransferSyntax_Jpeg2000,
-    TransferSyntax_JpegLossless,
-    TransferSyntax_Jpip,
-    TransferSyntax_Mpeg2,
-    TransferSyntax_Rle
-  };
-
-  enum DicomToJsonFormat
-  {
-    DicomToJsonFormat_Full,
-    DicomToJsonFormat_Short,
-    DicomToJsonFormat_Human
-  };
-
-  enum DicomToJsonFlags
-  {
-    DicomToJsonFlags_IncludeBinary         = (1 << 0),
-    DicomToJsonFlags_IncludePrivateTags    = (1 << 1),
-    DicomToJsonFlags_IncludeUnknownTags    = (1 << 2),
-    DicomToJsonFlags_IncludePixelData      = (1 << 3),
-    DicomToJsonFlags_ConvertBinaryToAscii  = (1 << 4),
-    DicomToJsonFlags_ConvertBinaryToNull   = (1 << 5),
-
-    // Some predefined combinations
-    DicomToJsonFlags_None     = 0,
-    DicomToJsonFlags_Default  = (DicomToJsonFlags_IncludeBinary |
-                                 DicomToJsonFlags_IncludePixelData | 
-                                 DicomToJsonFlags_IncludePrivateTags | 
-                                 DicomToJsonFlags_IncludeUnknownTags | 
-                                 DicomToJsonFlags_ConvertBinaryToNull)
-  };
-
-  enum DicomFromJsonFlags
-  {
-    DicomFromJsonFlags_DecodeDataUriScheme = (1 << 0),
-    DicomFromJsonFlags_GenerateIdentifiers = (1 << 1)
-  };
-
-  enum IdentifierConstraintType
-  {
-    IdentifierConstraintType_Equal,
-    IdentifierConstraintType_SmallerOrEqual,
-    IdentifierConstraintType_GreaterOrEqual,
-    IdentifierConstraintType_Wildcard        /* Case sensitive, "*" or "?" are the only allowed wildcards */
-  };
-
-  enum DicomVersion
-  {
-    DicomVersion_2008,
-    DicomVersion_2017c
-  };
-
-
-  /**
-   * WARNING: Do not change the explicit values in the enumerations
-   * below this point. This would result in incompatible databases
-   * between versions of Orthanc!
-   **/
-
-  enum GlobalProperty
-  {
-    GlobalProperty_DatabaseSchemaVersion = 1,   // Unused in the Orthanc core as of Orthanc 0.9.5
-    GlobalProperty_FlushSleep = 2,
-    GlobalProperty_AnonymizationSequence = 3,
-    GlobalProperty_DatabasePatchLevel = 4       // Reserved for internal use of the database plugins
-  };
-
-  enum MetadataType
-  {
-    MetadataType_Instance_IndexInSeries = 1,
-    MetadataType_Instance_ReceptionDate = 2,
-    MetadataType_Instance_RemoteAet = 3,
-    MetadataType_Series_ExpectedNumberOfInstances = 4,
-    MetadataType_ModifiedFrom = 5,
-    MetadataType_AnonymizedFrom = 6,
-    MetadataType_LastUpdate = 7,
-    MetadataType_Instance_Origin = 8,          // New in Orthanc 0.9.5
-    MetadataType_Instance_TransferSyntax = 9,  // New in Orthanc 1.2.0
-    MetadataType_Instance_SopClassUid = 10,    // New in Orthanc 1.2.0
-
-    // Make sure that the value "65535" can be stored into this enumeration
-    MetadataType_StartUser = 1024,
-    MetadataType_EndUser = 65535
-  };
-
-  enum ChangeType
-  {
-    ChangeType_CompletedSeries = 1,
-    ChangeType_NewInstance = 2,
-    ChangeType_NewPatient = 3,
-    ChangeType_NewSeries = 4,
-    ChangeType_NewStudy = 5,
-    ChangeType_AnonymizedStudy = 6,
-    ChangeType_AnonymizedSeries = 7,
-    ChangeType_ModifiedStudy = 8,
-    ChangeType_ModifiedSeries = 9,
-    ChangeType_AnonymizedPatient = 10,
-    ChangeType_ModifiedPatient = 11,
-    ChangeType_StablePatient = 12,
-    ChangeType_StableStudy = 13,
-    ChangeType_StableSeries = 14,
-    ChangeType_UpdatedAttachment = 15,
-    ChangeType_UpdatedMetadata = 16,
-
-    ChangeType_INTERNAL_LastLogged = 4095,
-
-    // The changes below this point are not logged into the database
-    ChangeType_Deleted = 4096,
-    ChangeType_NewChildInstance = 4097
-  };
-
-
-
-  void InitializeServerEnumerations();
-
-  void RegisterUserMetadata(int metadata,
-                            const std::string& name);
-
-  MetadataType StringToMetadata(const std::string& str);
-
-  std::string EnumerationToString(MetadataType type);
-
-  void RegisterUserContentType(int contentType,
-                               const std::string& name,
-                               const std::string& mime);
-
-  FileContentType StringToContentType(const std::string& str);
-
-  std::string EnumerationToString(FileContentType type);
-
-  std::string GetFileContentMime(FileContentType type);
-
-  std::string GetBasePath(ResourceType type,
-                          const std::string& publicId);
-
-  const char* EnumerationToString(SeriesStatus status);
-
-  const char* EnumerationToString(StoreStatus status);
-
-  const char* EnumerationToString(ChangeType type);
-
-  const char* EnumerationToString(ModalityManufacturer manufacturer);
-
-  const char* EnumerationToString(DicomRequestType type);
-
-  const char* EnumerationToString(TransferSyntax syntax);
-
-  const char* EnumerationToString(DicomVersion version);
-
-  ModalityManufacturer StringToModalityManufacturer(const std::string& manufacturer);
-
-  DicomVersion StringToDicomVersion(const std::string& version);
-
-  bool IsUserMetadata(MetadataType type);
-}
--- a/Resources/Orthanc/OrthancServer/ToDcmtkBridge.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,150 +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 Osimis, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * In addition, as a special exception, the copyright holders of this
- * program give permission to link the code of its release with the
- * OpenSSL project's "OpenSSL" library (or with modified versions of it
- * that use the same license as the "OpenSSL" library), and distribute
- * the linked executables. You must obey the GNU General Public License
- * in all respects for all of the code used other than "OpenSSL". If you
- * modify file(s) with this exception, you may extend this exception to
- * your version of the file(s), but you are not obligated to do so. If
- * you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files
- * in the program, then also delete it here.
- * 
- * 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "PrecompiledHeadersServer.h"
-#include "ToDcmtkBridge.h"
-
-#include <memory>
-#include <dcmtk/dcmnet/diutil.h>
-
-#include "../Core/OrthancException.h"
-
-
-namespace Orthanc
-{
-  DcmEVR ToDcmtkBridge::Convert(ValueRepresentation vr)
-  {
-    switch (vr)
-    {
-      case ValueRepresentation_ApplicationEntity:
-        return EVR_AE;
-
-      case ValueRepresentation_AgeString:
-        return EVR_AS;
-
-      case ValueRepresentation_AttributeTag:
-        return EVR_AT;
-
-      case ValueRepresentation_CodeString:
-        return EVR_CS;
-
-      case ValueRepresentation_Date:
-        return EVR_DA;
-
-      case ValueRepresentation_DecimalString:
-        return EVR_DS;
-
-      case ValueRepresentation_DateTime:
-        return EVR_DT;
-
-      case ValueRepresentation_FloatingPointSingle:
-        return EVR_FL;
-
-      case ValueRepresentation_FloatingPointDouble:
-        return EVR_FD;
-
-      case ValueRepresentation_IntegerString:
-        return EVR_IS;
-
-      case ValueRepresentation_LongString:
-        return EVR_LO;
-
-      case ValueRepresentation_LongText:
-        return EVR_LT;
-
-      case ValueRepresentation_OtherByte:
-        return EVR_OB;
-
-        // Not supported as of DCMTK 3.6.0
-        /*case ValueRepresentation_OtherDouble:
-          return EVR_OD;*/
-
-      case ValueRepresentation_OtherFloat:
-        return EVR_OF;
-
-        // Not supported as of DCMTK 3.6.0
-        /*case ValueRepresentation_OtherLong:
-          return EVR_OL;*/
-
-      case ValueRepresentation_OtherWord:
-        return EVR_OW;
-
-      case ValueRepresentation_PersonName:
-        return EVR_PN;
-
-      case ValueRepresentation_ShortString:
-        return EVR_SH;
-
-      case ValueRepresentation_SignedLong:
-        return EVR_SL;
-
-      case ValueRepresentation_Sequence:
-        return EVR_SQ;
-
-      case ValueRepresentation_SignedShort:
-        return EVR_SS;
-
-      case ValueRepresentation_ShortText:
-        return EVR_ST;
-
-      case ValueRepresentation_Time:
-        return EVR_TM;
-
-        // Not supported as of DCMTK 3.6.0
-        /*case ValueRepresentation_UnlimitedCharacters:
-          return EVR_UC;*/
-
-      case ValueRepresentation_UniqueIdentifier:
-        return EVR_UI;
-
-      case ValueRepresentation_UnsignedLong:
-        return EVR_UL;
-
-      case ValueRepresentation_Unknown:
-        return EVR_UN;
-
-        // Not supported as of DCMTK 3.6.0
-        /*case ValueRepresentation_UniversalResource:
-          return EVR_UR;*/
-
-      case ValueRepresentation_UnsignedShort:
-        return EVR_US;
-
-      case ValueRepresentation_UnlimitedText:
-        return EVR_UT;
-
-      default:
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-}
--- a/Resources/Orthanc/OrthancServer/ToDcmtkBridge.h	Tue Jan 02 10:01:35 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +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 Osimis, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * In addition, as a special exception, the copyright holders of this
- * program give permission to link the code of its release with the
- * OpenSSL project's "OpenSSL" library (or with modified versions of it
- * that use the same license as the "OpenSSL" library), and distribute
- * the linked executables. You must obey the GNU General Public License
- * in all respects for all of the code used other than "OpenSSL". If you
- * modify file(s) with this exception, you may extend this exception to
- * your version of the file(s), but you are not obligated to do so. If
- * you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files
- * in the program, then also delete it here.
- * 
- * 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "../Core/DicomFormat/DicomMap.h"
-#include <dcmtk/dcmdata/dcdatset.h>
-
-namespace Orthanc
-{
-  class ToDcmtkBridge
-  {
-  public:
-    static DcmTagKey Convert(const DicomTag& tag)
-    {
-      return DcmTagKey(tag.GetGroup(), tag.GetElement());
-    }
-
-    static DcmEVR Convert(ValueRepresentation vr);
-  };
-}
--- a/Resources/Orthanc/Plugins/Engine/SharedLibrary.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Engine/SharedLibrary.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Engine/SharedLibrary.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Engine/SharedLibrary.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomPath.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomPath.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomTag.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomTag.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomTag.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/DicomTag.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -94,8 +94,10 @@
   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);
--- a/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -44,13 +44,15 @@
 
 
 
+#if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)
 #define ORTHANC_PLUGINS_VERSION_IS_ABOVE(major, minor, revision) \
   (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER > major ||               \
    (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER == major &&             \
     (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER > minor ||             \
      (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER == minor &&           \
       ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER >= revision))))
-  
+#endif
+
 
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 2, 0)
 // The "OrthancPluginFindMatcher()" primitive was introduced in Orthanc 1.2.0
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginException.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginException.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.h	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.h	Thu Jan 04 10:49:34 2018 +0100
@@ -2,7 +2,7 @@
  * Orthanc - A Lightweight, RESTful DICOM Store
  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017 Osimis, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Resources/CMake/BoostConfiguration.cmake	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Resources/CMake/BoostConfiguration.cmake	Thu Jan 04 10:49:34 2018 +0100
@@ -41,12 +41,18 @@
   ## Parameters for static compilation of Boost 
   ##
   
-  set(BOOST_NAME boost_1_64_0)
-  set(BOOST_BCP_SUFFIX bcpdigest-1.3.0)
-  set(BOOST_MD5 "ecb266cf46adcc7f695ad12685871174")
+  set(BOOST_NAME boost_1_65_1)
+  set(BOOST_BCP_SUFFIX bcpdigest-1.3.1)
+  set(BOOST_MD5 "92c9c603e56bbd7a450a305f08747d90")
   set(BOOST_URL "http://www.orthanc-server.com/downloads/third-party/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz")
   set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME})
 
+  if (IS_DIRECTORY "${BOOST_SOURCES_DIR}")
+    set(FirstRun OFF)
+  else()
+    set(FirstRun ON)
+  endif()
+
   DownloadPackage(${BOOST_MD5} ${BOOST_URL} "${BOOST_SOURCES_DIR}")
 
 
@@ -78,7 +84,22 @@
     ${BOOST_SOURCES_DIR}/libs/system/src/error_code.cpp
     )
 
+  if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
+    add_definitions(-DBOOST_SYSTEM_USE_STRERROR=1)
+    
+    execute_process(
+      COMMAND ${PATCH_EXECUTABLE} -p0 -N -i
+      ${ORTHANC_ROOT}/Resources/Patches/boost-1.65.1-linux-standard-base.patch
+      WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+      RESULT_VARIABLE Failure
+      )
 
+    if (FirstRun AND Failure)
+      message(FATAL_ERROR "Error while patching a file")
+    endif()
+  endif()
+
+  
   ##
   ## Configuration of boost::thread
   ##
@@ -199,13 +220,29 @@
       ${BOOST_SOURCES_DIR}/libs/locale/src/util/locale_data.cpp
       )        
 
-    if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
-        CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR
-        CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
-        CMAKE_SYSTEM_NAME STREQUAL "kFreeBSD" OR
-        CMAKE_SYSTEM_NAME STREQUAL "PNaCl" OR
-        CMAKE_SYSTEM_NAME STREQUAL "NaCl32" OR
-        CMAKE_SYSTEM_NAME STREQUAL "NaCl64")
+    if (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR
+        CMAKE_SYSTEM_VERSION STREQUAL "LinuxStandardBase")
+      list(APPEND BOOST_SOURCES
+        ${BOOST_SOURCES_DIR}/libs/locale/src/std/codecvt.cpp
+        ${BOOST_SOURCES_DIR}/libs/locale/src/std/collate.cpp
+        ${BOOST_SOURCES_DIR}/libs/locale/src/std/converter.cpp
+        ${BOOST_SOURCES_DIR}/libs/locale/src/std/numeric.cpp
+        ${BOOST_SOURCES_DIR}/libs/locale/src/std/std_backend.cpp
+        )
+
+      add_definitions(
+        -DBOOST_LOCALE_WITH_ICONV=1
+        -DBOOST_LOCALE_NO_WINAPI_BACKEND=1
+        -DBOOST_LOCALE_NO_POSIX_BACKEND=1
+        )
+      
+    elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+            CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR
+            CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
+            CMAKE_SYSTEM_NAME STREQUAL "kFreeBSD" OR
+            CMAKE_SYSTEM_NAME STREQUAL "PNaCl" OR
+            CMAKE_SYSTEM_NAME STREQUAL "NaCl32" OR
+            CMAKE_SYSTEM_NAME STREQUAL "NaCl64")
       list(APPEND BOOST_SOURCES
         ${BOOST_SOURCES_DIR}/libs/locale/src/posix/codecvt.cpp
         ${BOOST_SOURCES_DIR}/libs/locale/src/posix/collate.cpp
@@ -220,21 +257,6 @@
         -DBOOST_LOCALE_NO_STD_BACKEND=1
         )
       
-    elseif (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
-      list(APPEND BOOST_SOURCES
-        ${BOOST_SOURCES_DIR}/libs/locale/src/std/codecvt.cpp
-        ${BOOST_SOURCES_DIR}/libs/locale/src/std/collate.cpp
-        ${BOOST_SOURCES_DIR}/libs/locale/src/std/converter.cpp
-        ${BOOST_SOURCES_DIR}/libs/locale/src/std/numeric.cpp
-        ${BOOST_SOURCES_DIR}/libs/locale/src/std/std_backend.cpp
-        )
-
-      add_definitions(
-        -DBOOST_LOCALE_WITH_ICONV=1
-        -DBOOST_LOCALE_NO_WINAPI_BACKEND=1
-        -DBOOST_LOCALE_NO_POSIX_BACKEND=1
-        )
-      
     elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
       list(APPEND BOOST_SOURCES
         ${BOOST_SOURCES_DIR}/libs/locale/src/win32/collate.cpp
--- a/Resources/Orthanc/Resources/CMake/Compiler.cmake	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Resources/CMake/Compiler.cmake	Thu Jan 04 10:49:34 2018 +0100
@@ -1,6 +1,7 @@
 # This file sets all the compiler-related flags
 
-if (CMAKE_CROSSCOMPILING)
+if (CMAKE_CROSSCOMPILING OR
+    "${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
   # Cross-compilation necessarily implies standalone and static build
   SET(STATIC_BUILD ON)
   SET(STANDALONE_BUILD ON)
@@ -87,7 +88,7 @@
   # Remove the "-rdynamic" option
   # http://www.mail-archive.com/cmake@cmake.org/msg08837.html
   set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
-  link_libraries(uuid pthread)
+  link_libraries(pthread)
 
   if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
     link_libraries(rt)
@@ -117,11 +118,6 @@
       )
   endif()
 
-  CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H)
-  if (NOT HAVE_UUID_H)
-    message(FATAL_ERROR "Please install the uuid-dev package (or e2fsprogs if OpenBSD)")
-  endif()
-
 elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
   if (MSVC)
     message("MSVC compiler version = " ${MSVC_VERSION} "\n")
@@ -174,23 +170,14 @@
     )
   link_libraries(iconv)
 
-  CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H)
-  if (NOT HAVE_UUID_H)
-    message(FATAL_ERROR "Please install the uuid-dev package")
-  endif()
+elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
+  message("Building using Emscripten (for WebAssembly or asm.js targets)")
 
 else()
   message(FATAL_ERROR "Support your platform here")
 endif()
 
 
-if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
-  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -I${LSB_PATH}/include")
-  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -nostdinc++ -I${LSB_PATH}/include -I${LSB_PATH}/include/c++ -I${LSB_PATH}/include/c++/backward -fpermissive")
-  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -L${LSB_LIBPATH}")
-endif()
-
-
 if (DEFINED ENABLE_PROFILING AND ENABLE_PROFILING)
   if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
     message(WARNING "Enabling profiling on a non-debug build will not produce full information")
@@ -208,6 +195,21 @@
 endif()
 
 
+if (CMAKE_COMPILER_IS_GNUCXX)
+  # "When creating a static library using binutils (ar) and there
+  # exist a duplicate object name (e.g. a/Foo.cpp.o, b/Foo.cpp.o), the
+  # resulting static library can end up having only one of the
+  # duplicate objects. [...] This bug only happens if there are many
+  # objects." The trick consists in replacing the "r" argument
+  # ("replace") provided to "ar" (as used in CMake < 3.1) by the "q"
+  # argument ("quick append"). This is because of the fact that CMake
+  # will invoke "ar" several times with several batches of ".o"
+  # objects, and using "r" would overwrite symbols defined in
+  # preceding batches. https://cmake.org/Bug/view.php?id=14874
+  set(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> <LINK_FLAGS> q <TARGET> <OBJECTS>")
+endif()
+
+
 if (STATIC_BUILD)
   add_definitions(-DORTHANC_STATIC=1)
 else()
--- a/Resources/Orthanc/Resources/CMake/DcmtkConfiguration.cmake	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Resources/CMake/DcmtkConfiguration.cmake	Thu Jan 04 10:49:34 2018 +0100
@@ -9,8 +9,6 @@
     SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.0)
     SET(DCMTK_URL "http://www.orthanc-server.com/downloads/third-party/dcmtk-3.6.0.zip")
     SET(DCMTK_MD5 "219ad631b82031806147e4abbfba4fa4")
-    SET(DCMTK_PATCH_SPEED "${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-speed.patch")
-    SET(DCMTK_PATCH_MINGW64 "${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-mingw64.patch")
   else()
     SET(DCMTK_VERSION_NUMBER 362)
     SET(DCMTK_PACKAGE_VERSION "3.6.2")
@@ -99,23 +97,28 @@
     endif()
   ENDIF()
   
+  if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
+    SET(DCMTK_ENABLE_CHARSET_CONVERSION "iconv" CACHE STRING "")
+    SET(HAVE_PROTOTYPE_STD__ISINF 1 CACHE INTERNAL "")
+    SET(HAVE_PROTOTYPE_STD__ISNAN 1 CACHE INTERNAL "")
+    SET(HAVE_SYS_GETTID 0 CACHE INTERNAL "")
+
+    execute_process(
+      COMMAND ${PATCH_EXECUTABLE} -p0 -N -i
+      ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.2-linux-standard-base.patch
+      WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+      RESULT_VARIABLE Failure
+      )
+
+    if (FirstRun AND Failure)
+      message(FATAL_ERROR "Error while patching a file")
+    endif()
+  endif()
+
   SET(DCMTK_SOURCE_DIR ${DCMTK_SOURCES_DIR})
   include(${DCMTK_SOURCES_DIR}/CMake/CheckFunctionWithHeaderExists.cmake)
   include(${DCMTK_SOURCES_DIR}/CMake/GenerateDCMTKConfigure.cmake)
 
-  if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
-    set(HAVE_SSTREAM 1)
-    set(HAVE_PROTOTYPE_BZERO 1)
-    set(HAVE_PROTOTYPE_GETHOSTNAME 1)
-    set(HAVE_PROTOTYPE_GETSOCKOPT 1)
-    set(HAVE_PROTOTYPE_SETSOCKOPT 1)
-    set(HAVE_PROTOTYPE_CONNECT 1)
-    set(HAVE_PROTOTYPE_BIND 1)
-    set(HAVE_PROTOTYPE_ACCEPT 1)
-    set(HAVE_PROTOTYPE_SETSOCKNAME 1)
-    set(HAVE_PROTOTYPE_GETSOCKNAME 1)
-  endif()
-
   set(DCMTK_PACKAGE_VERSION_SUFFIX "")
   set(DCMTK_PACKAGE_VERSION_NUMBER ${DCMTK_VERSION_NUMBER})
 
@@ -151,7 +154,7 @@
       )
   endif()
 
-  if (ENABLE_JPEG)
+  if (ENABLE_DCMTK_JPEG)
     AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc DCMTK_SOURCES)
     AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpeg/libijg8 DCMTK_SOURCES)
     AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpeg/libijg12 DCMTK_SOURCES)
@@ -179,7 +182,7 @@
   endif()
 
 
-  if (ENABLE_JPEG_LOSSLESS)
+  if (ENABLE_DCMTK_JPEG_LOSSLESS)
     AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpls/libsrc DCMTK_SOURCES)
     AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpls/libcharls DCMTK_SOURCES)
     include_directories(
@@ -223,7 +226,8 @@
         USE_DCMTK_360)
       # This is a patch for MinGW64
       execute_process(
-        COMMAND ${PATCH_EXECUTABLE} -p0 -N -i ${DCMTK_PATCH_MINGW64}
+        COMMAND ${PATCH_EXECUTABLE} -p0 -N -i
+        ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-mingw64.patch
         WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
         RESULT_VARIABLE Failure
         )
--- a/Resources/Orthanc/Resources/CMake/JsonCppConfiguration.cmake	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Resources/CMake/JsonCppConfiguration.cmake	Thu Jan 04 10:49:34 2018 +0100
@@ -48,9 +48,10 @@
       JSONCPP_VERSION_MAJOR ${JSONCPP_VERSION_MAJOR1})
     message("JsonCpp major version: ${JSONCPP_VERSION_MAJOR}")
 
-    if (CMAKE_COMPILER_IS_GNUCXX AND 
+    if ((CMAKE_COMPILER_IS_GNUCXX OR
+          "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") AND 
         JSONCPP_VERSION_MAJOR GREATER 0)
-      message("Switching to C++11 standard, as version of JsonCpp is >= 1.0.0")
+      message("Switching to C++11 standard in gcc/clang, as version of JsonCpp is >= 1.0.0")
       set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-deprecated-declarations")
     endif()
   else()
--- a/Resources/Orthanc/Resources/CMake/LibCurlConfiguration.cmake	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Resources/CMake/LibCurlConfiguration.cmake	Thu Jan 04 10:49:34 2018 +0100
@@ -1,10 +1,29 @@
 if (STATIC_BUILD OR NOT USE_SYSTEM_CURL)
-  SET(CURL_SOURCES_DIR ${CMAKE_BINARY_DIR}/curl-7.50.3)
-  SET(CURL_URL "http://www.orthanc-server.com/downloads/third-party/curl-7.50.3.tar.gz")
-  SET(CURL_MD5 "870e16fd88a88b52e26a4f04dfc161db")
+  SET(CURL_SOURCES_DIR ${CMAKE_BINARY_DIR}/curl-7.57.0)
+  SET(CURL_URL "http://www.orthanc-server.com/downloads/third-party/curl-7.57.0.tar.gz")
+  SET(CURL_MD5 "c7aab73aaf5e883ca1d7518f93649dc2")
 
+  if (IS_DIRECTORY "${CURL_SOURCES_DIR}")
+    set(FirstRun OFF)
+  else()
+    set(FirstRun ON)
+  endif()
+  
   DownloadPackage(${CURL_MD5} ${CURL_URL} "${CURL_SOURCES_DIR}")
 
+  if (FirstRun)
+    execute_process(
+      COMMAND ${PATCH_EXECUTABLE} -p0 -N -i
+      ${ORTHANC_ROOT}/Resources/Patches/curl-7.57.0-cmake.patch
+      WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+      RESULT_VARIABLE Failure
+      )
+    
+    if (Failure)
+      message(FATAL_ERROR "Error while patching a file")
+    endif()
+  endif()
+  
   include_directories(
     ${CURL_SOURCES_DIR}/include
     )
@@ -42,7 +61,7 @@
   endif()
 
   if (NOT EXISTS "${CURL_SOURCES_DIR}/lib/curl_config.h")
-    file(WRITE ${CURL_SOURCES_DIR}/lib/curl_config.h "")
+    #file(WRITE ${CURL_SOURCES_DIR}/lib/curl_config.h "")
 
     file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/vauth.h "#include \"../vauth.h\"\n")
     file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/digest.h "#include \"../digest.h\"\n")
@@ -70,48 +89,234 @@
 
     set_property(
       SOURCE ${CURL_SOURCES}
-      PROPERTY COMPILE_DEFINITIONS "HAVE_TIME_H;HAVE_STRUCT_TIMEVAL;HAVE_SYS_STAT_H;HAVE_SOCKET;HAVE_STRUCT_SOCKADDR_STORAGE;HAVE_SYS_SOCKET_H;HAVE_SOCKET;HAVE_SYS_SOCKET_H;HAVE_NETINET_IN_H;HAVE_NETDB_H;HAVE_FCNTL_O_NONBLOCK;HAVE_FCNTL_H;HAVE_SELECT;HAVE_ERRNO_H;HAVE_SEND;HAVE_RECV;HAVE_LONGLONG;OS=\"${TMP_OS}\""
+      PROPERTY COMPILE_DEFINITIONS "HAVE_CONFIG_H=1;OS=\"${TMP_OS}\""
       )
+   
+    include(${CURL_SOURCES_DIR}/CMake/Macros.cmake)
+
+    check_include_file_concat("alloca.h"         HAVE_ALLOCA_H)
+    check_include_file_concat("arpa/inet.h"      HAVE_ARPA_INET_H)
+    check_include_file_concat("arpa/tftp.h"      HAVE_ARPA_TFTP_H)
+    check_include_file_concat("assert.h"         HAVE_ASSERT_H)
+    check_include_file_concat("crypto.h"         HAVE_CRYPTO_H)
+    check_include_file_concat("des.h"            HAVE_DES_H)
+    check_include_file_concat("dlfcn.h"          HAVE_DLFCN_H)
+    check_include_file_concat("err.h"            HAVE_ERR_H)
+    check_include_file_concat("errno.h"          HAVE_ERRNO_H)
+    check_include_file_concat("fcntl.h"          HAVE_FCNTL_H)
+    check_include_file_concat("idn2.h"           HAVE_IDN2_H)
+    check_include_file_concat("ifaddrs.h"        HAVE_IFADDRS_H)
+    check_include_file_concat("inttypes.h"       HAVE_INTTYPES_H)
+    check_include_file_concat("io.h"             HAVE_IO_H)
+    check_include_file_concat("krb.h"            HAVE_KRB_H)
+    check_include_file_concat("libgen.h"         HAVE_LIBGEN_H)
+    check_include_file_concat("limits.h"         HAVE_LIMITS_H)
+    check_include_file_concat("locale.h"         HAVE_LOCALE_H)
+    check_include_file_concat("malloc.h"         HAVE_MALLOC_H)
+    check_include_file_concat("memory.h"         HAVE_MEMORY_H)
+    check_include_file_concat("net/if.h"         HAVE_NET_IF_H)
+    check_include_file_concat("netdb.h"          HAVE_NETDB_H)
+    check_include_file_concat("netinet/if_ether.h" HAVE_NETINET_IF_ETHER_H)
+    check_include_file_concat("netinet/in.h"     HAVE_NETINET_IN_H)
+    check_include_file_concat("netinet/tcp.h"    HAVE_NETINET_TCP_H)
+    check_include_file_concat("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H)
+    check_include_file_concat("openssl/engine.h" HAVE_OPENSSL_ENGINE_H)
+    check_include_file_concat("openssl/err.h"    HAVE_OPENSSL_ERR_H)
+    check_include_file_concat("openssl/pem.h"    HAVE_OPENSSL_PEM_H)
+    check_include_file_concat("openssl/rand.h"   HAVE_OPENSSL_RAND_H)
+    check_include_file_concat("openssl/rsa.h"    HAVE_OPENSSL_RSA_H)
+    check_include_file_concat("openssl/ssl.h"    HAVE_OPENSSL_SSL_H)
+    check_include_file_concat("openssl/x509.h"   HAVE_OPENSSL_X509_H)
+    check_include_file_concat("pem.h"            HAVE_PEM_H)
+    check_include_file_concat("poll.h"           HAVE_POLL_H)
+    check_include_file_concat("process.h"        HAVE_PROCESS_H)
+    check_include_file_concat("pwd.h"            HAVE_PWD_H)
+    check_include_file_concat("rsa.h"            HAVE_RSA_H)
+    check_include_file_concat("setjmp.h"         HAVE_SETJMP_H)
+    check_include_file_concat("sgtty.h"          HAVE_SGTTY_H)
+    check_include_file_concat("signal.h"         HAVE_SIGNAL_H)
+    check_include_file_concat("sockio.h"         HAVE_SOCKIO_H)
+    check_include_file_concat("ssl.h"            HAVE_SSL_H)
+    check_include_file_concat("stdbool.h"        HAVE_STDBOOL_H)
+    check_include_file_concat("stddef.h"         HAVE_STDDEF_H)
+    check_include_file_concat("stdint.h"         HAVE_STDINT_H)
+    check_include_file_concat("stdint.h"         HAVE_STDINT_H)
+    check_include_file_concat("stdio.h"          HAVE_STDIO_H)
+    check_include_file_concat("stdio.h"          HAVE_STDIO_H)
+    check_include_file_concat("stdlib.h"         HAVE_STDLIB_H)
+    check_include_file_concat("string.h"         HAVE_STRING_H)
+    check_include_file_concat("strings.h"        HAVE_STRINGS_H)
+    check_include_file_concat("stropts.h"        HAVE_STROPTS_H)
+    check_include_file_concat("sys/filio.h"      HAVE_SYS_FILIO_H)
+    check_include_file_concat("sys/ioctl.h"      HAVE_SYS_IOCTL_H)
+    check_include_file_concat("sys/param.h"      HAVE_SYS_PARAM_H)
+    check_include_file_concat("sys/poll.h"       HAVE_SYS_POLL_H)
+    check_include_file_concat("sys/resource.h"   HAVE_SYS_RESOURCE_H)
+    check_include_file_concat("sys/select.h"     HAVE_SYS_SELECT_H)
+    check_include_file_concat("sys/socket.h"     HAVE_SYS_SOCKET_H)
+    check_include_file_concat("sys/sockio.h"     HAVE_SYS_SOCKIO_H)
+    check_include_file_concat("sys/stat.h"       HAVE_SYS_STAT_H)
+    check_include_file_concat("sys/time.h"       HAVE_SYS_TIME_H)
+    check_include_file_concat("sys/types.h"      HAVE_SYS_TYPES_H)
+    check_include_file_concat("sys/uio.h"        HAVE_SYS_UIO_H)
+    check_include_file_concat("sys/un.h"         HAVE_SYS_UN_H)
+    check_include_file_concat("sys/utime.h"      HAVE_SYS_UTIME_H)
+    check_include_file_concat("sys/utsname.h"    HAVE_SYS_UTSNAME_H)
+    check_include_file_concat("sys/xattr.h"      HAVE_SYS_XATTR_H)
+    check_include_file_concat("termio.h"         HAVE_TERMIO_H)
+    check_include_file_concat("termios.h"        HAVE_TERMIOS_H)
+    check_include_file_concat("time.h"           HAVE_TIME_H)
+    check_include_file_concat("unistd.h"         HAVE_UNISTD_H)
+    check_include_file_concat("utime.h"          HAVE_UTIME_H)
+    check_include_file_concat("x509.h"           HAVE_X509_H)
+
+    check_type_size("size_t"  SIZEOF_SIZE_T)
+    check_type_size("ssize_t"  SIZEOF_SSIZE_T)
+    check_type_size("long long"  SIZEOF_LONG_LONG)
+    check_type_size("long"  SIZEOF_LONG)
+    check_type_size("short"  SIZEOF_SHORT)
+    check_type_size("int"  SIZEOF_INT)
+    check_type_size("__int64"  SIZEOF___INT64)
+    check_type_size("long double"  SIZEOF_LONG_DOUBLE)
+    check_type_size("time_t"  SIZEOF_TIME_T)
+    check_type_size("off_t"  SIZEOF_OFF_T)
+    check_type_size("socklen_t" CURL_SIZEOF_CURL_SOCKLEN_T)
 
-    if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
-      add_definitions(
-        -DRECV_TYPE_ARG1=int
-        -DRECV_TYPE_ARG2=void*
-        -DRECV_TYPE_ARG3=size_t
-        -DRECV_TYPE_ARG4=int
-        -DRECV_TYPE_RETV=ssize_t
-        -DSEND_TYPE_ARG1=int
-        -DSEND_TYPE_ARG2=void*
-        -DSEND_QUAL_ARG2=const
-        -DSEND_TYPE_ARG3=size_t
-        -DSEND_TYPE_ARG4=int
-        -DSEND_TYPE_RETV=ssize_t
-        -DSIZEOF_SHORT=2
-        -DSIZEOF_INT=4
-        -DSIZEOF_SIZE_T=8
+    check_symbol_exists(basename      "${CURL_INCLUDES}" HAVE_BASENAME)
+    check_symbol_exists(socket        "${CURL_INCLUDES}" HAVE_SOCKET)
+    # poll on macOS is unreliable, it first did not exist, then was broken until
+    # fixed in 10.9 only to break again in 10.12.
+    if(NOT APPLE)
+      check_symbol_exists(poll        "${CURL_INCLUDES}" HAVE_POLL)
+    endif()
+    check_symbol_exists(select        "${CURL_INCLUDES}" HAVE_SELECT)
+    check_symbol_exists(strdup        "${CURL_INCLUDES}" HAVE_STRDUP)
+    check_symbol_exists(strstr        "${CURL_INCLUDES}" HAVE_STRSTR)
+    check_symbol_exists(strtok_r      "${CURL_INCLUDES}" HAVE_STRTOK_R)
+    check_symbol_exists(strftime      "${CURL_INCLUDES}" HAVE_STRFTIME)
+    check_symbol_exists(uname         "${CURL_INCLUDES}" HAVE_UNAME)
+    check_symbol_exists(strcasecmp    "${CURL_INCLUDES}" HAVE_STRCASECMP)
+    check_symbol_exists(stricmp       "${CURL_INCLUDES}" HAVE_STRICMP)
+    check_symbol_exists(strcmpi       "${CURL_INCLUDES}" HAVE_STRCMPI)
+    check_symbol_exists(strncmpi      "${CURL_INCLUDES}" HAVE_STRNCMPI)
+    check_symbol_exists(alarm         "${CURL_INCLUDES}" HAVE_ALARM)
+    if(NOT HAVE_STRNCMPI)
+      set(HAVE_STRCMPI)
+    endif(NOT HAVE_STRNCMPI)
+
+    check_symbol_exists(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR)
+    check_symbol_exists(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R)
+    check_symbol_exists(gettimeofday  "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY)
+    check_symbol_exists(inet_addr     "${CURL_INCLUDES}" HAVE_INET_ADDR)
+    check_symbol_exists(inet_ntoa     "${CURL_INCLUDES}" HAVE_INET_NTOA)
+    check_symbol_exists(inet_ntoa_r   "${CURL_INCLUDES}" HAVE_INET_NTOA_R)
+    check_symbol_exists(tcsetattr     "${CURL_INCLUDES}" HAVE_TCSETATTR)
+    check_symbol_exists(tcgetattr     "${CURL_INCLUDES}" HAVE_TCGETATTR)
+    check_symbol_exists(perror        "${CURL_INCLUDES}" HAVE_PERROR)
+    check_symbol_exists(closesocket   "${CURL_INCLUDES}" HAVE_CLOSESOCKET)
+    check_symbol_exists(setvbuf       "${CURL_INCLUDES}" HAVE_SETVBUF)
+    check_symbol_exists(sigsetjmp     "${CURL_INCLUDES}" HAVE_SIGSETJMP)
+    check_symbol_exists(getpass_r     "${CURL_INCLUDES}" HAVE_GETPASS_R)
+    check_symbol_exists(strlcat       "${CURL_INCLUDES}" HAVE_STRLCAT)
+    check_symbol_exists(getpwuid      "${CURL_INCLUDES}" HAVE_GETPWUID)
+    check_symbol_exists(geteuid       "${CURL_INCLUDES}" HAVE_GETEUID)
+    check_symbol_exists(utime         "${CURL_INCLUDES}" HAVE_UTIME)
+    check_symbol_exists(gmtime_r      "${CURL_INCLUDES}" HAVE_GMTIME_R)
+    check_symbol_exists(localtime_r   "${CURL_INCLUDES}" HAVE_LOCALTIME_R)
+
+    check_symbol_exists(gethostbyname   "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME)
+    check_symbol_exists(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R)
+
+    check_symbol_exists(signal        "${CURL_INCLUDES}" HAVE_SIGNAL_FUNC)
+    check_symbol_exists(SIGALRM       "${CURL_INCLUDES}" HAVE_SIGNAL_MACRO)
+    if(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
+      set(HAVE_SIGNAL 1)
+    endif(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
+    check_symbol_exists(uname          "${CURL_INCLUDES}" HAVE_UNAME)
+    check_symbol_exists(strtoll        "${CURL_INCLUDES}" HAVE_STRTOLL)
+    check_symbol_exists(_strtoi64      "${CURL_INCLUDES}" HAVE__STRTOI64)
+    check_symbol_exists(strerror_r     "${CURL_INCLUDES}" HAVE_STRERROR_R)
+    check_symbol_exists(siginterrupt   "${CURL_INCLUDES}" HAVE_SIGINTERRUPT)
+    check_symbol_exists(perror         "${CURL_INCLUDES}" HAVE_PERROR)
+    check_symbol_exists(fork           "${CURL_INCLUDES}" HAVE_FORK)
+    check_symbol_exists(getaddrinfo    "${CURL_INCLUDES}" HAVE_GETADDRINFO)
+    check_symbol_exists(freeaddrinfo   "${CURL_INCLUDES}" HAVE_FREEADDRINFO)
+    check_symbol_exists(freeifaddrs    "${CURL_INCLUDES}" HAVE_FREEIFADDRS)
+    check_symbol_exists(pipe           "${CURL_INCLUDES}" HAVE_PIPE)
+    check_symbol_exists(ftruncate      "${CURL_INCLUDES}" HAVE_FTRUNCATE)
+    check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME)
+    check_symbol_exists(getrlimit      "${CURL_INCLUDES}" HAVE_GETRLIMIT)
+    check_symbol_exists(setlocale      "${CURL_INCLUDES}" HAVE_SETLOCALE)
+    check_symbol_exists(setmode        "${CURL_INCLUDES}" HAVE_SETMODE)
+    check_symbol_exists(setrlimit      "${CURL_INCLUDES}" HAVE_SETRLIMIT)
+    check_symbol_exists(fcntl          "${CURL_INCLUDES}" HAVE_FCNTL)
+    check_symbol_exists(ioctl          "${CURL_INCLUDES}" HAVE_IOCTL)
+    check_symbol_exists(setsockopt     "${CURL_INCLUDES}" HAVE_SETSOCKOPT)
+
+    if(HAVE_SIZEOF_LONG_LONG)
+      set(HAVE_LONGLONG 1)
+      set(HAVE_LL 1)
+    endif(HAVE_SIZEOF_LONG_LONG)
+
+    check_function_exists(mach_absolute_time HAVE_MACH_ABSOLUTE_TIME)
+    check_function_exists(gethostname HAVE_GETHOSTNAME)
+
+    check_include_file_concat("pthread.h" HAVE_PTHREAD_H)
+    check_symbol_exists(recv "sys/socket.h" HAVE_RECV)
+    check_symbol_exists(send "sys/socket.h" HAVE_SEND)
+
+    check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS)
+
+    set(CMAKE_REQUIRED_INCLUDES "${CURL_SOURCES_DIR}/include")
+    set(CMAKE_EXTRA_INCLUDE_FILES "curl/system.h")
+    check_type_size("curl_off_t"  SIZEOF_CURL_OFF_T)
+
+    add_definitions(-DHAVE_GLIBC_STRERROR_R=1)
+
+    include(${CURL_SOURCES_DIR}/CMake/OtherTests.cmake)
+
+    foreach(CURL_TEST
+        HAVE_FCNTL_O_NONBLOCK
+        HAVE_IOCTLSOCKET
+        HAVE_IOCTLSOCKET_CAMEL
+        HAVE_IOCTLSOCKET_CAMEL_FIONBIO
+        HAVE_IOCTLSOCKET_FIONBIO
+        HAVE_IOCTL_FIONBIO
+        HAVE_IOCTL_SIOCGIFADDR
+        HAVE_SETSOCKOPT_SO_NONBLOCK
+        HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+        TIME_WITH_SYS_TIME
+        HAVE_O_NONBLOCK
+        HAVE_GETHOSTBYADDR_R_5
+        HAVE_GETHOSTBYADDR_R_7
+        HAVE_GETHOSTBYADDR_R_8
+        HAVE_GETHOSTBYADDR_R_5_REENTRANT
+        HAVE_GETHOSTBYADDR_R_7_REENTRANT
+        HAVE_GETHOSTBYADDR_R_8_REENTRANT
+        HAVE_GETHOSTBYNAME_R_3
+        HAVE_GETHOSTBYNAME_R_5
+        HAVE_GETHOSTBYNAME_R_6
+        HAVE_GETHOSTBYNAME_R_3_REENTRANT
+        HAVE_GETHOSTBYNAME_R_5_REENTRANT
+        HAVE_GETHOSTBYNAME_R_6_REENTRANT
+        HAVE_SOCKLEN_T
+        HAVE_IN_ADDR_T
+        HAVE_BOOL_T
+        STDC_HEADERS
+        RETSIGTYPE_TEST
+        HAVE_INET_NTOA_R_DECL
+        HAVE_INET_NTOA_R_DECL_REENTRANT
+        HAVE_GETADDRINFO
+        HAVE_FILE_OFFSET_BITS
         )
-    elseif ("${CMAKE_SIZEOF_VOID_P}" EQUAL "4")
-      add_definitions(
-        -DRECV_TYPE_ARG1=int
-        -DRECV_TYPE_ARG2=void*
-        -DRECV_TYPE_ARG3=size_t
-        -DRECV_TYPE_ARG4=int
-        -DRECV_TYPE_RETV=int
-        -DSEND_TYPE_ARG1=int
-        -DSEND_TYPE_ARG2=void*
-        -DSEND_QUAL_ARG2=const
-        -DSEND_TYPE_ARG3=size_t
-        -DSEND_TYPE_ARG4=int
-        -DSEND_TYPE_RETV=int
-        -DSIZEOF_SHORT=2
-        -DSIZEOF_INT=4
-        -DSIZEOF_SIZE_T=4
-        )
-    else()
-      message(FATAL_ERROR "Support your platform here")
-    endif()
+      curl_internal_test(${CURL_TEST})
+    endforeach(CURL_TEST)
+
+    configure_file(
+      ${CURL_SOURCES_DIR}/lib/curl_config.h.cmake
+      ${CURL_SOURCES_DIR}/lib/curl_config.h
+      )
   endif()
-
 else()
   include(FindCURL)
   include_directories(${CURL_INCLUDE_DIRS})
--- a/Resources/Orthanc/Resources/CMake/OpenSslConfiguration.cmake	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Resources/CMake/OpenSslConfiguration.cmake	Thu Jan 04 10:49:34 2018 +0100
@@ -1,232 +1,219 @@
-if (ENABLE_SSL)
-  if (STATIC_BUILD OR NOT USE_SYSTEM_OPENSSL)
-    # WARNING - We had to repack the upstream ".tar.gz" file to a ZIP
-    # file, as the upstream distribution ships symbolic links that are
-    # not always properly handled when uncompressing on Windows.
+if (STATIC_BUILD OR NOT USE_SYSTEM_OPENSSL)
+  # WARNING - We had to repack the upstream ".tar.gz" file to a ZIP
+  # file, as the upstream distribution ships symbolic links that are
+  # not always properly handled when uncompressing on Windows.
+
+  SET(OPENSSL_SOURCES_DIR ${CMAKE_BINARY_DIR}/openssl-1.0.2d)
+  SET(OPENSSL_URL "http://www.orthanc-server.com/downloads/third-party/openssl-1.0.2d.zip")
+  SET(OPENSSL_MD5 "4b2ac15fc6db17f3dadc54482d3eee85")
 
-    SET(OPENSSL_SOURCES_DIR ${CMAKE_BINARY_DIR}/openssl-1.0.2d)
-    SET(OPENSSL_URL "http://www.orthanc-server.com/downloads/third-party/openssl-1.0.2d.zip")
-    SET(OPENSSL_MD5 "4b2ac15fc6db17f3dadc54482d3eee85")
+  if (IS_DIRECTORY "${OPENSSL_SOURCES_DIR}")
+    set(FirstRun OFF)
+  else()
+    set(FirstRun ON)
+  endif()
 
-    if (IS_DIRECTORY "${OPENSSL_SOURCES_DIR}")
-      set(FirstRun OFF)
-    else()
-      set(FirstRun ON)
-    endif()
+  DownloadPackage(${OPENSSL_MD5} ${OPENSSL_URL} "${OPENSSL_SOURCES_DIR}")
 
-    DownloadPackage(${OPENSSL_MD5} ${OPENSSL_URL} "${OPENSSL_SOURCES_DIR}")
+  add_definitions(
+    -DOPENSSL_THREADS
+    -DOPENSSL_IA32_SSE2
+    -DOPENSSL_NO_ASM
+    -DOPENSSL_NO_DYNAMIC_ENGINE
+    -DNO_WINDOWS_BRAINDEATH
 
-    add_definitions(
-      -DOPENSSL_THREADS
-      -DOPENSSL_IA32_SSE2
-      -DOPENSSL_NO_ASM
-      -DOPENSSL_NO_DYNAMIC_ENGINE
-      -DNO_WINDOWS_BRAINDEATH
-
-      -DOPENSSL_NO_BF 
-      -DOPENSSL_NO_CAMELLIA
-      -DOPENSSL_NO_CAST 
-      -DOPENSSL_NO_EC_NISTP_64_GCC_128
-      -DOPENSSL_NO_GMP
-      -DOPENSSL_NO_GOST
-      -DOPENSSL_NO_HW
-      -DOPENSSL_NO_JPAKE
-      -DOPENSSL_NO_IDEA
-      -DOPENSSL_NO_KRB5 
-      -DOPENSSL_NO_MD2 
-      -DOPENSSL_NO_MDC2 
-      -DOPENSSL_NO_MD4
-      -DOPENSSL_NO_RC2 
-      -DOPENSSL_NO_RC4 
-      -DOPENSSL_NO_RC5 
-      -DOPENSSL_NO_RFC3779
-      -DOPENSSL_NO_SCTP
-      -DOPENSSL_NO_STORE
-      -DOPENSSL_NO_SEED
-      -DOPENSSL_NO_WHIRLPOOL
-      -DOPENSSL_NO_RIPEMD
-      )
+    -DOPENSSL_NO_BF 
+    -DOPENSSL_NO_CAMELLIA
+    -DOPENSSL_NO_CAST 
+    -DOPENSSL_NO_EC_NISTP_64_GCC_128
+    -DOPENSSL_NO_GMP
+    -DOPENSSL_NO_GOST
+    -DOPENSSL_NO_HW
+    -DOPENSSL_NO_JPAKE
+    -DOPENSSL_NO_IDEA
+    -DOPENSSL_NO_KRB5 
+    -DOPENSSL_NO_MD2 
+    -DOPENSSL_NO_MDC2 
+    -DOPENSSL_NO_MD4
+    -DOPENSSL_NO_RC2 
+    -DOPENSSL_NO_RC4 
+    -DOPENSSL_NO_RC5 
+    -DOPENSSL_NO_RFC3779
+    -DOPENSSL_NO_SCTP
+    -DOPENSSL_NO_STORE
+    -DOPENSSL_NO_SEED
+    -DOPENSSL_NO_WHIRLPOOL
+    -DOPENSSL_NO_RIPEMD
+    )
 
-    include_directories(
-      ${OPENSSL_SOURCES_DIR}
-      ${OPENSSL_SOURCES_DIR}/crypto
-      ${OPENSSL_SOURCES_DIR}/crypto/asn1
-      ${OPENSSL_SOURCES_DIR}/crypto/modes
-      ${OPENSSL_SOURCES_DIR}/crypto/evp
-      ${OPENSSL_SOURCES_DIR}/include
-      )
+  include_directories(
+    ${OPENSSL_SOURCES_DIR}
+    ${OPENSSL_SOURCES_DIR}/crypto
+    ${OPENSSL_SOURCES_DIR}/crypto/asn1
+    ${OPENSSL_SOURCES_DIR}/crypto/modes
+    ${OPENSSL_SOURCES_DIR}/crypto/evp
+    ${OPENSSL_SOURCES_DIR}/include
+    )
 
-    set(OPENSSL_SOURCES_SUBDIRS
-      ${OPENSSL_SOURCES_DIR}/crypto
-      ${OPENSSL_SOURCES_DIR}/crypto/aes
-      ${OPENSSL_SOURCES_DIR}/crypto/asn1
-      ${OPENSSL_SOURCES_DIR}/crypto/bio
-      ${OPENSSL_SOURCES_DIR}/crypto/bn
-      ${OPENSSL_SOURCES_DIR}/crypto/buffer
-      ${OPENSSL_SOURCES_DIR}/crypto/cmac
-      ${OPENSSL_SOURCES_DIR}/crypto/cms
-      ${OPENSSL_SOURCES_DIR}/crypto/comp
-      ${OPENSSL_SOURCES_DIR}/crypto/conf
-      ${OPENSSL_SOURCES_DIR}/crypto/des
-      ${OPENSSL_SOURCES_DIR}/crypto/dh
-      ${OPENSSL_SOURCES_DIR}/crypto/dsa
-      ${OPENSSL_SOURCES_DIR}/crypto/dso
-      ${OPENSSL_SOURCES_DIR}/crypto/engine
-      ${OPENSSL_SOURCES_DIR}/crypto/err
-      ${OPENSSL_SOURCES_DIR}/crypto/evp
-      ${OPENSSL_SOURCES_DIR}/crypto/hmac
-      ${OPENSSL_SOURCES_DIR}/crypto/lhash
-      ${OPENSSL_SOURCES_DIR}/crypto/md5
-      ${OPENSSL_SOURCES_DIR}/crypto/modes
-      ${OPENSSL_SOURCES_DIR}/crypto/objects
-      ${OPENSSL_SOURCES_DIR}/crypto/ocsp
-      ${OPENSSL_SOURCES_DIR}/crypto/pem
-      ${OPENSSL_SOURCES_DIR}/crypto/pkcs12
-      ${OPENSSL_SOURCES_DIR}/crypto/pkcs7
-      ${OPENSSL_SOURCES_DIR}/crypto/pqueue
-      ${OPENSSL_SOURCES_DIR}/crypto/rand
-      ${OPENSSL_SOURCES_DIR}/crypto/rsa
-      ${OPENSSL_SOURCES_DIR}/crypto/sha
-      ${OPENSSL_SOURCES_DIR}/crypto/srp
-      ${OPENSSL_SOURCES_DIR}/crypto/stack
-      ${OPENSSL_SOURCES_DIR}/crypto/ts
-      ${OPENSSL_SOURCES_DIR}/crypto/txt_db
-      ${OPENSSL_SOURCES_DIR}/crypto/ui
-      ${OPENSSL_SOURCES_DIR}/crypto/x509
-      ${OPENSSL_SOURCES_DIR}/crypto/x509v3
-      ${OPENSSL_SOURCES_DIR}/ssl
-      )
+  set(OPENSSL_SOURCES_SUBDIRS
+    ${OPENSSL_SOURCES_DIR}/crypto
+    ${OPENSSL_SOURCES_DIR}/crypto/aes
+    ${OPENSSL_SOURCES_DIR}/crypto/asn1
+    ${OPENSSL_SOURCES_DIR}/crypto/bio
+    ${OPENSSL_SOURCES_DIR}/crypto/bn
+    ${OPENSSL_SOURCES_DIR}/crypto/buffer
+    ${OPENSSL_SOURCES_DIR}/crypto/cmac
+    ${OPENSSL_SOURCES_DIR}/crypto/cms
+    ${OPENSSL_SOURCES_DIR}/crypto/comp
+    ${OPENSSL_SOURCES_DIR}/crypto/conf
+    ${OPENSSL_SOURCES_DIR}/crypto/des
+    ${OPENSSL_SOURCES_DIR}/crypto/dh
+    ${OPENSSL_SOURCES_DIR}/crypto/dsa
+    ${OPENSSL_SOURCES_DIR}/crypto/dso
+    ${OPENSSL_SOURCES_DIR}/crypto/engine
+    ${OPENSSL_SOURCES_DIR}/crypto/err
+    ${OPENSSL_SOURCES_DIR}/crypto/evp
+    ${OPENSSL_SOURCES_DIR}/crypto/hmac
+    ${OPENSSL_SOURCES_DIR}/crypto/lhash
+    ${OPENSSL_SOURCES_DIR}/crypto/md5
+    ${OPENSSL_SOURCES_DIR}/crypto/modes
+    ${OPENSSL_SOURCES_DIR}/crypto/objects
+    ${OPENSSL_SOURCES_DIR}/crypto/ocsp
+    ${OPENSSL_SOURCES_DIR}/crypto/pem
+    ${OPENSSL_SOURCES_DIR}/crypto/pkcs12
+    ${OPENSSL_SOURCES_DIR}/crypto/pkcs7
+    ${OPENSSL_SOURCES_DIR}/crypto/pqueue
+    ${OPENSSL_SOURCES_DIR}/crypto/rand
+    ${OPENSSL_SOURCES_DIR}/crypto/rsa
+    ${OPENSSL_SOURCES_DIR}/crypto/sha
+    ${OPENSSL_SOURCES_DIR}/crypto/srp
+    ${OPENSSL_SOURCES_DIR}/crypto/stack
+    ${OPENSSL_SOURCES_DIR}/crypto/ts
+    ${OPENSSL_SOURCES_DIR}/crypto/txt_db
+    ${OPENSSL_SOURCES_DIR}/crypto/ui
+    ${OPENSSL_SOURCES_DIR}/crypto/x509
+    ${OPENSSL_SOURCES_DIR}/crypto/x509v3
+    ${OPENSSL_SOURCES_DIR}/ssl
+    )
 
-    if (ENABLE_PKCS11)
-      list(APPEND OPENSSL_SOURCES_SUBDIRS
-        # EC, ECDH and ECDSA are necessary for PKCS11
-        ${OPENSSL_SOURCES_DIR}/crypto/ec
-        ${OPENSSL_SOURCES_DIR}/crypto/ecdh
-        ${OPENSSL_SOURCES_DIR}/crypto/ecdsa
-        )
-    else()
-      add_definitions(
-        -DOPENSSL_NO_EC
-        -DOPENSSL_NO_ECDH
-        -DOPENSSL_NO_ECDSA
-        )
-    endif()
+  if (ENABLE_PKCS11)
+    list(APPEND OPENSSL_SOURCES_SUBDIRS
+      # EC, ECDH and ECDSA are necessary for PKCS11
+      ${OPENSSL_SOURCES_DIR}/crypto/ec
+      ${OPENSSL_SOURCES_DIR}/crypto/ecdh
+      ${OPENSSL_SOURCES_DIR}/crypto/ecdsa
+      )
+  else()
+    add_definitions(
+      -DOPENSSL_NO_EC
+      -DOPENSSL_NO_ECDH
+      -DOPENSSL_NO_ECDSA
+      )
+  endif()
 
-    foreach(d ${OPENSSL_SOURCES_SUBDIRS})
-      AUX_SOURCE_DIRECTORY(${d} OPENSSL_SOURCES)
-    endforeach()
+  foreach(d ${OPENSSL_SOURCES_SUBDIRS})
+    AUX_SOURCE_DIRECTORY(${d} OPENSSL_SOURCES)
+  endforeach()
 
-    list(REMOVE_ITEM OPENSSL_SOURCES
-      ${OPENSSL_SOURCES_DIR}/crypto/LPdir_unix.c
-      ${OPENSSL_SOURCES_DIR}/crypto/LPdir_vms.c
-      ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win.c
-      ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win32.c
-      ${OPENSSL_SOURCES_DIR}/crypto/LPdir_wince.c
-      ${OPENSSL_SOURCES_DIR}/crypto/armcap.c
-      ${OPENSSL_SOURCES_DIR}/crypto/bf/bfs.cpp
-      ${OPENSSL_SOURCES_DIR}/crypto/bio/bss_rtcp.c
-      ${OPENSSL_SOURCES_DIR}/crypto/bn/exp.c
-      ${OPENSSL_SOURCES_DIR}/crypto/conf/cnf_save.c
-      ${OPENSSL_SOURCES_DIR}/crypto/conf/test.c
-      ${OPENSSL_SOURCES_DIR}/crypto/des/des.c
-      ${OPENSSL_SOURCES_DIR}/crypto/des/des3s.cpp
-      ${OPENSSL_SOURCES_DIR}/crypto/des/des_opts.c
-      ${OPENSSL_SOURCES_DIR}/crypto/des/dess.cpp
-      ${OPENSSL_SOURCES_DIR}/crypto/des/read_pwd.c
-      ${OPENSSL_SOURCES_DIR}/crypto/des/speed.c
-      ${OPENSSL_SOURCES_DIR}/crypto/evp/e_dsa.c
-      ${OPENSSL_SOURCES_DIR}/crypto/evp/m_ripemd.c
-      ${OPENSSL_SOURCES_DIR}/crypto/lhash/lh_test.c
-      ${OPENSSL_SOURCES_DIR}/crypto/md5/md5s.cpp
-      ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/bio_ber.c
-      ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/pk7_enc.c
-      ${OPENSSL_SOURCES_DIR}/crypto/ppccap.c
-      ${OPENSSL_SOURCES_DIR}/crypto/rand/randtest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/s390xcap.c
-      ${OPENSSL_SOURCES_DIR}/crypto/sparcv9cap.c
-      ${OPENSSL_SOURCES_DIR}/crypto/x509v3/tabtest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3conf.c
-      ${OPENSSL_SOURCES_DIR}/ssl/ssl_task.c
-      ${OPENSSL_SOURCES_DIR}/crypto/LPdir_nyi.c
-      ${OPENSSL_SOURCES_DIR}/crypto/aes/aes_x86core.c
-      ${OPENSSL_SOURCES_DIR}/crypto/bio/bss_dgram.c
-      ${OPENSSL_SOURCES_DIR}/crypto/bn/bntest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/bn/expspeed.c
-      ${OPENSSL_SOURCES_DIR}/crypto/bn/exptest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/engine/enginetest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/evp/evp_test.c
-      ${OPENSSL_SOURCES_DIR}/crypto/hmac/hmactest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/md5/md5.c
-      ${OPENSSL_SOURCES_DIR}/crypto/md5/md5test.c
-      ${OPENSSL_SOURCES_DIR}/crypto/o_dir_test.c
-      ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/dec.c
-      ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/enc.c
-      ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/sign.c
-      ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/verify.c
-      ${OPENSSL_SOURCES_DIR}/crypto/rsa/rsa_test.c
-      ${OPENSSL_SOURCES_DIR}/crypto/sha/sha.c
-      ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1.c
-      ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1t.c
-      ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1test.c
-      ${OPENSSL_SOURCES_DIR}/crypto/sha/sha256t.c
-      ${OPENSSL_SOURCES_DIR}/crypto/sha/sha512t.c
-      ${OPENSSL_SOURCES_DIR}/crypto/sha/shatest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/srp/srptest.c
+  list(REMOVE_ITEM OPENSSL_SOURCES
+    ${OPENSSL_SOURCES_DIR}/crypto/LPdir_unix.c
+    ${OPENSSL_SOURCES_DIR}/crypto/LPdir_vms.c
+    ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win.c
+    ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win32.c
+    ${OPENSSL_SOURCES_DIR}/crypto/LPdir_wince.c
+    ${OPENSSL_SOURCES_DIR}/crypto/armcap.c
+    ${OPENSSL_SOURCES_DIR}/crypto/bf/bfs.cpp
+    ${OPENSSL_SOURCES_DIR}/crypto/bio/bss_rtcp.c
+    ${OPENSSL_SOURCES_DIR}/crypto/bn/exp.c
+    ${OPENSSL_SOURCES_DIR}/crypto/conf/cnf_save.c
+    ${OPENSSL_SOURCES_DIR}/crypto/conf/test.c
+    ${OPENSSL_SOURCES_DIR}/crypto/des/des.c
+    ${OPENSSL_SOURCES_DIR}/crypto/des/des3s.cpp
+    ${OPENSSL_SOURCES_DIR}/crypto/des/des_opts.c
+    ${OPENSSL_SOURCES_DIR}/crypto/des/dess.cpp
+    ${OPENSSL_SOURCES_DIR}/crypto/des/read_pwd.c
+    ${OPENSSL_SOURCES_DIR}/crypto/des/speed.c
+    ${OPENSSL_SOURCES_DIR}/crypto/evp/e_dsa.c
+    ${OPENSSL_SOURCES_DIR}/crypto/evp/m_ripemd.c
+    ${OPENSSL_SOURCES_DIR}/crypto/lhash/lh_test.c
+    ${OPENSSL_SOURCES_DIR}/crypto/md5/md5s.cpp
+    ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/bio_ber.c
+    ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/pk7_enc.c
+    ${OPENSSL_SOURCES_DIR}/crypto/ppccap.c
+    ${OPENSSL_SOURCES_DIR}/crypto/rand/randtest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/s390xcap.c
+    ${OPENSSL_SOURCES_DIR}/crypto/sparcv9cap.c
+    ${OPENSSL_SOURCES_DIR}/crypto/x509v3/tabtest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3conf.c
+    ${OPENSSL_SOURCES_DIR}/ssl/ssl_task.c
+    ${OPENSSL_SOURCES_DIR}/crypto/LPdir_nyi.c
+    ${OPENSSL_SOURCES_DIR}/crypto/aes/aes_x86core.c
+    ${OPENSSL_SOURCES_DIR}/crypto/bio/bss_dgram.c
+    ${OPENSSL_SOURCES_DIR}/crypto/bn/bntest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/bn/expspeed.c
+    ${OPENSSL_SOURCES_DIR}/crypto/bn/exptest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/engine/enginetest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/evp/evp_test.c
+    ${OPENSSL_SOURCES_DIR}/crypto/hmac/hmactest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/md5/md5.c
+    ${OPENSSL_SOURCES_DIR}/crypto/md5/md5test.c
+    ${OPENSSL_SOURCES_DIR}/crypto/o_dir_test.c
+    ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/dec.c
+    ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/enc.c
+    ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/sign.c
+    ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/verify.c
+    ${OPENSSL_SOURCES_DIR}/crypto/rsa/rsa_test.c
+    ${OPENSSL_SOURCES_DIR}/crypto/sha/sha.c
+    ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1.c
+    ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1t.c
+    ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1test.c
+    ${OPENSSL_SOURCES_DIR}/crypto/sha/sha256t.c
+    ${OPENSSL_SOURCES_DIR}/crypto/sha/sha512t.c
+    ${OPENSSL_SOURCES_DIR}/crypto/sha/shatest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/srp/srptest.c
 
-      ${OPENSSL_SOURCES_DIR}/crypto/bn/divtest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/bn/bnspeed.c
-      ${OPENSSL_SOURCES_DIR}/crypto/des/destest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/dh/p192.c
-      ${OPENSSL_SOURCES_DIR}/crypto/dh/p512.c
-      ${OPENSSL_SOURCES_DIR}/crypto/dh/p1024.c
-      ${OPENSSL_SOURCES_DIR}/crypto/des/rpw.c
-      ${OPENSSL_SOURCES_DIR}/ssl/ssltest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/dsa/dsagen.c
-      ${OPENSSL_SOURCES_DIR}/crypto/dsa/dsatest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/dh/dhtest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/pqueue/pq_test.c
-      ${OPENSSL_SOURCES_DIR}/crypto/des/ncbc_enc.c
+    ${OPENSSL_SOURCES_DIR}/crypto/bn/divtest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/bn/bnspeed.c
+    ${OPENSSL_SOURCES_DIR}/crypto/des/destest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/dh/p192.c
+    ${OPENSSL_SOURCES_DIR}/crypto/dh/p512.c
+    ${OPENSSL_SOURCES_DIR}/crypto/dh/p1024.c
+    ${OPENSSL_SOURCES_DIR}/crypto/des/rpw.c
+    ${OPENSSL_SOURCES_DIR}/ssl/ssltest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/dsa/dsagen.c
+    ${OPENSSL_SOURCES_DIR}/crypto/dsa/dsatest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/dh/dhtest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/pqueue/pq_test.c
+    ${OPENSSL_SOURCES_DIR}/crypto/des/ncbc_enc.c
 
-      ${OPENSSL_SOURCES_DIR}/crypto/evp/evp_extra_test.c
-      ${OPENSSL_SOURCES_DIR}/crypto/evp/verify_extra_test.c
-      ${OPENSSL_SOURCES_DIR}/crypto/x509/verify_extra_test.c
-      ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3prin.c
-      ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3nametest.c
-      ${OPENSSL_SOURCES_DIR}/crypto/constant_time_test.c
-      ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistz256_table.c
+    ${OPENSSL_SOURCES_DIR}/crypto/evp/evp_extra_test.c
+    ${OPENSSL_SOURCES_DIR}/crypto/evp/verify_extra_test.c
+    ${OPENSSL_SOURCES_DIR}/crypto/x509/verify_extra_test.c
+    ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3prin.c
+    ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3nametest.c
+    ${OPENSSL_SOURCES_DIR}/crypto/constant_time_test.c
+    ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistz256_table.c
 
-      ${OPENSSL_SOURCES_DIR}/ssl/heartbeat_test.c
-      )
+    ${OPENSSL_SOURCES_DIR}/ssl/heartbeat_test.c
+    )
 
 
-    if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
-      set_source_files_properties(
-        ${OPENSSL_SOURCES}
-        PROPERTIES COMPILE_DEFINITIONS
-        "OPENSSL_SYSNAME_WIN32;SO_WIN32;WIN32_LEAN_AND_MEAN;L_ENDIAN")
+  if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
+    set_source_files_properties(
+      ${OPENSSL_SOURCES}
+      PROPERTIES COMPILE_DEFINITIONS
+      "OPENSSL_SYSNAME_WIN32;SO_WIN32;WIN32_LEAN_AND_MEAN;L_ENDIAN")
+  endif()
 
-    elseif ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
-      execute_process(
-        COMMAND ${PATCH_EXECUTABLE} -N ui_openssl.c -i ${ORTHANC_ROOT}/Resources/Patches/openssl-lsb.diff
-        WORKING_DIRECTORY ${OPENSSL_SOURCES_DIR}/crypto/ui
-        RESULT_VARIABLE Failure
-        )
+  source_group(ThirdParty\\OpenSSL REGULAR_EXPRESSION ${OPENSSL_SOURCES_DIR}/.*)
 
-      if (Failure AND FirstRun)
-        message(FATAL_ERROR "Error while patching a file")
-      endif()
-    endif()
-
-    source_group(ThirdParty\\OpenSSL REGULAR_EXPRESSION ${OPENSSL_SOURCES_DIR}/.*)
+else()
+  include(FindOpenSSL)
 
-  else()
-    include(FindOpenSSL)
+  if (NOT ${OPENSSL_FOUND})
+    message(FATAL_ERROR "Unable to find OpenSSL")
+  endif()
 
-    if (NOT ${OPENSSL_FOUND})
-      message(FATAL_ERROR "Unable to find OpenSSL")
-    endif()
-
-    include_directories(${OPENSSL_INCLUDE_DIR})
-    link_libraries(${OPENSSL_LIBRARIES})
-  endif()
+  include_directories(${OPENSSL_INCLUDE_DIR})
+  link_libraries(${OPENSSL_LIBRARIES})
 endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Resources/CMake/UuidConfiguration.cmake	Thu Jan 04 10:49:34 2018 +0100
@@ -0,0 +1,94 @@
+if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+
+  if (STATIC_BUILD OR NOT USE_SYSTEM_UUID)
+    SET(E2FSPROGS_SOURCES_DIR ${CMAKE_BINARY_DIR}/e2fsprogs-1.43.8)
+    SET(E2FSPROGS_URL "http://www.orthanc-server.com/downloads/third-party/e2fsprogs-1.43.8.tar.gz")
+    SET(E2FSPROGS_MD5 "670b7a74a8ead5333acf21b9afc92b3c")
+
+    DownloadPackage(${E2FSPROGS_MD5} ${E2FSPROGS_URL} "${E2FSPROGS_SOURCES_DIR}")
+
+    include_directories(
+      ${E2FSPROGS_SOURCES_DIR}/lib
+      )
+
+    set(UUID_SOURCES
+      #${E2FSPROGS_SOURCES_DIR}/lib/uuid/tst_uuid.c
+      #${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_time.c
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/clear.c
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/compare.c
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/copy.c
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/gen_uuid.c
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/isnull.c
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/pack.c
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/parse.c
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/unpack.c
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/unparse.c
+      )
+
+    check_include_file("net/if.h"       HAVE_NET_IF_H)
+    check_include_file("net/if_dl.h"    HAVE_NET_IF_DL_H)
+    check_include_file("netinet/in.h"   HAVE_NETINET_IN_H)
+    check_include_file("stdlib.h"       HAVE_STDLIB_H)
+    check_include_file("sys/file.h"     HAVE_SYS_FILE_H)
+    check_include_file("sys/ioctl.h"    HAVE_SYS_IOCTL_H)
+    check_include_file("sys/resource.h" HAVE_SYS_RESOURCE_H)
+    check_include_file("sys/socket.h"   HAVE_SYS_SOCKET_H)
+    check_include_file("sys/sockio.h"   HAVE_SYS_SOCKIO_H)
+    check_include_file("sys/syscall.h"  HAVE_SYS_SYSCALL_H)
+    check_include_file("sys/time.h"     HAVE_SYS_TIME_H)
+    check_include_file("sys/un.h"       HAVE_SYS_UN_H)
+    check_include_file("unistd.h"       HAVE_UNISTD_H)
+
+    file(WRITE ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h.cmake "
+#cmakedefine HAVE_NET_IF_H \@HAVE_NET_IF_H\@
+#cmakedefine HAVE_NET_IF_DL_H \@HAVE_NET_IF_DL_H\@
+#cmakedefine HAVE_NETINET_IN_H \@HAVE_NETINET_IN_H\@
+#cmakedefine HAVE_STDLIB_H \@HAVE_STDLIB_H \@
+#cmakedefine HAVE_SYS_FILE_H \@HAVE_SYS_FILE_H\@
+#cmakedefine HAVE_SYS_IOCTL_H \@HAVE_SYS_IOCTL_H\@
+#cmakedefine HAVE_SYS_RESOURCE_H \@HAVE_SYS_RESOURCE_H\@
+#cmakedefine HAVE_SYS_SOCKET_H \@HAVE_SYS_SOCKET_H\@
+#cmakedefine HAVE_SYS_SOCKIO_H \@HAVE_SYS_SOCKIO_H\@
+#cmakedefine HAVE_SYS_SYSCALL_H \@HAVE_SYS_SYSCALL_H\@
+#cmakedefine HAVE_SYS_TIME_H \@HAVE_SYS_TIME_H\@
+#cmakedefine HAVE_SYS_UN_H \@HAVE_SYS_UN_H\@
+#cmakedefine HAVE_UNISTD_H \@HAVE_UNISTD_H\@
+")
+    
+    configure_file(
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h.cmake
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h
+      )
+    
+    
+    configure_file(
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid.h.in
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid.h
+      )
+
+    file(WRITE
+      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h
+      "#include <stdint.h>\n")
+
+    #configure_file(
+    #  ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h.in
+    #  ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h
+    #  )
+    
+    source_group(ThirdParty\\uuid REGULAR_EXPRESSION ${E2FSPROGS_SOURCES_DIR}/.*)
+
+  else()
+    CHECK_INCLUDE_FILE(uuid/uuid.h HAVE_UUID_H)
+    if (NOT HAVE_UUID_H)
+      message(FATAL_ERROR "Please install uuid-dev, e2fsprogs (OpenBSD) or e2fsprogs-libuuid (FreeBSD)")
+    endif()
+
+    check_library_exists(uuid uuid_generate_random "" HAVE_UUID_LIB)
+    if (NOT HAVE_UUID_LIB)
+      message(FATAL_ERROR "Unable to find the uuid library")
+    endif()
+    
+    link_libraries(uuid)
+  endif()
+
+endif()
--- a/Resources/Orthanc/Resources/CMake/VisualStudioPrecompiledHeaders.cmake	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Resources/CMake/VisualStudioPrecompiledHeaders.cmake	Thu Jan 04 10:49:34 2018 +0100
@@ -1,4 +1,4 @@
-macro(ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS PrecompiledHeaders PrecompiledSource Sources)
+macro(ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS PrecompiledHeaders PrecompiledSource Sources Target)
   get_filename_component(PrecompiledBasename ${PrecompiledHeaders} NAME_WE)
   set(PrecompiledBinary "${PrecompiledBasename}_$(ConfigurationName).pch")
 
@@ -10,5 +10,5 @@
     PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeaders}\" /FI\"${PrecompiledHeaders}\" /Fp\"${PrecompiledBinary}\""
     OBJECT_DEPENDS "${PrecompiledBinary}")
 
-  list(APPEND ${Sources} ${PrecompiledSource})
+  set(${Target} ${PrecompiledSource})
 endmacro()
--- a/Resources/Orthanc/Resources/EmbedResources.py	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Resources/EmbedResources.py	Thu Jan 04 10:49:34 2018 +0100
@@ -3,7 +3,7 @@
 # Orthanc - A Lightweight, RESTful DICOM Store
 # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
 # Department, University Hospital of Liege, Belgium
-# Copyright (C) 2017 Osimis, Belgium
+# Copyright (C) 2017-2018 Osimis S.A., Belgium
 #
 # This program is free software: you can redistribute it and/or
 # modify it under the terms of the GNU General Public License as
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Resources/Patches/boost-1.65.1-linux-standard-base.patch	Thu Jan 04 10:49:34 2018 +0100
@@ -0,0 +1,12 @@
+diff -urEb boost_1_65_1.orig/boost/move/adl_move_swap.hpp boost_1_65_1/boost/move/adl_move_swap.hpp
+--- boost_1_65_1.orig/boost/move/adl_move_swap.hpp	2017-11-08 17:43:20.000000000 +0100
++++ boost_1_65_1/boost/move/adl_move_swap.hpp	2018-01-02 15:34:48.829052917 +0100
+@@ -28,6 +28,8 @@
+ //Try to avoid including <algorithm>, as it's quite big
+ #if defined(_MSC_VER) && defined(BOOST_DINKUMWARE_STDLIB)
+    #include <utility>   //Dinkum libraries define std::swap in utility which is lighter than algorithm
++#elif defined(__LSB_VERSION__)
++#  include <utility>
+ #elif defined(BOOST_GNU_STDLIB)
+    //For non-GCC compilers, where GNUC version is not very reliable, or old GCC versions
+    //use the good old stl_algobase header, which is quite lightweight
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Resources/Patches/curl-7.57.0-cmake.patch	Thu Jan 04 10:49:34 2018 +0100
@@ -0,0 +1,12 @@
+diff -urEb curl-7.57.0.orig/CMake/Macros.cmake curl-7.57.0/CMake/Macros.cmake
+--- curl-7.57.0.orig/CMake/Macros.cmake	2017-11-09 23:40:36.000000000 +0100
++++ curl-7.57.0/CMake/Macros.cmake	2018-01-03 10:39:15.589520034 +0100
+@@ -38,7 +38,7 @@
+     message(STATUS "Performing Curl Test ${CURL_TEST}")
+     try_compile(${CURL_TEST}
+       ${CMAKE_BINARY_DIR}
+-      ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c
++      ${CURL_SOURCES_DIR}/CMake/CurlTests.c
+       CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+       "${CURL_TEST_ADD_LIBRARIES}"
+       OUTPUT_VARIABLE OUTPUT)
--- a/Resources/Orthanc/Resources/WindowsResources.py	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/Orthanc/Resources/WindowsResources.py	Thu Jan 04 10:49:34 2018 +0100
@@ -3,7 +3,7 @@
 # Orthanc - A Lightweight, RESTful DICOM Store
 # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
 # Department, University Hospital of Liege, Belgium
-# Copyright (C) 2017 Osimis, Belgium
+# Copyright (C) 2017-2018 Osimis S.A., Belgium
 #
 # This program is free software: you can redistribute it and/or
 # modify it under the terms of the GNU General Public License as
--- a/Resources/SyncOrthancFolder.py	Tue Jan 02 10:01:35 2018 +0100
+++ b/Resources/SyncOrthancFolder.py	Thu Jan 04 10:49:34 2018 +0100
@@ -27,6 +27,10 @@
     'Core/DicomFormat/DicomTag.h',
     'Core/DicomFormat/DicomValue.cpp',
     'Core/DicomFormat/DicomValue.h',
+    'Core/DicomParsing/FromDcmtkBridge.cpp',
+    'Core/DicomParsing/FromDcmtkBridge.h',
+    'Core/DicomParsing/ToDcmtkBridge.cpp',
+    'Core/DicomParsing/ToDcmtkBridge.h',
     'Core/Endianness.h',
     'Core/EnumerationDictionary.h',
     'Core/Enumerations.cpp',
@@ -75,26 +79,16 @@
     'Core/Toolbox.h',
     'Core/WebServiceParameters.cpp',
     'Core/WebServiceParameters.h',
-    'OrthancServer/FromDcmtkBridge.cpp',
-    'OrthancServer/FromDcmtkBridge.h',
     'OrthancServer/PrecompiledHeadersServer.h',
-    'OrthancServer/ServerEnumerations.cpp',
-    'OrthancServer/ServerEnumerations.h',
-    'OrthancServer/ToDcmtkBridge.cpp',
-    'OrthancServer/ToDcmtkBridge.h',
     'Plugins/Engine/SharedLibrary.cpp',
     'Plugins/Engine/SharedLibrary.h',
-    'Plugins/Samples/Common/ExportedSymbols.list',
-    'Plugins/Samples/Common/OrthancPluginCppWrapper.cpp',
-    'Plugins/Samples/Common/OrthancPluginCppWrapper.h',
-    'Plugins/Samples/Common/OrthancPluginException.h',
-    'Plugins/Samples/Common/VersionScript.map',
     'Plugins/Samples/Common/DicomDatasetReader.cpp',
     'Plugins/Samples/Common/DicomDatasetReader.h',
     'Plugins/Samples/Common/DicomPath.cpp',
     'Plugins/Samples/Common/DicomPath.h',
     'Plugins/Samples/Common/DicomTag.cpp',
     'Plugins/Samples/Common/DicomTag.h',
+    'Plugins/Samples/Common/ExportedSymbols.list',
     'Plugins/Samples/Common/FullOrthancDataset.cpp',
     'Plugins/Samples/Common/FullOrthancDataset.h',
     'Plugins/Samples/Common/IDicomDataset.h',
@@ -104,8 +98,12 @@
     'Plugins/Samples/Common/OrthancHttpConnection.h',
     'Plugins/Samples/Common/OrthancPluginConnection.cpp',
     'Plugins/Samples/Common/OrthancPluginConnection.h',
+    'Plugins/Samples/Common/OrthancPluginCppWrapper.cpp',
+    'Plugins/Samples/Common/OrthancPluginCppWrapper.h',
+    'Plugins/Samples/Common/OrthancPluginException.h',
     'Plugins/Samples/Common/SimplifiedOrthancDataset.cpp',
     'Plugins/Samples/Common/SimplifiedOrthancDataset.h',
+    'Plugins/Samples/Common/VersionScript.map',
     'Resources/CMake/AutoGeneratedCode.cmake',
     'Resources/CMake/BoostConfiguration.cmake',
     'Resources/CMake/Compiler.cmake',
@@ -117,12 +115,15 @@
     'Resources/CMake/LibJpegConfiguration.cmake',
     'Resources/CMake/LibPngConfiguration.cmake',
     'Resources/CMake/OpenSslConfiguration.cmake',
+    'Resources/CMake/UuidConfiguration.cmake',
     'Resources/CMake/VisualStudioPrecompiledHeaders.cmake',
     'Resources/CMake/ZlibConfiguration.cmake',
     'Resources/EmbedResources.py',
     'Resources/MinGW-W64-Toolchain32.cmake',
     'Resources/MinGW-W64-Toolchain64.cmake',
     'Resources/MinGWToolchain.cmake',
+    'Resources/Patches/boost-1.65.1-linux-standard-base.patch',
+    'Resources/Patches/curl-7.57.0-cmake.patch',
     'Resources/Patches/dcmtk-3.6.0-dulparse-vulnerability.patch',
     'Resources/Patches/dcmtk-3.6.0-mingw64.patch',
     'Resources/Patches/dcmtk-3.6.0-speed.patch',
--- a/ViewerPlugin/CMakeLists.txt	Tue Jan 02 10:01:35 2018 +0100
+++ b/ViewerPlugin/CMakeLists.txt	Thu Jan 04 10:49:34 2018 +0100
@@ -16,8 +16,9 @@
 SET(USE_SYSTEM_LIBJPEG ON CACHE BOOL "Use the system version of libjpeg")
 SET(USE_SYSTEM_LIBPNG ON CACHE BOOL "Use the system version of libpng")
 SET(USE_SYSTEM_OPENJPEG ON CACHE BOOL "Use the system version of OpenJpeg")
+SET(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK")
 SET(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib")
-SET(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK")
+set(USE_SYSTEM_UUID ON CACHE BOOL "Use the system version of the uuid library from e2fsprogs")
 
 # Parameters related to OpenLayers
 SET(USE_SYSTEM_OPENLAYERS OFF CACHE BOOL "Use the system version of OpenLayers")
@@ -35,12 +36,13 @@
 SET(USE_OPENJPEG_JP2 ON)
 SET(ENABLE_LOCALE OFF)         # Disable support for locales (notably in Boost)
 
+include(CheckIncludeFile)
+include(CheckIncludeFileCXX)
 include(CheckIncludeFiles)
-include(CheckIncludeFileCXX)
 include(CheckLibraryExists)
-include(FindPythonInterp)
+include(CheckSymbolExists)
 include(FindPkgConfig)
-include(CheckSymbolExists)
+include(FindPythonInterp)
 
 include(${ORTHANC_ROOT}/Resources/CMake/Compiler.cmake)
 include(${ORTHANC_ROOT}/Resources/CMake/AutoGeneratedCode.cmake)
@@ -52,6 +54,7 @@
 include(${ORTHANC_ROOT}/Resources/CMake/JsonCppConfiguration.cmake)
 include(${ORTHANC_ROOT}/Resources/CMake/LibJpegConfiguration.cmake)
 include(${ORTHANC_ROOT}/Resources/CMake/LibPngConfiguration.cmake)
+include(${ORTHANC_ROOT}/Resources/CMake/UuidConfiguration.cmake)
 include(${ORTHANC_ROOT}/Resources/CMake/ZlibConfiguration.cmake)
 
 # Include components specific to WSI
@@ -59,16 +62,19 @@
 include(${ORTHANC_WSI_DIR}/Resources/CMake/OpenJpegConfiguration.cmake)
 
 add_definitions(
+  -DHAS_ORTHANC_EXCEPTION=1
+  -DORTHANC_DEFAULT_DICOM_ENCODING=Encoding_Latin1
   -DORTHANC_ENABLE_BASE64=0
   -DORTHANC_ENABLE_CURL=0
   -DORTHANC_ENABLE_DCMTK=0
+  -DORTHANC_ENABLE_JPEG=1
   -DORTHANC_ENABLE_LOCALE=0
   -DORTHANC_ENABLE_LOGGING=1
   -DORTHANC_ENABLE_LOGGING_PLUGIN=1
   -DORTHANC_ENABLE_MD5=0
+  -DORTHANC_ENABLE_PNG=1
   -DORTHANC_ENABLE_PUGIXML=0
   -DORTHANC_SANDBOXED=0
-  -DHAS_ORTHANC_EXCEPTION=1
   )
 
 
@@ -229,10 +235,11 @@
   # Mandatory components
   ${BOOST_SOURCES}
   ${JSONCPP_SOURCES}
-  ${ZLIB_SOURCES}
+  ${LIBJPEG_SOURCES}
   ${LIBPNG_SOURCES}
-  ${LIBJPEG_SOURCES}
   ${OPENJPEG_SOURCES}
+  ${UUID_SOURCES}
+  ${ZLIB_SOURCES}
   )
 
 message("Setting the version of the library to ${ORTHANC_WSI_VERSION}")