]> Creatis software - gdcm.git/blobdiff - src/gdcmDocument.cxx
Add verbosity when something wrong happens
[gdcm.git] / src / gdcmDocument.cxx
index d56b0527fe202a244da9553f3d51aab0a17eabb7..fbc717435e6030132b576b6619da0410fc71ded7 100644 (file)
@@ -3,8 +3,8 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmDocument.cxx,v $
   Language:  C++
-  Date:      $Date: 2006/03/01 10:15:12 $
-  Version:   $Revision: 1.343 $
+  Date:      $Date: 2006/06/21 14:06:56 $
+  Version:   $Revision: 1.351 $
                                                                                 
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
@@ -95,19 +95,22 @@ bool Document::Load(  )
    return DoTheLoadingDocumentJob( );
 }
 
-#ifndef GDCM_LEGACY_REMOVE
+
+//#ifndef GDCM_LEGACY_REMOVE
 /**
  * \brief   Loader. (DEPRECATED : not to break the API)   
  * @param   fileName 'Document' (File or DicomDir) to be open for parsing
  * @return false if file cannot be open or no swap info was found,
  *         or no tag was found.
  */
+ /*
 bool Document::Load( std::string const &fileName ) 
 {
    Filename = fileName;
    return DoTheLoadingDocumentJob( );
 }
-#endif
+*/
+//#endif
 
 /**
  * \brief   Performs the Loading Job (internal use only)  
@@ -260,7 +263,7 @@ bool Document::DoTheLoadingDocumentJob(  )
       LoadDocEntry(d, true);
    }
 
-   CloseFile(); 
+   CloseFile();
   
    // ----------------------------
    // Specific code to allow gdcm to read ACR-LibIDO formated images
@@ -621,7 +624,6 @@ std::ifstream *Document::OpenFile()
    }
  
    //-- Broken ACR or DICOM with no Preamble; may start with a Shadow Group --
-   
    // FIXME : We cannot be sure the preable is only zeroes..
    //         (see ACUSON-24-YBR_FULL-RLE.dcm )
    if ( 
@@ -695,7 +697,6 @@ void Document::WriteContent(std::ofstream *fp, FileType filetype)
       fp->write(filePreamble, 128);
       fp->write("DICM", 4);
    }
-
    /*
     * \todo rewrite later, if really usefull
     *       - 'Group Length' element is optional in DICOM
@@ -1047,13 +1048,13 @@ void Document::ParseDES(DocEntrySet *set, long offset,
    DocEntry *newDocEntry;
    DataEntry *newDataEntry;
    SeqEntry *newSeqEntry;
-   VRKey vr;
+   //VRKey vr;
    bool used; // will be set to false when something wrong happens to an Entry.
               // (Entry will then be deleted)
    bool delim_mode_intern = delim_mode;
    bool first = true;
    gdcmDebugMacro( "Enter in ParseDES, delim-mode " <<  delim_mode
-                     << " at offset " << std::hex << "0x(" << offset << ")" ); 
+                     << " at offset " << std::hex << "0x(" << offset << ")" );    
    while (true)
    {
    
@@ -1063,29 +1064,30 @@ void Document::ParseDES(DocEntrySet *set, long offset,
 // Uncomment to track the bug
 /*   
    if( Debug::GetDebugFlag() )   
-      std::cout << std::dec <<"(long)(Fp->tellg()) " << (long)(Fp->tellg()) 
+      std::cout << std::dec <<"(long)(Fp->tellg()) " << (long)(Fp->tellg()) // in Debug mode
                 << std::hex << " 0x(" <<(long)(Fp->tellg()) <<  ")" << std::endl;
-*/
-
+ */ 
    // if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max) // Once per DocEntry   
       if ( !delim_mode ) // 'and then' doesn't exist in C++ :-(
          if ( ((long)(Fp->tellg())-offset) >= l_max) // Once per DocEntry, when no delim mode
          {
             break;
          }
-      newDocEntry = ReadNextDocEntry( );
 
-      // Uncoment this cerr line to be able to 'follow' the DocEntries
-      // when something *very* strange happens
-      if( Debug::GetDebugFlag() ) 
-         std::cerr<<newDocEntry->GetKey()<<" "<<newDocEntry->GetVR()<<std::endl;
+      newDocEntry = ReadNextDocEntry( );
 
       if ( !newDocEntry )
       {
          break;
       }
+      
+      // Uncoment this cerr line to be able to 'follow' the DocEntries
+      // when something *very* strange happens
+      if( Debug::GetDebugFlag() ) 
+         std::cerr<<newDocEntry->GetKey()<<" "<<newDocEntry->GetVR()<<std::endl;
 
-       // an Item Starter found elsewhere but the first position
+       // an Item Starter found elsewhere but in the first position
        // of a SeqEntry means previous entry was a Sequence
        // but we didn't get it (private Sequence + Implicit VR)
        // we have to backtrack.
@@ -1106,7 +1108,7 @@ void Document::ParseDES(DocEntrySet *set, long offset,
       {
          //////////////////////////// DataEntry
  
-         vr = newDocEntry->GetVR();
+         //vr = newDocEntry->GetVR(); // useless ?
 
          if ( !set->AddEntry( newDataEntry ) )
          {
@@ -1232,7 +1234,6 @@ void Document::ParseDES(DocEntrySet *set, long offset,
                      l, delim_mode_intern);
 
             gdcmDebugMacro( "Exit from ParseSQ, delim " << delim_mode_intern);
          }
          if ( !set->AddEntry( newSeqEntry ) )
          {
@@ -1298,12 +1299,14 @@ void Document::ParseSQ( SeqEntry *seqEntry,
             break;
          }
       }
-      if ( !delim_mode ) // andthen doesn't exist in C++ :-(
+      else // ! delim_mode
+      {
          if ( ((long)(Fp->tellg())-offset) >= l_max) // Once per SQItem when no delim mode
          {
             newDocEntry->Delete();
             break;
          }
+      }
       // create the current SQItem
       SQItem *itemSQ = SQItem::New( seqEntry->GetDepthLevel() );
       unsigned int l = newDocEntry->GetReadLength();
@@ -1316,16 +1319,12 @@ void Document::ParseSQ( SeqEntry *seqEntry,
       {
          dlm_mod = false;
       }
-
-      // remove fff0,e000, created out of the SQItem
-      
-      //Fp->seekg(offsetStartCurrentSQItem, std::ios::beg); //JPRx
-      
+            
       // fill up the current SQItem, starting at the beginning of fff0,e000
-
+      
+      Fp->seekg(offsetStartCurrentSQItem, std::ios::beg);        // Once per SQItem
       ParseDES(itemSQ, offsetStartCurrentSQItem, l+8, dlm_mod);
-
-      offsetStartCurrentSQItem = Fp->tellg();  // Once per SQItem
+      offsetStartCurrentSQItem = Fp->tellg();                    // Once per SQItem
  
       seqEntry->AddSQItem( itemSQ, SQItemNumber ); 
       itemSQ->Delete();
@@ -1381,10 +1380,10 @@ DocEntry *Document::Backtrack(DocEntry *docEntry)
  */
 void Document::LoadDocEntry(DocEntry *entry, bool forceLoad)
 {
-   uint16_t group  = entry->GetGroup();
-   uint16_t elem  = entry->GetElement();
+   uint16_t group   = entry->GetGroup();
+   uint16_t elem    = entry->GetElement();
    const VRKey  &vr = entry->GetVR();
-   uint32_t length = entry->GetLength();
+   uint32_t length  = entry->GetLength();
 
  //  Fp->seekg((long)entry->GetOffset(), std::ios::beg); // JPRx
 
@@ -1595,7 +1594,9 @@ uint32_t Document::FindDocEntryLengthOBOrOW()
 VRKey Document::FindDocEntryVR()
 {
    if ( Filetype != ExplicitVR )
+   {
       return GDCM_VRUNKNOWN;
+   }
 
    // Delimiters (0xfffe), are not explicit VR ... 
    if ( CurrentGroup == 0xfffe )
@@ -1622,7 +1623,7 @@ VRKey Document::FindDocEntryVR()
    if ( !CheckDocEntryVR(vr) )
    {
 /*   
-      std::cout << "================================================================Unknown VR" 
+//      std::cout << "================================================================Unknown VR" 
                << std::hex << "0x(" 
                         << (unsigned int)vr[0] << "|" << (unsigned int)vr[1] 
                         << ")" << "for : " <<  CurrentGroup
@@ -1732,21 +1733,32 @@ void Document::FixDocEntryFoundLength(DocEntry *entry,
    // 'Leonardo' source. Hence, one might consider commenting out the
    // following fix on efficiency reasons.
    else if ( gr == 0x0009 && ( elem == 0x1113 || elem == 0x1114 ) )
-   {
-      foundLength = 4;
-      entry->SetReadLength(4); // a bug is to be fixed !
-   } 
+   { 
+   // Ideally we should check we are in Explicit and double check
+   // that VR=UL... this is done properly in gdcm2
+      if( foundLength == 6 )
+      {
+         gdcmWarningMacro( "Replacing Length from 6 into 4" );
+         foundLength = 4;
+         entry->SetReadLength(4); // a bug is to be fixed !
+      } 
+      else if ( foundLength%4 )
+      {
+        gdcmErrorMacro( "This looks like to a buggy Siemens DICOM file."
+        "The length of this tag seems to be wrong" );
+      }
+   }
+
    else if ( entry->GetVR() == "SQ" )
    {
-      foundLength = 0;      // ReadLength is unchanged 
-   } 
-    
-   //////// We encountered a 'delimiter' element i.e. a tag of the form 
+      foundLength = 0;      // ReadLength is unchanged
+   }
+
+   //////// We encountered a 'delimiter' element i.e. a tag of the form
    // "fffe|xxxx" which is just a marker. Delimiters length should not be
    // taken into account.
    else if ( gr == 0xfffe )
-   {    
+   {
      // According to the norm, fffe|0000 shouldn't exist. BUT the Philips
      // image gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm happens to
      // causes extra troubles...
@@ -1758,7 +1770,7 @@ void Document::FixDocEntryFoundLength(DocEntry *entry,
      {
         foundLength=12; // to skip the mess that follows this bugged Tag !
      }
-   }                
+   }
    entry->SetLength(foundLength);
 }
 
@@ -1794,6 +1806,7 @@ bool Document::IsDocEntryAnInteger(DocEntry *entry)
          // encounter such an ill-formed image, we simply display a warning
          // message and proceed on parsing (while crossing fingers).
          long filePosition = Fp->tellg(); // Only when elem 0x0000 length is not 4 (?!?)
+         (void)filePosition;
          gdcmWarningMacro( "Erroneous Group Length element length  on : (" 
            << std::hex << group << " , " << elem
            << ") -before- position x(" << filePosition << ")"
@@ -1980,6 +1993,9 @@ bool Document::CheckSwap()
          //  Find a trick to tell it the caller...
       
          s16 = *((uint16_t *)(deb));
+         gdcmDebugMacro("not a DicomV3 nor a 'clean' ACR/NEMA;"
+                     << " (->despaired wild guesses !)"); 
       
          switch ( s16 )
          {
@@ -2043,7 +2059,7 @@ void Document::SwitchByteSwapCode()
  * \brief  during parsing, Header Elements too long are not loaded in memory
  * @param newSize new size
  */
-void Document::SetMaxSizeLoadEntry(long newSize) 
+void Document::SetMaxSizeLoadEntry(long newSize)
 {
    if ( newSize < 0 )
    {
@@ -2062,7 +2078,7 @@ void Document::SetMaxSizeLoadEntry(long newSize)
  *          (read the 'Group Number', the 'Element Number',
  *          gets the Dict Entry
  *          gets the VR, gets the length, gets the offset value)
- * @return  On succes : the newly created DocEntry, NULL on failure.      
+ * @return  On succes : the newly created DocEntry, NULL on failure.
  */
 DocEntry *Document::ReadNextDocEntry()
 {
@@ -2073,7 +2089,7 @@ DocEntry *Document::ReadNextDocEntry()
    }
    catch ( FormatError )
    {
-      // We reached the EOF (or an error occured) therefore 
+      // We reached the EOF (or an error occured) therefore
       // header parsing has to be considered as finished.
       return 0;
    }
@@ -2085,11 +2101,10 @@ DocEntry *Document::ReadNextDocEntry()
          HandleOutOfGroup0002(CurrentGroup, CurrentElem);
       else
          // Sometimes file contains groups of tags with reversed endianess.
-         HandleBrokenEndian(CurrentGroup, CurrentElem);  
+         HandleBrokenEndian(CurrentGroup, CurrentElem);
     }
-        
+
    VRKey vr = FindDocEntryVR();
-   
    VRKey realVR = vr;
 
    if ( vr == GDCM_VRUNKNOWN )
@@ -2098,9 +2113,14 @@ DocEntry *Document::ReadNextDocEntry()
       {
          realVR = "UL";     // must be UL
       }
+      else if (CurrentGroup == 0xfffe) // Don't get DictEntry for Delimitors
+      {
+         realVR = "UL";
+      }
+
       // Commented out in order not to generate 'Shadow Groups' where some 
       // Data Elements are Explicit VR and some other ones Implicit VR
-      // (Stupid MatLab DICOM Reader couln't read gdcm-written images)
+      // (Stupid MatLab DICOM Reader couldn't read gdcm-written images)
       /*
       else if (CurrentGroup%2 == 1 &&  
                                (CurrentElem >= 0x0010 && CurrentElem <=0x00ff ))
@@ -2112,11 +2132,11 @@ DocEntry *Document::ReadNextDocEntry()
       */
       else
       {
-         DictEntry *dictEntry = GetDictEntry(CurrentGroup,CurrentElem);
+         DictEntry *dictEntry = GetDictEntry(CurrentGroup,CurrentElem);//only when ImplicitVR
          if ( dictEntry )
          {
             realVR = dictEntry->GetVR();
-            dictEntry->Unregister();
+            dictEntry->Unregister(); // GetDictEntry registered it 
          }
       }
    }
@@ -2124,8 +2144,10 @@ DocEntry *Document::ReadNextDocEntry()
    DocEntry *newEntry;
    //if ( Global::GetVR()->IsVROfSequence(realVR) )
    if (realVR == "SQ")
+   {
       newEntry = NewSeqEntry(CurrentGroup, CurrentElem);
-   else 
+   }
+   else
    {
       newEntry = NewDataEntry(CurrentGroup, CurrentElem, realVR);
       static_cast<DataEntry *>(newEntry)->SetState(DataEntry::STATE_NOTLOADED);
@@ -2137,14 +2159,14 @@ DocEntry *Document::ReadNextDocEntry()
       {
          // We thought this was explicit VR, but we end up with an
          // implicit VR tag. Let's backtrack.
-         if ( newEntry->GetGroup() != 0xfffe )
+         //if ( newEntry->GetGroup() != 0xfffe ) 
+         if (CurrentGroup != 0xfffe)
          { 
-            std::string msg;
             int offset = Fp->tellg();//Only when heuristic for Explicit/Implicit was wrong
-            msg = Util::Format(
-                        "Entry (%04x,%04x) at x(%x) should be Explicit VR\n", 
-                        newEntry->GetGroup(), newEntry->GetElement(), offset );
-            gdcmWarningMacro( msg.c_str() );
+
+            gdcmWarningMacro("Entry (" << newEntry->GetKey() << ") at x("
+                     <<  offset << ") should be Explicit VR");
           }
       }
       newEntry->SetImplicitVR();
@@ -2162,7 +2184,6 @@ DocEntry *Document::ReadNextDocEntry()
    }
 
    newEntry->SetOffset(Fp->tellg());  // for each DocEntry
-   
    return newEntry;
 }
 
@@ -2174,6 +2195,23 @@ DocEntry *Document::ReadNextDocEntry()
  */
 void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem)
 {
+ // for strange PMS Gyroscan Intera images
+ // Item 'starter' has a tag : 0x3f3f,0x3f00, for no apparent reason
+ // --- Feel free to remove this test *on your own coy of gdcm*
+ //     if you are sure you'll never face this problem.
+   if ((group == 0x3f3f) && (elem == 0x3f00))
+   {
+     // start endian swap mark for group found
+     gdcmDebugMacro( " delimiter 0x3f3f  found." );
+     // fix the tag
+     group = 0xfffe;
+     elem  = 0xe000;
+     return;
+   }
+   // --- End of removable code
+   
    // Endian reversion. 
    // Some files contain groups of tags with reversed endianess.
    static int reversedEndian = 0;