changeset 188:a11bf02917e9

sync
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 11 Apr 2018 15:19:24 +0200
parents 4b9da483ae4d
children 56b1894b5619
files Orthanc/Core/DicomFormat/DicomTag.h Orthanc/Core/Enumerations.cpp Orthanc/Core/Enumerations.h Orthanc/Core/Logging.h Orthanc/Core/SystemToolbox.cpp Orthanc/Core/SystemToolbox.h Orthanc/Core/Toolbox.cpp Orthanc/Core/Toolbox.h Orthanc/NEWS Orthanc/Resources/CMake/BoostConfiguration.cmake Orthanc/Resources/CMake/Compiler.cmake Orthanc/Resources/CMake/UuidConfiguration.cmake Orthanc/Resources/LinuxStandardBaseToolchain.cmake Plugin/Cache/CacheManager.cpp Resources/CMake/LinuxStandardBaseToolchain.cmake
diffstat 15 files changed, 428 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/Orthanc/Core/DicomFormat/DicomTag.h	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/Core/DicomFormat/DicomTag.h	Wed Apr 11 15:19:24 2018 +0200
@@ -193,4 +193,14 @@
   static const DicomTag DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES(0x0020, 0x1208);  
   static const DicomTag DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES(0x0020, 0x1209);  
   static const DicomTag DICOM_TAG_SOP_CLASSES_IN_STUDY(0x0008, 0x0062);  
+
+  // Tags to preserve relationships during anonymization
+  static const DicomTag DICOM_TAG_REFERENCED_IMAGE_SEQUENCE(0x0008, 0x1140);
+  static const DicomTag DICOM_TAG_REFERENCED_SOP_INSTANCE_UID(0x0008, 0x1155);
+  static const DicomTag DICOM_TAG_SOURCE_IMAGE_SEQUENCE(0x0008, 0x2112);
+  static const DicomTag DICOM_TAG_FRAME_OF_REFERENCE_UID(0x0020, 0x0052);
+  static const DicomTag DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_UID(0x3006, 0x0024);
+  static const DicomTag DICOM_TAG_RELATED_FRAME_OF_REFERENCE_UID(0x3006, 0x00c2);
+  static const DicomTag DICOM_TAG_CURRENT_REQUESTED_PROCEDURE_EVIDENCE_SEQUENCE(0x0040, 0xa375);
+  static const DicomTag DICOM_TAG_REFERENCED_SERIES_SEQUENCE(0x0008, 0x1115);
 }
--- a/Orthanc/Core/Enumerations.cpp	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/Core/Enumerations.cpp	Wed Apr 11 15:19:24 2018 +0200
@@ -878,6 +878,112 @@
   }
 
 
+  const char* EnumerationToString(ValueRepresentation vr)
+  {
+    switch (vr)
+    {
+      case ValueRepresentation_ApplicationEntity:     // AE
+        return "AE";
+
+      case ValueRepresentation_AgeString:             // AS
+        return "AS";
+
+      case ValueRepresentation_AttributeTag:          // AT (2 x uint16_t)
+        return "AT";
+
+      case ValueRepresentation_CodeString:            // CS
+        return "CS";
+
+      case ValueRepresentation_Date:                  // DA
+        return "DA";
+
+      case ValueRepresentation_DecimalString:         // DS
+        return "DS";
+
+      case ValueRepresentation_DateTime:              // DT
+        return "DT";
+
+      case ValueRepresentation_FloatingPointSingle:   // FL (float)
+        return "FL";
+
+      case ValueRepresentation_FloatingPointDouble:   // FD (double)
+        return "FD";
+
+      case ValueRepresentation_IntegerString:         // IS
+        return "IS";
+
+      case ValueRepresentation_LongString:            // LO
+        return "LO";
+
+      case ValueRepresentation_LongText:              // LT
+        return "LT";
+
+      case ValueRepresentation_OtherByte:             // OB
+        return "OB";
+
+      case ValueRepresentation_OtherDouble:           // OD
+        return "OD";
+
+      case ValueRepresentation_OtherFloat:            // OF
+        return "OF";
+
+      case ValueRepresentation_OtherLong:             // OL
+        return "OL";
+
+      case ValueRepresentation_OtherWord:             // OW
+        return "OW";
+
+      case ValueRepresentation_PersonName:            // PN
+        return "PN";
+
+      case ValueRepresentation_ShortString:           // SH
+        return "SH";
+
+      case ValueRepresentation_SignedLong:            // SL (int32_t)
+        return "SL";
+
+      case ValueRepresentation_Sequence:              // SQ
+        return "SQ";
+
+      case ValueRepresentation_SignedShort:           // SS (int16_t)
+        return "SS";
+
+      case ValueRepresentation_ShortText:             // ST
+        return "ST";
+
+      case ValueRepresentation_Time:                  // TM
+        return "TM";
+
+      case ValueRepresentation_UnlimitedCharacters:   // UC
+        return "UC";
+
+      case ValueRepresentation_UniqueIdentifier:      // UI (UID)
+        return "UI";
+
+      case ValueRepresentation_UnsignedLong:          // UL (uint32_t)
+        return "UL";
+
+      case ValueRepresentation_Unknown:               // UN
+        return "UN";
+
+      case ValueRepresentation_UniversalResource:     // UR (URI or URL)
+        return "UR";
+
+      case ValueRepresentation_UnsignedShort:         // US (uint16_t)
+        return "US";
+
+      case ValueRepresentation_UnlimitedText:         // UT
+        return "UT";
+
+      case ValueRepresentation_NotSupported:
+        return "Not supported";
+
+      default: 
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
   Encoding StringToEncoding(const char* encoding)
   {
     std::string s(encoding);
--- a/Orthanc/Core/Enumerations.h	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/Core/Enumerations.h	Wed Apr 11 15:19:24 2018 +0200
@@ -620,6 +620,8 @@
 
   const char* EnumerationToString(DicomVersion version);
 
+  const char* EnumerationToString(ValueRepresentation vr);
+
   Encoding StringToEncoding(const char* encoding);
 
   ResourceType StringToResourceType(const char* type);
--- a/Orthanc/Core/Logging.h	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/Core/Logging.h	Wed Apr 11 15:19:24 2018 +0200
@@ -59,6 +59,8 @@
 #  include <orthanc/OrthancCPlugin.h>
 #endif
 
+#include <boost/lexical_cast.hpp>
+
 namespace Orthanc
 {
   namespace Logging
@@ -91,13 +93,8 @@
       {
       }
       
-      std::ostream& operator<< (const std::string& message)
-      {
-        return *this;
-      }
-
-      // This overload fixes build problems with Visual Studio 2015
-      std::ostream& operator<< (const char* message)
+      template <typename T>
+      std::ostream& operator<< (const T& message)
       {
         return *this;
       }
@@ -116,39 +113,38 @@
        ORTHANC_ENABLE_LOGGING_STDIO == 1)
 
 #  include <boost/noncopyable.hpp>
-#  include <boost/lexical_cast.hpp>
 #  define LOG(level)  ::Orthanc::Logging::InternalLogger \
-  (::Orthanc::Logging::level, __FILE__, __LINE__)
+  (::Orthanc::Logging::InternalLevel_ ## level, __FILE__, __LINE__)
 #  define VLOG(level) ::Orthanc::Logging::InternalLogger \
-  (::Orthanc::Logging::TRACE, __FILE__, __LINE__)
+  (::Orthanc::Logging::InternalLevel_TRACE, __FILE__, __LINE__)
 
 namespace Orthanc
 {
   namespace Logging
   {
-    enum Level
+    enum InternalLevel
     {
-      ERROR,
-      WARNING,
-      INFO,
-      TRACE
+      InternalLevel_ERROR,
+      InternalLevel_WARNING,
+      InternalLevel_INFO,
+      InternalLevel_TRACE
     };
     
     class InternalLogger : public boost::noncopyable
     {
     private:
-      Level       level_;
-      std::string message_;
+      InternalLevel  level_;
+      std::string    message_;
 
     public:
-      InternalLogger(Level level,
+      InternalLogger(InternalLevel level,
                      const char* file,
                      int line);
 
       ~InternalLogger();
       
       template <typename T>
-      InternalLogger& operator<< (T message)
+      InternalLogger& operator<< (const T& message)
       {
         message_ += boost::lexical_cast<std::string>(message);
         return *this;
@@ -186,15 +182,10 @@
 
       ~InternalLogger();
       
-      std::ostream& operator<< (const std::string& message)
+      template <typename T>
+      std::ostream& operator<< (const T& message)
       {
-        return (*stream_) << message;
-      }
-
-      // This overload fixes build problems with Visual Studio 2015
-      std::ostream& operator<< (const char* message)
-      {
-        return (*stream_) << message;
+        return (*stream_) << boost::lexical_cast<std::string>(message);
       }
     };
   }
--- a/Orthanc/Core/SystemToolbox.cpp	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/Core/SystemToolbox.cpp	Wed Apr 11 15:19:24 2018 +0200
@@ -62,19 +62,6 @@
 #endif
 
 
-// Inclusions for UUID
-// http://stackoverflow.com/a/1626302
-
-extern "C"
-{
-#if defined(_WIN32)
-#  include <rpc.h>
-#else
-#  include <uuid/uuid.h>
-#endif
-}
-
-
 #include "Logging.h"
 #include "OrthancException.h"
 #include "Toolbox.h"
@@ -182,7 +169,7 @@
   {
     if (!IsRegularFile(path))
     {
-      LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
+      LOG(ERROR) << "The path does not point to a regular file: " << path;
       throw OrthancException(ErrorCode_RegularFileExpected);
     }
 
@@ -210,7 +197,7 @@
   {
     if (!IsRegularFile(path))
     {
-      LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
+      LOG(ERROR) << "The path does not point to a regular file: " << path;
       throw OrthancException(ErrorCode_RegularFileExpected);
     }
 
@@ -539,28 +526,6 @@
   }
 
 
-  std::string SystemToolbox::GenerateUuid()
-  {
-#ifdef WIN32
-    UUID uuid;
-    UuidCreate ( &uuid );
-
-    unsigned char * str;
-    UuidToStringA ( &uuid, &str );
-
-    std::string s( ( char* ) str );
-
-    RpcStringFreeA ( &str );
-#else
-    uuid_t uuid;
-    uuid_generate_random ( uuid );
-    char s[37];
-    uuid_unparse ( uuid, s );
-#endif
-    return s;
-  }
-
-
   static boost::posix_time::ptime GetNow(bool utc)
   {
     if (utc)
--- a/Orthanc/Core/SystemToolbox.h	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/Core/SystemToolbox.h	Wed Apr 11 15:19:24 2018 +0200
@@ -93,8 +93,6 @@
     FILE* OpenFile(const std::string& path,
                    FileMode mode);
 
-    std::string GenerateUuid();
-
     std::string GetNowIsoString(bool utc);
 
     void GetNowDicom(std::string& date,
--- a/Orthanc/Core/Toolbox.cpp	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/Core/Toolbox.cpp	Wed Apr 11 15:19:24 2018 +0200
@@ -87,8 +87,94 @@
 #endif
 
 
+// Inclusions for UUID
+// http://stackoverflow.com/a/1626302
+
+extern "C"
+{
+#if defined(_WIN32)
+#  include <rpc.h>
+#else
+#  include <uuid/uuid.h>
+#endif
+}
+
+
+
 namespace Orthanc
 {
+  void Toolbox::LinesIterator::FindEndOfLine()
+  {
+    lineEnd_ = lineStart_;
+
+    while (lineEnd_ < content_.size() &&
+           content_[lineEnd_] != '\n' &&
+           content_[lineEnd_] != '\r')
+    {
+      lineEnd_ += 1;
+    }
+  }
+  
+
+  Toolbox::LinesIterator::LinesIterator(const std::string& content) :
+    content_(content),
+    lineStart_(0)
+  {
+    FindEndOfLine();
+  }
+
+    
+  bool Toolbox::LinesIterator::GetLine(std::string& target) const
+  {
+    assert(lineStart_ <= content_.size() &&
+           lineEnd_ <= content_.size() &&
+           lineStart_ <= lineEnd_);
+
+    if (lineStart_ == content_.size())
+    {
+      return false;
+    }
+    else
+    {
+      target = content_.substr(lineStart_, lineEnd_ - lineStart_);
+      return true;
+    }
+  }
+
+    
+  void Toolbox::LinesIterator::Next()
+  {
+    lineStart_ = lineEnd_;
+
+    if (lineStart_ != content_.size())
+    {
+      assert(content_[lineStart_] == '\r' ||
+             content_[lineStart_] == '\n');
+
+      char second;
+      
+      if (content_[lineStart_] == '\r')
+      {
+        second = '\n';
+      }
+      else
+      {
+        second = '\r';
+      }
+        
+      lineStart_ += 1;
+
+      if (lineStart_ < content_.size() &&
+          content_[lineStart_] == second)
+      {
+        lineStart_ += 1;
+      }
+
+      FindEndOfLine();
+    }
+  }
+
+  
   void Toolbox::ToUpperCase(std::string& s)
   {
     std::transform(s.begin(), s.end(), s.begin(), toupper);
@@ -1376,4 +1462,65 @@
     return boost::locale::conv::utf_to_utf<char>(w);
   }
 #endif
+
+
+  std::string Toolbox::GenerateUuid()
+  {
+#ifdef WIN32
+    UUID uuid;
+    UuidCreate ( &uuid );
+
+    unsigned char * str;
+    UuidToStringA ( &uuid, &str );
+
+    std::string s( ( char* ) str );
+
+    RpcStringFreeA ( &str );
+#else
+    uuid_t uuid;
+    uuid_generate_random ( uuid );
+    char s[37];
+    uuid_unparse ( uuid, s );
+#endif
+    return s;
+  }
 }
+
+
+
+OrthancLinesIterator* OrthancLinesIterator_Create(const std::string& content)
+{
+  return reinterpret_cast<OrthancLinesIterator*>(new Orthanc::Toolbox::LinesIterator(content));
+}
+
+
+bool OrthancLinesIterator_GetLine(std::string& target,
+                                         const OrthancLinesIterator* iterator)
+{
+  if (iterator != NULL)
+  {
+    return reinterpret_cast<const Orthanc::Toolbox::LinesIterator*>(iterator)->GetLine(target);
+  }
+  else
+  {
+    return false;
+  }
+}
+
+
+void OrthancLinesIterator_Next(OrthancLinesIterator* iterator)
+{
+  if (iterator != NULL)
+  {
+    reinterpret_cast<Orthanc::Toolbox::LinesIterator*>(iterator)->Next();
+  }
+}
+
+
+void OrthancLinesIterator_Free(OrthancLinesIterator* iterator)
+{
+  if (iterator != NULL)
+  {
+    delete reinterpret_cast<const Orthanc::Toolbox::LinesIterator*>(iterator);
+  }
+}
--- a/Orthanc/Core/Toolbox.h	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/Core/Toolbox.h	Wed Apr 11 15:19:24 2018 +0200
@@ -79,6 +79,24 @@
 
   namespace Toolbox
   {
+    class LinesIterator
+    {
+    private:
+      const std::string& content_;
+      size_t             lineStart_;
+      size_t             lineEnd_;
+
+      void FindEndOfLine();
+  
+    public:
+      LinesIterator(const std::string& content);
+  
+      bool GetLine(std::string& target) const;
+
+      void Next();
+    };
+    
+    
     void ToUpperCase(std::string& s);  // Inplace version
 
     void ToLowerCase(std::string& s);  // Inplace version
@@ -214,5 +232,28 @@
 
     std::string ToUpperCaseWithAccents(const std::string& source);
 #endif
+
+    std::string GenerateUuid();
   }
 }
+
+
+
+
+/**
+ * The plain C, opaque data structure "OrthancLinesIterator" is a thin
+ * wrapper around Orthanc::Toolbox::LinesIterator, and is only used by
+ * "../Resources/WebAssembly/dcdict.cc", in order to avoid code
+ * duplication
+ **/
+
+struct OrthancLinesIterator;
+
+OrthancLinesIterator* OrthancLinesIterator_Create(const std::string& content);
+
+bool OrthancLinesIterator_GetLine(std::string& target,
+                                  const OrthancLinesIterator* iterator);
+
+void OrthancLinesIterator_Next(OrthancLinesIterator* iterator);
+
+void OrthancLinesIterator_Free(OrthancLinesIterator* iterator);
--- a/Orthanc/NEWS	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/NEWS	Wed Apr 11 15:19:24 2018 +0200
@@ -11,6 +11,7 @@
 * Added "?expand" GET argument to "/peers" and "/modalities" routes
 * New URI: "/tools/create-media-extended" to generate a DICOMDIR
   archive from several resources, including additional type-3 tags
+* Preservation of UID relationships while anonymizing
 
 Lua
 ---
@@ -28,13 +29,16 @@
 
 * Orthanc now uses UTC (universal time) instead of local time in its database
 * Fix to allow creating DICOM instances with empty Specific Character Set (0008,0005)
-* Upgrade to curl 7.57.0 for static and Windows builds
 * Support of Linux Standard Base
 * Static linking against libuuid (from e2fsprogs)
 * Fix static build on CentOS 6
-* Upgrade to JsonCpp 1.8.4 for static builds
 * Possibility of using JsonCpp 0.10.6 if the compiler does not support C++11
   with the "-DUSE_LEGACY_JSONCPP=ON" CMake option
+* Upgraded dependencies for static and Windows builds:
+  - boost 1.66.0
+  - curl 7.57.0
+  - jsoncpp 1.8.4
+  - zlib 1.2.11
 
 
 Version 1.3.1 (2017-11-29)
--- a/Orthanc/Resources/CMake/BoostConfiguration.cmake	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/Resources/CMake/BoostConfiguration.cmake	Wed Apr 11 15:19:24 2018 +0200
@@ -53,9 +53,9 @@
   ## 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_NAME boost_1_66_0)
+  set(BOOST_BCP_SUFFIX bcpdigest-1.3.2)
+  set(BOOST_MD5 "4e15b0fd883528be159be9661b6ba20a")
   set(BOOST_URL "http://www.orthanc-server.com/downloads/third-party/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz")
   set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME})
 
@@ -97,11 +97,13 @@
     )
 
   if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
-    add_definitions(-DBOOST_SYSTEM_USE_STRERROR=1)
+    add_definitions(
+      -DBOOST_SYSTEM_USE_STRERROR=1
+      )
     
     execute_process(
       COMMAND ${PATCH_EXECUTABLE} -p0 -N -i
-      ${ORTHANC_ROOT}/Resources/Patches/boost-1.65.1-linux-standard-base.patch
+      ${ORTHANC_ROOT}/Resources/Patches/boost-1.66.0-linux-standard-base.patch
       WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
       RESULT_VARIABLE Failure
       )
@@ -145,6 +147,7 @@
       )
 
   elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
+    # No support for threads in WebAssembly
 
   else()
     message(FATAL_ERROR "Support your platform here")
@@ -254,7 +257,8 @@
             CMAKE_SYSTEM_NAME STREQUAL "kFreeBSD" OR
             CMAKE_SYSTEM_NAME STREQUAL "PNaCl" OR
             CMAKE_SYSTEM_NAME STREQUAL "NaCl32" OR
-            CMAKE_SYSTEM_NAME STREQUAL "NaCl64")
+            CMAKE_SYSTEM_NAME STREQUAL "NaCl64" OR
+            CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # For WebAssembly or asm.js
       list(APPEND BOOST_SOURCES
         ${BOOST_SOURCES_DIR}/libs/locale/src/posix/codecvt.cpp
         ${BOOST_SOURCES_DIR}/libs/locale/src/posix/collate.cpp
--- a/Orthanc/Resources/CMake/Compiler.cmake	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/Resources/CMake/Compiler.cmake	Wed Apr 11 15:19:24 2018 +0200
@@ -174,6 +174,12 @@
 elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
   message("Building using Emscripten (for WebAssembly or asm.js targets)")
 
+  # The BINARYEN_TRAP_MODE specifies what to do when divisions per
+  # zero (and similar conditions like integer overflows) are
+  # encountered: The "clamp" mode avoids throwing errors, as they
+  # cannot be properly catched by "try {} catch (...)" constructions.
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]' -s BINARYEN_TRAP_MODE='\"clamp\"'")
+
 else()
   message(FATAL_ERROR "Support your platform here")
 endif()
--- a/Orthanc/Resources/CMake/UuidConfiguration.cmake	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/Resources/CMake/UuidConfiguration.cmake	Wed Apr 11 15:19:24 2018 +0200
@@ -39,7 +39,7 @@
     check_include_file("sys/un.h"       HAVE_SYS_UN_H)
     check_include_file("unistd.h"       HAVE_UNISTD_H)
 
-    If (NOT HAVE_NET_IF_H)  # This is the case of OpenBSD
+    if (NOT HAVE_NET_IF_H)  # This is the case of OpenBSD
       unset(HAVE_NET_IF_H CACHE)
       check_include_files("sys/socket.h;net/if.h" HAVE_NET_IF_H)
     endif()
@@ -49,7 +49,8 @@
       check_include_files("sys/socket.h;netinet/tcp.h" HAVE_NETINET_TCP_H)
     endif()
 
-    file(WRITE ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h.cmake "
+    if (NOT EXISTS ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h)
+      file(WRITE ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h.cmake "
 #cmakedefine HAVE_NET_IF_H \@HAVE_NET_IF_H\@
 #cmakedefine HAVE_NET_IF_DL_H \@HAVE_NET_IF_DL_H\@
 #cmakedefine HAVE_NETINET_IN_H \@HAVE_NETINET_IN_H\@
@@ -64,26 +65,23 @@
 #cmakedefine HAVE_SYS_UN_H \@HAVE_SYS_UN_H\@
 #cmakedefine HAVE_UNISTD_H \@HAVE_UNISTD_H\@
 ")
-    
+    endif()
+      
     configure_file(
       ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h.cmake
       ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h
       )
-    
-    
+      
     configure_file(
       ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid.h.in
       ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid.h
       )
 
-    file(WRITE
-      ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h
-      "#include <stdint.h>\n")
-
-    #configure_file(
-    #  ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h.in
-    #  ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h
-    #  )
+    if (NOT EXISTS ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h)
+      file(WRITE
+        ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h
+        "#include <stdint.h>\n")
+    endif()
     
     source_group(ThirdParty\\uuid REGULAR_EXPRESSION ${E2FSPROGS_SOURCES_DIR}/.*)
 
--- a/Orthanc/Resources/LinuxStandardBaseToolchain.cmake	Thu Mar 22 17:03:48 2018 +0100
+++ b/Orthanc/Resources/LinuxStandardBaseToolchain.cmake	Wed Apr 11 15:19:24 2018 +0200
@@ -1,4 +1,4 @@
-# LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../Resources/LinuxStandardBaseToolchain.cmake
+# LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../Resources/LinuxStandardBaseToolchain.cmake -DUSE_LEGACY_JSONCPP=ON
 
 INCLUDE(CMakeForceCompiler)
 
--- a/Plugin/Cache/CacheManager.cpp	Thu Mar 22 17:03:48 2018 +0100
+++ b/Plugin/Cache/CacheManager.cpp	Wed Apr 11 15:19:24 2018 +0200
@@ -21,7 +21,7 @@
 
 #include "CacheManager.h"
 
-#include "../../Orthanc/Core/SystemToolbox.h"
+#include "../../Orthanc/Core/Toolbox.h"
 #include "../../Orthanc/Core/SQLite/Transaction.h"
 
 #include <boost/lexical_cast.hpp>
@@ -354,7 +354,7 @@
 
     // Store the cached content on the disk
     const char* data = content.size() ? &content[0] : NULL;
-    std::string uuid = SystemToolbox::GenerateUuid();
+    std::string uuid = Toolbox::GenerateUuid();
     pimpl_->storage_.Create(uuid, data, content.size(), Orthanc::FileContentType_Unknown);
 
     bool ok = true;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/CMake/LinuxStandardBaseToolchain.cmake	Wed Apr 11 15:19:24 2018 +0200
@@ -0,0 +1,66 @@
+# LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../Resources/LinuxStandardBaseToolchain.cmake -DUSE_LEGACY_JSONCPP=ON
+
+INCLUDE(CMakeForceCompiler)
+
+SET(LSB_PATH $ENV{LSB_PATH})
+SET(LSB_CC $ENV{LSB_CC})
+SET(LSB_CXX $ENV{LSB_CXX})
+SET(LSB_TARGET_VERSION "4.0")
+
+IF ("${LSB_PATH}" STREQUAL "")
+  SET(LSB_PATH "/opt/lsb")
+ENDIF()
+
+IF (EXISTS ${LSB_PATH}/lib64)
+  SET(LSB_TARGET_PROCESSOR "x86_64")
+  SET(LSB_LIBPATH ${LSB_PATH}/lib64-${LSB_TARGET_VERSION})
+ELSEIF (EXISTS ${LSB_PATH}/lib)
+  SET(LSB_TARGET_PROCESSOR "x86")
+  SET(LSB_LIBPATH ${LSB_PATH}/lib-${LSB_TARGET_VERSION})
+ELSE()
+  MESSAGE(FATAL_ERROR "Unable to detect the target processor architecture. Check the LSB_PATH environment variable.")
+ENDIF()
+
+SET(LSB_CPPPATH ${LSB_PATH}/include)
+SET(PKG_CONFIG_PATH ${LSB_LIBPATH}/pkgconfig/)
+
+# the name of the target operating system
+SET(CMAKE_SYSTEM_NAME Linux)
+SET(CMAKE_SYSTEM_VERSION LinuxStandardBase)
+SET(CMAKE_SYSTEM_PROCESSOR ${LSB_TARGET_PROCESSOR})
+
+# which compilers to use for C and C++
+SET(CMAKE_C_COMPILER ${LSB_PATH}/bin/lsbcc)
+CMAKE_FORCE_CXX_COMPILER(${LSB_PATH}/bin/lsbc++ GNU)
+
+# here is the target environment located
+SET(CMAKE_FIND_ROOT_PATH ${LSB_PATH})
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search 
+# programs in the host environment
+SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
+SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
+
+SET(CMAKE_CROSSCOMPILING OFF)
+
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -I${LSB_PATH}/include" CACHE INTERNAL "" FORCE)
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -nostdinc++ -I${LSB_PATH}/include -I${LSB_PATH}/include/c++ -I${LSB_PATH}/include/c++/backward" CACHE INTERNAL "" FORCE)
+SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -L${LSB_LIBPATH} --lsb-besteffort" CACHE INTERNAL "" FORCE)
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -L${LSB_LIBPATH} --lsb-besteffort" CACHE INTERNAL "" FORCE)
+
+if (NOT "${LSB_CXX}" STREQUAL "")
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --lsb-cxx=${LSB_CXX}")
+  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --lsb-cxx=${LSB_CXX}")
+  SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --lsb-cxx=${LSB_CXX}")
+endif()
+
+if (NOT "${LSB_CC}" STREQUAL "")
+  SET(CMAKE_C_FLAGS "${CMAKE_CC_FLAGS} --lsb-cc=${LSB_CC}")
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --lsb-cc=${LSB_CC}")
+  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --lsb-cc=${LSB_CC}")
+  SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --lsb-cc=${LSB_CC}")
+endif()
+