changeset 2202:9b373b7d6713

Fix handling of encodings in C-FIND requests
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 08 Dec 2016 12:45:06 +0100
parents 307365d0991a
children 7d5320c59a05
files Core/DicomFormat/DicomMap.h Core/Enumerations.cpp NEWS OrthancServer/DicomProtocol/DicomFindAnswers.cpp OrthancServer/DicomProtocol/DicomUserConnection.cpp OrthancServer/OrthancInitialization.cpp OrthancServer/OrthancInitialization.h OrthancServer/OrthancRestApi/OrthancRestSystem.cpp OrthancServer/ParsedDicomFile.cpp OrthancServer/ParsedDicomFile.h OrthancServer/ToDcmtkBridge.cpp OrthancServer/ToDcmtkBridge.h TODO UnitTestsSources/FromDcmtkTests.cpp
diffstat 14 files changed, 255 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomFormat/DicomMap.h	Tue Dec 06 14:40:46 2016 +0100
+++ b/Core/DicomFormat/DicomMap.h	Thu Dec 08 12:45:06 2016 +0100
@@ -47,7 +47,7 @@
   private:
     friend class DicomArray;
     friend class FromDcmtkBridge;
-    friend class ToDcmtkBridge;
+    friend class ParsedDicomFile;
 
     typedef std::map<DicomTag, DicomValue*>  Map;
 
--- a/Core/Enumerations.cpp	Tue Dec 06 14:40:46 2016 +0100
+++ b/Core/Enumerations.cpp	Thu Dec 08 12:45:06 2016 +0100
@@ -1083,15 +1083,18 @@
   bool GetDicomEncoding(Encoding& encoding,
                         const char* specificCharacterSet)
   {
-    std::string s = specificCharacterSet;
+    std::string s = Toolbox::StripSpaces(specificCharacterSet);
     Toolbox::ToUpperCase(s);
 
     // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.12.1.1.2
     // https://github.com/dcm4che/dcm4che/blob/master/dcm4che-core/src/main/java/org/dcm4che3/data/SpecificCharacterSet.java
     if (s == "ISO_IR 6" ||
-        s == "ISO_IR 192" ||
         s == "ISO 2022 IR 6")
     {
+      encoding = Encoding_Ascii;
+    }
+    else if (s == "ISO_IR 192")
+    {
       encoding = Encoding_Utf8;
     }
     else if (s == "ISO_IR 100" ||
@@ -1238,8 +1241,10 @@
     // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.12.1.1.2
     switch (encoding)
     {
+      case Encoding_Ascii:
+        return "ISO_IR 6";
+
       case Encoding_Utf8:
-      case Encoding_Ascii:
         return "ISO_IR 192";
 
       case Encoding_Latin1:
--- a/NEWS	Tue Dec 06 14:40:46 2016 +0100
+++ b/NEWS	Thu Dec 08 12:45:06 2016 +0100
@@ -18,6 +18,7 @@
   to avoid waiting for the completion of image transfers
 * Possibility to DELETE "dicom-as-json" attachments to reconstruct the JSON summaries
 * "Keep" option for modifications to keep original DICOM identifiers (advanced feature)
+* "/tools/default-encoding" to get or temporarily change the default encoding
 
 Plugins
 -------
@@ -29,6 +30,7 @@
 Maintenance
 -----------
 
+* Fix handling of encodings in C-FIND requests
 * Use of DCMTK 3.6.1 dictionary of private tags in standalone builds
 * Avoid hard crash if not enough memory (handling of std::bad_alloc)
 * Improved robustness of Orthanc Explorer wrt. query/retrieve (maybe fix issue 24)
--- a/OrthancServer/DicomProtocol/DicomFindAnswers.cpp	Tue Dec 06 14:40:46 2016 +0100
+++ b/OrthancServer/DicomProtocol/DicomFindAnswers.cpp	Thu Dec 08 12:45:06 2016 +0100
@@ -109,19 +109,6 @@
 
       return *dicom_;
     }
-
-    DcmDataset* ExtractDcmDataset() const
-    {
-      if (dicom_ != NULL)
-      {
-        return new DcmDataset(*dicom_->GetDcmtkObject().getDataset());
-      }
-      else
-      {
-        assert(map_ != NULL);
-        return ToDcmtkBridge::Convert(*map_);
-      }
-    }
   };
 
 
@@ -200,7 +187,7 @@
 
   DcmDataset* DicomFindAnswers::ExtractDcmDataset(size_t index) const
   {
-    return GetAnswerInternal(index).ExtractDcmDataset();
+    return new DcmDataset(*GetAnswer(index).GetDcmtkObject().getDataset());
   }
 
 
--- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp	Tue Dec 06 14:40:46 2016 +0100
+++ b/OrthancServer/DicomProtocol/DicomUserConnection.cpp	Thu Dec 08 12:45:06 2016 +0100
@@ -478,8 +478,8 @@
   }
 
 
-  static DcmDataset* ConvertQueryFields(const DicomMap& fields,
-                                        ModalityManufacturer manufacturer)
+  static ParsedDicomFile* ConvertQueryFields(const DicomMap& fields,
+                                             ModalityManufacturer manufacturer)
   {
     switch (manufacturer)
     {
@@ -513,11 +513,11 @@
           }
         }
 
-        return ToDcmtkBridge::Convert(*fix);
+        return new ParsedDicomFile(*fix);
       }
 
       default:
-        return ToDcmtkBridge::Convert(fields);
+        return new ParsedDicomFile(fields);
     }
   }
 
@@ -577,7 +577,9 @@
 
     CheckIsOpen();
 
-    std::auto_ptr<DcmDataset> dataset(ConvertQueryFields(fields, manufacturer_));
+    std::auto_ptr<ParsedDicomFile> query(ConvertQueryFields(fields, manufacturer_));
+    DcmDataset* dataset = query->GetDcmtkObject().getDataset();
+
     const char* clevel = NULL;
     const char* sopClass = NULL;
 
@@ -585,19 +587,19 @@
     {
       case ResourceType_Patient:
         clevel = "PATIENT";
-        DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "PATIENT");
+        DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "PATIENT");
         sopClass = UID_FINDPatientRootQueryRetrieveInformationModel;
         break;
 
       case ResourceType_Study:
         clevel = "STUDY";
-        DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "STUDY");
+        DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "STUDY");
         sopClass = UID_FINDStudyRootQueryRetrieveInformationModel;
         break;
 
       case ResourceType_Series:
         clevel = "SERIES";
-        DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "SERIES");
+        DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "SERIES");
         sopClass = UID_FINDStudyRootQueryRetrieveInformationModel;
         break;
 
@@ -609,11 +611,11 @@
           // This is a particular case for ClearCanvas, thanks to Peter Somlo <peter.somlo@gmail.com>.
           // https://groups.google.com/d/msg/orthanc-users/j-6C3MAVwiw/iolB9hclom8J
           // http://www.clearcanvas.ca/Home/Community/OldForums/tabid/526/aff/11/aft/14670/afv/topic/Default.aspx
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "IMAGE");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "IMAGE");
         }
         else
         {
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "INSTANCE");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "INSTANCE");
         }
 
         sopClass = UID_FINDStudyRootQueryRetrieveInformationModel;
@@ -630,26 +632,26 @@
       case ResourceType_Instance:
         // SOP Instance UID
         if (!fields.HasTag(0x0008, 0x0018))
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0018), "");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0018), "");
 
       case ResourceType_Series:
         // Series instance UID
         if (!fields.HasTag(0x0020, 0x000e))
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0020, 0x000e), "");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0020, 0x000e), "");
 
       case ResourceType_Study:
         // Accession number
         if (!fields.HasTag(0x0008, 0x0050))
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0050), "");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0050), "");
 
         // Study instance UID
         if (!fields.HasTag(0x0020, 0x000d))
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0020, 0x000d), "");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0020, 0x000d), "");
 
       case ResourceType_Patient:
         // Patient ID
         if (!fields.HasTag(0x0010, 0x0020))
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0010, 0x0020), "");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0010, 0x0020), "");
 
         break;
 
@@ -658,7 +660,7 @@
     }
 
     assert(clevel != NULL && sopClass != NULL);
-    ExecuteFind(result, pimpl_->assoc_, dataset.get(), sopClass, false, clevel, pimpl_->dimseTimeout_);
+    ExecuteFind(result, pimpl_->assoc_, dataset, sopClass, false, clevel, pimpl_->dimseTimeout_);
   }
 
 
@@ -668,21 +670,22 @@
   {
     CheckIsOpen();
 
-    std::auto_ptr<DcmDataset> dataset(ConvertQueryFields(fields, manufacturer_));
+    std::auto_ptr<ParsedDicomFile> query(ConvertQueryFields(fields, manufacturer_));
+    DcmDataset* dataset = query->GetDcmtkObject().getDataset();
 
     const char* sopClass = UID_MOVEStudyRootQueryRetrieveInformationModel;
     switch (level)
     {
       case ResourceType_Patient:
-        DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "PATIENT");
+        DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "PATIENT");
         break;
 
       case ResourceType_Study:
-        DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "STUDY");
+        DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "STUDY");
         break;
 
       case ResourceType_Series:
-        DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "SERIES");
+        DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "SERIES");
         break;
 
       case ResourceType_Instance:
@@ -692,11 +695,11 @@
           // This is a particular case for ClearCanvas, thanks to Peter Somlo <peter.somlo@gmail.com>.
           // https://groups.google.com/d/msg/orthanc-users/j-6C3MAVwiw/iolB9hclom8J
           // http://www.clearcanvas.ca/Home/Community/OldForums/tabid/526/aff/11/aft/14670/afv/topic/Default.aspx
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "IMAGE");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "IMAGE");
         }
         else
         {
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "INSTANCE");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "INSTANCE");
         }
         break;
 
@@ -722,7 +725,7 @@
     T_DIMSE_C_MoveRSP response;
     DcmDataset* statusDetail = NULL;
     DcmDataset* responseIdentifiers = NULL;
-    OFCondition cond = DIMSE_moveUser(pimpl_->assoc_, presID, &request, dataset.get(),
+    OFCondition cond = DIMSE_moveUser(pimpl_->assoc_, presID, &request, dataset,
                                       NULL, NULL,
                                       /*opt_blockMode*/ DIMSE_BLOCKING, 
                                       /*opt_dimse_timeout*/ pimpl_->dimseTimeout_,
--- a/OrthancServer/OrthancInitialization.cpp	Tue Dec 06 14:40:46 2016 +0100
+++ b/OrthancServer/OrthancInitialization.cpp	Thu Dec 08 12:45:06 2016 +0100
@@ -1111,6 +1111,19 @@
   }
 
 
+  void Configuration::SetDefaultEncoding(Encoding encoding)
+  {
+    std::string name = EnumerationToString(encoding);
+
+    {
+      boost::recursive_mutex::scoped_lock lock(globalMutex_);
+      configuration_["DefaultEncoding"] = name;
+    }
+
+    LOG(INFO) << "Default encoding was changed to: " << name;
+  }
+
+
   bool Configuration::HasConfigurationChanged()
   {
     Json::Value starting;
--- a/OrthancServer/OrthancInitialization.h	Tue Dec 06 14:40:46 2016 +0100
+++ b/OrthancServer/OrthancInitialization.h	Thu Dec 08 12:45:06 2016 +0100
@@ -138,6 +138,8 @@
 
     static Encoding GetDefaultEncoding();
 
+    static void SetDefaultEncoding(Encoding encoding);
+
     static bool HasConfigurationChanged();
 
 
--- a/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp	Tue Dec 06 14:40:46 2016 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp	Thu Dec 08 12:45:06 2016 +0100
@@ -248,6 +248,23 @@
   }
 
 
+  static void GetDefaultEncoding(RestApiGetCall& call)
+  {
+    Encoding encoding = Configuration::GetDefaultEncoding();
+    call.GetOutput().AnswerBuffer(EnumerationToString(encoding), "text/plain");
+  }
+
+
+  static void SetDefaultEncoding(RestApiPutCall& call)
+  {
+    Encoding encoding = StringToEncoding(call.GetBodyData());
+
+    Configuration::SetDefaultEncoding(encoding);
+
+    call.GetOutput().AnswerBuffer(EnumerationToString(encoding), "text/plain");
+  }
+
+
   void OrthancRestApi::RegisterSystem()
   {
     Register("/", ServeRoot);
@@ -257,6 +274,8 @@
     Register("/tools/execute-script", ExecuteScript);
     Register("/tools/now", GetNowIsoString);
     Register("/tools/dicom-conformance", GetDicomConformanceStatement);
+    Register("/tools/default-encoding", GetDefaultEncoding);
+    Register("/tools/default-encoding", SetDefaultEncoding);
 
     Register("/plugins", ListPlugins);
     Register("/plugins/{id}", GetPlugin);
--- a/OrthancServer/ParsedDicomFile.cpp	Tue Dec 06 14:40:46 2016 +0100
+++ b/OrthancServer/ParsedDicomFile.cpp	Thu Dec 08 12:45:06 2016 +0100
@@ -872,15 +872,55 @@
   }
 
 
-  ParsedDicomFile::ParsedDicomFile(const DicomMap& map) : pimpl_(new PImpl)
+  void ParsedDicomFile::CreateFromDicomMap(const DicomMap& source,
+                                           Encoding defaultEncoding)
   {
-    std::auto_ptr<DcmDataset> dataset(ToDcmtkBridge::Convert(map));
+    pimpl_->file_.reset(new DcmFileFormat);
+
+    const DicomValue* tmp = source.TestAndGetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET);
+    if (tmp != NULL)
+    {
+      Encoding encoding;
+      if (tmp->IsNull() ||
+          tmp->IsBinary() ||
+          !GetDicomEncoding(encoding, tmp->GetContent().c_str()))
+      {
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+      else
+      {
+        SetEncoding(encoding);
+      }
+    }
+    else
+    {
+      SetEncoding(defaultEncoding);
+    }
 
-    // NOTE: This implies an unnecessary memory copy of the dataset, but no way to get around
-    // http://support.dcmtk.org/redmine/issues/544
-    std::auto_ptr<DcmFileFormat> fileFormat(new DcmFileFormat(dataset.get()));
+    for (DicomMap::Map::const_iterator 
+           it = source.map_.begin(); it != source.map_.end(); ++it)
+    {
+      if (it->first != DICOM_TAG_SPECIFIC_CHARACTER_SET &&
+          !it->second->IsNull())
+      {
+        ReplacePlainString(it->first, it->second->GetContent());
+      }
+    }
+  }
+
 
-    pimpl_->file_.reset(fileFormat.release());
+  ParsedDicomFile::ParsedDicomFile(const DicomMap& map,
+                                   Encoding defaultEncoding) :
+    pimpl_(new PImpl)
+  {
+    CreateFromDicomMap(map, defaultEncoding);
+  }
+
+
+  ParsedDicomFile::ParsedDicomFile(const DicomMap& map) : 
+    pimpl_(new PImpl)
+  {
+    CreateFromDicomMap(map, Configuration::GetDefaultEncoding());
   }
 
 
--- a/OrthancServer/ParsedDicomFile.h	Tue Dec 06 14:40:46 2016 +0100
+++ b/OrthancServer/ParsedDicomFile.h	Thu Dec 08 12:45:06 2016 +0100
@@ -52,6 +52,9 @@
 
     ParsedDicomFile(ParsedDicomFile& other);
 
+    void CreateFromDicomMap(const DicomMap& source,
+                            Encoding defaultEncoding);
+
     void RemovePrivateTagsInternal(const std::set<DicomTag>* toKeep);
 
     void UpdateStorageUid(const DicomTag& tag,
@@ -65,6 +68,9 @@
   public:
     ParsedDicomFile(bool createIdentifiers);  // Create a minimal DICOM instance
 
+    ParsedDicomFile(const DicomMap& map,
+                    Encoding defaultEncoding);
+
     ParsedDicomFile(const DicomMap& map);
 
     ParsedDicomFile(const void* content,
--- a/OrthancServer/ToDcmtkBridge.cpp	Tue Dec 06 14:40:46 2016 +0100
+++ b/OrthancServer/ToDcmtkBridge.cpp	Thu Dec 08 12:45:06 2016 +0100
@@ -41,24 +41,6 @@
 
 namespace Orthanc
 {
-  DcmDataset* ToDcmtkBridge::Convert(const DicomMap& map)
-  {
-    std::auto_ptr<DcmDataset> result(new DcmDataset);
-
-    for (DicomMap::Map::const_iterator 
-           it = map.map_.begin(); it != map.map_.end(); ++it)
-    {
-      if (!it->second->IsNull())
-      {
-        std::string s = it->second->GetContent();
-        DU_putStringDOElement(result.get(), Convert(it->first), s.c_str());
-      }
-    }
-
-    return result.release();
-  }
-
-
   DcmEVR ToDcmtkBridge::Convert(ValueRepresentation vr)
   {
     switch (vr)
--- a/OrthancServer/ToDcmtkBridge.h	Tue Dec 06 14:40:46 2016 +0100
+++ b/OrthancServer/ToDcmtkBridge.h	Thu Dec 08 12:45:06 2016 +0100
@@ -45,8 +45,6 @@
       return DcmTagKey(tag.GetGroup(), tag.GetElement());
     }
 
-    static DcmDataset* Convert(const DicomMap& map);
-
     static DcmEVR Convert(ValueRepresentation vr);
   };
 }
--- a/TODO	Tue Dec 06 14:40:46 2016 +0100
+++ b/TODO	Thu Dec 08 12:45:06 2016 +0100
@@ -114,6 +114,8 @@
 
 * Use Semaphore::Locker everywhere (instead of explicit
   Release() and Acquire())
+* Avoid direct calls to FromDcmtkBridge, go through ParsedDicomFile
+  wherever possible
 
 
 =================
--- a/UnitTestsSources/FromDcmtkTests.cpp	Tue Dec 06 14:40:46 2016 +0100
+++ b/UnitTestsSources/FromDcmtkTests.cpp	Thu Dec 08 12:45:06 2016 +0100
@@ -51,6 +51,7 @@
 #include "../Plugins/Engine/PluginsEnumerations.h"
 
 #include <dcmtk/dcmdata/dcelem.h>
+#include <dcmtk/dcmdata/dcdeftag.h>
 
 using namespace Orthanc;
 
@@ -225,7 +226,7 @@
   Encoding e;
 
   ASSERT_FALSE(GetDicomEncoding(e, ""));
-  ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 6"));  ASSERT_EQ(Encoding_Utf8, e);
+  ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 6"));  ASSERT_EQ(Encoding_Ascii, e);
 
   // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#table_C.12-2
   ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 100"));  ASSERT_EQ(Encoding_Latin1, e);
@@ -241,7 +242,7 @@
   ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 166"));  ASSERT_EQ(Encoding_Thai, e);
 
   // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#table_C.12-3
-  ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 6"));    ASSERT_EQ(Encoding_Utf8, e);
+  ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 6"));    ASSERT_EQ(Encoding_Ascii, e);
   ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 100"));  ASSERT_EQ(Encoding_Latin1, e);
   ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 101"));  ASSERT_EQ(Encoding_Latin2, e);
   ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 109"));  ASSERT_EQ(Encoding_Latin3, e);
@@ -1042,3 +1043,129 @@
     }
   }
 }
+
+
+
+static void CheckEncoding(const ParsedDicomFile& dicom,
+                          Encoding expected)
+{
+  const char* value = NULL;
+  ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->findAndGetString(DCM_SpecificCharacterSet, value).good());
+
+  Encoding encoding;
+  ASSERT_TRUE(GetDicomEncoding(encoding, value));
+  ASSERT_EQ(expected, encoding);
+}
+
+
+TEST(ParsedDicomFile, DicomMapEncodings1)
+{
+  Configuration::SetDefaultEncoding(Encoding_Ascii);
+  ASSERT_EQ(Encoding_Ascii, Configuration::GetDefaultEncoding());
+
+  {
+    DicomMap m;
+    ParsedDicomFile dicom(m);
+    ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+    CheckEncoding(dicom, Encoding_Ascii);
+  }
+
+  {
+    DicomMap m;
+    ParsedDicomFile dicom(m, Encoding_Latin4);
+    ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+    CheckEncoding(dicom, Encoding_Latin4);
+  }
+
+  {
+    DicomMap m;
+    m.SetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET, "ISO_IR 148", false);
+    ParsedDicomFile dicom(m);
+    ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+    CheckEncoding(dicom, Encoding_Latin5);
+  }
+
+  {
+    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());
+    CheckEncoding(dicom, Encoding_Latin5);
+  }
+}
+
+
+TEST(ParsedDicomFile, DicomMapEncodings2)
+{
+  const char* utf8 = NULL;
+  for (unsigned int i = 0; i < testEncodingsCount; i++)
+  {
+    if (testEncodings[i] == Encoding_Utf8)
+    {
+      utf8 = testEncodingsEncoded[i];
+      break;
+    }
+  }  
+
+  ASSERT_TRUE(utf8 != NULL);
+
+  for (unsigned int i = 0; i < testEncodingsCount; i++)
+  {
+    // 1251 codepage is not supported by the core DICOM standard, ignore it
+    if (testEncodings[i] != Encoding_Windows1251) 
+    {
+      {
+        // Sanity check to test the proper behavior of "EncodingTests.py"
+        std::string encoded = Toolbox::ConvertFromUtf8(testEncodingsExpected[i], testEncodings[i]);
+        ASSERT_STREQ(testEncodingsEncoded[i], encoded.c_str());
+        std::string decoded = Toolbox::ConvertToUtf8(encoded, testEncodings[i]);
+        ASSERT_STREQ(testEncodingsExpected[i], decoded.c_str());
+
+        if (testEncodings[i] != Encoding_Chinese)
+        {
+          // A specific source string is used in "EncodingTests.py" to
+          // test against Chinese, it is normal that it does not correspond to UTF8
+
+          std::string encoded = Toolbox::ConvertToUtf8(Toolbox::ConvertFromUtf8(utf8, testEncodings[i]), testEncodings[i]);
+          ASSERT_STREQ(testEncodingsExpected[i], encoded.c_str());
+        }
+      }
+
+
+      Json::Value v;
+
+      {
+        DicomMap m;
+        m.SetValue(DICOM_TAG_PATIENT_NAME, testEncodingsExpected[i], false);
+
+        ParsedDicomFile dicom(m, testEncodings[i]);
+    
+        const char* encoded = NULL;
+        ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->findAndGetString(DCM_PatientName, encoded).good());
+        ASSERT_STREQ(testEncodingsEncoded[i], encoded);
+
+        dicom.DatasetToJson(v, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
+
+        Encoding encoding;
+        ASSERT_TRUE(GetDicomEncoding(encoding, v["SpecificCharacterSet"].asCString()));
+        ASSERT_EQ(encoding, testEncodings[i]);
+        ASSERT_STREQ(testEncodingsExpected[i], v["PatientName"].asCString());
+      }
+
+
+      {
+        DicomMap m;
+        m.SetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET, GetDicomSpecificCharacterSet(testEncodings[i]), false);
+        m.SetValue(DICOM_TAG_PATIENT_NAME, testEncodingsExpected[i], false);
+
+        ParsedDicomFile dicom(m, testEncodings[i]);
+
+        Json::Value v2;
+        dicom.DatasetToJson(v2, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
+        
+        ASSERT_EQ(v2["PatientName"].asString(), v["PatientName"].asString());
+        ASSERT_EQ(v2["SpecificCharacterSet"].asString(), v["SpecificCharacterSet"].asString());
+      }
+    }
+  }
+}