diff Core/Toolbox.cpp @ 1660:4a5c79e31b60 db-changes

integration mainline->db-changes
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 30 Sep 2015 13:23:31 +0200
parents 3727a09e7b53
children b268756c2cb9
line wrap: on
line diff
--- a/Core/Toolbox.cpp	Wed Feb 11 10:40:08 2015 +0100
+++ b/Core/Toolbox.cpp	Wed Sep 30 13:23:31 2015 +0200
@@ -34,21 +34,29 @@
 #include "Toolbox.h"
 
 #include "OrthancException.h"
+#include "Logging.h"
 
+#include <string>
 #include <stdint.h>
 #include <string.h>
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/uuid/sha1.hpp>
+#include <boost/lexical_cast.hpp>
 #include <algorithm>
 #include <ctype.h>
+
+#if BOOST_HAS_DATE_TIME == 1
+#include <boost/date_time/posix_time/posix_time.hpp>
+#endif
+
+#if BOOST_HAS_REGEX == 1
 #include <boost/regex.hpp> 
-#include <glog/logging.h>
+#endif
 
 #if defined(_WIN32)
 #include <windows.h>
-#include <process.h>   // For "_spawnvp()"
+#include <process.h>   // For "_spawnvp()" and "_getpid()"
 #else
 #include <unistd.h>    // For "execvp()"
 #include <sys/wait.h>  // For "waitpid()"
@@ -59,7 +67,7 @@
 #include <limits.h>      /* PATH_MAX */
 #endif
 
-#if defined(__linux) || defined(__FreeBSD_kernel__)
+#if defined(__linux) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
 #include <limits.h>      /* PATH_MAX */
 #include <signal.h>
 #include <unistd.h>
@@ -71,8 +79,15 @@
 
 #include <boost/locale.hpp>
 
+
+#if !defined(ORTHANC_ENABLE_MD5) || ORTHANC_ENABLE_MD5 == 1
 #include "../Resources/ThirdParty/md5/md5.h"
+#endif
+
+
+#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
 #include "../Resources/ThirdParty/base64/base64.h"
+#endif
 
 
 #if defined(_MSC_VER) && (_MSC_VER < 1800)
@@ -116,7 +131,7 @@
   {
 #if defined(_WIN32)
     ::Sleep(static_cast<DWORD>(microSeconds / static_cast<uint64_t>(1000)));
-#elif defined(__linux) || defined(__APPLE__) || defined(__FreeBSD_kernel__)
+#elif defined(__linux) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
     usleep(microSeconds);
 #else
 #error Support your platform here
@@ -193,6 +208,12 @@
   void Toolbox::ReadFile(std::string& content,
                          const std::string& path) 
   {
+    if (!boost::filesystem::is_regular_file(path))
+    {
+      LOG(ERROR) << "The path does not point to a regular file: " << path;
+      throw OrthancException(ErrorCode_RegularFileExpected);
+    }
+
     boost::filesystem::ifstream f;
     f.open(path, std::ifstream::in | std::ifstream::binary);
     if (!f.good())
@@ -215,7 +236,8 @@
   }
 
 
-  void Toolbox::WriteFile(const std::string& content,
+  void Toolbox::WriteFile(const void* content,
+                          size_t size,
                           const std::string& path)
   {
     boost::filesystem::ofstream f;
@@ -225,24 +247,35 @@
       throw OrthancException(ErrorCode_CannotWriteFile);
     }
 
-    if (content.size() != 0)
+    if (size != 0)
     {
-      f.write(content.c_str(), content.size());
+      f.write(reinterpret_cast<const char*>(content), size);
     }
 
     f.close();
   }
 
 
+  void Toolbox::WriteFile(const std::string& content,
+                          const std::string& path)
+  {
+    WriteFile(content.size() > 0 ? content.c_str() : NULL,
+              content.size(), path);
+  }
+
 
   void Toolbox::RemoveFile(const std::string& path)
   {
     if (boost::filesystem::exists(path))
     {
       if (boost::filesystem::is_regular_file(path))
+      {
         boost::filesystem::remove(path);
+      }
       else
-        throw OrthancException("The path is not a regular file: " + path);
+      {
+        throw OrthancException(ErrorCode_RegularFileExpected);
+      }
     }
   }
 
@@ -422,21 +455,26 @@
     {
       return static_cast<uint64_t>(boost::filesystem::file_size(path));
     }
-    catch (boost::filesystem::filesystem_error)
+    catch (boost::filesystem::filesystem_error&)
     {
       throw OrthancException(ErrorCode_InexistentFile);
     }
   }
 
 
+#if !defined(ORTHANC_ENABLE_MD5) || ORTHANC_ENABLE_MD5 == 1
   static char GetHexadecimalCharacter(uint8_t value)
   {
     assert(value < 16);
 
     if (value < 10)
+    {
       return value + '0';
+    }
     else
+    {
       return (value - 10) + 'a';
+    }
   }
 
 
@@ -474,12 +512,14 @@
     result.resize(32);
     for (unsigned int i = 0; i < 16; i++)
     {
-      result[2 * i] = GetHexadecimalCharacter(actualHash[i] / 16);
-      result[2 * i + 1] = GetHexadecimalCharacter(actualHash[i] % 16);
+      result[2 * i] = GetHexadecimalCharacter(static_cast<uint8_t>(actualHash[i] / 16));
+      result[2 * i + 1] = GetHexadecimalCharacter(static_cast<uint8_t>(actualHash[i] % 16));
     }
   }
+#endif
 
 
+#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
   void Toolbox::EncodeBase64(std::string& result, 
                              const std::string& data)
   {
@@ -493,6 +533,31 @@
   }
 
 
+#  if BOOST_HAS_REGEX == 1
+  void Toolbox::DecodeDataUriScheme(std::string& mime,
+                                    std::string& content,
+                                    const std::string& source)
+  {
+    boost::regex pattern("data:([^;]+);base64,([a-zA-Z0-9=+/]*)",
+                         boost::regex::icase /* case insensitive search */);
+
+    boost::cmatch what;
+    if (regex_match(source.c_str(), what, pattern))
+    {
+      mime = what[1];
+      DecodeBase64(content, what[2]);
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+  }
+#  endif
+
+#endif
+
+
+
 #if defined(_WIN32)
   static std::string GetPathToExecutableInternal()
   {
@@ -503,14 +568,14 @@
     return std::string(&buffer[0]);
   }
 
-#elif defined(__linux) || defined(__FreeBSD_kernel__)
+#elif defined(__linux) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
   static std::string GetPathToExecutableInternal()
   {
     std::vector<char> buffer(PATH_MAX + 1);
     ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1);
     if (bytes == 0)
     {
-      throw OrthancException("Unable to get the path to the executable");
+      throw OrthancException(ErrorCode_PathToExecutable);
     }
 
     return std::string(&buffer[0]);
@@ -546,73 +611,89 @@
   }
 
 
-  std::string Toolbox::ConvertToUtf8(const std::string& source,
-                                     const Encoding sourceEncoding)
+  static const char* GetBoostLocaleEncoding(const Encoding sourceEncoding)
   {
-    const char* encoding;
-
-
-    // http://bradleyross.users.sourceforge.net/docs/dicom/doc/src-html/org/dcm4che2/data/SpecificCharacterSet.html
     switch (sourceEncoding)
     {
       case Encoding_Utf8:
-        // Already in UTF-8: No conversion is required
-        return source;
+        return "UTF-8";
 
       case Encoding_Ascii:
-        return ConvertToAscii(source);
+        return "ASCII";
 
       case Encoding_Latin1:
-        encoding = "ISO-8859-1";
+        return "ISO-8859-1";
         break;
 
       case Encoding_Latin2:
-        encoding = "ISO-8859-2";
+        return "ISO-8859-2";
         break;
 
       case Encoding_Latin3:
-        encoding = "ISO-8859-3";
+        return "ISO-8859-3";
         break;
 
       case Encoding_Latin4:
-        encoding = "ISO-8859-4";
+        return "ISO-8859-4";
         break;
 
       case Encoding_Latin5:
-        encoding = "ISO-8859-9";
+        return "ISO-8859-9";
         break;
 
       case Encoding_Cyrillic:
-        encoding = "ISO-8859-5";
+        return "ISO-8859-5";
+        break;
+
+      case Encoding_Windows1251:
+        return "WINDOWS-1251";
         break;
 
       case Encoding_Arabic:
-        encoding = "ISO-8859-6";
+        return "ISO-8859-6";
         break;
 
       case Encoding_Greek:
-        encoding = "ISO-8859-7";
+        return "ISO-8859-7";
         break;
 
       case Encoding_Hebrew:
-        encoding = "ISO-8859-8";
+        return "ISO-8859-8";
         break;
         
       case Encoding_Japanese:
-        encoding = "SHIFT-JIS";
+        return "SHIFT-JIS";
         break;
 
       case Encoding_Chinese:
-        encoding = "GB18030";
+        return "GB18030";
         break;
 
       case Encoding_Thai:
-        encoding = "TIS620.2533-0";
+        return "TIS620.2533-0";
         break;
 
       default:
         throw OrthancException(ErrorCode_NotImplemented);
     }
+  }
+
+
+  std::string Toolbox::ConvertToUtf8(const std::string& source,
+                                     Encoding sourceEncoding)
+  {
+    if (sourceEncoding == Encoding_Utf8)
+    {
+      // Already in UTF-8: No conversion is required
+      return source;
+    }
+
+    if (sourceEncoding == Encoding_Ascii)
+    {
+      return ConvertToAscii(source);
+    }
+
+    const char* encoding = GetBoostLocaleEncoding(sourceEncoding);
 
     try
     {
@@ -626,6 +707,34 @@
   }
 
 
+  std::string Toolbox::ConvertFromUtf8(const std::string& source,
+                                       Encoding targetEncoding)
+  {
+    if (targetEncoding == Encoding_Utf8)
+    {
+      // Already in UTF-8: No conversion is required
+      return source;
+    }
+
+    if (targetEncoding == Encoding_Ascii)
+    {
+      return ConvertToAscii(source);
+    }
+
+    const char* encoding = GetBoostLocaleEncoding(targetEncoding);
+
+    try
+    {
+      return boost::locale::conv::from_utf<char>(source, encoding);
+    }
+    catch (std::runtime_error&)
+    {
+      // Bad input string or bad encoding
+      return ConvertToAscii(source);
+    }
+  }
+
+
   std::string Toolbox::ConvertToAscii(const std::string& source)
   {
     std::string result;
@@ -633,7 +742,7 @@
     result.reserve(source.size() + 1);
     for (size_t i = 0; i < source.size(); i++)
     {
-      if (source[i] < 128 && source[i] >= 0 && !iscntrl(source[i]))
+      if (source[i] <= 127 && source[i] >= 0 && !iscntrl(source[i]))
       {
         result.push_back(source[i]);
       }
@@ -668,9 +777,46 @@
             digest[4]);
   }
 
-  bool Toolbox::IsSHA1(const std::string& str)
+  bool Toolbox::IsSHA1(const char* str,
+                       size_t size)
   {
-    if (str.size() != 44)
+    if (size == 0)
+    {
+      return false;
+    }
+
+    const char* start = str;
+    const char* end = str + size;
+
+    // Trim the beginning of the string
+    while (start < end)
+    {
+      if (*start == '\0' ||
+          isspace(*start))
+      {
+        start++;
+      }
+      else
+      {
+        break;
+      }
+    }
+
+    // Trim the trailing of the string
+    while (start < end)
+    {
+      if (*(end - 1) == '\0' ||
+          isspace(*(end - 1)))
+      {
+        end--;
+      }
+      else
+      {
+        break;
+      }
+    }
+
+    if (end - start != 44)
     {
       return false;
     }
@@ -682,12 +828,12 @@
           i == 26 ||
           i == 35)
       {
-        if (str[i] != '-')
+        if (start[i] != '-')
           return false;
       }
       else
       {
-        if (!isalnum(str[i]))
+        if (!isalnum(start[i]))
           return false;
       }
     }
@@ -695,12 +841,44 @@
     return true;
   }
 
+
+  bool Toolbox::IsSHA1(const std::string& s)
+  {
+    if (s.size() == 0)
+    {
+      return false;
+    }
+    else
+    {
+      return IsSHA1(s.c_str(), s.size());
+    }
+  }
+
+
+#if BOOST_HAS_DATE_TIME == 1
   std::string Toolbox::GetNowIsoString()
   {
     boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
     return boost::posix_time::to_iso_string(now);
   }
 
+  void Toolbox::GetNowDicom(std::string& date,
+                            std::string& time)
+  {
+    boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
+    tm tm = boost::posix_time::to_tm(now);
+
+    char s[32];
+    sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+    date.assign(s);
+
+    // TODO milliseconds
+    sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
+    time.assign(s);
+  }
+#endif
+
+
   std::string Toolbox::StripSpaces(const std::string& source)
   {
     size_t first = 0;
@@ -801,6 +979,7 @@
   }
 
 
+#if BOOST_HAS_REGEX == 1
   std::string Toolbox::WildcardToRegularExpression(const std::string& source)
   {
     // TODO - Speed up this with a regular expression
@@ -828,6 +1007,7 @@
 
     return result;
   }
+#endif
 
 
 
@@ -856,40 +1036,20 @@
   }
 
 
-  void Toolbox::DecodeDataUriScheme(std::string& mime,
-                                    std::string& content,
-                                    const std::string& source)
-  {
-    boost::regex pattern("data:([^;]+);base64,([a-zA-Z0-9=+/]*)",
-                         boost::regex::icase /* case insensitive search */);
-
-    boost::cmatch what;
-    if (regex_match(source.c_str(), what, pattern))
-    {
-      mime = what[1];
-      content = what[2];
-    }
-    else
-    {
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-  }
-
-
-  void Toolbox::CreateDirectory(const std::string& path)
+  void Toolbox::MakeDirectory(const std::string& path)
   {
     if (boost::filesystem::exists(path))
     {
       if (!boost::filesystem::is_directory(path))
       {
-        throw OrthancException("Cannot create the directory over an existing file: " + path);
+        throw OrthancException(ErrorCode_DirectoryOverFile);
       }
     }
     else
     {
       if (!boost::filesystem::create_directories(path))
       {
-        throw OrthancException("Unable to create the directory: " + path);
+        throw OrthancException(ErrorCode_MakeDirectory);
       }
     }
   }
@@ -1050,7 +1210,10 @@
     if (pid == -1)
     {
       // Error in fork()
+#if ORTHANC_ENABLE_LOGGING == 1
       LOG(ERROR) << "Cannot fork a child process";
+#endif
+
       throw OrthancException(ErrorCode_SystemCommand);
     }
     else if (pid == 0)
@@ -1070,7 +1233,10 @@
 
     if (status != 0)
     {
+#if ORTHANC_ENABLE_LOGGING == 1
       LOG(ERROR) << "System command failed with status code " << status;
+#endif
+
       throw OrthancException(ErrorCode_SystemCommand);
     }
   }
@@ -1108,5 +1274,89 @@
 
     return true;
   }
+
+
+  void Toolbox::CopyJsonWithoutComments(Json::Value& target,
+                                        const Json::Value& source)
+  {
+    switch (source.type())
+    {
+      case Json::nullValue:
+        target = Json::nullValue;
+        break;
+
+      case Json::intValue:
+        target = source.asInt64();
+        break;
+
+      case Json::uintValue:
+        target = source.asUInt64();
+        break;
+
+      case Json::realValue:
+        target = source.asDouble();
+        break;
+
+      case Json::stringValue:
+        target = source.asString();
+        break;
+
+      case Json::booleanValue:
+        target = source.asBool();
+        break;
+
+      case Json::arrayValue:
+      {
+        target = Json::arrayValue;
+        for (Json::Value::ArrayIndex i = 0; i < source.size(); i++)
+        {
+          Json::Value& item = target.append(Json::nullValue);
+          CopyJsonWithoutComments(item, source[i]);
+        }
+
+        break;
+      }
+
+      case Json::objectValue:
+      {
+        target = Json::objectValue;
+        Json::Value::Members members = source.getMemberNames();
+        for (Json::Value::ArrayIndex i = 0; i < members.size(); i++)
+        {
+          const std::string item = members[i];
+          CopyJsonWithoutComments(target[item], source[item]);
+        }
+
+        break;
+      }
+
+      default:
+        break;
+    }
+  }
+
+
+  bool Toolbox::StartsWith(const std::string& str,
+                           const std::string& prefix)
+  {
+    if (str.size() < prefix.size())
+    {
+      return false;
+    }
+    else
+    {
+      return str.compare(0, prefix.size(), prefix) == 0;
+    }
+  }
+
+
+  int Toolbox::GetProcessId()
+  {
+#if defined(_WIN32)
+    return static_cast<int>(_getpid());
+#else
+    return static_cast<int>(getpid());
+#endif
+  }
 }