changeset 3691:4922bdd046dd

Fix issue #140 (Modifying private tags with REST API changes VR from LO to UN) - DANGEROUS COMMIT
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 25 Feb 2020 21:44:09 +0100
parents a9ce35d67c3c
children fd302ec6a502
files Core/DicomNetworking/Internals/CommandDispatcher.cpp Core/DicomParsing/DicomModification.cpp Core/DicomParsing/DicomModification.h Core/DicomParsing/FromDcmtkBridge.cpp Core/DicomParsing/FromDcmtkBridge.h Core/DicomParsing/ITagVisitor.h Core/DicomParsing/ParsedDicomFile.cpp Core/DicomParsing/ParsedDicomFile.h NEWS OrthancServer/OrthancFindRequestHandler.cpp OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp OrthancServer/OrthancRestApi/OrthancRestModalities.cpp OrthancServer/Search/HierarchicalMatcher.cpp Plugins/Engine/OrthancPlugins.cpp Resources/Graveyard/FromDcmtkBridge.cpp UnitTestsSources/DicomMapTests.cpp UnitTestsSources/FromDcmtkTests.cpp UnitTestsSources/MultiThreadingTests.cpp
diffstat 18 files changed, 454 insertions(+), 313 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomNetworking/Internals/CommandDispatcher.cpp	Tue Feb 25 13:57:43 2020 +0100
+++ b/Core/DicomNetworking/Internals/CommandDispatcher.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -430,6 +430,7 @@
         transferSyntaxes.push_back(UID_MPEG2MainProfileAtHighLevelTransferSyntax);
       }
 
+#if DCMTK_VERSION_NUMBER >= 361
       // New in Orthanc 1.6.0
       if (!server.HasApplicationEntityFilter() ||
           server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Mpeg4))
@@ -440,6 +441,7 @@
         transferSyntaxes.push_back(UID_MPEG4HighProfileLevel4_2_For3DVideoTransferSyntax);
         transferSyntaxes.push_back(UID_MPEG4StereoHighProfileLevel4_2TransferSyntax);
       }
+#endif
 
       if (!server.HasApplicationEntityFilter() ||
           server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Rle))
--- a/Core/DicomParsing/DicomModification.cpp	Tue Feb 25 13:57:43 2020 +0100
+++ b/Core/DicomParsing/DicomModification.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -347,7 +347,7 @@
 
     dicom.Replace(*tag, mapped, 
                   false /* don't try and decode data URI scheme for UIDs */, 
-                  DicomReplaceMode_InsertIfAbsent);
+                  DicomReplaceMode_InsertIfAbsent, privateCreator_);
   }
 
   
@@ -359,6 +359,7 @@
     keepSeriesInstanceUid_(false),
     updateReferencedRelationships_(true),
     isAnonymization_(false),
+    //privateCreator_("PrivateCreator"),
     identifierGenerator_(NULL)
   {
   }
@@ -1067,7 +1068,8 @@
     for (Replacements::const_iterator it = replacements_.begin(); 
          it != replacements_.end(); ++it)
     {
-      toModify.Replace(it->first, *it->second, true /* decode data URI scheme */, DicomReplaceMode_InsertIfAbsent);
+      toModify.Replace(it->first, *it->second, true /* decode data URI scheme */,
+                       DicomReplaceMode_InsertIfAbsent, privateCreator_);
     }
 
     // (6) Update the DICOM identifiers
@@ -1262,6 +1264,12 @@
     {
       ParseListOfTags(*this, request["Keep"], TagOperation_Keep, force);
     }
+
+    // New in Orthanc 1.6.0
+    if (request.isMember("PrivateCreator"))
+    {
+      privateCreator_ = SerializationToolbox::ReadString(request, "PrivateCreator");
+    }
   }
 
 
@@ -1336,6 +1344,7 @@
   static const char* MAP_STUDIES = "MapStudies";
   static const char* MAP_SERIES = "MapSeries";
   static const char* MAP_INSTANCES = "MapInstances";
+  static const char* PRIVATE_CREATOR = "PrivateCreator";  // New in Orthanc 1.6.0
   
   void DicomModification::Serialize(Json::Value& value) const
   {
@@ -1353,6 +1362,7 @@
     value[KEEP_SERIES_INSTANCE_UID] = keepSeriesInstanceUid_;
     value[UPDATE_REFERENCED_RELATIONSHIPS] = updateReferencedRelationships_;
     value[IS_ANONYMIZATION] = isAnonymization_;
+    value[PRIVATE_CREATOR] = privateCreator_;
 
     SerializationToolbox::WriteSetOfTags(value, removals_, REMOVALS);
     SerializationToolbox::WriteSetOfTags(value, clearings_, CLEARINGS);
@@ -1451,6 +1461,11 @@
       (serialized, UPDATE_REFERENCED_RELATIONSHIPS);
     isAnonymization_ = SerializationToolbox::ReadBoolean(serialized, IS_ANONYMIZATION);
 
+    if (serialized.isMember(PRIVATE_CREATOR))
+    {
+      privateCreator_ = SerializationToolbox::ReadString(serialized, PRIVATE_CREATOR);
+    }
+
     SerializationToolbox::ReadSetOfTags(removals_, serialized, REMOVALS);
     SerializationToolbox::ReadSetOfTags(clearings_, serialized, CLEARINGS);
     SerializationToolbox::ReadSetOfTags(privateTagsToKeep_, serialized, PRIVATE_TAGS_TO_KEEP);
--- a/Core/DicomParsing/DicomModification.h	Tue Feb 25 13:57:43 2020 +0100
+++ b/Core/DicomParsing/DicomModification.h	Tue Feb 25 21:44:09 2020 +0100
@@ -86,6 +86,7 @@
     bool updateReferencedRelationships_;
     bool isAnonymization_;
     DicomMap currentSource_;
+    std::string privateCreator_;
 
     IDicomIdentifierGenerator* identifierGenerator_;
 
@@ -185,5 +186,15 @@
     }
 
     void Serialize(Json::Value& value) const;
+
+    void SetPrivateCreator(std::string& privateCreator)
+    {
+      privateCreator_ = privateCreator;
+    }
+
+    const std::string& GetPrivateCreator()
+    {
+      return privateCreator_;
+    }
   };
 }
--- a/Core/DicomParsing/FromDcmtkBridge.cpp	Tue Feb 25 13:57:43 2020 +0100
+++ b/Core/DicomParsing/FromDcmtkBridge.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -115,6 +115,16 @@
 
 namespace Orthanc
 {
+  static bool IsBinaryTag(const DcmTag& key)
+  {
+    return (key.isUnknownVR() ||
+            key.getEVR() == EVR_OB ||
+            key.getEVR() == EVR_OW ||
+            key.getEVR() == EVR_UN ||
+            key.getEVR() == EVR_ox);
+  }
+
+
 #if DCMTK_USE_EMBEDDED_DICTIONARIES == 1
   static void LoadEmbeddedDictionary(DcmDataDictionary& dictionary,
                                      EmbeddedResources::FileResourceId resource)
@@ -938,18 +948,13 @@
       if (!(flags & DicomToJsonFlags_IncludeUnknownTags))
       {
         DictionaryLocker locker;
-        if (locker->findEntry(element->getTag(), NULL) == NULL)
+        if (locker->findEntry(element->getTag(), element->getTag().getPrivateCreator()) == NULL)
         {
           continue;
         }
       }
 
-      DcmEVR evr = element->getTag().getEVR();
-      if (evr == EVR_OB ||
-          evr == EVR_OF ||
-          evr == EVR_OW ||
-          evr == EVR_UN ||
-          evr == EVR_ox)
+      if (IsBinaryTag(element->getTag()))
       {
         // This is a binary tag
         if ((tag == DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludePixelData)) ||
@@ -1371,189 +1376,49 @@
   }
 
 
-  static bool IsBinaryTag(const DcmTag& key)
+  DcmElement* FromDcmtkBridge::CreateElementForTag(const DicomTag& tag,
+                                                   const std::string& privateCreator)
   {
-    return (key.isUnknownVR() ||
-#if DCMTK_VERSION_NUMBER >= 361
-            key.getEVR() == EVR_OD ||
-#endif
-            
-#if DCMTK_VERSION_NUMBER >= 362
-            key.getEVR() == EVR_OL ||
-#endif            
-            key.getEVR() == EVR_OB ||
-            key.getEVR() == EVR_OF ||
-            key.getEVR() == EVR_OW ||
-            key.getEVR() == EVR_UN ||
-            key.getEVR() == EVR_ox);
-  }
-
-
-  DcmElement* FromDcmtkBridge::CreateElementForTag(const DicomTag& tag)
-  {
-    DcmTag key(tag.GetGroup(), tag.GetElement());
-
-    if (tag.IsPrivate() ||
-        IsBinaryTag(key))
+    if (tag.IsPrivate() &&
+        privateCreator.empty())
     {
-      return new DcmOtherByteOtherWord(key);
+      // This solves issue 140 (Modifying private tags with REST API
+      // changes VR from LO to UN)
+      // https://bitbucket.org/sjodogne/orthanc/issues/140
+      LOG(WARNING) << "Private creator should not be empty while creating a private tag: " << tag.Format();
     }
-
-    switch (key.getEVR())
-    {
-      // http://support.dcmtk.org/docs/dcvr_8h-source.html
-
-      /**
-       * Binary types, handled above
-       **/
     
 #if DCMTK_VERSION_NUMBER >= 361
-      case EVR_OD:
-#endif            
-
-#if DCMTK_VERSION_NUMBER >= 362
-      case EVR_OL:
-#endif            
-
-      case EVR_OB:  // other byte
-      case EVR_OF:  // other float
-      case EVR_OW:  // other word
-      case EVR_UN:  // unknown value representation
-      case EVR_ox:  // OB or OW depending on context
-        throw OrthancException(ErrorCode_InternalError);
-
-
-      /**
-       * String types.
-       * http://support.dcmtk.org/docs/classDcmByteString.html
-       **/
-      
-      case EVR_AS:  // age string
-        return new DcmAgeString(key);
-
-      case EVR_AE:  // application entity title
-        return new DcmApplicationEntity(key);
-
-      case EVR_CS:  // code string
-        return new DcmCodeString(key);        
-
-      case EVR_DA:  // date string
-        return new DcmDate(key);
-        
-      case EVR_DT:  // date time string
-        return new DcmDateTime(key);
-
-      case EVR_DS:  // decimal string
-        return new DcmDecimalString(key);
-
-      case EVR_IS:  // integer string
-        return new DcmIntegerString(key);
-
-      case EVR_TM:  // time string
-        return new DcmTime(key);
-
-      case EVR_UI:  // unique identifier
-        return new DcmUniqueIdentifier(key);
-
-      case EVR_ST:  // short text
-        return new DcmShortText(key);
-
-      case EVR_LO:  // long string
-        return new DcmLongString(key);
-
-      case EVR_LT:  // long text
-        return new DcmLongText(key);
-
-      case EVR_UT:  // unlimited text
-        return new DcmUnlimitedText(key);
-
-      case EVR_SH:  // short string
-        return new DcmShortString(key);
-
-      case EVR_PN:  // person name
-        return new DcmPersonName(key);
-
-#if DCMTK_VERSION_NUMBER >= 361
-      case EVR_UC:  // unlimited characters
-        return new DcmUnlimitedCharacters(key);
-#endif
-
-#if DCMTK_VERSION_NUMBER >= 361
-      case EVR_UR:  // URI/URL
-        return new DcmUniversalResourceIdentifierOrLocator(key);
-#endif
-          
-        
-      /**
-       * Numerical types
-       **/ 
-      
-      case EVR_SL:  // signed long
-        return new DcmSignedLong(key);
-
-      case EVR_SS:  // signed short
-        return new DcmSignedShort(key);
-
-      case EVR_UL:  // unsigned long
-        return new DcmUnsignedLong(key);
-
-      case EVR_US:  // unsigned short
-        return new DcmUnsignedShort(key);
-
-      case EVR_FL:  // float single-precision
-        return new DcmFloatingPointSingle(key);
-
-      case EVR_FD:  // float double-precision
-        return new DcmFloatingPointDouble(key);
-
-
-      /**
-       * Sequence types, should never occur at this point.
-       **/
-
-      case EVR_SQ:  // sequence of items
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-
-
-      /**
-       * TODO
-       **/
-
-      case EVR_AT:  // attribute tag
-        throw OrthancException(ErrorCode_NotImplemented);
-
-
-      /**
-       * Internal to DCMTK.
-       **/ 
-
-      case EVR_xs:  // SS or US depending on context
-      case EVR_lt:  // US, SS or OW depending on context, used for LUT Data (thus the name)
-      case EVR_na:  // na="not applicable", for data which has no VR
-      case EVR_up:  // up="unsigned pointer", used internally for DICOMDIR suppor
-      case EVR_item:  // used internally for items
-      case EVR_metainfo:  // used internally for meta info datasets
-      case EVR_dataset:  // used internally for datasets
-      case EVR_fileFormat:  // used internally for DICOM files
-      case EVR_dicomDir:  // used internally for DICOMDIR objects
-      case EVR_dirRecord:  // used internally for DICOMDIR records
-      case EVR_pixelSQ:  // used internally for pixel sequences in a compressed image
-      case EVR_pixelItem:  // used internally for pixel items in a compressed image
-      case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR)
-      case EVR_PixelData:  // used internally for uncompressed pixeld data
-      case EVR_OverlayData:  // used internally for overlay data
-      case EVR_UNKNOWN2B:  // used internally for elements with unknown VR with 2-byte length field in explicit VR
-      default:
-        break;
+    DcmTag key(tag.GetGroup(), tag.GetElement());
+    if (tag.IsPrivate())
+    {
+      return DcmItem::newDicomElement(key, privateCreator.c_str());
+    }
+    else
+    {
+      return DcmItem::newDicomElement(key, NULL);
     }
-
-    throw OrthancException(ErrorCode_InternalError);          
+    
+#else
+    DcmTag key(tag.GetGroup(), tag.GetElement());
+    if (tag.IsPrivate())
+    {
+      // https://forum.dcmtk.org/viewtopic.php?t=4527
+      LOG(WARNING) << "You are using DCMTK <= 3.6.0: All the private tags "
+        "are considered as having a binary value representation";
+      key.setPrivateCreator(privateCreator.c_str());
+      return new DcmOtherByteOtherWord(key);
+    }
+    else
+    {
+      return newDicomElement(key);
+    }
+#endif      
   }
 
 
 
   void FromDcmtkBridge::FillElementWithString(DcmElement& element,
-                                              const DicomTag& tag,
                                               const std::string& utf8Value,
                                               bool decodeDataUriScheme,
                                               Encoding dicomEncoding)
@@ -1578,14 +1443,11 @@
       decoded = &binary;
     }
 
-    DcmTag key(tag.GetGroup(), tag.GetElement());
-
-    if (tag.IsPrivate() ||
-        IsBinaryTag(key))
+    if (IsBinaryTag(element.getTag()))
     {
       bool ok;
 
-      switch (key.getEVR())
+      switch (element.getTag().getEVR())
       {
         case EVR_OW:
           if (decoded->size() % sizeof(Uint16) != 0)
@@ -1619,7 +1481,7 @@
     
     try
     {
-      switch (key.getEVR())
+      switch (element.getTag().getEVR())
       {
         // http://support.dcmtk.org/docs/dcvr_8h-source.html
 
@@ -1628,7 +1490,6 @@
          **/
 
         case EVR_OB:  // other byte
-        case EVR_OF:  // other float
         case EVR_OW:  // other word
         case EVR_AT:  // attribute tag
           throw OrthancException(ErrorCode_NotImplemented);
@@ -1683,6 +1544,9 @@
         }
 
         case EVR_UL:  // unsigned long
+#if DCMTK_VERSION_NUMBER >= 361
+        case EVR_OL:  // other long (requires byte-swapping)
+#endif
         {
           ok = element.putUint32(boost::lexical_cast<Uint32>(*decoded)).good();
           break;
@@ -1695,12 +1559,16 @@
         }
 
         case EVR_FL:  // float single-precision
+        case EVR_OF:  // other float (requires byte swapping)
         {
           ok = element.putFloat32(boost::lexical_cast<float>(*decoded)).good();
           break;
         }
 
         case EVR_FD:  // float double-precision
+#if DCMTK_VERSION_NUMBER >= 361
+        case EVR_OD:  // other double (requires byte-swapping)
+#endif
         {
           ok = element.putFloat64(boost::lexical_cast<double>(*decoded)).good();
           break;
@@ -1750,6 +1618,7 @@
 
     if (!ok)
     {
+      DicomTag tag(element.getTag().getGroup(), element.getTag().getElement());
       throw OrthancException(ErrorCode_BadFileFormat,
                              "While creating a DICOM instance, tag (" + tag.Format() +
                              ") has out-of-range value: \"" + (*decoded) + "\"");
@@ -1760,20 +1629,21 @@
   DcmElement* FromDcmtkBridge::FromJson(const DicomTag& tag,
                                         const Json::Value& value,
                                         bool decodeDataUriScheme,
-                                        Encoding dicomEncoding)
+                                        Encoding dicomEncoding,
+                                        const std::string& privateCreator)
   {
     std::auto_ptr<DcmElement> element;
 
     switch (value.type())
     {
       case Json::stringValue:
-        element.reset(CreateElementForTag(tag));
-        FillElementWithString(*element, tag, value.asString(), decodeDataUriScheme, dicomEncoding);
+        element.reset(CreateElementForTag(tag, privateCreator));
+        FillElementWithString(*element, value.asString(), decodeDataUriScheme, dicomEncoding);
         break;
 
       case Json::nullValue:
-        element.reset(CreateElementForTag(tag));
-        FillElementWithString(*element, tag, "", decodeDataUriScheme, dicomEncoding);
+        element.reset(CreateElementForTag(tag, privateCreator));
+        FillElementWithString(*element, "", decodeDataUriScheme, dicomEncoding);
         break;
 
       case Json::arrayValue:
@@ -1798,7 +1668,7 @@
               Json::Value::Members members = value[i].getMemberNames();
               for (Json::Value::ArrayIndex j = 0; j < members.size(); j++)
               {
-                item->insert(FromJson(ParseTag(members[j]), value[i][members[j]], decodeDataUriScheme, dicomEncoding));
+                item->insert(FromJson(ParseTag(members[j]), value[i][members[j]], decodeDataUriScheme, dicomEncoding, privateCreator));
               }
               break;
             }
@@ -1907,7 +1777,8 @@
   DcmDataset* FromDcmtkBridge::FromJson(const Json::Value& json,  // Encoded using UTF-8
                                         bool generateIdentifiers,
                                         bool decodeDataUriScheme,
-                                        Encoding defaultEncoding)
+                                        Encoding defaultEncoding,
+                                        const std::string& privateCreator)
   {
     std::auto_ptr<DcmDataset> result(new DcmDataset);
     Encoding encoding = ExtractEncoding(json, defaultEncoding);
@@ -1945,7 +1816,7 @@
 
       if (tag != DICOM_TAG_SPECIFIC_CHARACTER_SET)
       {
-        std::auto_ptr<DcmElement> element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding));
+        std::auto_ptr<DcmElement> element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding, privateCreator));
         const DcmTagKey& tag = element->getTag();
 
         result->findAndDeleteElement(tag);
@@ -2268,13 +2139,6 @@
      **/
 
     if (evr == EVR_OB ||  // other byte
-        evr == EVR_OF ||  // other float
-#if DCMTK_VERSION_NUMBER >= 361
-        evr == EVR_OD ||  // other double
-#endif
-#if DCMTK_VERSION_NUMBER >= 362
-        evr == EVR_OL ||  // other long
-#endif
         evr == EVR_OW ||  // other word
         evr == EVR_UN)    // unknown value representation
     {
@@ -2464,6 +2328,9 @@
         }
 
         case EVR_UL:  // unsigned long
+#if DCMTK_VERSION_NUMBER >= 362
+        case EVR_OL:
+#endif
         {
           DcmUnsignedLong& content = dynamic_cast<DcmUnsignedLong&>(element);
 
@@ -2504,6 +2371,7 @@
         }
 
         case EVR_FL:  // float single-precision
+        case EVR_OF:
         {
           DcmFloatingPointSingle& content = dynamic_cast<DcmFloatingPointSingle&>(element);
 
@@ -2524,6 +2392,9 @@
         }
 
         case EVR_FD:  // float double-precision
+#if DCMTK_VERSION_NUMBER >= 361
+        case EVR_OD:
+#endif
         {
           DcmFloatingPointDouble& content = dynamic_cast<DcmFloatingPointDouble&>(element);
 
--- a/Core/DicomParsing/FromDcmtkBridge.h	Tue Feb 25 13:57:43 2020 +0100
+++ b/Core/DicomParsing/FromDcmtkBridge.h	Tue Feb 25 21:44:09 2020 +0100
@@ -209,10 +209,10 @@
 
     static ValueRepresentation LookupValueRepresentation(const DicomTag& tag);
 
-    static DcmElement* CreateElementForTag(const DicomTag& tag);
+    static DcmElement* CreateElementForTag(const DicomTag& tag,
+                                           const std::string& privateCreator);
     
     static void FillElementWithString(DcmElement& element,
-                                      const DicomTag& tag,
                                       const std::string& utf8alue,  // Encoded using UTF-8
                                       bool decodeDataUriScheme,
                                       Encoding dicomEncoding);
@@ -220,7 +220,8 @@
     static DcmElement* FromJson(const DicomTag& tag,
                                 const Json::Value& element,  // Encoded using UTF-8
                                 bool decodeDataUriScheme,
-                                Encoding dicomEncoding);
+                                Encoding dicomEncoding,
+                                const std::string& privateCreator);
 
     static DcmPixelSequence* GetPixelSequence(DcmDataset& dataset);
 
@@ -230,7 +231,8 @@
     static DcmDataset* FromJson(const Json::Value& json,  // Encoded using UTF-8
                                 bool generateIdentifiers,
                                 bool decodeDataUriScheme,
-                                Encoding defaultEncoding);
+                                Encoding defaultEncoding,
+                                const std::string& privateCreator);
 
     static DcmFileFormat* LoadFromMemoryBuffer(const void* buffer,
                                                size_t size);
--- a/Core/DicomParsing/ITagVisitor.h	Tue Feb 25 13:57:43 2020 +0100
+++ b/Core/DicomParsing/ITagVisitor.h	Tue Feb 25 21:44:09 2020 +0100
@@ -71,7 +71,7 @@
                                ValueRepresentation vr,
                                const std::vector<int64_t>& values) = 0;
 
-    // FL, FD
+    // FL, FD, OD, OF
     virtual void VisitDoubles(const std::vector<DicomTag>& parentTags,
                               const std::vector<size_t>& parentIndexes,
                               const DicomTag& tag,
@@ -84,7 +84,7 @@
                                  const DicomTag& tag,
                                  const std::vector<DicomTag>& values) = 0;
 
-    // OB, OD, OF, OL, OW, UN
+    // OB, OL, OW, UN
     virtual void VisitBinary(const std::vector<DicomTag>& parentTags,
                              const std::vector<size_t>& parentIndexes,
                              const DicomTag& tag,
--- a/Core/DicomParsing/ParsedDicomFile.cpp	Tue Feb 25 13:57:43 2020 +0100
+++ b/Core/DicomParsing/ParsedDicomFile.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -619,7 +619,8 @@
 
   void ParsedDicomFile::Insert(const DicomTag& tag,
                                const Json::Value& value,
-                               bool decodeDataUriScheme)
+                               bool decodeDataUriScheme,
+                               const std::string& privateCreator)
   {
     if (tag.GetElement() == 0x0000)
     {
@@ -648,11 +649,38 @@
 
     bool hasCodeExtensions;
     Encoding encoding = DetectEncoding(hasCodeExtensions);
-    std::auto_ptr<DcmElement> element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding));
+    std::auto_ptr<DcmElement> element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding, privateCreator));
     InsertInternal(*pimpl_->file_->getDataset(), element.release());
   }
 
 
+  void ParsedDicomFile::ReplacePlainString(const DicomTag& tag,
+                                           const std::string& utf8Value)
+  {
+    if (tag.IsPrivate())
+    {
+      throw OrthancException(ErrorCode_InternalError,
+                             "Cannot apply this function to private tags: " + tag.Format());
+    }
+    else
+    {
+      Replace(tag, utf8Value, false, DicomReplaceMode_InsertIfAbsent,
+              "" /* not a private tag, so no private creator */);
+    }
+  }
+
+
+  void ParsedDicomFile::SetIfAbsent(const DicomTag& tag,
+                                    const std::string& utf8Value)
+  {
+    std::string currentValue;
+    if (!GetTagValue(currentValue, tag))
+    {
+      ReplacePlainString(tag, utf8Value);
+    }
+  }
+
+
   static bool CanReplaceProceed(DcmDataset& dicom,
                                 const DcmTagKey& tag,
                                 DicomReplaceMode mode)
@@ -742,7 +770,8 @@
   void ParsedDicomFile::Replace(const DicomTag& tag,
                                 const std::string& utf8Value,
                                 bool decodeDataUriScheme,
-                                DicomReplaceMode mode)
+                                DicomReplaceMode mode,
+                                const std::string& privateCreator)
   {
     if (tag.GetElement() == 0x0000)
     {
@@ -769,13 +798,13 @@
         }
       }
 
-      std::auto_ptr<DcmElement> element(FromDcmtkBridge::CreateElementForTag(tag));
+      std::auto_ptr<DcmElement> element(FromDcmtkBridge::CreateElementForTag(tag, privateCreator));
 
       if (!utf8Value.empty())
       {
         bool hasCodeExtensions;
         Encoding encoding = DetectEncoding(hasCodeExtensions);
-        FromDcmtkBridge::FillElementWithString(*element, tag, utf8Value, decodeDataUriScheme, encoding);
+        FromDcmtkBridge::FillElementWithString(*element, utf8Value, decodeDataUriScheme, encoding);
       }
 
       InsertInternal(dicom, element.release());
@@ -787,7 +816,8 @@
   void ParsedDicomFile::Replace(const DicomTag& tag,
                                 const Json::Value& value,
                                 bool decodeDataUriScheme,
-                                DicomReplaceMode mode)
+                                DicomReplaceMode mode,
+                                const std::string& privateCreator)
   {
     if (tag.GetElement() == 0x0000)
     {
@@ -817,7 +847,7 @@
 
       bool hasCodeExtensions;
       Encoding encoding = DetectEncoding(hasCodeExtensions);
-      InsertInternal(dicom, FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding));
+      InsertInternal(dicom, FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding, privateCreator));
 
       if (tag == DICOM_TAG_SOP_CLASS_UID ||
           tag == DICOM_TAG_SOP_INSTANCE_UID)
@@ -1483,7 +1513,8 @@
 
 
   ParsedDicomFile* ParsedDicomFile::CreateFromJson(const Json::Value& json,
-                                                   DicomFromJsonFlags flags)
+                                                   DicomFromJsonFlags flags,
+                                                   const std::string& privateCreator)
   {
     const bool generateIdentifiers = (flags & DicomFromJsonFlags_GenerateIdentifiers) ? true : false;
     const bool decodeDataUriScheme = (flags & DicomFromJsonFlags_DecodeDataUriScheme) ? true : false;
@@ -1512,7 +1543,7 @@
       }
       else if (tag != DICOM_TAG_SPECIFIC_CHARACTER_SET)
       {
-        result->Replace(tag, value, decodeDataUriScheme, DicomReplaceMode_InsertIfAbsent);
+        result->Replace(tag, value, decodeDataUriScheme, DicomReplaceMode_InsertIfAbsent, privateCreator);
       }
     }
 
--- a/Core/DicomParsing/ParsedDicomFile.h	Tue Feb 25 13:57:43 2020 +0100
+++ b/Core/DicomParsing/ParsedDicomFile.h	Tue Feb 25 21:44:09 2020 +0100
@@ -138,32 +138,27 @@
     void Replace(const DicomTag& tag,
                  const std::string& utf8Value,
                  bool decodeDataUriScheme,
-                 DicomReplaceMode mode);
+                 DicomReplaceMode mode,
+                 const std::string& privateCreator /* used only for private tags */);
 
     void Replace(const DicomTag& tag,
                  const Json::Value& value,  // Assumed to be encoded with UTF-8
                  bool decodeDataUriScheme,
-                 DicomReplaceMode mode);
+                 DicomReplaceMode mode,
+                 const std::string& privateCreator /* used only for private tags */);
 
     void Insert(const DicomTag& tag,
                 const Json::Value& value,   // Assumed to be encoded with UTF-8
-                bool decodeDataUriScheme);
+                bool decodeDataUriScheme,
+                const std::string& privateCreator /* used only for private tags */);
 
+    // Cannot be applied to private tags
     void ReplacePlainString(const DicomTag& tag,
-                            const std::string& utf8Value)
-    {
-      Replace(tag, utf8Value, false, DicomReplaceMode_InsertIfAbsent);
-    }
+                            const std::string& utf8Value);
 
+    // Cannot be applied to private tags
     void SetIfAbsent(const DicomTag& tag,
-                     const std::string& utf8Value)
-    {
-      std::string currentValue;
-      if (!GetTagValue(currentValue, tag))
-      {
-        ReplacePlainString(tag, utf8Value);
-      }
-    }
+                     const std::string& utf8Value);
 
     void RemovePrivateTags()
     {
@@ -234,7 +229,8 @@
     unsigned int GetFramesCount() const;
 
     static ParsedDicomFile* CreateFromJson(const Json::Value& value,
-                                           DicomFromJsonFlags flags);
+                                           DicomFromJsonFlags flags,
+                                           const std::string& privateCreator);
 
     void ChangeEncoding(Encoding target);
 
--- a/NEWS	Tue Feb 25 13:57:43 2020 +0100
+++ b/NEWS	Tue Feb 25 21:44:09 2020 +0100
@@ -13,6 +13,7 @@
 * added "/instances/{id}/frames/{frame}/rendered" and "/instances/{id}/rendered" routes
   to render frames, taking windowing and resizing into account
 * "/instances": Support "Content-Encoding: gzip" to upload gzip-compressed DICOM files
+* ".../modify" and "/tools/create-dicom": New option "PrivateCreator" for private tags
 
 Plugins
 -------
@@ -37,6 +38,7 @@
 * More strict C-FIND SCP wrt. the DICOM standard: Forbid wildcard
   matching on some VRs, ignore main tags below the queried level
 * Fix issue #65 (Logging improvements)
+* Fix issue #140 (Modifying private tags with REST API changes VR from LO to UN)
 * Fix issue #156 (Chunked Dicom-web transfer uses 100% CPU)
 * Fix issue #165 (Boundary parameter in multipart Content-Type is too long)
 * Fix issue #166 (CMake find_boost version is now broken with newer boost/cmake)
--- a/OrthancServer/OrthancFindRequestHandler.cpp	Tue Feb 25 13:57:43 2020 +0100
+++ b/OrthancServer/OrthancFindRequestHandler.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -394,7 +394,8 @@
             content.append(item);
           }
 
-          dicom.Replace(*tag, content, false, DicomReplaceMode_InsertIfAbsent);
+          dicom.Replace(*tag, content, false, DicomReplaceMode_InsertIfAbsent,
+                        "" /* no private creator */);
         }
       }
 
--- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Tue Feb 25 13:57:43 2020 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -267,7 +267,8 @@
 
   static void InjectTags(ParsedDicomFile& dicom,
                          const Json::Value& tags,
-                         bool decodeBinaryTags)
+                         bool decodeBinaryTags,
+                         const std::string& privateCreator)
   {
     if (tags.type() != Json::objectValue)
     {
@@ -305,7 +306,7 @@
         }
         else
         {
-          dicom.Replace(tag, tags[name], decodeBinaryTags, DicomReplaceMode_InsertIfAbsent);
+          dicom.Replace(tag, tags[name], decodeBinaryTags, DicomReplaceMode_InsertIfAbsent, privateCreator);
         }
       }
     }
@@ -315,7 +316,8 @@
   static void CreateSeries(RestApiPostCall& call,
                            ParsedDicomFile& base /* in */,
                            const Json::Value& content,
-                           bool decodeBinaryTags)
+                           bool decodeBinaryTags,
+                           const std::string& privateCreator)
   {
     assert(content.isArray());
     assert(content.size() > 0);
@@ -348,7 +350,7 @@
 
           if (content[i].isMember("Tags"))
           {
-            InjectTags(*dicom, content[i]["Tags"], decodeBinaryTags);
+            InjectTags(*dicom, content[i]["Tags"], decodeBinaryTags, privateCreator);
           }
         }
 
@@ -538,6 +540,20 @@
       decodeBinaryTags = v.asBool();
     }
 
+
+    // New argument in Orthanc 1.6.0
+    std::string privateCreator;
+    if (request.isMember("PrivateCreator"))
+    {
+      const Json::Value& v = request["PrivateCreator"];
+      if (v.type() != Json::stringValue)
+      {
+        throw OrthancException(ErrorCode_BadRequest);
+      }
+
+      privateCreator = v.asString();
+    }
+
     
     // Inject time-related information
     std::string date, time;
@@ -565,7 +581,7 @@
     }
 
 
-    InjectTags(dicom, request["Tags"], decodeBinaryTags);
+    InjectTags(dicom, request["Tags"], decodeBinaryTags, privateCreator);
 
 
     // Inject the content (either an image, or a PDF file)
@@ -583,7 +599,7 @@
         if (content.size() > 0)
         {
           // Let's create a series instead of a single instance
-          CreateSeries(call, dicom, content, decodeBinaryTags);
+          CreateSeries(call, dicom, content, decodeBinaryTags, privateCreator);
           return;
         }
       }
--- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp	Tue Feb 25 13:57:43 2020 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -1277,7 +1277,8 @@
         MyGetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
 
       std::auto_ptr<ParsedDicomFile> query
-        (ParsedDicomFile::CreateFromJson(json, static_cast<DicomFromJsonFlags>(0)));
+        (ParsedDicomFile::CreateFromJson(json, static_cast<DicomFromJsonFlags>(0),
+                                         "" /* no private creator */));
 
       DicomFindAnswers answers(true);
 
--- a/OrthancServer/Search/HierarchicalMatcher.cpp	Tue Feb 25 13:57:43 2020 +0100
+++ b/OrthancServer/Search/HierarchicalMatcher.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -268,7 +268,13 @@
       if (source.findAndGetElement(tag, element).good() &&
           element != NULL)
       {
-        std::auto_ptr<DcmElement> cloned(FromDcmtkBridge::CreateElementForTag(*it));
+        if (it->IsPrivate())
+        {
+          throw OrthancException(ErrorCode_NotImplemented,
+                                 "Not applicable to private tags: " + it->Format());
+        }
+        
+        std::auto_ptr<DcmElement> cloned(FromDcmtkBridge::CreateElementForTag(*it, "" /* no private creator */));
         cloned->copyFrom(*element);
         target->insert(cloned.release());
       }
--- a/Plugins/Engine/OrthancPlugins.cpp	Tue Feb 25 13:57:43 2020 +0100
+++ b/Plugins/Engine/OrthancPlugins.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -824,7 +824,8 @@
           Json::Value target;
           call.ExecuteToJson(target, true);
           
-          filtered_.reset(ParsedDicomFile::CreateFromJson(target, DicomFromJsonFlags_None));
+          filtered_.reset(ParsedDicomFile::CreateFromJson(target, DicomFromJsonFlags_None,
+                                                          "" /* no private creator */));
           currentQuery_ = filtered_.get();
         }
       }
@@ -2922,7 +2923,8 @@
 
     {
       std::auto_ptr<ParsedDicomFile> file
-        (ParsedDicomFile::CreateFromJson(json, static_cast<DicomFromJsonFlags>(p.flags)));
+        (ParsedDicomFile::CreateFromJson(json, static_cast<DicomFromJsonFlags>(p.flags),
+                                         "" /* TODO - private creator */));
 
       if (p.pixelData)
       {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Graveyard/FromDcmtkBridge.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -0,0 +1,168 @@
+  DcmElement* FromDcmtkBridge::CreateElementForTag(const DicomTag& tag)
+  {
+    DcmTag key(tag.GetGroup(), tag.GetElement());
+
+    if (tag.IsPrivate())
+    {
+      // This raises BitBucket issue 140 (Modifying private tags with
+      // REST API changes VR from LO to UN)
+      // https://bitbucket.org/sjodogne/orthanc/issues/140
+      LOG(WARNING) << "You are using DCMTK < 3.6.1: All the private tags "
+        "are considered as having a binary value representation";
+      return new DcmOtherByteOtherWord(key);
+    }
+    else if (IsBinaryTag(key))
+    {
+      return new DcmOtherByteOtherWord(key);
+    }
+
+    switch (key.getEVR())
+    {
+      // http://support.dcmtk.org/docs/dcvr_8h-source.html
+
+      /**
+       * Binary types, handled above
+       **/
+    
+#if DCMTK_VERSION_NUMBER >= 361
+      case EVR_OD:
+#endif            
+
+#if DCMTK_VERSION_NUMBER >= 362
+      case EVR_OL:
+#endif            
+
+      case EVR_OB:  // other byte
+      case EVR_OF:  // other float
+      case EVR_OW:  // other word
+      case EVR_UN:  // unknown value representation
+      case EVR_ox:  // OB or OW depending on context
+        throw OrthancException(ErrorCode_InternalError);
+
+
+      /**
+       * String types.
+       * http://support.dcmtk.org/docs/classDcmByteString.html
+       **/
+      
+      case EVR_AS:  // age string
+        return new DcmAgeString(key);
+
+      case EVR_AE:  // application entity title
+        return new DcmApplicationEntity(key);
+
+      case EVR_CS:  // code string
+        return new DcmCodeString(key);        
+
+      case EVR_DA:  // date string
+        return new DcmDate(key);
+        
+      case EVR_DT:  // date time string
+        return new DcmDateTime(key);
+
+      case EVR_DS:  // decimal string
+        return new DcmDecimalString(key);
+
+      case EVR_IS:  // integer string
+        return new DcmIntegerString(key);
+
+      case EVR_TM:  // time string
+        return new DcmTime(key);
+
+      case EVR_UI:  // unique identifier
+        return new DcmUniqueIdentifier(key);
+
+      case EVR_ST:  // short text
+        return new DcmShortText(key);
+
+      case EVR_LO:  // long string
+        return new DcmLongString(key);
+
+      case EVR_LT:  // long text
+        return new DcmLongText(key);
+
+      case EVR_UT:  // unlimited text
+        return new DcmUnlimitedText(key);
+
+      case EVR_SH:  // short string
+        return new DcmShortString(key);
+
+      case EVR_PN:  // person name
+        return new DcmPersonName(key);
+
+#if DCMTK_VERSION_NUMBER >= 361
+      case EVR_UC:  // unlimited characters
+        return new DcmUnlimitedCharacters(key);
+#endif
+
+#if DCMTK_VERSION_NUMBER >= 361
+      case EVR_UR:  // URI/URL
+        return new DcmUniversalResourceIdentifierOrLocator(key);
+#endif
+          
+        
+      /**
+       * Numerical types
+       **/ 
+      
+      case EVR_SL:  // signed long
+        return new DcmSignedLong(key);
+
+      case EVR_SS:  // signed short
+        return new DcmSignedShort(key);
+
+      case EVR_UL:  // unsigned long
+        return new DcmUnsignedLong(key);
+
+      case EVR_US:  // unsigned short
+        return new DcmUnsignedShort(key);
+
+      case EVR_FL:  // float single-precision
+        return new DcmFloatingPointSingle(key);
+
+      case EVR_FD:  // float double-precision
+        return new DcmFloatingPointDouble(key);
+
+
+      /**
+       * Sequence types, should never occur at this point.
+       **/
+
+      case EVR_SQ:  // sequence of items
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+
+
+      /**
+       * TODO
+       **/
+
+      case EVR_AT:  // attribute tag
+        throw OrthancException(ErrorCode_NotImplemented);
+
+
+      /**
+       * Internal to DCMTK.
+       **/ 
+
+      case EVR_xs:  // SS or US depending on context
+      case EVR_lt:  // US, SS or OW depending on context, used for LUT Data (thus the name)
+      case EVR_na:  // na="not applicable", for data which has no VR
+      case EVR_up:  // up="unsigned pointer", used internally for DICOMDIR suppor
+      case EVR_item:  // used internally for items
+      case EVR_metainfo:  // used internally for meta info datasets
+      case EVR_dataset:  // used internally for datasets
+      case EVR_fileFormat:  // used internally for DICOM files
+      case EVR_dicomDir:  // used internally for DICOMDIR objects
+      case EVR_dirRecord:  // used internally for DICOMDIR records
+      case EVR_pixelSQ:  // used internally for pixel sequences in a compressed image
+      case EVR_pixelItem:  // used internally for pixel items in a compressed image
+      case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR)
+      case EVR_PixelData:  // used internally for uncompressed pixeld data
+      case EVR_OverlayData:  // used internally for overlay data
+      case EVR_UNKNOWN2B:  // used internally for elements with unknown VR with 2-byte length field in explicit VR
+      default:
+        break;
+    }
+
+    throw OrthancException(ErrorCode_InternalError);
+  }
--- a/UnitTestsSources/DicomMapTests.cpp	Tue Feb 25 13:57:43 2020 +0100
+++ b/UnitTestsSources/DicomMapTests.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -725,9 +725,9 @@
   dicom.ReplacePlainString(DicomTag(0x0008, 0x0070), "LO");
   dicom.ReplacePlainString(DicomTag(0x0010, 0x4000), "LT");
   dicom.ReplacePlainString(DicomTag(0x0028, 0x2000), "OB");
-  dicom.ReplacePlainString(DicomTag(0x7fe0, 0x0009), "OD");
-  dicom.ReplacePlainString(DicomTag(0x0064, 0x0009), "OF");
-  dicom.ReplacePlainString(DicomTag(0x0066, 0x0040), "46");
+  dicom.ReplacePlainString(DicomTag(0x7fe0, 0x0009), "3.14159");  // OD (other double)
+  dicom.ReplacePlainString(DicomTag(0x0064, 0x0009), "2.71828");  // OF (other float)
+  dicom.ReplacePlainString(DicomTag(0x0066, 0x0040), "46");  // OL (other long)
   ASSERT_THROW(dicom.ReplacePlainString(DicomTag(0x0028, 0x1201), "O"), OrthancException);
   dicom.ReplacePlainString(DicomTag(0x0028, 0x1201), "OWOW");
   dicom.ReplacePlainString(DicomTag(0x0010, 0x0010), "PN");
@@ -784,28 +784,25 @@
 
 #if DCMTK_VERSION_NUMBER >= 361
   ASSERT_EQ("OD", visitor.GetResult() ["7FE00009"]["vr"].asString());
+  ASSERT_FLOAT_EQ(3.14159f, boost::lexical_cast<float>(visitor.GetResult() ["7FE00009"]["Value"][0].asString()));
 #else
   ASSERT_EQ("UN", visitor.GetResult() ["7FE00009"]["vr"].asString());
+  Toolbox::DecodeBase64(s, visitor.GetResult() ["7FE00009"]["InlineBinary"].asString());
+  ASSERT_EQ(8u, s.size()); // Because of padding
+  ASSERT_EQ(0, s[7]);
+  ASSERT_EQ("3.14159", s.substr(0, 7));
 #endif
 
-  Toolbox::DecodeBase64(s, visitor.GetResult() ["7FE00009"]["InlineBinary"].asString());
-  ASSERT_EQ("OD", s);
-
   ASSERT_EQ("OF", visitor.GetResult() ["00640009"]["vr"].asString());
-  Toolbox::DecodeBase64(s, visitor.GetResult() ["00640009"]["InlineBinary"].asString());
-  ASSERT_EQ("OF", s);
+  ASSERT_FLOAT_EQ(2.71828f, boost::lexical_cast<float>(visitor.GetResult() ["00640009"]["Value"][0].asString()));
 
 #if DCMTK_VERSION_NUMBER < 361
   ASSERT_EQ("UN", visitor.GetResult() ["00660040"]["vr"].asString());
   Toolbox::DecodeBase64(s, visitor.GetResult() ["00660040"]["InlineBinary"].asString());
   ASSERT_EQ("46", s);
-#elif DCMTK_VERSION_NUMBER == 361
-  ASSERT_EQ("UL", visitor.GetResult() ["00660040"]["vr"].asString());
+#else
+  ASSERT_EQ("OL", visitor.GetResult() ["00660040"]["vr"].asString());
   ASSERT_EQ(46, visitor.GetResult() ["00660040"]["Value"][0].asInt());
-#elif DCMTK_VERSION_NUMBER > 361
-  ASSERT_EQ("OL", visitor.GetResult() ["00660040"]["vr"].asString());
-  Toolbox::DecodeBase64(s, visitor.GetResult() ["00660040"]["InlineBinary"].asString());
-  ASSERT_EQ("46", s);
 #endif
 
   ASSERT_EQ("OW", visitor.GetResult() ["00281201"]["vr"].asString());
@@ -893,8 +890,18 @@
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0070), false));  ASSERT_EQ("LO", s);
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x4000), false));  ASSERT_EQ("LT", s);
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0028, 0x2000), true));   ASSERT_EQ("OB", s);
-    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x7fe0, 0x0009), true));   ASSERT_EQ("OD", s);
-    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0064, 0x0009), true));   ASSERT_EQ("OF", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x7fe0, 0x0009), true));
+
+#if DCMTK_VERSION_NUMBER >= 361
+    ASSERT_FLOAT_EQ(3.14159f, boost::lexical_cast<float>(s));
+#else
+    ASSERT_EQ(8u, s.size()); // Because of padding
+    ASSERT_EQ(0, s[7]);
+    ASSERT_EQ("3.14159", s.substr(0, 7));
+#endif
+
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0064, 0x0009), true));
+    ASSERT_FLOAT_EQ(2.71828f, boost::lexical_cast<float>(s));
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0028, 0x1201), true));   ASSERT_EQ("OWOW", s);
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x0010), false));  ASSERT_EQ("PN", s);
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0050), false));  ASSERT_EQ("SH", s);
@@ -902,20 +909,23 @@
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0018, 0x9219), false));  ASSERT_EQ("-16", s);
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0081), false));  ASSERT_EQ("ST", s);
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0013), false));  ASSERT_EQ("TM", s);
-    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0119), false));  ASSERT_EQ("UC", s);
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0016), false));  ASSERT_EQ("UI", s);
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1161), false));  ASSERT_EQ("128", s);
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x4342, 0x1234), true));   ASSERT_EQ("UN", s);
-    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0120), false));  ASSERT_EQ("UR", s);
-    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0301), false));  ASSERT_EQ("17", s);
     ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0040, 0x0031), false));  ASSERT_EQ("UT", s);
 
-#if DCMTK_VERSION_NUMBER == 361
-    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), false));
+#if DCMTK_VERSION_NUMBER >= 361
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), false));  ASSERT_EQ("46", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0119), false));  ASSERT_EQ("UC", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0120), false));  ASSERT_EQ("UR", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0301), false));  ASSERT_EQ("17", s);
 #else
-    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), true));
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), true));  ASSERT_EQ("46", s);  // OL
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0119), true));  ASSERT_EQ("UC", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0120), true));  ASSERT_EQ("UR", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0301), true));  ASSERT_EQ("17", s);  // US (but tag unknown to DCMTK 3.6.0)
 #endif
-    ASSERT_EQ("46", s);
+    
   }
 }
 
--- a/UnitTestsSources/FromDcmtkTests.cpp	Tue Feb 25 13:57:43 2020 +0100
+++ b/UnitTestsSources/FromDcmtkTests.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -108,7 +108,7 @@
 {
   ASSERT_EQ(DICOM_TAG_PATIENT_NAME, FromDcmtkBridge::ParseTag("PatientName"));
 
-  const DicomTag privateTag(0x0045, 0x0010);
+  const DicomTag privateTag(0x0045, 0x1010);
   const DicomTag privateTag2(FromDcmtkBridge::ParseTag("0031-1020"));
   ASSERT_TRUE(privateTag.IsPrivate());
   ASSERT_TRUE(privateTag2.IsPrivate());
@@ -119,19 +119,19 @@
   ParsedDicomFile o(true);
   o.ReplacePlainString(DICOM_TAG_PATIENT_NAME, "coucou");
   ASSERT_FALSE(o.GetTagValue(s, privateTag));
-  o.Insert(privateTag, "private tag", false);
+  o.Insert(privateTag, "private tag", false, "OrthancCreator");
   ASSERT_TRUE(o.GetTagValue(s, privateTag));
   ASSERT_STREQ("private tag", s.c_str());
 
   ASSERT_FALSE(o.GetTagValue(s, privateTag2));
-  ASSERT_THROW(o.Replace(privateTag2, std::string("hello"), false, DicomReplaceMode_ThrowIfAbsent), OrthancException);
+  ASSERT_THROW(o.Replace(privateTag2, std::string("hello"), false, DicomReplaceMode_ThrowIfAbsent, "OrthancCreator"), OrthancException);
   ASSERT_FALSE(o.GetTagValue(s, privateTag2));
-  o.Replace(privateTag2, std::string("hello"), false, DicomReplaceMode_IgnoreIfAbsent);
+  o.Replace(privateTag2, std::string("hello"), false, DicomReplaceMode_IgnoreIfAbsent, "OrthancCreator");
   ASSERT_FALSE(o.GetTagValue(s, privateTag2));
-  o.Replace(privateTag2, std::string("hello"), false, DicomReplaceMode_InsertIfAbsent);
+  o.Replace(privateTag2, std::string("hello"), false, DicomReplaceMode_InsertIfAbsent, "OrthancCreator");
   ASSERT_TRUE(o.GetTagValue(s, privateTag2));
   ASSERT_STREQ("hello", s.c_str());
-  o.ReplacePlainString(privateTag2, "hello world");
+  o.Replace(privateTag2, std::string("hello world"), false, DicomReplaceMode_InsertIfAbsent, "OrthancCreator");
   ASSERT_TRUE(o.GetTagValue(s, privateTag2));
   ASSERT_STREQ("hello world", s.c_str());
 
@@ -290,7 +290,7 @@
       f.SetEncoding(testEncodings[i]);
 
       std::string s = Toolbox::ConvertToUtf8(testEncodingsEncoded[i], testEncodings[i], false);
-      f.Insert(DICOM_TAG_PATIENT_NAME, s, false);
+      f.Insert(DICOM_TAG_PATIENT_NAME, s, false, "");
       f.SaveToMemoryBuffer(dicom);
     }
 
@@ -407,7 +407,7 @@
     {
       Json::Value a;
       a = "Hello";
-      element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8));
+      element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8, ""));
 
       Json::Value b;
       std::set<DicomTag> ignoreTagLength;
@@ -439,20 +439,20 @@
       Json::Value a;
       a = "Hello";
       // Cannot assign a string to a sequence
-      ASSERT_THROW(element.reset(FromDcmtkBridge::FromJson(REFERENCED_STUDY_SEQUENCE, a, false, Encoding_Utf8)), OrthancException);
+      ASSERT_THROW(element.reset(FromDcmtkBridge::FromJson(REFERENCED_STUDY_SEQUENCE, a, false, Encoding_Utf8, "")), OrthancException);
     }
 
     {
       Json::Value a = Json::arrayValue;
       a.append("Hello");
       // Cannot assign an array to a string
-      ASSERT_THROW(element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8)), OrthancException);
+      ASSERT_THROW(element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8, "")), OrthancException);
     }
 
     {
       Json::Value a;
       a = "data:application/octet-stream;base64,SGVsbG8=";  // echo -n "Hello" | base64
-      element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, true, Encoding_Utf8));
+      element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, true, Encoding_Utf8, ""));
 
       Json::Value b;
       std::set<DicomTag> ignoreTagLength;
@@ -464,7 +464,7 @@
     {
       Json::Value a = Json::arrayValue;
       CreateSampleJson(a);
-      element.reset(FromDcmtkBridge::FromJson(REFERENCED_STUDY_SEQUENCE, a, true, Encoding_Utf8));
+      element.reset(FromDcmtkBridge::FromJson(REFERENCED_STUDY_SEQUENCE, a, true, Encoding_Utf8, ""));
 
       {
         Json::Value b;
@@ -506,8 +506,8 @@
 {
   ParsedDicomFile f(true);
 
-  f.Insert(DICOM_TAG_PATIENT_NAME, "World", false);
-  ASSERT_THROW(f.Insert(DICOM_TAG_PATIENT_ID, "Hello", false), OrthancException);  // Already existing tag
+  f.Insert(DICOM_TAG_PATIENT_NAME, "World", false, "");
+  ASSERT_THROW(f.Insert(DICOM_TAG_PATIENT_ID, "Hello", false, ""), OrthancException);  // Already existing tag
   f.ReplacePlainString(DICOM_TAG_SOP_INSTANCE_UID, "Toto");  // (*)
   f.ReplacePlainString(DICOM_TAG_SOP_CLASS_UID, "Tata");  // (**)
 
@@ -515,16 +515,16 @@
   ASSERT_FALSE(f.LookupTransferSyntax(s));
 
   ASSERT_THROW(f.Replace(DICOM_TAG_ACCESSION_NUMBER, std::string("Accession"),
-                         false, DicomReplaceMode_ThrowIfAbsent), OrthancException);
-  f.Replace(DICOM_TAG_ACCESSION_NUMBER, std::string("Accession"), false, DicomReplaceMode_IgnoreIfAbsent);
+                         false, DicomReplaceMode_ThrowIfAbsent, ""), OrthancException);
+  f.Replace(DICOM_TAG_ACCESSION_NUMBER, std::string("Accession"), false, DicomReplaceMode_IgnoreIfAbsent, "");
   ASSERT_FALSE(f.GetTagValue(s, DICOM_TAG_ACCESSION_NUMBER));
-  f.Replace(DICOM_TAG_ACCESSION_NUMBER, std::string("Accession"), false, DicomReplaceMode_InsertIfAbsent);
+  f.Replace(DICOM_TAG_ACCESSION_NUMBER, std::string("Accession"), false, DicomReplaceMode_InsertIfAbsent, "");
   ASSERT_TRUE(f.GetTagValue(s, DICOM_TAG_ACCESSION_NUMBER));
   ASSERT_EQ(s, "Accession");
-  f.Replace(DICOM_TAG_ACCESSION_NUMBER, std::string("Accession2"), false, DicomReplaceMode_IgnoreIfAbsent);
+  f.Replace(DICOM_TAG_ACCESSION_NUMBER, std::string("Accession2"), false, DicomReplaceMode_IgnoreIfAbsent, "");
   ASSERT_TRUE(f.GetTagValue(s, DICOM_TAG_ACCESSION_NUMBER));
   ASSERT_EQ(s, "Accession2");
-  f.Replace(DICOM_TAG_ACCESSION_NUMBER, std::string("Accession3"), false, DicomReplaceMode_ThrowIfAbsent);
+  f.Replace(DICOM_TAG_ACCESSION_NUMBER, std::string("Accession3"), false, DicomReplaceMode_ThrowIfAbsent, "");
   ASSERT_TRUE(f.GetTagValue(s, DICOM_TAG_ACCESSION_NUMBER));
   ASSERT_EQ(s, "Accession3");
 
@@ -552,20 +552,20 @@
 
   ASSERT_FALSE(f.HasTag(REFERENCED_STUDY_SEQUENCE));
   f.Remove(REFERENCED_STUDY_SEQUENCE);  // No effect
-  f.Insert(REFERENCED_STUDY_SEQUENCE, a, true);
+  f.Insert(REFERENCED_STUDY_SEQUENCE, a, true, "");
   ASSERT_TRUE(f.HasTag(REFERENCED_STUDY_SEQUENCE));
-  ASSERT_THROW(f.Insert(REFERENCED_STUDY_SEQUENCE, a, true), OrthancException);
+  ASSERT_THROW(f.Insert(REFERENCED_STUDY_SEQUENCE, a, true, ""), OrthancException);
   f.Remove(REFERENCED_STUDY_SEQUENCE);
   ASSERT_FALSE(f.HasTag(REFERENCED_STUDY_SEQUENCE));
-  f.Insert(REFERENCED_STUDY_SEQUENCE, a, true);
+  f.Insert(REFERENCED_STUDY_SEQUENCE, a, true, "");
   ASSERT_TRUE(f.HasTag(REFERENCED_STUDY_SEQUENCE));
 
   ASSERT_FALSE(f.HasTag(REFERENCED_PATIENT_SEQUENCE));
-  ASSERT_THROW(f.Replace(REFERENCED_PATIENT_SEQUENCE, a, false, DicomReplaceMode_ThrowIfAbsent), OrthancException);
+  ASSERT_THROW(f.Replace(REFERENCED_PATIENT_SEQUENCE, a, false, DicomReplaceMode_ThrowIfAbsent, ""), OrthancException);
   ASSERT_FALSE(f.HasTag(REFERENCED_PATIENT_SEQUENCE));
-  f.Replace(REFERENCED_PATIENT_SEQUENCE, a, false, DicomReplaceMode_IgnoreIfAbsent);
+  f.Replace(REFERENCED_PATIENT_SEQUENCE, a, false, DicomReplaceMode_IgnoreIfAbsent, "");
   ASSERT_FALSE(f.HasTag(REFERENCED_PATIENT_SEQUENCE));
-  f.Replace(REFERENCED_PATIENT_SEQUENCE, a, false, DicomReplaceMode_InsertIfAbsent);
+  f.Replace(REFERENCED_PATIENT_SEQUENCE, a, false, DicomReplaceMode_InsertIfAbsent, "");
   ASSERT_TRUE(f.HasTag(REFERENCED_PATIENT_SEQUENCE));
 
   {
@@ -580,8 +580,8 @@
   }
 
   a = "data:application/octet-stream;base64,VGF0YQ==";   // echo -n "Tata" | base64 
-  f.Replace(DICOM_TAG_SOP_INSTANCE_UID, a, false, DicomReplaceMode_InsertIfAbsent);  // (*)
-  f.Replace(DICOM_TAG_SOP_CLASS_UID, a, true, DicomReplaceMode_InsertIfAbsent);  // (**)
+  f.Replace(DICOM_TAG_SOP_INSTANCE_UID, a, false, DicomReplaceMode_InsertIfAbsent, "");  // (*)
+  f.Replace(DICOM_TAG_SOP_CLASS_UID, a, true, DicomReplaceMode_InsertIfAbsent, "");  // (**)
 
   std::string s;
   ASSERT_TRUE(f.GetTagValue(s, DICOM_TAG_SOP_INSTANCE_UID));
@@ -614,7 +614,7 @@
       }
 
       Json::Value s = Toolbox::ConvertToUtf8(testEncodingsEncoded[i], testEncodings[i], false);
-      f.Replace(DICOM_TAG_PATIENT_NAME, s, false, DicomReplaceMode_InsertIfAbsent);
+      f.Replace(DICOM_TAG_PATIENT_NAME, s, false, DicomReplaceMode_InsertIfAbsent, "");
 
       Json::Value v;
       f.DatasetToJson(v, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
@@ -626,13 +626,13 @@
 
 TEST(ParsedDicomFile, ToJsonFlags1)
 {
-  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7053, 0x1000), ValueRepresentation_PersonName, "MyPrivateTag", 1, 1, "");
+  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7053, 0x1000), ValueRepresentation_OtherByte, "MyPrivateTag", 1, 1, "OrthancCreator");
   FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PersonName, "Declared public tag", 1, 1, "");
 
   ParsedDicomFile f(true);
-  f.Insert(DicomTag(0x7050, 0x1000), "Some public tag", false);  // Even group => public tag
-  f.Insert(DicomTag(0x7052, 0x1000), "Some unknown tag", false);  // Even group => public, unknown tag
-  f.Insert(DicomTag(0x7053, 0x1000), "Some private tag", false);  // Odd group => private tag
+  f.Insert(DicomTag(0x7050, 0x1000), "Some public tag", false, "");  // Even group => public tag
+  f.Insert(DicomTag(0x7052, 0x1000), "Some unknown tag", false, "");  // Even group => public, unknown tag
+  f.Insert(DicomTag(0x7053, 0x1000), "Some private tag", false, "OrthancCreator");  // Odd group => private tag
 
   Json::Value v;
   f.DatasetToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_None, 0);
@@ -644,7 +644,7 @@
   ASSERT_EQ(Json::stringValue, v["7050,1000"].type());
   ASSERT_EQ("Some public tag", v["7050,1000"].asString());
 
-  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_IncludeBinary | DicomToJsonFlags_ConvertBinaryToNull), 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(7u, v.getMemberNames().size());
   ASSERT_FALSE(v.isMember("7052,1000"));
@@ -653,7 +653,14 @@
   ASSERT_EQ("Some public tag", v["7050,1000"].asString());
   ASSERT_EQ(Json::nullValue, v["7053,1000"].type());
 
-  f.DatasetToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_IncludePrivateTags, 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePrivateTags), 0);
+  ASSERT_EQ(Json::objectValue, v.type());
+  ASSERT_EQ(6u, v.getMemberNames().size());
+  ASSERT_FALSE(v.isMember("7052,1000"));
+  ASSERT_TRUE(v.isMember("7050,1000"));
+  ASSERT_FALSE(v.isMember("7053,1000"));
+
+  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_IncludeBinary), 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(7u, v.getMemberNames().size());
   ASSERT_FALSE(v.isMember("7052,1000"));
@@ -666,7 +673,7 @@
   ASSERT_EQ("application/octet-stream", mime);
   ASSERT_EQ("Some private tag", content);
 
-  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_IncludeBinary | DicomToJsonFlags_ConvertBinaryToNull), 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(7u, v.getMemberNames().size());
   ASSERT_TRUE(v.isMember("7050,1000"));
@@ -675,7 +682,7 @@
   ASSERT_EQ("Some public tag", v["7050,1000"].asString());
   ASSERT_EQ(Json::nullValue, v["7052,1000"].type());
 
-  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags), 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_IncludeBinary), 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(7u, v.getMemberNames().size());
   ASSERT_TRUE(v.isMember("7050,1000"));
@@ -687,7 +694,7 @@
   ASSERT_EQ("application/octet-stream", mime);
   ASSERT_EQ("Some unknown tag", content);
 
-  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_IncludeBinary | DicomToJsonFlags_ConvertBinaryToNull), 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(8u, v.getMemberNames().size());
   ASSERT_TRUE(v.isMember("7050,1000"));
@@ -702,7 +709,7 @@
 TEST(ParsedDicomFile, ToJsonFlags2)
 {
   ParsedDicomFile f(true);
-  f.Insert(DICOM_TAG_PIXEL_DATA, "Pixels", false);
+  f.Insert(DICOM_TAG_PIXEL_DATA, "Pixels", false, "");
 
   Json::Value v;
   f.DatasetToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_None, 0);
@@ -811,7 +818,7 @@
 
   {
     std::auto_ptr<ParsedDicomFile> dicom
-      (ParsedDicomFile::CreateFromJson(v, static_cast<DicomFromJsonFlags>(DicomFromJsonFlags_GenerateIdentifiers)));
+      (ParsedDicomFile::CreateFromJson(v, static_cast<DicomFromJsonFlags>(DicomFromJsonFlags_GenerateIdentifiers), ""));
 
     Json::Value vv;
     dicom->DatasetToJson(vv, DicomToJsonFormat_Human, toJsonFlags, 0);
@@ -827,7 +834,7 @@
 
   {
     std::auto_ptr<ParsedDicomFile> dicom
-      (ParsedDicomFile::CreateFromJson(v, static_cast<DicomFromJsonFlags>(DicomFromJsonFlags_GenerateIdentifiers)));
+      (ParsedDicomFile::CreateFromJson(v, static_cast<DicomFromJsonFlags>(DicomFromJsonFlags_GenerateIdentifiers), ""));
 
     Json::Value vv;
     dicom->DatasetToJson(vv, DicomToJsonFormat_Human, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData), 0);
@@ -841,7 +848,7 @@
 
   {
     std::auto_ptr<ParsedDicomFile> dicom
-      (ParsedDicomFile::CreateFromJson(v, static_cast<DicomFromJsonFlags>(DicomFromJsonFlags_DecodeDataUriScheme)));
+      (ParsedDicomFile::CreateFromJson(v, static_cast<DicomFromJsonFlags>(DicomFromJsonFlags_DecodeDataUriScheme), ""));
 
     Json::Value vv;
     dicom->DatasetToJson(vv, DicomToJsonFormat_Short, toJsonFlags, 0);
--- a/UnitTestsSources/MultiThreadingTests.cpp	Tue Feb 25 13:57:43 2020 +0100
+++ b/UnitTestsSources/MultiThreadingTests.cpp	Tue Feb 25 21:44:09 2020 +0100
@@ -1143,9 +1143,9 @@
   Json::Value s;
 
   ParsedDicomFile source(true);
-  source.Insert(DICOM_TAG_STUDY_DESCRIPTION, "Test 1", false);
-  source.Insert(DICOM_TAG_SERIES_DESCRIPTION, "Test 2", false);
-  source.Insert(DICOM_TAG_PATIENT_NAME, "Test 3", false);
+  source.Insert(DICOM_TAG_STUDY_DESCRIPTION, "Test 1", false, "");
+  source.Insert(DICOM_TAG_SERIES_DESCRIPTION, "Test 2", false, "");
+  source.Insert(DICOM_TAG_PATIENT_NAME, "Test 3", false, "");
 
   std::auto_ptr<ParsedDicomFile> modified(source.Clone(true));
 
@@ -1310,7 +1310,7 @@
       // Create a sample DICOM file
       ParsedDicomFile dicom(true);
       dicom.Replace(DICOM_TAG_PATIENT_NAME, std::string("JODOGNE"),
-                    false, DicomReplaceMode_InsertIfAbsent);
+                    false, DicomReplaceMode_InsertIfAbsent, "");
 
       DicomInstanceToStore toStore;
       toStore.SetParsedDicomFile(dicom);