diff OrthancFramework/Sources/DicomFormat/DicomStreamReader.h @ 4220:92a21efa5c96

reorganization of DicomStreamReader
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 30 Sep 2020 15:33:47 +0200
parents
children e4c0218b6b23
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Sources/DicomFormat/DicomStreamReader.h	Wed Sep 30 15:33:47 2020 +0200
@@ -0,0 +1,129 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 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/>.
+ **/
+
+
+#pragma once
+
+#include "DicomTag.h"
+#include "StreamBlockReader.h"
+
+namespace Orthanc
+{
+  /**
+   * This class parses a stream containing a DICOM instance. It does
+   * *not* support the visit of sequences (it only works at the first
+   * level of the hierarchy), and as a consequence, it doesn't give
+   * access to the pixel data of compressed transfer syntaxes.
+   **/
+  class DicomStreamReader : public boost::noncopyable
+  {
+  public:
+    class IVisitor : public boost::noncopyable
+    {
+    public:
+      virtual ~IVisitor()
+      {
+      }
+
+      // The data from this function will always be Little Endian (as
+      // specified by the DICOM standard)
+      virtual void VisitMetaHeaderTag(const DicomTag& tag,
+                                      const ValueRepresentation& vr,
+                                      const std::string& value) = 0;
+
+      virtual void VisitTransferSyntax(DicomTransferSyntax transferSyntax) = 0;
+
+      // Return "false" to stop processing
+      virtual bool VisitDatasetTag(const DicomTag& tag,
+                                   const ValueRepresentation& vr,
+                                   const std::string& value,
+                                   bool isLittleEndian) = 0;
+    };
+    
+  private:
+    enum State
+    {
+      State_Preamble,
+      State_MetaHeader,
+      State_DatasetTag,
+      State_SequenceExplicitLength,
+      State_SequenceExplicitValue,
+      State_DatasetExplicitLength,
+      State_DatasetValue,
+      State_Done
+    };
+
+    StreamBlockReader    reader_;
+    State                state_;
+    DicomTransferSyntax  transferSyntax_;
+    DicomTag             previousTag_;
+    DicomTag             danglingTag_;  // Root-level tag
+    ValueRepresentation  danglingVR_;
+    unsigned int         sequenceDepth_;
+    
+    bool IsLittleEndian() const;
+    
+    void HandlePreamble(IVisitor& visitor,
+                        const std::string& block);
+    
+    void HandleMetaHeader(IVisitor& visitor,
+                          const std::string& block);
+
+    void HandleDatasetTag(const std::string& block,
+                          const DicomTag& untilTag);
+
+    void HandleDatasetExplicitLength(uint32_t length);
+    
+    void HandleDatasetExplicitLength(const std::string& block);
+
+    void HandleSequenceExplicitLength(const std::string& block);
+
+    void HandleSequenceExplicitValue();
+    
+    void HandleDatasetValue(IVisitor& visitor,
+                            const std::string& block);
+    
+  public:
+    DicomStreamReader(std::istream& stream);
+
+    /**
+     * Consume all the available bytes from the input stream, until
+     * end-of-stream is reached or the current tag is ">= untilTag".
+     * This method can be invoked several times, as more bytes are
+     * available from the input stream. To check if the DICOM stream
+     * is fully parsed until the goal tag, call "IsDone()".
+     **/
+    void Consume(IVisitor& visitor,
+                 const DicomTag& untilTag);
+
+    void Consume(IVisitor& visitor);
+
+    bool IsDone() const
+    {
+      return (state_ == State_Done);
+    }
+
+    uint64_t GetProcessedBytes() const
+    {
+      return reader_.GetProcessedBytes();
+    }
+  };
+}