]> Creatis software - gdcm.git/blobdiff - src/gdcmElementSet.cxx
Fix mistypings
[gdcm.git] / src / gdcmElementSet.cxx
index 33325c3fda8ba30b71857eac771eaf988534e90b..31f74ae64890537f8d0d688992a557e32a3364ad 100644 (file)
-// gdcmElementSet.cxx
-//-----------------------------------------------------------------------------
-//
-#include "gdcmElementSet.h"
-#include "gdcmTS.h"
+/*=========================================================================
+                                                                                
+  Program:   gdcm
+  Module:    $RCSfile: gdcmElementSet.cxx,v $
+  Language:  C++
+  Date:      $Date: 2008/05/19 09:25:42 $
+  Version:   $Revision: 1.80 $
+                                                                                
+  Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
+  l'Image). All rights reserved. See Doc/License.txt or
+  http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
+                                                                                
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+                                                                                
+=========================================================================*/
 
+#include "gdcmElementSet.h"
+#include "gdcmDebug.h"
+#include "gdcmSeqEntry.h"
+#include "gdcmDataEntry.h"
 
+namespace GDCM_NAME_SPACE 
+{
 //-----------------------------------------------------------------------------
 // Constructor / Destructor
 /**
- * \ingroup gdcmElementSet
- * \brief   Constructor from a given gdcmElementSet
+ * \brief   Constructor for a given ElementSet
  */
-gdcmDocEntrySet::gdcmDocEntrySet() {
-
+ElementSet::ElementSet() 
+          : DocEntrySet()
+{
 }
 
 /**
- * \ingroup gdcmElementSet
  * \brief   Canonical destructor.
  */
-gdcmElementSet::~gdcmElementSet() 
+ElementSet::~ElementSet() 
 {
-/*   for(tous les DocEntry)
+   ClearEntry();
+}
+
+//-----------------------------------------------------------------------------
+// Public
+/**
+  * \brief   Writes the Header Entries (Dicom Elements)
+  *          from the H Table
+  * @param fp ofstream to write to  
+  * @param filetype    ExplicitVR/ImplicitVR/ACR/ACR_LIBIDO/JPEG/JPEG2000/...
+  */ 
+void ElementSet::WriteContent(std::ofstream *fp, FileType filetype, bool dummy, bool dummy2)
+{
+   bool insideMetaElements     = false;
+   bool yetOutsideMetaElements = false;
+   (void)dummy2;(void)dummy;
+   
+   for (TagDocEntryHT::const_iterator i = TagHT.begin(); 
+                                     i != TagHT.end(); 
+                                    ++i)
    {
-      delete *cc;
+        int group = (i->second)->GetGroup();
+       
+       if (yetOutsideMetaElements==false && group == 0x0002)
+          insideMetaElements = true;
+    
+       if (insideMetaElements == true && group != 0x0002)
+       {
+          yetOutsideMetaElements = true;
+          insideMetaElements     = false;
+       }
+   
+       // depending on the gdcm::Document type 
+       // (gdcm::File; gdcm::DicomDir, (more to come ?)
+       // some groups *cannot* be present.
+       // We hereby protect gdcm for writting stupid things
+       // if they were found in the original document. 
+       if ( !MayIWrite( group ) )
+          continue;
+  
+      // Skip 'Group Length' element, since it may be wrong.
+      //       except for Group 0x0002
+      // ( keep it as well for Group 0x0008 of ACR Files, 
+      //  since some ACR readers *need* it )
+      
+       if ( (i->second)->GetElement() != 0x0000 
+           || 
+            (  (i->second)->GetGroup() == 0x0002 
+             ||( (filetype == ACR || filetype == ACR_LIBIDO ) && (i->second)->GetGroup() == 0x0008 ) )
+        )
+       {           
+             // There are DocEntries, written recursively
+             // false : we are outside any Sequence
+             i->second->WriteContent(fp, filetype, insideMetaElements, false );
+       }             
+   } 
+}
+
+/**
+ * \brief   add a new Dicom Element pointer to the H Table
+ * @param   newEntry entry to add
+ */
+bool ElementSet::AddEntry(DocEntry *newEntry)
+{
+   const TagKey &key = newEntry->GetKey();
+
+   if ( TagHT.count(key) == 1 )
+   {
+      gdcmWarningMacro( "Key already present: " << key );
+      return false;
+   }
+   else
+   {
+      TagHT.insert(TagDocEntryHT::value_type(newEntry->GetKey(), newEntry));
+      newEntry->Register();
+      return true;
    }
-   */
 }
 
+/**
+ * \brief   Clear the hash table from given entry AND delete the entry.
+ * @param   entryToRemove Entry to remove AND delete.
+ */
+bool ElementSet::RemoveEntry( DocEntry *entryToRemove)
+{
+   const TagKey &key = entryToRemove->GetKey();
+   if ( TagHT.count(key) == 1 )
+   {
+      TagHT.erase(key);
+      entryToRemove->Unregister();
+      return true;
+   }
 
-//-----------------------------------------------------------------------------
-// Public
+   gdcmWarningMacro( "Key not present : " << key);
+   return false ;
+}
 
+/**
+ * \brief   delete all entries in the ElementSet
+ */
+void ElementSet::ClearEntry()
+{
+   for(TagDocEntryHT::iterator cc = TagHT.begin();cc != TagHT.end(); ++cc)
+   {
+      if ( cc->second )
+      {
+         cc->second->Unregister();
+      }
+   }
+   TagHT.clear();
+}
 
-//-----------------------------------------------------------------------------
-// Protected
+/**
+ * \brief   Get the first entry while visiting *the* 'zero level' DocEntrySet
+ *              (DocEntries out of any Sequence)
+ * \return  The first DocEntry if found, otherwhise NULL
+ */
+DocEntry *ElementSet::GetFirstEntry()
+{
+   ItTagHT = TagHT.begin();
+   if (ItTagHT != TagHT.end())
+      return  ItTagHT->second;
+   return NULL;
+}
 
-//-----------------------------------------------------------------------------
-// Private
+/**
+ * \brief   Get the next entry while visiting *the* 'zero level' DocEntrySet
+ *              (DocEntries out of any Sequence) 
+ * \note : meaningfull only if GetFirstEntry already called 
+ * \return  The next DocEntry if found, otherwhise NULL
+ */
+DocEntry *ElementSet::GetNextEntry()
+{
+   gdcmAssertMacro (ItTagHT != TagHT.end());
+
+   ++ItTagHT;
+   if (ItTagHT != TagHT.end())
+      return  ItTagHT->second;
+   return NULL;
+}
 
 /**
- * \brief  Find the value Length of the passed Header Entry
- * @param  Entry Header Entry whose length of the value shall be loaded. 
+ * \brief  retrieves a Dicom Element using (group, element)
+ * @param   group  Group number of the searched Dicom Element 
+ * @param   elem Element number of the searched Dicom Element 
+ * @return  
  */
- void gdcmElementSet::FindDocEntryLength (gdcmDocEntry *Entry) {
-   guint16 element = Entry->GetElement();
-   //guint16 group   = Entry->GetGroup(); //FIXME
-   std::string  vr = Entry->GetVR();
-   guint16 length16;
-       
-   
-   if ( (filetype == ExplicitVR) && (! Entry->IsImplicitVR()) ) 
+DocEntry *ElementSet::GetDocEntry(uint16_t group, uint16_t elem) 
+{
+   TagKey key = DictEntry::TranslateToKey(group, elem);
+   TagDocEntryHT::iterator it = TagHT.find(key);
+
+   if ( it!=TagHT.end() )
+      return it->second;
+   return NULL;
+}
+
+/**
+ * \brief Copies all the attributes from an other DocEntrySet 
+ * @param set entry to copy from
+ * @remarks The contained DocEntries a not copied, only referenced
+ */
+void ElementSet::Copy(DocEntrySet *set)
+{
+   // Remove all previous entries
+   ClearEntry();
+
+   DocEntrySet::Copy(set);
+
+   ElementSet *eltSet = dynamic_cast<ElementSet *>(set);
+   if( eltSet )
    {
-      if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) 
+      TagHT = eltSet->TagHT;
+      for(ItTagHT = TagHT.begin();ItTagHT != TagHT.end();++ItTagHT)
       {
-         // The following reserved two bytes (see PS 3.5-2001, section
-         // 7.1.2 Data element structure with explicit vr p27) must be
-         // skipped before proceeding on reading the length on 4 bytes.
-         fseek(fp, 2L, SEEK_CUR);
-         guint32 length32 = ReadInt32();
-
-         if ( (vr == "OB") && (length32 == 0xffffffff) ) 
-         {
-            Entry->SetLength(FindHeaderEntryLengthOB());
-            return;
-         }
-         FixHeaderEntryFoundLength(Entry, length32); 
-         return;
+         (ItTagHT->second)->Register();
       }
+   }
+}
 
-      // Length is encoded on 2 bytes.
-      length16 = ReadInt16();
-      
-      // We can tell the current file is encoded in big endian (like
-      // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag
-      // and it's value is the one of the encoding of a big endian file.
-      // In order to deal with such big endian encoded files, we have
-      // (at least) two strategies:
-      // * when we load the "Transfer Syntax" tag with value of big endian
-      //   encoding, we raise the proper flags. Then we wait for the end
-      //   of the META group (0x0002) among which is "Transfer Syntax",
-      //   before switching the swap code to big endian. We have to postpone
-      //   the switching of the swap code since the META group is fully encoded
-      //   in little endian, and big endian coding only starts at the next
-      //   group. The corresponding code can be hard to analyse and adds
-      //   many additional unnecessary tests for regular tags.
-      // * the second strategy consists in waiting for trouble, that shall
-      //   appear when we find the first group with big endian encoding. This
-      //   is easy to detect since the length of a "Group Length" tag (the
-      //   ones with zero as element number) has to be of 4 (0x0004). When we
-      //   encounter 1024 (0x0400) chances are the encoding changed and we
-      //   found a group with big endian encoding.
-      // We shall use this second strategy. In order to make sure that we
-      // can interpret the presence of an apparently big endian encoded
-      // length of a "Group Length" without committing a big mistake, we
-      // add an additional check: we look in the already parsed elements
-      // for the presence of a "Transfer Syntax" whose value has to be "big
-      // endian encoding". When this is the case, chances are we have got our
-      // hands on a big endian encoded file: we switch the swap code to
-      // big endian and proceed...
-      if ( (element  == 0x0000) && (length16 == 0x0400) ) 
+/**
+ * \brief Checks whether *all* the DataEntries of the group have all
+ *        the same type for VR (ImplicitVR or ExplicitVR) 
+ * @param group group number to be checked
+ * @return 1:ImplicitVR 2:ExplicitVR -1:NotCoherent 
+ */
+int ElementSet::IsVRCoherent( uint16_t group )
+{
+   uint16_t currentGroup;
+   int codeVR = -1;
+   int currentCodeVR;
+   for(TagDocEntryHT::iterator cc = TagHT.begin();cc != TagHT.end(); ++cc)
+   {
+      currentGroup = cc->second->GetGroup();
+
+      if ( currentGroup < group )
+         continue;   
+      if ( currentGroup > group )
+         break;
+      // currentGroup == group
+      if (codeVR == -1)
       {
-         if ( ! IsExplicitVRBigEndianTransferSyntax() ) 
-         {
-            dbg.Verbose(0, "gdcmDocument::FindLength", "not explicit VR");
-            errno = 1;
-            return;
-         }
-         length16 = 4;
-         SwitchSwapToBigEndian();
-         // Restore the unproperly loaded values i.e. the group, the element
-         // and the dictionary entry depending on them.
-         guint16 CorrectGroup   = SwapShort(Entry->GetGroup());
-         guint16 CorrectElem    = SwapShort(Entry->GetElement());
-         gdcmDictEntry * NewTag = GetDictEntryByNumber(CorrectGroup,
-                                                       CorrectElem);
-         if (!NewTag) 
-         {
-            // This correct tag is not in the dictionary. Create a new one.
-            NewTag = NewVirtualDictEntry(CorrectGroup, CorrectElem);
-         }
-         // FIXME this can create a memory leaks on the old entry that be
-         // left unreferenced.
-         Entry->SetDictEntry(NewTag);
+         if (cc->second->IsImplicitVR() )
+            codeVR = 1;
+         else 
+            codeVR = 2;
+         continue;
       }
-       
-      // Heuristic: well some files are really ill-formed.
-      if ( length16 == 0xffff) 
+      else
       {
-         length16 = 0;
-         //dbg.Verbose(0, "gdcmDocument::FindLength",
-         //            "Erroneous element length fixed.");
-         // Actually, length= 0xffff means that we deal with
-         // Unknown Sequence Length 
+         if (cc->second->IsImplicitVR() )
+            currentCodeVR = 1; //Implicit
+         else 
+            currentCodeVR = 2; // Explicit  
+  
+         if ( currentCodeVR == codeVR )
+           continue;
+         else
+            return -1;    // -1 : not coherent 
       }
-      FixHeaderEntryFoundLength(Entry, (guint32)length16);
-      return;
+   }   
+   return codeVR;
+}
+
+
+//-----------------------------------------------------------------------------
+// Protected
+
+//-----------------------------------------------------------------------------
+// Private
+
+//-----------------------------------------------------------------------------
+// Print
+/**
+  * \brief   Prints the Header Entries (Dicom Elements) from the H Table
+  * @param os ostream to write to  
+  * @param indent Indentation string to be prepended during printing
+  */ 
+void ElementSet::Print(std::ostream &os, std::string const & )
+{
+   // Let's change the 'warning value' for Pixel Data,
+   // to avoid human reader to be confused by 'gdcm::NotLoaded'.   
+   DataEntry *pixelElement = GetDataEntry(0x7fe0,0x0010);
+   if ( pixelElement != 0 )
+   {
+      pixelElement->SetFlag( DataEntry::FLAG_PIXELDATA );
    }
-   else
+
+   for( TagDocEntryHT::const_iterator i = TagHT.begin(); i != TagHT.end(); ++i)
    {
-      // Either implicit VR or a non DICOM conformal (see note below) explicit
-      // VR that ommited the VR of (at least) this element. Farts happen.
-      // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25
-      // on Data elements "Implicit and Explicit VR Data Elements shall
-      // not coexist in a Data Set and Data Sets nested within it".]
-      // Length is on 4 bytes.
-      
-      FixHeaderEntryFoundLength(Entry, ReadInt32());
-      return;
+      DocEntry *entry = i->second;
+
+      entry->SetPrintLevel(PrintLevel);
+      entry->Print(os);   
+
+      if ( dynamic_cast<SeqEntry*>(entry) )
+      {
+         // Avoid the newline for a sequence:
+         continue;
+      }
+      os << std::endl;
    }
 }
+
+//-----------------------------------------------------------------------------
+} // end namespace gdcm