[med-svn] [orthanc] 01/05: New upstream version 1.3.1+dfsg

Sebastien Jodogne jodogne-guest at moszumanska.debian.org
Thu Nov 30 11:28:24 UTC 2017


This is an automated email from the git hooks/post-receive script.

jodogne-guest pushed a commit to branch master
in repository orthanc.

commit 4d644cab00866ab1058d8aec003de161452575e8
Author: jodogne-guest <s.jodogne at gmail.com>
Date:   Thu Nov 30 12:04:28 2017 +0100

    New upstream version 1.3.1+dfsg
---
 .hg_archival.txt                                   |   8 +-
 .travis.yml                                        |   2 +-
 CMakeLists.txt                                     | 399 ++++------------
 Core/Cache/SharedArchive.h                         |   8 +
 Core/Compression/HierarchicalZipWriter.h           |   4 +
 Core/Compression/ZipWriter.h                       |   4 -
 Core/DicomFormat/DicomImageInformation.cpp         |  32 +-
 Core/DicomFormat/DicomMap.cpp                      | 191 ++++++++
 Core/DicomFormat/DicomMap.h                        |  24 +
 Core/DicomFormat/DicomTag.h                        |  11 +
 Core/DicomFormat/DicomValue.cpp                    | 102 +++++
 Core/DicomFormat/DicomValue.h                      |  16 +
 .../DicomNetworking}/DicomFindAnswers.cpp          |   9 +-
 .../DicomNetworking}/DicomFindAnswers.h            |   2 +-
 .../DicomNetworking}/DicomServer.cpp               |  44 +-
 .../DicomNetworking}/DicomServer.h                 |  25 +
 .../DicomNetworking}/DicomUserConnection.cpp       |  17 +-
 .../DicomNetworking}/DicomUserConnection.h         |   6 +-
 .../DicomNetworking}/IApplicationEntityFilter.h    |   2 +-
 .../DicomNetworking}/IFindRequestHandler.h         |   2 +
 .../DicomNetworking}/IFindRequestHandlerFactory.h  |   0
 .../DicomNetworking}/IMoveRequestHandler.h         |   0
 .../DicomNetworking}/IMoveRequestHandlerFactory.h  |   0
 .../DicomNetworking}/IStoreRequestHandler.h        |   0
 .../DicomNetworking}/IStoreRequestHandlerFactory.h |   0
 .../DicomNetworking}/IWorklistRequestHandler.h     |   0
 .../IWorklistRequestHandlerFactory.h               |   0
 .../Internals/CommandDispatcher.cpp                |  11 +-
 .../DicomNetworking}/Internals/CommandDispatcher.h |   4 +-
 .../DicomNetworking}/Internals/FindScp.cpp         |  21 +-
 .../DicomNetworking}/Internals/FindScp.h           |   4 +-
 .../DicomNetworking}/Internals/MoveScp.cpp         |  13 +-
 .../DicomNetworking}/Internals/MoveScp.h           |   2 +-
 .../DicomNetworking}/Internals/StoreScp.cpp        |  20 +-
 .../DicomNetworking}/Internals/StoreScp.h          |   2 +-
 .../DicomNetworking}/RemoteModalityParameters.cpp  |   6 +-
 .../DicomNetworking}/RemoteModalityParameters.h    |   2 +-
 .../ReusableDicomUserConnection.cpp                |   6 +-
 .../DicomNetworking}/ReusableDicomUserConnection.h |   0
 .../DicomParsing}/DicomDirWriter.cpp               |  72 ++-
 .../DicomParsing}/DicomDirWriter.h                 |   4 +
 .../DicomParsing}/DicomModification.cpp            |   6 +-
 .../DicomParsing}/DicomModification.h              |   0
 .../DicomParsing}/FromDcmtkBridge.cpp              | 124 ++++-
 .../DicomParsing}/FromDcmtkBridge.h                |  48 +-
 .../DicomParsing}/Internals/DicomFrameIndex.cpp    |  11 +-
 .../DicomParsing}/Internals/DicomFrameIndex.h      |   2 +
 .../DicomParsing}/Internals/DicomImageDecoder.cpp  | 266 +++++++++--
 .../DicomParsing}/Internals/DicomImageDecoder.h    |  18 +-
 .../DicomParsing}/ParsedDicomFile.cpp              | 189 +++++---
 .../DicomParsing}/ParsedDicomFile.h                |  47 +-
 .../DicomParsing}/ToDcmtkBridge.cpp                |   4 +-
 .../DicomParsing}/ToDcmtkBridge.h                  |   6 +-
 Core/Endianness.h                                  |   4 +-
 Core/Enumerations.cpp                              | 233 +++++++++-
 Core/Enumerations.h                                | 108 ++++-
 Core/FileStorage/FilesystemStorage.h               |   8 +
 Core/FileStorage/StorageAccessor.cpp               |  11 +-
 Core/FileStorage/StorageAccessor.h                 |  27 +-
 Core/HttpServer/MongooseServer.cpp                 |  62 ++-
 Core/HttpServer/MongooseServer.h                   |  14 +
 Core/Images/Font.cpp                               |  17 +-
 Core/Images/Font.h                                 |   2 +
 Core/Images/FontRegistry.cpp                       |   4 +
 Core/Images/FontRegistry.h                         |  12 +-
 Core/Images/ImageAccessor.cpp                      |   4 +
 Core/Images/ImageProcessing.cpp                    |  68 ++-
 Core/Images/ImageProcessing.h                      |  10 +-
 Core/Images/JpegErrorManager.h                     |   8 +
 Core/Images/JpegReader.h                           |  16 +-
 Core/Images/JpegWriter.cpp                         |   2 +
 Core/Images/JpegWriter.h                           |   8 +
 Core/Images/PngReader.h                            |   8 +
 Core/Images/PngWriter.cpp                          |   2 +
 Core/Images/PngWriter.h                            |   8 +
 Core/Logging.cpp                                   |   7 +-
 Core/Lua/LuaContext.cpp                            |   2 +
 Core/Lua/LuaContext.h                              |  11 +-
 Core/MultiThreading/Mutex.cpp                      |   4 +-
 Core/PrecompiledHeaders.h                          |  19 +-
 Core/SQLite/OrthancSQLiteException.h               |   5 +
 Core/SQLite/Statement.h                            |   2 +-
 Core/SystemToolbox.cpp                             |  51 ++-
 Core/SystemToolbox.h                               |   2 -
 Core/Toolbox.cpp                                   |  28 +-
 Core/Toolbox.h                                     |  16 +-
 LinuxCompilation.txt                               |   6 +-
 NEWS                                               |  35 ++
 OrthancServer/DefaultDicomImageDecoder.h           |   4 +-
 OrthancServer/DicomInstanceToStore.cpp             |  14 +-
 OrthancServer/DicomInstanceToStore.h               |   2 +-
 OrthancServer/OrthancFindRequestHandler.cpp        |   4 +-
 OrthancServer/OrthancFindRequestHandler.h          |   2 +-
 OrthancServer/OrthancInitialization.cpp            |  82 +---
 OrthancServer/OrthancInitialization.h              |  21 +-
 OrthancServer/OrthancMoveRequestHandler.cpp        |   2 +-
 OrthancServer/OrthancMoveRequestHandler.h          |   2 +-
 .../OrthancRestApi/OrthancRestAnonymizeModify.cpp  |   6 +-
 OrthancServer/OrthancRestApi/OrthancRestApi.cpp    |   1 -
 OrthancServer/OrthancRestApi/OrthancRestApi.h      |   3 +-
 .../OrthancRestApi/OrthancRestArchive.cpp          |  19 +-
 .../OrthancRestApi/OrthancRestModalities.cpp       |   2 +-
 .../OrthancRestApi/OrthancRestResources.cpp        | 117 +++--
 OrthancServer/OrthancRestApi/OrthancRestSystem.cpp |   4 +-
 OrthancServer/PrecompiledHeadersServer.h           |  38 +-
 OrthancServer/QueryRetrieveHandler.cpp             |   2 +-
 OrthancServer/Scheduler/ModifyInstanceCommand.h    |   2 +-
 OrthancServer/Search/HierarchicalMatcher.cpp       |  10 +-
 OrthancServer/Search/HierarchicalMatcher.h         |   3 +-
 OrthancServer/Search/IFindConstraint.cpp           |   2 +-
 OrthancServer/Search/LookupIdentifierQuery.cpp     |   2 +-
 OrthancServer/Search/LookupResource.cpp            |   2 +-
 OrthancServer/ServerContext.cpp                    |  82 +++-
 OrthancServer/ServerContext.h                      |  26 +-
 OrthancServer/ServerEnumerations.cpp               | 191 --------
 OrthancServer/ServerEnumerations.h                 |  87 ----
 OrthancServer/ServerIndex.cpp                      |   4 +-
 OrthancServer/ServerToolbox.cpp                    |  84 +---
 OrthancServer/ServerToolbox.h                      |   2 -
 OrthancServer/main.cpp                             |  48 +-
 Plugins/Engine/OrthancPlugins.cpp                  |   6 +-
 Plugins/Engine/OrthancPlugins.h                    |   8 +-
 Plugins/Engine/PluginsEnumerations.cpp             |  24 +
 Plugins/Engine/PluginsManager.cpp                  |   2 +-
 Plugins/Engine/SharedLibrary.cpp                   |   8 +-
 Plugins/Include/orthanc/OrthancCPlugin.h           |  44 +-
 Plugins/Samples/Common/DicomTag.h                  |   2 +
 Plugins/Samples/Common/OrthancPluginCppWrapper.h   |   4 +-
 Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp   |  12 +
 Plugins/Samples/GdcmDecoder/GdcmImageDecoder.h     |  12 +
 Plugins/Samples/ServeFolders/Plugin.cpp            |   1 +
 Resources/CMake/BoostConfiguration.cmake           | 292 ++++++------
 Resources/CMake/BoostConfiguration.sh              |  26 +-
 Resources/CMake/CivetwebConfiguration.cmake        |  57 +++
 Resources/CMake/Compiler.cmake                     |  62 ++-
 Resources/CMake/DcmtkConfiguration.cmake           |   9 +-
 Resources/CMake/GoogleTestConfiguration.cmake      |  47 +-
 Resources/CMake/JsonCppConfiguration.cmake         |   5 +-
 Resources/CMake/LibCurlConfiguration.cmake         |   3 +-
 Resources/CMake/LibIconvConfiguration.cmake        | 148 +++---
 Resources/CMake/LibP11Configuration.cmake          |   1 +
 .../CMake/OrthancFrameworkConfiguration.cmake      | 509 +++++++++++++++++++++
 Resources/CMake/OrthancFrameworkParameters.cmake   |  96 ++++
 Resources/CMake/PugixmlConfiguration.cmake         |  43 +-
 Resources/CMake/SQLiteConfiguration.cmake          |   8 +-
 .../CMake/VisualStudioPrecompiledHeaders.cmake     |   4 +-
 Resources/CMake/ZlibConfiguration.cmake            |   9 +
 Resources/Configuration.json                       |   6 +
 Resources/OldBuildInstructions.txt                 |   8 +-
 .../OrthancFramework/MicroService/CMakeLists.txt   |  16 +
 .../OrthancFramework/MicroService/README.txt       |   2 +
 .../OrthancFramework/MicroService/Sample.cpp       |  61 +++
 Resources/Samples/Tools/CMakeLists.txt             |  22 +-
 TODO                                               |  11 +
 UnitTestsSources/DicomMapTests.cpp                 | 150 +++++-
 UnitTestsSources/FromDcmtkTests.cpp                |  59 ++-
 UnitTestsSources/ImageTests.cpp                    |   2 +-
 UnitTestsSources/JpegLosslessTests.cpp             |   4 +-
 UnitTestsSources/LuaTests.cpp                      |  11 +-
 UnitTestsSources/MultiThreadingTests.cpp           |   2 +-
 UnitTestsSources/PluginsTests.cpp                  |   4 +-
 UnitTestsSources/RestApiTests.cpp                  |   8 +-
 UnitTestsSources/UnitTestsMain.cpp                 |   8 +-
 UnitTestsSources/VersionsTests.cpp                 |  10 +-
 164 files changed, 3726 insertions(+), 1590 deletions(-)

diff --git a/.hg_archival.txt b/.hg_archival.txt
index 185a01a..8e2e699 100644
--- a/.hg_archival.txt
+++ b/.hg_archival.txt
@@ -1,6 +1,6 @@
 repo: 3959d33612ccaadc0d4d707227fbed09ac35e5fe
-node: ed050cfd5898523069a3304daee76a1822769ba1
-branch: Orthanc-1.3.0
+node: 4d4dff4693b87cb4a29cd563776a739b0e8fdebf
+branch: Orthanc-1.3.1
 latesttag: dcmtk-3.6.1
-latesttagdistance: 21
-changessincelatesttag: 22
+latesttagdistance: 97
+changessincelatesttag: 102
diff --git a/.travis.yml b/.travis.yml
index 1da1cfa..ae15d7a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -44,7 +44,7 @@ before_script:
   - if [ $TRAVIS_OS_NAME == linux -a $TRAVIS_MINGW == OFF ]; then cmake
     -DCMAKE_BUILD_TYPE=Debug "-DDCMTK_LIBRARIES=CharLS;dcmjpls;wrap;oflog"
     -DALLOW_DOWNLOADS=ON -DUSE_SYSTEM_BOOST=OFF -DUSE_SYSTEM_MONGOOSE=OFF -DUSE_SYSTEM_JSONCPP=OFF
-    -DUSE_SYSTEM_GOOGLE_LOG=OFF -DUSE_SYSTEM_PUGIXML=OFF -DUSE_GTEST_DEBIAN_SOURCE_PACKAGE=ON
+    -DUSE_SYSTEM_GOOGLE_LOG=OFF -DUSE_SYSTEM_PUGIXML=OFF -DUSE_GOOGLE_TEST_DEBIAN_PACKAGE=ON
     ..; fi
   - if [ $TRAVIS_OS_NAME == linux -a $TRAVIS_MINGW == ON ]; then cmake
     -DCMAKE_BUILD_TYPE=Debug -DSTATIC_BUILD=ON -DSTANDALONE_BUILD=ON -DALLOW_DOWNLOADS=ON
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d66b960..020a1dc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,180 +2,62 @@ cmake_minimum_required(VERSION 2.8)
 
 project(Orthanc)
 
-# Version of the build, should always be "mainline" except in release branches
-set(ORTHANC_VERSION "1.3.0")
 
-# Version of the database schema. History:
-#   * Orthanc 0.1.0 -> Orthanc 0.3.0 = no versioning
-#   * Orthanc 0.3.1                  = version 2
-#   * Orthanc 0.4.0 -> Orthanc 0.7.2 = version 3
-#   * Orthanc 0.7.3 -> Orthanc 0.8.4 = version 4
-#   * Orthanc 0.8.5 -> Orthanc 0.9.4 = version 5
-#   * Orthanc 0.9.5 -> mainline      = version 6
-set(ORTHANC_DATABASE_VERSION 6)
+#####################################################################
+## Generic parameters of the Orthanc framework
+#####################################################################
+
+include(${CMAKE_SOURCE_DIR}/Resources/CMake/OrthancFrameworkParameters.cmake)
+
+# Enable all the optional components of the Orthanc framework
+set(ENABLE_CRYPTO_OPTIONS ON)
+set(ENABLE_DCMTK ON)
+set(ENABLE_DCMTK_NETWORKING ON)
+set(ENABLE_GOOGLE_TEST ON)
+set(ENABLE_JPEG ON)
+set(ENABLE_LOCALE ON)
+set(ENABLE_LUA ON)
+set(ENABLE_PNG ON)
+set(ENABLE_PUGIXML ON)
+set(ENABLE_SQLITE ON)
+set(ENABLE_WEB_CLIENT ON)
+set(ENABLE_WEB_SERVER ON)
+
+set(HAS_EMBEDDED_RESOURCES ON)
 
 
 #####################################################################
-## CMake parameters tunable at the command line
+## CMake parameters tunable at the command line to configure the
+## plugins, the companion tools, and the unit tests
 #####################################################################
 
 # Parameters of the build
-SET(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)")
-SET(STANDALONE_BUILD ON CACHE BOOL "Standalone build (all the resources are embedded, necessary for releases)")
-SET(ENABLE_SSL ON CACHE BOOL "Include support for SSL")
-SET(DCMTK_DICTIONARY_DIR "" CACHE PATH "Directory containing the DCMTK dictionaries \"dicom.dic\" and \"private.dic\" (only when using system version of DCMTK)") 
-SET(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages")
-SET(UNIT_TESTS_WITH_HTTP_CONNEXIONS ON CACHE BOOL "Allow unit tests to make HTTP requests")
-SET(ENABLE_JPEG ON CACHE BOOL "Enable JPEG decompression")
-SET(ENABLE_JPEG_LOSSLESS ON CACHE BOOL "Enable JPEG-LS (Lossless) decompression")
-SET(ENABLE_PLUGINS ON CACHE BOOL "Enable plugins")
-SET(BUILD_SERVE_FOLDERS ON CACHE BOOL "Whether to build the ServeFolders plugin")
 SET(BUILD_MODALITY_WORKLISTS ON CACHE BOOL "Whether to build the sample plugin to serve modality worklists")
 SET(BUILD_RECOVER_COMPRESSED_FILE ON CACHE BOOL "Whether to build the companion tool to recover files compressed using Orthanc")
-SET(ENABLE_PKCS11 OFF CACHE BOOL "Enable PKCS#11 for HTTPS client authentication using hardware security modules and smart cards")
-SET(ENABLE_PROFILING OFF CACHE BOOL "Whether to enable the generation of profiling information with gprof")
-
-# Advanced parameters to fine-tune linking against system libraries
-SET(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp")
-SET(USE_SYSTEM_GOOGLE_TEST ON CACHE BOOL "Use the system version of Google Test")
-SET(USE_SYSTEM_SQLITE ON CACHE BOOL "Use the system version of SQLite")
-SET(USE_SYSTEM_MONGOOSE ON CACHE BOOL "Use the system version of Mongoose")
-SET(USE_SYSTEM_LUA ON CACHE BOOL "Use the system version of Lua")
-SET(USE_SYSTEM_DCMTK ON CACHE BOOL "Use the system version of DCMTK")
-SET(USE_SYSTEM_BOOST ON CACHE BOOL "Use the system version of Boost")
-SET(USE_SYSTEM_LIBPNG ON CACHE BOOL "Use the system version of libpng")
-SET(USE_SYSTEM_LIBJPEG ON CACHE BOOL "Use the system version of libjpeg")
-SET(USE_SYSTEM_CURL ON CACHE BOOL "Use the system version of LibCurl")
-SET(USE_SYSTEM_OPENSSL ON CACHE BOOL "Use the system version of OpenSSL")
-SET(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib")
-SET(USE_SYSTEM_PUGIXML ON CACHE BOOL "Use the system version of Pugixml")
-SET(USE_SYSTEM_LIBP11 OFF CACHE BOOL "Use the system version of libp11 (PKCS#11 wrapper library)")
-
-# Advanced parameters
-SET(USE_PUGIXML ON CACHE BOOL "Use the Pugixml parser (turn off only for debug)")
-SET(USE_DCMTK_360 OFF CACHE BOOL "Use older DCMTK version 3.6.0 in static builds (instead of default 3.6.2)")
-SET(USE_DCMTK_362_PRIVATE_DIC ON CACHE BOOL "Use the dictionary of private tags from DCMTK 3.6.2 if using DCMTK 3.6.0")
-
-# Distribution-specific settings
-SET(USE_GTEST_DEBIAN_SOURCE_PACKAGE OFF CACHE BOOL "Use the sources of Google Test shipped with libgtest-dev (Debian only)")
-SET(SYSTEM_MONGOOSE_USE_CALLBACKS ON CACHE BOOL "The system version of Mongoose uses callbacks (version >= 3.7)")
-SET(USE_BOOST_ICONV ON CACHE BOOL "Use iconv instead of wconv (Windows only)")
-
-mark_as_advanced(USE_GTEST_DEBIAN_SOURCE_PACKAGE)
-mark_as_advanced(SYSTEM_MONGOOSE_USE_CALLBACKS)
-mark_as_advanced(USE_BOOST_ICONV)
-mark_as_advanced(USE_PUGIXML)
-
-# Path to the root folder of the Orthanc distribution
-set(ORTHANC_ROOT ${CMAKE_SOURCE_DIR})
-set(ENABLE_DCMTK_NETWORK ON)
-set(USE_BOOST_LOCALE_BACKEND OFF)
-
-# Some basic inclusions
-include(CheckIncludeFiles)
-include(CheckIncludeFileCXX)
-include(CheckLibraryExists)
-include(FindPythonInterp)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/AutoGeneratedCode.cmake)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/DownloadPackage.cmake)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/Compiler.cmake)
+SET(BUILD_SERVE_FOLDERS ON CACHE BOOL "Whether to build the ServeFolders plugin")
+SET(ENABLE_PLUGINS ON CACHE BOOL "Enable plugins")
+SET(UNIT_TESTS_WITH_HTTP_CONNEXIONS ON CACHE BOOL "Allow unit tests to make HTTP requests")
+
+
+#####################################################################
+## Configuration of the Orthanc framework
+#####################################################################
+
 include(${CMAKE_SOURCE_DIR}/Resources/CMake/VisualStudioPrecompiledHeaders.cmake)
+include(${CMAKE_SOURCE_DIR}/Resources/CMake/OrthancFrameworkConfiguration.cmake)
 
+include_directories(${ORTHANC_ROOT})
 
 
 #####################################################################
 ## List of source files
 #####################################################################
 
-set(ORTHANC_CORE_SOURCES
-  Core/Cache/MemoryCache.cpp
-  Core/Cache/SharedArchive.cpp
-  Core/ChunkedBuffer.cpp
-  Core/Compression/DeflateBaseCompressor.cpp
-  Core/Compression/GzipCompressor.cpp
-  Core/Compression/HierarchicalZipWriter.cpp
-  Core/Compression/ZipWriter.cpp
-  Core/Compression/ZlibCompressor.cpp
-  Core/DicomFormat/DicomArray.cpp
-  Core/DicomFormat/DicomMap.cpp
-  Core/DicomFormat/DicomTag.cpp
-  Core/DicomFormat/DicomImageInformation.cpp
-  Core/DicomFormat/DicomIntegerPixelAccessor.cpp
-  Core/DicomFormat/DicomInstanceHasher.cpp
-  Core/DicomFormat/DicomValue.cpp
-  Core/Enumerations.cpp
-  Core/FileStorage/FilesystemStorage.cpp
-  Core/FileStorage/StorageAccessor.cpp
-  Core/HttpClient.cpp
-  Core/HttpServer/BufferHttpSender.cpp
-  Core/HttpServer/EmbeddedResourceHttpHandler.cpp
-  Core/HttpServer/FilesystemHttpHandler.cpp
-  Core/HttpServer/HttpToolbox.cpp
-  Core/HttpServer/HttpOutput.cpp
-  Core/HttpServer/StringHttpOutput.cpp
-  Core/HttpServer/MongooseServer.cpp
-  Core/HttpServer/HttpFileSender.cpp
-  Core/HttpServer/FilesystemHttpSender.cpp
-  Core/HttpServer/HttpContentNegociation.cpp
-  Core/HttpServer/HttpStreamTranscoder.cpp
-  Core/Logging.cpp
-  Core/RestApi/RestApiCall.cpp
-  Core/RestApi/RestApiGetCall.cpp
-  Core/RestApi/RestApiHierarchy.cpp
-  Core/RestApi/RestApiPath.cpp
-  Core/RestApi/RestApiOutput.cpp
-  Core/RestApi/RestApi.cpp
-  Core/MultiThreading/BagOfTasksProcessor.cpp
-  Core/MultiThreading/Mutex.cpp
-  Core/MultiThreading/ReaderWriterLock.cpp
-  Core/MultiThreading/RunnableWorkersPool.cpp
-  Core/MultiThreading/Semaphore.cpp
-  Core/MultiThreading/SharedMessageQueue.cpp
-  Core/Images/Font.cpp
-  Core/Images/FontRegistry.cpp
-  Core/Images/IImageWriter.cpp
-  Core/Images/Image.cpp
-  Core/Images/ImageAccessor.cpp
-  Core/Images/ImageBuffer.cpp
-  Core/Images/ImageProcessing.cpp
-  Core/Images/JpegErrorManager.cpp
-  Core/Images/JpegReader.cpp
-  Core/Images/JpegWriter.cpp
-  Core/Images/PngReader.cpp
-  Core/Images/PngWriter.cpp
-  Core/SQLite/Connection.cpp
-  Core/SQLite/FunctionContext.cpp
-  Core/SQLite/Statement.cpp
-  Core/SQLite/StatementId.cpp
-  Core/SQLite/StatementReference.cpp
-  Core/SQLite/Transaction.cpp
-  Core/SystemToolbox.cpp
-  Core/TemporaryFile.cpp
-  Core/Toolbox.cpp
-  Core/WebServiceParameters.cpp
-  Core/Lua/LuaContext.cpp
-  Core/Lua/LuaFunctionCall.cpp
-  )
-
-
 set(ORTHANC_SERVER_SOURCES
   OrthancServer/DatabaseWrapper.cpp
   OrthancServer/DatabaseWrapperBase.cpp
-  OrthancServer/DicomDirWriter.cpp
-  OrthancServer/DicomModification.cpp
-  OrthancServer/DicomProtocol/DicomFindAnswers.cpp
-  OrthancServer/DicomProtocol/DicomServer.cpp
-  OrthancServer/DicomProtocol/DicomUserConnection.cpp
-  OrthancServer/DicomProtocol/RemoteModalityParameters.cpp
-  OrthancServer/DicomProtocol/ReusableDicomUserConnection.cpp
+  OrthancServer/DicomInstanceToStore.cpp
   OrthancServer/ExportedResource.cpp
-  OrthancServer/FromDcmtkBridge.cpp
-  OrthancServer/Internals/CommandDispatcher.cpp
-  OrthancServer/Internals/DicomFrameIndex.cpp
-  OrthancServer/Internals/DicomImageDecoder.cpp
-  OrthancServer/Internals/FindScp.cpp
-  OrthancServer/Internals/MoveScp.cpp
-  OrthancServer/Internals/StoreScp.cpp
   OrthancServer/LuaScripting.cpp
   OrthancServer/OrthancFindRequestHandler.cpp
   OrthancServer/OrthancHttpHandler.cpp
@@ -188,15 +70,22 @@ set(ORTHANC_SERVER_SOURCES
   OrthancServer/OrthancRestApi/OrthancRestModalities.cpp
   OrthancServer/OrthancRestApi/OrthancRestResources.cpp
   OrthancServer/OrthancRestApi/OrthancRestSystem.cpp
-  OrthancServer/ParsedDicomFile.cpp
   OrthancServer/QueryRetrieveHandler.cpp
+  OrthancServer/Scheduler/CallSystemCommand.cpp
+  OrthancServer/Scheduler/DeleteInstanceCommand.cpp
+  OrthancServer/Scheduler/ModifyInstanceCommand.cpp
+  OrthancServer/Scheduler/ServerCommandInstance.cpp
+  OrthancServer/Scheduler/ServerJob.cpp
+  OrthancServer/Scheduler/ServerScheduler.cpp
+  OrthancServer/Scheduler/StorePeerCommand.cpp
+  OrthancServer/Scheduler/StoreScuCommand.cpp
   OrthancServer/Search/HierarchicalMatcher.cpp
   OrthancServer/Search/IFindConstraint.cpp
+  OrthancServer/Search/ListConstraint.cpp
   OrthancServer/Search/LookupIdentifierQuery.cpp
   OrthancServer/Search/LookupResource.cpp
-  OrthancServer/Search/SetOfResources.cpp
-  OrthancServer/Search/ListConstraint.cpp
   OrthancServer/Search/RangeConstraint.cpp
+  OrthancServer/Search/SetOfResources.cpp
   OrthancServer/Search/ValueConstraint.cpp
   OrthancServer/Search/WildcardConstraint.cpp
   OrthancServer/ServerContext.cpp
@@ -204,18 +93,6 @@ set(ORTHANC_SERVER_SOURCES
   OrthancServer/ServerIndex.cpp
   OrthancServer/ServerToolbox.cpp
   OrthancServer/SliceOrdering.cpp
-  OrthancServer/ToDcmtkBridge.cpp
-
-  # From "lua-scripting" branch
-  OrthancServer/DicomInstanceToStore.cpp
-  OrthancServer/Scheduler/DeleteInstanceCommand.cpp
-  OrthancServer/Scheduler/ModifyInstanceCommand.cpp
-  OrthancServer/Scheduler/ServerCommandInstance.cpp
-  OrthancServer/Scheduler/ServerJob.cpp
-  OrthancServer/Scheduler/ServerScheduler.cpp
-  OrthancServer/Scheduler/StorePeerCommand.cpp
-  OrthancServer/Scheduler/StoreScuCommand.cpp
-  OrthancServer/Scheduler/CallSystemCommand.cpp
   )
 
 
@@ -256,27 +133,31 @@ if (ENABLE_PLUGINS)
 endif()
 
 
-set(ORTHANC_ALL_SOURCES
-  ${ORTHANC_CORE_SOURCES}
-  ${ORTHANC_SERVER_SOURCES}
-  ${ORTHANC_UNIT_TESTS_SOURCES}
-  Plugins/Samples/ServeFolders/Plugin.cpp
-  Plugins/Samples/ModalityWorklists/Plugin.cpp
-  OrthancServer/main.cpp
-  )
-
-
 if (CMAKE_COMPILER_IS_GNUCXX
     AND NOT CMAKE_CROSSCOMPILING 
     AND USE_DCMTK_360)
   # Add the "-pedantic" flag only on the Orthanc sources, and only if
-  # using DCMTK 3.6.0
+  # cross-compiling DCMTK 3.6.0
+  set(ORTHANC_ALL_SOURCES
+    ${ORTHANC_CORE_SOURCES_INTERNAL}
+    ${ORTHANC_DICOM_SOURCES_INTERNAL}
+    ${ORTHANC_SERVER_SOURCES}
+    ${ORTHANC_UNIT_TESTS_SOURCES}
+    Plugins/Samples/ServeFolders/Plugin.cpp
+    Plugins/Samples/ModalityWorklists/Plugin.cpp
+    OrthancServer/main.cpp
+    )
+
   set_source_files_properties(${ORTHANC_ALL_SOURCES}
     PROPERTIES COMPILE_FLAGS -pedantic
     )
 endif()
 
 
+#####################################################################
+## Autogeneration of files
+#####################################################################
+
 set(ORTHANC_EMBEDDED_FILES
   PREPARE_DATABASE            ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/PrepareDatabase.sql
   UPGRADE_DATABASE_3_TO_4     ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/Upgrade3To4.sql
@@ -287,78 +168,6 @@ set(ORTHANC_EMBEDDED_FILES
   FONT_UBUNTU_MONO_BOLD_16    ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Fonts/UbuntuMonoBold-16.json
   )
 
-
-
-#####################################################################
-## Inclusion of third-party dependencies
-#####################################################################
-
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/JsonCppConfiguration.cmake)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibCurlConfiguration.cmake)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibPngConfiguration.cmake)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibJpegConfiguration.cmake)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/LuaConfiguration.cmake)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/MongooseConfiguration.cmake)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/PugixmlConfiguration.cmake)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/SQLiteConfiguration.cmake)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/ZlibConfiguration.cmake)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/GoogleTestConfiguration.cmake)
-
-# These are the two most heavyweight dependencies. We put them as the
-# last includes to quickly spot problems when configuring static
-# builds.
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/BoostConfiguration.cmake)
-include(${CMAKE_SOURCE_DIR}/Resources/CMake/DcmtkConfiguration.cmake)
-
-
-if (ENABLE_SSL)
-  add_definitions(-DORTHANC_ENABLE_SSL=1)
-  include(${CMAKE_SOURCE_DIR}/Resources/CMake/OpenSslConfiguration.cmake)
-else()
-  add_definitions(-DORTHANC_ENABLE_SSL=0)
-endif()
-
-
-if (ENABLE_JPEG)
-  add_definitions(-DORTHANC_ENABLE_JPEG=1)
-else()
-  add_definitions(-DORTHANC_ENABLE_JPEG=0)
-endif()
-
-
-if (ENABLE_JPEG_LOSSLESS)
-  add_definitions(-DORTHANC_ENABLE_JPEG_LOSSLESS=1)
-else()
-  add_definitions(-DORTHANC_ENABLE_JPEG_LOSSLESS=0)
-endif()
-
-
-if (ENABLE_PLUGINS)
-  add_definitions(-DORTHANC_ENABLE_PLUGINS=1)
-else()
-  add_definitions(-DORTHANC_ENABLE_PLUGINS=0)
-endif()
-
-
-if (ENABLE_PKCS11)
-  if (ENABLE_SSL)
-    include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibP11Configuration.cmake)
-
-    add_definitions(-DORTHANC_ENABLE_PKCS11=1)
-    list(APPEND ORTHANC_CORE_SOURCES Core/Pkcs11.cpp)
-  else()
-    message(FATAL_ERROR "OpenSSL is required to enable PKCS#11")
-  endif()
-else()
-  add_definitions(-DORTHANC_ENABLE_PKCS11=0)  
-endif()
-
-
-
-#####################################################################
-## Autogeneration of files
-#####################################################################
-
 if (STANDALONE_BUILD)
   # We embed all the resources in the binaries for standalone builds
   add_definitions(-DORTHANC_STANDALONE=1)
@@ -399,26 +208,25 @@ endif()
 ## Configuration of the C/C++ macros
 #####################################################################
 
+if (ENABLE_PLUGINS)
+  add_definitions(-DORTHANC_ENABLE_PLUGINS=1)
+else()
+  add_definitions(-DORTHANC_ENABLE_PLUGINS=0)
+endif()
+
+
 if (UNIT_TESTS_WITH_HTTP_CONNEXIONS)
   add_definitions(-DUNIT_TESTS_WITH_HTTP_CONNEXIONS=1)
 else()
   add_definitions(-DUNIT_TESTS_WITH_HTTP_CONNEXIONS=0)
 endif()
 
+
 include_directories(${CMAKE_SOURCE_DIR}/Plugins/Include)
 
 add_definitions(
-  -DORTHANC_VERSION="${ORTHANC_VERSION}"
-  -DORTHANC_DATABASE_VERSION=${ORTHANC_DATABASE_VERSION}
   -DORTHANC_BUILD_UNIT_TESTS=1
-  -DORTHANC_ENABLE_BASE64=1
-  -DORTHANC_ENABLE_LOGGING=1
-  -DORTHANC_ENABLE_LOGGING_PLUGIN=0
-  -DORTHANC_ENABLE_LUA=1
-  -DORTHANC_ENABLE_MD5=1
-  -DORTHANC_MAXIMUM_TAG_LENGTH=256
-  -DORTHANC_SANDBOXED=0
-
+  
   # Macros for the plugins
   -DHAS_ORTHANC_EXCEPTION=0
   -DMODALITY_WORKLISTS_VERSION="${ORTHANC_VERSION}"
@@ -435,14 +243,22 @@ add_definitions(
 if (MSVC)
   add_definitions(-DORTHANC_USE_PRECOMPILED_HEADERS=1)
 
+  set(TMP
+    ${ORTHANC_CORE_SOURCES_INTERNAL}
+    ${ORTHANC_DICOM_SOURCES_INTERNAL}
+    )
+  
   ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS(
-    "PrecompiledHeaders.h" "Core/PrecompiledHeaders.cpp" ORTHANC_CORE_SOURCES)
+    "PrecompiledHeaders.h" "Core/PrecompiledHeaders.cpp"
+    TMP ORTHANC_CORE_PCH)
 
   ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS(
-    "PrecompiledHeadersServer.h" "OrthancServer/PrecompiledHeadersServer.cpp" ORTHANC_SERVER_SOURCES)
+    "PrecompiledHeadersServer.h" "OrthancServer/PrecompiledHeadersServer.cpp"
+    ORTHANC_SERVER_SOURCES ORTHANC_SERVER_PCH)
 
   ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS(
-    "PrecompiledHeadersUnitTests.h" "UnitTestsSources/PrecompiledHeadersUnitTests.cpp" ORTHANC_UNIT_TESTS_SOURCES)
+    "PrecompiledHeadersUnitTests.h" "UnitTestsSources/PrecompiledHeadersUnitTests.cpp"
+    ORTHANC_UNIT_TESTS_SOURCES ORTHANC_UNIT_TESTS_PCH)
 endif()
 
 
@@ -451,36 +267,14 @@ endif()
 ## Build the core of Orthanc
 #####################################################################
 
-list(LENGTH OPENSSL_SOURCES OPENSSL_SOURCES_LENGTH)
-if (${OPENSSL_SOURCES_LENGTH} GREATER 0)
-  add_library(OpenSSL STATIC ${OPENSSL_SOURCES})
-endif()
-
-# "CodeLibrary" contains all the third-party dependencies and the
-# content of the "Core" folder, but not OpenSSL, nor DCMTK.
+# "CoreLibrary" contains all the third-party dependencies and the
+# content of the "Core" folder
 add_library(CoreLibrary
   STATIC
+  ${ORTHANC_CORE_PCH}
   ${ORTHANC_CORE_SOURCES}
+  ${ORTHANC_DICOM_SOURCES}
   ${AUTOGENERATED_SOURCES}
-
-  ${BOOST_SOURCES}
-  ${CURL_SOURCES}
-  ${JSONCPP_SOURCES}
-  ${LIBPNG_SOURCES}
-  ${LIBJPEG_SOURCES}
-  ${LUA_SOURCES}
-  ${MONGOOSE_SOURCES}
-  ${PUGIXML_SOURCES}
-  ${SQLITE_SOURCES}
-  ${ZLIB_SOURCES}
-  ${LIBP11_SOURCES}
-
-  ${CMAKE_SOURCE_DIR}/Resources/ThirdParty/md5/md5.c
-  ${CMAKE_SOURCE_DIR}/Resources/ThirdParty/base64/base64.cpp
-
-  # This is the minizip distribution to create ZIP files using zlib
-  ${ORTHANC_ROOT}/Resources/ThirdParty/minizip/ioapi.c
-  ${ORTHANC_ROOT}/Resources/ThirdParty/minizip/zip.c
   )  
 
 
@@ -488,10 +282,9 @@ add_library(CoreLibrary
 ## Build the Orthanc server
 #####################################################################
 
-# "ServerLibrary" contains DCMTK
 add_library(ServerLibrary
   STATIC
-  ${DCMTK_SOURCES}
+  ${ORTHANC_SERVER_PCH}
   ${ORTHANC_SERVER_SOURCES}
   )
 
@@ -505,32 +298,28 @@ add_executable(Orthanc
 
 target_link_libraries(Orthanc ServerLibrary CoreLibrary ${DCMTK_LIBRARIES})
 
-if (${OPENSSL_SOURCES_LENGTH} GREATER 0)
-  target_link_libraries(Orthanc OpenSSL)
-endif()
-
 install(
   TARGETS Orthanc
   RUNTIME DESTINATION sbin
   )
 
 
-
 #####################################################################
 ## Build the unit tests
 #####################################################################
 
 add_executable(UnitTests
-  ${GTEST_SOURCES}
+  ${GOOGLE_TEST_SOURCES}
+  ${ORTHANC_UNIT_TESTS_PCH}
   ${ORTHANC_UNIT_TESTS_SOURCES}
   )
 
-target_link_libraries(UnitTests ServerLibrary CoreLibrary ${DCMTK_LIBRARIES})
-
-if (${OPENSSL_SOURCES_LENGTH} GREATER 0)
-  target_link_libraries(UnitTests OpenSSL)
-endif()
-
+target_link_libraries(UnitTests
+  ServerLibrary
+  CoreLibrary
+  ${DCMTK_LIBRARIES}
+  ${GOOGLE_TEST_LIBRARIES}
+  )
 
 
 #####################################################################
@@ -557,6 +346,7 @@ if (ENABLE_PLUGINS AND BUILD_SERVE_FOLDERS)
   add_library(ServeFolders SHARED 
     ${BOOST_SOURCES}
     ${JSONCPP_SOURCES}
+    ${LIBICONV_SOURCES}
     Plugins/Samples/ServeFolders/Plugin.cpp
     Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
     ${SERVE_FOLDERS_RESOURCES}
@@ -601,6 +391,7 @@ if (ENABLE_PLUGINS AND BUILD_MODALITY_WORKLISTS)
   add_library(ModalityWorklists SHARED 
     ${BOOST_SOURCES}
     ${JSONCPP_SOURCES}
+    ${LIBICONV_SOURCES}
     Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
     Plugins/Samples/ModalityWorklists/Plugin.cpp
     ${MODALITY_WORKLISTS_RESOURCES}
diff --git a/Core/Cache/SharedArchive.h b/Core/Cache/SharedArchive.h
index 19cab4a..ff0b163 100644
--- a/Core/Cache/SharedArchive.h
+++ b/Core/Cache/SharedArchive.h
@@ -33,6 +33,14 @@
 
 #pragma once
 
+#if !defined(ORTHANC_SANDBOXED)
+#  error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if ORTHANC_SANDBOXED == 1
+#  error The class SharedArchive cannot be used in sandboxed environments
+#endif
+
 #include "LeastRecentlyUsedIndex.h"
 #include "../IDynamicObject.h"
 
diff --git a/Core/Compression/HierarchicalZipWriter.h b/Core/Compression/HierarchicalZipWriter.h
index f77d735..4237442 100644
--- a/Core/Compression/HierarchicalZipWriter.h
+++ b/Core/Compression/HierarchicalZipWriter.h
@@ -39,6 +39,10 @@
 #include <list>
 #include <boost/lexical_cast.hpp>
 
+#if ORTHANC_BUILD_UNIT_TESTS == 1
+#  include <gtest/gtest_prod.h>
+#endif
+
 namespace Orthanc
 {
   class HierarchicalZipWriter
diff --git a/Core/Compression/ZipWriter.h b/Core/Compression/ZipWriter.h
index f4db7d4..d5b8705 100644
--- a/Core/Compression/ZipWriter.h
+++ b/Core/Compression/ZipWriter.h
@@ -37,10 +37,6 @@
 #include <string>
 #include <boost/shared_ptr.hpp>
 
-#if ORTHANC_BUILD_UNIT_TESTS == 1
-#include <gtest/gtest_prod.h>
-#endif
-
 namespace Orthanc
 {
   class ZipWriter
diff --git a/Core/DicomFormat/DicomImageInformation.cpp b/Core/DicomFormat/DicomImageInformation.cpp
index cc68131..1bfb153 100644
--- a/Core/DicomFormat/DicomImageInformation.cpp
+++ b/Core/DicomFormat/DicomImageInformation.cpp
@@ -178,19 +178,21 @@ namespace Orthanc
       throw OrthancException(ErrorCode_NotImplemented);
     }
 
-    try
+    if (values.HasTag(DICOM_TAG_NUMBER_OF_FRAMES))
     {
-      numberOfFrames_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_NUMBER_OF_FRAMES).GetContent());
+      try
+      {
+        numberOfFrames_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_NUMBER_OF_FRAMES).GetContent());
+      }
+      catch (boost::bad_lexical_cast&)
+      {
+        throw OrthancException(ErrorCode_NotImplemented);
+      }
     }
-    catch (OrthancException&)
+    else
     {
-      // If the tag "NumberOfFrames" is absent, assume there is a single frame
       numberOfFrames_ = 1;
     }
-    catch (boost::bad_lexical_cast&)
-    {
-      throw OrthancException(ErrorCode_NotImplemented);
-    }
 
     if ((bitsAllocated_ != 8 && bitsAllocated_ != 16 && 
          bitsAllocated_ != 24 && bitsAllocated_ != 32) ||
@@ -217,9 +219,19 @@ namespace Orthanc
   {
     if (photometric_ == PhotometricInterpretation_Palette)
     {
-      return false;
-    }
+      if (GetBitsStored() == 8 && GetChannelCount() == 1 && !IsSigned())
+      {
+        format = PixelFormat_RGB24;
+        return true;
+      }
 
+      if (GetBitsStored() == 16 && GetChannelCount() == 1 && !IsSigned())
+      {
+        format = PixelFormat_RGB48;
+        return true;
+      }
+    }
+    
     if (ignorePhotometricInterpretation ||
         photometric_ == PhotometricInterpretation_Monochrome1 ||
         photometric_ == PhotometricInterpretation_Monochrome2)
diff --git a/Core/DicomFormat/DicomMap.cpp b/Core/DicomFormat/DicomMap.cpp
index c11ee82..621fd98 100644
--- a/Core/DicomFormat/DicomMap.cpp
+++ b/Core/DicomFormat/DicomMap.cpp
@@ -36,7 +36,9 @@
 
 #include <stdio.h>
 #include <memory>
+
 #include "../Endianness.h"
+#include "../Logging.h"
 #include "../OrthancException.h"
 
 
@@ -781,4 +783,193 @@ namespace Orthanc
 
     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);
+    }
+  }
 }
diff --git a/Core/DicomFormat/DicomMap.h b/Core/DicomFormat/DicomMap.h
index 80732ef..fd5f2dc 100644
--- a/Core/DicomFormat/DicomMap.h
+++ b/Core/DicomFormat/DicomMap.h
@@ -181,5 +181,29 @@ namespace Orthanc
     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;                                
   };
 }
diff --git a/Core/DicomFormat/DicomTag.h b/Core/DicomFormat/DicomTag.h
index 6b9ba90..14edf5d 100644
--- a/Core/DicomFormat/DicomTag.h
+++ b/Core/DicomFormat/DicomTag.h
@@ -173,6 +173,17 @@ namespace Orthanc
   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);  
diff --git a/Core/DicomFormat/DicomValue.cpp b/Core/DicomFormat/DicomValue.cpp
index 9c8958d..507352a 100644
--- a/Core/DicomFormat/DicomValue.cpp
+++ b/Core/DicomFormat/DicomValue.cpp
@@ -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 @@ namespace Orthanc
   }
 #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;
+    }
+  }    
 }
diff --git a/Core/DicomFormat/DicomValue.h b/Core/DicomFormat/DicomValue.h
index 405cdda..5b607ed 100644
--- a/Core/DicomFormat/DicomValue.h
+++ b/Core/DicomFormat/DicomValue.h
@@ -33,6 +33,7 @@
 
 #pragma once
 
+#include <stdint.h>
 #include <string>
 #include <boost/noncopyable.hpp>
 
@@ -93,5 +94,20 @@ namespace Orthanc
       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;                                
   };
 }
diff --git a/OrthancServer/DicomProtocol/DicomFindAnswers.cpp b/Core/DicomNetworking/DicomFindAnswers.cpp
similarity index 95%
rename from OrthancServer/DicomProtocol/DicomFindAnswers.cpp
rename to Core/DicomNetworking/DicomFindAnswers.cpp
index c32f26a..d418bc0 100644
--- a/OrthancServer/DicomProtocol/DicomFindAnswers.cpp
+++ b/Core/DicomNetworking/DicomFindAnswers.cpp
@@ -31,12 +31,11 @@
  **/
 
 
-#include "../PrecompiledHeadersServer.h"
+#include "../PrecompiledHeaders.h"
 #include "DicomFindAnswers.h"
 
-#include "../OrthancInitialization.h"
-#include "../FromDcmtkBridge.h"
-#include "../../Core/OrthancException.h"
+#include "../DicomParsing/FromDcmtkBridge.h"
+#include "../OrthancException.h"
 
 #include <memory>
 #include <dcmtk/dcmdata/dcfilefo.h>
@@ -64,7 +63,7 @@ namespace Orthanc
 
 
   DicomFindAnswers::DicomFindAnswers(bool isWorklist) : 
-    encoding_(Configuration::GetDefaultEncoding()),
+    encoding_(GetDefaultDicomEncoding()),
     isWorklist_(isWorklist),
     complete_(true)
   {
diff --git a/OrthancServer/DicomProtocol/DicomFindAnswers.h b/Core/DicomNetworking/DicomFindAnswers.h
similarity index 98%
rename from OrthancServer/DicomProtocol/DicomFindAnswers.h
rename to Core/DicomNetworking/DicomFindAnswers.h
index da07d76..ffaa841 100644
--- a/OrthancServer/DicomProtocol/DicomFindAnswers.h
+++ b/Core/DicomNetworking/DicomFindAnswers.h
@@ -33,7 +33,7 @@
 
 #pragma once
 
-#include "../ParsedDicomFile.h"
+#include "../DicomParsing/ParsedDicomFile.h"
 
 namespace Orthanc
 {
diff --git a/OrthancServer/DicomProtocol/DicomServer.cpp b/Core/DicomNetworking/DicomServer.cpp
similarity index 91%
rename from OrthancServer/DicomProtocol/DicomServer.cpp
rename to Core/DicomNetworking/DicomServer.cpp
index c9337e4..e63f4f7 100644
--- a/OrthancServer/DicomProtocol/DicomServer.cpp
+++ b/Core/DicomNetworking/DicomServer.cpp
@@ -31,16 +31,14 @@
  **/
 
 
-#include "../PrecompiledHeadersServer.h"
+#include "../PrecompiledHeaders.h"
 #include "DicomServer.h"
 
 #include "../../Core/Logging.h"
+#include "../../Core/MultiThreading/RunnableWorkersPool.h"
 #include "../../Core/OrthancException.h"
 #include "../../Core/Toolbox.h"
-#include "../Internals/CommandDispatcher.h"
-#include "../OrthancInitialization.h"
-#include "EmbeddedResources.h"
-#include "../../Core/MultiThreading/RunnableWorkersPool.h"
+#include "Internals/CommandDispatcher.h"
 
 #include <boost/thread.hpp>
 
@@ -91,6 +89,7 @@ namespace Orthanc
     aet_("ANY-SCP")
   {
     port_ = 104;
+    modalities_ = NULL;
     findRequestHandlerFactory_ = NULL;
     moveRequestHandlerFactory_ = NULL;
     storeRequestHandlerFactory_ = NULL;
@@ -180,6 +179,24 @@ namespace Orthanc
     return aet_;
   }
 
+  void DicomServer::SetRemoteModalities(IRemoteModalities& modalities)
+  {
+    Stop();
+    modalities_ = &modalities;
+  }
+  
+  DicomServer::IRemoteModalities& DicomServer::GetRemoteModalities() const
+  {
+    if (modalities_ == NULL)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      return *modalities_;
+    }
+  }
+    
   void DicomServer::SetFindRequestHandlerFactory(IFindRequestHandlerFactory& factory)
   {
     Stop();
@@ -297,6 +314,12 @@ namespace Orthanc
 
   void DicomServer::Start()
   {
+    if (modalities_ == NULL)
+    {
+      LOG(ERROR) << "No list of modalities was provided to the DICOM server";
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+    
     Stop();
 
     /* initialize network, i.e. create an instance of T_ASC_Network*. */
@@ -340,13 +363,20 @@ namespace Orthanc
 
   bool DicomServer::IsMyAETitle(const std::string& aet) const
   {
+    if (modalities_ == NULL)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+    
     if (!HasCalledApplicationEntityTitleCheck())
     {
       // OK, no check on the AET.
       return true;
     }
-
-    return Configuration::IsSameAETitle(aet, GetApplicationEntityTitle());
+    else
+    {
+      return modalities_->IsSameAETitle(aet, GetApplicationEntityTitle());
+    }
   }
 
 }
diff --git a/OrthancServer/DicomProtocol/DicomServer.h b/Core/DicomNetworking/DicomServer.h
similarity index 83%
rename from OrthancServer/DicomProtocol/DicomServer.h
rename to Core/DicomNetworking/DicomServer.h
index 5afadda..a00f919 100644
--- a/OrthancServer/DicomProtocol/DicomServer.h
+++ b/Core/DicomNetworking/DicomServer.h
@@ -33,11 +33,16 @@
 
 #pragma once
 
+#if ORTHANC_ENABLE_DCMTK_NETWORKING != 1
+#  error The macro ORTHANC_ENABLE_DCMTK_NETWORKING must be set to 1
+#endif
+
 #include "IFindRequestHandlerFactory.h"
 #include "IMoveRequestHandlerFactory.h"
 #include "IStoreRequestHandlerFactory.h"
 #include "IWorklistRequestHandlerFactory.h"
 #include "IApplicationEntityFilter.h"
+#include "RemoteModalityParameters.h"
 
 #include <boost/shared_ptr.hpp>
 #include <boost/noncopyable.hpp>
@@ -47,6 +52,22 @@ namespace Orthanc
 {
   class DicomServer : public boost::noncopyable
   {
+  public:
+    // WARNING: The methods of this class must be thread-safe
+    class IRemoteModalities : public boost::noncopyable
+    {
+    public:
+      virtual ~IRemoteModalities()
+      {
+      }
+      
+      virtual bool IsSameAETitle(const std::string& aet1,
+                                 const std::string& aet2) = 0;
+
+      virtual bool LookupAETitle(RemoteModalityParameters& modality,
+                                 const std::string& aet) = 0;
+    };
+    
   private:
     struct PImpl;
     boost::shared_ptr<PImpl> pimpl_;
@@ -56,6 +77,7 @@ namespace Orthanc
     uint16_t port_;
     bool continue_;
     uint32_t associationTimeout_;
+    IRemoteModalities* modalities_;
     IFindRequestHandlerFactory* findRequestHandlerFactory_;
     IMoveRequestHandlerFactory* moveRequestHandlerFactory_;
     IStoreRequestHandlerFactory* storeRequestHandlerFactory_;
@@ -81,6 +103,9 @@ namespace Orthanc
     void SetApplicationEntityTitle(const std::string& aet);
     const std::string& GetApplicationEntityTitle() const;
 
+    void SetRemoteModalities(IRemoteModalities& modalities);
+    IRemoteModalities& GetRemoteModalities() const;
+    
     void SetFindRequestHandlerFactory(IFindRequestHandlerFactory& handler);
     bool HasFindRequestHandlerFactory() const;
     IFindRequestHandlerFactory& GetFindRequestHandlerFactory() const;
diff --git a/OrthancServer/DicomProtocol/DicomUserConnection.cpp b/Core/DicomNetworking/DicomUserConnection.cpp
similarity index 99%
rename from OrthancServer/DicomProtocol/DicomUserConnection.cpp
rename to Core/DicomNetworking/DicomUserConnection.cpp
index fccc033..927545d 100644
--- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp
+++ b/Core/DicomNetworking/DicomUserConnection.cpp
@@ -79,15 +79,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 =========================================================================*/
 
 
-#include "../PrecompiledHeadersServer.h"
+#include "../PrecompiledHeaders.h"
 #include "DicomUserConnection.h"
 
-#include "../../Core/DicomFormat/DicomArray.h"
-#include "../../Core/Logging.h"
-#include "../../Core/OrthancException.h"
-#include "../FromDcmtkBridge.h"
-#include "../ToDcmtkBridge.h"
-#include "../OrthancInitialization.h"
+#include "../DicomFormat/DicomArray.h"
+#include "../Logging.h"
+#include "../OrthancException.h"
+#include "../DicomParsing/FromDcmtkBridge.h"
+#include "../DicomParsing/ToDcmtkBridge.h"
 
 #include <dcmtk/dcmdata/dcistrmb.h>
 #include <dcmtk/dcmdata/dcistrmf.h>
@@ -402,8 +401,8 @@ namespace Orthanc
       else
       {
         DicomMap m;
-        Configuration::ExtractDicomSummary(m, *responseIdentifiers);
-
+        FromDcmtkBridge::ExtractDicomSummary(m, *responseIdentifiers);
+        
         if (!m.HasTag(DICOM_TAG_QUERY_RETRIEVE_LEVEL))
         {
           m.SetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL, payload.level, false);
diff --git a/OrthancServer/DicomProtocol/DicomUserConnection.h b/Core/DicomNetworking/DicomUserConnection.h
similarity index 97%
rename from OrthancServer/DicomProtocol/DicomUserConnection.h
rename to Core/DicomNetworking/DicomUserConnection.h
index d3a7b4d..6a2b1f1 100644
--- a/OrthancServer/DicomProtocol/DicomUserConnection.h
+++ b/Core/DicomNetworking/DicomUserConnection.h
@@ -33,8 +33,12 @@
 
 #pragma once
 
+#if ORTHANC_ENABLE_DCMTK_NETWORKING != 1
+#  error The macro ORTHANC_ENABLE_DCMTK_NETWORKING must be set to 1
+#endif
+
 #include "DicomFindAnswers.h"
-#include "../ServerEnumerations.h"
+#include "../Enumerations.h"
 #include "RemoteModalityParameters.h"
 
 #include <stdint.h>
diff --git a/OrthancServer/DicomProtocol/IApplicationEntityFilter.h b/Core/DicomNetworking/IApplicationEntityFilter.h
similarity index 98%
rename from OrthancServer/DicomProtocol/IApplicationEntityFilter.h
rename to Core/DicomNetworking/IApplicationEntityFilter.h
index 2e46d5d..7276968 100644
--- a/OrthancServer/DicomProtocol/IApplicationEntityFilter.h
+++ b/Core/DicomNetworking/IApplicationEntityFilter.h
@@ -33,7 +33,7 @@
 
 #pragma once
 
-#include "../ServerEnumerations.h"
+#include "../Enumerations.h"
 
 #include <string>
 
diff --git a/OrthancServer/DicomProtocol/IFindRequestHandler.h b/Core/DicomNetworking/IFindRequestHandler.h
similarity index 99%
rename from OrthancServer/DicomProtocol/IFindRequestHandler.h
rename to Core/DicomNetworking/IFindRequestHandler.h
index 91eef22..227385e 100644
--- a/OrthancServer/DicomProtocol/IFindRequestHandler.h
+++ b/Core/DicomNetworking/IFindRequestHandler.h
@@ -35,6 +35,8 @@
 
 #include "DicomFindAnswers.h"
 
+#include <list>
+
 namespace Orthanc
 {
   class IFindRequestHandler : public boost::noncopyable
diff --git a/OrthancServer/DicomProtocol/IFindRequestHandlerFactory.h b/Core/DicomNetworking/IFindRequestHandlerFactory.h
similarity index 100%
rename from OrthancServer/DicomProtocol/IFindRequestHandlerFactory.h
rename to Core/DicomNetworking/IFindRequestHandlerFactory.h
diff --git a/OrthancServer/DicomProtocol/IMoveRequestHandler.h b/Core/DicomNetworking/IMoveRequestHandler.h
similarity index 100%
rename from OrthancServer/DicomProtocol/IMoveRequestHandler.h
rename to Core/DicomNetworking/IMoveRequestHandler.h
diff --git a/OrthancServer/DicomProtocol/IMoveRequestHandlerFactory.h b/Core/DicomNetworking/IMoveRequestHandlerFactory.h
similarity index 100%
rename from OrthancServer/DicomProtocol/IMoveRequestHandlerFactory.h
rename to Core/DicomNetworking/IMoveRequestHandlerFactory.h
diff --git a/OrthancServer/DicomProtocol/IStoreRequestHandler.h b/Core/DicomNetworking/IStoreRequestHandler.h
similarity index 100%
rename from OrthancServer/DicomProtocol/IStoreRequestHandler.h
rename to Core/DicomNetworking/IStoreRequestHandler.h
diff --git a/OrthancServer/DicomProtocol/IStoreRequestHandlerFactory.h b/Core/DicomNetworking/IStoreRequestHandlerFactory.h
similarity index 100%
rename from OrthancServer/DicomProtocol/IStoreRequestHandlerFactory.h
rename to Core/DicomNetworking/IStoreRequestHandlerFactory.h
diff --git a/OrthancServer/DicomProtocol/IWorklistRequestHandler.h b/Core/DicomNetworking/IWorklistRequestHandler.h
similarity index 100%
rename from OrthancServer/DicomProtocol/IWorklistRequestHandler.h
rename to Core/DicomNetworking/IWorklistRequestHandler.h
diff --git a/OrthancServer/DicomProtocol/IWorklistRequestHandlerFactory.h b/Core/DicomNetworking/IWorklistRequestHandlerFactory.h
similarity index 100%
rename from OrthancServer/DicomProtocol/IWorklistRequestHandlerFactory.h
rename to Core/DicomNetworking/IWorklistRequestHandlerFactory.h
diff --git a/OrthancServer/Internals/CommandDispatcher.cpp b/Core/DicomNetworking/Internals/CommandDispatcher.cpp
similarity index 99%
rename from OrthancServer/Internals/CommandDispatcher.cpp
rename to Core/DicomNetworking/Internals/CommandDispatcher.cpp
index 71ed77e..aaf2d8f 100644
--- a/OrthancServer/Internals/CommandDispatcher.cpp
+++ b/Core/DicomNetworking/Internals/CommandDispatcher.cpp
@@ -80,14 +80,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 =========================================================================*/
 
 
-#include "../PrecompiledHeadersServer.h"
+#include "../../PrecompiledHeaders.h"
 #include "CommandDispatcher.h"
 
 #include "FindScp.h"
 #include "StoreScp.h"
 #include "MoveScp.h"
-#include "../../Core/Toolbox.h"
-#include "../../Core/Logging.h"
+#include "../../Toolbox.h"
+#include "../../Logging.h"
 
 #include <dcmtk/dcmnet/dcasccfg.h>      /* for class DcmAssociationConfiguration */
 #include <boost/lexical_cast.hpp>
@@ -871,8 +871,9 @@ namespace Orthanc
                   worklistHandler.reset(server_.GetWorklistRequestHandlerFactory().ConstructWorklistRequestHandler());
                 }
 
-                cond = Internals::findScp(assoc_, &msg, presID, findHandler.get(), 
-                                          worklistHandler.get(), remoteIp_, remoteAet_, calledAet_);
+                cond = Internals::findScp(assoc_, &msg, presID, server_.GetRemoteModalities(),
+                                          findHandler.get(), worklistHandler.get(),
+                                          remoteIp_, remoteAet_, calledAet_);
               }
               break;
 
diff --git a/OrthancServer/Internals/CommandDispatcher.h b/Core/DicomNetworking/Internals/CommandDispatcher.h
similarity index 96%
rename from OrthancServer/Internals/CommandDispatcher.h
rename to Core/DicomNetworking/Internals/CommandDispatcher.h
index 84553eb..5e645a9 100644
--- a/OrthancServer/Internals/CommandDispatcher.h
+++ b/Core/DicomNetworking/Internals/CommandDispatcher.h
@@ -33,8 +33,8 @@
 
 #pragma once
 
-#include "../DicomProtocol/DicomServer.h"
-#include "../../Core/MultiThreading/IRunnableBySteps.h"
+#include "../DicomServer.h"
+#include "../../MultiThreading/IRunnableBySteps.h"
 
 #include <dcmtk/dcmnet/dimse.h>
 
diff --git a/OrthancServer/Internals/FindScp.cpp b/Core/DicomNetworking/Internals/FindScp.cpp
similarity index 95%
rename from OrthancServer/Internals/FindScp.cpp
rename to Core/DicomNetworking/Internals/FindScp.cpp
index a17e601..daa6d62 100644
--- a/OrthancServer/Internals/FindScp.cpp
+++ b/Core/DicomNetworking/Internals/FindScp.cpp
@@ -80,14 +80,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 
-#include "../PrecompiledHeadersServer.h"
+#include "../../PrecompiledHeaders.h"
 #include "FindScp.h"
 
-#include "../FromDcmtkBridge.h"
-#include "../ToDcmtkBridge.h"
-#include "../../Core/Logging.h"
-#include "../../Core/OrthancException.h"
-#include "../OrthancInitialization.h"
+#include "../../DicomParsing/FromDcmtkBridge.h"
+#include "../../DicomParsing/ToDcmtkBridge.h"
+#include "../../Logging.h"
+#include "../../OrthancException.h"
 
 #include <dcmtk/dcmdata/dcfilefo.h>
 #include <dcmtk/dcmdata/dcdeftag.h>
@@ -139,6 +138,7 @@ namespace Orthanc
   {  
     struct FindScpData
     {
+      DicomServer::IRemoteModalities* modalities_;
       IFindRequestHandler* findHandler_;
       IWorklistRequestHandler* worklistHandler_;
       DicomFindAnswers answers_;
@@ -197,7 +197,8 @@ namespace Orthanc
            * Ensure that the remote modality is known to Orthanc for C-FIND requests.
            **/
 
-          if (!Configuration::LookupDicomModalityUsingAETitle(modality, *data.remoteAet_))
+          assert(data.modalities_ != NULL);
+          if (!data.modalities_->LookupAETitle(modality, *data.remoteAet_))
           {
             LOG(ERROR) << "Modality with AET \"" << *data.remoteAet_
                        << "\" is not defined in the \"DicomModalities\" configuration option";
@@ -252,7 +253,7 @@ namespace Orthanc
               }
 
               DicomMap input;
-              Configuration::ExtractDicomSummary(input, *requestIdentifiers);
+              FromDcmtkBridge::ExtractDicomSummary(input, *requestIdentifiers);
 
               data.findHandler_->Handle(data.answers_, input, sequencesToReturn,
                                         *data.remoteIp_, *data.remoteAet_,
@@ -314,6 +315,7 @@ namespace Orthanc
   OFCondition Internals::findScp(T_ASC_Association * assoc, 
                                  T_DIMSE_Message * msg, 
                                  T_ASC_PresentationContextID presID,
+                                 DicomServer::IRemoteModalities& modalities,
                                  IFindRequestHandler* findHandler,
                                  IWorklistRequestHandler* worklistHandler,
                                  const std::string& remoteIp,
@@ -321,9 +323,10 @@ namespace Orthanc
                                  const std::string& calledAet)
   {
     FindScpData data;
-    data.lastRequest_ = NULL;
+    data.modalities_ = &modalities;
     data.findHandler_ = findHandler;
     data.worklistHandler_ = worklistHandler;
+    data.lastRequest_ = NULL;
     data.remoteIp_ = &remoteIp;
     data.remoteAet_ = &remoteAet;
     data.calledAet_ = &calledAet;
diff --git a/OrthancServer/Internals/FindScp.h b/Core/DicomNetworking/Internals/FindScp.h
similarity index 95%
rename from OrthancServer/Internals/FindScp.h
rename to Core/DicomNetworking/Internals/FindScp.h
index 5d63f94..accdd13 100644
--- a/OrthancServer/Internals/FindScp.h
+++ b/Core/DicomNetworking/Internals/FindScp.h
@@ -33,8 +33,7 @@
 
 #pragma once
 
-#include "../DicomProtocol/IFindRequestHandler.h"
-#include "../DicomProtocol/IWorklistRequestHandler.h"
+#include "../DicomServer.h"
 
 #include <dcmtk/dcmnet/dimse.h>
 
@@ -45,6 +44,7 @@ namespace Orthanc
     OFCondition findScp(T_ASC_Association * assoc, 
                         T_DIMSE_Message * msg, 
                         T_ASC_PresentationContextID presID,
+                        DicomServer::IRemoteModalities& modalities,
                         IFindRequestHandler* findHandler,   // can be NULL
                         IWorklistRequestHandler* worklistHandler,   // can be NULL
                         const std::string& remoteIp,
diff --git a/OrthancServer/Internals/MoveScp.cpp b/Core/DicomNetworking/Internals/MoveScp.cpp
similarity index 96%
rename from OrthancServer/Internals/MoveScp.cpp
rename to Core/DicomNetworking/Internals/MoveScp.cpp
index 5578f88..2d0c80c 100644
--- a/OrthancServer/Internals/MoveScp.cpp
+++ b/Core/DicomNetworking/Internals/MoveScp.cpp
@@ -80,16 +80,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 =========================================================================*/
 
 
-#include "../PrecompiledHeadersServer.h"
+#include "../../PrecompiledHeaders.h"
 #include "MoveScp.h"
 
 #include <memory>
 
-#include "../FromDcmtkBridge.h"
-#include "../ToDcmtkBridge.h"
-#include "../OrthancInitialization.h"
-#include "../../Core/Logging.h"
-#include "../../Core/OrthancException.h"
+#include "../../DicomParsing/FromDcmtkBridge.h"
+#include "../../DicomParsing/ToDcmtkBridge.h"
+#include "../../Logging.h"
+#include "../../OrthancException.h"
 
 #include <boost/lexical_cast.hpp>
 
@@ -169,7 +168,7 @@ namespace Orthanc
       if (data.lastRequest_ == NULL)
       {
         DicomMap input;
-        Configuration::ExtractDicomSummary(input, *requestIdentifiers);
+        FromDcmtkBridge::ExtractDicomSummary(input, *requestIdentifiers);
 
         try
         {
diff --git a/OrthancServer/Internals/MoveScp.h b/Core/DicomNetworking/Internals/MoveScp.h
similarity index 97%
rename from OrthancServer/Internals/MoveScp.h
rename to Core/DicomNetworking/Internals/MoveScp.h
index 0e4e103..8f9a016 100644
--- a/OrthancServer/Internals/MoveScp.h
+++ b/Core/DicomNetworking/Internals/MoveScp.h
@@ -33,7 +33,7 @@
 
 #pragma once
 
-#include "../DicomProtocol/IMoveRequestHandler.h"
+#include "../IMoveRequestHandler.h"
 
 #include <dcmtk/dcmnet/dimse.h>
 
diff --git a/OrthancServer/Internals/StoreScp.cpp b/Core/DicomNetworking/Internals/StoreScp.cpp
similarity index 95%
rename from OrthancServer/Internals/StoreScp.cpp
rename to Core/DicomNetworking/Internals/StoreScp.cpp
index 692765a..31880a4 100644
--- a/OrthancServer/Internals/StoreScp.cpp
+++ b/Core/DicomNetworking/Internals/StoreScp.cpp
@@ -80,15 +80,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 =========================================================================*/
 
 
-#include "../PrecompiledHeadersServer.h"
+#include "../../PrecompiledHeaders.h"
 #include "StoreScp.h"
 
-#include "../FromDcmtkBridge.h"
-#include "../ServerToolbox.h"
-#include "../ToDcmtkBridge.h"
-#include "../OrthancInitialization.h"
-#include "../../Core/OrthancException.h"
-#include "../../Core/Logging.h"
+#include "../../DicomParsing/FromDcmtkBridge.h"
+#include "../../DicomParsing/ToDcmtkBridge.h"
+#include "../../OrthancException.h"
+#include "../../Logging.h"
 
 #include <dcmtk/dcmdata/dcfilefo.h>
 #include <dcmtk/dcmdata/dcmetinf.h>
@@ -169,8 +167,10 @@ namespace Orthanc
 
           try
           {
-            Configuration::ExtractDicomSummary(summary, **imageDataSet);
-            Configuration::ExtractDicomAsJson(dicomJson, **imageDataSet);
+            std::set<DicomTag> ignoreTagLength;
+            
+            FromDcmtkBridge::ExtractDicomSummary(summary, **imageDataSet);
+            FromDcmtkBridge::ExtractDicomAsJson(dicomJson, **imageDataSet, ignoreTagLength);
 
             if (!FromDcmtkBridge::SaveToMemoryBuffer(buffer, **imageDataSet))
             {
@@ -213,7 +213,7 @@ namespace Orthanc
 
                 if (e.GetErrorCode() == ErrorCode_InexistentTag)
                 {
-                  ServerToolbox::LogMissingRequiredTag(summary);
+                  summary.LogMissingTagsForStore();
                 }
                 else
                 {
diff --git a/OrthancServer/Internals/StoreScp.h b/Core/DicomNetworking/Internals/StoreScp.h
similarity index 97%
rename from OrthancServer/Internals/StoreScp.h
rename to Core/DicomNetworking/Internals/StoreScp.h
index 6c28fb4..bf202ce 100644
--- a/OrthancServer/Internals/StoreScp.h
+++ b/Core/DicomNetworking/Internals/StoreScp.h
@@ -33,7 +33,7 @@
 
 #pragma once
 
-#include "../DicomProtocol/IStoreRequestHandler.h"
+#include "../IStoreRequestHandler.h"
 
 #include <dcmtk/dcmnet/dimse.h>
 
diff --git a/OrthancServer/DicomProtocol/RemoteModalityParameters.cpp b/Core/DicomNetworking/RemoteModalityParameters.cpp
similarity index 97%
rename from OrthancServer/DicomProtocol/RemoteModalityParameters.cpp
rename to Core/DicomNetworking/RemoteModalityParameters.cpp
index a99c643..72eb4bd 100644
--- a/OrthancServer/DicomProtocol/RemoteModalityParameters.cpp
+++ b/Core/DicomNetworking/RemoteModalityParameters.cpp
@@ -31,11 +31,11 @@
  **/
 
 
-#include "../PrecompiledHeadersServer.h"
+#include "../PrecompiledHeaders.h"
 #include "RemoteModalityParameters.h"
 
-#include "../../Core/Logging.h"
-#include "../../Core/OrthancException.h"
+#include "../Logging.h"
+#include "../OrthancException.h"
 
 #include <boost/lexical_cast.hpp>
 #include <stdexcept>
diff --git a/OrthancServer/DicomProtocol/RemoteModalityParameters.h b/Core/DicomNetworking/RemoteModalityParameters.h
similarity index 98%
rename from OrthancServer/DicomProtocol/RemoteModalityParameters.h
rename to Core/DicomNetworking/RemoteModalityParameters.h
index 7b382ee..7141f44 100644
--- a/OrthancServer/DicomProtocol/RemoteModalityParameters.h
+++ b/Core/DicomNetworking/RemoteModalityParameters.h
@@ -33,7 +33,7 @@
 
 #pragma once
 
-#include "../ServerEnumerations.h"
+#include "../Enumerations.h"
 
 #include <stdint.h>
 #include <string>
diff --git a/OrthancServer/DicomProtocol/ReusableDicomUserConnection.cpp b/Core/DicomNetworking/ReusableDicomUserConnection.cpp
similarity index 97%
rename from OrthancServer/DicomProtocol/ReusableDicomUserConnection.cpp
rename to Core/DicomNetworking/ReusableDicomUserConnection.cpp
index 65f84a6..e200a75 100644
--- a/OrthancServer/DicomProtocol/ReusableDicomUserConnection.cpp
+++ b/Core/DicomNetworking/ReusableDicomUserConnection.cpp
@@ -31,11 +31,11 @@
  **/
 
 
-#include "../PrecompiledHeadersServer.h"
+#include "../PrecompiledHeaders.h"
 #include "ReusableDicomUserConnection.h"
 
-#include "../../Core/Logging.h"
-#include "../../Core/OrthancException.h"
+#include "../Logging.h"
+#include "../OrthancException.h"
 
 namespace Orthanc
 {
diff --git a/OrthancServer/DicomProtocol/ReusableDicomUserConnection.h b/Core/DicomNetworking/ReusableDicomUserConnection.h
similarity index 100%
rename from OrthancServer/DicomProtocol/ReusableDicomUserConnection.h
rename to Core/DicomNetworking/ReusableDicomUserConnection.h
diff --git a/OrthancServer/DicomDirWriter.cpp b/Core/DicomParsing/DicomDirWriter.cpp
similarity index 89%
rename from OrthancServer/DicomDirWriter.cpp
rename to Core/DicomParsing/DicomDirWriter.cpp
index f7975ee..174cac3 100644
--- a/OrthancServer/DicomDirWriter.cpp
+++ b/Core/DicomParsing/DicomDirWriter.cpp
@@ -98,17 +98,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  ***/
 
 
-#include "PrecompiledHeadersServer.h"
+#include "../PrecompiledHeaders.h"
 #include "DicomDirWriter.h"
 
 #include "FromDcmtkBridge.h"
 #include "ToDcmtkBridge.h"
 
-#include "../Core/Logging.h"
-#include "../Core/OrthancException.h"
-#include "../Core/TemporaryFile.h"
-#include "../Core/Toolbox.h"
-#include "../Core/SystemToolbox.h"
+#include "../Logging.h"
+#include "../OrthancException.h"
+#include "../TemporaryFile.h"
+#include "../Toolbox.h"
+#include "../SystemToolbox.h"
 
 #include <dcmtk/dcmdata/dcdicdir.h>
 #include <dcmtk/dcmdata/dcmetinf.h>
@@ -128,8 +128,9 @@ namespace Orthanc
   class DicomDirWriter::PImpl
   {
   private:
-    std::string fileSetId_;
-    TemporaryFile file_;
+    std::string                fileSetId_;
+    bool                       extendedSopClass_;
+    TemporaryFile              file_;
     std::auto_ptr<DcmDicomDir> dir_;
 
     typedef std::pair<ResourceType, std::string>  IndexKey;
@@ -211,6 +212,13 @@ namespace Orthanc
       std::string value;
       bool found = GetUtf8TagValue(value, source, encoding, key);
 
+      if (!found)
+      {
+        // We don't raise an exception if "!optional", even if this
+        // results in an invalid DICOM file
+        value.clear();
+      }
+
       SetTagValue(target, key, value);
       return found;
     }
@@ -240,12 +248,38 @@ namespace Orthanc
       CopyString(target, source, encoding, key, false, true);
     }
 
+    static void CopyStringType3(DcmDirectoryRecord& target,
+                                DcmDataset& source,
+                                Encoding encoding,
+                                const DcmTagKey& key)
+    {
+      CopyString(target, source, encoding, key, true, true);
+    }
+
 
   public:
-    PImpl() : fileSetId_("ORTHANC_MEDIA")
+    PImpl() :
+      fileSetId_("ORTHANC_MEDIA"),
+      extendedSopClass_(false)
     {
     }
 
+    void EnableExtendedSopClass(bool enable)
+    {
+      if (enable)
+      {
+        LOG(WARNING) << "Generating a DICOMDIR with type 3 attributes, "
+                     << "which leads to an Extended SOP Class";
+      }
+      
+      extendedSopClass_ = enable;
+    }
+
+    bool IsExtendedSopClass() const
+    {
+      return extendedSopClass_;
+    }
+
     void FillPatient(DcmDirectoryRecord& record,
                      DcmDataset& dicom,
                      Encoding encoding)
@@ -304,6 +338,14 @@ namespace Orthanc
       CopyStringType1(record, dicom, encoding, DCM_SeriesInstanceUID);
       /* use type 1C instead of 1 in order to avoid unwanted overwriting */
       CopyStringType1C(record, dicom, encoding, DCM_SeriesNumber);
+
+      // Add extended (non-standard) type 3 tags, those are not generated by DCMTK
+      // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part02/sect_7.3.html
+      // https://groups.google.com/d/msg/orthanc-users/Y7LOvZMDeoc/9cp3kDgxAwAJ
+      if (extendedSopClass_)
+      {
+        CopyStringType3(record, dicom, encoding, DCM_SeriesDescription);
+      }
     }
 
     void FillInstance(DcmDirectoryRecord& record,
@@ -507,4 +549,16 @@ namespace Orthanc
   {
     pimpl_->Read(target);
   }
+
+
+  void DicomDirWriter::EnableExtendedSopClass(bool enable)
+  {
+    pimpl_->EnableExtendedSopClass(enable);
+  }
+
+  
+  bool DicomDirWriter::IsExtendedSopClass() const
+  {
+    return pimpl_->IsExtendedSopClass();
+  }
 }
diff --git a/OrthancServer/DicomDirWriter.h b/Core/DicomParsing/DicomDirWriter.h
similarity index 96%
rename from OrthancServer/DicomDirWriter.h
rename to Core/DicomParsing/DicomDirWriter.h
index 0e09353..b2bcbc6 100644
--- a/OrthancServer/DicomDirWriter.h
+++ b/Core/DicomParsing/DicomDirWriter.h
@@ -57,6 +57,10 @@ namespace Orthanc
              ParsedDicomFile& dicom);
 
     void Encode(std::string& target);
+
+    void EnableExtendedSopClass(bool enable);
+
+    bool IsExtendedSopClass() const;
   };
 
 }
diff --git a/OrthancServer/DicomModification.cpp b/Core/DicomParsing/DicomModification.cpp
similarity index 99%
rename from OrthancServer/DicomModification.cpp
rename to Core/DicomParsing/DicomModification.cpp
index dc15d97..d7ad0cc 100644
--- a/OrthancServer/DicomModification.cpp
+++ b/Core/DicomParsing/DicomModification.cpp
@@ -31,11 +31,11 @@
  **/
 
 
-#include "PrecompiledHeadersServer.h"
+#include "../PrecompiledHeaders.h"
 #include "DicomModification.h"
 
-#include "../Core/Logging.h"
-#include "../Core/OrthancException.h"
+#include "../Logging.h"
+#include "../OrthancException.h"
 #include "FromDcmtkBridge.h"
 
 #include <memory>   // For std::auto_ptr
diff --git a/OrthancServer/DicomModification.h b/Core/DicomParsing/DicomModification.h
similarity index 100%
rename from OrthancServer/DicomModification.h
rename to Core/DicomParsing/DicomModification.h
diff --git a/OrthancServer/FromDcmtkBridge.cpp b/Core/DicomParsing/FromDcmtkBridge.cpp
similarity index 94%
rename from OrthancServer/FromDcmtkBridge.cpp
rename to Core/DicomParsing/FromDcmtkBridge.cpp
index b81362b..923d071 100644
--- a/OrthancServer/FromDcmtkBridge.cpp
+++ b/Core/DicomParsing/FromDcmtkBridge.cpp
@@ -31,7 +31,7 @@
  **/
 
 
-#include "PrecompiledHeadersServer.h"
+#include "../PrecompiledHeaders.h"
 
 #ifndef NOMINMAX
 #define NOMINMAX
@@ -39,11 +39,11 @@
 
 #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 "../Logging.h"
+#include "../SystemToolbox.h"
+#include "../Toolbox.h"
+#include "../TemporaryFile.h"
+#include "../OrthancException.h"
 
 #include <list>
 #include <limits>
@@ -84,9 +84,16 @@
 #include <dcmtk/dcmdata/dcvrus.h>
 #include <dcmtk/dcmdata/dcvrut.h>
 
-
 #if DCMTK_USE_EMBEDDED_DICTIONARIES == 1
-#include <EmbeddedResources.h>
+#  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
 
 
@@ -209,7 +216,7 @@ namespace Orthanc
         LOG(INFO) << "The dictionary of private tags has not been loaded";
       }
 
-#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+#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);
@@ -388,6 +395,8 @@ namespace Orthanc
                                             unsigned int maxStringLength,
                                             Encoding defaultEncoding)
   {
+    std::set<DicomTag> ignoreTagLength;
+    
     Encoding encoding = DetectEncoding(dataset, defaultEncoding);
 
     target.Clear();
@@ -398,7 +407,8 @@ namespace Orthanc
       {
         target.SetValue(element->getTag().getGTag(),
                         element->getTag().getETag(),
-                        ConvertLeafElement(*element, DicomToJsonFlags_Default, maxStringLength, encoding));
+                        ConvertLeafElement(*element, DicomToJsonFlags_Default,
+                                           maxStringLength, encoding, ignoreTagLength));
       }
     }
   }
@@ -419,7 +429,8 @@ namespace Orthanc
   DicomValue* FromDcmtkBridge::ConvertLeafElement(DcmElement& element,
                                                   DicomToJsonFlags flags,
                                                   unsigned int maxStringLength,
-                                                  Encoding encoding)
+                                                  Encoding encoding,
+                                                  const std::set<DicomTag>& ignoreTagLength)
   {
     if (!element.isLeaf())
     {
@@ -441,7 +452,8 @@ namespace Orthanc
         std::string utf8 = Toolbox::ConvertToUtf8(s, encoding);
 
         if (maxStringLength != 0 &&
-            utf8.size() > maxStringLength)
+            utf8.size() > maxStringLength &&
+            ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end())
         {
           return new DicomValue;  // Too long, create a NULL value
         }
@@ -479,7 +491,8 @@ namespace Orthanc
             return new DicomValue("", false);   // Empty string
           }
           else if (maxStringLength != 0 &&
-                   element.getLength() > maxStringLength)
+                   element.getLength() > maxStringLength &&
+                   ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end())
           {
             return new DicomValue;  // Too long, create a NULL value
           }
@@ -492,7 +505,7 @@ namespace Orthanc
       }
     }
 
-
+    
     try
     {
       // http://support.dcmtk.org/docs/dcvr_8h-source.html
@@ -807,7 +820,8 @@ namespace Orthanc
                                       DicomToJsonFormat format,
                                       DicomToJsonFlags flags,
                                       unsigned int maxStringLength,
-                                      Encoding encoding)
+                                      Encoding encoding,
+                                      const std::set<DicomTag>& ignoreTagLength)
   {
     if (parent.type() == Json::nullValue)
     {
@@ -820,8 +834,17 @@ namespace Orthanc
     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);
+      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
     {
@@ -837,7 +860,7 @@ namespace Orthanc
       {
         DcmItem* child = sequence.getItem(i);
         Json::Value& v = target.append(Json::objectValue);
-        DatasetToJson(v, *child, format, flags, maxStringLength, encoding);
+        DatasetToJson(v, *child, format, flags, maxStringLength, encoding, ignoreTagLength);
       }
     }
   }
@@ -848,7 +871,8 @@ namespace Orthanc
                                       DicomToJsonFormat format,
                                       DicomToJsonFlags flags,
                                       unsigned int maxStringLength,
-                                      Encoding encoding)
+                                      Encoding encoding,
+                                      const std::set<DicomTag>& ignoreTagLength)
   {
     assert(parent.type() == Json::objectValue);
 
@@ -893,7 +917,8 @@ namespace Orthanc
         }
       }
 
-      FromDcmtkBridge::ElementToJson(parent, *element, format, flags, maxStringLength, encoding);
+      FromDcmtkBridge::ElementToJson(parent, *element, format, flags,
+                                     maxStringLength, encoding, ignoreTagLength);
     }
   }
 
@@ -903,12 +928,13 @@ namespace Orthanc
                                            DicomToJsonFormat format,
                                            DicomToJsonFlags flags,
                                            unsigned int maxStringLength,
-                                           Encoding defaultEncoding)
+                                           Encoding defaultEncoding,
+                                           const std::set<DicomTag>& ignoreTagLength)
   {
     Encoding encoding = DetectEncoding(dataset, defaultEncoding);
 
     target = Json::objectValue;
-    DatasetToJson(target, dataset, format, flags, maxStringLength, encoding);
+    DatasetToJson(target, dataset, format, flags, maxStringLength, encoding, ignoreTagLength);
   }
 
 
@@ -918,8 +944,9 @@ namespace Orthanc
                                             DicomToJsonFlags flags,
                                             unsigned int maxStringLength)
   {
+    std::set<DicomTag> ignoreTagLength;
     target = Json::objectValue;
-    DatasetToJson(target, dataset, format, flags, maxStringLength, Encoding_Ascii);
+    DatasetToJson(target, dataset, format, flags, maxStringLength, Encoding_Ascii, ignoreTagLength);
   }
 
 
@@ -1879,6 +1906,7 @@ namespace Orthanc
     result->transferInit();
     if (!result->read(is).good())
     {
+      LOG(ERROR) << "Cannot parse an invalid DICOM file (size: " << size << " bytes)";
       throw OrthancException(ErrorCode_BadFileFormat);
     }
 
@@ -2017,4 +2045,54 @@ namespace Orthanc
     }
   }
 #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
+  }
 }
diff --git a/OrthancServer/FromDcmtkBridge.h b/Core/DicomParsing/FromDcmtkBridge.h
similarity index 85%
rename from OrthancServer/FromDcmtkBridge.h
rename to Core/DicomParsing/FromDcmtkBridge.h
index 9a05d5f..72624eb 100644
--- a/OrthancServer/FromDcmtkBridge.h
+++ b/Core/DicomParsing/FromDcmtkBridge.h
@@ -33,10 +33,8 @@
 
 #pragma once
 
-#include "ServerEnumerations.h"
-
-#include "../Core/DicomFormat/DicomElement.h"
-#include "../Core/DicomFormat/DicomMap.h"
+#include "../DicomFormat/DicomElement.h"
+#include "../DicomFormat/DicomMap.h"
 
 #include <dcmtk/dcmdata/dcdatset.h>
 #include <dcmtk/dcmdata/dcmetinf.h>
@@ -44,20 +42,28 @@
 #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_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 "../Core/Lua/LuaFunctionCall.h"
+#  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
 
 
@@ -70,7 +76,6 @@ namespace Orthanc
 #endif
 
     friend class ParsedDicomFile;
-    friend class Configuration;
 
   private:
     FromDcmtkBridge();  // Pure static class
@@ -85,21 +90,24 @@ namespace Orthanc
                               DicomToJsonFormat format,
                               DicomToJsonFlags flags,
                               unsigned int maxStringLength,
-                              Encoding encoding);
+                              Encoding encoding,
+                              const std::set<DicomTag>& ignoreTagLength);
 
     static void ElementToJson(Json::Value& parent,
                               DcmElement& element,
                               DicomToJsonFormat format,
                               DicomToJsonFlags flags,
                               unsigned int maxStringLength,
-                              Encoding dicomEncoding);
+                              Encoding dicomEncoding,
+                              const std::set<DicomTag>& ignoreTagLength);
 
     static void ExtractDicomAsJson(Json::Value& target, 
                                    DcmDataset& dataset,
                                    DicomToJsonFormat format,
                                    DicomToJsonFlags flags,
                                    unsigned int maxStringLength,
-                                   Encoding defaultEncoding);
+                                   Encoding defaultEncoding,
+                                   const std::set<DicomTag>& ignoreTagLength);
 
     static void ChangeStringEncoding(DcmItem& dataset,
                                      Encoding source,
@@ -127,7 +135,8 @@ namespace Orthanc
     static DicomValue* ConvertLeafElement(DcmElement& element,
                                           DicomToJsonFlags flags,
                                           unsigned int maxStringLength,
-                                          Encoding encoding);
+                                          Encoding encoding,
+                                          const std::set<DicomTag>& ignoreTagLength);
 
     static void ExtractHeaderAsJson(Json::Value& target, 
                                     DcmMetaInfo& header,
@@ -220,5 +229,16 @@ namespace Orthanc
     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();
   };
 }
diff --git a/OrthancServer/Internals/DicomFrameIndex.cpp b/Core/DicomParsing/Internals/DicomFrameIndex.cpp
similarity index 97%
rename from OrthancServer/Internals/DicomFrameIndex.cpp
rename to Core/DicomParsing/Internals/DicomFrameIndex.cpp
index 67c9406..94079c2 100644
--- a/OrthancServer/Internals/DicomFrameIndex.cpp
+++ b/Core/DicomParsing/Internals/DicomFrameIndex.cpp
@@ -31,14 +31,13 @@
  **/
 
 
-#include "../PrecompiledHeadersServer.h"
+#include "../../PrecompiledHeaders.h"
 #include "DicomFrameIndex.h"
 
-#include "../../Core/OrthancException.h"
-#include "../../Core/DicomFormat/DicomImageInformation.h"
+#include "../../OrthancException.h"
+#include "../../DicomFormat/DicomImageInformation.h"
 #include "../FromDcmtkBridge.h"
-#include "../OrthancInitialization.h"
-#include "../../Core/Endianness.h"
+#include "../../Endianness.h"
 #include "DicomImageDecoder.h"
 
 #include <boost/lexical_cast.hpp>
@@ -405,7 +404,7 @@ namespace Orthanc
 
     // Extract information about the image structure
     DicomMap tags;
-    Configuration::ExtractDicomSummary(tags, dataset);
+    FromDcmtkBridge::ExtractDicomSummary(tags, dataset);
 
     DicomImageInformation information(tags);
 
diff --git a/OrthancServer/Internals/DicomFrameIndex.h b/Core/DicomParsing/Internals/DicomFrameIndex.h
similarity index 98%
rename from OrthancServer/Internals/DicomFrameIndex.h
rename to Core/DicomParsing/Internals/DicomFrameIndex.h
index 52a1819..603b154 100644
--- a/OrthancServer/Internals/DicomFrameIndex.h
+++ b/Core/DicomParsing/Internals/DicomFrameIndex.h
@@ -33,6 +33,8 @@
 
 #pragma once
 
+#include "../../Enumerations.h"
+
 #include <dcmtk/dcmdata/dcdatset.h>
 #include <dcmtk/dcmdata/dcfilefo.h>
 #include <vector>
diff --git a/OrthancServer/Internals/DicomImageDecoder.cpp b/Core/DicomParsing/Internals/DicomImageDecoder.cpp
similarity index 75%
rename from OrthancServer/Internals/DicomImageDecoder.cpp
rename to Core/DicomParsing/Internals/DicomImageDecoder.cpp
index a20f0ef..fa73ffd 100644
--- a/OrthancServer/Internals/DicomImageDecoder.cpp
+++ b/Core/DicomParsing/Internals/DicomImageDecoder.cpp
@@ -31,7 +31,7 @@
  **/
 
 
-#include "../PrecompiledHeadersServer.h"
+#include "../../PrecompiledHeaders.h"
 #include "DicomImageDecoder.h"
 
 
@@ -77,31 +77,39 @@
   =========================================================================*/
 
 
-#include "../../Core/Logging.h"
-#include "../../Core/OrthancException.h"
-#include "../../Core/Images/Image.h"
-#include "../../Core/Images/ImageProcessing.h"
-#include "../../Core/Images/PngWriter.h"
-#include "../../Core/Images/JpegWriter.h"
-#include "../../Core/DicomFormat/DicomIntegerPixelAccessor.h"
+#include "../../Logging.h"
+#include "../../OrthancException.h"
+#include "../../Images/Image.h"
+#include "../../Images/ImageProcessing.h"
+#include "../../DicomFormat/DicomIntegerPixelAccessor.h"
 #include "../ToDcmtkBridge.h"
 #include "../FromDcmtkBridge.h"
 #include "../ParsedDicomFile.h"
-#include "../OrthancInitialization.h"
+
+#if ORTHANC_ENABLE_PNG == 1
+#  include "../../Images/PngWriter.h"
+#endif
+
+#if ORTHANC_ENABLE_JPEG == 1
+#  include "../../Images/JpegWriter.h"
+#endif
 
 #include <boost/lexical_cast.hpp>
 
+#include <dcmtk/dcmdata/dcdeftag.h>
 #include <dcmtk/dcmdata/dcfilefo.h>
 #include <dcmtk/dcmdata/dcrleccd.h>
 #include <dcmtk/dcmdata/dcrlecp.h>
+#include <dcmtk/dcmdata/dcrlerp.h>
 
-#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
+#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1
+#  include <dcmtk/dcmjpeg/djrplol.h>
 #  include <dcmtk/dcmjpls/djcodecd.h>
 #  include <dcmtk/dcmjpls/djcparam.h>
-#  include <dcmtk/dcmjpeg/djrplol.h>
+#  include <dcmtk/dcmjpls/djrparam.h>
 #endif
 
-#if ORTHANC_ENABLE_JPEG == 1
+#if ORTHANC_ENABLE_DCMTK_JPEG == 1
 #  include <dcmtk/dcmjpeg/djcodecd.h>
 #  include <dcmtk/dcmjpeg/djcparam.h>
 #  include <dcmtk/dcmjpeg/djdecbas.h>
@@ -110,6 +118,7 @@
 #  include <dcmtk/dcmjpeg/djdecpro.h>
 #  include <dcmtk/dcmjpeg/djdecsps.h>
 #  include <dcmtk/dcmjpeg/djdecsv1.h>
+#  include <dcmtk/dcmjpeg/djrploss.h>
 #endif
 
 #if DCMTK_VERSION_NUMBER <= 360
@@ -251,7 +260,7 @@ namespace Orthanc
       // See also: http://support.dcmtk.org/wiki/dcmtk/howto/accessing-compressed-data
 
       DicomMap m;
-      Configuration::ExtractDicomSummary(m, dataset);
+      FromDcmtkBridge::ExtractDicomSummary(m, dataset);
 
       /**
        * Create an accessor to the raw values of the DICOM image.
@@ -323,7 +332,7 @@ namespace Orthanc
                                                 bool ignorePhotometricInterpretation)
   {
     DicomMap m;
-    Configuration::ExtractDicomSummary(m, dataset);
+    FromDcmtkBridge::ExtractDicomSummary(m, dataset);
 
     DicomImageInformation info(m);
     PixelFormat format;
@@ -376,33 +385,155 @@ namespace Orthanc
   }
 
 
-  ImageAccessor* DicomImageDecoder::DecodeUncompressedImage(DcmDataset& dataset,
-                                                            unsigned int frame)
+  static ImageAccessor* DecodeLookupTable(std::auto_ptr<ImageAccessor>& target,
+                                          const DicomImageInformation& info,
+                                          DcmDataset& dataset,
+                                          const uint8_t* pixelData,
+                                          unsigned long pixelLength)
   {
-    ImageSource source;
-    source.Setup(dataset, frame);
+    LOG(INFO) << "Decoding a lookup table";
+
+    OFString r, g, b;
+    PixelFormat format;
+    const uint16_t* lutRed = NULL;
+    const uint16_t* lutGreen = NULL;
+    const uint16_t* lutBlue = NULL;
+    unsigned long rc = 0;
+    unsigned long gc = 0;
+    unsigned long bc = 0;
+
+    if (pixelData == NULL &&
+        !dataset.findAndGetUint8Array(DCM_PixelData, pixelData, &pixelLength).good())
+    {
+      throw OrthancException(ErrorCode_NotImplemented);
+    }
+
+    if (info.IsPlanar() ||
+        info.GetNumberOfFrames() != 1 ||
+        !info.ExtractPixelFormat(format, false) ||
+        !dataset.findAndGetOFStringArray(DCM_BluePaletteColorLookupTableDescriptor, b).good() ||
+        !dataset.findAndGetOFStringArray(DCM_GreenPaletteColorLookupTableDescriptor, g).good() ||
+        !dataset.findAndGetOFStringArray(DCM_RedPaletteColorLookupTableDescriptor, r).good() ||
+        !dataset.findAndGetUint16Array(DCM_BluePaletteColorLookupTableData, lutBlue, &bc).good() ||
+        !dataset.findAndGetUint16Array(DCM_GreenPaletteColorLookupTableData, lutGreen, &gc).good() ||
+        !dataset.findAndGetUint16Array(DCM_RedPaletteColorLookupTableData, lutRed, &rc).good() ||
+        r != g ||
+        r != b ||
+        g != b ||
+        lutRed == NULL ||
+        lutGreen == NULL ||
+        lutBlue == NULL ||
+        pixelData == NULL)
+    {
+      throw OrthancException(ErrorCode_NotImplemented);
+    }
+
+    switch (format)
+    {
+      case PixelFormat_RGB24:
+      {
+        if (r != "256\\0\\16" ||
+            rc != 256 ||
+            gc != 256 ||
+            bc != 256 ||
+            pixelLength != target->GetWidth() * target->GetHeight())
+        {
+          throw OrthancException(ErrorCode_NotImplemented);
+        }
+
+        const uint8_t* source = reinterpret_cast<const uint8_t*>(pixelData);
+        
+        for (unsigned int y = 0; y < target->GetHeight(); y++)
+        {
+          uint8_t* p = reinterpret_cast<uint8_t*>(target->GetRow(y));
+
+          for (unsigned int x = 0; x < target->GetWidth(); x++)
+          {
+            p[0] = lutRed[*source] >> 8;
+            p[1] = lutGreen[*source] >> 8;
+            p[2] = lutBlue[*source] >> 8;
+            source++;
+            p += 3;
+          }
+        }
+
+        return target.release();
+      }
+
+      case PixelFormat_RGB48:
+      {
+        if (r != "0\\0\\16" ||
+            rc != 65536 ||
+            gc != 65536 ||
+            bc != 65536 ||
+            pixelLength != 2 * target->GetWidth() * target->GetHeight())
+        {
+          throw OrthancException(ErrorCode_NotImplemented);
+        }
+
+        const uint16_t* source = reinterpret_cast<const uint16_t*>(pixelData);
+        
+        for (unsigned int y = 0; y < target->GetHeight(); y++)
+        {
+          uint16_t* p = reinterpret_cast<uint16_t*>(target->GetRow(y));
+
+          for (unsigned int x = 0; x < target->GetWidth(); x++)
+          {
+            p[0] = lutRed[*source];
+            p[1] = lutGreen[*source];
+            p[2] = lutBlue[*source];
+            source++;
+            p += 3;
+          }
+        }
+
+        return target.release();
+      }
+
+      default:
+        break;
+    }
+
+    throw OrthancException(ErrorCode_InternalError);
+  }                                          
 
 
+  ImageAccessor* DicomImageDecoder::DecodeUncompressedImage(DcmDataset& dataset,
+                                                            unsigned int frame)
+  {
     /**
-     * Resize the target image.
+     * Create the target image.
      **/
 
     std::auto_ptr<ImageAccessor> target(CreateImage(dataset, false));
 
+    ImageSource source;
+    source.Setup(dataset, frame);
+
     if (source.GetWidth() != target->GetWidth() ||
         source.GetHeight() != target->GetHeight())
     {
       throw OrthancException(ErrorCode_InternalError);
     }
 
+    
+    /**
+     * Deal with lookup tables
+     **/
+
+    const DicomImageInformation& info = source.GetAccessor().GetInformation();
+
+    if (info.GetPhotometricInterpretation() == PhotometricInterpretation_Palette)
+    {
+      return DecodeLookupTable(target, info, dataset, NULL, 0);
+    }       
+
 
     /**
      * If the format of the DICOM buffer is natively supported, use a
      * direct access to copy its values.
      **/
 
-    const DicomImageInformation& info = source.GetAccessor().GetInformation();
-
     bool fastVersionSuccess = false;
     PixelFormat sourceFormat;
     if (!info.IsPlanar() &&
@@ -465,10 +596,12 @@ namespace Orthanc
   }
 
 
-  ImageAccessor* DicomImageDecoder::ApplyCodec(const DcmCodec& codec,
-                                               const DcmCodecParameter& parameters,
-                                               DcmDataset& dataset,
-                                               unsigned int frame)
+  ImageAccessor* DicomImageDecoder::ApplyCodec
+  (const DcmCodec& codec,
+   const DcmCodecParameter& parameters,
+   const DcmRepresentationParameter& representationParameter,
+   DcmDataset& dataset,
+   unsigned int frame)
   {
     DcmPixelSequence* pixelSequence = FromDcmtkBridge::GetPixelSequence(dataset);
     if (pixelSequence == NULL)
@@ -476,24 +609,49 @@ namespace Orthanc
       throw OrthancException(ErrorCode_BadFileFormat);
     }
 
+    DicomMap m;
+    FromDcmtkBridge::ExtractDicomSummary(m, dataset);
+    DicomImageInformation info(m);
+
     std::auto_ptr<ImageAccessor> target(CreateImage(dataset, true));
 
     Uint32 startFragment = 0;  // Default 
     OFString decompressedColorModel;  // Out
-    DJ_RPLossless representationParameter;
-    OFCondition c = codec.decodeFrame(&representationParameter, 
-                                      pixelSequence, &parameters, 
-                                      &dataset, frame, startFragment, target->GetBuffer(), 
-                                      target->GetSize(), decompressedColorModel);
 
-    if (c.good())
+    OFCondition c;
+    
+    if (info.GetPhotometricInterpretation() == PhotometricInterpretation_Palette &&
+        info.GetChannelCount() == 1)
     {
-      return target.release();    
+      std::string uncompressed;
+      uncompressed.resize(info.GetWidth() * info.GetHeight() * info.GetBytesPerValue());
+
+      if (uncompressed.size() == 0 ||
+          !codec.decodeFrame(&representationParameter, 
+                             pixelSequence, &parameters, 
+                             &dataset, frame, startFragment, &uncompressed[0],
+                             uncompressed.size(), decompressedColorModel).good())
+      {
+        LOG(ERROR) << "Cannot decode a palette image";
+        throw OrthancException(ErrorCode_BadFileFormat);
+      }
+
+      return DecodeLookupTable(target, info, dataset,
+                               reinterpret_cast<const uint8_t*>(uncompressed.c_str()),
+                               uncompressed.size());
     }
     else
     {
-      LOG(ERROR) << "Cannot decode an image";
-      throw OrthancException(ErrorCode_BadFileFormat);
+      if (!codec.decodeFrame(&representationParameter, 
+                             pixelSequence, &parameters, 
+                             &dataset, frame, startFragment, target->GetBuffer(), 
+                             target->GetSize(), decompressedColorModel).good())
+      {
+        LOG(ERROR) << "Cannot decode a non-palette image";
+        throw OrthancException(ErrorCode_BadFileFormat);
+      }
+
+      return target.release();
     }
   }
 
@@ -518,7 +676,7 @@ namespace Orthanc
     }
 
 
-#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
+#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1
     /**
      * Deal with JPEG-LS images.
      **/
@@ -526,6 +684,10 @@ namespace Orthanc
     if (syntax == EXS_JPEGLSLossless ||
         syntax == EXS_JPEGLSLossy)
     {
+      // The (2, OFTrue) are the default parameters as found in DCMTK 3.6.2
+      // http://support.dcmtk.org/docs/classDJLSRepresentationParameter.html
+      DJLSRepresentationParameter representationParameter(2, OFTrue);
+
       DJLSCodecParameter parameters;
       std::auto_ptr<DJLSDecoderBase> decoder;
 
@@ -545,12 +707,12 @@ namespace Orthanc
           throw OrthancException(ErrorCode_InternalError);
       }
     
-      return ApplyCodec(*decoder, parameters, dataset, frame);
+      return ApplyCodec(*decoder, parameters, representationParameter, dataset, frame);
     }
 #endif
 
 
-#if ORTHANC_ENABLE_JPEG == 1
+#if ORTHANC_ENABLE_DCMTK_JPEG == 1
     /**
      * Deal with JPEG images.
      **/
@@ -568,6 +730,7 @@ namespace Orthanc
         EDC_photometricInterpretation,  // Perform color space conversion from YCbCr to RGB if DICOM photometric interpretation indicates YCbCr
         EUC_default,     // Mode for UID creation, unused for decompression
         EPC_default);    // Automatically determine whether color-by-plane is required from the SOP Class UID and decompressed photometric interpretation
+      DJ_RPLossy representationParameter;
       std::auto_ptr<DJCodecDecoder> decoder;
 
       switch (syntax)
@@ -606,7 +769,7 @@ namespace Orthanc
           throw OrthancException(ErrorCode_InternalError);
       }
     
-      return ApplyCodec(*decoder, parameters, dataset, frame);      
+      return ApplyCodec(*decoder, parameters, representationParameter, dataset, frame);      
     }
 #endif
 
@@ -616,7 +779,8 @@ namespace Orthanc
       LOG(INFO) << "Decoding a RLE lossless DICOM image";
       DcmRLECodecParameter parameters;
       DcmRLECodecDecoder decoder;
-      return ApplyCodec(decoder, parameters, dataset, frame);
+      DcmRLERepresentationParameter representationParameter;
+      return ApplyCodec(decoder, parameters, representationParameter, dataset, frame);
     }
 
 
@@ -673,7 +837,8 @@ namespace Orthanc
     if (image->GetFormat() != format)
     {
       // A conversion is required
-      std::auto_ptr<ImageAccessor> target(new Image(format, image->GetWidth(), image->GetHeight(), false));
+      std::auto_ptr<ImageAccessor> target
+        (new Image(format, image->GetWidth(), image->GetHeight(), false));
       ImageProcessing::Convert(*target, *image);
       image = target;
     }
@@ -692,13 +857,22 @@ namespace Orthanc
         return true;
       }
 
+      case PixelFormat_RGB48:
+      {
+        std::auto_ptr<ImageAccessor> target
+          (new Image(PixelFormat_RGB24, image->GetWidth(), image->GetHeight(), false));
+        ImageProcessing::Convert(*target, *image);
+        image = target;
+        return true;
+      }
+
       case PixelFormat_Grayscale8:
       case PixelFormat_Grayscale16:
       case PixelFormat_SignedGrayscale16:
       {
         // Grayscale image: Stretch its dynamics to the [0,255] range
         int64_t a, b;
-        ImageProcessing::GetMinMaxValue(a, b, *image);
+        ImageProcessing::GetMinMaxIntegerValue(a, b, *image);
 
         if (a == b)
         {
@@ -706,13 +880,15 @@ namespace Orthanc
         }
         else
         {
-          ImageProcessing::ShiftScale(*image, static_cast<float>(-a), 255.0f / static_cast<float>(b - a));
+          ImageProcessing::ShiftScale(*image, static_cast<float>(-a),
+                                      255.0f / static_cast<float>(b - a));
         }
 
         // If the source image is not grayscale 8bpp, convert it
         if (image->GetFormat() != PixelFormat_Grayscale8)
         {
-          std::auto_ptr<ImageAccessor> target(new Image(PixelFormat_Grayscale8, image->GetWidth(), image->GetHeight(), false));
+          std::auto_ptr<ImageAccessor> target
+            (new Image(PixelFormat_Grayscale8, image->GetWidth(), image->GetHeight(), false));
           ImageProcessing::Convert(*target, *image);
           image = target;
         }
@@ -775,6 +951,7 @@ namespace Orthanc
   }
 
 
+#if ORTHANC_ENABLE_PNG == 1
   void DicomImageDecoder::ExtractPngImage(std::string& result,
                                           std::auto_ptr<ImageAccessor>& image,
                                           ImageExtractionMode mode,
@@ -785,8 +962,10 @@ namespace Orthanc
     PngWriter writer;
     writer.WriteToMemory(result, *image);
   }
+#endif
 
 
+#if ORTHANC_ENABLE_JPEG == 1
   void DicomImageDecoder::ExtractJpegImage(std::string& result,
                                            std::auto_ptr<ImageAccessor>& image,
                                            ImageExtractionMode mode,
@@ -805,4 +984,5 @@ namespace Orthanc
     writer.SetQuality(quality);
     writer.WriteToMemory(result, *image);
   }
+#endif
 }
diff --git a/OrthancServer/Internals/DicomImageDecoder.h b/Core/DicomParsing/Internals/DicomImageDecoder.h
similarity index 87%
rename from OrthancServer/Internals/DicomImageDecoder.h
rename to Core/DicomParsing/Internals/DicomImageDecoder.h
index 5a791d0..f1beb28 100644
--- a/OrthancServer/Internals/DicomImageDecoder.h
+++ b/Core/DicomParsing/Internals/DicomImageDecoder.h
@@ -41,14 +41,23 @@
 #  error The macro ORTHANC_ENABLE_JPEG must be defined
 #endif
 
-#if !defined(ORTHANC_ENABLE_JPEG_LOSSLESS)
-#  error The macro ORTHANC_ENABLE_JPEG_LOSSLESS must be defined
+#if !defined(ORTHANC_ENABLE_PNG)
+#  error The macro ORTHANC_ENABLE_PNG must be defined
+#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
 
 
 class DcmDataset;
 class DcmCodec;
 class DcmCodecParameter;
+class DcmRepresentationParameter;
 
 namespace Orthanc
 {
@@ -69,6 +78,7 @@ namespace Orthanc
 
     static ImageAccessor* ApplyCodec(const DcmCodec& codec,
                                      const DcmCodecParameter& parameters,
+                                     const DcmRepresentationParameter& representationParameter,
                                      DcmDataset& dataset,
                                      unsigned int frame);
 
@@ -91,15 +101,19 @@ namespace Orthanc
     static ImageAccessor *Decode(ParsedDicomFile& dicom,
                                  unsigned int frame);
 
+#if ORTHANC_ENABLE_PNG == 1
     static void ExtractPngImage(std::string& result,
                                 std::auto_ptr<ImageAccessor>& image,
                                 ImageExtractionMode mode,
                                 bool invert);
+#endif
 
+#if ORTHANC_ENABLE_JPEG == 1
     static void ExtractJpegImage(std::string& result,
                                  std::auto_ptr<ImageAccessor>& image,
                                  ImageExtractionMode mode,
                                  bool invert,
                                  uint8_t quality);
+#endif
   };
 }
diff --git a/OrthancServer/ParsedDicomFile.cpp b/Core/DicomParsing/ParsedDicomFile.cpp
similarity index 93%
rename from OrthancServer/ParsedDicomFile.cpp
rename to Core/DicomParsing/ParsedDicomFile.cpp
index 158d12d..311d158 100644
--- a/OrthancServer/ParsedDicomFile.cpp
+++ b/Core/DicomParsing/ParsedDicomFile.cpp
@@ -73,7 +73,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 =========================================================================*/
 
 
-#include "PrecompiledHeadersServer.h"
+#include "../PrecompiledHeaders.h"
 
 #ifndef NOMINMAX
 #define NOMINMAX
@@ -81,16 +81,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "ParsedDicomFile.h"
 
-#include "OrthancInitialization.h"
-#include "ServerToolbox.h"
 #include "FromDcmtkBridge.h"
 #include "ToDcmtkBridge.h"
 #include "Internals/DicomFrameIndex.h"
-#include "../Core/Images/JpegReader.h"
-#include "../Core/Images/PngReader.h"
-#include "../Core/Logging.h"
-#include "../Core/OrthancException.h"
-#include "../Core/Toolbox.h"
+#include "../Logging.h"
+#include "../OrthancException.h"
+#include "../Toolbox.h"
+#include "../SystemToolbox.h"
+
+#if ORTHANC_ENABLE_JPEG == 1
+#  include "../Images/JpegReader.h"
+#endif
+
+#if ORTHANC_ENABLE_PNG == 1
+#  include "../Images/PngReader.h"
+#endif
 
 #include <list>
 #include <limits>
@@ -141,9 +146,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endif
 
 
-static const char* CONTENT_TYPE_OCTET_STREAM = "application/octet-stream";
-
-
 
 namespace Orthanc
 {
@@ -154,6 +156,33 @@ namespace Orthanc
   };
 
 
+#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
+  static const char* CONTENT_TYPE_OCTET_STREAM = "application/octet-stream";
+
+  static void ParseTagAndGroup(DcmTagKey& key,
+                               const std::string& tag)
+  {
+    DicomTag t = FromDcmtkBridge::ParseTag(tag);
+    key = DcmTagKey(t.GetGroup(), t.GetElement());
+  }
+
+  
+  static unsigned int GetPixelDataBlockCount(DcmPixelData& pixelData,
+                                             E_TransferSyntax transferSyntax)
+  {
+    DcmPixelSequence* pixelSequence = NULL;
+    if (pixelData.getEncapsulatedRepresentation
+        (transferSyntax, NULL, pixelSequence).good() && pixelSequence)
+    {
+      return pixelSequence->card();
+    }
+    else
+    {
+      return 1;
+    }
+  }
+
+  
   static void SendPathValueForDictionary(RestApiOutput& output,
                                          DcmItem& dicom)
   {
@@ -173,33 +202,6 @@ namespace Orthanc
     output.AnswerJson(v);
   }
 
-  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]));
-  }
-
-  static void ParseTagAndGroup(DcmTagKey& key,
-                               const std::string& tag)
-  {
-    DicomTag t = FromDcmtkBridge::ParseTag(tag);
-    key = DcmTagKey(t.GetGroup(), t.GetElement());
-  }
-
 
   static void SendSequence(RestApiOutput& output,
                            DcmSequenceOfItems& sequence)
@@ -216,22 +218,6 @@ namespace Orthanc
   }
 
 
-  static unsigned int GetPixelDataBlockCount(DcmPixelData& pixelData,
-                                             E_TransferSyntax transferSyntax)
-  {
-    DcmPixelSequence* pixelSequence = NULL;
-    if (pixelData.getEncapsulatedRepresentation
-        (transferSyntax, NULL, pixelSequence).good() && pixelSequence)
-    {
-      return pixelSequence->card();
-    }
-    else
-    {
-      return 1;
-    }
-  }
-
-
   namespace
   {
     class DicomFieldStream : public IHttpStreamAnswer
@@ -408,7 +394,6 @@ namespace Orthanc
   }
 
 
-
   static void SendPathValueForLeaf(RestApiOutput& output,
                                    const std::string& tag,
                                    DcmItem& dicom,
@@ -436,7 +421,32 @@ namespace Orthanc
       output.AnswerStream(stream);
     }
   }
+#endif
+
+  
+  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 ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
   void ParsedDicomFile::SendPathValue(RestApiOutput& output,
                                       const UriComponents& uri)
   {
@@ -493,7 +503,8 @@ namespace Orthanc
       SendPathValueForLeaf(output, uri.back(), *dicom, transferSyntax);
     }
   }
-
+#endif
+  
 
   void ParsedDicomFile::Remove(const DicomTag& tag)
   {
@@ -777,6 +788,7 @@ namespace Orthanc
   }
 
     
+#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
   void ParsedDicomFile::Answer(RestApiOutput& output)
   {
     std::string serialized;
@@ -785,7 +797,7 @@ namespace Orthanc
       output.AnswerBuffer(serialized, CONTENT_TYPE_OCTET_STREAM);
     }
   }
-
+#endif
 
 
   bool ParsedDicomFile::GetTagValue(std::string& value,
@@ -830,9 +842,10 @@ namespace Orthanc
         return false;
       }
 
+      std::set<DicomTag> tmp;
       std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement
                                   (*element, DicomToJsonFlags_Default, 
-                                   ORTHANC_MAXIMUM_TAG_LENGTH, GetEncoding()));
+                                   0, GetEncoding(), tmp));
       
       if (v.get() == NULL ||
           v->IsNull())
@@ -943,7 +956,7 @@ namespace Orthanc
   ParsedDicomFile::ParsedDicomFile(const DicomMap& map) : 
     pimpl_(new PImpl)
   {
-    CreateFromDicomMap(map, Configuration::GetDefaultEncoding());
+    CreateFromDicomMap(map, GetDefaultDicomEncoding());
   }
 
 
@@ -1016,10 +1029,23 @@ namespace Orthanc
 
     Toolbox::ToLowerCase(mime);
 
-    if (mime == "image/png" ||
-        mime == "image/jpeg")
+    if (mime == "image/png")
+    {
+#if ORTHANC_ENABLE_PNG == 1
+      EmbedImage(mime, content);
+#else
+      LOG(ERROR) << "Orthanc was compiled without support of PNG";
+      throw OrthancException(ErrorCode_NotImplemented);
+#endif
+    }
+    else if (mime == "image/jpeg")
     {
+#if ORTHANC_ENABLE_JPEG == 1
       EmbedImage(mime, content);
+#else
+      LOG(ERROR) << "Orthanc was compiled without support of JPEG";
+      throw OrthancException(ErrorCode_NotImplemented);
+#endif
     }
     else if (mime == "application/pdf")
     {
@@ -1044,6 +1070,8 @@ namespace Orthanc
   }
 
 
+#if (ORTHANC_ENABLE_JPEG == 1 &&  \
+     ORTHANC_ENABLE_PNG == 1)
   void ParsedDicomFile::EmbedImage(const std::string& mime,
                                    const std::string& content)
   {
@@ -1064,6 +1092,7 @@ namespace Orthanc
       throw OrthancException(ErrorCode_NotImplemented);
     }
   }
+#endif
 
 
   void ParsedDicomFile::EmbedImage(const ImageAccessor& accessor)
@@ -1191,7 +1220,7 @@ namespace Orthanc
   Encoding ParsedDicomFile::GetEncoding() const
   {
     return FromDcmtkBridge::DetectEncoding(*pimpl_->file_->getDataset(),
-                                           Configuration::GetDefaultEncoding());
+                                           GetDefaultDicomEncoding());
   }
 
 
@@ -1213,14 +1242,36 @@ namespace Orthanc
                                       DicomToJsonFlags flags,
                                       unsigned int maxStringLength)
   {
+    std::set<DicomTag> ignoreTagLength;
     FromDcmtkBridge::ExtractDicomAsJson(target, *pimpl_->file_->getDataset(),
-                                        format, flags, maxStringLength, Configuration::GetDefaultEncoding());
+                                        format, flags, maxStringLength,
+                                        GetDefaultDicomEncoding(), ignoreTagLength);
+  }
+
+
+  void ParsedDicomFile::DatasetToJson(Json::Value& target, 
+                                      DicomToJsonFormat format,
+                                      DicomToJsonFlags flags,
+                                      unsigned int maxStringLength,
+                                      const std::set<DicomTag>& ignoreTagLength)
+  {
+    FromDcmtkBridge::ExtractDicomAsJson(target, *pimpl_->file_->getDataset(),
+                                        format, flags, maxStringLength,
+                                        GetDefaultDicomEncoding(), ignoreTagLength);
+  }
+
+
+  void ParsedDicomFile::DatasetToJson(Json::Value& target,
+                                      const std::set<DicomTag>& ignoreTagLength)
+  {
+    FromDcmtkBridge::ExtractDicomAsJson(target, *pimpl_->file_->getDataset(), ignoreTagLength);
   }
 
 
   void ParsedDicomFile::DatasetToJson(Json::Value& target)
   {
-    Configuration::ExtractDicomAsJson(target, *pimpl_->file_->getDataset());
+    const std::set<DicomTag> ignoreTagLength;
+    FromDcmtkBridge::ExtractDicomAsJson(target, *pimpl_->file_->getDataset(), ignoreTagLength);
   }
 
 
@@ -1330,7 +1381,7 @@ namespace Orthanc
 	const bool decodeDataUriScheme = (flags & DicomFromJsonFlags_DecodeDataUriScheme) ? true : false;
 
     std::auto_ptr<ParsedDicomFile> result(new ParsedDicomFile(generateIdentifiers));
-    result->SetEncoding(FromDcmtkBridge::ExtractEncoding(json, Configuration::GetDefaultEncoding()));
+    result->SetEncoding(FromDcmtkBridge::ExtractEncoding(json, GetDefaultDicomEncoding()));
 
     const Json::Value::Members tags = json.getMemberNames();
     
@@ -1417,13 +1468,7 @@ namespace Orthanc
 
   void ParsedDicomFile::ExtractDicomSummary(DicomMap& target) const
   {
-    Configuration::ExtractDicomSummary(target, *pimpl_->file_->getDataset());
-  }
-
-
-  void ParsedDicomFile::ExtractDicomAsJson(Json::Value& target) const
-  {
-    Configuration::ExtractDicomAsJson(target, *pimpl_->file_->getDataset());
+    FromDcmtkBridge::ExtractDicomSummary(target, *pimpl_->file_->getDataset());
   }
 
 
diff --git a/OrthancServer/ParsedDicomFile.h b/Core/DicomParsing/ParsedDicomFile.h
similarity index 82%
rename from OrthancServer/ParsedDicomFile.h
rename to Core/DicomParsing/ParsedDicomFile.h
index 2c8bdf8..902fde6 100644
--- a/OrthancServer/ParsedDicomFile.h
+++ b/Core/DicomParsing/ParsedDicomFile.h
@@ -33,12 +33,31 @@
 
 #pragma once
 
-#include "../Core/DicomFormat/DicomInstanceHasher.h"
-#include "../Core/Images/ImageAccessor.h"
-#include "../Core/IDynamicObject.h"
-#include "../Core/RestApi/RestApiOutput.h"
-#include "../Core/Toolbox.h"
-#include "ServerEnumerations.h"
+#if !defined(ORTHANC_ENABLE_JPEG)
+#  error Macro ORTHANC_ENABLE_JPEG must be defined to use this file
+#endif
+
+#if !defined(ORTHANC_ENABLE_PNG)
+#  error Macro ORTHANC_ENABLE_PNG must be defined to use this file
+#endif
+
+#if !defined(ORTHANC_ENABLE_CIVETWEB)
+#  error Macro ORTHANC_ENABLE_CIVETWEB must be defined to use this file
+#endif
+
+#if !defined(ORTHANC_ENABLE_MONGOOSE)
+#  error Macro ORTHANC_ENABLE_MONGOOSE must be defined to use this file
+#endif
+
+#include "../DicomFormat/DicomInstanceHasher.h"
+#include "../Images/ImageAccessor.h"
+#include "../IDynamicObject.h"
+#include "../Toolbox.h"
+
+#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
+#  include "../RestApi/RestApiOutput.h"
+#endif
+
 
 class DcmDataset;
 class DcmFileFormat;
@@ -89,10 +108,12 @@ namespace Orthanc
 
     ParsedDicomFile* Clone();
 
+#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
     void SendPathValue(RestApiOutput& output,
                        const UriComponents& uri);
 
     void Answer(RestApiOutput& output);
+#endif
 
     void Remove(const DicomTag& tag);
 
@@ -144,8 +165,11 @@ namespace Orthanc
 
     void EmbedImage(const ImageAccessor& accessor);
 
+#if (ORTHANC_ENABLE_JPEG == 1 &&  \
+     ORTHANC_ENABLE_PNG == 1)
     void EmbedImage(const std::string& mime,
                     const std::string& content);
+#endif
 
     Encoding GetEncoding() const;
 
@@ -158,8 +182,17 @@ namespace Orthanc
                        DicomToJsonFlags flags,
                        unsigned int maxStringLength);
 
+    void DatasetToJson(Json::Value& target, 
+                       DicomToJsonFormat format,
+                       DicomToJsonFlags flags,
+                       unsigned int maxStringLength,
+                       const std::set<DicomTag>& ignoreTagLength);
+      
     // This version uses the default parameters for
     // FileContentType_DicomAsJson
+    void DatasetToJson(Json::Value& target,
+                       const std::set<DicomTag>& ignoreTagLength);
+
     void DatasetToJson(Json::Value& target);
 
     void HeaderToJson(Json::Value& target, 
@@ -184,8 +217,6 @@ namespace Orthanc
 
     void ExtractDicomSummary(DicomMap& target) const;
 
-    void ExtractDicomAsJson(Json::Value& target) const;
-
     bool LookupTransferSyntax(std::string& result);
 
     bool LookupPhotometricInterpretation(PhotometricInterpretation& result) const;
diff --git a/OrthancServer/ToDcmtkBridge.cpp b/Core/DicomParsing/ToDcmtkBridge.cpp
similarity index 98%
rename from OrthancServer/ToDcmtkBridge.cpp
rename to Core/DicomParsing/ToDcmtkBridge.cpp
index e848262..3d8a929 100644
--- a/OrthancServer/ToDcmtkBridge.cpp
+++ b/Core/DicomParsing/ToDcmtkBridge.cpp
@@ -31,13 +31,13 @@
  **/
 
 
-#include "PrecompiledHeadersServer.h"
+#include "../PrecompiledHeaders.h"
 #include "ToDcmtkBridge.h"
 
 #include <memory>
 #include <dcmtk/dcmnet/diutil.h>
 
-#include "../Core/OrthancException.h"
+#include "../OrthancException.h"
 
 
 namespace Orthanc
diff --git a/OrthancServer/ToDcmtkBridge.h b/Core/DicomParsing/ToDcmtkBridge.h
similarity index 93%
rename from OrthancServer/ToDcmtkBridge.h
rename to Core/DicomParsing/ToDcmtkBridge.h
index 551640f..7a6b88f 100644
--- a/OrthancServer/ToDcmtkBridge.h
+++ b/Core/DicomParsing/ToDcmtkBridge.h
@@ -33,7 +33,11 @@
 
 #pragma once
 
-#include "../Core/DicomFormat/DicomMap.h"
+#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
diff --git a/Core/Endianness.h b/Core/Endianness.h
index 14cbca1..102bbd5 100644
--- a/Core/Endianness.h
+++ b/Core/Endianness.h
@@ -35,10 +35,10 @@
 
 
 /********************************************************************
- ** LINUX ARCHITECTURES
+ ** LINUX-LIKE ARCHITECTURES
  ********************************************************************/
 
-#if defined(__linux__)
+#if defined(__linux__) || defined(__EMSCRIPTEN__)
 #  define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1
 #  include <endian.h>
 #endif
diff --git a/Core/Enumerations.cpp b/Core/Enumerations.cpp
index 8309e1a..57a52e6 100644
--- a/Core/Enumerations.cpp
+++ b/Core/Enumerations.cpp
@@ -38,6 +38,7 @@
 #include "Toolbox.h"
 #include "Logging.h"
 
+#include <boost/thread/mutex.hpp>
 #include <string.h>
 #include <cassert>
 
@@ -752,12 +753,128 @@ namespace Orthanc
       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 @@ namespace Orthanc
   }
   
 
+  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 @@ namespace Orthanc
 
       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 @@ namespace Orthanc
     {
       encoding = Encoding_Japanese;
     }
-    else if (s == "GB18030")
+    else if (s == "GB18030" || s == "GBK")
     {
+      /**
+       * According to tumashu at 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 @@ namespace Orthanc
       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;
+  }
+
 }
diff --git a/Core/Enumerations.h b/Core/Enumerations.h
index aae6627..89e68d0 100644
--- a/Core/Enumerations.h
+++ b/Core/Enumerations.h
@@ -199,8 +199,21 @@ namespace Orthanc
      **/
     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 @@ namespace Orthanc
     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 @@ namespace Orthanc
 
   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 @@ namespace Orthanc
                                                   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 @@ namespace Orthanc
   bool IsUserContentType(FileContentType type);
 
   bool IsBinaryValueRepresentation(ValueRepresentation vr);
+  
+  Encoding GetDefaultDicomEncoding();
+
+  void SetDefaultDicomEncoding(Encoding encoding);
 }
diff --git a/Core/FileStorage/FilesystemStorage.h b/Core/FileStorage/FilesystemStorage.h
index 793b6b5..630e82f 100644
--- a/Core/FileStorage/FilesystemStorage.h
+++ b/Core/FileStorage/FilesystemStorage.h
@@ -33,6 +33,14 @@
 
 #pragma once
 
+#if !defined(ORTHANC_SANDBOXED)
+#  error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if ORTHANC_SANDBOXED == 1
+#  error The class FilesystemStorage cannot be used in sandboxed environments
+#endif
+
 #include "IStorageArea.h"
 
 #include <stdint.h>
diff --git a/Core/FileStorage/StorageAccessor.cpp b/Core/FileStorage/StorageAccessor.cpp
index 89830fc..6c523fc 100644
--- a/Core/FileStorage/StorageAccessor.cpp
+++ b/Core/FileStorage/StorageAccessor.cpp
@@ -36,10 +36,13 @@
 
 #include "../Compression/ZlibCompressor.h"
 #include "../OrthancException.h"
-#include "../HttpServer/HttpStreamTranscoder.h"
 #include "../Toolbox.h"
 #include "../SystemToolbox.h"
 
+#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
+#  include "../HttpServer/HttpStreamTranscoder.h"
+#endif
+
 namespace Orthanc
 {
   FileInfo StorageAccessor::Write(const void* data,
@@ -143,6 +146,7 @@ namespace Orthanc
   }
 
 
+#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
   void StorageAccessor::SetupSender(BufferHttpSender& sender,
                                     const FileInfo& info,
                                     const std::string& mime)
@@ -168,8 +172,10 @@ namespace Orthanc
 
     sender.SetContentFilename(info.GetUuid() + std::string(extension));
   }
+#endif
 
 
+#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
   void StorageAccessor::AnswerFile(HttpOutput& output,
                                    const FileInfo& info,
                                    const std::string& mime)
@@ -180,8 +186,10 @@ namespace Orthanc
     HttpStreamTranscoder transcoder(sender, info.GetCompressionType());
     output.Answer(transcoder);
   }
+#endif
 
 
+#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
   void StorageAccessor::AnswerFile(RestApiOutput& output,
                                    const FileInfo& info,
                                    const std::string& mime)
@@ -192,4 +200,5 @@ namespace Orthanc
     HttpStreamTranscoder transcoder(sender, info.GetCompressionType());
     output.AnswerStream(transcoder);
   }
+#endif
 }
diff --git a/Core/FileStorage/StorageAccessor.h b/Core/FileStorage/StorageAccessor.h
index 6268d32..022e44c 100644
--- a/Core/FileStorage/StorageAccessor.h
+++ b/Core/FileStorage/StorageAccessor.h
@@ -33,10 +33,29 @@
 
 #pragma once
 
+#if !defined(ORTHANC_SANDBOXED)
+#  error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if ORTHANC_SANDBOXED == 1
+#  error The class StorageAccessor cannot be used in sandboxed environments
+#endif
+
+#if !defined(ORTHANC_ENABLE_CIVETWEB)
+#  error Macro ORTHANC_ENABLE_CIVETWEB must be defined to use this file
+#endif
+
+#if !defined(ORTHANC_ENABLE_MONGOOSE)
+#  error Macro ORTHANC_ENABLE_MONGOOSE must be defined to use this file
+#endif
+
 #include "IStorageArea.h"
 #include "FileInfo.h"
-#include "../HttpServer/BufferHttpSender.h"
-#include "../RestApi/RestApiOutput.h"
+
+#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
+#  include "../HttpServer/BufferHttpSender.h"
+#  include "../RestApi/RestApiOutput.h"
+#endif
 
 #include <vector>
 #include <string>
@@ -51,9 +70,11 @@ namespace Orthanc
   private:
     IStorageArea&  area_;
 
+#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
     void SetupSender(BufferHttpSender& sender,
                      const FileInfo& info,
                      const std::string& mime);
+#endif
 
   public:
     StorageAccessor(IStorageArea& area) : area_(area)
@@ -86,6 +107,7 @@ namespace Orthanc
       area_.Remove(info.GetUuid(), info.GetContentType());
     }
 
+#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
     void AnswerFile(HttpOutput& output,
                     const FileInfo& info,
                     const std::string& mime);
@@ -93,5 +115,6 @@ namespace Orthanc
     void AnswerFile(RestApiOutput& output,
                     const FileInfo& info,
                     const std::string& mime);
+#endif
   };
 }
diff --git a/Core/HttpServer/MongooseServer.cpp b/Core/HttpServer/MongooseServer.cpp
index d89af62..8c3be1f 100644
--- a/Core/HttpServer/MongooseServer.cpp
+++ b/Core/HttpServer/MongooseServer.cpp
@@ -39,7 +39,17 @@
 #include "../Logging.h"
 #include "../ChunkedBuffer.h"
 #include "HttpToolbox.h"
-#include "mongoose.h"
+
+#if ORTHANC_ENABLE_MONGOOSE == 1
+#  include "mongoose.h"
+
+#elif ORTHANC_ENABLE_CIVETWEB == 1
+#  include "civetweb.h"
+#  define MONGOOSE_USE_CALLBACKS 1
+
+#else
+#  error "Either Mongoose or Civetweb must be enabled to compile this file"
+#endif
 
 #include <algorithm>
 #include <string.h>
@@ -60,8 +70,6 @@
 
 #define ORTHANC_REALM "Orthanc Secure Area"
 
-static const long LOCALHOST = (127ll << 24) + 1ll;
-
 
 namespace Orthanc
 {
@@ -586,9 +594,22 @@ namespace Orthanc
                                struct mg_connection *connection,
                                const struct mg_request_info *request)
   {
+    bool localhost;
+
+#if ORTHANC_ENABLE_MONGOOSE == 1
+    static const long LOCALHOST = (127ll << 24) + 1ll;
+    localhost = (request->remote_ip == LOCALHOST);
+#elif ORTHANC_ENABLE_CIVETWEB == 1
+    // The "remote_ip" field of "struct mg_request_info" is tagged as
+    // deprecated in Civetweb, using "remote_addr" instead.
+    localhost = (std::string(request->remote_addr) == "127.0.0.1");
+#else
+#error
+#endif
+    
     // Check remote calls
     if (!server.IsRemoteAccessAllowed() &&
-        request->remote_ip != LOCALHOST)
+        !localhost)
     {
       output.SendUnauthorized(ORTHANC_REALM);
       return;
@@ -638,7 +659,8 @@ namespace Orthanc
       return;
     }
 
-
+    
+#if ORTHANC_ENABLE_MONGOOSE == 1
     // Apply the filter, if it is installed
     char remoteIp[24];
     sprintf(remoteIp, "%d.%d.%d.%d", 
@@ -646,6 +668,11 @@ namespace Orthanc
             reinterpret_cast<const uint8_t*>(&request->remote_ip) [2], 
             reinterpret_cast<const uint8_t*>(&request->remote_ip) [1], 
             reinterpret_cast<const uint8_t*>(&request->remote_ip) [0]);
+#elif ORTHANC_ENABLE_CIVETWEB == 1
+    const char* remoteIp = request->remote_addr;
+#else
+#error
+#endif
 
     std::string username = GetAuthenticatedUsername(headers);
 
@@ -747,8 +774,19 @@ namespace Orthanc
   {
     try
     {
-      MongooseServer* server = reinterpret_cast<MongooseServer*>(request->user_data);
+      void* that = NULL;
+
+#if ORTHANC_ENABLE_MONGOOSE == 1
+      that = request->user_data;
+#elif ORTHANC_ENABLE_CIVETWEB == 1
+      // https://github.com/civetweb/civetweb/issues/409
+      that = mg_get_user_data(mg_get_context(connection));
+#else
+#error
+#endif                              
       
+      MongooseServer* server = reinterpret_cast<MongooseServer*>(that);
+
       if (server == NULL)
       {
         MongooseOutputStream stream(connection);
@@ -756,7 +794,7 @@ namespace Orthanc
         output.SendStatus(HttpStatus_500_InternalServerError);
         return;
       }
-      
+
       MongooseOutputStream stream(connection);
       HttpOutput output(stream, server->IsKeepAliveEnabled());
       HttpMethod method = HttpMethod_Get;
@@ -846,7 +884,7 @@ namespace Orthanc
 #elif MONGOOSE_USE_CALLBACKS == 1
   static int Callback(struct mg_connection *connection)
   {
-    struct mg_request_info *request = mg_get_request_info(connection);
+    const struct mg_request_info *request = mg_get_request_info(connection);
 
     ProtectedCallback(connection, request);
 
@@ -906,6 +944,14 @@ namespace Orthanc
 
   void MongooseServer::Start()
   {
+#if ORTHANC_ENABLE_MONGOOSE == 1
+    LOG(INFO) << "Starting embedded Web server using Mongoose";
+#elif ORTHANC_ENABLE_CIVETWEB == 1
+    LOG(INFO) << "Starting embedded Web server using Civetweb";
+#else
+#error
+#endif  
+
     if (!IsRunning())
     {
       std::string port = boost::lexical_cast<std::string>(port_);
diff --git a/Core/HttpServer/MongooseServer.h b/Core/HttpServer/MongooseServer.h
index a482ca1..e6af512 100644
--- a/Core/HttpServer/MongooseServer.h
+++ b/Core/HttpServer/MongooseServer.h
@@ -33,6 +33,20 @@
 
 #pragma once
 
+#if !defined(ORTHANC_ENABLE_MONGOOSE)
+#  error Macro ORTHANC_ENABLE_MONGOOSE must be defined to include this file
+#endif
+
+#if !defined(ORTHANC_ENABLE_CIVETWEB)
+#  error Macro ORTHANC_ENABLE_CIVETWEB must be defined to include this file
+#endif
+
+#if (ORTHANC_ENABLE_MONGOOSE == 0 && \
+     ORTHANC_ENABLE_CIVETWEB == 0)
+#  error Either ORTHANC_ENABLE_MONGOOSE or ORTHANC_ENABLE_CIVETWEB must be set to 1
+#endif
+
+
 #include "IIncomingHttpRequestFilter.h"
 
 #include "../OrthancException.h"
diff --git a/Core/Images/Font.cpp b/Core/Images/Font.cpp
index e063a5a..ffc5660 100644
--- a/Core/Images/Font.cpp
+++ b/Core/Images/Font.cpp
@@ -34,7 +34,14 @@
 #include "../PrecompiledHeaders.h"
 #include "Font.h"
 
-#include "../SystemToolbox.h"
+#if !defined(ORTHANC_ENABLE_LOCALE)
+#  error ORTHANC_ENABLE_LOCALE must be defined to use this file
+#endif
+
+#if ORTHANC_SANDBOXED == 0
+#  include "../SystemToolbox.h"
+#endif
+
 #include "../Toolbox.h"
 #include "../OrthancException.h"
 
@@ -134,12 +141,14 @@ namespace Orthanc
   }
 
 
+#if ORTHANC_SANDBOXED == 0
   void Font::LoadFromFile(const std::string& path)
   {
     std::string font;
     SystemToolbox::ReadFile(font, path);
     LoadFromMemory(font);
   }
+#endif
 
 
   static unsigned int MyMin(unsigned int a, 
@@ -254,7 +263,13 @@ namespace Orthanc
 
     int a = x;
 
+#if ORTHANC_ENABLE_LOCALE == 1
     std::string s = Toolbox::ConvertFromUtf8(utf8, Encoding_Latin1);
+#else
+    // If the locale support is disabled, simply drop non-ASCII
+    // characters from the source UTF-8 string
+    std::string s = Toolbox::ConvertToAscii(utf8);
+#endif
 
     for (size_t i = 0; i < s.size(); i++)
     {
diff --git a/Core/Images/Font.h b/Core/Images/Font.h
index 3a91271..5a39181 100644
--- a/Core/Images/Font.h
+++ b/Core/Images/Font.h
@@ -84,7 +84,9 @@ namespace Orthanc
 
     void LoadFromMemory(const std::string& font);
 
+#if ORTHANC_SANDBOXED == 0
     void LoadFromFile(const std::string& path);
+#endif
 
     const std::string& GetName() const
     {
diff --git a/Core/Images/FontRegistry.cpp b/Core/Images/FontRegistry.cpp
index 20b8013..86f0df6 100644
--- a/Core/Images/FontRegistry.cpp
+++ b/Core/Images/FontRegistry.cpp
@@ -57,20 +57,24 @@ namespace Orthanc
   }
 
 
+#if ORTHANC_SANDBOXED == 0
   void FontRegistry::AddFromFile(const std::string& path)
   {
     std::auto_ptr<Font> f(new Font);
     f->LoadFromFile(path);
     fonts_.push_back(f.release());
   }
+#endif
 
 
+#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
   void FontRegistry::AddFromResource(EmbeddedResources::FileResourceId resource)
   {
     std::string content;
     EmbeddedResources::GetFileResource(content, resource);
     AddFromMemory(content);
   }
+#endif
 
 
   const Font& FontRegistry::GetFont(size_t i) const
diff --git a/Core/Images/FontRegistry.h b/Core/Images/FontRegistry.h
index e3519b0..c4c3af7 100644
--- a/Core/Images/FontRegistry.h
+++ b/Core/Images/FontRegistry.h
@@ -35,7 +35,13 @@
 
 #include "Font.h"
 
-#include <EmbeddedResources.h>   // Autogenerated file
+#if !defined(ORTHANC_HAS_EMBEDDED_RESOURCES)
+#  error Macro ORTHANC_HAS_EMBEDDED_RESOURCES must be defined
+#endif
+
+#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
+#  include <EmbeddedResources.h>   // Autogenerated file
+#endif
 
 namespace Orthanc
 {
@@ -51,9 +57,13 @@ namespace Orthanc
 
     void AddFromMemory(const std::string& font);
 
+#if ORTHANC_SANDBOXED == 0
     void AddFromFile(const std::string& path);
+#endif
 
+#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
     void AddFromResource(EmbeddedResources::FileResourceId resource);
+#endif
 
     size_t GetSize() const
     {
diff --git a/Core/Images/ImageAccessor.cpp b/Core/Images/ImageAccessor.cpp
index 2c61674..942be97 100644
--- a/Core/Images/ImageAccessor.cpp
+++ b/Core/Images/ImageAccessor.cpp
@@ -218,6 +218,10 @@ namespace Orthanc
         ToMatlabStringInternal<uint16_t>(buffer, *this);
         break;
 
+      case PixelFormat_Grayscale32:
+        ToMatlabStringInternal<uint32_t>(buffer, *this);
+        break;
+
       case PixelFormat_SignedGrayscale16:
         ToMatlabStringInternal<int16_t>(buffer, *this);
         break;
diff --git a/Core/Images/ImageProcessing.cpp b/Core/Images/ImageProcessing.cpp
index eea0a85..12667a9 100644
--- a/Core/Images/ImageProcessing.cpp
+++ b/Core/Images/ImageProcessing.cpp
@@ -413,6 +413,13 @@ namespace Orthanc
     }
 
     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 @@ namespace Orthanc
       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 @@ namespace Orthanc
         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 @@ namespace Orthanc
   }
 
 
-  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 @@ namespace Orthanc
         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 @@ namespace Orthanc
   }
 
 
+  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)
diff --git a/Core/Images/ImageProcessing.h b/Core/Images/ImageProcessing.h
index 8ee4297..1b6c616 100644
--- a/Core/Images/ImageProcessing.h
+++ b/Core/Images/ImageProcessing.h
@@ -60,9 +60,13 @@ namespace Orthanc
     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);
diff --git a/Core/Images/JpegErrorManager.h b/Core/Images/JpegErrorManager.h
index f149510..118e57e 100644
--- a/Core/Images/JpegErrorManager.h
+++ b/Core/Images/JpegErrorManager.h
@@ -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>
diff --git a/Core/Images/JpegReader.h b/Core/Images/JpegReader.h
index 105a9b8..5c9781c 100644
--- a/Core/Images/JpegReader.h
+++ b/Core/Images/JpegReader.h
@@ -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 : 
diff --git a/Core/Images/JpegWriter.cpp b/Core/Images/JpegWriter.cpp
index 1c62ac2..81b42a7 100644
--- a/Core/Images/JpegWriter.cpp
+++ b/Core/Images/JpegWriter.cpp
@@ -162,6 +162,7 @@ namespace Orthanc
 #endif
 
 
+#if ORTHANC_SANDBOXED == 0
   void JpegWriter::WriteToMemoryInternal(std::string& jpeg,
                                          unsigned int width,
                                          unsigned int height,
@@ -206,4 +207,5 @@ namespace Orthanc
     jpeg.assign(reinterpret_cast<const char*>(data), size);
     free(data);
   }
+#endif
 }
diff --git a/Core/Images/JpegWriter.h b/Core/Images/JpegWriter.h
index 94341c4..8570a61 100644
--- a/Core/Images/JpegWriter.h
+++ b/Core/Images/JpegWriter.h
@@ -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
diff --git a/Core/Images/PngReader.h b/Core/Images/PngReader.h
index f07013d..659037f 100644
--- a/Core/Images/PngReader.h
+++ b/Core/Images/PngReader.h
@@ -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"
diff --git a/Core/Images/PngWriter.cpp b/Core/Images/PngWriter.cpp
index bf04e9a..72aa6cd 100644
--- a/Core/Images/PngWriter.cpp
+++ b/Core/Images/PngWriter.cpp
@@ -248,6 +248,7 @@ namespace Orthanc
 
 
 
+#if ORTHANC_SANDBOXED == 0
   void PngWriter::WriteToMemoryInternal(std::string& png,
                                         unsigned int width,
                                         unsigned int height,
@@ -271,4 +272,5 @@ namespace Orthanc
 
     chunks.Flatten(png);
   }
+#endif
 }
diff --git a/Core/Images/PngWriter.h b/Core/Images/PngWriter.h
index 691a579..e7dd42b 100644
--- a/Core/Images/PngWriter.h
+++ b/Core/Images/PngWriter.h
@@ -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>
diff --git a/Core/Logging.cpp b/Core/Logging.cpp
index c1635a4..13e438c 100644
--- a/Core/Logging.cpp
+++ b/Core/Logging.cpp
@@ -161,12 +161,7 @@ namespace Orthanc
 #include <fstream>
 #include <boost/filesystem.hpp>
 #include <boost/thread.hpp>
-
-#if BOOST_HAS_DATE_TIME == 1
-#  include <boost/date_time/posix_time/posix_time.hpp>
-#else
-#  error Boost::date_time is required
-#endif
+#include <boost/date_time/posix_time/posix_time.hpp>
 
 
 namespace
diff --git a/Core/Lua/LuaContext.cpp b/Core/Lua/LuaContext.cpp
index d8e80b7..9eb81a1 100644
--- a/Core/Lua/LuaContext.cpp
+++ b/Core/Lua/LuaContext.cpp
@@ -588,12 +588,14 @@ namespace Orthanc
   }
 
 
+#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
   void LuaContext::Execute(EmbeddedResources::FileResourceId resource)
   {
     std::string command;
     EmbeddedResources::GetFileResource(command, resource);
     ExecuteInternal(NULL, command);
   }
+#endif
 
 
   bool LuaContext::IsExistingFunction(const char* name)
diff --git a/Core/Lua/LuaContext.h b/Core/Lua/LuaContext.h
index ac51591..62e98d7 100644
--- a/Core/Lua/LuaContext.h
+++ b/Core/Lua/LuaContext.h
@@ -37,10 +37,18 @@
 #  error The macro ORTHANC_ENABLE_LUA must be defined
 #endif
 
+#if !defined(ORTHANC_HAS_EMBEDDED_RESOURCES)
+#  error Macro ORTHANC_HAS_EMBEDDED_RESOURCES must be defined
+#endif
+
 #if ORTHANC_ENABLE_LUA == 0
 #  error The Lua support is disabled, cannot include this file
 #endif
 
+#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
+#  include <EmbeddedResources.h>   // Autogenerated file
+#endif
+
 #include "../HttpClient.h"
 
 extern "C" 
@@ -48,7 +56,6 @@ extern "C"
 #include <lua.h>
 }
 
-#include <EmbeddedResources.h>
 #include <boost/noncopyable.hpp>
 
 namespace Orthanc
@@ -105,7 +112,9 @@ namespace Orthanc
     void Execute(Json::Value& output,
                  const std::string& command);
 
+#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1
     void Execute(EmbeddedResources::FileResourceId resource);
+#endif
 
     bool IsExistingFunction(const char* name);
 
diff --git a/Core/MultiThreading/Mutex.cpp b/Core/MultiThreading/Mutex.cpp
index f15cc31..b0bd7c5 100644
--- a/Core/MultiThreading/Mutex.cpp
+++ b/Core/MultiThreading/Mutex.cpp
@@ -38,7 +38,7 @@
 
 #if defined(_WIN32)
 #include <windows.h>
-#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__FreeBSD__)
+#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
 #include <pthread.h>
 #else
 #error Support your platform here
@@ -76,7 +76,7 @@ namespace Orthanc
   }
 
 
-#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__FreeBSD__)
+#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
 
   struct Mutex::PImpl
   {
diff --git a/Core/PrecompiledHeaders.h b/Core/PrecompiledHeaders.h
index 4fc6435..98d03ea 100644
--- a/Core/PrecompiledHeaders.h
+++ b/Core/PrecompiledHeaders.h
@@ -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
diff --git a/Core/SQLite/OrthancSQLiteException.h b/Core/SQLite/OrthancSQLiteException.h
index 9ffd382..09d9feb 100644
--- a/Core/SQLite/OrthancSQLiteException.h
+++ b/Core/SQLite/OrthancSQLiteException.h
@@ -38,6 +38,11 @@
 #pragma once
 
 
+#if ORTHANC_ENABLE_SQLITE != 1
+#  error Macro ORTHANC_ENABLE_SQLITE must be set to 1 to use SQLite
+#endif
+
+
 #if ORTHANC_SQLITE_STANDALONE == 1
 #include <stdexcept>
 
diff --git a/Core/SQLite/Statement.h b/Core/SQLite/Statement.h
index 24b14c3..d3ba599 100644
--- a/Core/SQLite/Statement.h
+++ b/Core/SQLite/Statement.h
@@ -46,7 +46,7 @@
 #include <stdint.h>
 
 #if ORTHANC_BUILD_UNIT_TESTS == 1
-#include <gtest/gtest_prod.h>
+#  include <gtest/gtest_prod.h>
 #endif
 
 
diff --git a/Core/SystemToolbox.cpp b/Core/SystemToolbox.cpp
index 5fc53ae..7f722ef 100644
--- a/Core/SystemToolbox.cpp
+++ b/Core/SystemToolbox.cpp
@@ -35,11 +35,6 @@
 #include "SystemToolbox.h"
 
 
-#if BOOST_HAS_DATE_TIME == 1
-#  include <boost/date_time/posix_time/posix_time.hpp>
-#endif
-
-
 #if defined(_WIN32)
 #  include <windows.h>
 #  include <process.h>   // For "_spawnvp()" and "_getpid()"
@@ -62,12 +57,17 @@
 #endif
 
 
+#if defined(__OpenBSD__)
+#  include <sys/sysctl.h>  // For "sysctl", "CTL_KERN" and "KERN_PROC_ARGS"
+#endif
+
+
 // Inclusions for UUID
 // http://stackoverflow.com/a/1626302
 
 extern "C"
 {
-#ifdef WIN32
+#if defined(_WIN32)
 #  include <rpc.h>
 #else
 #  include <uuid/uuid.h>
@@ -81,6 +81,7 @@ extern "C"
 
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
 
 
 namespace Orthanc
@@ -157,7 +158,7 @@ namespace Orthanc
   {
 #if defined(_WIN32)
     ::Sleep(static_cast<DWORD>(microSeconds / static_cast<uint64_t>(1000)));
-#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__native_client__)
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__native_client__)
     usleep(microSeconds);
 #else
 #error Support your platform here
@@ -349,6 +350,8 @@ namespace Orthanc
 #elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
   static std::string GetPathToExecutableInternal()
   {
+    // NOTE: For FreeBSD, using KERN_PROC_PATHNAME might be a better alternative
+
     std::vector<char> buffer(PATH_MAX + 1);
     ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1);
     if (bytes == 0)
@@ -370,6 +373,37 @@ namespace Orthanc
     return std::string(pathbuf);
   }
 
+#elif defined(__OpenBSD__)
+  static std::string GetPathToExecutableInternal()
+  {
+    // This is an adapted version of the patch proposed in issue #64
+    // without an explicit call to "malloc()" to prevent memory leak
+    // https://bitbucket.org/sjodogne/orthanc/issues/64/add-openbsd-support
+    // https://stackoverflow.com/q/31494901/881731
+
+    const int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
+
+    size_t len;
+    if (sysctl(mib, 4, NULL, &len, NULL, 0) == -1) 
+    {
+      throw OrthancException(ErrorCode_PathToExecutable);
+    }
+
+    std::string tmp;
+    tmp.resize(len);
+
+    char** buffer = reinterpret_cast<char**>(&tmp[0]);
+
+    if (sysctl(mib, 4, buffer, &len, NULL, 0) == -1) 
+    {
+      throw OrthancException(ErrorCode_PathToExecutable);
+    }
+    else
+    {
+      return std::string(buffer[0]);
+    }
+  }
+
 #else
 #error Support your platform here
 #endif
@@ -527,13 +561,13 @@ namespace Orthanc
   }
 
 
-#if BOOST_HAS_DATE_TIME == 1
   std::string SystemToolbox::GetNowIsoString()
   {
     boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
     return boost::posix_time::to_iso_string(now);
   }
 
+  
   void SystemToolbox::GetNowDicom(std::string& date,
                                   std::string& time)
   {
@@ -548,5 +582,4 @@ namespace Orthanc
     sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
     time.assign(s);
   }
-#endif
 }
diff --git a/Core/SystemToolbox.h b/Core/SystemToolbox.h
index 0b3fe3f..752af59 100644
--- a/Core/SystemToolbox.h
+++ b/Core/SystemToolbox.h
@@ -95,11 +95,9 @@ namespace Orthanc
 
     std::string GenerateUuid();
 
-#if BOOST_HAS_DATE_TIME == 1
     std::string GetNowIsoString();
 
     void GetNowDicom(std::string& date,
                      std::string& time);
-#endif
   }
 }
diff --git a/Core/Toolbox.cpp b/Core/Toolbox.cpp
index 74b3c57..c9c02a2 100644
--- a/Core/Toolbox.cpp
+++ b/Core/Toolbox.cpp
@@ -40,7 +40,7 @@
 #include <boost/algorithm/string/case_conv.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/lexical_cast.hpp>
-#include <boost/locale.hpp>
+#include <boost/regex.hpp> 
 #include <boost/uuid/sha1.hpp>
  
 #include <string>
@@ -49,13 +49,6 @@
 #include <algorithm>
 #include <ctype.h>
 
-#if BOOST_HAS_REGEX == 1
-#  include <boost/regex.hpp> 
-#endif
-
-#if BOOST_HAS_LOCALE != 1
-#  error Since version 0.7.6, Orthanc entirely relies on boost::locale
-#endif
 
 #if ORTHANC_ENABLE_MD5 == 1
 #  include "../Resources/ThirdParty/md5/md5.h"
@@ -65,6 +58,10 @@
 #  include "../Resources/ThirdParty/base64/base64.h"
 #endif
 
+#if ORTHANC_ENABLE_LOCALE == 1
+#  include <boost/locale.hpp>
+#endif
+
 
 #if defined(_MSC_VER) && (_MSC_VER < 1800)
 // Patch for the missing "_strtoll" symbol when compiling with Visual Studio < 2013
@@ -369,7 +366,6 @@ namespace Orthanc
   }
 
 
-#  if BOOST_HAS_REGEX == 1
   bool Toolbox::DecodeDataUriScheme(std::string& mime,
                                     std::string& content,
                                     const std::string& source)
@@ -389,7 +385,6 @@ namespace Orthanc
       return false;
     }
   }
-#  endif
 
 
   void Toolbox::EncodeDataUriScheme(std::string& result,
@@ -402,6 +397,7 @@ namespace Orthanc
 #endif
 
 
+#if ORTHANC_ENABLE_LOCALE == 1
   static const char* GetBoostLocaleEncoding(const Encoding sourceEncoding)
   {
     switch (sourceEncoding)
@@ -468,8 +464,10 @@ namespace Orthanc
         throw OrthancException(ErrorCode_NotImplemented);
     }
   }
+#endif
 
 
+#if ORTHANC_ENABLE_LOCALE == 1
   std::string Toolbox::ConvertToUtf8(const std::string& source,
                                      Encoding sourceEncoding)
   {
@@ -496,8 +494,10 @@ namespace Orthanc
       return ConvertToAscii(source);
     }
   }
+#endif
+  
 
-
+#if ORTHANC_ENABLE_LOCALE == 1
   std::string Toolbox::ConvertFromUtf8(const std::string& source,
                                        Encoding targetEncoding)
   {
@@ -524,6 +524,7 @@ namespace Orthanc
       return ConvertToAscii(source);
     }
   }
+#endif
 
 
   bool Toolbox::IsAsciiString(const void* data,
@@ -779,7 +780,6 @@ namespace Orthanc
   }
 
 
-#if BOOST_HAS_REGEX == 1
   std::string Toolbox::WildcardToRegularExpression(const std::string& source)
   {
     // TODO - Speed up this with a regular expression
@@ -807,8 +807,6 @@ namespace Orthanc
 
     return result;
   }
-#endif
-
 
 
   void Toolbox::TokenizeString(std::vector<std::string>& result,
@@ -1254,6 +1252,7 @@ namespace Orthanc
   }
 
 
+#if ORTHANC_ENABLE_LOCALE == 1
   static std::auto_ptr<std::locale>  globalLocale_;
 
   static bool SetGlobalLocale(const char* locale)
@@ -1370,4 +1369,5 @@ namespace Orthanc
     w = boost::algorithm::to_upper_copy<std::wstring>(w, *globalLocale_);
     return boost::locale::conv::utf_to_utf<char>(w);
   }
+#endif
 }
diff --git a/Core/Toolbox.h b/Core/Toolbox.h
index f0a9623..d532adb 100644
--- a/Core/Toolbox.h
+++ b/Core/Toolbox.h
@@ -45,6 +45,10 @@
 #  error The macro ORTHANC_ENABLE_BASE64 must be defined
 #endif
 
+#if !defined(ORTHANC_ENABLE_LOCALE)
+#  error The macro ORTHANC_ENABLE_LOCALE must be defined
+#endif
+
 #if !defined(ORTHANC_ENABLE_MD5)
 #  error The macro ORTHANC_ENABLE_MD5 must be defined
 #endif
@@ -53,10 +57,6 @@
 #  error The macro ORTHANC_ENABLE_PUGIXML must be defined
 #endif
 
-#if !defined(BOOST_HAS_REGEX)
-#  error The macro BOOST_HAS_REGEX must be defined
-#endif
-
 
 /**
  * NOTE: GUID vs. UUID
@@ -132,22 +132,22 @@ namespace Orthanc
     void EncodeBase64(std::string& result, 
                       const std::string& data);
 
-#  if BOOST_HAS_REGEX == 1
     bool DecodeDataUriScheme(std::string& mime,
                              std::string& content,
                              const std::string& source);
-#  endif
 
     void EncodeDataUriScheme(std::string& result,
                              const std::string& mime,
                              const std::string& content);
 #endif
 
+#if ORTHANC_ENABLE_LOCALE == 1
     std::string ConvertToUtf8(const std::string& source,
                               Encoding sourceEncoding);
 
     std::string ConvertFromUtf8(const std::string& source,
                                 Encoding targetEncoding);
+#endif
 
     bool IsAsciiString(const void* data,
                        size_t size);
@@ -161,9 +161,7 @@ namespace Orthanc
 
     Endianness DetectEndianness();
 
-#if BOOST_HAS_REGEX == 1
     std::string WildcardToRegularExpression(const std::string& s);
-#endif
 
     void TokenizeString(std::vector<std::string>& result,
                         const std::string& source,
@@ -207,10 +205,12 @@ namespace Orthanc
 
     bool StartsWithUuid(const std::string& str);
 
+#if ORTHANC_ENABLE_LOCALE == 1
     void InitializeGlobalLocale(const char* locale);
 
     void FinalizeGlobalLocale();
 
     std::string ToUpperCaseWithAccents(const std::string& source);
+#endif
   }
 }
diff --git a/LinuxCompilation.txt b/LinuxCompilation.txt
index 8c075cb..e83a4e2 100644
--- a/LinuxCompilation.txt
+++ b/LinuxCompilation.txt
@@ -86,7 +86,7 @@ SUPPORTED - Debian Jessie/Sid
 
 # cmake -DALLOW_DOWNLOADS=ON \
 	-DUSE_SYSTEM_MONGOOSE=OFF \
-        -DUSE_GTEST_DEBIAN_SOURCE_PACKAGE=ON \
+        -DUSE_GOOGLE_TEST_DEBIAN_PACKAGE=ON \
         -DDCMTK_LIBRARIES=dcmjpls \
 	~/Orthanc
 
@@ -108,7 +108,7 @@ SUPPORTED - Ubuntu 12.04.5 LTS
 	-DUSE_SYSTEM_MONGOOSE=OFF \
 	-DUSE_SYSTEM_JSONCPP=OFF \
 	-DUSE_SYSTEM_PUGIXML=OFF \
-        -DUSE_GTEST_DEBIAN_SOURCE_PACKAGE=ON \
+        -DUSE_GOOGLE_TEST_DEBIAN_PACKAGE=ON \
 	~/Orthanc
 
 
@@ -123,7 +123,7 @@ SUPPORTED - Ubuntu 14.04 LTS
                        libcharls-dev libjsoncpp-dev libpugixml-dev
 
 # cmake -DALLOW_DOWNLOADS=ON \
-        -DUSE_GTEST_DEBIAN_SOURCE_PACKAGE=ON \
+        -DUSE_GOOGLE_TEST_DEBIAN_PACKAGE=ON \
         -DUSE_SYSTEM_MONGOOSE=OFF \
         -DDCMTK_LIBRARIES=dcmjpls \
         ~/Orthanc
diff --git a/NEWS b/NEWS
index 92dc78c..7eb8dbc 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,41 @@ Pending changes in the mainline
 ===============================
 
 
+Version 1.3.1 (2017-11-29)
+==========================
+
+General
+-------
+
+* Built-in decoding of palette images
+
+REST API
+--------
+
+* New URI: "/instances/.../frames/.../raw.gz" to compress raw frames using gzip
+* New argument "ignore-length" to force the inclusion of too long tags in JSON
+* New argument "/.../media?extended" to include additional type-3 tags in DICOMDIR
+
+Plugins
+-------
+
+* New pixel formats exposed in SDK: BGRA32, Float32, Grayscale32, RGB48
+
+Maintenance
+-----------
+
+* Creation of ./Resources/CMake/OrthancFramework*.cmake to reuse the Orthanc
+  C++ framework in other projects
+* New security-related options: "DicomAlwaysAllowEcho"
+* Use "GBK" (frequently used in China) as an alias for "GB18030"
+* Experimental support of actively maintained Civetweb to replace Mongoose 3.8
+* Fix issue 31 for good (create new modality types for Philips ADW, GE Xeleris, GE AWServer)
+* Fix issue 64 (OpenBSD support)
+* Fix static compilation of DCMTK 3.6.2 on Fedora
+* Upgrade to Boost 1.65.1 in static builds
+* Upgrade to SQLite amalgamation 3.21.0 in static builds
+
+
 Version 1.3.0 (2017-07-19)
 ==========================
 
diff --git a/OrthancServer/DefaultDicomImageDecoder.h b/OrthancServer/DefaultDicomImageDecoder.h
index 2e9effd..bca5833 100644
--- a/OrthancServer/DefaultDicomImageDecoder.h
+++ b/OrthancServer/DefaultDicomImageDecoder.h
@@ -34,8 +34,8 @@
 #pragma once
 
 #include "IDicomImageDecoder.h"
-#include "ParsedDicomFile.h"
-#include "Internals/DicomImageDecoder.h"
+#include "../Core/DicomParsing/ParsedDicomFile.h"
+#include "../Core/DicomParsing/Internals/DicomImageDecoder.h"
 
 namespace Orthanc
 {
diff --git a/OrthancServer/DicomInstanceToStore.cpp b/OrthancServer/DicomInstanceToStore.cpp
index 68133e3..e916671 100644
--- a/OrthancServer/DicomInstanceToStore.cpp
+++ b/OrthancServer/DicomInstanceToStore.cpp
@@ -34,8 +34,7 @@
 #include "PrecompiledHeadersServer.h"
 #include "DicomInstanceToStore.h"
 
-#include "FromDcmtkBridge.h"
-#include "OrthancInitialization.h"
+#include "../Core/DicomParsing/FromDcmtkBridge.h"
 #include "../Core/Logging.h"
 
 #include <dcmtk/dcmdata/dcfilefo.h>
@@ -106,15 +105,18 @@ namespace Orthanc
     if (!summary_.HasContent())
     {
       summary_.Allocate();
-      Configuration::ExtractDicomSummary(summary_.GetContent(), 
-                                         *parsed_.GetContent().GetDcmtkObject().getDataset());
+      FromDcmtkBridge::ExtractDicomSummary(summary_.GetContent(), 
+                                           *parsed_.GetContent().GetDcmtkObject().getDataset());
     }
     
     if (!json_.HasContent())
     {
       json_.Allocate();
-      Configuration::ExtractDicomAsJson(json_.GetContent(), 
-                                        *parsed_.GetContent().GetDcmtkObject().getDataset());
+
+      std::set<DicomTag> ignoreTagLength;
+      FromDcmtkBridge::ExtractDicomAsJson(json_.GetContent(), 
+                                          *parsed_.GetContent().GetDcmtkObject().getDataset(),
+                                          ignoreTagLength);
     }
   }
 
diff --git a/OrthancServer/DicomInstanceToStore.h b/OrthancServer/DicomInstanceToStore.h
index 1118fa0..e71813b 100644
--- a/OrthancServer/DicomInstanceToStore.h
+++ b/OrthancServer/DicomInstanceToStore.h
@@ -33,7 +33,7 @@
 
 #pragma once
 
-#include "ParsedDicomFile.h"
+#include "../Core/DicomParsing/ParsedDicomFile.h"
 #include "ServerIndex.h"
 #include "../Core/OrthancException.h"
 #include "../Core/RestApi/RestApiCall.h"
diff --git a/OrthancServer/OrthancFindRequestHandler.cpp b/OrthancServer/OrthancFindRequestHandler.cpp
index f64f5c6..4a93786 100644
--- a/OrthancServer/OrthancFindRequestHandler.cpp
+++ b/OrthancServer/OrthancFindRequestHandler.cpp
@@ -37,7 +37,7 @@
 #include "../Core/DicomFormat/DicomArray.h"
 #include "../Core/Lua/LuaFunctionCall.h"
 #include "../Core/Logging.h"
-#include "FromDcmtkBridge.h"
+#include "../Core/DicomParsing/FromDcmtkBridge.h"
 #include "OrthancInitialization.h"
 #include "Search/LookupResource.h"
 #include "ServerToolbox.h"
@@ -454,7 +454,7 @@ namespace Orthanc
     // Whatever the manufacturer, remove the GenericGroupLength tags
     // http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.2.html
     // https://bitbucket.org/sjodogne/orthanc/issues/31/
-    if (tag.GetGroup() == 0x0000)
+    if (tag.GetElement() == 0x0000)
     {
       return false;
     }
diff --git a/OrthancServer/OrthancFindRequestHandler.h b/OrthancServer/OrthancFindRequestHandler.h
index 5577489..da9ba61 100644
--- a/OrthancServer/OrthancFindRequestHandler.h
+++ b/OrthancServer/OrthancFindRequestHandler.h
@@ -32,7 +32,7 @@
 
 #pragma once
 
-#include "DicomProtocol/IFindRequestHandler.h"
+#include "../Core/DicomNetworking/IFindRequestHandler.h"
 
 #include "ServerContext.h"
 
diff --git a/OrthancServer/OrthancInitialization.cpp b/OrthancServer/OrthancInitialization.cpp
index 0bc6ca1..1e732be 100644
--- a/OrthancServer/OrthancInitialization.cpp
+++ b/OrthancServer/OrthancInitialization.cpp
@@ -42,26 +42,14 @@
 
 #include "ServerEnumerations.h"
 #include "DatabaseWrapper.h"
-#include "FromDcmtkBridge.h"
-#include "ToDcmtkBridge.h"
+#include "../Core/DicomParsing/FromDcmtkBridge.h"
 
 #include <boost/lexical_cast.hpp>
 #include <boost/filesystem.hpp>
 #include <curl/curl.h>
 #include <boost/thread/recursive_mutex.hpp>
 
-
-#if ORTHANC_ENABLE_JPEG == 1
-#  include <dcmtk/dcmjpeg/djdecode.h>
-#endif
-
-
-#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
-#  include <dcmtk/dcmjpls/djdecode.h>
-#endif
-
-
-#include <dcmtk/dcmnet/dul.h>
+#include <dcmtk/dcmnet/dul.h>   // For dcmDisableGethostbyaddr()
 
 
 
@@ -482,6 +470,16 @@ namespace Orthanc
       Toolbox::InitializeGlobalLocale(NULL);
     }
 
+    if (configuration_.isMember("DefaultEncoding"))
+    {
+      std::string encoding = GetGlobalStringParameterInternal("DefaultEncoding", "");
+      SetDefaultDicomEncoding(StringToEncoding(encoding.c_str()));
+    }
+    else
+    {
+      SetDefaultDicomEncoding(ORTHANC_DEFAULT_DICOM_ENCODING);
+    }
+
     if (configuration_.isMember("Pkcs11"))
     {
       ConfigurePkcs11(configuration_["Pkcs11"]);
@@ -495,15 +493,7 @@ namespace Orthanc
     FromDcmtkBridge::InitializeDictionary(GetGlobalBoolParameterInternal("LoadPrivateDictionary", true));
     LoadCustomDictionary(configuration_);
 
-#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
-    LOG(WARNING) << "Registering JPEG Lossless codecs";
-    DJLSDecoderRegistration::registerCodecs();    
-#endif
-
-#if ORTHANC_ENABLE_JPEG == 1
-    LOG(WARNING) << "Registering JPEG codecs";
-    DJDecoderRegistration::registerCodecs(); 
-#endif
+    FromDcmtkBridge::InitializeCodecs();
 
     fontRegistry_.AddFromResource(EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
 
@@ -517,17 +507,7 @@ namespace Orthanc
   {
     boost::recursive_mutex::scoped_lock lock(globalMutex_);
     HttpClient::GlobalFinalize();
-
-#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
-    // Unregister JPEG-LS codecs
-    DJLSDecoderRegistration::cleanup();
-#endif
-
-#if ORTHANC_ENABLE_JPEG == 1
-    // Unregister JPEG codecs
-    DJDecoderRegistration::cleanup();
-#endif
-
+    FromDcmtkBridge::FinalizeCodecs();
     HttpClient::FinalizeOpenSsl();
     Toolbox::FinalizeGlobalLocale();
   }
@@ -1134,25 +1114,16 @@ namespace Orthanc
   }
 
 
-  Encoding Configuration::GetDefaultEncoding()
-  {
-    std::string s = GetGlobalStringParameter("DefaultEncoding", "Latin1");
-
-    // By default, Latin1 encoding is assumed
-    return s.empty() ? Encoding_Latin1 : StringToEncoding(s.c_str());
-  }
-
-
   void Configuration::SetDefaultEncoding(Encoding encoding)
   {
-    std::string name = EnumerationToString(encoding);
+    SetDefaultDicomEncoding(encoding);
 
     {
+      // Propagate the encoding to the configuration file that is
+      // stored in memory
       boost::recursive_mutex::scoped_lock lock(globalMutex_);
-      configuration_["DefaultEncoding"] = name;
+      configuration_["DefaultEncoding"] = EnumerationToString(encoding);
     }
-
-    LOG(INFO) << "Default encoding was changed to: " << name;
   }
 
 
@@ -1170,21 +1141,4 @@ namespace Orthanc
 
     return a != b;
   }
-
-
-  void Configuration::ExtractDicomSummary(DicomMap& target, 
-                                          DcmItem& dataset)
-  {
-    FromDcmtkBridge::ExtractDicomSummary(target, dataset, 
-                                         ORTHANC_MAXIMUM_TAG_LENGTH, GetDefaultEncoding());
-  }
-
-  
-  void Configuration::ExtractDicomAsJson(Json::Value& target, 
-                                         DcmDataset& dataset)
-  {
-    FromDcmtkBridge::ExtractDicomAsJson(target, dataset, 
-                                        DicomToJsonFormat_Full, DicomToJsonFlags_Default, 
-                                        ORTHANC_MAXIMUM_TAG_LENGTH, GetDefaultEncoding());
-  }
 }
diff --git a/OrthancServer/OrthancInitialization.h b/OrthancServer/OrthancInitialization.h
index 0fb20ae..eeeecc0 100644
--- a/OrthancServer/OrthancInitialization.h
+++ b/OrthancServer/OrthancInitialization.h
@@ -42,22 +42,11 @@
 #include "../Core/HttpServer/MongooseServer.h"
 #include "../Core/Images/FontRegistry.h"
 #include "../Core/WebServiceParameters.h"
+#include "../Core/DicomNetworking/RemoteModalityParameters.h"
 
-#include "DicomProtocol/RemoteModalityParameters.h"
 #include "IDatabaseWrapper.h"
 #include "ServerEnumerations.h"
 
-#if !defined(ORTHANC_ENABLE_JPEG)
-#  error The macro ORTHANC_ENABLE_JPEG must be defined
-#endif
-
-#if !defined(ORTHANC_ENABLE_JPEG_LOSSLESS)
-#  error The macro ORTHANC_ENABLE_JPEG_LOSSLESS must be defined
-#endif
-
-
-class DcmDataset;
-class DcmItem;
 
 namespace Orthanc
 {
@@ -138,16 +127,8 @@ namespace Orthanc
 
     static const FontRegistry& GetFontRegistry();
 
-    static Encoding GetDefaultEncoding();
-
     static void SetDefaultEncoding(Encoding encoding);
 
     static bool HasConfigurationChanged();
-
-    static void ExtractDicomSummary(DicomMap& target, 
-                                    DcmItem& dataset);
-
-    static void ExtractDicomAsJson(Json::Value& target, 
-                                   DcmDataset& dataset);
   };
 }
diff --git a/OrthancServer/OrthancMoveRequestHandler.cpp b/OrthancServer/OrthancMoveRequestHandler.cpp
index 5e28bdf..081c426 100644
--- a/OrthancServer/OrthancMoveRequestHandler.cpp
+++ b/OrthancServer/OrthancMoveRequestHandler.cpp
@@ -35,7 +35,7 @@
 #include "OrthancMoveRequestHandler.h"
 
 #include "OrthancInitialization.h"
-#include "FromDcmtkBridge.h"
+#include "../../Core/DicomParsing/FromDcmtkBridge.h"
 #include "../Core/DicomFormat/DicomArray.h"
 #include "../Core/Logging.h"
 
diff --git a/OrthancServer/OrthancMoveRequestHandler.h b/OrthancServer/OrthancMoveRequestHandler.h
index 23c866b..23434a1 100644
--- a/OrthancServer/OrthancMoveRequestHandler.h
+++ b/OrthancServer/OrthancMoveRequestHandler.h
@@ -32,7 +32,7 @@
 
 #pragma once
 
-#include "DicomProtocol/IMoveRequestHandler.h"
+#include "../Core/DicomNetworking/IMoveRequestHandler.h"
 #include "ServerContext.h"
 
 namespace Orthanc
diff --git a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp
index 6b8c023..64f7663 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp
@@ -35,7 +35,7 @@
 #include "OrthancRestApi.h"
 
 #include "../../Core/Logging.h"
-#include "../FromDcmtkBridge.h"
+#include "../../Core/DicomParsing/FromDcmtkBridge.h"
 #include "../ServerContext.h"
 #include "../OrthancInitialization.h"
 
@@ -223,7 +223,7 @@ namespace Orthanc
   static bool ParseAnonymizationRequest(DicomModification& target,
                                         RestApiPostCall& call)
   {
-    // curl http://localhost:8042/instances/6e67da51-d119d6ae-c5667437-87b9a8a5-0f07c49f/anonymize -X POST -d '{"Replace":{"PatientName":"hello","0010-0020":"world"},"Keep":["StudyDescription", "SeriesDescription"],"KeepPrivateTags": null,"Remove":["Modality"]}' > Anonymized.dcm
+    // curl http://localhost:8042/instances/6e67da51-d119d6ae-c5667437-87b9a8a5-0f07c49f/anonymize -X POST -d '{"Replace":{"PatientName":"hello","0010-0020":"world"},"Keep":["StudyDescription", "SeriesDescription"],"KeepPrivateTags": true,"Remove":["Modality"]}' > Anonymized.dcm
 
     Json::Value request;
     if (!call.ParseJsonRequest(request) ||
@@ -710,7 +710,7 @@ namespace Orthanc
       }
       else
       {
-        encoding = Configuration::GetDefaultEncoding();
+        encoding = GetDefaultDicomEncoding();
       }
 
       dicom.SetEncoding(encoding);
diff --git a/OrthancServer/OrthancRestApi/OrthancRestApi.cpp b/OrthancServer/OrthancRestApi/OrthancRestApi.cpp
index c050a18..22b0d39 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestApi.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestApi.cpp
@@ -35,7 +35,6 @@
 #include "OrthancRestApi.h"
 
 #include "../../Core/Logging.h"
-#include "../DicomModification.h"
 #include "../ServerContext.h"
 
 namespace Orthanc
diff --git a/OrthancServer/OrthancRestApi/OrthancRestApi.h b/OrthancServer/OrthancRestApi/OrthancRestApi.h
index 8089e76..75552a6 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestApi.h
+++ b/OrthancServer/OrthancRestApi/OrthancRestApi.h
@@ -34,7 +34,8 @@
 #pragma once
 
 #include "../../Core/RestApi/RestApi.h"
-#include "../DicomModification.h"
+#include "../../Core/DicomParsing/DicomModification.h"
+#include "../ServerEnumerations.h"
 
 #include <set>
 
diff --git a/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp b/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp
index 2b01f94..4441a8f 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp
@@ -34,7 +34,7 @@
 #include "../PrecompiledHeadersServer.h"
 #include "OrthancRestApi.h"
 
-#include "../DicomDirWriter.h"
+#include "../../Core/DicomParsing/DicomDirWriter.h"
 #include "../../Core/FileStorage/StorageAccessor.h"
 #include "../../Core/Compression/HierarchicalZipWriter.h"
 #include "../../Core/HttpServer/FilesystemHttpSender.h"
@@ -625,7 +625,8 @@ namespace Orthanc
       static void Apply(RestApiOutput& output,
                         ServerContext& context,
                         ArchiveIndex& archive,
-                        const std::string& filename)
+                        const std::string& filename,
+                        bool enableExtendedSopClass)
       {
         archive.Expand(context.GetIndex());
 
@@ -643,10 +644,12 @@ namespace Orthanc
           writer.SetZip64(isZip64);
           writer.OpenDirectory("IMAGES");
 
-          // Create the DICOMDIR writer
-          DicomDirWriter dicomDir;
-
+          // Create a DICOMDIR writer
           MediaWriterVisitor v(writer, context);
+
+          // Request type-3 arguments to be added to the DICOMDIR
+          v.dicomDir_.EnableExtendedSopClass(enableExtendedSopClass);
+
           archive.Apply(v);
 
           // Add the DICOMDIR
@@ -723,7 +726,8 @@ namespace Orthanc
       MediaWriterVisitor::Apply(call.GetOutput(),
                                 OrthancRestApi::GetContext(call),
                                 archive,
-                                "Archive.zip");
+                                "Archive.zip",
+                                false);
     }
   }  
 
@@ -758,7 +762,8 @@ namespace Orthanc
     MediaWriterVisitor::Apply(call.GetOutput(),
                               OrthancRestApi::GetContext(call),
                               archive,
-                              id + ".zip");
+                              id + ".zip",
+                              call.HasArgument("extended"));
   }
 
 
diff --git a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp
index ad14b9b..5ec0257 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp
@@ -37,7 +37,7 @@
 #include "../OrthancInitialization.h"
 #include "../../Core/HttpClient.h"
 #include "../../Core/Logging.h"
-#include "../FromDcmtkBridge.h"
+#include "../../Core/DicomParsing/FromDcmtkBridge.h"
 #include "../Scheduler/ServerJob.h"
 #include "../Scheduler/StoreScuCommand.h"
 #include "../Scheduler/StorePeerCommand.h"
diff --git a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp
index 2a49bf7..cbd4f2d 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp
@@ -34,10 +34,11 @@
 #include "../PrecompiledHeadersServer.h"
 #include "OrthancRestApi.h"
 
+#include "../../Core/Compression/GzipCompressor.h"
+#include "../../Core/DicomParsing/FromDcmtkBridge.h"
+#include "../../Core/DicomParsing/Internals/DicomImageDecoder.h"
 #include "../../Core/HttpServer/HttpContentNegociation.h"
 #include "../../Core/Logging.h"
-#include "../FromDcmtkBridge.h"
-#include "../Internals/DicomImageDecoder.h"
 #include "../OrthancInitialization.h"
 #include "../Search/LookupResource.h"
 #include "../ServerContext.h"
@@ -47,6 +48,42 @@
 
 namespace Orthanc
 {
+  static void AnswerDicomAsJson(RestApiCall& call,
+                                const Json::Value& dicom,
+                                bool simplify)
+  {
+    if (simplify)
+    {
+      Json::Value simplified;
+      ServerToolbox::SimplifyTags(simplified, dicom, DicomToJsonFormat_Human);
+      call.GetOutput().AnswerJson(simplified);
+    }
+    else
+    {
+      call.GetOutput().AnswerJson(dicom);
+    }
+  }
+
+
+  static void ParseSetOfTags(std::set<DicomTag>& target,
+                             const RestApiGetCall& call,
+                             const std::string& argument)
+  {
+    target.clear();
+
+    if (call.HasArgument(argument))
+    {
+      std::vector<std::string> tags;
+      Toolbox::TokenizeString(tags, call.GetArgument(argument, ""), ',');
+
+      for (size_t i = 0; i < tags.size(); i++)
+      {
+        target.insert(FromDcmtkBridge::ParseTag(tags[i]));
+      }
+    }
+  }
+
+
   // List all the patients, studies, series or instances ----------------------
  
   static void AnswerListOfResources(RestApiOutput& output,
@@ -205,18 +242,22 @@ namespace Orthanc
     ServerContext& context = OrthancRestApi::GetContext(call);
 
     std::string publicId = call.GetUriComponent("id", "");
+
+    std::set<DicomTag> ignoreTagLength;
+    ParseSetOfTags(ignoreTagLength, call, "ignore-length");
     
-    if (simplify)
+    if (simplify ||
+        !ignoreTagLength.empty())
     {
       Json::Value full;
-      context.ReadDicomAsJson(full, publicId);
-
-      Json::Value simplified;
-      ServerToolbox::SimplifyTags(simplified, full, DicomToJsonFormat_Human);
-      call.GetOutput().AnswerJson(simplified);
+      context.ReadDicomAsJson(full, publicId, ignoreTagLength);
+      AnswerDicomAsJson(call, full, simplify);
     }
     else
     {
+      // This path allows to avoid the JSON decoding if no
+      // simplification is asked, or if no "ignore-length" argument is
+      // present
       std::string full;
       context.ReadDicomAsJson(full, publicId);
       call.GetOutput().AnswerBuffer(full, "application/json");
@@ -497,7 +538,7 @@ namespace Orthanc
   }
 
 
-
+  template <bool GzipCompression>
   static void GetRawFrame(RestApiGetCall& call)
   {
     std::string frameId = call.GetUriComponent("frame", "0");
@@ -520,7 +561,17 @@ namespace Orthanc
       locker.GetDicom().GetRawFrame(raw, mime, frame);
     }
 
-    call.GetOutput().AnswerBuffer(raw, mime);
+    if (GzipCompression)
+    {
+      GzipCompressor gzip;
+      std::string compressed;
+      gzip.Compress(compressed, raw.empty() ? NULL : raw.c_str(), raw.size());
+      call.GetOutput().AnswerBuffer(compressed, "application/gzip");
+    }
+    else
+    {
+      call.GetOutput().AnswerBuffer(raw, mime);
+    }
   }
 
 
@@ -999,16 +1050,7 @@ namespace Orthanc
     if (ExtractSharedTags(sharedTags, context, publicId))
     {
       // Success: Send the value of the shared tags
-      if (simplify)
-      {
-        Json::Value simplified;
-        ServerToolbox::SimplifyTags(simplified, sharedTags, DicomToJsonFormat_Human);
-        call.GetOutput().AnswerJson(simplified);
-      }
-      else
-      {
-        call.GetOutput().AnswerJson(sharedTags);
-      }
+      AnswerDicomAsJson(call, sharedTags, simplify);
     }
   }
 
@@ -1031,6 +1073,9 @@ namespace Orthanc
     std::string publicId = call.GetUriComponent("id", "");
     bool simplify = call.HasArgument("simplify");
 
+    std::set<DicomTag> ignoreTagLength;
+    ParseSetOfTags(ignoreTagLength, call, "ignore-length");
+
     typedef std::set<DicomTag> ModuleTags;
     ModuleTags moduleTags;
     DicomTag::AddTagsForModule(moduleTags, module);
@@ -1053,7 +1098,7 @@ namespace Orthanc
       publicId = instances.front();
     }
 
-    context.ReadDicomAsJson(tags, publicId);
+    context.ReadDicomAsJson(tags, publicId, ignoreTagLength);
     
     // Filter the tags of the instance according to the module
     Json::Value result = Json::objectValue;
@@ -1066,16 +1111,7 @@ namespace Orthanc
       }      
     }
 
-    if (simplify)
-    {
-      Json::Value simplified;
-      ServerToolbox::SimplifyTags(simplified, result, DicomToJsonFormat_Human);
-      call.GetOutput().AnswerJson(simplified);
-    }
-    else
-    {
-      call.GetOutput().AnswerJson(result);
-    }    
+    AnswerDicomAsJson(call, result, simplify);
   }
     
 
@@ -1272,6 +1308,9 @@ namespace Orthanc
     std::string publicId = call.GetUriComponent("id", "");
     bool simplify = call.HasArgument("simplify");
 
+    std::set<DicomTag> ignoreTagLength;
+    ParseSetOfTags(ignoreTagLength, call, "ignore-length");
+
     // Retrieve all the instances of this patient/study/series
     typedef std::list<std::string> Instances;
     Instances instances;
@@ -1284,7 +1323,7 @@ namespace Orthanc
          it != instances.end(); ++it)
     {
       Json::Value full;
-      context.ReadDicomAsJson(full, *it);
+      context.ReadDicomAsJson(full, *it, ignoreTagLength);
 
       if (simplify)
       {
@@ -1383,16 +1422,7 @@ namespace Orthanc
     Json::Value header;
     dicom.HeaderToJson(header, DicomToJsonFormat_Full);
 
-    if (simplify)
-    {
-      Json::Value simplified;
-      ServerToolbox::SimplifyTags(simplified, header, DicomToJsonFormat_Human);
-      call.GetOutput().AnswerJson(simplified);
-    }
-    else
-    {
-      call.GetOutput().AnswerJson(header);
-    }
+    AnswerDicomAsJson(call, header, simplify);
   }
 
 
@@ -1473,7 +1503,8 @@ namespace Orthanc
     Register("/instances/{id}/frames/{frame}/image-uint16", GetImage<ImageExtractionMode_UInt16>);
     Register("/instances/{id}/frames/{frame}/image-int16", GetImage<ImageExtractionMode_Int16>);
     Register("/instances/{id}/frames/{frame}/matlab", GetMatlabImage);
-    Register("/instances/{id}/frames/{frame}/raw", GetRawFrame);
+    Register("/instances/{id}/frames/{frame}/raw", GetRawFrame<false>);
+    Register("/instances/{id}/frames/{frame}/raw.gz", GetRawFrame<true>);
     Register("/instances/{id}/pdf", ExtractPdf);
     Register("/instances/{id}/preview", GetImage<ImageExtractionMode_Preview>);
     Register("/instances/{id}/image-uint8", GetImage<ImageExtractionMode_UInt8>);
diff --git a/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp b/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp
index 69de4d1..bf725eb 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp
@@ -35,7 +35,7 @@
 #include "OrthancRestApi.h"
 
 #include "../OrthancInitialization.h"
-#include "../FromDcmtkBridge.h"
+#include "../../Core/DicomParsing/FromDcmtkBridge.h"
 #include "../../Plugins/Engine/PluginsManager.h"
 #include "../../Plugins/Engine/OrthancPlugins.h"
 #include "../ServerContext.h"
@@ -251,7 +251,7 @@ namespace Orthanc
 
   static void GetDefaultEncoding(RestApiGetCall& call)
   {
-    Encoding encoding = Configuration::GetDefaultEncoding();
+    Encoding encoding = GetDefaultDicomEncoding();
     call.GetOutput().AnswerBuffer(EnumerationToString(encoding), "text/plain");
   }
 
diff --git a/OrthancServer/PrecompiledHeadersServer.h b/OrthancServer/PrecompiledHeadersServer.h
index 84f7329..a85bcbb 100644
--- a/OrthancServer/PrecompiledHeadersServer.h
+++ b/OrthancServer/PrecompiledHeadersServer.h
@@ -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
diff --git a/OrthancServer/QueryRetrieveHandler.cpp b/OrthancServer/QueryRetrieveHandler.cpp
index ef036b9..da92fb2 100644
--- a/OrthancServer/QueryRetrieveHandler.cpp
+++ b/OrthancServer/QueryRetrieveHandler.cpp
@@ -35,7 +35,7 @@
 #include "QueryRetrieveHandler.h"
 
 #include "OrthancInitialization.h"
-#include "FromDcmtkBridge.h"
+#include "../Core/DicomParsing/FromDcmtkBridge.h"
 
 
 namespace Orthanc
diff --git a/OrthancServer/Scheduler/ModifyInstanceCommand.h b/OrthancServer/Scheduler/ModifyInstanceCommand.h
index 1553667..062457b 100644
--- a/OrthancServer/Scheduler/ModifyInstanceCommand.h
+++ b/OrthancServer/Scheduler/ModifyInstanceCommand.h
@@ -35,7 +35,7 @@
 
 #include "IServerCommand.h"
 #include "../ServerContext.h"
-#include "../DicomModification.h"
+#include "../../Core/DicomParsing/DicomModification.h"
 
 namespace Orthanc
 {
diff --git a/OrthancServer/Search/HierarchicalMatcher.cpp b/OrthancServer/Search/HierarchicalMatcher.cpp
index caf5131..ddb8e52 100644
--- a/OrthancServer/Search/HierarchicalMatcher.cpp
+++ b/OrthancServer/Search/HierarchicalMatcher.cpp
@@ -36,8 +36,8 @@
 
 #include "../../Core/Logging.h"
 #include "../../Core/OrthancException.h"
-#include "../FromDcmtkBridge.h"
-#include "../ToDcmtkBridge.h"
+#include "../../Core/DicomParsing/FromDcmtkBridge.h"
+#include "../../Core/DicomParsing/ToDcmtkBridge.h"
 #include "../OrthancInitialization.h"
 
 #include <dcmtk/dcmdata/dcfilefo.h>
@@ -122,9 +122,10 @@ namespace Orthanc
       }
       else
       {
+        std::set<DicomTag> ignoreTagLength;
         std::auto_ptr<DicomValue> value(FromDcmtkBridge::ConvertLeafElement
                                         (*element, DicomToJsonFlags_None, 
-                                         ORTHANC_MAXIMUM_TAG_LENGTH, encoding));
+                                         ORTHANC_MAXIMUM_TAG_LENGTH, encoding, ignoreTagLength));
 
         if (value->IsBinary())
         {
@@ -222,9 +223,10 @@ namespace Orthanc
           return false;
         }
 
+        std::set<DicomTag> ignoreTagLength;
         std::auto_ptr<DicomValue> value(FromDcmtkBridge::ConvertLeafElement
                                         (*element, DicomToJsonFlags_None, 
-                                         ORTHANC_MAXIMUM_TAG_LENGTH, encoding));
+                                         ORTHANC_MAXIMUM_TAG_LENGTH, encoding, ignoreTagLength));
 
         if (value->IsNull() ||
             value->IsBinary() ||
diff --git a/OrthancServer/Search/HierarchicalMatcher.h b/OrthancServer/Search/HierarchicalMatcher.h
index d01859c..b8cee7c 100644
--- a/OrthancServer/Search/HierarchicalMatcher.h
+++ b/OrthancServer/Search/HierarchicalMatcher.h
@@ -33,9 +33,8 @@
 
 #pragma once
 
-#include "../../Core/DicomFormat/DicomMap.h"
 #include "IFindConstraint.h"
-#include "../ParsedDicomFile.h"
+#include "../../Core/DicomParsing/ParsedDicomFile.h"
 
 class DcmItem;
 
diff --git a/OrthancServer/Search/IFindConstraint.cpp b/OrthancServer/Search/IFindConstraint.cpp
index 6f522ed..5e6149f 100644
--- a/OrthancServer/Search/IFindConstraint.cpp
+++ b/OrthancServer/Search/IFindConstraint.cpp
@@ -39,7 +39,7 @@
 #include "ValueConstraint.h"
 #include "WildcardConstraint.h"
 
-#include "../FromDcmtkBridge.h"
+#include "../../Core/DicomParsing/FromDcmtkBridge.h"
 #include "../../Core/OrthancException.h"
 
 namespace Orthanc
diff --git a/OrthancServer/Search/LookupIdentifierQuery.cpp b/OrthancServer/Search/LookupIdentifierQuery.cpp
index abe40c3..b0da867 100644
--- a/OrthancServer/Search/LookupIdentifierQuery.cpp
+++ b/OrthancServer/Search/LookupIdentifierQuery.cpp
@@ -36,7 +36,7 @@
 
 #include "../../Core/OrthancException.h"
 #include "SetOfResources.h"
-#include "../FromDcmtkBridge.h"
+#include "../../Core/DicomParsing/FromDcmtkBridge.h"
 
 #include <cassert>
 
diff --git a/OrthancServer/Search/LookupResource.cpp b/OrthancServer/Search/LookupResource.cpp
index 35d7b67..38ba557 100644
--- a/OrthancServer/Search/LookupResource.cpp
+++ b/OrthancServer/Search/LookupResource.cpp
@@ -37,7 +37,7 @@
 #include "../../Core/OrthancException.h"
 #include "../../Core/FileStorage/StorageAccessor.h"
 #include "../ServerToolbox.h"
-#include "../FromDcmtkBridge.h"
+#include "../../Core/DicomParsing/FromDcmtkBridge.h"
 
 
 namespace Orthanc
diff --git a/OrthancServer/ServerContext.cpp b/OrthancServer/ServerContext.cpp
index b63c1ed..1acfd2d 100644
--- a/OrthancServer/ServerContext.cpp
+++ b/OrthancServer/ServerContext.cpp
@@ -38,7 +38,7 @@
 #include "../Core/HttpServer/FilesystemHttpSender.h"
 #include "../Core/HttpServer/HttpStreamTranscoder.h"
 #include "../Core/Logging.h"
-#include "FromDcmtkBridge.h"
+#include "../Core/DicomParsing/FromDcmtkBridge.h"
 #include "ServerToolbox.h"
 #include "OrthancInitialization.h"
 
@@ -314,7 +314,7 @@ namespace Orthanc
     {
       if (e.GetErrorCode() == ErrorCode_InexistentTag)
       {
-        ServerToolbox::LogMissingRequiredTag(dicom.GetSummary());
+        dicom.GetSummary().LogMissingTagsForStore();
       }
 
       throw;
@@ -383,48 +383,82 @@ namespace Orthanc
   }
 
 
-  void ServerContext::ReadDicomAsJson(std::string& result,
-                                      const std::string& instancePublicId)
+  void ServerContext::ReadDicomAsJsonInternal(std::string& result,
+                                              const std::string& instancePublicId)
   {
     FileInfo attachment;
     if (index_.LookupAttachment(attachment, instancePublicId, FileContentType_DicomAsJson))
     {
       ReadAttachment(result, attachment);
-      return;
     }
+    else
+    {
+      // The "DICOM as JSON" summary is not available from the Orthanc
+      // store (most probably deleted), reconstruct it from the DICOM file
+      std::string dicom;
+      ReadDicom(dicom, instancePublicId);
 
-    // The "DICOM as JSON" summary is not available from the Orthanc
-    // store (most probably deleted), reconstruct it from the DICOM file
-    std::string dicom;
-    ReadDicom(dicom, instancePublicId);
-
-    LOG(INFO) << "Reconstructing the missing DICOM-as-JSON summary for instance: " << instancePublicId;
+      LOG(INFO) << "Reconstructing the missing DICOM-as-JSON summary for instance: "
+                << instancePublicId;
     
-    ParsedDicomFile parsed(dicom);
+      ParsedDicomFile parsed(dicom);
+
+      Json::Value summary;
+      parsed.DatasetToJson(summary);
 
-    Json::Value summary;
-    parsed.DatasetToJson(summary);
+      result = summary.toStyledString();
+
+      if (!AddAttachment(instancePublicId, FileContentType_DicomAsJson,
+                         result.c_str(), result.size()))
+      {
+        LOG(WARNING) << "Cannot associate the DICOM-as-JSON summary to instance: " << instancePublicId;
+        throw OrthancException(ErrorCode_InternalError);
+      }
+    }
+  }
 
-    result = summary.toStyledString();
 
-    if (!AddAttachment(instancePublicId, FileContentType_DicomAsJson, result.c_str(), result.size()))
+  void ServerContext::ReadDicomAsJson(std::string& result,
+                                      const std::string& instancePublicId,
+                                      const std::set<DicomTag>& ignoreTagLength)
+  {
+    if (ignoreTagLength.empty())
     {
-      LOG(WARNING) << "Cannot associate the DICOM-as-JSON summary to instance: " << instancePublicId;
-      throw OrthancException(ErrorCode_InternalError);
+      ReadDicomAsJsonInternal(result, instancePublicId);
+    }
+    else
+    {
+      Json::Value tmp;
+      ReadDicomAsJson(tmp, instancePublicId, ignoreTagLength);
+      result = tmp.toStyledString();
     }
   }
 
 
   void ServerContext::ReadDicomAsJson(Json::Value& result,
-                                      const std::string& instancePublicId)
+                                      const std::string& instancePublicId,
+                                      const std::set<DicomTag>& ignoreTagLength)
   {
-    std::string tmp;
-    ReadDicomAsJson(tmp, instancePublicId);
+    if (ignoreTagLength.empty())
+    {
+      std::string tmp;
+      ReadDicomAsJsonInternal(tmp, instancePublicId);
 
-    Json::Reader reader;
-    if (!reader.parse(tmp, result))
+      Json::Reader reader;
+      if (!reader.parse(tmp, result))
+      {
+        throw OrthancException(ErrorCode_CorruptedFile);
+      }
+    }
+    else
     {
-      throw OrthancException(ErrorCode_CorruptedFile);
+      // The "DicomAsJson" attachment might have stored some tags as
+      // "too long". We are forced to re-parse the DICOM file.
+      std::string dicom;
+      ReadDicom(dicom, instancePublicId);
+
+      ParsedDicomFile parsed(dicom);
+      parsed.DatasetToJson(result, ignoreTagLength);
     }
   }
 
diff --git a/OrthancServer/ServerContext.h b/OrthancServer/ServerContext.h
index 72348db..c3f6c39 100644
--- a/OrthancServer/ServerContext.h
+++ b/OrthancServer/ServerContext.h
@@ -41,10 +41,10 @@
 #include "../Core/RestApi/RestApiOutput.h"
 #include "../Plugins/Engine/OrthancPlugins.h"
 #include "DicomInstanceToStore.h"
-#include "DicomProtocol/ReusableDicomUserConnection.h"
+#include "../Core/DicomNetworking/ReusableDicomUserConnection.h"
 #include "IServerListener.h"
 #include "LuaScripting.h"
-#include "ParsedDicomFile.h"
+#include "../Core/DicomParsing/ParsedDicomFile.h"
 #include "Scheduler/ServerScheduler.h"
 #include "ServerIndex.h"
 #include "OrthancHttpHandler.h"
@@ -106,6 +106,8 @@ namespace Orthanc
 
     static void ChangeThread(ServerContext* that);
 
+    void ReadDicomAsJsonInternal(std::string& result,
+                                 const std::string& instancePublicId);
 
     ServerIndex index_;
     IStorageArea& area_;
@@ -193,10 +195,26 @@ namespace Orthanc
                                      CompressionType compression);
 
     void ReadDicomAsJson(std::string& result,
-                         const std::string& instancePublicId);
+                         const std::string& instancePublicId,
+                         const std::set<DicomTag>& ignoreTagLength);
 
     void ReadDicomAsJson(Json::Value& result,
-                         const std::string& instancePublicId);
+                         const std::string& instancePublicId,
+                         const std::set<DicomTag>& ignoreTagLength);
+
+    void ReadDicomAsJson(std::string& result,
+                         const std::string& instancePublicId)
+    {
+      std::set<DicomTag> ignoreTagLength;
+      ReadDicomAsJson(result, instancePublicId, ignoreTagLength);
+    }
+
+    void ReadDicomAsJson(Json::Value& result,
+                         const std::string& instancePublicId)
+    {
+      std::set<DicomTag> ignoreTagLength;
+      ReadDicomAsJson(result, instancePublicId, ignoreTagLength);
+    }
 
     void ReadDicom(std::string& dicom,
                    const std::string& instancePublicId)
diff --git a/OrthancServer/ServerEnumerations.cpp b/OrthancServer/ServerEnumerations.cpp
index b8e9746..c709288 100644
--- a/OrthancServer/ServerEnumerations.cpp
+++ b/OrthancServer/ServerEnumerations.cpp
@@ -317,197 +317,6 @@ namespace Orthanc
     }
   }
 
-
-  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)
   {
diff --git a/OrthancServer/ServerEnumerations.h b/OrthancServer/ServerEnumerations.h
index 1c6f074..977b2f5 100644
--- a/OrthancServer/ServerEnumerations.h
+++ b/OrthancServer/ServerEnumerations.h
@@ -56,75 +56,6 @@ namespace Orthanc
     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,
@@ -133,12 +64,6 @@ namespace Orthanc
     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
@@ -228,17 +153,5 @@ namespace Orthanc
 
   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);
 }
diff --git a/OrthancServer/ServerIndex.cpp b/OrthancServer/ServerIndex.cpp
index a5ad4e5..aa5d2a5 100644
--- a/OrthancServer/ServerIndex.cpp
+++ b/OrthancServer/ServerIndex.cpp
@@ -41,13 +41,13 @@
 #include "ServerIndexChange.h"
 #include "EmbeddedResources.h"
 #include "OrthancInitialization.h"
-#include "ParsedDicomFile.h"
+#include "../Core/DicomParsing/ParsedDicomFile.h"
 #include "ServerToolbox.h"
 #include "../Core/Toolbox.h"
 #include "../Core/Logging.h"
 #include "../Core/DicomFormat/DicomArray.h"
 
-#include "FromDcmtkBridge.h"
+#include "../Core/DicomParsing/FromDcmtkBridge.h"
 #include "ServerContext.h"
 #include "DicomInstanceToStore.h"
 #include "Search/LookupResource.h"
diff --git a/OrthancServer/ServerToolbox.cpp b/OrthancServer/ServerToolbox.cpp
index 812cbcf..50f52cb 100644
--- a/OrthancServer/ServerToolbox.cpp
+++ b/OrthancServer/ServerToolbox.cpp
@@ -135,88 +135,6 @@ namespace Orthanc
     }
 
 
-    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 LogMissingRequiredTag(const DicomMap& summary)
-    {
-      std::string s, t;
-
-      if (summary.HasTag(DICOM_TAG_PATIENT_ID))
-      {
-        if (t.size() > 0)
-          t += ", ";
-        t += "PatientID=" + ValueAsString(summary, DICOM_TAG_PATIENT_ID);
-      }
-      else
-      {
-        if (s.size() > 0)
-          s += ", ";
-        s += "PatientID";
-      }
-
-      if (summary.HasTag(DICOM_TAG_STUDY_INSTANCE_UID))
-      {
-        if (t.size() > 0)
-          t += ", ";
-        t += "StudyInstanceUID=" + ValueAsString(summary, DICOM_TAG_STUDY_INSTANCE_UID);
-      }
-      else
-      {
-        if (s.size() > 0)
-          s += ", ";
-        s += "StudyInstanceUID";
-      }
-
-      if (summary.HasTag(DICOM_TAG_SERIES_INSTANCE_UID))
-      {
-        if (t.size() > 0)
-          t += ", ";
-        t += "SeriesInstanceUID=" + ValueAsString(summary, DICOM_TAG_SERIES_INSTANCE_UID);
-      }
-      else
-      {
-        if (s.size() > 0)
-          s += ", ";
-        s += "SeriesInstanceUID";
-      }
-
-      if (summary.HasTag(DICOM_TAG_SOP_INSTANCE_UID))
-      {
-        if (t.size() > 0)
-          t += ", ";
-        t += "SOPInstanceUID=" + ValueAsString(summary, 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;
-      }
-    }
-
-
     static void StoreMainDicomTagsInternal(IDatabaseWrapper& database,
                                            int64_t resource,
                                            const DicomMap& tags)
@@ -513,7 +431,7 @@ namespace Orthanc
         ServerContext::DicomCacheLocker locker(context, *it);
 
         Json::Value dicomAsJson;
-        locker.GetDicom().ExtractDicomAsJson(dicomAsJson);
+        locker.GetDicom().DatasetToJson(dicomAsJson);
 
         std::string s = dicomAsJson.toStyledString();
         context.AddAttachment(*it, FileContentType_DicomAsJson, s.c_str(), s.size());
diff --git a/OrthancServer/ServerToolbox.h b/OrthancServer/ServerToolbox.h
index dfdf20e..adca9d9 100644
--- a/OrthancServer/ServerToolbox.h
+++ b/OrthancServer/ServerToolbox.h
@@ -45,8 +45,6 @@ namespace Orthanc
                       const Json::Value& source,
                       DicomToJsonFormat format);
 
-    void LogMissingRequiredTag(const DicomMap& summary);
-
     void StoreMainDicomTags(IDatabaseWrapper& database,
                             int64_t resource,
                             ResourceType level,
diff --git a/OrthancServer/main.cpp b/OrthancServer/main.cpp
index 67ecdc0..99ebbba 100644
--- a/OrthancServer/main.cpp
+++ b/OrthancServer/main.cpp
@@ -41,15 +41,15 @@
 #include "../Core/HttpServer/FilesystemHttpHandler.h"
 #include "../Core/Lua/LuaFunctionCall.h"
 #include "../Core/DicomFormat/DicomArray.h"
-#include "DicomProtocol/DicomServer.h"
-#include "DicomProtocol/ReusableDicomUserConnection.h"
+#include "../Core/DicomNetworking/DicomServer.h"
+#include "../Core/DicomNetworking/ReusableDicomUserConnection.h"
 #include "OrthancInitialization.h"
 #include "ServerContext.h"
 #include "OrthancFindRequestHandler.h"
 #include "OrthancMoveRequestHandler.h"
 #include "ServerToolbox.h"
 #include "../Plugins/Engine/OrthancPlugins.h"
-#include "FromDcmtkBridge.h"
+#include "../Core/DicomParsing/FromDcmtkBridge.h"
 
 using namespace Orthanc;
 
@@ -89,6 +89,23 @@ public:
 
 
 
+class ModalitiesFromConfiguration : public Orthanc::DicomServer::IRemoteModalities
+{
+public:
+  virtual bool IsSameAETitle(const std::string& aet1,
+                             const std::string& aet2) 
+  {
+    return Orthanc::Configuration::IsSameAETitle(aet1, aet2);
+  }
+
+  virtual bool LookupAETitle(RemoteModalityParameters& modality,
+                             const std::string& aet) 
+  {
+    return Orthanc::Configuration::LookupDicomModalityUsingAETitle(modality, aet);
+  }
+};
+
+
 class MyDicomServerFactory : 
   public IStoreRequestHandlerFactory,
   public IFindRequestHandlerFactory, 
@@ -152,12 +169,14 @@ class OrthancApplicationEntityFilter : public IApplicationEntityFilter
 {
 private:
   ServerContext& context_;
+  bool           alwaysAllowEcho_;
   bool           alwaysAllowStore_;
 
 public:
   OrthancApplicationEntityFilter(ServerContext& context) :
     context_(context)
   {
+    alwaysAllowEcho_ = Configuration::GetGlobalBoolParameter("DicomAlwaysAllowEcho", true);
     alwaysAllowStore_ = Configuration::GetGlobalBoolParameter("DicomAlwaysAllowStore", true);
   }
 
@@ -168,7 +187,8 @@ public:
     LOG(INFO) << "Incoming connection from AET " << remoteAet
               << " on IP " << remoteIp << ", calling AET " << calledAet;
 
-    return (alwaysAllowStore_ ||
+    return (alwaysAllowEcho_ ||
+            alwaysAllowStore_ ||
             Configuration::IsKnownAETitle(remoteAet, remoteIp));
   }
 
@@ -180,10 +200,16 @@ public:
     LOG(INFO) << "Incoming " << Orthanc::EnumerationToString(type) << " request from AET "
               << remoteAet << " on IP " << remoteIp << ", calling AET " << calledAet;
     
-    if (type == DicomRequestType_Store &&
-        alwaysAllowStore_)
+    if (type == DicomRequestType_Echo &&
+        alwaysAllowEcho_)
+    {
+      // Incoming C-Echo requests are always accepted, even from unknown AET
+      return true;
+    }
+    else if (type == DicomRequestType_Store &&
+             alwaysAllowStore_)
     {
-      // Incoming store requests are always accepted, even from unknown AET
+      // Incoming C-Store requests are always accepted, even from unknown AET
       return true;
     }
     else if (!Configuration::IsKnownAETitle(remoteAet, remoteIp))
@@ -788,10 +814,12 @@ static bool StartDicomServer(ServerContext& context,
   }
 
   MyDicomServerFactory serverFactory(context);
-
-  // DICOM server
-  DicomServer dicomServer;
   OrthancApplicationEntityFilter dicomFilter(context);
+  ModalitiesFromConfiguration modalities;
+  
+  // Setup the DICOM server  
+  DicomServer dicomServer;
+  dicomServer.SetRemoteModalities(modalities);
   dicomServer.SetCalledApplicationEntityTitleCheck(Configuration::GetGlobalBoolParameter("DicomCheckCalledAet", false));
   dicomServer.SetStoreRequestHandlerFactory(serverFactory);
   dicomServer.SetMoveRequestHandlerFactory(serverFactory);
diff --git a/Plugins/Engine/OrthancPlugins.cpp b/Plugins/Engine/OrthancPlugins.cpp
index da07351..99ac7bf 100644
--- a/Plugins/Engine/OrthancPlugins.cpp
+++ b/Plugins/Engine/OrthancPlugins.cpp
@@ -45,13 +45,13 @@
 #include "../../Core/Logging.h"
 #include "../../Core/OrthancException.h"
 #include "../../Core/Toolbox.h"
-#include "../../OrthancServer/FromDcmtkBridge.h"
-#include "../../OrthancServer/ToDcmtkBridge.h"
+#include "../../Core/DicomParsing/FromDcmtkBridge.h"
+#include "../../Core/DicomParsing/ToDcmtkBridge.h"
 #include "../../OrthancServer/OrthancInitialization.h"
 #include "../../OrthancServer/ServerContext.h"
 #include "../../OrthancServer/ServerToolbox.h"
 #include "../../OrthancServer/Search/HierarchicalMatcher.h"
-#include "../../OrthancServer/Internals/DicomImageDecoder.h"
+#include "../../Core/DicomParsing/Internals/DicomImageDecoder.h"
 #include "../../Core/Compression/ZlibCompressor.h"
 #include "../../Core/Compression/GzipCompressor.h"
 #include "../../Core/Images/Image.h"
diff --git a/Plugins/Engine/OrthancPlugins.h b/Plugins/Engine/OrthancPlugins.h
index a8e8dff..7bf2820 100644
--- a/Plugins/Engine/OrthancPlugins.h
+++ b/Plugins/Engine/OrthancPlugins.h
@@ -53,14 +53,14 @@ namespace Orthanc
 
 #else
 
+#include "../../Core/DicomNetworking/IFindRequestHandlerFactory.h"
+#include "../../Core/DicomNetworking/IMoveRequestHandlerFactory.h"
+#include "../../Core/DicomNetworking/IWorklistRequestHandlerFactory.h"
 #include "../../Core/FileStorage/IStorageArea.h"
 #include "../../Core/HttpServer/IHttpHandler.h"
 #include "../../Core/HttpServer/IIncomingHttpRequestFilter.h"
-#include "../../OrthancServer/IServerListener.h"
 #include "../../OrthancServer/IDicomImageDecoder.h"
-#include "../../OrthancServer/DicomProtocol/IWorklistRequestHandlerFactory.h"
-#include "../../OrthancServer/DicomProtocol/IFindRequestHandlerFactory.h"
-#include "../../OrthancServer/DicomProtocol/IMoveRequestHandlerFactory.h"
+#include "../../OrthancServer/IServerListener.h"
 #include "OrthancPluginDatabase.h"
 #include "PluginsManager.h"
 
diff --git a/Plugins/Engine/PluginsEnumerations.cpp b/Plugins/Engine/PluginsEnumerations.cpp
index 53f587e..86c2caf 100644
--- a/Plugins/Engine/PluginsEnumerations.cpp
+++ b/Plugins/Engine/PluginsEnumerations.cpp
@@ -139,15 +139,27 @@ namespace Orthanc
     {
       switch (format)
       {
+        case PixelFormat_BGRA32:
+          return OrthancPluginPixelFormat_BGRA32;
+
+        case PixelFormat_Float32:
+          return OrthancPluginPixelFormat_Float32;
+
         case PixelFormat_Grayscale16:
           return OrthancPluginPixelFormat_Grayscale16;
 
+        case PixelFormat_Grayscale32:
+          return OrthancPluginPixelFormat_Grayscale32;
+
         case PixelFormat_Grayscale8:
           return OrthancPluginPixelFormat_Grayscale8;
 
         case PixelFormat_RGB24:
           return OrthancPluginPixelFormat_RGB24;
 
+        case PixelFormat_RGB48:
+          return OrthancPluginPixelFormat_RGB48;
+
         case PixelFormat_RGBA32:
           return OrthancPluginPixelFormat_RGBA32;
 
@@ -164,15 +176,27 @@ namespace Orthanc
     {
       switch (format)
       {
+        case OrthancPluginPixelFormat_BGRA32:
+          return PixelFormat_BGRA32;
+
+        case OrthancPluginPixelFormat_Float32:
+          return PixelFormat_Float32;
+
         case OrthancPluginPixelFormat_Grayscale16:
           return PixelFormat_Grayscale16;
 
+        case OrthancPluginPixelFormat_Grayscale32:
+          return PixelFormat_Grayscale32;
+
         case OrthancPluginPixelFormat_Grayscale8:
           return PixelFormat_Grayscale8;
 
         case OrthancPluginPixelFormat_RGB24:
           return PixelFormat_RGB24;
 
+        case OrthancPluginPixelFormat_RGB48:
+          return PixelFormat_RGB48;
+
         case OrthancPluginPixelFormat_RGBA32:
           return PixelFormat_RGBA32;
 
diff --git a/Plugins/Engine/PluginsManager.cpp b/Plugins/Engine/PluginsManager.cpp
index 776c58a..0f0219d 100644
--- a/Plugins/Engine/PluginsManager.cpp
+++ b/Plugins/Engine/PluginsManager.cpp
@@ -49,7 +49,7 @@
 
 #ifdef WIN32
 #define PLUGIN_EXTENSION ".dll"
-#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__)
 #define PLUGIN_EXTENSION ".so"
 #elif defined(__APPLE__) && defined(__MACH__)
 #define PLUGIN_EXTENSION ".dylib"
diff --git a/Plugins/Engine/SharedLibrary.cpp b/Plugins/Engine/SharedLibrary.cpp
index 97e231d..74c0508 100644
--- a/Plugins/Engine/SharedLibrary.cpp
+++ b/Plugins/Engine/SharedLibrary.cpp
@@ -46,7 +46,7 @@
 
 #if defined(_WIN32)
 #include <windows.h>
-#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__)
 #include <dlfcn.h>
 #else
 #error Support your platform here
@@ -66,7 +66,7 @@ namespace Orthanc
       throw OrthancException(ErrorCode_SharedLibrary);
     }
 
-#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__)
     handle_ = ::dlopen(path_.c_str(), RTLD_NOW);
     if (handle_ == NULL) 
     {
@@ -92,7 +92,7 @@ namespace Orthanc
     {
 #if defined(_WIN32)
       ::FreeLibrary((HMODULE)handle_);
-#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__)
       ::dlclose(handle_);
 #else
 #error Support your platform here
@@ -110,7 +110,7 @@ namespace Orthanc
 
 #if defined(_WIN32)
     return ::GetProcAddress((HMODULE)handle_, name.c_str());
-#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__)
     return ::dlsym(handle_, name.c_str());
 #else
 #error Support your platform here
diff --git a/Plugins/Include/orthanc/OrthancCPlugin.h b/Plugins/Include/orthanc/OrthancCPlugin.h
index f278a36..542f223 100644
--- a/Plugins/Include/orthanc/OrthancCPlugin.h
+++ b/Plugins/Include/orthanc/OrthancCPlugin.h
@@ -118,7 +118,17 @@
 
 #define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER     1
 #define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER     3
-#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  0
+#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  1
+
+
+#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
 
 
 
@@ -570,6 +580,38 @@ extern "C"
 
     OrthancPluginPixelFormat_Unknown = 6,   /*!< Unknown pixel format */
 
+    /**
+     * @brief Color image in RGB48 format.
+     *
+     * This format describes a color image. The pixels are stored in 6
+     * consecutive bytes. The memory layout is RRGGBB.
+     **/
+    OrthancPluginPixelFormat_RGB48 = 7,
+
+    /**
+     * @brief Graylevel, unsigned 32bpp image.
+     *
+     * The image is graylevel. Each pixel is unsigned and stored in
+     * four bytes.
+     **/
+    OrthancPluginPixelFormat_Grayscale32 = 8,
+
+    /**
+     * @brief Graylevel, floating-point 32bpp image.
+     *
+     * The image is graylevel. Each pixel is floating-point and stored
+     * in four bytes.
+     **/
+    OrthancPluginPixelFormat_Float32 = 9,
+
+    /**
+     * @brief Color image in BGRA32 format.
+     *
+     * This format describes a color image. The pixels are stored in 4
+     * consecutive bytes. The memory layout is BGRA.
+     **/
+    OrthancPluginPixelFormat_BGRA32 = 10,
+
     _OrthancPluginPixelFormat_INTERNAL = 0x7fffffff
   } OrthancPluginPixelFormat;
 
diff --git a/Plugins/Samples/Common/DicomTag.h b/Plugins/Samples/Common/DicomTag.h
index 51e5901..61f63f6 100644
--- a/Plugins/Samples/Common/DicomTag.h
+++ b/Plugins/Samples/Common/DicomTag.h
@@ -94,8 +94,10 @@ namespace OrthancPlugins
   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);
diff --git a/Plugins/Samples/Common/OrthancPluginCppWrapper.h b/Plugins/Samples/Common/OrthancPluginCppWrapper.h
index 4f8c1df..05838ad 100644
--- a/Plugins/Samples/Common/OrthancPluginCppWrapper.h
+++ b/Plugins/Samples/Common/OrthancPluginCppWrapper.h
@@ -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
diff --git a/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp b/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp
index 9ebb67b..976ebd7 100644
--- a/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp
+++ b/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.cpp
@@ -199,6 +199,13 @@ namespace OrthancPlugins
         case gdcm::PixelFormat::UINT8:
           return OrthancPluginPixelFormat_RGB24;
 
+        case gdcm::PixelFormat::UINT16:
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 3, 1)
+          return OrthancPluginPixelFormat_RGB48;
+#else
+          throw std::runtime_error("RGB48 pixel format is only supported if compiled against Orthanc SDK >= 1.3.1");
+#endif
+          
         default:
           break;
       }      
@@ -240,6 +247,11 @@ namespace OrthancPlugins
       case OrthancPluginPixelFormat_RGB24:
         return 3;
 
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 3, 1)
+      case OrthancPluginPixelFormat_RGB48:
+        return 6;
+#endif
+
       default:
         throw std::runtime_error("Unsupport pixel format");
     }
diff --git a/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.h b/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.h
index ee80750..c7378ca 100644
--- a/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.h
+++ b/Plugins/Samples/GdcmDecoder/GdcmImageDecoder.h
@@ -26,6 +26,18 @@
 #include <boost/noncopyable.hpp>
 #include <boost/shared_ptr.hpp>
 
+
+// This is for compatibility with Orthanc SDK <= 1.3.0
+#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
+
+
 namespace OrthancPlugins
 {
   class GdcmImageDecoder : public boost::noncopyable
diff --git a/Plugins/Samples/ServeFolders/Plugin.cpp b/Plugins/Samples/ServeFolders/Plugin.cpp
index 8a444f2..ab323fa 100644
--- a/Plugins/Samples/ServeFolders/Plugin.cpp
+++ b/Plugins/Samples/ServeFolders/Plugin.cpp
@@ -67,6 +67,7 @@ static void RegisterDefaultExtensions()
   extensions_["pexe"] = "application/x-pnacl";
   extensions_["png"]  = "image/png";
   extensions_["svg"]  = "image/svg+xml";
+  extensions_["wasm"] = "application/wasm";
   extensions_["woff"] = "application/x-font-woff";
   extensions_["xml"]  = "application/xml";
 }
diff --git a/Resources/CMake/BoostConfiguration.cmake b/Resources/CMake/BoostConfiguration.cmake
index 59728b5..66ccfa8 100644
--- a/Resources/CMake/BoostConfiguration.cmake
+++ b/Resources/CMake/BoostConfiguration.cmake
@@ -7,8 +7,12 @@ else()
   #set(Boost_DEBUG 1)
   #set(Boost_USE_STATIC_LIBS ON)
 
+  if (ENABLE_LOCALE)
+    list(APPEND ORTHANC_BOOST_COMPONENTS locale)
+  endif()
+
   find_package(Boost
-    COMPONENTS filesystem thread system date_time regex locale ${ORTHANC_BOOST_COMPONENTS})
+    COMPONENTS filesystem thread system date_time regex ${ORTHANC_BOOST_COMPONENTS})
 
   if (NOT Boost_FOUND)
     message(FATAL_ERROR "Unable to locate Boost on this system")
@@ -27,112 +31,120 @@ else()
       )
   endif()
 
-  #if (${Boost_VERSION} LESS 104800)
-  # boost::locale is only available from 1.48.00
-  #message("Too old version of Boost (${Boost_LIB_VERSION}): Building the static version")
-  #  set(BOOST_STATIC 1)
-  #endif()
-
   include_directories(${Boost_INCLUDE_DIRS})
   link_libraries(${Boost_LIBRARIES})
 endif()
 
 
 if (BOOST_STATIC)
-  # Parameters for Boost 1.64.0
-  set(BOOST_NAME boost_1_64_0)
-  set(BOOST_BCP_SUFFIX bcpdigest-1.3.0)
-  set(BOOST_MD5 "ecb266cf46adcc7f695ad12685871174")
+  ##
+  ## Parameters for static compilation of Boost 
+  ##
+  
+  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_FILESYSTEM_SOURCES_DIR "${BOOST_NAME}/libs/filesystem/src") 
   set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME})
 
   DownloadPackage(${BOOST_MD5} ${BOOST_URL} "${BOOST_SOURCES_DIR}")
 
-  set(BOOST_SOURCES)
 
-  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")
+  ##
+  ## Generic configuration of Boost
+  ## 
+
+  if (CMAKE_COMPILER_IS_GNUCXX)
+    add_definitions(-isystem ${BOOST_SOURCES_DIR})
+  endif()
+
+  include_directories(
+    ${BOOST_SOURCES_DIR}
+    )
+
+  add_definitions(
+    # Static build of Boost
+    -DBOOST_ALL_NO_LIB 
+    -DBOOST_ALL_NOLIB 
+    -DBOOST_DATE_TIME_NO_LIB 
+    -DBOOST_THREAD_BUILD_LIB
+    -DBOOST_PROGRAM_OPTIONS_NO_LIB
+    -DBOOST_REGEX_NO_LIB
+    -DBOOST_SYSTEM_NO_LIB
+    -DBOOST_LOCALE_NO_LIB
+    )
+
+  set(BOOST_SOURCES
+    ${BOOST_SOURCES_DIR}/libs/system/src/error_code.cpp
+    )
+
+
+  ##
+  ## Configuration of boost::thread
+  ##
+  
+  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 "OpenBSD" 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/atomic/src/lockpool.cpp
       ${BOOST_SOURCES_DIR}/libs/thread/src/pthread/once.cpp
       ${BOOST_SOURCES_DIR}/libs/thread/src/pthread/thread.cpp
       )
-    add_definitions(
-      -DBOOST_LOCALE_WITH_ICONV=1
-      -DBOOST_LOCALE_NO_WINAPI_BACKEND=1
-      -DBOOST_LOCALE_NO_STD_BACKEND=1
-      )
 
     if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase" OR
-        ${CMAKE_SYSTEM_NAME} STREQUAL "PNaCl" OR
-        ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl32" OR
-        ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl64")
+        CMAKE_SYSTEM_NAME STREQUAL "PNaCl" OR
+        CMAKE_SYSTEM_NAME STREQUAL "NaCl32" OR
+        CMAKE_SYSTEM_NAME STREQUAL "NaCl64")
       add_definitions(-DBOOST_HAS_SCHED_YIELD=1)
     endif()
 
-  elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+  elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
     list(APPEND BOOST_SOURCES
       ${BOOST_SOURCES_DIR}/libs/thread/src/win32/tss_dll.cpp
       ${BOOST_SOURCES_DIR}/libs/thread/src/win32/thread.cpp
       ${BOOST_SOURCES_DIR}/libs/thread/src/win32/tss_pe.cpp
-      ${BOOST_FILESYSTEM_SOURCES_DIR}/windows_file_codecvt.cpp
       )
 
-    # Starting with release 0.8.2, Orthanc statically links against
-    # libiconv, even on Windows. Indeed, the "WCONV" library of
-    # Windows XP seems not to support properly several codepages
-    # (notably "Latin3", "Hebrew", and "Arabic").
-
-    if (USE_BOOST_ICONV)
-      include(${ORTHANC_ROOT}/Resources/CMake/LibIconvConfiguration.cmake)
-    else()
-      add_definitions(-DBOOST_LOCALE_WITH_WCONV=1)
-    endif()
-
-    add_definitions(
-      -DBOOST_LOCALE_NO_POSIX_BACKEND=1
-      -DBOOST_LOCALE_NO_STD_BACKEND=1
-      )
-
-  elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
-    add_definitions(
-      -DBOOST_LOCALE_NO_POSIX_BACKEND=1
-      -DBOOST_LOCALE_NO_STD_BACKEND=1
-      )
+  elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
 
   else()
     message(FATAL_ERROR "Support your platform here")
   endif()
 
-  if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
-    list(APPEND BOOST_SOURCES
-      ${BOOST_SOURCES_DIR}/libs/filesystem/src/utf8_codecvt_facet.cpp
-      )
-  endif()
 
+  ##
+  ## Configuration of boost::regex
+  ##
+  
   aux_source_directory(${BOOST_SOURCES_DIR}/libs/regex/src BOOST_REGEX_SOURCES)
 
   list(APPEND BOOST_SOURCES
     ${BOOST_REGEX_SOURCES}
+    )
+
+
+  ##
+  ## Configuration of boost::datetime
+  ##
+  
+  list(APPEND BOOST_SOURCES
     ${BOOST_SOURCES_DIR}/libs/date_time/src/gregorian/greg_month.cpp
-    ${BOOST_SOURCES_DIR}/libs/system/src/error_code.cpp
     )
 
-  if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
-    list(APPEND BOOST_SOURCES
-      ${BOOST_SOURCES_DIR}/libs/locale/src/encoding/codepage.cpp
-      )
-  endif()
 
-  if (${CMAKE_SYSTEM_NAME} STREQUAL "PNaCl" OR
-      ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl32" OR
-      ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl64")
+  ##
+  ## Configuration of boost::filesystem
+  ## 
+
+  if (CMAKE_SYSTEM_NAME STREQUAL "PNaCl" OR
+      CMAKE_SYSTEM_NAME STREQUAL "NaCl32" OR
+      CMAKE_SYSTEM_NAME STREQUAL "NaCl64")
     # boost::filesystem is not available on PNaCl
     add_definitions(
       -DBOOST_HAS_FILESYSTEM_V3=0
@@ -143,50 +155,36 @@ if (BOOST_STATIC)
       -DBOOST_HAS_FILESYSTEM_V3=1
       )
     list(APPEND BOOST_SOURCES
-      ${BOOST_FILESYSTEM_SOURCES_DIR}/codecvt_error_category.cpp
-      ${BOOST_FILESYSTEM_SOURCES_DIR}/operations.cpp
-      ${BOOST_FILESYSTEM_SOURCES_DIR}/path.cpp
-      ${BOOST_FILESYSTEM_SOURCES_DIR}/path_traits.cpp
+      ${BOOST_NAME}/libs/filesystem/src/codecvt_error_category.cpp
+      ${BOOST_NAME}/libs/filesystem/src/operations.cpp
+      ${BOOST_NAME}/libs/filesystem/src/path.cpp
+      ${BOOST_NAME}/libs/filesystem/src/path_traits.cpp
       )
-  endif()
 
-  if (USE_BOOST_LOCALE_BACKEND)
-    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")
-      list(APPEND BOOST_SOURCES
-        ${BOOST_SOURCES_DIR}/libs/locale/src/posix/codecvt.cpp
-        ${BOOST_SOURCES_DIR}/libs/locale/src/posix/collate.cpp
-        ${BOOST_SOURCES_DIR}/libs/locale/src/posix/converter.cpp
-        ${BOOST_SOURCES_DIR}/libs/locale/src/posix/numeric.cpp
-        ${BOOST_SOURCES_DIR}/libs/locale/src/posix/posix_backend.cpp
+    if (CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR
+        CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR
+        CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+     list(APPEND BOOST_SOURCES
+        ${BOOST_SOURCES_DIR}/libs/filesystem/src/utf8_codecvt_facet.cpp
         )
-    elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+
+    elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
       list(APPEND BOOST_SOURCES
-        ${BOOST_SOURCES_DIR}/libs/locale/src/win32/collate.cpp
-        ${BOOST_SOURCES_DIR}/libs/locale/src/win32/converter.cpp
-        ${BOOST_SOURCES_DIR}/libs/locale/src/win32/lcid.cpp
-        ${BOOST_SOURCES_DIR}/libs/locale/src/win32/numeric.cpp
-        ${BOOST_SOURCES_DIR}/libs/locale/src/win32/win_backend.cpp
+        ${BOOST_NAME}/libs/filesystem/src/windows_file_codecvt.cpp
         )
-    else()
-      message(FATAL_ERROR "Support your platform here")
     endif()
+  endif()
 
-    list(APPEND BOOST_SOURCES
-      ${BOOST_REGEX_SOURCES}
-      ${BOOST_SOURCES_DIR}/libs/date_time/src/gregorian/greg_month.cpp
-      ${BOOST_SOURCES_DIR}/libs/system/src/error_code.cpp
 
-      ${BOOST_FILESYSTEM_SOURCES_DIR}/codecvt_error_category.cpp
-      ${BOOST_FILESYSTEM_SOURCES_DIR}/operations.cpp
-      ${BOOST_FILESYSTEM_SOURCES_DIR}/path.cpp
-      ${BOOST_FILESYSTEM_SOURCES_DIR}/path_traits.cpp
+  ##
+  ## Configuration of boost::locale
+  ## 
 
+  if (NOT ENABLE_LOCALE)
+    message("boost::locale is disabled")
+  else()
+    list(APPEND BOOST_SOURCES
+      ${BOOST_SOURCES_DIR}/libs/locale/src/encoding/codepage.cpp
       ${BOOST_SOURCES_DIR}/libs/locale/src/shared/generator.cpp
       ${BOOST_SOURCES_DIR}/libs/locale/src/shared/date_time.cpp
       ${BOOST_SOURCES_DIR}/libs/locale/src/shared/formatting.cpp
@@ -200,39 +198,75 @@ if (BOOST_STATIC)
       ${BOOST_SOURCES_DIR}/libs/locale/src/util/info.cpp
       ${BOOST_SOURCES_DIR}/libs/locale/src/util/locale_data.cpp
       )        
-  endif()
 
-  add_definitions(
-    # Static build of Boost
-    -DBOOST_ALL_NO_LIB 
-    -DBOOST_ALL_NOLIB 
-    -DBOOST_DATE_TIME_NO_LIB 
-    -DBOOST_THREAD_BUILD_LIB
-    -DBOOST_PROGRAM_OPTIONS_NO_LIB
-    -DBOOST_REGEX_NO_LIB
-    -DBOOST_SYSTEM_NO_LIB
-    -DBOOST_LOCALE_NO_LIB
-    -DBOOST_HAS_LOCALE=1
-    )
+    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")
+      list(APPEND BOOST_SOURCES
+        ${BOOST_SOURCES_DIR}/libs/locale/src/posix/codecvt.cpp
+        ${BOOST_SOURCES_DIR}/libs/locale/src/posix/collate.cpp
+        ${BOOST_SOURCES_DIR}/libs/locale/src/posix/converter.cpp
+        ${BOOST_SOURCES_DIR}/libs/locale/src/posix/numeric.cpp
+        ${BOOST_SOURCES_DIR}/libs/locale/src/posix/posix_backend.cpp
+        )
 
-  if (CMAKE_COMPILER_IS_GNUCXX)
-    add_definitions(-isystem ${BOOST_SOURCES_DIR})
-  endif()
+      add_definitions(
+        -DBOOST_LOCALE_WITH_ICONV=1
+        -DBOOST_LOCALE_NO_WINAPI_BACKEND=1
+        -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
+        )
 
-  include_directories(
-    ${BOOST_SOURCES_DIR}
-    )
+      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
+        ${BOOST_SOURCES_DIR}/libs/locale/src/win32/converter.cpp
+        ${BOOST_SOURCES_DIR}/libs/locale/src/win32/lcid.cpp
+        ${BOOST_SOURCES_DIR}/libs/locale/src/win32/numeric.cpp
+        ${BOOST_SOURCES_DIR}/libs/locale/src/win32/win_backend.cpp
+        )
 
-  source_group(ThirdParty\\boost REGULAR_EXPRESSION ${BOOST_SOURCES_DIR}/.*)
+      add_definitions(
+        -DBOOST_LOCALE_NO_POSIX_BACKEND=1
+        -DBOOST_LOCALE_NO_STD_BACKEND=1
+        )
 
-else()
-  add_definitions(
-    -DBOOST_HAS_LOCALE=1
-    )
-endif()
+      # Starting with release 0.8.2, Orthanc statically links against
+      # libiconv, even on Windows. Indeed, the "WCONV" library of
+      # Windows XP seems not to support properly several codepages
+      # (notably "Latin3", "Hebrew", and "Arabic"). Set
+      # "USE_BOOST_ICONV" to "OFF" to use WCONV anyway.
 
+      if (USE_BOOST_ICONV)
+        add_definitions(-DBOOST_LOCALE_WITH_ICONV=1)
+      else()
+        add_definitions(-DBOOST_LOCALE_WITH_WCONV=1)
+      endif()
 
-add_definitions(
-  -DBOOST_HAS_DATE_TIME=1
-  -DBOOST_HAS_REGEX=1
-  )
+    else()
+      message(FATAL_ERROR "Support your platform here")
+    endif()
+  endif()
+
+  
+  source_group(ThirdParty\\boost REGULAR_EXPRESSION ${BOOST_SOURCES_DIR}/.*)
+
+endif()
diff --git a/Resources/CMake/BoostConfiguration.sh b/Resources/CMake/BoostConfiguration.sh
index 2e0ca40..d77a8c6 100755
--- a/Resources/CMake/BoostConfiguration.sh
+++ b/Resources/CMake/BoostConfiguration.sh
@@ -16,22 +16,26 @@ set -u
 ##   - Orthanc between 0.9.2 and 0.9.4: Boost 1.58.0
 ##   - Orthanc between 0.9.5 and 1.0.0: Boost 1.59.0
 ##   - Orthanc between 1.1.0 and 1.2.0: Boost 1.60.0
-##   - Orthanc >= 1.3.0: Boost 1.64.0
+##   - Orthanc 1.3.0: Boost 1.64.0
+##   - Orthanc >= 1.3.1: Boost 1.65.1
 
-rm -rf /tmp/boost_1_64_0
-rm -rf /tmp/bcp/boost_1_64_0
+BOOST_VERSION=1_65_1
+ORTHANC_VERSION=1.3.1
+
+rm -rf /tmp/boost_${BOOST_VERSION}
+rm -rf /tmp/bcp/boost_${BOOST_VERSION}
 
 cd /tmp
-echo "Uncompressing the sources of Boost 1.64.0..."
-tar xfz ./boost_1_64_0.tar.gz 
+echo "Uncompressing the sources of Boost ${BOOST_VERSION}..."
+tar xfz ./boost_${BOOST_VERSION}.tar.gz 
 
 echo "Generating the subset..."
-mkdir -p /tmp/bcp/boost_1_64_0
-bcp --boost=/tmp/boost_1_64_0 thread system locale date_time filesystem math/special_functions algorithm uuid atomic iostreams program_options numeric/ublas /tmp/bcp/boost_1_64_0
+mkdir -p /tmp/bcp/boost_${BOOST_VERSION}
+bcp --boost=/tmp/boost_${BOOST_VERSION} thread system locale date_time filesystem math/special_functions algorithm uuid atomic iostreams program_options numeric/ublas geometry polygon /tmp/bcp/boost_${BOOST_VERSION}
 cd /tmp/bcp
 
 echo "Compressing the subset..."
-tar cfz boost_1_64_0_bcpdigest-1.3.0.tar.gz boost_1_64_0
-ls -l boost_1_64_0_bcpdigest-1.3.0.tar.gz
-md5sum boost_1_64_0_bcpdigest-1.3.0.tar.gz
-readlink -f boost_1_64_0_bcpdigest-1.3.0.tar.gz
+tar cfz boost_${BOOST_VERSION}_bcpdigest-${ORTHANC_VERSION}.tar.gz boost_${BOOST_VERSION}
+ls -l boost_${BOOST_VERSION}_bcpdigest-${ORTHANC_VERSION}.tar.gz
+md5sum boost_${BOOST_VERSION}_bcpdigest-${ORTHANC_VERSION}.tar.gz
+readlink -f boost_${BOOST_VERSION}_bcpdigest-${ORTHANC_VERSION}.tar.gz
diff --git a/Resources/CMake/CivetwebConfiguration.cmake b/Resources/CMake/CivetwebConfiguration.cmake
new file mode 100644
index 0000000..3e58509
--- /dev/null
+++ b/Resources/CMake/CivetwebConfiguration.cmake
@@ -0,0 +1,57 @@
+if (STATIC_BUILD OR NOT USE_SYSTEM_CIVETWEB)
+  set(CIVETWEB_SOURCES_DIR ${CMAKE_BINARY_DIR}/civetweb-1.9.1)
+  set(CIVETWEB_URL "http://www.orthanc-server.com/downloads/third-party/civetweb-1.9.1.tar.gz")
+  set(CIVETWEB_MD5 "c713f7336582d1a78897971260c67c2a")
+
+  DownloadPackage(${CIVETWEB_MD5} ${CIVETWEB_URL} "${CIVETWEB_SOURCES_DIR}")
+
+  include_directories(
+    ${CIVETWEB_SOURCES_DIR}/include
+    )
+
+  set(CIVETWEB_SOURCES
+    ${CIVETWEB_SOURCES_DIR}/src/civetweb.c
+    )
+
+
+  if (ENABLE_SSL)
+    add_definitions(
+      -DNO_SSL_DL=1
+      )
+    if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
+        ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD")
+      link_libraries(dl)
+    endif()
+
+  else()
+    add_definitions(
+      -DNO_SSL=1   # Remove SSL support from civetweb
+      )
+  endif()
+
+
+  if (CMAKE_SYSTEM_NAME STREQUAL "Windows" AND
+      CMAKE_COMPILER_IS_GNUCXX)
+    # This is a patch for MinGW64
+    add_definitions(-D_TIMESPEC_DEFINED=1)
+  endif()
+
+  source_group(ThirdParty\\Civetweb REGULAR_EXPRESSION ${CIVETWEB_SOURCES_DIR}/.*)
+
+else()
+  include(CMakePushCheckState)
+  
+  CHECK_INCLUDE_FILE_CXX(civetweb.h HAVE_CIVETWEB_H)
+  if (NOT HAVE_CIVETWEB_H)
+    message(FATAL_ERROR "Please install the libcivetweb-devel package")
+  endif()
+
+  cmake_reset_check_state()
+  set(CMAKE_REQUIRED_LIBRARIES dl pthread)
+  CHECK_LIBRARY_EXISTS(civetweb mg_start "" HAVE_CIVETWEB_LIB)
+  if (NOT HAVE_CIVETWEB_LIB)
+    message(FATAL_ERROR "Please install the libcivetweb-devel package")
+  endif()
+
+  link_libraries(civetweb)
+endif()
diff --git a/Resources/CMake/Compiler.cmake b/Resources/CMake/Compiler.cmake
index fa7577d..fcfe34a 100644
--- a/Resources/CMake/Compiler.cmake
+++ b/Resources/CMake/Compiler.cmake
@@ -7,7 +7,8 @@ if (CMAKE_CROSSCOMPILING)
 endif()
 
 if (CMAKE_COMPILER_IS_GNUCXX)
-  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-long-long -Wno-implicit-function-declaration")  
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-long-long")
+
   # --std=c99 makes libcurl not to compile
   # -pedantic gives a lot of warnings on OpenSSL 
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-variadic-macros")
@@ -56,11 +57,27 @@ elseif (MSVC)
 endif()
 
 
+if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR
+    ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
+  # In FreeBSD/OpenBSD, the "/usr/local/" folder contains the ports and need to be imported
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/local/include")
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/local/include")
+  SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib")
+  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L/usr/local/lib")
+endif()
+
+
 if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
     ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR
-    ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
-  set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined")
-  set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
+    ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR
+    ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
+
+  if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
+    # The "--no-undefined" linker flag makes the shared libraries
+    # (plugins ModalityWorklists and ServeFolders) fail to compile on OpenBSD
+    set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined")
+    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
+  endif()
 
   if (NOT DEFINED ENABLE_PLUGINS_VERSION_SCRIPT OR 
       ENABLE_PLUGINS_VERSION_SCRIPT)
@@ -70,22 +87,39 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
   # 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 rt)
+  link_libraries(uuid pthread)
+
+  if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
+    link_libraries(rt)
+  endif()
+
+  if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND
+      NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
+    link_libraries(dl)
+  endif()
 
   if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
+    # The "--as-needed" linker flag is not available on FreeBSD
     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")
     set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--as-needed")
     set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed")
+  endif()
+
+  if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND
+      NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
+    # FreeBSD/OpenBSD have just one single interface for file
+    # handling, which is 64bit clean, so there is no need to define macro
+    # for LFS (Large File Support).
+    # https://ohse.de/uwe/articles/lfs.html
     add_definitions(
       -D_LARGEFILE64_SOURCE=1 
       -D_FILE_OFFSET_BITS=64
       )
-    link_libraries(dl)
   endif()
 
   CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H)
   if (NOT HAVE_UUID_H)
-    message(FATAL_ERROR "Please install the uuid-dev package")
+    message(FATAL_ERROR "Please install the uuid-dev package (or e2fsprogs if OpenBSD)")
   endif()
 
 elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
@@ -145,6 +179,11 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
     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()
 
 
@@ -155,15 +194,6 @@ if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
 endif()
 
 
-if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
-  # In FreeBSD, the "/usr/local/" folder contains the ports and need to be imported
-  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/local/include")
-  SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -I/usr/local/include")
-  SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib")
-  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L/usr/local/lib")
-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")
diff --git a/Resources/CMake/DcmtkConfiguration.cmake b/Resources/CMake/DcmtkConfiguration.cmake
index 0d88735..184369f 100644
--- a/Resources/CMake/DcmtkConfiguration.cmake
+++ b/Resources/CMake/DcmtkConfiguration.cmake
@@ -26,6 +26,8 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
 
     set(DCMTK_BINARY_DIR ${DCMTK_SOURCES_DIR}/)
     set(DCMTK_CMAKE_INCLUDE ${DCMTK_SOURCES_DIR}/)
+    set(DCMTK_WITH_THREADS ON)
+    
     add_definitions(-DDCMTK_INSIDE_LOG4CPLUS=1)
   endif()
   
@@ -149,7 +151,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
       )
   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)
@@ -177,7 +179,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
   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(
@@ -202,7 +204,8 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
   if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
       ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR
       ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR
-      ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD")
+      ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR
+      ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
     list(REMOVE_ITEM DCMTK_SOURCES 
       ${DCMTK_SOURCES_DIR}/oflog/libsrc/clfsap.cc
       ${DCMTK_SOURCES_DIR}/oflog/libsrc/windebap.cc
diff --git a/Resources/CMake/GoogleTestConfiguration.cmake b/Resources/CMake/GoogleTestConfiguration.cmake
index b9074b4..aa6b2f1 100644
--- a/Resources/CMake/GoogleTestConfiguration.cmake
+++ b/Resources/CMake/GoogleTestConfiguration.cmake
@@ -1,5 +1,5 @@
-if (USE_GTEST_DEBIAN_SOURCE_PACKAGE)
-  find_path(GTEST_DEBIAN_SOURCES_DIR
+if (USE_GOOGLE_TEST_DEBIAN_PACKAGE)
+  find_path(GOOGLE_TEST_DEBIAN_SOURCES_DIR
     NAMES src/gtest-all.cc
     PATHS
     /usr/src/gtest
@@ -7,37 +7,40 @@ if (USE_GTEST_DEBIAN_SOURCE_PACKAGE)
     PATH_SUFFIXES src
     )
 
-  find_path(GTEST_DEBIAN_INCLUDE_DIR
+  find_path(GOOGLE_TEST_DEBIAN_INCLUDE_DIR
     NAMES gtest.h
     PATHS
     /usr/include/gtest
     )
 
-  message("Path to the Debian Google Test sources: ${GTEST_DEBIAN_SOURCES_DIR}")
-  message("Path to the Debian Google Test includes: ${GTEST_DEBIAN_INCLUDE_DIR}")
+  message("Path to the Debian Google Test sources: ${GOOGLE_TEST_DEBIAN_SOURCES_DIR}")
+  message("Path to the Debian Google Test includes: ${GOOGLE_TEST_DEBIAN_INCLUDE_DIR}")
 
-  set(GTEST_SOURCES ${GTEST_DEBIAN_SOURCES_DIR}/src/gtest-all.cc)
-  include_directories(${GTEST_DEBIAN_SOURCES_DIR})
+  set(GOOGLE_TEST_SOURCES
+    ${GOOGLE_TEST_DEBIAN_SOURCES_DIR}/src/gtest-all.cc
+    )
+
+  include_directories(${GOOGLE_TEST_DEBIAN_SOURCES_DIR})
 
-  if (NOT EXISTS ${GTEST_SOURCES} OR
-      NOT EXISTS ${GTEST_DEBIAN_INCLUDE_DIR}/gtest.h)
+  if (NOT EXISTS ${GOOGLE_TEST_SOURCES} OR
+      NOT EXISTS ${GOOGLE_TEST_DEBIAN_INCLUDE_DIR}/gtest.h)
     message(FATAL_ERROR "Please install the libgtest-dev package")
   endif()
 
 elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST)
-  set(GTEST_SOURCES_DIR ${CMAKE_BINARY_DIR}/gtest-1.7.0)
-  set(GTEST_URL "http://www.orthanc-server.com/downloads/third-party/gtest-1.7.0.zip")
-  set(GTEST_MD5 "2d6ec8ccdf5c46b05ba54a9fd1d130d7")
+  set(GOOGLE_TEST_SOURCES_DIR ${CMAKE_BINARY_DIR}/gtest-1.7.0)
+  set(GOOGLE_TEST_URL "http://www.orthanc-server.com/downloads/third-party/gtest-1.7.0.zip")
+  set(GOOGLE_TEST_MD5 "2d6ec8ccdf5c46b05ba54a9fd1d130d7")
 
-  DownloadPackage(${GTEST_MD5} ${GTEST_URL} "${GTEST_SOURCES_DIR}")
+  DownloadPackage(${GOOGLE_TEST_MD5} ${GOOGLE_TEST_URL} "${GOOGLE_TEST_SOURCES_DIR}")
 
   include_directories(
-    ${GTEST_SOURCES_DIR}/include
-    ${GTEST_SOURCES_DIR}
+    ${GOOGLE_TEST_SOURCES_DIR}/include
+    ${GOOGLE_TEST_SOURCES_DIR}
     )
 
-  set(GTEST_SOURCES
-    ${GTEST_SOURCES_DIR}/src/gtest-all.cc
+  set(GOOGLE_TEST_SOURCES
+    ${GOOGLE_TEST_SOURCES_DIR}/src/gtest-all.cc
     )
 
   # https://code.google.com/p/googletest/issues/detail?id=412
@@ -45,14 +48,16 @@ elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST)
     add_definitions(/D _VARIADIC_MAX=10)
   endif()
 
-  source_group(ThirdParty\\GoogleTest REGULAR_EXPRESSION ${GTEST_SOURCES_DIR}/.*)
+  source_group(ThirdParty\\GoogleTest REGULAR_EXPRESSION ${GOOGLE_TEST_SOURCES_DIR}/.*)
 
 else()
   include(FindGTest)
-  if (NOT GTEST_FOUND)
+  if (NOT GOOGLE_TEST_FOUND)
     message(FATAL_ERROR "Unable to find GoogleTest")
   endif()
 
-  include_directories(${GTEST_INCLUDE_DIRS})
-  link_libraries(${GTEST_LIBRARIES})
+  include_directories(${GOOGLE_TEST_INCLUDE_DIRS})
+
+  # The variable GOOGLE_TEST_LIBRARIES contains the shared library of
+  # Google Test
 endif()
diff --git a/Resources/CMake/JsonCppConfiguration.cmake b/Resources/CMake/JsonCppConfiguration.cmake
index 1532a81..9fe93e9 100644
--- a/Resources/CMake/JsonCppConfiguration.cmake
+++ b/Resources/CMake/JsonCppConfiguration.cmake
@@ -48,9 +48,10 @@ else()
       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()
diff --git a/Resources/CMake/LibCurlConfiguration.cmake b/Resources/CMake/LibCurlConfiguration.cmake
index 390a1a7..c507acf 100644
--- a/Resources/CMake/LibCurlConfiguration.cmake
+++ b/Resources/CMake/LibCurlConfiguration.cmake
@@ -60,7 +60,8 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_CURL)
   if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
       ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR
       ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR
-      ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD")
+      ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR
+      ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
     if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
       SET(TMP_OS "x86_64")
     else()
diff --git a/Resources/CMake/LibIconvConfiguration.cmake b/Resources/CMake/LibIconvConfiguration.cmake
index c4fe211..dfa3426 100644
--- a/Resources/CMake/LibIconvConfiguration.cmake
+++ b/Resources/CMake/LibIconvConfiguration.cmake
@@ -1,52 +1,96 @@
-set(LIBICONV_SOURCES_DIR ${CMAKE_BINARY_DIR}/libiconv-1.15)
-set(LIBICONV_URL "http://www.orthanc-server.com/downloads/third-party/libiconv-1.15.tar.gz")
-set(LIBICONV_MD5 "ace8b5f2db42f7b3b3057585e80d9808")
-
-DownloadPackage(${LIBICONV_MD5} ${LIBICONV_URL} "${LIBICONV_SOURCES_DIR}")
-
-# https://groups.google.com/d/msg/android-ndk/AS1nkxnk6m4/EQm09hD1tigJ
-add_definitions(
-  -DBOOST_LOCALE_WITH_ICONV=1
-  -DBUILDING_LIBICONV=1
-  -DIN_LIBRARY=1
-  -DLIBDIR=""
-  -DICONV_CONST=
-  )
-
-configure_file(
-  ${LIBICONV_SOURCES_DIR}/srclib/localcharset.h
-  ${LIBICONV_SOURCES_DIR}/include
-  COPYONLY)
-
-set(HAVE_VISIBILITY 0)
-set(ICONV_CONST ${ICONV_CONST})
-set(USE_MBSTATE_T 1)
-set(BROKEN_WCHAR_H 0)
-set(EILSEQ)
-set(HAVE_WCHAR_T 1)   
-configure_file(
-  ${LIBICONV_SOURCES_DIR}/include/iconv.h.build.in
-  ${LIBICONV_SOURCES_DIR}/include/iconv.h
-  )
-unset(HAVE_VISIBILITY)
-unset(ICONV_CONST)
-unset(USE_MBSTATE_T)
-unset(BROKEN_WCHAR_H)
-unset(EILSEQ)
-unset(HAVE_WCHAR_T)   
-
-# Create an empty "config.h" for libiconv
-file(WRITE ${LIBICONV_SOURCES_DIR}/include/config.h "")
-
-include_directories(
-  ${LIBICONV_SOURCES_DIR}/include
-  )
-
-list(APPEND BOOST_SOURCES
-  ${LIBICONV_SOURCES_DIR}/lib/iconv.c  
-  ${LIBICONV_SOURCES_DIR}/lib/relocatable.c
-  ${LIBICONV_SOURCES_DIR}/libcharset/lib/localcharset.c  
-  ${LIBICONV_SOURCES_DIR}/libcharset/lib/relocatable.c
-  )
-
-source_group(ThirdParty\\libiconv REGULAR_EXPRESSION ${LIBICONV_SOURCES_DIR}/.*)
+if (NOT ENABLE_LOCALE)
+  message("Support for locales is disabled")
+
+elseif (NOT USE_BOOST_ICONV)
+  message("Not using libiconv")
+
+else()
+  message("Using libiconv")
+
+  if (STATIC_BUILD OR NOT USE_SYSTEM_LIBICONV)
+    set(LIBICONV_SOURCES_DIR ${CMAKE_BINARY_DIR}/libiconv-1.15)
+    set(LIBICONV_URL "http://www.orthanc-server.com/downloads/third-party/libiconv-1.15.tar.gz")
+    set(LIBICONV_MD5 "ace8b5f2db42f7b3b3057585e80d9808")
+
+    DownloadPackage(${LIBICONV_MD5} ${LIBICONV_URL} "${LIBICONV_SOURCES_DIR}")
+
+    # Disable the support of libiconv that is shipped by default with
+    # the C standard library on Linux. Setting this macro redirects
+    # calls from "iconv*()" to "libiconv*()" by defining macros in the
+    # C headers of "libiconv-1.15".
+    add_definitions(-DLIBICONV_PLUG=1)
+
+    # https://groups.google.com/d/msg/android-ndk/AS1nkxnk6m4/EQm09hD1tigJ
+    add_definitions(
+      -DBUILDING_LIBICONV=1
+      -DIN_LIBRARY=1
+      -DLIBDIR=""
+      -DICONV_CONST=
+      )
+
+    configure_file(
+      ${LIBICONV_SOURCES_DIR}/srclib/localcharset.h
+      ${LIBICONV_SOURCES_DIR}/include
+      COPYONLY)
+
+    set(HAVE_VISIBILITY 0)
+    set(ICONV_CONST ${ICONV_CONST})
+    set(USE_MBSTATE_T 1)
+    set(BROKEN_WCHAR_H 0)
+    set(EILSEQ)
+    set(HAVE_WCHAR_T 1)
+    configure_file(
+      ${LIBICONV_SOURCES_DIR}/include/iconv.h.build.in
+      ${LIBICONV_SOURCES_DIR}/include/iconv.h
+      )
+    unset(HAVE_VISIBILITY)
+    unset(ICONV_CONST)
+    unset(USE_MBSTATE_T)
+    unset(BROKEN_WCHAR_H)
+    unset(EILSEQ)
+    unset(HAVE_WCHAR_T)
+
+    # Create an empty "config.h" for libiconv
+    file(WRITE ${LIBICONV_SOURCES_DIR}/include/config.h "")
+
+    include_directories(
+      ${LIBICONV_SOURCES_DIR}/include
+      )
+
+    set(LIBICONV_SOURCES
+      ${LIBICONV_SOURCES_DIR}/lib/iconv.c  
+      ${LIBICONV_SOURCES_DIR}/lib/relocatable.c
+      ${LIBICONV_SOURCES_DIR}/libcharset/lib/localcharset.c  
+      ${LIBICONV_SOURCES_DIR}/libcharset/lib/relocatable.c
+      )
+
+    source_group(ThirdParty\\libiconv REGULAR_EXPRESSION ${LIBICONV_SOURCES_DIR}/.*)
+
+    if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
+      add_definitions(-DHAVE_WORKING_O_NOFOLLOW=0)
+    else()
+      add_definitions(-DHAVE_WORKING_O_NOFOLLOW=1)
+    endif()
+
+  else() 
+    CHECK_INCLUDE_FILE_CXX(iconv.h HAVE_ICONV_H)
+    if (NOT HAVE_ICONV_H)
+      message(FATAL_ERROR "Please install the libiconv-dev package")
+    endif()
+
+    # Check whether the support for libiconv is bundled within the
+    # standard C library
+    CHECK_FUNCTION_EXISTS(iconv_open HAVE_ICONV_LIB)
+    if (NOT HAVE_ICONV_LIB)
+      # No builtin support for libiconv, try and find an external library.
+      # Open question: Does this make sense on any platform?
+      CHECK_LIBRARY_EXISTS(iconv iconv_open "" HAVE_ICONV_LIB_2)
+      if (NOT HAVE_ICONV_LIB_2)
+        message(FATAL_ERROR "Please install the libiconv-dev package")
+      else()
+        link_libraries(iconv)
+      endif()
+    endif()
+
+  endif()
+endif()
diff --git a/Resources/CMake/LibP11Configuration.cmake b/Resources/CMake/LibP11Configuration.cmake
index 21ab70d..8dc7438 100644
--- a/Resources/CMake/LibP11Configuration.cmake
+++ b/Resources/CMake/LibP11Configuration.cmake
@@ -48,6 +48,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBP11)
   if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
       ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR
       ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR
+      ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" OR
       ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
     list(APPEND LIBP11_SOURCES 
       ${LIBP11_SOURCES_DIR}/src/atfork.c
diff --git a/Resources/CMake/OrthancFrameworkConfiguration.cmake b/Resources/CMake/OrthancFrameworkConfiguration.cmake
new file mode 100644
index 0000000..1100162
--- /dev/null
+++ b/Resources/CMake/OrthancFrameworkConfiguration.cmake
@@ -0,0 +1,509 @@
+##
+## This is a CMake configuration file that configures the core
+## libraries of Orthanc. This file can be used by external projects so
+## as to gain access to the Orthanc APIs (the most prominent examples
+## are currently "Stone of Orthanc" and "Orthanc for whole-slide
+## imaging plugin").
+##
+
+
+#####################################################################
+## Configuration of the components
+#####################################################################
+
+# Path to the root folder of the Orthanc distribution
+set(ORTHANC_ROOT ${CMAKE_CURRENT_LIST_DIR}/../..)
+
+# Some basic inclusions
+include(CheckIncludeFiles)
+include(CheckIncludeFileCXX)
+include(CheckFunctionExists)
+include(CheckLibraryExists)
+include(FindPythonInterp)
+
+include(${CMAKE_CURRENT_LIST_DIR}/AutoGeneratedCode.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/DownloadPackage.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/Compiler.cmake)
+
+
+#####################################################################
+## Disable unneeded macros
+#####################################################################
+
+if (NOT ENABLE_SQLITE)
+  unset(USE_SYSTEM_SQLITE CACHE)
+  add_definitions(-DORTHANC_ENABLE_SQLITE=0)
+endif()
+
+if (NOT ENABLE_CRYPTO_OPTIONS)
+  unset(ENABLE_SSL CACHE)
+  unset(ENABLE_PKCS11 CACHE)
+  unset(USE_SYSTEM_OPENSSL CACHE)
+  unset(USE_SYSTEM_LIBP11 CACHE)
+  add_definitions(
+    -DORTHANC_ENABLE_SSL=0
+    -DORTHANC_ENABLE_PKCS11=0
+    )
+endif()
+
+if (NOT ENABLE_WEB_CLIENT)
+  unset(USE_SYSTEM_CURL CACHE)
+  add_definitions(-DORTHANC_ENABLE_CURL=0)
+endif()
+
+if (NOT ENABLE_WEB_SERVER)
+  unset(ENABLE_CIVETWEB CACHE)
+  unset(USE_SYSTEM_CIVETWEB CACHE)
+  unset(USE_SYSTEM_MONGOOSE CACHE)
+  add_definitions(
+    -DORTHANC_ENABLE_CIVETWEB=0
+    -DORTHANC_ENABLE_MONGOOSE=0
+    )
+endif()
+
+if (NOT ENABLE_JPEG)
+  unset(USE_SYSTEM_LIBJPEG CACHE)
+  add_definitions(-DORTHANC_ENABLE_JPEG=0)
+endif()
+
+if (NOT ENABLE_PNG)
+  unset(USE_SYSTEM_LIBPNG CACHE)
+  add_definitions(-DORTHANC_ENABLE_PNG=0)
+endif()
+
+if (NOT ENABLE_LUA)
+  unset(USE_SYSTEM_LUA CACHE)
+  add_definitions(-DORTHANC_ENABLE_LUA=0)
+endif()
+
+if (NOT ENABLE_PUGIXML)
+  unset(USE_SYSTEM_PUGIXML CACHE)
+  add_definitions(-DORTHANC_ENABLE_PUGIXML=0)
+endif()
+
+if (NOT ENABLE_LOCALE)
+  unset(USE_SYSTEM_LIBICONV CACHE)
+  add_definitions(-DORTHANC_ENABLE_LOCALE=0)
+endif()
+
+if (NOT ENABLE_GOOGLE_TEST)
+  unset(USE_SYSTEM_GOOGLE_TEST CACHE)
+  unset(USE_GOOGLE_TEST_DEBIAN_PACKAGE CACHE)
+endif()
+
+if (NOT ENABLE_DCMTK)
+  add_definitions(
+    -DORTHANC_ENABLE_DCMTK=0
+    -DORTHANC_ENABLE_DCMTK_NETWORKING=0
+    )
+  unset(DCMTK_DICTIONARY_DIR CACHE)
+  unset(USE_DCMTK_360 CACHE)
+  unset(USE_DCMTK_362_PRIVATE_DIC CACHE)
+  unset(USE_SYSTEM_DCMTK CACHE)
+  unset(ENABLE_DCMTK_JPEG CACHE)
+  unset(ENABLE_DCMTK_JPEG_LOSSLESS CACHE)
+endif()
+
+
+#####################################################################
+## List of source files
+#####################################################################
+
+set(ORTHANC_CORE_SOURCES_INTERNAL
+  ${ORTHANC_ROOT}/Core/Cache/MemoryCache.cpp
+  ${ORTHANC_ROOT}/Core/ChunkedBuffer.cpp
+  ${ORTHANC_ROOT}/Core/Compression/DeflateBaseCompressor.cpp
+  ${ORTHANC_ROOT}/Core/Compression/GzipCompressor.cpp
+  ${ORTHANC_ROOT}/Core/Compression/HierarchicalZipWriter.cpp
+  ${ORTHANC_ROOT}/Core/Compression/ZipWriter.cpp
+  ${ORTHANC_ROOT}/Core/Compression/ZlibCompressor.cpp
+  ${ORTHANC_ROOT}/Core/DicomFormat/DicomArray.cpp
+  ${ORTHANC_ROOT}/Core/DicomFormat/DicomImageInformation.cpp
+  ${ORTHANC_ROOT}/Core/DicomFormat/DicomInstanceHasher.cpp
+  ${ORTHANC_ROOT}/Core/DicomFormat/DicomIntegerPixelAccessor.cpp
+  ${ORTHANC_ROOT}/Core/DicomFormat/DicomMap.cpp
+  ${ORTHANC_ROOT}/Core/DicomFormat/DicomTag.cpp
+  ${ORTHANC_ROOT}/Core/DicomFormat/DicomValue.cpp
+  ${ORTHANC_ROOT}/Core/Enumerations.cpp
+  ${ORTHANC_ROOT}/Core/Images/Font.cpp
+  ${ORTHANC_ROOT}/Core/Images/FontRegistry.cpp
+  ${ORTHANC_ROOT}/Core/Images/IImageWriter.cpp
+  ${ORTHANC_ROOT}/Core/Images/Image.cpp
+  ${ORTHANC_ROOT}/Core/Images/ImageAccessor.cpp
+  ${ORTHANC_ROOT}/Core/Images/ImageBuffer.cpp
+  ${ORTHANC_ROOT}/Core/Images/ImageProcessing.cpp
+  ${ORTHANC_ROOT}/Core/Logging.cpp
+  ${ORTHANC_ROOT}/Core/Toolbox.cpp
+  ${ORTHANC_ROOT}/Core/WebServiceParameters.cpp
+  )
+
+
+#####################################################################
+## Configuration of optional third-party dependencies
+#####################################################################
+
+
+##
+## Embedded database: SQLite
+##
+
+if (ENABLE_SQLITE)
+  include(${CMAKE_CURRENT_LIST_DIR}/SQLiteConfiguration.cmake)
+  add_definitions(-DORTHANC_ENABLE_SQLITE=1)
+
+  list(APPEND ORTHANC_CORE_SOURCES_INTERNAL
+    ${ORTHANC_ROOT}/Core/SQLite/Connection.cpp
+    ${ORTHANC_ROOT}/Core/SQLite/FunctionContext.cpp
+    ${ORTHANC_ROOT}/Core/SQLite/Statement.cpp
+    ${ORTHANC_ROOT}/Core/SQLite/StatementId.cpp
+    ${ORTHANC_ROOT}/Core/SQLite/StatementReference.cpp
+    ${ORTHANC_ROOT}/Core/SQLite/Transaction.cpp
+    )
+endif()
+
+
+##
+## Cryptography: OpenSSL and libp11
+## Must be above "ENABLE_WEB_CLIENT" and "ENABLE_WEB_SERVER"
+##
+
+if (ENABLE_CRYPTO_OPTIONS)
+  if (ENABLE_SSL)
+    include(${CMAKE_CURRENT_LIST_DIR}/OpenSslConfiguration.cmake)
+    add_definitions(-DORTHANC_ENABLE_SSL=1)
+  else()
+    unset(USE_SYSTEM_OPENSSL CACHE)
+    add_definitions(-DORTHANC_ENABLE_SSL=0)
+  endif()
+
+  if (ENABLE_PKCS11)
+    if (ENABLE_SSL)
+      include(${CMAKE_CURRENT_LIST_DIR}/LibP11Configuration.cmake)
+
+      add_definitions(-DORTHANC_ENABLE_PKCS11=1)
+      list(APPEND ORTHANC_CORE_SOURCES_INTERNAL
+        ${ORTHANC_ROOT}/Core/Pkcs11.cpp
+        )
+    else()
+      message(FATAL_ERROR "OpenSSL is required to enable PKCS#11 support")
+    endif()
+  else()
+    add_definitions(-DORTHANC_ENABLE_PKCS11=0)  
+  endif()
+endif()
+
+
+##
+## HTTP client: libcurl
+##
+
+if (ENABLE_WEB_CLIENT)
+  include(${CMAKE_CURRENT_LIST_DIR}/LibCurlConfiguration.cmake)
+  add_definitions(-DORTHANC_ENABLE_CURL=1)
+
+  list(APPEND ORTHANC_CORE_SOURCES_INTERNAL
+    ${ORTHANC_ROOT}/Core/HttpClient.cpp
+    )
+endif()
+
+
+##
+## HTTP server: Mongoose 3.8 or Civetweb
+##
+
+if (ENABLE_WEB_SERVER)
+  if (ENABLE_CIVETWEB)
+    include(${CMAKE_CURRENT_LIST_DIR}/CivetwebConfiguration.cmake)
+    add_definitions(
+      -DORTHANC_ENABLE_CIVETWEB=1
+      -DORTHANC_ENABLE_MONGOOSE=0
+      )
+  else()
+    include(${CMAKE_CURRENT_LIST_DIR}/MongooseConfiguration.cmake)
+    add_definitions(
+      -DORTHANC_ENABLE_CIVETWEB=0
+      -DORTHANC_ENABLE_MONGOOSE=1
+      )
+  endif()
+
+  list(APPEND ORTHANC_CORE_SOURCES_INTERNAL
+    ${ORTHANC_ROOT}/Core/HttpServer/BufferHttpSender.cpp
+    ${ORTHANC_ROOT}/Core/HttpServer/FilesystemHttpHandler.cpp
+    ${ORTHANC_ROOT}/Core/HttpServer/FilesystemHttpSender.cpp
+    ${ORTHANC_ROOT}/Core/HttpServer/HttpContentNegociation.cpp
+    ${ORTHANC_ROOT}/Core/HttpServer/HttpFileSender.cpp
+    ${ORTHANC_ROOT}/Core/HttpServer/HttpOutput.cpp
+    ${ORTHANC_ROOT}/Core/HttpServer/HttpStreamTranscoder.cpp
+    ${ORTHANC_ROOT}/Core/HttpServer/HttpToolbox.cpp
+    ${ORTHANC_ROOT}/Core/HttpServer/MongooseServer.cpp
+    ${ORTHANC_ROOT}/Core/HttpServer/StringHttpOutput.cpp
+    ${ORTHANC_ROOT}/Core/RestApi/RestApi.cpp
+    ${ORTHANC_ROOT}/Core/RestApi/RestApiCall.cpp
+    ${ORTHANC_ROOT}/Core/RestApi/RestApiGetCall.cpp
+    ${ORTHANC_ROOT}/Core/RestApi/RestApiHierarchy.cpp
+    ${ORTHANC_ROOT}/Core/RestApi/RestApiOutput.cpp
+    ${ORTHANC_ROOT}/Core/RestApi/RestApiPath.cpp
+    )
+endif()
+
+
+##
+## JPEG support: libjpeg
+##
+
+if (ENABLE_JPEG)
+  include(${CMAKE_CURRENT_LIST_DIR}/LibJpegConfiguration.cmake)
+  add_definitions(-DORTHANC_ENABLE_JPEG=1)
+
+  list(APPEND ORTHANC_CORE_SOURCES_INTERNAL
+    ${ORTHANC_ROOT}/Core/Images/JpegErrorManager.cpp
+    ${ORTHANC_ROOT}/Core/Images/JpegReader.cpp
+    ${ORTHANC_ROOT}/Core/Images/JpegWriter.cpp
+    )
+endif()
+
+
+##
+## PNG support: libpng (in conjunction with zlib)
+##
+
+if (ENABLE_PNG)
+  include(${CMAKE_CURRENT_LIST_DIR}/LibPngConfiguration.cmake)
+  add_definitions(-DORTHANC_ENABLE_PNG=1)
+
+  list(APPEND ORTHANC_CORE_SOURCES_INTERNAL
+    ${ORTHANC_ROOT}/Core/Images/PngReader.cpp
+    ${ORTHANC_ROOT}/Core/Images/PngWriter.cpp
+    )
+endif()
+
+
+##
+## Lua support
+##
+
+if (ENABLE_LUA)
+  include(${CMAKE_CURRENT_LIST_DIR}/LuaConfiguration.cmake)
+  add_definitions(-DORTHANC_ENABLE_LUA=1)
+
+  list(APPEND ORTHANC_CORE_SOURCES_INTERNAL
+    ${ORTHANC_ROOT}/Core/Lua/LuaContext.cpp
+    ${ORTHANC_ROOT}/Core/Lua/LuaFunctionCall.cpp
+    )
+endif()
+
+
+##
+## XML support: pugixml
+##
+
+if (ENABLE_PUGIXML)
+  include(${CMAKE_CURRENT_LIST_DIR}/PugixmlConfiguration.cmake)
+  add_definitions(-DORTHANC_ENABLE_PUGIXML=1)
+endif()
+
+
+##
+## Locale support: libiconv
+##
+
+if (ENABLE_LOCALE)
+  include(${CMAKE_CURRENT_LIST_DIR}/LibIconvConfiguration.cmake)
+  add_definitions(-DORTHANC_ENABLE_LOCALE=1)
+endif()
+
+
+##
+## Google Test for unit testing
+##
+
+if (ENABLE_GOOGLE_TEST)
+  include(${CMAKE_CURRENT_LIST_DIR}/GoogleTestConfiguration.cmake)
+endif()
+
+
+
+#####################################################################
+## Inclusion of mandatory third-party dependencies
+#####################################################################
+
+include(${CMAKE_CURRENT_LIST_DIR}/JsonCppConfiguration.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/ZlibConfiguration.cmake)
+
+# We put Boost as the last dependency, as it is the heaviest to
+# configure, which allows to quickly spot problems when configuring
+# static builds in other dependencies
+include(${CMAKE_CURRENT_LIST_DIR}/BoostConfiguration.cmake)
+
+
+#####################################################################
+## Optional configuration of DCMTK
+#####################################################################
+
+if (ENABLE_DCMTK)
+  if (NOT ENABLE_LOCALE)
+    message(FATAL_ERROR "Support for locales must be enabled if enabling DICOM support")
+  endif()
+
+  include(${CMAKE_CURRENT_LIST_DIR}/DcmtkConfiguration.cmake)
+
+  add_definitions(-DORTHANC_ENABLE_DCMTK=1)
+
+  if (ENABLE_DCMTK_JPEG)
+    add_definitions(-DORTHANC_ENABLE_DCMTK_JPEG=1)
+  else()
+    add_definitions(-DORTHANC_ENABLE_DCMTK_JPEG=0)
+  endif()
+
+  if (ENABLE_DCMTK_JPEG_LOSSLESS)
+    add_definitions(-DORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS=1)
+  else()
+    add_definitions(-DORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS=0)
+  endif()
+
+  set(ORTHANC_DICOM_SOURCES_INTERNAL
+    ${ORTHANC_ROOT}/Core/DicomParsing/DicomDirWriter.cpp
+    ${ORTHANC_ROOT}/Core/DicomParsing/DicomModification.cpp
+    ${ORTHANC_ROOT}/Core/DicomParsing/FromDcmtkBridge.cpp
+    ${ORTHANC_ROOT}/Core/DicomParsing/ParsedDicomFile.cpp
+    ${ORTHANC_ROOT}/Core/DicomParsing/ToDcmtkBridge.cpp
+
+    ${ORTHANC_ROOT}/Core/DicomParsing/Internals/DicomFrameIndex.cpp
+    ${ORTHANC_ROOT}/Core/DicomParsing/Internals/DicomImageDecoder.cpp
+    )
+
+  if (ENABLE_DCMTK_NETWORKING)
+    add_definitions(-DORTHANC_ENABLE_DCMTK_NETWORKING=1)
+    list(APPEND ORTHANC_DICOM_SOURCES_INTERNAL
+      ${ORTHANC_ROOT}/Core/DicomNetworking/DicomFindAnswers.cpp
+      ${ORTHANC_ROOT}/Core/DicomNetworking/DicomServer.cpp
+      ${ORTHANC_ROOT}/Core/DicomNetworking/DicomUserConnection.cpp
+      ${ORTHANC_ROOT}/Core/DicomNetworking/RemoteModalityParameters.cpp
+      ${ORTHANC_ROOT}/Core/DicomNetworking/ReusableDicomUserConnection.cpp
+
+      ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/CommandDispatcher.cpp
+      ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/FindScp.cpp
+      ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/MoveScp.cpp
+      ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/StoreScp.cpp
+      )
+  else()
+    add_definitions(-DORTHANC_ENABLE_DCMTK_NETWORKING=0)
+  endif()
+
+  if (STANDALONE_BUILD AND NOT HAS_EMBEDDED_RESOURCES)
+    EmbedResources(
+      ${DCMTK_DICTIONARIES}
+      )
+    list(APPEND ORTHANC_DICOM_SOURCES_DEPENDENCIES
+      ${AUTOGENERATED_SOURCES}
+      )
+  endif()
+endif()
+
+
+#####################################################################
+## Configuration of the C/C++ macros
+#####################################################################
+
+add_definitions(
+  -DORTHANC_DATABASE_VERSION=${ORTHANC_DATABASE_VERSION}
+  -DORTHANC_DEFAULT_DICOM_ENCODING=Encoding_Latin1
+  -DORTHANC_ENABLE_BASE64=1
+  -DORTHANC_ENABLE_MD5=1
+  -DORTHANC_MAXIMUM_TAG_LENGTH=256
+  -DORTHANC_VERSION="${ORTHANC_VERSION}"
+  )
+
+
+if (ORTHANC_SANDBOXED)
+  add_definitions(
+    -DORTHANC_SANDBOXED=1
+    -DORTHANC_ENABLE_LOGGING=0
+    -DORTHANC_ENABLE_LOGGING_PLUGIN=0
+    )
+  
+else()
+  add_definitions(
+    -DORTHANC_SANDBOXED=0
+    -DORTHANC_ENABLE_LOGGING=1
+    -DORTHANC_ENABLE_LOGGING_PLUGIN=0
+    )
+  
+  list(APPEND ORTHANC_CORE_SOURCES_INTERNAL
+    ${ORTHANC_ROOT}/Core/Cache/SharedArchive.cpp
+    ${ORTHANC_ROOT}/Core/FileStorage/FilesystemStorage.cpp
+    ${ORTHANC_ROOT}/Core/FileStorage/StorageAccessor.cpp
+    ${ORTHANC_ROOT}/Core/MultiThreading/BagOfTasksProcessor.cpp
+    ${ORTHANC_ROOT}/Core/MultiThreading/Mutex.cpp
+    ${ORTHANC_ROOT}/Core/MultiThreading/ReaderWriterLock.cpp
+    ${ORTHANC_ROOT}/Core/MultiThreading/RunnableWorkersPool.cpp
+    ${ORTHANC_ROOT}/Core/MultiThreading/Semaphore.cpp
+    ${ORTHANC_ROOT}/Core/MultiThreading/SharedMessageQueue.cpp
+    ${ORTHANC_ROOT}/Core/SystemToolbox.cpp
+    ${ORTHANC_ROOT}/Core/TemporaryFile.cpp
+    )
+endif()
+
+
+if (HAS_EMBEDDED_RESOURCES)
+  add_definitions(-DORTHANC_HAS_EMBEDDED_RESOURCES=1)
+
+  list(APPEND ORTHANC_CORE_SOURCES_INTERNAL
+    ${ORTHANC_ROOT}/Core/HttpServer/EmbeddedResourceHttpHandler.cpp
+    )
+else()
+  add_definitions(-DORTHANC_HAS_EMBEDDED_RESOURCES=0)
+endif()
+
+
+#####################################################################
+## Gathering of all the source code
+#####################################################################
+
+# The "xxx_INTERNAL" variables list the source code that belongs to
+# the Orthanc project. It can be used to configure precompiled headers
+# if using Microsoft Visual Studio.
+
+# The "xxx_DEPENDENCIES" variables list the source code coming from
+# third-party dependencies.
+
+
+set(ORTHANC_CORE_SOURCES_DEPENDENCIES
+  ${BOOST_SOURCES}
+  ${CIVETWEB_SOURCES}
+  ${CURL_SOURCES}
+  ${JSONCPP_SOURCES}
+  ${LIBICONV_SOURCES}
+  ${LIBJPEG_SOURCES}
+  ${LIBP11_SOURCES}
+  ${LIBPNG_SOURCES}
+  ${LUA_SOURCES}
+  ${MONGOOSE_SOURCES}
+  ${OPENSSL_SOURCES}
+  ${PUGIXML_SOURCES}
+  ${SQLITE_SOURCES}
+  ${ZLIB_SOURCES}
+
+  ${ORTHANC_ROOT}/Resources/ThirdParty/md5/md5.c
+  ${ORTHANC_ROOT}/Resources/ThirdParty/base64/base64.cpp
+
+  # This is the minizip distribution to create ZIP files using zlib
+  ${ORTHANC_ROOT}/Resources/ThirdParty/minizip/ioapi.c
+  ${ORTHANC_ROOT}/Resources/ThirdParty/minizip/zip.c
+  )  
+
+set(ORTHANC_CORE_SOURCES
+  ${ORTHANC_CORE_SOURCES_INTERNAL}
+  ${ORTHANC_CORE_SOURCES_DEPENDENCIES}
+  )
+
+if (ENABLE_DCMTK)
+  list(APPEND ORTHANC_DICOM_SOURCES_DEPENDENCIES
+    ${DCMTK_SOURCES}
+    )
+  
+  set(ORTHANC_DICOM_SOURCES
+    ${ORTHANC_DICOM_SOURCES_INTERNAL}
+    ${ORTHANC_DICOM_SOURCES_DEPENDENCIES}
+    )
+endif()
diff --git a/Resources/CMake/OrthancFrameworkParameters.cmake b/Resources/CMake/OrthancFrameworkParameters.cmake
new file mode 100644
index 0000000..9888e11
--- /dev/null
+++ b/Resources/CMake/OrthancFrameworkParameters.cmake
@@ -0,0 +1,96 @@
+#####################################################################
+## Versioning information
+#####################################################################
+
+# Version of the build, should always be "mainline" except in release branches
+set(ORTHANC_VERSION "1.3.1")
+
+# Version of the database schema. History:
+#   * Orthanc 0.1.0 -> Orthanc 0.3.0 = no versioning
+#   * Orthanc 0.3.1                  = version 2
+#   * Orthanc 0.4.0 -> Orthanc 0.7.2 = version 3
+#   * Orthanc 0.7.3 -> Orthanc 0.8.4 = version 4
+#   * Orthanc 0.8.5 -> Orthanc 0.9.4 = version 5
+#   * Orthanc 0.9.5 -> mainline      = version 6
+set(ORTHANC_DATABASE_VERSION 6)
+
+
+#####################################################################
+## CMake parameters tunable by the user
+#####################################################################
+
+# Support of static compilation
+set(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages")
+set(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)")
+set(STANDALONE_BUILD ON CACHE BOOL "Standalone build (all the resources are embedded, necessary for releases)")
+
+# Generic parameters of the build
+set(ENABLE_CIVETWEB OFF CACHE BOOL "Use Civetweb instead of Mongoose (experimental)")
+set(ENABLE_PKCS11 OFF CACHE BOOL "Enable PKCS#11 for HTTPS client authentication using hardware security modules and smart cards")
+set(ENABLE_PROFILING OFF CACHE BOOL "Whether to enable the generation of profiling information with gprof")
+set(ENABLE_SSL ON CACHE BOOL "Include support for SSL")
+
+# Parameters to fine-tune linking against system libraries
+set(USE_SYSTEM_BOOST ON CACHE BOOL "Use the system version of Boost")
+set(USE_SYSTEM_CIVETWEB ON CACHE BOOL "Use the system version of Civetweb (experimental)")
+set(USE_SYSTEM_CURL ON CACHE BOOL "Use the system version of LibCurl")
+set(USE_SYSTEM_GOOGLE_TEST ON CACHE BOOL "Use the system version of Google Test")
+set(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp")
+set(USE_SYSTEM_LIBICONV ON CACHE BOOL "Use the system version of libiconv")
+set(USE_SYSTEM_LIBJPEG ON CACHE BOOL "Use the system version of libjpeg")
+set(USE_SYSTEM_LIBP11 OFF CACHE BOOL "Use the system version of libp11 (PKCS#11 wrapper library)")
+set(USE_SYSTEM_LIBPNG ON CACHE BOOL "Use the system version of libpng")
+set(USE_SYSTEM_LUA ON CACHE BOOL "Use the system version of Lua")
+set(USE_SYSTEM_MONGOOSE ON CACHE BOOL "Use the system version of Mongoose")
+set(USE_SYSTEM_OPENSSL ON CACHE BOOL "Use the system version of OpenSSL")
+set(USE_SYSTEM_PUGIXML ON CACHE BOOL "Use the system version of Pugixml")
+set(USE_SYSTEM_SQLITE ON CACHE BOOL "Use the system version of SQLite")
+set(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib")
+
+# Parameters specific to DCMTK
+set(DCMTK_DICTIONARY_DIR "" CACHE PATH "Directory containing the DCMTK dictionaries \"dicom.dic\" and \"private.dic\" (only when using system version of DCMTK)") 
+set(USE_DCMTK_360 OFF CACHE BOOL "Use older DCMTK version 3.6.0 in static builds (instead of default 3.6.2)")
+set(USE_DCMTK_362_PRIVATE_DIC ON CACHE BOOL "Use the dictionary of private tags from DCMTK 3.6.2 if using DCMTK 3.6.0")
+set(USE_SYSTEM_DCMTK ON CACHE BOOL "Use the system version of DCMTK")
+set(ENABLE_DCMTK_JPEG ON CACHE BOOL "Enable JPEG-LS (Lossless) decompression")
+set(ENABLE_DCMTK_JPEG_LOSSLESS ON CACHE BOOL "Enable JPEG-LS (Lossless) decompression")
+
+# Advanced and distribution-specific parameters
+set(USE_GOOGLE_TEST_DEBIAN_PACKAGE OFF CACHE BOOL "Use the sources of Google Test shipped with libgtest-dev (Debian only)")
+set(SYSTEM_MONGOOSE_USE_CALLBACKS ON CACHE BOOL "The system version of Mongoose uses callbacks (version >= 3.7)")
+set(USE_BOOST_ICONV ON CACHE BOOL "Use iconv instead of wconv (Windows only)")
+set(USE_PUGIXML ON CACHE BOOL "Use the Pugixml parser (turn off only for debug)")
+
+mark_as_advanced(USE_GOOGLE_TEST_DEBIAN_PACKAGE)
+mark_as_advanced(SYSTEM_MONGOOSE_USE_CALLBACKS)
+mark_as_advanced(USE_BOOST_ICONV)
+mark_as_advanced(USE_PUGIXML)
+
+
+#####################################################################
+## Internal CMake parameters to enable the optional subcomponents of
+## the Orthanc framework
+#####################################################################
+
+# These options must be set to "ON" if compiling Orthanc, but might be
+# set to "OFF" by third-party projects if their associated features
+# are not required
+
+set(ENABLE_CRYPTO_OPTIONS OFF CACHE INTERNAL "Show options related to cryptography")
+set(ENABLE_JPEG OFF CACHE INTERNAL "Enable support of JPEG")
+set(ENABLE_GOOGLE_TEST OFF CACHE INTERNAL "Enable support of Google Test")
+set(ENABLE_LOCALE OFF CACHE INTERNAL "Enable support for locales (notably in Boost)")
+set(ENABLE_LUA OFF CACHE INTERNAL "Enable support of Lua scripting")
+set(ENABLE_PNG OFF CACHE INTERNAL "Enable support of PNG")
+set(ENABLE_PUGIXML OFF CACHE INTERNAL "Enable support of XML through Pugixml")
+set(ENABLE_SQLITE OFF CACHE INTERNAL "Enable support of SQLite databases")
+set(ENABLE_WEB_CLIENT OFF CACHE INTERNAL "Enable Web client")
+set(ENABLE_WEB_SERVER OFF CACHE INTERNAL "Enable embedded Web server")
+set(ENABLE_DCMTK OFF CACHE INTERNAL "Enable DCMTK")
+set(ENABLE_DCMTK_NETWORKING OFF CACHE INTERNAL "Enable DICOM networking in DCMTK")
+
+set(HAS_EMBEDDED_RESOURCES OFF CACHE INTERNAL
+  "Whether resources are auto-generated using EmbedResources.py")
+
+set(ORTHANC_SANDBOXED OFF CACHE INTERNAL
+  "Whether Orthanc runs inside a sandboxed environment (such as Google NaCl or WebAssembly)")
diff --git a/Resources/CMake/PugixmlConfiguration.cmake b/Resources/CMake/PugixmlConfiguration.cmake
index 4d57b12..8b2715a 100644
--- a/Resources/CMake/PugixmlConfiguration.cmake
+++ b/Resources/CMake/PugixmlConfiguration.cmake
@@ -1,33 +1,26 @@
-if (USE_PUGIXML)
-  add_definitions(-DORTHANC_ENABLE_PUGIXML=1)
+if (STATIC_BUILD OR NOT USE_SYSTEM_PUGIXML)
+  set(PUGIXML_SOURCES_DIR ${CMAKE_BINARY_DIR}/pugixml-1.4)
+  set(PUGIXML_MD5 "7c56c91cfe3ecdee248a8e4892ef5781")
+  set(PUGIXML_URL "http://www.orthanc-server.com/downloads/third-party/pugixml-1.4.tar.gz")
 
-  if (STATIC_BUILD OR NOT USE_SYSTEM_PUGIXML)
-    set(PUGIXML_SOURCES_DIR ${CMAKE_BINARY_DIR}/pugixml-1.4)
-    set(PUGIXML_MD5 "7c56c91cfe3ecdee248a8e4892ef5781")
-    set(PUGIXML_URL "http://www.orthanc-server.com/downloads/third-party/pugixml-1.4.tar.gz")
+  DownloadPackage(${PUGIXML_MD5} ${PUGIXML_URL} "${PUGIXML_SOURCES_DIR}")
 
-    DownloadPackage(${PUGIXML_MD5} ${PUGIXML_URL} "${PUGIXML_SOURCES_DIR}")
+  include_directories(
+    ${PUGIXML_SOURCES_DIR}/src
+    )
 
-    include_directories(
-      ${PUGIXML_SOURCES_DIR}/src
-      )
-
-    set(PUGIXML_SOURCES
-      #${PUGIXML_SOURCES_DIR}/src/vlog_is_on.cc
-      ${PUGIXML_SOURCES_DIR}/src/pugixml.cpp
-      )
-
-  else()
-    CHECK_INCLUDE_FILE_CXX(pugixml.hpp HAVE_PUGIXML_H)
-    if (NOT HAVE_PUGIXML_H)
-      message(FATAL_ERROR "Please install the libpugixml-dev package")
-    endif()
-
-    link_libraries(pugixml)
-  endif()
+  set(PUGIXML_SOURCES
+    #${PUGIXML_SOURCES_DIR}/src/vlog_is_on.cc
+    ${PUGIXML_SOURCES_DIR}/src/pugixml.cpp
+    )
 
   source_group(ThirdParty\\pugixml REGULAR_EXPRESSION ${PUGIXML_SOURCES_DIR}/.*)
 
 else()
-  add_definitions(-DORTHANC_ENABLE_PUGIXML=0)
+  CHECK_INCLUDE_FILE_CXX(pugixml.hpp HAVE_PUGIXML_H)
+  if (NOT HAVE_PUGIXML_H)
+    message(FATAL_ERROR "Please install the libpugixml-dev package")
+  endif()
+
+  link_libraries(pugixml)
 endif()
diff --git a/Resources/CMake/SQLiteConfiguration.cmake b/Resources/CMake/SQLiteConfiguration.cmake
index 49ae259..6abec71 100644
--- a/Resources/CMake/SQLiteConfiguration.cmake
+++ b/Resources/CMake/SQLiteConfiguration.cmake
@@ -15,11 +15,11 @@ endif()
 
 
 if (SQLITE_STATIC)
-  SET(SQLITE_SOURCES_DIR ${CMAKE_BINARY_DIR}/sqlite-amalgamation-3071300)
-  SET(SQLITE_MD5 "5fbeff9645ab035a1f580e90b279a16d")
-  SET(SQLITE_URL "http://www.orthanc-server.com/downloads/third-party/sqlite-amalgamation-3071300.zip")
+  SET(SQLITE_SOURCES_DIR ${CMAKE_BINARY_DIR}/sqlite-amalgamation-3210000)
+  SET(SQLITE_MD5 "fe330e88d81e77e1e61554a370ae5001")
+  SET(SQLITE_URL "http://www.orthanc-server.com/downloads/third-party/sqlite-amalgamation-3210000.zip")
 
-  add_definitions(-DORTHANC_SQLITE_VERSION=3007013)
+  add_definitions(-DORTHANC_SQLITE_VERSION=3021000)
 
   DownloadPackage(${SQLITE_MD5} ${SQLITE_URL} "${SQLITE_SOURCES_DIR}")
 
diff --git a/Resources/CMake/VisualStudioPrecompiledHeaders.cmake b/Resources/CMake/VisualStudioPrecompiledHeaders.cmake
index 08e59a6..eb1df19 100644
--- a/Resources/CMake/VisualStudioPrecompiledHeaders.cmake
+++ b/Resources/CMake/VisualStudioPrecompiledHeaders.cmake
@@ -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 @@ macro(ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS PrecompiledHeaders PrecompiledSource
     PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeaders}\" /FI\"${PrecompiledHeaders}\" /Fp\"${PrecompiledBinary}\""
     OBJECT_DEPENDS "${PrecompiledBinary}")
 
-  list(APPEND ${Sources} ${PrecompiledSource})
+  set(${Target} ${PrecompiledSource})
 endmacro()
diff --git a/Resources/CMake/ZlibConfiguration.cmake b/Resources/CMake/ZlibConfiguration.cmake
index 4487c1e..84f1e3e 100644
--- a/Resources/CMake/ZlibConfiguration.cmake
+++ b/Resources/CMake/ZlibConfiguration.cmake
@@ -29,6 +29,15 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_ZLIB)
 
   source_group(ThirdParty\\zlib REGULAR_EXPRESSION ${ZLIB_SOURCES_DIR}/.*)
 
+  if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR
+      ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
+    # "ioapi.c" from zlib (minizip) expects the "IOAPI_NO_64" macro to be set to "true"
+    # https://ohse.de/uwe/articles/lfs.html
+    add_definitions(
+      -DIOAPI_NO_64=1
+      )
+  endif()
+
 else()
   include(FindZLIB)
   include_directories(${ZLIB_INCLUDE_DIRS})
diff --git a/Resources/Configuration.json b/Resources/Configuration.json
index 069c6cd..1bd93b5 100644
--- a/Resources/Configuration.json
+++ b/Resources/Configuration.json
@@ -171,6 +171,12 @@
     // "clearcanvas" : [ "CLEARCANVAS", "192.168.1.1", 104, "ClearCanvas" ]
   },
 
+  // Whether the Orthanc SCP allows incoming C-Echo requests, even
+  // from SCU modalities it does not know about (i.e. that are not
+  // listed in the "DicomModalities" option above). Orthanc 1.3.0
+  // is the only version to behave as if this argument was set to "false".
+  "DicomAlwaysAllowEcho" : true,
+
   // Whether the Orthanc SCP allows incoming C-Store requests, even
   // from SCU modalities it does not know about (i.e. that are not
   // listed in the "DicomModalities" option above)
diff --git a/Resources/OldBuildInstructions.txt b/Resources/OldBuildInstructions.txt
index 3c390f7..9167bcc 100644
--- a/Resources/OldBuildInstructions.txt
+++ b/Resources/OldBuildInstructions.txt
@@ -32,7 +32,7 @@ Debian Wheezy (7.x)
 # cmake -DALLOW_DOWNLOADS=ON \
         -DUSE_SYSTEM_GOOGLE_LOG=OFF \
 	-DUSE_SYSTEM_MONGOOSE=OFF \
-        -DUSE_GTEST_DEBIAN_SOURCE_PACKAGE=ON \
+        -DUSE_GOOGLE_TEST_DEBIAN_PACKAGE=ON \
 	-DUSE_SYSTEM_PUGIXML=OFF \
         -DENABLE_JPEG=OFF \
         -DENABLE_JPEG_LOSSLESS=OFF \
@@ -55,7 +55,7 @@ With JPEG:
         -DALLOW_DOWNLOADS=ON \
 	-DUSE_SYSTEM_MONGOOSE=OFF \
 	-DUSE_SYSTEM_JSONCPP=OFF \
-        -DUSE_GTEST_DEBIAN_SOURCE_PACKAGE=ON \
+        -DUSE_GOOGLE_TEST_DEBIAN_PACKAGE=ON \
 	-DUSE_SYSTEM_PUGIXML=OFF \
 	~/Orthanc
 
@@ -66,7 +66,7 @@ Without JPEG:
         -DALLOW_DOWNLOADS=ON \
 	-DUSE_SYSTEM_MONGOOSE=OFF \
 	-DUSE_SYSTEM_JSONCPP=OFF \
-        -DUSE_GTEST_DEBIAN_SOURCE_PACKAGE=ON \
+        -DUSE_GOOGLE_TEST_DEBIAN_PACKAGE=ON \
 	-DUSE_SYSTEM_PUGIXML=OFF \
         -DENABLE_JPEG=OFF \
         -DENABLE_JPEG_LOSSLESS=OFF \
@@ -85,7 +85,7 @@ SUPPORTED - Ubuntu 13.10
 # cmake "-DDCMTK_LIBRARIES=wrap;oflog" \
         -DALLOW_DOWNLOADS=ON \
 	-DUSE_SYSTEM_MONGOOSE=OFF \
-        -DUSE_GTEST_DEBIAN_SOURCE_PACKAGE=ON \
+        -DUSE_GOOGLE_TEST_DEBIAN_PACKAGE=ON \
 	-DUSE_SYSTEM_PUGIXML=OFF \
         -DENABLE_JPEG=OFF \
         -DENABLE_JPEG_LOSSLESS=OFF \
diff --git a/Resources/Samples/OrthancFramework/MicroService/CMakeLists.txt b/Resources/Samples/OrthancFramework/MicroService/CMakeLists.txt
new file mode 100644
index 0000000..6dfd7b6
--- /dev/null
+++ b/Resources/Samples/OrthancFramework/MicroService/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(Sample)
+
+include(${CMAKE_SOURCE_DIR}/../../../CMake/OrthancFrameworkParameters.cmake)
+
+set(ENABLE_WEB_SERVER ON)
+
+include(${CMAKE_SOURCE_DIR}/../../../CMake/OrthancFrameworkConfiguration.cmake)
+
+add_executable(Sample
+  ${ORTHANC_CORE_SOURCES}
+  Sample.cpp
+  )
+
+include_directories(${ORTHANC_ROOT}/Core)
diff --git a/Resources/Samples/OrthancFramework/MicroService/README.txt b/Resources/Samples/OrthancFramework/MicroService/README.txt
new file mode 100644
index 0000000..a92d992
--- /dev/null
+++ b/Resources/Samples/OrthancFramework/MicroService/README.txt
@@ -0,0 +1,2 @@
+This file shows how to create a simple Web service in C++ (similar to
+Python's Flask) using the Orthanc standalone framework.
diff --git a/Resources/Samples/OrthancFramework/MicroService/Sample.cpp b/Resources/Samples/OrthancFramework/MicroService/Sample.cpp
new file mode 100644
index 0000000..5736b16
--- /dev/null
+++ b/Resources/Samples/OrthancFramework/MicroService/Sample.cpp
@@ -0,0 +1,61 @@
+#include <stdio.h>
+
+#include <HttpServer/MongooseServer.h>
+#include <Logging.h>
+#include <RestApi/RestApi.h>
+#include <SystemToolbox.h>
+
+class MicroService : public Orthanc::RestApi
+{
+private:
+  static MicroService& GetSelf(Orthanc::RestApiCall& call)
+  {
+    return dynamic_cast<MicroService&>(call.GetContext());
+  }
+
+  void SayHello()
+  {
+    printf("Hello\n");
+  }
+
+  static void Hello(Orthanc::RestApiGetCall& call)
+  {
+    GetSelf(call).SayHello();
+    
+    Json::Value value = Json::arrayValue;
+    value.append("World");
+    
+    call.GetOutput().AnswerJson(value);
+  }
+
+public:
+  MicroService()
+  {
+    Register("/hello", Hello);
+  }  
+};
+
+int main()
+{
+  Orthanc::Logging::Initialize();
+  Orthanc::Logging::EnableTraceLevel(true);
+
+  MicroService rest;
+  
+  {
+    Orthanc::MongooseServer httpServer;
+    httpServer.SetPortNumber(8000);
+    httpServer.Register(rest);
+    httpServer.SetRemoteAccessAllowed(true);
+    httpServer.Start();
+    
+    LOG(WARNING) << "Micro-service started on port " << httpServer.GetPortNumber();
+    Orthanc::SystemToolbox::ServerBarrier();
+  }
+
+  LOG(WARNING) << "Micro-service stopped";
+
+  Orthanc::Logging::Finalize();
+  
+  return 0;
+}
diff --git a/Resources/Samples/Tools/CMakeLists.txt b/Resources/Samples/Tools/CMakeLists.txt
index c426f5e..408d890 100644
--- a/Resources/Samples/Tools/CMakeLists.txt
+++ b/Resources/Samples/Tools/CMakeLists.txt
@@ -8,32 +8,18 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
   link_libraries(pthread dl)
 endif()
 
+include(${CMAKE_SOURCE_DIR}/../../CMake/OrthancFrameworkParameters.cmake)
+
 set(STATIC_BUILD ON)
 set(ALLOW_DOWNLOADS ON)
 
-set(ORTHANC_ROOT ${CMAKE_SOURCE_DIR}/../../..)
-
-include(CheckIncludeFiles)
-include(CheckIncludeFileCXX)
-include(CheckLibraryExists)
-include(${ORTHANC_ROOT}/Resources/CMake/Compiler.cmake)
-include(${ORTHANC_ROOT}/Resources/CMake/DownloadPackage.cmake)
-include(${ORTHANC_ROOT}/Resources/CMake/BoostConfiguration.cmake)
-include(${ORTHANC_ROOT}/Resources/CMake/ZlibConfiguration.cmake)
-include(${ORTHANC_ROOT}/Resources/CMake/JsonCppConfiguration.cmake)
-
-add_definitions(
-  -DORTHANC_ENABLE_BASE64=0
-  -DORTHANC_ENABLE_MD5=0
-  -DORTHANC_ENABLE_PUGIXML=0
-  -DORTHANC_ENABLE_LOGGING=0
-  -DORTHANC_SANDBOXED=0
-  )
+include(${CMAKE_SOURCE_DIR}/../../CMake/OrthancFrameworkConfiguration.cmake)
 
 add_library(CommonLibraries
   ${BOOST_SOURCES}
   ${JSONCPP_SOURCES}
   ${ORTHANC_ROOT}/Core/Enumerations.cpp
+  ${ORTHANC_ROOT}/Core/Logging.cpp
   ${ORTHANC_ROOT}/Core/SystemToolbox.cpp
   ${ORTHANC_ROOT}/Core/Toolbox.cpp
   ${ORTHANC_ROOT}/Resources/ThirdParty/md5/md5.c
diff --git a/TODO b/TODO
index 55a0c8b..019b512 100644
--- a/TODO
+++ b/TODO
@@ -20,6 +20,15 @@ General
 * Option to enable DNS lookups in DICOM: https://goo.gl/woa35Z
 
 
+============
+Dependencies
+============
+
+* Switch from libiconv to libICU (http://site.icu-project.org/download),
+  as recommended by Boost:
+  http://www.boost.org/doc/libs/1_64_0/libs/locale/doc/html/building_boost_locale.html
+
+
 ========
 REST API
 ========
@@ -67,6 +76,8 @@ Long-term
 * Support DICOM TLS (cf. "--enable-tls" in storescp)
 * Support Storage Commitment:
   https://groups.google.com/forum/#!msg/orthanc-users/VZOn8St65jw/s8kg_OHesj0J
+* Support extended association:
+  https://groups.google.com/d/msg/orthanc-users/xD4d3mpc6ms/srF7E2goAAAJ
 
 
 =======
diff --git a/UnitTestsSources/DicomMapTests.cpp b/UnitTestsSources/DicomMapTests.cpp
index 2aeb047..03d37d4 100644
--- a/UnitTestsSources/DicomMapTests.cpp
+++ b/UnitTestsSources/DicomMapTests.cpp
@@ -36,7 +36,7 @@
 
 #include "../Core/OrthancException.h"
 #include "../Core/DicomFormat/DicomMap.h"
-#include "../OrthancServer/FromDcmtkBridge.h"
+#include "../Core/DicomParsing/FromDcmtkBridge.h"
 
 #include <memory>
 
@@ -220,3 +220,151 @@ TEST(DicomMap, Modules)
   TestModule(ResourceType_Series, DicomModule_Series);   // TODO
   TestModule(ResourceType_Instance, DicomModule_Instance);
 }
+
+
+TEST(DicomMap, Parse)
+{
+  DicomMap m;
+  float f;
+  double d;
+  int32_t i;
+  int64_t j;
+  uint32_t k;
+  uint64_t l;
+  std::string s;
+  
+  m.SetValue(DICOM_TAG_PATIENT_NAME, "      ", false);  // Empty value
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l));
+  
+  m.SetValue(DICOM_TAG_PATIENT_NAME, "0", true);  // Binary value
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l));
+
+  ASSERT_FALSE(m.CopyToString(s, DICOM_TAG_PATIENT_NAME, false));
+  ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_PATIENT_NAME, true));
+  ASSERT_EQ("0", s);
+               
+
+  // 2**31-1
+  m.SetValue(DICOM_TAG_PATIENT_NAME, "2147483647", false);
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l));
+  ASSERT_FLOAT_EQ(2147483647.0f, f);
+  ASSERT_DOUBLE_EQ(2147483647.0, d);
+  ASSERT_EQ(2147483647, i);
+  ASSERT_EQ(2147483647ll, j);
+  ASSERT_EQ(2147483647u, k);
+  ASSERT_EQ(2147483647ull, l);
+
+  // Test shortcuts
+  m.SetValue(DICOM_TAG_PATIENT_NAME, "42", false);
+  ASSERT_TRUE(m.ParseFloat(f, DICOM_TAG_PATIENT_NAME));
+  ASSERT_TRUE(m.ParseDouble(d, DICOM_TAG_PATIENT_NAME));
+  ASSERT_TRUE(m.ParseInteger32(i, DICOM_TAG_PATIENT_NAME));
+  ASSERT_TRUE(m.ParseInteger64(j, DICOM_TAG_PATIENT_NAME));
+  ASSERT_TRUE(m.ParseUnsignedInteger32(k, DICOM_TAG_PATIENT_NAME));
+  ASSERT_TRUE(m.ParseUnsignedInteger64(l, DICOM_TAG_PATIENT_NAME));
+  ASSERT_FLOAT_EQ(42.0f, f);
+  ASSERT_DOUBLE_EQ(42.0, d);
+  ASSERT_EQ(42, i);
+  ASSERT_EQ(42ll, j);
+  ASSERT_EQ(42u, k);
+  ASSERT_EQ(42ull, l);
+
+  ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_PATIENT_NAME, false));
+  ASSERT_EQ("42", s);
+  ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_PATIENT_NAME, true));
+  ASSERT_EQ("42", s);
+               
+  
+  // 2**31
+  m.SetValue(DICOM_TAG_PATIENT_NAME, "2147483648", false);
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l));
+  ASSERT_FLOAT_EQ(2147483648.0f, f);
+  ASSERT_DOUBLE_EQ(2147483648.0, d);
+  ASSERT_EQ(2147483648ll, j);
+  ASSERT_EQ(2147483648u, k);
+  ASSERT_EQ(2147483648ull, l);
+
+  // 2**32-1
+  m.SetValue(DICOM_TAG_PATIENT_NAME, "4294967295", false);
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l));
+  ASSERT_FLOAT_EQ(4294967295.0f, f);
+  ASSERT_DOUBLE_EQ(4294967295.0, d);
+  ASSERT_EQ(4294967295ll, j);
+  ASSERT_EQ(4294967295u, k);
+  ASSERT_EQ(4294967295ull, l);
+  
+  // 2**32
+  m.SetValue(DICOM_TAG_PATIENT_NAME, "4294967296", false);
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l));
+  ASSERT_FLOAT_EQ(4294967296.0f, f);
+  ASSERT_DOUBLE_EQ(4294967296.0, d);
+  ASSERT_EQ(4294967296ll, j);
+  ASSERT_EQ(4294967296ull, l);
+  
+  m.SetValue(DICOM_TAG_PATIENT_NAME, "-1", false);
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l));
+  ASSERT_FLOAT_EQ(-1.0f, f);
+  ASSERT_DOUBLE_EQ(-1.0, d);
+  ASSERT_EQ(-1, i);
+  ASSERT_EQ(-1ll, j);
+
+  // -2**31
+  m.SetValue(DICOM_TAG_PATIENT_NAME, "-2147483648", false);
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l));
+  ASSERT_FLOAT_EQ(-2147483648.0f, f);
+  ASSERT_DOUBLE_EQ(-2147483648.0, d); 
+  ASSERT_EQ(-2147483648, i);
+  ASSERT_EQ(-2147483648ll, j);
+  
+  // -2**31 - 1
+  m.SetValue(DICOM_TAG_PATIENT_NAME, "-2147483649", false);
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseFloat(f));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseDouble(d));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger32(i));
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseInteger64(j));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k));
+  ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l));
+  ASSERT_FLOAT_EQ(-2147483649.0f, f);
+  ASSERT_DOUBLE_EQ(-2147483649.0, d); 
+  ASSERT_EQ(-2147483649ll, j);
+}
diff --git a/UnitTestsSources/FromDcmtkTests.cpp b/UnitTestsSources/FromDcmtkTests.cpp
index 57f9aeb..d0eeecc 100644
--- a/UnitTestsSources/FromDcmtkTests.cpp
+++ b/UnitTestsSources/FromDcmtkTests.cpp
@@ -34,10 +34,9 @@
 #include "PrecompiledHeadersUnitTests.h"
 #include "gtest/gtest.h"
 
-#include "../OrthancServer/FromDcmtkBridge.h"
-#include "../OrthancServer/ToDcmtkBridge.h"
-#include "../OrthancServer/OrthancInitialization.h"
-#include "../OrthancServer/DicomModification.h"
+#include "../Core/DicomParsing/FromDcmtkBridge.h"
+#include "../Core/DicomParsing/ToDcmtkBridge.h"
+#include "../Core/DicomParsing/DicomModification.h"
 #include "../OrthancServer/ServerToolbox.h"
 #include "../Core/OrthancException.h"
 #include "../Core/Images/ImageBuffer.h"
@@ -47,8 +46,8 @@
 #include "../Core/Images/ImageProcessing.h"
 #include "../Core/Endianness.h"
 #include "../Resources/EncodingTests.h"
-#include "../OrthancServer/DicomProtocol/DicomFindAnswers.h"
-#include "../OrthancServer/Internals/DicomImageDecoder.h"
+#include "../Core/DicomNetworking/DicomFindAnswers.h"
+#include "../Core/DicomParsing/Internals/DicomImageDecoder.h"
 #include "../Plugins/Engine/PluginsEnumerations.h"
 
 #include <dcmtk/dcmdata/dcelem.h>
@@ -264,6 +263,7 @@ TEST(FromDcmtkBridge, Enumerations)
   // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#table_C.12-5
   ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 192"));  ASSERT_EQ(Encoding_Utf8, e);
   ASSERT_TRUE(GetDicomEncoding(e, "GB18030"));     ASSERT_EQ(Encoding_Chinese, e);
+  ASSERT_TRUE(GetDicomEncoding(e, "GBK"));         ASSERT_EQ(Encoding_Chinese, e);
 }
 
 
@@ -395,7 +395,28 @@ namespace Orthanc
       element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8));
 
       Json::Value b;
-      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+      std::set<DicomTag> ignoreTagLength;
+      ignoreTagLength.insert(DICOM_TAG_PATIENT_ID);
+
+      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short,
+                                     DicomToJsonFlags_Default, 0, Encoding_Ascii, ignoreTagLength);
+      ASSERT_TRUE(b.isMember("0010,0010"));
+      ASSERT_EQ("Hello", b["0010,0010"].asString());
+
+      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short,
+                                     DicomToJsonFlags_Default, 3, Encoding_Ascii, ignoreTagLength);
+      ASSERT_TRUE(b["0010,0010"].isNull()); // "Hello" has more than 3 characters
+
+      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Full,
+                                     DicomToJsonFlags_Default, 3, Encoding_Ascii, ignoreTagLength);
+      ASSERT_TRUE(b["0010,0010"].isObject());
+      ASSERT_EQ("PatientName", b["0010,0010"]["Name"].asString());
+      ASSERT_EQ("TooLong", b["0010,0010"]["Type"].asString());
+      ASSERT_TRUE(b["0010,0010"]["Value"].isNull());
+
+      ignoreTagLength.insert(DICOM_TAG_PATIENT_NAME);
+      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short,
+                                     DicomToJsonFlags_Default, 3, Encoding_Ascii, ignoreTagLength);
       ASSERT_EQ("Hello", b["0010,0010"].asString());
     }
 
@@ -419,7 +440,9 @@ namespace Orthanc
       element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, true, Encoding_Utf8));
 
       Json::Value b;
-      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+      std::set<DicomTag> ignoreTagLength;
+      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short,
+                                     DicomToJsonFlags_Default, 0, Encoding_Ascii, ignoreTagLength);
       ASSERT_EQ("Hello", b["0010,0010"].asString());
     }
 
@@ -430,7 +453,9 @@ namespace Orthanc
 
       {
         Json::Value b;
-        FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+        std::set<DicomTag> ignoreTagLength;
+        FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short,
+                                       DicomToJsonFlags_Default, 0, Encoding_Ascii, ignoreTagLength);
         ASSERT_EQ(Json::arrayValue, b["0008,1110"].type());
         ASSERT_EQ(2u, b["0008,1110"].size());
       
@@ -447,7 +472,9 @@ namespace Orthanc
 
       {
         Json::Value b;
-        FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+        std::set<DicomTag> ignoreTagLength;
+        FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Full,
+                                       DicomToJsonFlags_Default, 0, Encoding_Ascii, ignoreTagLength);
 
         Json::Value c;
         ServerToolbox::SimplifyTags(c, b, DicomToJsonFormat_Human);
@@ -1062,20 +1089,20 @@ static void CheckEncoding(const ParsedDicomFile& dicom,
 
 TEST(ParsedDicomFile, DicomMapEncodings1)
 {
-  Configuration::SetDefaultEncoding(Encoding_Ascii);
-  ASSERT_EQ(Encoding_Ascii, Configuration::GetDefaultEncoding());
+  SetDefaultDicomEncoding(Encoding_Ascii);
+  ASSERT_EQ(Encoding_Ascii, GetDefaultDicomEncoding());
 
   {
     DicomMap m;
     ParsedDicomFile dicom(m);
-    ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+    ASSERT_EQ(1u, dicom.GetDcmtkObject().getDataset()->card());
     CheckEncoding(dicom, Encoding_Ascii);
   }
 
   {
     DicomMap m;
     ParsedDicomFile dicom(m, Encoding_Latin4);
-    ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+    ASSERT_EQ(1u, dicom.GetDcmtkObject().getDataset()->card());
     CheckEncoding(dicom, Encoding_Latin4);
   }
 
@@ -1083,7 +1110,7 @@ TEST(ParsedDicomFile, DicomMapEncodings1)
     DicomMap m;
     m.SetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET, "ISO_IR 148", false);
     ParsedDicomFile dicom(m);
-    ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+    ASSERT_EQ(1u, dicom.GetDcmtkObject().getDataset()->card());
     CheckEncoding(dicom, Encoding_Latin5);
   }
 
@@ -1091,7 +1118,7 @@ TEST(ParsedDicomFile, DicomMapEncodings1)
     DicomMap m;
     m.SetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET, "ISO_IR 148", false);
     ParsedDicomFile dicom(m, Encoding_Latin1);
-    ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+    ASSERT_EQ(1u, dicom.GetDcmtkObject().getDataset()->card());
     CheckEncoding(dicom, Encoding_Latin5);
   }
 }
diff --git a/UnitTestsSources/ImageTests.cpp b/UnitTestsSources/ImageTests.cpp
index 9c9be56..8c72f33 100644
--- a/UnitTestsSources/ImageTests.cpp
+++ b/UnitTestsSources/ImageTests.cpp
@@ -43,7 +43,7 @@
 #include "../Core/Images/PngWriter.h"
 #include "../Core/Toolbox.h"
 #include "../Core/TemporaryFile.h"
-#include "../OrthancServer/OrthancInitialization.h"
+#include "../OrthancServer/OrthancInitialization.h"  // For the FontRegistry
 
 #include <stdint.h>
 
diff --git a/UnitTestsSources/JpegLosslessTests.cpp b/UnitTestsSources/JpegLosslessTests.cpp
index dc5a98f..95dd1ae 100644
--- a/UnitTestsSources/JpegLosslessTests.cpp
+++ b/UnitTestsSources/JpegLosslessTests.cpp
@@ -34,13 +34,13 @@
 #include "PrecompiledHeadersUnitTests.h"
 #include "gtest/gtest.h"
 
-#include "../OrthancServer/Internals/DicomImageDecoder.h"
+#include "../Core/DicomParsing/Internals/DicomImageDecoder.h"
 
 #if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
 
 #include <dcmtk/dcmdata/dcfilefo.h>
 
-#include "../OrthancServer/ParsedDicomFile.h"
+#include "../Core/DicomParsing/ParsedDicomFile.h"
 #include "../Core/OrthancException.h"
 #include "../Core/Images/ImageBuffer.h"
 #include "../Core/Images/PngWriter.h"
diff --git a/UnitTestsSources/LuaTests.cpp b/UnitTestsSources/LuaTests.cpp
index d3beb93..6c759aa 100644
--- a/UnitTestsSources/LuaTests.cpp
+++ b/UnitTestsSources/LuaTests.cpp
@@ -287,9 +287,14 @@ TEST(Lua, Http)
 {
   Orthanc::LuaContext lua;
 
-#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1  
-  lua.Execute("JSON = loadstring(HttpGet('http://www.orthanc-server.com/downloads/third-party/JSON.lua')) ()");
-  const std::string url("http://www.orthanc-server.com/downloads/third-party/Product.json");
+#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1
+  // The "http://www.orthanc-server.com/downloads/third-party/" does
+  // not automatically redirect to HTTPS, so we cas use it even if the
+  // OpenSSL/HTTPS support is disabled in curl
+  const std::string BASE = "http://www.orthanc-server.com/downloads/third-party/";
+
+  lua.Execute("JSON = loadstring(HttpGet('" + BASE + "JSON.lua')) ()");
+  const std::string url(BASE + "Product.json");
 #endif
 
   std::string s;
diff --git a/UnitTestsSources/MultiThreadingTests.cpp b/UnitTestsSources/MultiThreadingTests.cpp
index 0b448b4..64379e4 100644
--- a/UnitTestsSources/MultiThreadingTests.cpp
+++ b/UnitTestsSources/MultiThreadingTests.cpp
@@ -129,7 +129,7 @@ TEST(MultiThreading, ReaderWriterLock)
 
 
 
-#include "../OrthancServer/DicomProtocol/ReusableDicomUserConnection.h"
+#include "../Core/DicomNetworking/ReusableDicomUserConnection.h"
 
 TEST(ReusableDicomUserConnection, DISABLED_Basic)
 {
diff --git a/UnitTestsSources/PluginsTests.cpp b/UnitTestsSources/PluginsTests.cpp
index a2ab865..b11e70f 100644
--- a/UnitTestsSources/PluginsTests.cpp
+++ b/UnitTestsSources/PluginsTests.cpp
@@ -65,8 +65,8 @@ TEST(SharedLibrary, Basic)
   ASSERT_TRUE(l.HasFunction("dlclose"));
   ASSERT_FALSE(l.HasFunction("world"));
 
-#elif defined(__FreeBSD__)
-  // dlopen() in FreeBSD is supplied by libc, libc.so is
+#elif defined(__FreeBSD__) || defined(__OpenBSD__)
+  // dlopen() in FreeBSD/OpenBSD is supplied by libc, libc.so is
   // a ldscript, so we can't actually use it. Use thread
   // library instead - if it works - dlopen() is good.
   SharedLibrary l("libpthread.so");
diff --git a/UnitTestsSources/RestApiTests.cpp b/UnitTestsSources/RestApiTests.cpp
index 7d0b690..8bdf7ff 100644
--- a/UnitTestsSources/RestApiTests.cpp
+++ b/UnitTestsSources/RestApiTests.cpp
@@ -66,8 +66,14 @@ TEST(HttpClient, Basic)
   ASSERT_FALSE(c.IsVerbose());
 
 #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1
+  // The "http://www.orthanc-server.com/downloads/third-party/" does
+  // not automatically redirect to HTTPS, so we cas use it even if the
+  // OpenSSL/HTTPS support is disabled in curl
+  const std::string BASE = "http://www.orthanc-server.com/downloads/third-party/";
+
   Json::Value v;
-  c.SetUrl("http://www.orthanc-server.com/downloads/third-party/Product.json");
+  c.SetUrl(BASE + "Product.json");
+
   c.Apply(v);
   ASSERT_TRUE(v.type() == Json::objectValue);
   ASSERT_TRUE(v.isMember("Description"));
diff --git a/UnitTestsSources/UnitTestsMain.cpp b/UnitTestsSources/UnitTestsMain.cpp
index 775ecc0..3905708 100644
--- a/UnitTestsSources/UnitTestsMain.cpp
+++ b/UnitTestsSources/UnitTestsMain.cpp
@@ -658,7 +658,7 @@ TEST(Toolbox, Enumerations)
 
 
 
-#if defined(__linux__)
+#if defined(__linux__) || defined(__OpenBSD__)
 #include <endian.h>
 #elif defined(__FreeBSD__)
 #include <machine/endian.h>
@@ -700,7 +700,7 @@ TEST(Toolbox, Endianness)
    * FreeBSD.
    **/
   
-#elif defined(__FreeBSD__)
+#elif defined(__FreeBSD__) || defined(__OpenBSD__)
 #  if _BYTE_ORDER == _BIG_ENDIAN
    ASSERT_EQ(Endianness_Big, Toolbox::DetectEndianness());
 #  else // _LITTLE_ENDIAN
@@ -977,7 +977,7 @@ TEST(Toolbox, AccessJson)
   v = Json::objectValue;
   ASSERT_EQ("nope", Toolbox::GetJsonStringField(v, "hello", "nope"));
   ASSERT_EQ(-10, Toolbox::GetJsonIntegerField(v, "hello", -10));
-  ASSERT_EQ(10, Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10));
+  ASSERT_EQ(10u, Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10));
   ASSERT_TRUE(Toolbox::GetJsonBooleanField(v, "hello", true));
 
   v["hello"] = "world";
@@ -995,7 +995,7 @@ TEST(Toolbox, AccessJson)
   v["hello"] = 42;
   ASSERT_THROW(Toolbox::GetJsonStringField(v, "hello", "nope"), OrthancException);
   ASSERT_EQ(42, Toolbox::GetJsonIntegerField(v, "hello", -10));
-  ASSERT_EQ(42, Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10));
+  ASSERT_EQ(42u, Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10));
   ASSERT_THROW(Toolbox::GetJsonBooleanField(v, "hello", true), OrthancException);
 
   v["hello"] = false;
diff --git a/UnitTestsSources/VersionsTests.cpp b/UnitTestsSources/VersionsTests.cpp
index b649b76..a201df0 100644
--- a/UnitTestsSources/VersionsTests.cpp
+++ b/UnitTestsSources/VersionsTests.cpp
@@ -44,6 +44,7 @@
 #include <sqlite3.h>
 #include <lua.h>
 #include <jpeglib.h>
+#include <iconv.h>
 
 #if ORTHANC_ENABLE_SSL == 1
 #include <openssl/opensslv.h>
@@ -103,7 +104,7 @@ TEST(Versions, ZlibStatic)
 
 TEST(Versions, BoostStatic)
 {
-  ASSERT_STREQ("1_64", BOOST_LIB_VERSION);
+  ASSERT_STREQ("1_65_1", BOOST_LIB_VERSION);
 }
 
 TEST(Versions, CurlStatic)
@@ -143,6 +144,13 @@ TEST(Version, LuaStatic)
   ASSERT_STREQ("Lua 5.1.5", LUA_RELEASE);
 }
 
+TEST(Version, LibIconvStatic)
+{
+  static const int major = 1;
+  static const int minor = 15;  
+  ASSERT_EQ((major << 8) + minor, _LIBICONV_VERSION);
+}
+
 
 #if ORTHANC_ENABLE_SSL == 1
 TEST(Version, OpenSslStatic)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/orthanc.git



More information about the debian-med-commit mailing list