]> Creatis software - gdcm.git/blobdiff - src/gdcmDocument.cxx
Fix a bug ... when reading a bugged DICOMDIR.
[gdcm.git] / src / gdcmDocument.cxx
index 69586df257d337040e4eb3cba1273605f784ffee..77af0cc52660ac0d3414266a3b662ade6daafe28 100644 (file)
@@ -3,8 +3,8 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmDocument.cxx,v $
   Language:  C++
-  Date:      $Date: 2006/11/08 17:06:36 $
-  Version:   $Revision: 1.356 $
+  Date:      $Date: 2007/06/18 11:10:17 $
+  Version:   $Revision: 1.361 $
                                                                                 
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
@@ -37,7 +37,7 @@
    #include <mem.h> // for memset
 #endif 
 
-namespace gdcm 
+namespace GDCM_NAME_SPACE 
 {
 //-----------------------------------------------------------------------------
 
@@ -70,6 +70,8 @@ Document::Document()
    LoadMode = LD_ALL; // default : load everything, later
    
    SetFileName("");
+   changeFromUN=false;
+   UnexpectedEOF=false;
 }
 
 /**
@@ -244,7 +246,7 @@ bool Document::DoTheLoadingDocumentJob(  )
 
    // Force Loading some more elements if user asked to.
 
-   gdcm::DocEntry *d;
+   GDCM_NAME_SPACE::DocEntry *d;
    for (ListElements::iterator it = UserForceLoadList.begin();  
                                it != UserForceLoadList.end();
                              ++it)
@@ -918,7 +920,7 @@ bool Document::operator<(Document &document)
 
 /**
  * \brief Reads a given length of bytes
- *       (in order to avoid to many CPU time consuming fread-s)
+ *       (in order to avoid to many CPU time-consuming fread-s)
  * @param l length to read 
  */
 void Document::ReadBegBuffer(size_t l)
@@ -1282,11 +1284,11 @@ void Document::ParseDES(DocEntrySet *set, long offset,
                                << " at offset 0x(" << std::hex
                                << newDocEntry->GetOffset() << ")");
 
-            ParseSQ( newSeqEntry, 
-                     newDocEntry->GetOffset(),
-                     l, delim_mode_intern);
+            bool res = ParseSQ( newSeqEntry, 
+                         newDocEntry->GetOffset(),
+                         l, delim_mode_intern);
 
-            gdcmDebugMacro( "Exit from ParseSQ, delim " << delim_mode_intern);
+            gdcmDebugMacro( "Exit from ParseSQ, delim " << delim_mode_intern << " -->return : " << res);
          }
          if ( !set->AddEntry( newSeqEntry ) )
          {
@@ -1318,15 +1320,18 @@ void Document::ParseDES(DocEntrySet *set, long offset,
          newDocEntry->Delete();
       }
       first = false;
+      
+      if (UnexpectedEOF) // some terminator was missing
+         break;
    }                               // end While
    gdcmDebugMacro( "Exit from ParseDES, delim-mode " << delim_mode );
 }
 
 /**
  * \brief   Parses a Sequence ( SeqEntry after SeqEntry)
- * @return  parsed length for this level
+ * @return  false if expected fff0,e000 not found
  */ 
-void Document::ParseSQ( SeqEntry *seqEntry,
+bool Document::ParseSQ( SeqEntry *seqEntry,
                         long offset, long l_max, bool delim_mode)
 {
    int SQItemNumber = 0;
@@ -1339,9 +1344,12 @@ void Document::ParseSQ( SeqEntry *seqEntry,
       DocEntry *newDocEntry = ReadNextDocEntry();
 
       if ( !newDocEntry )
-      {
+      { 
+         // The most frequent is when a SQ terminator is missing (?!?)
          gdcmWarningMacro("in ParseSQ : should never get here!");
-         break;
+         UnexpectedEOF = true;
+         return false;
+         //break;
       }
       if ( delim_mode )
       {
@@ -1389,6 +1397,7 @@ void Document::ParseSQ( SeqEntry *seqEntry,
          break;
       }
    }
+   return true;
 }
 
 /**
@@ -1502,12 +1511,12 @@ void Document::FindDocEntryLength( DocEntry *entry )
 {
    const VRKey &vr  = entry->GetVR();
    uint16_t length16;       
-   
    if ( Filetype == ExplicitVR && !entry->IsImplicitVR() ) 
    {
       if ( vr == "OB" || vr == "OW" || vr == "SQ" || vr == "UT" 
-                                                           || vr == "UN" )
+                                                           || vr == "UN" || changeFromUN == true)
       {
+         changeFromUN = false;
          // The following reserved two bytes (see PS 3.5-2003, section
          // "7.1.2 Data element structure with explicit vr", p 27) must be
          // skipped before proceeding on reading the length on 4 bytes.
@@ -1549,11 +1558,9 @@ void Document::FindDocEntryLength( DocEntry *entry )
          FixDocEntryFoundLength(entry, length32); 
          return;
       }
-
       // Length is encoded on 2 bytes.
       //length16 = ReadInt16();
       length16 = GetInt16();
-
       // 0xffff means that we deal with 'No Length' Sequence 
       //        or 'No Length' SQItem
       if ( length16 == 0xffff) 
@@ -1853,7 +1860,7 @@ bool Document::IsDocEntryAnInteger(DocEntry *entry)
 
    // When we have some semantics on the element we just read, and if we
    // a priori know we are dealing with an integer, then we shall be
-   // able to swap it's element value properly.
+   // able to swap its element value properly.
    if ( elem == 0 )  // This is the group length of the group
    {  
       if ( length == 4 )
@@ -2062,8 +2069,7 @@ bool Document::CheckSwap()
          s16 = *((uint16_t *)(deb));
  
          gdcmDebugMacro("not a DicomV3 nor a 'clean' ACR/NEMA;"
-                     << " (->despaired wild guesses !)"); 
-      
+                     << " (->despaired wild guesses !)");       
          switch ( s16 )
          {
             case 0x0001 :
@@ -2091,9 +2097,53 @@ bool Document::CheckSwap()
                Filetype = ACR;
                return true;
             default :
-               gdcmWarningMacro("ACR/NEMA unfound swap info (Hopeless !)");
-               Filetype = Unknown;
-               return false;
+    
+               s16 = *((uint16_t *)(deb));
+               if (s16 != 0x0000)
+                   return false;
+               s16 = *((uint16_t *)(deb+2));
+
+               //s32 = *((uint32_t *)(deb));
+               Fp->seekg ( 0L, std::ios::beg); // Once per Document
+               CurrentOffsetPosition = 0;
+               switch(s16)  // try an other trick!
+                            // -> to be able to decode 0029|1010 DataElement
+                            // -> and be not less cleaver than dcmdump ;-)
+               {
+                  case 0x00040000 :
+                     SwapCode = 4321;
+                     break;
+                  case 0x04000000 :
+                     SwapCode = 3412;
+                     break;
+                  case 0x00000400 :
+                     SwapCode = 2143;
+                     break;
+                  case 0x00000004 :
+                     SwapCode = 1234;
+                      break;
+     
+                  default:
+                     gdcmWarningMacro("ACR/NEMA unfound swap info (Hopeless !)");
+                     Filetype = Unknown;
+                     return false;
+               }
+               // Check if next 2 bytes are a VR
+               // Probabely something more time-consuming exists with std::string
+               const char VRvalues[] = "AEASCSDADSFLFDISLOLTPNSHSLSSSTTMUIULUSUTOBOWOFATUNSQ";
+               int nbVal = 26;
+               const char *pt = VRvalues;
+               for (int i=0;i<nbVal;i++)
+               {
+                  if(*(deb+4) == *pt++)
+                  if(*(deb+5) == *pt++) {
+                     Filetype = ExplicitVR;
+                     return true;       
+                  }
+
+              }
+              Filetype = ImplicitVR;
+              return true;       
          }
    }
 }
@@ -2164,6 +2214,7 @@ DocEntry *Document::ReadNextDocEntry()
       return 0;
    }
    
+   changeFromUN = false;
    CurrentGroup = GetInt16();
    CurrentElem  = GetInt16();
    
@@ -2214,6 +2265,26 @@ DocEntry *Document::ReadNextDocEntry()
       }
    }
 
+   // if UN found, let's check the dictionary, and trust it!
+   // (maybe a private dictionary exists?)    
+   else if (vr == "UN")
+   {
+      DictEntry *dictEntry = GetDictEntry(CurrentGroup,CurrentElem);
+      if ( dictEntry )
+      {
+         realVR = dictEntry->GetVR(); 
+         dictEntry->Unregister(); // GetDictEntry registered it
+
+         // for VR = "UN", length is always stored on 4 bytes.
+         changeFromUN=true;
+         /// \todo : fixme If inside a supposed to be UN DataElement (but SQ according to a private dictionnary)
+         ///         there is some more supposed to UN DataElements, it will probabely fail.
+         ///         --> find a -non time consuming- trick to store changeFromUN info at DataElement level,
+         ///         not at the Document level.
+      }   
+   }
+
+
    DocEntry *newEntry;
    //if ( Global::GetVR()->IsVROfSequence(realVR) )
    if (realVR == "SQ")