changeset 3991:5d2348b39392

turning toolbox namespaces into classes to control visibility in shared libraries
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 29 May 2020 21:23:57 +0200
parents 226ab94a33cd
children f9863630ec7f
files Core/EnumerationDictionary.h Core/Exports.h Core/HttpClient.h Core/OrthancException.h Core/SerializationToolbox.cpp Core/SerializationToolbox.h Core/SystemToolbox.h Core/Toolbox.h OrthancServer/ServerEnumerations.cpp UnitTestsSources/UnitTestsMain.cpp
diffstat 10 files changed, 596 insertions(+), 594 deletions(-) [+]
line wrap: on
line diff
--- a/Core/EnumerationDictionary.h	Fri May 29 19:43:28 2020 +0200
+++ b/Core/EnumerationDictionary.h	Fri May 29 21:23:57 2020 +0200
@@ -42,81 +42,78 @@
 
 namespace Orthanc
 {
-  namespace Toolbox
+  template <typename Enumeration>
+  class EnumerationDictionary
   {
-    template <typename Enumeration>
-    class EnumerationDictionary
-    {
-    private:
-      typedef std::map<Enumeration, std::string>  EnumerationToString;
-      typedef std::map<std::string, Enumeration>  StringToEnumeration;
+  private:
+    typedef std::map<Enumeration, std::string>  EnumerationToString;
+    typedef std::map<std::string, Enumeration>  StringToEnumeration;
+
+    EnumerationToString enumerationToString_;
+    StringToEnumeration stringToEnumeration_;
 
-      EnumerationToString enumerationToString_;
-      StringToEnumeration stringToEnumeration_;
+  public:
+    void Clear()
+    {
+      enumerationToString_.clear();
+      stringToEnumeration_.clear();
+    }
 
-    public:
-      void Clear()
+    bool Contains(Enumeration value) const
+    {
+      return enumerationToString_.find(value) != enumerationToString_.end();
+    }
+
+    void Add(Enumeration value, const std::string& str)
+    {
+      // Check if these values are free
+      if (enumerationToString_.find(value) != enumerationToString_.end() ||
+          stringToEnumeration_.find(str) != stringToEnumeration_.end() ||
+          Toolbox::IsInteger(str) /* Prevent the registration of a number */)
       {
-        enumerationToString_.clear();
-        stringToEnumeration_.clear();
-      }
-
-      bool Contains(Enumeration value) const
-      {
-        return enumerationToString_.find(value) != enumerationToString_.end();
+        throw OrthancException(ErrorCode_BadRequest);
       }
 
-      void Add(Enumeration value, const std::string& str)
+      // OK, the string is free and is not a number
+      enumerationToString_[value] = str;
+      stringToEnumeration_[str] = value;
+      stringToEnumeration_[boost::lexical_cast<std::string>(static_cast<int>(value))] = value;
+    }
+
+    Enumeration Translate(const std::string& str) const
+    {
+      if (Toolbox::IsInteger(str))
       {
-        // Check if these values are free
-        if (enumerationToString_.find(value) != enumerationToString_.end() ||
-            stringToEnumeration_.find(str) != stringToEnumeration_.end() ||
-            Toolbox::IsInteger(str) /* Prevent the registration of a number */)
-        {
-          throw OrthancException(ErrorCode_BadRequest);
-        }
-
-        // OK, the string is free and is not a number
-        enumerationToString_[value] = str;
-        stringToEnumeration_[str] = value;
-        stringToEnumeration_[boost::lexical_cast<std::string>(static_cast<int>(value))] = value;
+        return static_cast<Enumeration>(boost::lexical_cast<int>(str));
       }
 
-      Enumeration Translate(const std::string& str) const
-      {
-        if (Toolbox::IsInteger(str))
-        {
-          return static_cast<Enumeration>(boost::lexical_cast<int>(str));
-        }
+      typename StringToEnumeration::const_iterator
+        found = stringToEnumeration_.find(str);
 
-        typename StringToEnumeration::const_iterator
-          found = stringToEnumeration_.find(str);
-
-        if (found == stringToEnumeration_.end())
-        {
-          throw OrthancException(ErrorCode_InexistentItem);
-        }
-        else
-        {
-          return found->second;
-        }
+      if (found == stringToEnumeration_.end())
+      {
+        throw OrthancException(ErrorCode_InexistentItem);
+      }
+      else
+      {
+        return found->second;
       }
+    }
 
-      std::string Translate(Enumeration e) const
-      {
-        typename EnumerationToString::const_iterator
-          found = enumerationToString_.find(e);
+    std::string Translate(Enumeration e) const
+    {
+      typename EnumerationToString::const_iterator
+        found = enumerationToString_.find(e);
 
-        if (found == enumerationToString_.end())
-        {
-          // No name for this item
-          return boost::lexical_cast<std::string>(static_cast<int>(e));
-        }
-        else
-        {
-          return found->second;
-        }
+      if (found == enumerationToString_.end())
+      {
+        // No name for this item
+        return boost::lexical_cast<std::string>(static_cast<int>(e));
       }
-    };
-  }
+      else
+      {
+        return found->second;
+      }
+    }
+  };
 }
--- a/Core/Exports.h	Fri May 29 19:43:28 2020 +0200
+++ b/Core/Exports.h	Fri May 29 21:23:57 2020 +0200
@@ -34,6 +34,9 @@
 #pragma once
 
 
+//#define ORTHANC_PUBLIC __attribute__ ((visibility ("default")))
+#define ORTHANC_PUBLIC
+
 #if 0   // Test for the shared library
 
 // https://gcc.gnu.org/wiki/Visibility
--- a/Core/HttpClient.h	Fri May 29 19:43:28 2020 +0200
+++ b/Core/HttpClient.h	Fri May 29 21:23:57 2020 +0200
@@ -53,7 +53,7 @@
 
 namespace Orthanc
 {
-  class HttpClient : public boost::noncopyable
+  class ORTHANC_PUBLIC HttpClient : public boost::noncopyable
   {
   public:
     typedef std::map<std::string, std::string>  HttpHeaders;
--- a/Core/OrthancException.h	Fri May 29 19:43:28 2020 +0200
+++ b/Core/OrthancException.h	Fri May 29 21:23:57 2020 +0200
@@ -35,6 +35,7 @@
 
 #include "Compatibility.h"
 #include "Enumerations.h"
+#include "Exports.h"
 #include "Logging.h"
 
 #include <stdint.h>
@@ -43,7 +44,7 @@
 
 namespace Orthanc
 {
-  class OrthancException
+  class ORTHANC_PUBLIC OrthancException
   {
   private:
     OrthancException();  // Forbidden
--- a/Core/SerializationToolbox.cpp	Fri May 29 19:43:28 2020 +0200
+++ b/Core/SerializationToolbox.cpp	Fri May 29 21:23:57 2020 +0200
@@ -42,406 +42,403 @@
 
 namespace Orthanc
 {
-  namespace SerializationToolbox
+  static bool ParseTagInternal(DicomTag& tag,
+                               const char* name)
   {
-    static bool ParseTagInternal(DicomTag& tag,
-                                 const char* name)
-    {
 #if ORTHANC_ENABLE_DCMTK == 1
-      try
-      {
-        tag = FromDcmtkBridge::ParseTag(name);
-        return true;
-      }
-      catch (OrthancException&)
-      {
-        return false;
-      }
+    try
+    {
+      tag = FromDcmtkBridge::ParseTag(name);
+      return true;
+    }
+    catch (OrthancException&)
+    {
+      return false;
+    }
 #else
-      return DicomTag::ParseHexadecimal(tag, name);
+    return DicomTag::ParseHexadecimal(tag, name);
 #endif   
-    }
+  }
 
     
-    std::string ReadString(const Json::Value& value,
-                           const std::string& field)
+  std::string SerializationToolbox::ReadString(const Json::Value& value,
+                                               const std::string& field)
+  {
+    if (value.type() != Json::objectValue ||
+        !value.isMember(field.c_str()) ||
+        value[field.c_str()].type() != Json::stringValue)
     {
-      if (value.type() != Json::objectValue ||
-          !value.isMember(field.c_str()) ||
-          value[field.c_str()].type() != Json::stringValue)
-      {
-        throw OrthancException(ErrorCode_BadFileFormat,
-                               "String value expected in field: " + field);
-      }
-      else
-      {
-        return value[field.c_str()].asString();
-      }
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "String value expected in field: " + field);
     }
+    else
+    {
+      return value[field.c_str()].asString();
+    }
+  }
 
 
-    int ReadInteger(const Json::Value& value,
-                    const std::string& field)
+  int SerializationToolbox::ReadInteger(const Json::Value& value,
+                                        const std::string& field)
+  {
+    if (value.type() != Json::objectValue ||
+        !value.isMember(field.c_str()) ||
+        (value[field.c_str()].type() != Json::intValue &&
+         value[field.c_str()].type() != Json::uintValue))
     {
-      if (value.type() != Json::objectValue ||
-          !value.isMember(field.c_str()) ||
-          (value[field.c_str()].type() != Json::intValue &&
-           value[field.c_str()].type() != Json::uintValue))
-      {
-        throw OrthancException(ErrorCode_BadFileFormat,
-                               "Integer value expected in field: " + field);
-      }
-      else
-      {
-        return value[field.c_str()].asInt();
-      }    
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "Integer value expected in field: " + field);
     }
+    else
+    {
+      return value[field.c_str()].asInt();
+    }    
+  }
 
 
-    int ReadInteger(const Json::Value& value,
-                    const std::string& field,
-                    int defaultValue)
+  int SerializationToolbox::ReadInteger(const Json::Value& value,
+                                        const std::string& field,
+                                        int defaultValue)
+  {
+    if (value.isMember(field.c_str()))
+    {
+      return ReadInteger(value, field);
+    }
+    else
     {
-      if (value.isMember(field.c_str()))
-      {
-        return ReadInteger(value, field);
-      }
-      else
-      {
-        return defaultValue;
-      }
+      return defaultValue;
     }
+  }
+
+
+  unsigned int SerializationToolbox::ReadUnsignedInteger(const Json::Value& value,
+                                                         const std::string& field)
+  {
+    int tmp = ReadInteger(value, field);
+
+    if (tmp < 0)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "Unsigned integer value expected in field: " + field);
+    }
+    else
+    {
+      return static_cast<unsigned int>(tmp);
+    }
+  }
 
 
-    unsigned int ReadUnsignedInteger(const Json::Value& value,
-                                     const std::string& field)
+  bool SerializationToolbox::ReadBoolean(const Json::Value& value,
+                                         const std::string& field)
+  {
+    if (value.type() != Json::objectValue ||
+        !value.isMember(field.c_str()) ||
+        value[field.c_str()].type() != Json::booleanValue)
     {
-      int tmp = ReadInteger(value, field);
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "Boolean value expected in field: " + field);
+    }
+    else
+    {
+      return value[field.c_str()].asBool();
+    }   
+  }
 
-      if (tmp < 0)
-      {
-        throw OrthancException(ErrorCode_BadFileFormat,
-                               "Unsigned integer value expected in field: " + field);
-      }
-      else
-      {
-        return static_cast<unsigned int>(tmp);
-      }
+  
+  void SerializationToolbox::ReadArrayOfStrings(std::vector<std::string>& target,
+                                                const Json::Value& value,
+                                                const std::string& field)
+  {
+    if (value.type() != Json::objectValue ||
+        !value.isMember(field.c_str()) ||
+        value[field.c_str()].type() != Json::arrayValue)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "List of strings expected in field: " + field);
     }
 
+    const Json::Value& arr = value[field.c_str()];
 
-    bool ReadBoolean(const Json::Value& value,
-                     const std::string& field)
+    target.resize(arr.size());
+
+    for (Json::Value::ArrayIndex i = 0; i < arr.size(); i++)
     {
-      if (value.type() != Json::objectValue ||
-          !value.isMember(field.c_str()) ||
-          value[field.c_str()].type() != Json::booleanValue)
-      {
-        throw OrthancException(ErrorCode_BadFileFormat,
-                               "Boolean value expected in field: " + field);
-      }
-      else
-      {
-        return value[field.c_str()].asBool();
-      }   
-    }
-
-  
-    void ReadArrayOfStrings(std::vector<std::string>& target,
-                            const Json::Value& value,
-                            const std::string& field)
-    {
-      if (value.type() != Json::objectValue ||
-          !value.isMember(field.c_str()) ||
-          value[field.c_str()].type() != Json::arrayValue)
+      if (arr[i].type() != Json::stringValue)
       {
         throw OrthancException(ErrorCode_BadFileFormat,
                                "List of strings expected in field: " + field);
       }
-
-      const Json::Value& arr = value[field.c_str()];
-
-      target.resize(arr.size());
-
-      for (Json::Value::ArrayIndex i = 0; i < arr.size(); i++)
+      else
       {
-        if (arr[i].type() != Json::stringValue)
-        {
-          throw OrthancException(ErrorCode_BadFileFormat,
-                                 "List of strings expected in field: " + field);
-        }
-        else
-        {
-          target[i] = arr[i].asString();
-        }
+        target[i] = arr[i].asString();
       }
     }
+  }
 
 
-    void ReadListOfStrings(std::list<std::string>& target,
-                           const Json::Value& value,
-                           const std::string& field)
-    {
-      std::vector<std::string> tmp;
-      ReadArrayOfStrings(tmp, value, field);
+  void SerializationToolbox::ReadListOfStrings(std::list<std::string>& target,
+                                               const Json::Value& value,
+                                               const std::string& field)
+  {
+    std::vector<std::string> tmp;
+    ReadArrayOfStrings(tmp, value, field);
 
-      target.clear();
-      for (size_t i = 0; i < tmp.size(); i++)
-      {
-        target.push_back(tmp[i]);
-      }
+    target.clear();
+    for (size_t i = 0; i < tmp.size(); i++)
+    {
+      target.push_back(tmp[i]);
     }
+  }
   
 
-    void ReadSetOfStrings(std::set<std::string>& target,
-                          const Json::Value& value,
-                          const std::string& field)
+  void SerializationToolbox::ReadSetOfStrings(std::set<std::string>& target,
+                                              const Json::Value& value,
+                                              const std::string& field)
+  {
+    std::vector<std::string> tmp;
+    ReadArrayOfStrings(tmp, value, field);
+
+    target.clear();
+    for (size_t i = 0; i < tmp.size(); i++)
     {
-      std::vector<std::string> tmp;
-      ReadArrayOfStrings(tmp, value, field);
+      target.insert(tmp[i]);
+    }
+  }
+
 
-      target.clear();
-      for (size_t i = 0; i < tmp.size(); i++)
-      {
-        target.insert(tmp[i]);
-      }
+  void SerializationToolbox::ReadSetOfTags(std::set<DicomTag>& target,
+                                           const Json::Value& value,
+                                           const std::string& field)
+  {
+    if (value.type() != Json::objectValue ||
+        !value.isMember(field.c_str()) ||
+        value[field.c_str()].type() != Json::arrayValue)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "Set of DICOM tags expected in field: " + field);
     }
 
+    const Json::Value& arr = value[field.c_str()];
 
-    void ReadSetOfTags(std::set<DicomTag>& target,
-                       const Json::Value& value,
-                       const std::string& field)
+    target.clear();
+
+    for (Json::Value::ArrayIndex i = 0; i < arr.size(); i++)
     {
-      if (value.type() != Json::objectValue ||
-          !value.isMember(field.c_str()) ||
-          value[field.c_str()].type() != Json::arrayValue)
+      DicomTag tag(0, 0);
+
+      if (arr[i].type() != Json::stringValue ||
+          !ParseTagInternal(tag, arr[i].asCString()))
       {
         throw OrthancException(ErrorCode_BadFileFormat,
                                "Set of DICOM tags expected in field: " + field);
       }
-
-      const Json::Value& arr = value[field.c_str()];
-
-      target.clear();
-
-      for (Json::Value::ArrayIndex i = 0; i < arr.size(); i++)
+      else
       {
-        DicomTag tag(0, 0);
-
-        if (arr[i].type() != Json::stringValue ||
-            !ParseTagInternal(tag, arr[i].asCString()))
-        {
-          throw OrthancException(ErrorCode_BadFileFormat,
-                                 "Set of DICOM tags expected in field: " + field);
-        }
-        else
-        {
-          target.insert(tag);
-        }
+        target.insert(tag);
       }
     }
+  }
 
 
-    void ReadMapOfStrings(std::map<std::string, std::string>& target,
-                          const Json::Value& value,
-                          const std::string& field)
+  void SerializationToolbox::ReadMapOfStrings(std::map<std::string, std::string>& target,
+                                              const Json::Value& value,
+                                              const std::string& field)
+  {
+    if (value.type() != Json::objectValue ||
+        !value.isMember(field.c_str()) ||
+        value[field.c_str()].type() != Json::objectValue)
     {
-      if (value.type() != Json::objectValue ||
-          !value.isMember(field.c_str()) ||
-          value[field.c_str()].type() != Json::objectValue)
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "Associative array of strings to strings expected in field: " + field);
+    }
+
+    const Json::Value& source = value[field.c_str()];
+
+    target.clear();
+
+    Json::Value::Members members = source.getMemberNames();
+
+    for (size_t i = 0; i < members.size(); i++)
+    {
+      const Json::Value& tmp = source[members[i]];
+
+      if (tmp.type() != Json::stringValue)
       {
         throw OrthancException(ErrorCode_BadFileFormat,
-                               "Associative array of strings to strings expected in field: " + field);
+                               "Associative array of string to strings expected in field: " + field);
       }
-
-      const Json::Value& source = value[field.c_str()];
-
-      target.clear();
-
-      Json::Value::Members members = source.getMemberNames();
-
-      for (size_t i = 0; i < members.size(); i++)
+      else
       {
-        const Json::Value& tmp = source[members[i]];
-
-        if (tmp.type() != Json::stringValue)
-        {
-          throw OrthancException(ErrorCode_BadFileFormat,
-                                 "Associative array of string to strings expected in field: " + field);
-        }
-        else
-        {
-          target[members[i]] = tmp.asString();
-        }
+        target[members[i]] = tmp.asString();
       }
     }
+  }
 
 
-    void ReadMapOfTags(std::map<DicomTag, std::string>& target,
-                       const Json::Value& value,
-                       const std::string& field)
+  void SerializationToolbox::ReadMapOfTags(std::map<DicomTag, std::string>& target,
+                                           const Json::Value& value,
+                                           const std::string& field)
+  {
+    if (value.type() != Json::objectValue ||
+        !value.isMember(field.c_str()) ||
+        value[field.c_str()].type() != Json::objectValue)
     {
-      if (value.type() != Json::objectValue ||
-          !value.isMember(field.c_str()) ||
-          value[field.c_str()].type() != Json::objectValue)
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "Associative array of DICOM tags to strings expected in field: " + field);
+    }
+
+    const Json::Value& source = value[field.c_str()];
+
+    target.clear();
+
+    Json::Value::Members members = source.getMemberNames();
+
+    for (size_t i = 0; i < members.size(); i++)
+    {
+      const Json::Value& tmp = source[members[i]];
+
+      DicomTag tag(0, 0);
+
+      if (!ParseTagInternal(tag, members[i].c_str()) ||
+          tmp.type() != Json::stringValue)
       {
         throw OrthancException(ErrorCode_BadFileFormat,
                                "Associative array of DICOM tags to strings expected in field: " + field);
       }
-
-      const Json::Value& source = value[field.c_str()];
-
-      target.clear();
-
-      Json::Value::Members members = source.getMemberNames();
-
-      for (size_t i = 0; i < members.size(); i++)
-      {
-        const Json::Value& tmp = source[members[i]];
-
-        DicomTag tag(0, 0);
-
-        if (!ParseTagInternal(tag, members[i].c_str()) ||
-            tmp.type() != Json::stringValue)
-        {
-          throw OrthancException(ErrorCode_BadFileFormat,
-                                 "Associative array of DICOM tags to strings expected in field: " + field);
-        }
-        else
-        {
-          target[tag] = tmp.asString();
-        }
-      }
-    }
-
-
-    void WriteArrayOfStrings(Json::Value& target,
-                             const std::vector<std::string>& values,
-                             const std::string& field)
-    {
-      if (target.type() != Json::objectValue ||
-          target.isMember(field.c_str()))
-      {
-        throw OrthancException(ErrorCode_BadFileFormat);
-      }
-
-      Json::Value& value = target[field];
-
-      value = Json::arrayValue;
-      for (size_t i = 0; i < values.size(); i++)
-      {
-        value.append(values[i]);
-      }
-    }
-
-
-    void WriteListOfStrings(Json::Value& target,
-                            const std::list<std::string>& values,
-                            const std::string& field)
-    {
-      if (target.type() != Json::objectValue ||
-          target.isMember(field.c_str()))
-      {
-        throw OrthancException(ErrorCode_BadFileFormat);
-      }
-
-      Json::Value& value = target[field];
-
-      value = Json::arrayValue;
-
-      for (std::list<std::string>::const_iterator it = values.begin();
-           it != values.end(); ++it)
-      {
-        value.append(*it);
-      }
-    }
-
-
-    void WriteSetOfStrings(Json::Value& target,
-                           const std::set<std::string>& values,
-                           const std::string& field)
-    {
-      if (target.type() != Json::objectValue ||
-          target.isMember(field.c_str()))
+      else
       {
-        throw OrthancException(ErrorCode_BadFileFormat);
-      }
-
-      Json::Value& value = target[field];
-
-      value = Json::arrayValue;
-
-      for (std::set<std::string>::const_iterator it = values.begin();
-           it != values.end(); ++it)
-      {
-        value.append(*it);
-      }
-    }
-
-
-    void WriteSetOfTags(Json::Value& target,
-                        const std::set<DicomTag>& tags,
-                        const std::string& field)
-    {
-      if (target.type() != Json::objectValue ||
-          target.isMember(field.c_str()))
-      {
-        throw OrthancException(ErrorCode_BadFileFormat);
-      }
-
-      Json::Value& value = target[field];
-
-      value = Json::arrayValue;
-
-      for (std::set<DicomTag>::const_iterator it = tags.begin();
-           it != tags.end(); ++it)
-      {
-        value.append(it->Format());
-      }
-    }
-
-
-    void WriteMapOfStrings(Json::Value& target,
-                           const std::map<std::string, std::string>& values,
-                           const std::string& field)
-    {
-      if (target.type() != Json::objectValue ||
-          target.isMember(field.c_str()))
-      {
-        throw OrthancException(ErrorCode_BadFileFormat);
-      }
-
-      Json::Value& value = target[field];
-
-      value = Json::objectValue;
-
-      for (std::map<std::string, std::string>::const_iterator
-             it = values.begin(); it != values.end(); ++it)
-      {
-        value[it->first] = it->second;
-      }
-    }
-
-
-    void WriteMapOfTags(Json::Value& target,
-                        const std::map<DicomTag, std::string>& values,
-                        const std::string& field)
-    {
-      if (target.type() != Json::objectValue ||
-          target.isMember(field.c_str()))
-      {
-        throw OrthancException(ErrorCode_BadFileFormat);
-      }
-
-      Json::Value& value = target[field];
-
-      value = Json::objectValue;
-
-      for (std::map<DicomTag, std::string>::const_iterator
-             it = values.begin(); it != values.end(); ++it)
-      {
-        value[it->first.Format()] = it->second;
+        target[tag] = tmp.asString();
       }
     }
   }
+
+
+  void SerializationToolbox::WriteArrayOfStrings(Json::Value& target,
+                                                 const std::vector<std::string>& values,
+                                                 const std::string& field)
+  {
+    if (target.type() != Json::objectValue ||
+        target.isMember(field.c_str()))
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    Json::Value& value = target[field];
+
+    value = Json::arrayValue;
+    for (size_t i = 0; i < values.size(); i++)
+    {
+      value.append(values[i]);
+    }
+  }
+
+
+  void SerializationToolbox::WriteListOfStrings(Json::Value& target,
+                                                const std::list<std::string>& values,
+                                                const std::string& field)
+  {
+    if (target.type() != Json::objectValue ||
+        target.isMember(field.c_str()))
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    Json::Value& value = target[field];
+
+    value = Json::arrayValue;
+
+    for (std::list<std::string>::const_iterator it = values.begin();
+         it != values.end(); ++it)
+    {
+      value.append(*it);
+    }
+  }
+
+
+  void SerializationToolbox::WriteSetOfStrings(Json::Value& target,
+                                               const std::set<std::string>& values,
+                                               const std::string& field)
+  {
+    if (target.type() != Json::objectValue ||
+        target.isMember(field.c_str()))
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    Json::Value& value = target[field];
+
+    value = Json::arrayValue;
+
+    for (std::set<std::string>::const_iterator it = values.begin();
+         it != values.end(); ++it)
+    {
+      value.append(*it);
+    }
+  }
+
+
+  void SerializationToolbox::WriteSetOfTags(Json::Value& target,
+                                            const std::set<DicomTag>& tags,
+                                            const std::string& field)
+  {
+    if (target.type() != Json::objectValue ||
+        target.isMember(field.c_str()))
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    Json::Value& value = target[field];
+
+    value = Json::arrayValue;
+
+    for (std::set<DicomTag>::const_iterator it = tags.begin();
+         it != tags.end(); ++it)
+    {
+      value.append(it->Format());
+    }
+  }
+
+
+  void SerializationToolbox::WriteMapOfStrings(Json::Value& target,
+                                               const std::map<std::string, std::string>& values,
+                                               const std::string& field)
+  {
+    if (target.type() != Json::objectValue ||
+        target.isMember(field.c_str()))
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    Json::Value& value = target[field];
+
+    value = Json::objectValue;
+
+    for (std::map<std::string, std::string>::const_iterator
+           it = values.begin(); it != values.end(); ++it)
+    {
+      value[it->first] = it->second;
+    }
+  }
+
+
+  void SerializationToolbox::WriteMapOfTags(Json::Value& target,
+                                            const std::map<DicomTag, std::string>& values,
+                                            const std::string& field)
+  {
+    if (target.type() != Json::objectValue ||
+        target.isMember(field.c_str()))
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    Json::Value& value = target[field];
+
+    value = Json::objectValue;
+
+    for (std::map<DicomTag, std::string>::const_iterator
+           it = values.begin(); it != values.end(); ++it)
+    {
+      value[it->first.Format()] = it->second;
+    }
+  }
 }
--- a/Core/SerializationToolbox.h	Fri May 29 19:43:28 2020 +0200
+++ b/Core/SerializationToolbox.h	Fri May 29 21:23:57 2020 +0200
@@ -34,6 +34,7 @@
 #pragma once
 
 #include "DicomFormat/DicomTag.h"
+#include "Exports.h"
 
 #include <json/value.h>
 #include <list>
@@ -41,70 +42,71 @@
 
 namespace Orthanc
 {
-  namespace SerializationToolbox
+  class ORTHANC_PUBLIC SerializationToolbox
   {
-    std::string ReadString(const Json::Value& value,
-                           const std::string& field);
-
-    int ReadInteger(const Json::Value& value,
-                    const std::string& field);
-
-    int ReadInteger(const Json::Value& value,
-                    const std::string& field,
-                    int defaultValue);
+  public:
+    static std::string ReadString(const Json::Value& value,
+                                  const std::string& field);
 
-    unsigned int ReadUnsignedInteger(const Json::Value& value,
-                                     const std::string& field);
-
-    bool ReadBoolean(const Json::Value& value,
-                     const std::string& field);
-
-    void ReadArrayOfStrings(std::vector<std::string>& target,
-                            const Json::Value& value,
-                            const std::string& field);
-
-    void ReadListOfStrings(std::list<std::string>& target,
-                           const Json::Value& value,
+    static int ReadInteger(const Json::Value& value,
                            const std::string& field);
 
-    void ReadSetOfStrings(std::set<std::string>& target,
-                          const Json::Value& value,
-                          const std::string& field);
-
-    void ReadSetOfTags(std::set<DicomTag>& target,
-                       const Json::Value& value,
-                       const std::string& field);
+    static int ReadInteger(const Json::Value& value,
+                           const std::string& field,
+                           int defaultValue);
 
-    void ReadMapOfStrings(std::map<std::string, std::string>& values,
-                          const Json::Value& target,
-                          const std::string& field);
+    static unsigned int ReadUnsignedInteger(const Json::Value& value,
+                                            const std::string& field);
 
-    void ReadMapOfTags(std::map<DicomTag, std::string>& values,
-                       const Json::Value& target,
-                       const std::string& field);
-
-    void WriteArrayOfStrings(Json::Value& target,
-                             const std::vector<std::string>& values,
-                             const std::string& field);
-
-    void WriteListOfStrings(Json::Value& target,
-                            const std::list<std::string>& values,
+    static bool ReadBoolean(const Json::Value& value,
                             const std::string& field);
 
-    void WriteSetOfStrings(Json::Value& target,
-                           const std::set<std::string>& values,
-                           const std::string& field);
+    static void ReadArrayOfStrings(std::vector<std::string>& target,
+                                   const Json::Value& value,
+                                   const std::string& field);
+
+    static void ReadListOfStrings(std::list<std::string>& target,
+                                  const Json::Value& value,
+                                  const std::string& field);
+
+    static void ReadSetOfStrings(std::set<std::string>& target,
+                                 const Json::Value& value,
+                                 const std::string& field);
 
-    void WriteSetOfTags(Json::Value& target,
-                        const std::set<DicomTag>& tags,
-                        const std::string& field);
+    static void ReadSetOfTags(std::set<DicomTag>& target,
+                              const Json::Value& value,
+                              const std::string& field);
+
+    static void ReadMapOfStrings(std::map<std::string, std::string>& values,
+                                 const Json::Value& target,
+                                 const std::string& field);
+
+    static void ReadMapOfTags(std::map<DicomTag, std::string>& values,
+                              const Json::Value& target,
+                              const std::string& field);
 
-    void WriteMapOfStrings(Json::Value& target,
-                           const std::map<std::string, std::string>& values,
-                           const std::string& field);
+    static void WriteArrayOfStrings(Json::Value& target,
+                                    const std::vector<std::string>& values,
+                                    const std::string& field);
+
+    static void WriteListOfStrings(Json::Value& target,
+                                   const std::list<std::string>& values,
+                                   const std::string& field);
+
+    static void WriteSetOfStrings(Json::Value& target,
+                                  const std::set<std::string>& values,
+                                  const std::string& field);
 
-    void WriteMapOfTags(Json::Value& target,
-                        const std::map<DicomTag, std::string>& values,
-                        const std::string& field);
-  }
+    static void WriteSetOfTags(Json::Value& target,
+                               const std::set<DicomTag>& tags,
+                               const std::string& field);
+
+    static void WriteMapOfStrings(Json::Value& target,
+                                  const std::map<std::string, std::string>& values,
+                                  const std::string& field);
+
+    static void WriteMapOfTags(Json::Value& target,
+                               const std::map<DicomTag, std::string>& values,
+                               const std::string& field);
+  };
 }
--- a/Core/SystemToolbox.h	Fri May 29 19:43:28 2020 +0200
+++ b/Core/SystemToolbox.h	Fri May 29 21:23:57 2020 +0200
@@ -42,6 +42,7 @@
 #endif
 
 #include "Enumerations.h"
+#include "Exports.h"
 
 #include <map>
 #include <vector>
@@ -50,64 +51,65 @@
 
 namespace Orthanc
 {
-  namespace SystemToolbox
+  class ORTHANC_PUBLIC SystemToolbox
   {
-    void USleep(uint64_t microSeconds);
-
-    ServerBarrierEvent ServerBarrier(const bool& stopFlag);
+  public:
+    static void USleep(uint64_t microSeconds);
 
-    ServerBarrierEvent ServerBarrier();
+    static ServerBarrierEvent ServerBarrier(const bool& stopFlag);
+
+    static ServerBarrierEvent ServerBarrier();
 
-    void ReadFile(std::string& content,
-                  const std::string& path,
-                  bool log = true);
+    static void ReadFile(std::string& content,
+                         const std::string& path,
+                         bool log = true);
 
-    bool ReadHeader(std::string& header,
-                    const std::string& path,
-                    size_t headerSize);
+    static bool ReadHeader(std::string& header,
+                           const std::string& path,
+                           size_t headerSize);
 
-    void WriteFile(const void* content,
-                   size_t size,
-                   const std::string& path);
+    static void WriteFile(const void* content,
+                          size_t size,
+                          const std::string& path);
 
-    void WriteFile(const std::string& content,
-                   const std::string& path);
-
-    void RemoveFile(const std::string& path);
+    static void WriteFile(const std::string& content,
+                          const std::string& path);
 
-    uint64_t GetFileSize(const std::string& path);
+    static void RemoveFile(const std::string& path);
 
-    void MakeDirectory(const std::string& path);
+    static uint64_t GetFileSize(const std::string& path);
 
-    bool IsExistingFile(const std::string& path);
+    static void MakeDirectory(const std::string& path);
 
-    std::string GetPathToExecutable();
+    static bool IsExistingFile(const std::string& path);
 
-    std::string GetDirectoryOfExecutable();
+    static std::string GetPathToExecutable();
 
-    void ExecuteSystemCommand(const std::string& command,
-                              const std::vector<std::string>& arguments);
+    static std::string GetDirectoryOfExecutable();
 
-    int GetProcessId();
+    static void ExecuteSystemCommand(const std::string& command,
+                                     const std::vector<std::string>& arguments);
+
+    static int GetProcessId();
 
-    bool IsRegularFile(const std::string& path);
+    static bool IsRegularFile(const std::string& path);
 
-    FILE* OpenFile(const std::string& path,
-                   FileMode mode);
+    static FILE* OpenFile(const std::string& path,
+                          FileMode mode);
 
-    std::string GetNowIsoString(bool utc);
+    static std::string GetNowIsoString(bool utc);
 
-    void GetNowDicom(std::string& date,
-                     std::string& time,
-                     bool utc);
+    static void GetNowDicom(std::string& date,
+                            std::string& time,
+                            bool utc);
 
-    unsigned int GetHardwareConcurrency();
+    static unsigned int GetHardwareConcurrency();
 
-    MimeType AutodetectMimeType(const std::string& path);
+    static MimeType AutodetectMimeType(const std::string& path);
 
-    void GetEnvironmentVariables(std::map<std::string, std::string>& env);
+    static void GetEnvironmentVariables(std::map<std::string, std::string>& env);
 
-    std::string InterpretRelativePath(const std::string& baseDirectory,
-                                      const std::string& relativePath);
-  }
+    static std::string InterpretRelativePath(const std::string& baseDirectory,
+                                             const std::string& relativePath);
+  };
 }
--- a/Core/Toolbox.h	Fri May 29 19:43:28 2020 +0200
+++ b/Core/Toolbox.h	Fri May 29 21:23:57 2020 +0200
@@ -82,8 +82,9 @@
   {
   };
 
-  namespace Toolbox
+  class ORTHANC_PUBLIC Toolbox
   {
+  public:
     class LinesIterator
     {
     private:
@@ -101,169 +102,168 @@
       void Next();
     };
     
-    
-    void ToUpperCase(std::string& s);  // Inplace version
+    static void ToUpperCase(std::string& s);  // Inplace version
 
-    void ToLowerCase(std::string& s);  // Inplace version
+    static void ToLowerCase(std::string& s);  // Inplace version
 
-    void ToUpperCase(std::string& result,
-                     const std::string& source);
+    static void ToUpperCase(std::string& result,
+                            const std::string& source);
 
-    void ToLowerCase(std::string& result,
-                     const std::string& source);
+    static void ToLowerCase(std::string& result,
+                            const std::string& source);
 
-    void SplitUriComponents(UriComponents& components,
-                            const std::string& uri);
+    static void SplitUriComponents(UriComponents& components,
+                                   const std::string& uri);
   
-    void TruncateUri(UriComponents& target,
-                     const UriComponents& source,
-                     size_t fromLevel);
+    static void TruncateUri(UriComponents& target,
+                            const UriComponents& source,
+                            size_t fromLevel);
   
-    bool IsChildUri(const UriComponents& baseUri,
-                    const UriComponents& testedUri);
+    static bool IsChildUri(const UriComponents& baseUri,
+                           const UriComponents& testedUri);
 
-    std::string FlattenUri(const UriComponents& components,
-                           size_t fromLevel = 0);
+    static std::string FlattenUri(const UriComponents& components,
+                                  size_t fromLevel = 0);
 
 #if ORTHANC_ENABLE_MD5 == 1
-    void ComputeMD5(std::string& result,
-                    const std::string& data);
+    static void ComputeMD5(std::string& result,
+                           const std::string& data);
 
-    void ComputeMD5(std::string& result,
-                    const void* data,
-                    size_t size);
+    static void ComputeMD5(std::string& result,
+                           const void* data,
+                           size_t size);
 #endif
 
-    void ComputeSHA1(std::string& result,
-                     const std::string& data);
+    static void ComputeSHA1(std::string& result,
+                            const std::string& data);
 
-    void ComputeSHA1(std::string& result,
-                     const void* data,
-                     size_t size);
+    static void ComputeSHA1(std::string& result,
+                            const void* data,
+                            size_t size);
 
-    bool IsSHA1(const void* str,
-                size_t size);
+    static bool IsSHA1(const void* str,
+                       size_t size);
 
-    bool IsSHA1(const std::string& s);
+    static bool IsSHA1(const std::string& s);
 
 #if ORTHANC_ENABLE_BASE64 == 1
-    void DecodeBase64(std::string& result, 
-                      const std::string& data);
+    static void DecodeBase64(std::string& result, 
+                             const std::string& data);
 
-    void EncodeBase64(std::string& result, 
-                      const std::string& data);
+    static void EncodeBase64(std::string& result, 
+                             const std::string& data);
 
-    bool DecodeDataUriScheme(std::string& mime,
-                             std::string& content,
-                             const std::string& source);
+    static bool DecodeDataUriScheme(std::string& mime,
+                                    std::string& content,
+                                    const std::string& source);
 
-    void EncodeDataUriScheme(std::string& result,
-                             const std::string& mime,
-                             const std::string& content);
+    static 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,
-                              bool hasCodeExtensions);
+    static std::string ConvertToUtf8(const std::string& source,
+                                     Encoding sourceEncoding,
+                                     bool hasCodeExtensions);
 
-    std::string ConvertFromUtf8(const std::string& source,
-                                Encoding targetEncoding);
+    static std::string ConvertFromUtf8(const std::string& source,
+                                       Encoding targetEncoding);
 #endif
 
-    bool IsAsciiString(const void* data,
-                       size_t size);
+    static bool IsAsciiString(const void* data,
+                              size_t size);
 
-    bool IsAsciiString(const std::string& s);
+    static bool IsAsciiString(const std::string& s);
 
-    std::string ConvertToAscii(const std::string& source);
+    static std::string ConvertToAscii(const std::string& source);
 
-    std::string StripSpaces(const std::string& source);
+    static std::string StripSpaces(const std::string& source);
 
     // In-place percent-decoding for URL
-    void UrlDecode(std::string& s);
+    static void UrlDecode(std::string& s);
 
-    Endianness DetectEndianness();
+    static Endianness DetectEndianness();
 
-    std::string WildcardToRegularExpression(const std::string& s);
+    static std::string WildcardToRegularExpression(const std::string& s);
 
-    void TokenizeString(std::vector<std::string>& result,
-                        const std::string& source,
-                        char separator);
+    static void TokenizeString(std::vector<std::string>& result,
+                               const std::string& source,
+                               char separator);
 
 #if ORTHANC_ENABLE_PUGIXML == 1
-    void JsonToXml(std::string& target,
-                   const Json::Value& source,
-                   const std::string& rootElement = "root",
-                   const std::string& arrayElement = "item");
+    static void JsonToXml(std::string& target,
+                          const Json::Value& source,
+                          const std::string& rootElement = "root",
+                          const std::string& arrayElement = "item");
 #endif
 
 #if ORTHANC_ENABLE_PUGIXML == 1
-    void XmlToString(std::string& target,
-                     const pugi::xml_document& source);
+    static void XmlToString(std::string& target,
+                            const pugi::xml_document& source);
 #endif
 
-    bool IsInteger(const std::string& str);
+    static bool IsInteger(const std::string& str);
 
-    void CopyJsonWithoutComments(Json::Value& target,
-                                 const Json::Value& source);
+    static void CopyJsonWithoutComments(Json::Value& target,
+                                        const Json::Value& source);
 
-    bool StartsWith(const std::string& str,
-                    const std::string& prefix);
+    static bool StartsWith(const std::string& str,
+                           const std::string& prefix);
 
-    void UriEncode(std::string& target,
-                   const std::string& source);
+    static void UriEncode(std::string& target,
+                          const std::string& source);
 
-    std::string GetJsonStringField(const ::Json::Value& json,
-                                   const std::string& key,
-                                   const std::string& defaultValue);
+    static std::string GetJsonStringField(const ::Json::Value& json,
+                                          const std::string& key,
+                                          const std::string& defaultValue);
 
-    bool GetJsonBooleanField(const ::Json::Value& json,
-                             const std::string& key,
-                             bool defaultValue);
+    static bool GetJsonBooleanField(const ::Json::Value& json,
+                                    const std::string& key,
+                                    bool defaultValue);
 
-    int GetJsonIntegerField(const ::Json::Value& json,
-                            const std::string& key,
-                            int defaultValue);
+    static int GetJsonIntegerField(const ::Json::Value& json,
+                                   const std::string& key,
+                                   int defaultValue);
 
-    unsigned int GetJsonUnsignedIntegerField(const ::Json::Value& json,
-                                             const std::string& key,
-                                             unsigned int defaultValue);
+    static unsigned int GetJsonUnsignedIntegerField(const ::Json::Value& json,
+                                                    const std::string& key,
+                                                    unsigned int defaultValue);
 
-    bool IsUuid(const std::string& str);
+    static bool IsUuid(const std::string& str);
 
-    bool StartsWithUuid(const std::string& str);
+    static bool StartsWithUuid(const std::string& str);
 
 #if ORTHANC_ENABLE_LOCALE == 1
-    void InitializeGlobalLocale(const char* locale);
+    static void InitializeGlobalLocale(const char* locale);
 
-    void FinalizeGlobalLocale();
+    static void FinalizeGlobalLocale();
 
-    std::string ToUpperCaseWithAccents(const std::string& source);
+    static std::string ToUpperCaseWithAccents(const std::string& source);
 #endif
 
-    void InitializeOpenSsl();
+    static void InitializeOpenSsl();
     
-    void FinalizeOpenSsl();
+    static void FinalizeOpenSsl();
 
-    std::string GenerateUuid();
+    static std::string GenerateUuid();
 
-    std::string SubstituteVariables(const std::string& source,
-                                    const std::map<std::string, std::string>& dictionary);
+    static std::string SubstituteVariables(const std::string& source,
+                                           const std::map<std::string, std::string>& dictionary);
 
-    void RemoveIso2022EscapeSequences(std::string& dest,
-                                      const std::string& src);
+    static void RemoveIso2022EscapeSequences(std::string& dest,
+                                             const std::string& src);
 
-    void Utf8ToUnicodeCharacter(uint32_t& unicode,
-                                size_t& utf8Length,
-                                const std::string& utf8,
-                                size_t position);
+    static void Utf8ToUnicodeCharacter(uint32_t& unicode,
+                                       size_t& utf8Length,
+                                       const std::string& utf8,
+                                       size_t position);
 
-    std::string LargeHexadecimalToDecimal(const std::string& hex);
+    static std::string LargeHexadecimalToDecimal(const std::string& hex);
 
     // http://dicom.nema.org/medical/dicom/2019a/output/chtml/part05/sect_B.2.html
-    std::string GenerateDicomPrivateUniqueIdentifier();
-  }
+    static std::string GenerateDicomPrivateUniqueIdentifier();
+  };
 }
 
 
--- a/OrthancServer/ServerEnumerations.cpp	Fri May 29 19:43:28 2020 +0200
+++ b/OrthancServer/ServerEnumerations.cpp	Fri May 29 21:23:57 2020 +0200
@@ -46,8 +46,8 @@
   typedef std::map<FileContentType, std::string>  MimeTypes;
 
   static boost::mutex enumerationsMutex_;
-  static Toolbox::EnumerationDictionary<MetadataType> dictMetadataType_;
-  static Toolbox::EnumerationDictionary<FileContentType> dictContentType_;
+  static EnumerationDictionary<MetadataType> dictMetadataType_;
+  static EnumerationDictionary<FileContentType> dictContentType_;
   static MimeTypes  mimeTypes_;
 
   void InitializeServerEnumerations()
--- a/UnitTestsSources/UnitTestsMain.cpp	Fri May 29 19:43:28 2020 +0200
+++ b/UnitTestsSources/UnitTestsMain.cpp	Fri May 29 21:23:57 2020 +0200
@@ -49,7 +49,7 @@
 
 TEST(EnumerationDictionary, Simple)
 {
-  Toolbox::EnumerationDictionary<MetadataType>  d;
+  EnumerationDictionary<MetadataType>  d;
 
   ASSERT_THROW(d.Translate("ReceptionDate"), OrthancException);
   ASSERT_EQ(MetadataType_ModifiedFrom, d.Translate("5"));