changeset 1737:ec66a16aa398

removal of DicomStringValue and DicomNullValue
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 22 Oct 2015 07:52:24 +0200
parents b953c6eef28d
children 15a788a63846
files Core/DicomFormat/DicomArray.cpp Core/DicomFormat/DicomImageInformation.cpp Core/DicomFormat/DicomInstanceHasher.cpp Core/DicomFormat/DicomMap.cpp Core/DicomFormat/DicomMap.h Core/DicomFormat/DicomNullValue.h Core/DicomFormat/DicomString.h Core/DicomFormat/DicomValue.h OrthancServer/DicomFindQuery.cpp OrthancServer/DicomProtocol/DicomUserConnection.cpp OrthancServer/FromDcmtkBridge.cpp OrthancServer/FromDcmtkBridge.h OrthancServer/OrthancFindRequestHandler.cpp OrthancServer/OrthancMoveRequestHandler.cpp OrthancServer/OrthancRestApi/OrthancRestModalities.cpp OrthancServer/ParsedDicomFile.cpp OrthancServer/ParsedDicomFile.h OrthancServer/ServerIndex.cpp OrthancServer/ServerIndexChange.h OrthancServer/ServerToolbox.cpp OrthancServer/SliceOrdering.cpp OrthancServer/ToDcmtkBridge.cpp UnitTestsSources/DicomMapTests.cpp UnitTestsSources/ServerIndexTests.cpp
diffstat 24 files changed, 227 insertions(+), 260 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomFormat/DicomArray.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/Core/DicomFormat/DicomArray.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -63,7 +63,8 @@
     for (size_t  i = 0; i < elements_.size(); i++)
     {
       DicomTag t = elements_[i]->GetTag();
-      std::string s = elements_[i]->GetValue().AsString();
+      const DicomValue& v = elements_[i]->GetValue();
+      std::string s = v.IsNull() ? "(null)" : v.GetContent();
       printf("0x%04x 0x%04x [%s]\n", t.GetGroup(), t.GetElement(), s.c_str());
     }
   }
--- a/Core/DicomFormat/DicomImageInformation.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/Core/DicomFormat/DicomImageInformation.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -54,7 +54,7 @@
 
     try
     {
-      std::string p = values.GetValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION).AsString();
+      std::string p = values.GetValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION).GetContent();
       Toolbox::ToUpperCase(p);
 
       if (p == "RGB")
@@ -114,13 +114,13 @@
         photometric_ = PhotometricInterpretation_Unknown;
       }
 
-      width_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_COLUMNS).AsString());
-      height_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_ROWS).AsString());
-      bitsAllocated_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_BITS_ALLOCATED).AsString());
+      width_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_COLUMNS).GetContent());
+      height_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_ROWS).GetContent());
+      bitsAllocated_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_BITS_ALLOCATED).GetContent());
 
       try
       {
-        samplesPerPixel_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_SAMPLES_PER_PIXEL).AsString());
+        samplesPerPixel_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_SAMPLES_PER_PIXEL).GetContent());
       }
       catch (OrthancException&)
       {
@@ -129,7 +129,7 @@
 
       try
       {
-        bitsStored_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_BITS_STORED).AsString());
+        bitsStored_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_BITS_STORED).GetContent());
       }
       catch (OrthancException&)
       {
@@ -138,7 +138,7 @@
 
       try
       {
-        highBit_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_HIGH_BIT).AsString());
+        highBit_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_HIGH_BIT).GetContent());
       }
       catch (OrthancException&)
       {
@@ -147,7 +147,7 @@
 
       try
       {
-        pixelRepresentation = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_PIXEL_REPRESENTATION).AsString());
+        pixelRepresentation = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_PIXEL_REPRESENTATION).GetContent());
       }
       catch (OrthancException&)
       {
@@ -160,7 +160,7 @@
         // https://www.dabsoft.ch/dicom/3/C.7.6.3.1.3/
         try
         {
-          planarConfiguration = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_PLANAR_CONFIGURATION).AsString());
+          planarConfiguration = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_PLANAR_CONFIGURATION).GetContent());
         }
         catch (OrthancException&)
         {
@@ -179,9 +179,9 @@
 
     try
     {
-      numberOfFrames_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_NUMBER_OF_FRAMES).AsString());
+      numberOfFrames_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_NUMBER_OF_FRAMES).GetContent());
     }
-    catch (OrthancException)
+    catch (OrthancException&)
     {
       // If the tag "NumberOfFrames" is absent, assume there is a single frame
       numberOfFrames_ = 1;
--- a/Core/DicomFormat/DicomInstanceHasher.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/Core/DicomFormat/DicomInstanceHasher.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -60,10 +60,10 @@
   {
     const DicomValue* patientId = instance.TestAndGetValue(DICOM_TAG_PATIENT_ID);
 
-    Setup(patientId == NULL ? "" : patientId->AsString(),
-          instance.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString(),
-          instance.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).AsString(),
-          instance.GetValue(DICOM_TAG_SOP_INSTANCE_UID).AsString());
+    Setup(patientId == NULL ? "" : patientId->GetContent(),
+          instance.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent(),
+          instance.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).GetContent(),
+          instance.GetValue(DICOM_TAG_SOP_INSTANCE_UID).GetContent());
   }
 
   const std::string& DicomInstanceHasher::HashPatient()
--- a/Core/DicomFormat/DicomMap.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/Core/DicomFormat/DicomMap.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -35,7 +35,6 @@
 
 #include <stdio.h>
 #include <memory>
-#include "DicomString.h"
 #include "DicomArray.h"
 #include "../OrthancException.h"
 
--- a/Core/DicomFormat/DicomMap.h	Wed Oct 21 16:52:23 2015 +0200
+++ b/Core/DicomFormat/DicomMap.h	Thu Oct 22 07:52:24 2015 +0200
@@ -34,7 +34,6 @@
 
 #include "DicomTag.h"
 #include "DicomValue.h"
-#include "DicomString.h"
 #include "../Enumerations.h"
 
 #include <set>
@@ -105,14 +104,14 @@
     void SetValue(const DicomTag& tag,
                   const std::string& str)
     {
-      SetValue(tag, new DicomString(str));
+      SetValue(tag, new DicomValue(str, false));
     }
 
     void SetValue(uint16_t group, 
                   uint16_t element, 
                   const std::string& str)
     {
-      SetValue(group, element, new DicomString(str));
+      SetValue(group, element, new DicomValue(str, false));
     }
 
     bool HasTag(uint16_t group, uint16_t element) const
--- a/Core/DicomFormat/DicomNullValue.h	Wed Oct 21 16:52:23 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * In addition, as a special exception, the copyright holders of this
- * program give permission to link the code of its release with the
- * OpenSSL project's "OpenSSL" library (or with modified versions of it
- * that use the same license as the "OpenSSL" library), and distribute
- * the linked executables. You must obey the GNU General Public License
- * in all respects for all of the code used other than "OpenSSL". If you
- * modify file(s) with this exception, you may extend this exception to
- * your version of the file(s), but you are not obligated to do so. If
- * you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files
- * in the program, then also delete it here.
- * 
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "DicomValue.h"
-
-namespace Orthanc
-{
-  class DicomNullValue : public DicomValue
-  {
-  public:
-    DicomNullValue()
-    {
-    }
-
-    virtual DicomValue* Clone() const 
-    {
-      return new DicomNullValue();
-    }
-
-    virtual std::string AsString() const
-    {
-      return "(null)";
-    }
-
-    virtual bool IsNull() const
-    {
-      return true;
-    }
-  };
-}
--- a/Core/DicomFormat/DicomString.h	Wed Oct 21 16:52:23 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * In addition, as a special exception, the copyright holders of this
- * program give permission to link the code of its release with the
- * OpenSSL project's "OpenSSL" library (or with modified versions of it
- * that use the same license as the "OpenSSL" library), and distribute
- * the linked executables. You must obey the GNU General Public License
- * in all respects for all of the code used other than "OpenSSL". If you
- * modify file(s) with this exception, you may extend this exception to
- * your version of the file(s), but you are not obligated to do so. If
- * you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files
- * in the program, then also delete it here.
- * 
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "DicomValue.h"
-
-namespace Orthanc
-{
-  class DicomString : public DicomValue
-  {
-  private:
-    std::string value_;
-
-  public:
-    DicomString(const std::string& v) : value_(v)
-    {
-    }
-
-    DicomString(const char* v)
-    {
-      if (v)
-        value_ = v;
-      else
-        value_ = "";
-    }
-
-    virtual DicomValue* Clone() const 
-    {
-      return new DicomString(value_);
-    }
-
-    virtual std::string AsString() const
-    {
-      return value_;
-    }
-  };
-}
--- a/Core/DicomFormat/DicomValue.h	Wed Oct 21 16:52:23 2015 +0200
+++ b/Core/DicomFormat/DicomValue.h	Thu Oct 22 07:52:24 2015 +0200
@@ -32,22 +32,77 @@
 
 #pragma once
 
-#include "../IDynamicObject.h"
+#include "../OrthancException.h"
 
 #include <string>
+#include <boost/noncopyable.hpp>
 
 namespace Orthanc
 {
-  class DicomValue : public IDynamicObject
+  class DicomValue : public boost::noncopyable
   {
-  public:
-    virtual DicomValue* Clone() const = 0;
+  private:
+    enum Type
+    {
+      Type_Null,
+      Type_String,
+      Type_Binary
+    };
+
+    Type         type_;
+    std::string  content_;
+
+    DicomValue(const DicomValue& other) : 
+      type_(other.type_),
+      content_(other.content_)
+    {
+    }
 
-    virtual std::string AsString() const = 0;
+  public:
+    DicomValue() : type_(Type_Null)
+    {
+    }
+    
+    DicomValue(const std::string& content,
+               bool isBinary) :
+      type_(isBinary ? Type_Binary : Type_String),
+      content_(content)
+    {
+    }
+    
+    DicomValue(const char* data,
+               size_t size,
+               bool isBinary) :
+      type_(isBinary ? Type_Binary : Type_String)
+    {
+      content_.assign(data, size);
+    }
+    
+    const std::string& GetContent() const
+    {
+      if (type_ == Type_Null)
+      {
+        throw OrthancException(ErrorCode_BadParameterType);
+      }
+      else
+      {
+        return content_;
+      }
+    }
 
-    virtual bool IsNull() const
+    bool IsNull() const
+    {
+      return type_ == Type_Null;
+    }
+
+    bool IsBinary() const
     {
-      return false;
+      return type_ == Type_Binary;
+    }
+    
+    DicomValue* Clone() const
+    {
+      return new DicomValue(*this);
     }
   };
 }
--- a/OrthancServer/DicomFindQuery.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/DicomFindQuery.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -349,9 +349,15 @@
     for (std::set<DicomTag>::const_iterator
            it = tags.begin(); it != tags.end(); ++it)
     {
+      const DicomValue& value = mainTags.GetValue(*it);
+      if (value.IsBinary() || value.IsNull())
+      {
+        return false;
+      }
+
       Constraints::const_iterator constraint = constraints_.find(*it);
       if (constraint != constraints_.end() &&
-          !constraint->second->Apply(mainTags.GetValue(*it).AsString()))
+          !constraint->second->Apply(value.GetContent()))
       {
         return false;
       }
--- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/DicomProtocol/DicomUserConnection.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -457,7 +457,8 @@
             const DicomValue* value = fix->TestAndGetValue(*it);
 
             if (value != NULL && 
-                value->AsString() == "*")
+                !value->IsNull() &&
+                value->GetContent() == "*")
             {
               fix->SetValue(*it, "");
             }
@@ -948,7 +949,7 @@
       throw OrthancException(ErrorCode_InternalError);
     }
 
-    const std::string tmp = findResult.GetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL).AsString();
+    const std::string tmp = findResult.GetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL).GetContent();
     ResourceType level = StringToResourceType(tmp.c_str());
 
     DicomMap move;
--- a/OrthancServer/FromDcmtkBridge.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/FromDcmtkBridge.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -47,8 +47,6 @@
 #include "../Core/OrthancException.h"
 #include "../Core/Images/PngWriter.h"
 #include "../Core/Uuid.h"
-#include "../Core/DicomFormat/DicomString.h"
-#include "../Core/DicomFormat/DicomNullValue.h"
 #include "../Core/DicomFormat/DicomIntegerPixelAccessor.h"
 
 #include <list>
@@ -380,18 +378,18 @@
       {
         if (c == NULL)  // This case corresponds to the empty string
         {
-          return new DicomString("");
+          return new DicomValue("", false);
         }
         else
         {
           std::string s(c);
           std::string utf8 = Toolbox::ConvertToUtf8(s, encoding);
-          return new DicomString(utf8);
+          return new DicomValue(utf8, false);
         }
       }
       else
       {
-        return new DicomNullValue;
+        return new DicomValue;
       }
     }
 
@@ -409,7 +407,7 @@
         case EVR_OF:  // other float
         case EVR_OW:  // other word
         case EVR_UN:  // unknown value representation
-          return new DicomNullValue;
+          return new DicomValue;
     
           /**
            * String types, should never happen at this point because of
@@ -431,7 +429,7 @@
         case EVR_UT:  // unlimited text
         case EVR_PN:  // person name
         case EVR_UI:  // unique identifier
-          return new DicomNullValue;
+          return new DicomValue;
 
 
           /**
@@ -442,54 +440,54 @@
         {
           Sint32 f;
           if (dynamic_cast<DcmSignedLong&>(element).getSint32(f).good())
-            return new DicomString(boost::lexical_cast<std::string>(f));
+            return new DicomValue(boost::lexical_cast<std::string>(f), false);
           else
-            return new DicomNullValue;
+            return new DicomValue;
         }
 
         case EVR_SS:  // signed short
         {
           Sint16 f;
           if (dynamic_cast<DcmSignedShort&>(element).getSint16(f).good())
-            return new DicomString(boost::lexical_cast<std::string>(f));
+            return new DicomValue(boost::lexical_cast<std::string>(f), false);
           else
-            return new DicomNullValue;
+            return new DicomValue;
         }
 
         case EVR_UL:  // unsigned long
         {
           Uint32 f;
           if (dynamic_cast<DcmUnsignedLong&>(element).getUint32(f).good())
-            return new DicomString(boost::lexical_cast<std::string>(f));
+            return new DicomValue(boost::lexical_cast<std::string>(f), false);
           else
-            return new DicomNullValue;
+            return new DicomValue;
         }
 
         case EVR_US:  // unsigned short
         {
           Uint16 f;
           if (dynamic_cast<DcmUnsignedShort&>(element).getUint16(f).good())
-            return new DicomString(boost::lexical_cast<std::string>(f));
+            return new DicomValue(boost::lexical_cast<std::string>(f), false);
           else
-            return new DicomNullValue;
+            return new DicomValue;
         }
 
         case EVR_FL:  // float single-precision
         {
           Float32 f;
           if (dynamic_cast<DcmFloatingPointSingle&>(element).getFloat32(f).good())
-            return new DicomString(boost::lexical_cast<std::string>(f));
+            return new DicomValue(boost::lexical_cast<std::string>(f), false);
           else
-            return new DicomNullValue;
+            return new DicomValue;
         }
 
         case EVR_FD:  // float double-precision
         {
           Float64 f;
           if (dynamic_cast<DcmFloatingPointDouble&>(element).getFloat64(f).good())
-            return new DicomString(boost::lexical_cast<std::string>(f));
+            return new DicomValue(boost::lexical_cast<std::string>(f), false);
           else
-            return new DicomNullValue;
+            return new DicomValue;
         }
 
 
@@ -503,11 +501,11 @@
           if (dynamic_cast<DcmAttributeTag&>(element).getTagVal(tag, 0).good())
           {
             DicomTag t(tag.getGroup(), tag.getElement());
-            return new DicomString(t.Format());
+            return new DicomValue(t.Format(), false);
           }
           else
           {
-            return new DicomNullValue;
+            return new DicomValue;
           }
         }
 
@@ -518,7 +516,7 @@
          **/
 
         case EVR_SQ:  // sequence of items
-          return new DicomNullValue;
+          return new DicomValue;
 
 
           /**
@@ -542,7 +540,7 @@
         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
-          return new DicomNullValue;
+          return new DicomValue;
 
 
           /**
@@ -550,16 +548,16 @@
            **/ 
 
         default:
-          return new DicomNullValue;
+          return new DicomValue;
       }
     }
     catch (boost::bad_lexical_cast)
     {
-      return new DicomNullValue;
+      return new DicomValue;
     }
     catch (std::bad_cast)
     {
-      return new DicomNullValue;
+      return new DicomValue;
     }
   }
 
@@ -625,8 +623,6 @@
                               DicomToJsonFormat format,
                               unsigned int maxStringLength)
   {
-    std::string content = value.AsString();
-
     switch (format)
     {
       case DicomToJsonFormat_Short:
@@ -636,9 +632,9 @@
 
         if (!value.IsNull() &&
             (maxStringLength == 0 ||
-             content.size() <= maxStringLength))
+             value.GetContent().size() <= maxStringLength))
         {
-          target = content;
+          target = value.GetContent();
         }
 
         break;
@@ -656,10 +652,10 @@
         else
         {
           if (maxStringLength == 0 ||
-              content.size() <= maxStringLength)
+              value.GetContent().size() <= maxStringLength)
           {
             target["Type"] = "String";
-            target["Value"] = content;
+            target["Value"] = value.GetContent();
           }
           else
           {
@@ -866,18 +862,6 @@
   }
 
 
-  void FromDcmtkBridge::Print(FILE* fp, const DicomMap& m)
-  {
-    for (DicomMap::Map::const_iterator 
-           it = m.map_.begin(); it != m.map_.end(); ++it)
-    {
-      DicomTag t = it->first;
-      std::string s = it->second->AsString();
-      fprintf(fp, "0x%04x 0x%04x (%s) [%s]\n", t.GetGroup(), t.GetElement(), GetName(t).c_str(), s.c_str());
-    }
-  }
-
-
   void FromDcmtkBridge::ToJson(Json::Value& result,
                                const DicomMap& values,
                                bool simplify)
@@ -894,7 +878,15 @@
     {
       if (simplify)
       {
-        result[GetName(it->first)] = it->second->AsString();
+        if (it->second->IsNull())
+        {
+          result[GetName(it->first)] = Json::nullValue;
+        }
+        else
+        {
+          // TODO IsBinary
+          result[GetName(it->first)] = it->second->GetContent();
+        }
       }
       else
       {
@@ -909,8 +901,9 @@
         }
         else
         {
+          // TODO IsBinary
           value["Type"] = "String";
-          value["Value"] = it->second->AsString();
+          value["Value"] = it->second->GetContent();
         }
 
         result[it->first.Format()] = value;
--- a/OrthancServer/FromDcmtkBridge.h	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/FromDcmtkBridge.h	Thu Oct 22 07:52:24 2015 +0200
@@ -109,9 +109,6 @@
       target.SetValue(ParseTag(tagName), value);
     }
 
-    static void Print(FILE* fp, 
-                      const DicomMap& m);
-
     static void ToJson(Json::Value& result,
                        const DicomMap& values,
                        bool simplify);
--- a/OrthancServer/OrthancFindRequestHandler.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/OrthancFindRequestHandler.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -240,12 +240,14 @@
      **/
 
     const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL);
-    if (levelTmp == NULL) 
+    if (levelTmp == NULL ||
+        levelTmp->IsNull() ||
+        levelTmp->IsBinary())
     {
       throw OrthancException(ErrorCode_BadRequest);
     }
 
-    ResourceType level = StringToResourceType(levelTmp->AsString().c_str());
+    ResourceType level = StringToResourceType(levelTmp->GetContent().c_str());
 
     if (level != ResourceType_Patient &&
         level != ResourceType_Study &&
@@ -265,7 +267,7 @@
       {
         LOG(INFO) << "  " << query.GetElement(i).GetTag()
                   << "  " << FromDcmtkBridge::GetName(query.GetElement(i).GetTag())
-                  << " = " << query.GetElement(i).GetValue().AsString();
+                  << " = " << query.GetElement(i).GetValue().GetContent();
       }
     }
 
@@ -288,7 +290,7 @@
         continue;
       }
 
-      std::string value = query.GetElement(i).GetValue().AsString();
+      std::string value = query.GetElement(i).GetValue().GetContent();
       if (value.size() == 0)
       {
         // An empty string corresponds to a "*" wildcard constraint, so we ignore it
--- a/OrthancServer/OrthancMoveRequestHandler.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/OrthancMoveRequestHandler.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -138,10 +138,17 @@
       return false;
     }
 
-    std::string value = input.GetValue(tag).AsString();
+    const DicomValue& value = input.GetValue(tag);
+    if (value.IsNull() ||
+        value.IsBinary())
+    {
+      return false;
+    }
+
+    const std::string& content = value.GetContent();
 
     std::list<std::string> ids;
-    context_.GetIndex().LookupIdentifier(ids, tag, value, level);
+    context_.GetIndex().LookupIdentifier(ids, tag, content, level);
 
     if (ids.size() != 1)
     {
@@ -170,7 +177,7 @@
         {
           LOG(INFO) << "  " << query.GetElement(i).GetTag()
                     << "  " << FromDcmtkBridge::GetName(query.GetElement(i).GetTag())
-                    << " = " << query.GetElement(i).GetValue().AsString();
+                    << " = " << query.GetElement(i).GetValue().GetContent();
         }
       }
     }
@@ -183,7 +190,9 @@
 
     const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL);
 
-    if (levelTmp == NULL) 
+    if (levelTmp == NULL ||
+        levelTmp->IsNull() ||
+        levelTmp->IsBinary())
     {
       // The query level is not present in the C-Move request, which
       // does not follow the DICOM standard. This is for instance the
@@ -208,7 +217,7 @@
     }
 
     assert(levelTmp != NULL);
-    ResourceType level = StringToResourceType(levelTmp->AsString().c_str());      
+    ResourceType level = StringToResourceType(levelTmp->GetContent().c_str());      
 
 
     /**
--- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -198,8 +198,8 @@
       return;
     }
 
-    if (fields.GetValue(DICOM_TAG_ACCESSION_NUMBER).AsString().size() <= 2 &&
-        fields.GetValue(DICOM_TAG_PATIENT_ID).AsString().size() <= 2)
+    if (fields.GetValue(DICOM_TAG_ACCESSION_NUMBER).GetContent().size() <= 2 &&
+        fields.GetValue(DICOM_TAG_PATIENT_ID).GetContent().size() <= 2)
     {
       return;
     }        
@@ -228,9 +228,9 @@
       return;
     }
 
-    if ((fields.GetValue(DICOM_TAG_ACCESSION_NUMBER).AsString().size() <= 2 &&
-         fields.GetValue(DICOM_TAG_PATIENT_ID).AsString().size() <= 2) ||
-        fields.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString().size() <= 2)
+    if ((fields.GetValue(DICOM_TAG_ACCESSION_NUMBER).GetContent().size() <= 2 &&
+         fields.GetValue(DICOM_TAG_PATIENT_ID).GetContent().size() <= 2) ||
+        fields.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent().size() <= 2)
     {
       return;
     }        
@@ -259,10 +259,10 @@
       return;
     }
 
-    if ((fields.GetValue(DICOM_TAG_ACCESSION_NUMBER).AsString().size() <= 2 &&
-         fields.GetValue(DICOM_TAG_PATIENT_ID).AsString().size() <= 2) ||
-        fields.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString().size() <= 2 ||
-        fields.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).AsString().size() <= 2)
+    if ((fields.GetValue(DICOM_TAG_ACCESSION_NUMBER).GetContent().size() <= 2 &&
+         fields.GetValue(DICOM_TAG_PATIENT_ID).GetContent().size() <= 2) ||
+        fields.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent().size() <= 2 ||
+        fields.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).GetContent().size() <= 2)
     {
       return;
     }        
--- a/OrthancServer/ParsedDicomFile.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/ParsedDicomFile.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -90,8 +90,6 @@
 #include "../Core/Images/ImageBuffer.h"
 #include "../Core/Images/PngWriter.h"
 #include "../Core/Uuid.h"
-#include "../Core/DicomFormat/DicomString.h"
-#include "../Core/DicomFormat/DicomNullValue.h"
 #include "../Core/DicomFormat/DicomIntegerPixelAccessor.h"
 #include "../Core/Images/PngReader.h"
 
@@ -766,13 +764,15 @@
       std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement
                                   (*element, DicomToJsonFlags_Default, GetEncoding()));
       
-      if (v.get() == NULL)
+      if (v.get() == NULL ||
+          v->IsNull())
       {
         value = "";
       }
       else
       {
-        value = v->AsString();
+        // TODO v->IsBinary()
+        value = v->GetContent();
       }
       
       return true;
--- a/OrthancServer/ParsedDicomFile.h	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/ParsedDicomFile.h	Thu Oct 22 07:52:24 2015 +0200
@@ -37,6 +37,7 @@
 #include "ServerEnumerations.h"
 #include "../Core/Images/ImageAccessor.h"
 #include "../Core/Images/ImageBuffer.h"
+#include "../Core/IDynamicObject.h"
 
 namespace Orthanc
 {
--- a/OrthancServer/ServerIndex.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/ServerIndex.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -394,8 +394,8 @@
           (value2 = dicomSummary.TestAndGetValue(DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS)) != NULL)
       {
         // Patch for series with temporal positions thanks to Will Ryder
-        int64_t imagesInAcquisition = boost::lexical_cast<int64_t>(value->AsString());
-        int64_t countTemporalPositions = boost::lexical_cast<int64_t>(value2->AsString());
+        int64_t imagesInAcquisition = boost::lexical_cast<int64_t>(value->GetContent());
+        int64_t countTemporalPositions = boost::lexical_cast<int64_t>(value2->GetContent());
         std::string expected = boost::lexical_cast<std::string>(imagesInAcquisition * countTemporalPositions);
         db.SetMetadata(series, MetadataType_Series_ExpectedNumberOfInstances, expected);
       }
@@ -404,18 +404,21 @@
                (value2 = dicomSummary.TestAndGetValue(DICOM_TAG_NUMBER_OF_TIME_SLICES)) != NULL)
       {
         // Support of Cardio-PET images
-        int64_t numberOfSlices = boost::lexical_cast<int64_t>(value->AsString());
-        int64_t numberOfTimeSlices = boost::lexical_cast<int64_t>(value2->AsString());
+        int64_t numberOfSlices = boost::lexical_cast<int64_t>(value->GetContent());
+        int64_t numberOfTimeSlices = boost::lexical_cast<int64_t>(value2->GetContent());
         std::string expected = boost::lexical_cast<std::string>(numberOfSlices * numberOfTimeSlices);
         db.SetMetadata(series, MetadataType_Series_ExpectedNumberOfInstances, expected);
       }
 
       else if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES)) != NULL)
       {
-        db.SetMetadata(series, MetadataType_Series_ExpectedNumberOfInstances, value->AsString());
+        db.SetMetadata(series, MetadataType_Series_ExpectedNumberOfInstances, value->GetContent());
       }
     }
-    catch (boost::bad_lexical_cast)
+    catch (OrthancException&)
+    {
+    }
+    catch (boost::bad_lexical_cast&)
     {
     }
   }
@@ -768,8 +771,12 @@
       if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL ||
           (value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL)
       {
-        db_.SetMetadata(instance, MetadataType_Instance_IndexInSeries, value->AsString());
-        instanceMetadata[MetadataType_Instance_IndexInSeries] = value->AsString();
+        if (!value->IsNull() && 
+            !value->IsBinary())
+        {
+          db_.SetMetadata(instance, MetadataType_Instance_IndexInSeries, value->GetContent());
+          instanceMetadata[MetadataType_Instance_IndexInSeries] = value->GetContent();
+        }
       }
 
       // Check whether the series of this new instance is now completed
@@ -1197,22 +1204,22 @@
       switch (currentType)
       {
         case ResourceType_Patient:
-          patientId = map.GetValue(DICOM_TAG_PATIENT_ID).AsString();
+          patientId = map.GetValue(DICOM_TAG_PATIENT_ID).GetContent();
           done = true;
           break;
 
         case ResourceType_Study:
-          studyInstanceUid = map.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString();
+          studyInstanceUid = map.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent();
           currentType = ResourceType_Patient;
           break;
 
         case ResourceType_Series:
-          seriesInstanceUid = map.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).AsString();
+          seriesInstanceUid = map.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).GetContent();
           currentType = ResourceType_Study;
           break;
 
         case ResourceType_Instance:
-          sopInstanceUid = map.GetValue(DICOM_TAG_SOP_INSTANCE_UID).AsString();
+          sopInstanceUid = map.GetValue(DICOM_TAG_SOP_INSTANCE_UID).GetContent();
           currentType = ResourceType_Series;
           break;
 
--- a/OrthancServer/ServerIndexChange.h	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/ServerIndexChange.h	Thu Oct 22 07:52:24 2015 +0200
@@ -33,6 +33,7 @@
 #pragma once
 
 #include "ServerEnumerations.h"
+#include "../Core/IDynamicObject.h"
 #include "../Core/Toolbox.h"
 
 #include <string>
--- a/OrthancServer/ServerToolbox.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/ServerToolbox.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -91,6 +91,21 @@
     }
 
 
+    static std::string ValueAsString(const DicomMap& summary,
+                                     const DicomTag& tag)
+    {
+      const DicomValue& value = summary.GetValue(tag);
+      if (value.IsNull())
+      {
+        return "(null)";
+      }
+      else
+      {
+        return value.GetContent();
+      }
+    }
+
+
     void LogMissingRequiredTag(const DicomMap& summary)
     {
       std::string s, t;
@@ -99,7 +114,7 @@
       {
         if (t.size() > 0)
           t += ", ";
-        t += "PatientID=" + summary.GetValue(DICOM_TAG_PATIENT_ID).AsString();
+        t += "PatientID=" + ValueAsString(summary, DICOM_TAG_PATIENT_ID);
       }
       else
       {
@@ -112,7 +127,7 @@
       {
         if (t.size() > 0)
           t += ", ";
-        t += "StudyInstanceUID=" + summary.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString();
+        t += "StudyInstanceUID=" + ValueAsString(summary, DICOM_TAG_STUDY_INSTANCE_UID);
       }
       else
       {
@@ -125,7 +140,7 @@
       {
         if (t.size() > 0)
           t += ", ";
-        t += "SeriesInstanceUID=" + summary.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).AsString();
+        t += "SeriesInstanceUID=" + ValueAsString(summary, DICOM_TAG_SERIES_INSTANCE_UID);
       }
       else
       {
@@ -138,7 +153,7 @@
       {
         if (t.size() > 0)
           t += ", ";
-        t += "SOPInstanceUID=" + summary.GetValue(DICOM_TAG_SOP_INSTANCE_UID).AsString();
+        t += "SOPInstanceUID=" + ValueAsString(summary, DICOM_TAG_SOP_INSTANCE_UID);
       }
       else
       {
@@ -168,7 +183,12 @@
       {
         const DicomElement& element = flattened.GetElement(i);
         const DicomTag& tag = element.GetTag();
-        database.SetMainDicomTag(resource, tag, element.GetValue().AsString());
+        const DicomValue& value = element.GetValue();
+        if (!value.IsNull() && 
+            !value.IsBinary())
+        {
+          database.SetMainDicomTag(resource, tag, element.GetValue().GetContent());
+        }
       }
     }
 
@@ -180,9 +200,10 @@
     {
       const DicomValue* value = tags.TestAndGetValue(tag);
       if (value != NULL &&
-          !value->IsNull())
+          !value->IsNull() &&
+          !value->IsBinary())
       {
-        std::string s = value->AsString();
+        std::string s = value->GetContent();
 
         if (tag != DICOM_TAG_PATIENT_ID &&
             tag != DICOM_TAG_STUDY_INSTANCE_UID &&
--- a/OrthancServer/SliceOrdering.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/SliceOrdering.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -82,13 +82,14 @@
     const DicomValue* value = map.TestAndGetValue(tag);
 
     if (value == NULL ||
-        value->IsNull())
+        value->IsNull() ||
+        value->IsBinary())
     {
       return false;
     }
     else
     {
-      return TokenizeVector(result, value->AsString(), expectedSize);
+      return TokenizeVector(result, value->GetContent(), expectedSize);
     }
   }
 
@@ -117,11 +118,12 @@
 
       const DicomValue* frames = instance.TestAndGetValue(DICOM_TAG_NUMBER_OF_FRAMES);
       if (frames != NULL &&
-          !frames->IsNull())
+          !frames->IsNull() &&
+          !frames->IsBinary())
       {
         try
         {
-          framesCount_ = boost::lexical_cast<unsigned int>(frames->AsString());
+          framesCount_ = boost::lexical_cast<unsigned int>(frames->GetContent());
         }
         catch (boost::bad_lexical_cast&)
         {
--- a/OrthancServer/ToDcmtkBridge.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/OrthancServer/ToDcmtkBridge.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -52,8 +52,11 @@
     for (DicomMap::Map::const_iterator 
            it = map.map_.begin(); it != map.map_.end(); ++it)
     {
-      std::string s = it->second->AsString();
-      DU_putStringDOElement(result.get(), Convert(it->first), s.c_str());
+      if (!it->second->IsNull())
+      {
+        std::string s = it->second->GetContent();
+        DU_putStringDOElement(result.get(), Convert(it->first), s.c_str());
+      }
     }
 
     return result.release();
--- a/UnitTestsSources/DicomMapTests.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/UnitTestsSources/DicomMapTests.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -36,7 +36,6 @@
 #include "../Core/Uuid.h"
 #include "../Core/OrthancException.h"
 #include "../Core/DicomFormat/DicomMap.h"
-#include "../Core/DicomFormat/DicomNullValue.h"
 #include "../OrthancServer/FromDcmtkBridge.h"
 
 #include <memory>
@@ -103,7 +102,7 @@
   m.SetValue(DICOM_TAG_PATIENT_ID, "PatientID");
   ASSERT_TRUE(m.HasTag(0x0010, 0x0020));
   m.SetValue(DICOM_TAG_PATIENT_ID, "PatientID2");
-  ASSERT_EQ("PatientID2", m.GetValue(0x0010, 0x0020).AsString());
+  ASSERT_EQ("PatientID2", m.GetValue(0x0010, 0x0020).GetContent());
 
   m.GetTags(s);
   ASSERT_EQ(2u, s.size());
@@ -116,14 +115,14 @@
   ASSERT_EQ(DICOM_TAG_PATIENT_NAME, *s.begin());
 
   std::auto_ptr<DicomMap> mm(m.Clone());
-  ASSERT_EQ("PatientName", mm->GetValue(DICOM_TAG_PATIENT_NAME).AsString());  
+  ASSERT_EQ("PatientName", mm->GetValue(DICOM_TAG_PATIENT_NAME).GetContent());  
 
   m.SetValue(DICOM_TAG_PATIENT_ID, "Hello");
   ASSERT_THROW(mm->GetValue(DICOM_TAG_PATIENT_ID), OrthancException);
   mm->CopyTagIfExists(m, DICOM_TAG_PATIENT_ID);
-  ASSERT_EQ("Hello", mm->GetValue(DICOM_TAG_PATIENT_ID).AsString());  
+  ASSERT_EQ("Hello", mm->GetValue(DICOM_TAG_PATIENT_ID).GetContent());  
 
-  DicomNullValue v;
+  DicomValue v;
   ASSERT_TRUE(v.IsNull());
 }
 
--- a/UnitTestsSources/ServerIndexTests.cpp	Wed Oct 21 16:52:23 2015 +0200
+++ b/UnitTestsSources/ServerIndexTests.cpp	Thu Oct 22 07:52:24 2015 +0200
@@ -33,7 +33,6 @@
 #include "PrecompiledHeadersUnitTests.h"
 #include "gtest/gtest.h"
 
-#include "../Core/DicomFormat/DicomNullValue.h"
 #include "../Core/FileStorage/FilesystemStorage.h"
 #include "../Core/Logging.h"
 #include "../Core/Uuid.h"