diff OrthancFramework/Sources/DicomFormat/DicomPath.cpp @ 4681:c5528c7847a6

new class DicomPath
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 07 Jun 2021 17:05:48 +0200
parents
children d38a7040474a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Sources/DicomFormat/DicomPath.cpp	Mon Jun 07 17:05:48 2021 +0200
@@ -0,0 +1,256 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2021 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "DicomPath.h"
+
+
+#if !defined(ORTHANC_ENABLE_DCMTK)
+#  error Macro ORTHANC_ENABLE_DCMTK must be defined
+#endif
+
+#if ORTHANC_ENABLE_DCMTK == 1
+#  include "../DicomParsing/FromDcmtkBridge.h"
+#endif
+
+#include "../OrthancException.h"
+#include "../Toolbox.h"
+
+#include <boost/lexical_cast.hpp>
+
+
+namespace Orthanc
+{
+  DicomPath::PrefixItem::PrefixItem(DicomTag tag,
+                                    bool isUniversal,
+                                    size_t index) :
+    tag_(tag),
+    isUniversal_(isUniversal),
+    index_(index)
+  {
+  }
+      
+
+  size_t DicomPath::PrefixItem::GetIndex() const
+  {
+    if (isUniversal_)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      return index_;
+    }
+  }
+
+  
+  DicomTag DicomPath::ParseTag(const std::string& token)
+  {
+    DicomTag tag(0,0);
+            
+    if (token[0] == '(' &&
+        token[token.size() - 1] == ')')
+    {
+      std::string hex = token.substr(1, token.size() - 2);
+      if (!DicomTag::ParseHexadecimal(tag, hex.c_str()))
+      {
+        throw OrthancException(ErrorCode_UnknownDicomTag, "Cannot parse tag: " + token);
+      }
+    }
+    else
+    {
+#if ORTHANC_ENABLE_DCMTK == 1
+      tag = FromDcmtkBridge::ParseTag(token);
+#else
+      if (!DicomTag::ParseHexadecimal(tag, token.c_str()))
+      {
+        throw OrthancException(ErrorCode_UnknownDicomTag, "Cannot parse tag without DCMTK: " + token);
+      }
+#endif
+    }
+
+    return tag;
+  }
+
+
+  const DicomPath::PrefixItem& DicomPath::GetLevel(size_t i) const
+  {
+    if (i >= prefix_.size())
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      return prefix_[i];
+    }
+  }
+
+
+  DicomPath::DicomPath(const Orthanc::DicomTag& sequence,
+                       size_t index,
+                       const Orthanc::DicomTag& tag) :
+    finalTag_(tag)
+  {
+    AddIndexedTagToPrefix(sequence, index);
+  }
+
+  
+  DicomPath::DicomPath(const Orthanc::DicomTag& sequence1,
+                       size_t index1,
+                       const Orthanc::DicomTag& sequence2,
+                       size_t index2,
+                       const Orthanc::DicomTag& tag) :
+    finalTag_(tag)
+  {
+    AddIndexedTagToPrefix(sequence1, index1);
+    AddIndexedTagToPrefix(sequence2, index2);
+  }
+
+
+  DicomPath::DicomPath(const Orthanc::DicomTag& sequence1,
+                       size_t index1,
+                       const Orthanc::DicomTag& sequence2,
+                       size_t index2,
+                       const Orthanc::DicomTag& sequence3,
+                       size_t index3,
+                       const Orthanc::DicomTag& tag) :
+    finalTag_(tag)
+  {
+    AddIndexedTagToPrefix(sequence1, index1);
+    AddIndexedTagToPrefix(sequence2, index2);
+    AddIndexedTagToPrefix(sequence3, index3);
+  }
+
+
+  void DicomPath::AddIndexedTagToPrefix(const Orthanc::DicomTag& tag,
+                                        size_t index)
+  {
+    prefix_.push_back(PrefixItem::CreateIndexed(tag, index));
+  }
+
+
+  void DicomPath::AddUniversalTagToPrefix(const Orthanc::DicomTag& tag)
+  {
+    prefix_.push_back(PrefixItem::CreateUniversal(tag));
+  }
+  
+
+  std::string DicomPath::Format() const
+  {
+    std::string s;
+
+    for (size_t i = 0; i < prefix_.size(); i++)
+    {
+      s += "(" + prefix_[i].GetTag().Format() + ")";
+
+      if (prefix_[i].IsUniversal())
+      {
+        s += "[*].";
+      }
+      else
+      {
+        s += "[" + boost::lexical_cast<std::string>(prefix_[i].GetIndex()) + "].";
+      }
+    }
+
+    return s + "(" + finalTag_.Format() + ")";
+  }
+
+  
+  DicomPath DicomPath::Parse(const std::string& s,
+                             bool allowUniversal)
+  {
+    std::vector<std::string> tokens;
+    Toolbox::TokenizeString(tokens, s, '.');
+
+    if (tokens.empty())
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange, "Empty path to DICOM tags");
+    }
+
+    const DicomTag finalTag = ParseTag(Toolbox::StripSpaces(tokens[tokens.size() - 1]));
+
+    DicomPath path(finalTag);
+
+    for (size_t i = 0; i < tokens.size() - 1; i++)
+    {
+      size_t pos = tokens[i].find('[');
+      if (pos == std::string::npos)
+      {
+        throw OrthancException(ErrorCode_ParameterOutOfRange, "Parent path doesn't contain an index");
+      }
+      else
+      {
+        const std::string left = Orthanc::Toolbox::StripSpaces(tokens[i].substr(0, pos));
+        const std::string right = Orthanc::Toolbox::StripSpaces(tokens[i].substr(pos + 1));
+
+        if (left.empty())
+        {
+          throw OrthancException(ErrorCode_ParameterOutOfRange, "Parent path doesn't contain a tag");
+        }            
+        else if (right.empty() ||
+                 right[right.size() - 1] != ']')
+        {
+          throw OrthancException(ErrorCode_ParameterOutOfRange, "Parent path doesn't contain the end of the index");
+        }
+        else
+        {
+          DicomTag tag = ParseTag(left);
+
+          try
+          {
+            std::string s = Toolbox::StripSpaces(right.substr(0, right.size() - 1));
+            if (s == "*")
+            {
+              if (allowUniversal)
+              {
+                path.AddUniversalTagToPrefix(tag);
+              }
+              else
+              {
+                throw OrthancException(ErrorCode_ParameterOutOfRange, "Cannot create an universal parent path");
+              }
+            }
+            else
+            {
+              int index = boost::lexical_cast<int>(s);
+              if (index < 0)
+              {
+                throw OrthancException(ErrorCode_ParameterOutOfRange, "Negative index in parent path: " + s);
+              }
+              else
+              {
+                path.AddIndexedTagToPrefix(tag, static_cast<size_t>(index));
+              }
+            }
+          }
+          catch (boost::bad_lexical_cast&)
+          {
+            throw OrthancException(ErrorCode_ParameterOutOfRange, "Not a valid index in parent path: [" + right);
+          }
+        }
+      }
+    }
+
+    return path;
+  }
+}