]> Creatis software - gdcm.git/blobdiff - src/gdcmDocument.cxx
The automatic set to VR = "LO" for shadow elements that could be
[gdcm.git] / src / gdcmDocument.cxx
index dbeb89c48896adaa8015f07f721f06e0fc55983b..fed9a8ca3c22d68b511aad325964cdc7e55a6d78 100644 (file)
@@ -3,8 +3,8 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmDocument.cxx,v $
   Language:  C++
-  Date:      $Date: 2005/11/04 15:33:35 $
-  Version:   $Revision: 1.324 $
+  Date:      $Date: 2006/01/31 11:32:06 $
+  Version:   $Revision: 1.337 $
                                                                                 
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
 #include <ctype.h>  // for isdigit
 #include <stdlib.h> // for atoi
 
+#if defined(__BORLANDC__)
+   #include <mem.h> // for memset
+#endif 
+
 namespace gdcm 
 {
 //-----------------------------------------------------------------------------
@@ -89,17 +93,6 @@ bool Document::Load(  )
       return false;
    }
    return DoTheLoadingDocumentJob( );
-} 
-/**
- * \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( );
 }
 
 /**
@@ -337,22 +330,33 @@ bool Document::SetShaDict(DictKey const &dictName)
  * @return false when we're 150 % sure it's NOT a Dicom/Acr file,
  *         true otherwise. 
  */
-bool Document::IsReadable()
+bool Document::IsParsable()
 {
    if ( Filetype == Unknown )
    {
-      gdcmErrorMacro( "Wrong filetype for " << GetFileName());
+      gdcmWarningMacro( "Wrong filetype for " << GetFileName());
       return false;
    }
 
    if ( IsEmpty() )
    { 
-      gdcmErrorMacro( "No tag in internal hash table.");
+      gdcmWarningMacro( "No tag in internal hash table.");
       return false;
    }
 
    return true;
 }
+/**
+ * \brief  This predicate tells us whether or not the current Document 
+ *         was properly parsed and contains at least *one* Dicom Element
+ *         (and nothing more, sorry).
+ * @return false when we're 150 % sure it's NOT a Dicom/Acr file,
+ *         true otherwise. 
+ */
+bool Document::IsReadable()
+{
+   return IsParsable();
+}
 
 /**
  * \brief   Predicate for dicom version 3 file.
@@ -599,7 +603,10 @@ std::ifstream *Document::OpenFile()
       return 0;
    }
  
-   //-- ACR or DICOM with no Preamble; may start with a Shadow Group --
+   //-- 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 ( 
        zero == 0x0001 || zero == 0x0100 || zero == 0x0002 || zero == 0x0200 ||
        zero == 0x0003 || zero == 0x0300 || zero == 0x0004 || zero == 0x0400 ||
@@ -705,15 +712,15 @@ void Document::LoadEntryBinArea(uint16_t group, uint16_t elem)
    DocEntry *docEntry = GetDocEntry(group, elem);
    if ( !docEntry )
    {
-      gdcmWarningMacro(std::hex << group << "|" << elem 
-                       <<  "doesn't exist" );
+      gdcmDebugMacro(std::hex << group << "|" << elem 
+                       <<  " doesn't exist" );
       return;
    }
    DataEntry *dataEntry = dynamic_cast<DataEntry *>(docEntry);
    if ( !dataEntry )
    {
       gdcmWarningMacro(std::hex << group << "|" << elem 
-                       <<  "is NOT a DataEntry");
+                       <<  " is NOT a DataEntry");
       return;
    }
    LoadEntryBinArea(dataEntry);
@@ -928,7 +935,6 @@ uint32_t Document::ReadInt32()
 
 /**
  * \brief skips bytes inside the source file 
- * \warning NOT end user intended method !
  * @return 
  */
 void Document::SkipBytes(uint32_t nBytes)
@@ -981,11 +987,37 @@ int Document::ComputeGroup0002Length( )
    return groupLength; 
 }
 
+/**
+ * \brief   CallStartMethod
+ */
+void Document::CallStartMethod()
+{
+   Progress = 0.0f;
+   Abort    = false;
+   CommandManager::ExecuteCommand(this,CMD_STARTPROGRESS);
+}
+
+/**
+ * \brief   CallProgressMethod
+ */
+void Document::CallProgressMethod()
+{
+   CommandManager::ExecuteCommand(this,CMD_PROGRESS);
+}
+
+/**
+ * \brief   CallEndMethod
+ */
+void Document::CallEndMethod()
+{
+   Progress = 1.0f;
+   CommandManager::ExecuteCommand(this,CMD_ENDPROGRESS);
+}
+
 //-----------------------------------------------------------------------------
 // Private
 /**
  * \brief Loads all the needed Dictionaries
- * \warning NOT end user intended method !   
  */
 void Document::Initialize() 
 {
@@ -1013,7 +1045,7 @@ void Document::ParseDES(DocEntrySet *set, long offset,
    bool delim_mode_intern = delim_mode;
    bool first = true;
    gdcmDebugMacro( "Enter in ParseDES, delim-mode " <<  delim_mode
-                     << " at offset " << std::hex << offset ); 
+                     << " at offset " << std::hex << "0x(" << offset << ")" ); 
    while (true)
    {
       if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max)
@@ -1060,8 +1092,8 @@ void Document::ParseDES(DocEntrySet *set, long offset,
          {
             gdcmDebugMacro( "in ParseDES : cannot add a DataEntry "
                                  << newDataEntry->GetKey()  
-                                 << " (at offset : " 
-                                 << newDataEntry->GetOffset() << " )" );
+                                 << " (at offset : 0x(
+                                 << newDataEntry->GetOffset() << ") )" );
             used=false;
          }
          else
@@ -1070,7 +1102,6 @@ void Document::ParseDES(DocEntrySet *set, long offset,
             // Load only if we can add (not a duplicate key)
             LoadDocEntry( newDataEntry );
          }
-
          if ( newDataEntry->GetElement() == 0x0000 ) // if on group length
          {
             if ( newDataEntry->GetGroup()%2 != 0 )   // if Shadow Group
@@ -1078,8 +1109,9 @@ void Document::ParseDES(DocEntrySet *set, long offset,
                if ( LoadMode & LD_NOSHADOW ) // if user asked to skip shad.gr
                {
                   std::string strLgrGroup = newDataEntry->GetString();
+
                   int lgrGroup;
-                  if ( newDataEntry->IsUnfound() )
+                  //if ( newDataEntry->IsUnfound() ) /?!? JPR
                   {
                      lgrGroup = atoi(strLgrGroup.c_str());
                      Fp->seekg(lgrGroup, std::ios::cur);
@@ -1168,8 +1200,8 @@ void Document::ParseDES(DocEntrySet *set, long offset,
          {  // Don't try to parse zero-length sequences
 
             gdcmDebugMacro( "Entry in ParseSQ, delim " << delim_mode_intern
-                               << " at offset " << std::hex
-                               << newDocEntry->GetOffset() );
+                               << " at offset 0x(" << std::hex
+                               << newDocEntry->GetOffset() << ")");
 
             ParseSQ( newSeqEntry, 
                      newDocEntry->GetOffset(),
@@ -1182,8 +1214,8 @@ void Document::ParseDES(DocEntrySet *set, long offset,
          {
             gdcmWarningMacro( "in ParseDES : cannot add a SeqEntry "
                                 << newSeqEntry->GetKey()
-                                << " (at offset : " 
-                                << newSeqEntry->GetOffset() << " )" ); 
+                                << " (at offset : 0x(
+                                << newSeqEntry->GetOffset() << ") )" ); 
             used = false;
          }
          else
@@ -1294,8 +1326,8 @@ DocEntry *Document::Backtrack(DocEntry *docEntry)
    long offset    = PreviousDocEntry->GetOffset();
 
    gdcmDebugMacro( "Backtrack :" << std::hex << group 
-                                   << "|" << elem
-                                   << " at offset " << offset );
+                                 << "|" << elem
+                                 << " at offset 0x(" <<offset << ")" );
    RemoveEntry( PreviousDocEntry );
 
    // forge the Seq Entry
@@ -1462,7 +1494,6 @@ void Document::FindDocEntryLength( DocEntry *entry )
 
 /**
  * \brief  Find the Length till the next sequence delimiter
- * \warning NOT end user intended method !
  * @return 
  */
 uint32_t Document::FindDocEntryLengthOBOrOW()
@@ -1543,10 +1574,11 @@ VRKey Document::FindDocEntryVR()
    if ( !CheckDocEntryVR(vr) )
    {
       // Don't warn user with useless messages
-      if ( (unsigned char)vr[0] != 0xff || (unsigned char)vr[1] != 0xff )
+      // Often, delimiters (0xfffe), are not explicit VR ...
+      if ( CurrentGroup != 0xfffe )
          gdcmWarningMacro( "Unknown VR " << std::hex << "0x(" 
                         << (unsigned int)vr[0] << "|" << (unsigned int)vr[1] 
-                        << ") at offset :" << positionOnEntry );
+                        << ") at offset : 0x(" << positionOnEntry<< ")" );
       Fp->seekg(positionOnEntry, std::ios::beg);
       return GDCM_VRUNKNOWN;
    }
@@ -1568,7 +1600,6 @@ bool Document::CheckDocEntryVR(const VRKey &vr)
 
 /**
  * \brief   Skip a given Header Entry 
- * \warning NOT end user intended method !
  * @param   entry entry to skip
  */
 void Document::SkipDocEntry(DocEntry *entry) 
@@ -1578,7 +1609,6 @@ void Document::SkipDocEntry(DocEntry *entry)
 
 /**
  * \brief   Skips to the beginning of the next Header Entry 
- * \warning NOT end user intended method !
  * @param   currentDocEntry entry to skip
  */
 void Document::SkipToNextDocEntry(DocEntry *currentDocEntry) 
@@ -1975,13 +2005,10 @@ void Document::SetMaxSizeLoadEntry(long newSize)
  */
 DocEntry *Document::ReadNextDocEntry()
 {
-   uint16_t group;
-   uint16_t elem;
-
    try
    {
-      group = ReadInt16();
-      elem  = ReadInt16();
+      CurrentGroup = ReadInt16();
+      CurrentElem  = ReadInt16();
    }
    catch ( FormatError )
    {
@@ -1991,11 +2018,11 @@ DocEntry *Document::ReadNextDocEntry()
    }
 
    // Sometimes file contains groups of tags with reversed endianess.
-   HandleBrokenEndian(group, elem);
+   HandleBrokenEndian(CurrentGroup, CurrentElem);
 
    // In 'true DICOM' files Group 0002 is always little endian
    if ( HasDCMPreamble )
-      HandleOutOfGroup0002(group, elem);
+      HandleOutOfGroup0002(CurrentGroup, CurrentElem);
  
    VRKey vr = FindDocEntryVR();
    
@@ -2003,19 +2030,25 @@ DocEntry *Document::ReadNextDocEntry()
 
    if ( vr == GDCM_VRUNKNOWN )
    {
-      if ( elem == 0x0000 ) // Group Length
+      if ( CurrentElem == 0x0000 ) // Group Length
       {
          realVR = "UL";     // must be UL
       }
-      else if (group%2 == 1 &&  (elem >= 0x0010 && elem <=0x00ff ))
+      // 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)
+      /*
+      else if (CurrentGroup%2 == 1 &&  
+                               (CurrentElem >= 0x0010 && CurrentElem <=0x00ff ))
       {  
       // DICOM PS 3-5 7.8.1 a) states that those 
       // (gggg-0010->00FF where gggg is odd) attributes have to be LO
          realVR = "LO";
       }
+      */
       else
       {
-         DictEntry *dictEntry = GetDictEntry(group,elem);
+         DictEntry *dictEntry = GetDictEntry(CurrentGroup,CurrentElem);
          if ( dictEntry )
          {
             realVR = dictEntry->GetVR();
@@ -2027,10 +2060,10 @@ DocEntry *Document::ReadNextDocEntry()
 
    DocEntry *newEntry;
    if ( Global::GetVR()->IsVROfSequence(realVR) )
-      newEntry = NewSeqEntry(group, elem);
+      newEntry = NewSeqEntry(CurrentGroup, CurrentElem);
    else 
    {
-      newEntry = NewDataEntry(group, elem, realVR);
+      newEntry = NewDataEntry(CurrentGroup, CurrentElem, realVR);
       static_cast<DataEntry *>(newEntry)->SetState(DataEntry::STATE_NOTLOADED);
    }
 
@@ -2084,6 +2117,7 @@ void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem)
    if ((group == 0xfeff) && (elem == 0x00e0))
    {
      // start endian swap mark for group found
+     gdcmDebugMacro( "Start endian swap mark found." );
      reversedEndian++;
      SwitchByteSwapCode();
      // fix the tag
@@ -2093,6 +2127,7 @@ void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem)
    else if (group == 0xfffe && elem == 0xe00d && reversedEndian) 
    {
      // end of reversed endian group
+     gdcmDebugMacro( "End of reversed endian." );
      reversedEndian--;
      SwitchByteSwapCode();
    }
@@ -2130,17 +2165,6 @@ void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem)
       // if Transfer Syntax is Big Endian we have to change CheckSwap
 
       std::string ts = GetTransferSyntax();
-      if ( ts == GDCM_UNKNOWN )
-      {
-         gdcmDebugMacro("True DICOM File, with NO Transfer Syntax (?!) " );
-         return;      
-      }
-      if ( !Global::GetTS()->IsTransferSyntax(ts) )
-      {
-         gdcmWarningMacro("True DICOM File, with illegal Transfer Syntax: [" 
-                          << ts << "]");
-         return;
-      }
 
       // Group 0002 is always 'Explicit ...' 
       // even when Transfer Syntax says 'Implicit ..." 
@@ -2152,7 +2176,7 @@ void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem)
       }
        
       // FIXME Strangely, this works with 
-      //'Implicit VR BigEndian Transfer Syntax (GE Private)
+      //'Implicit VR BigEndian Transfer Syntax' (GE Private)
       //
       // --> Probabely normal, since we considered we never have 
       // to trust manufacturers.
@@ -2167,6 +2191,33 @@ void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem)
          group = SwapShort(group);
          elem  = SwapShort(elem);
       }
+      
+      /// \todo  find a trick to warn user and stop processing
+            
+      if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == 
+                                             TS::DeflatedExplicitVRLittleEndian)
+      {
+           gdcmWarningMacro("Transfer Syntax [" 
+                        << GetTransferSyntaxName() << "] :"
+                        << " not yet dealt with ");
+           return;       
+      }
+      
+      // The following shouldn't occur very often
+      // Let's check at the very end.
+
+      if ( ts == GDCM_UNKNOWN )
+      {
+         gdcmDebugMacro("True DICOM File, with NO Transfer Syntax (?!) " );
+         return;      
+      }
+      
+      if ( !Global::GetTS()->IsTransferSyntax(ts) )
+      {
+         gdcmWarningMacro("True DICOM File, with illegal Transfer Syntax: [" 
+                          << ts << "]");
+         return;
+      }      
    }
 }