]> Creatis software - gdcm.git/blobdiff - src/gdcmDocument.cxx
English mistakes
[gdcm.git] / src / gdcmDocument.cxx
index c339fa44ff53f8a59dbe98c6d4cdd58a91b9a175..1c50ab555b50df2015b30e3f8a369d96717e7408 100644 (file)
@@ -3,8 +3,8 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmDocument.cxx,v $
   Language:  C++
-  Date:      $Date: 2006/05/30 08:10:19 $
-  Version:   $Revision: 1.349 $
+  Date:      $Date: 2007/04/12 13:22:49 $
+  Version:   $Revision: 1.357 $
                                                                                 
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
@@ -62,11 +62,13 @@ Document::Document()
    Initialize();
    SwapCode = 1234;
    Filetype = ExplicitVR;
+   CurrentOffsetPosition = 0;
    // Load will set it to true if sucessfull
    Group0002Parsed = false;
    IsDocumentAlreadyLoaded = false;
    IsDocumentModified = true;
    LoadMode = LD_ALL; // default : load everything, later
+   
    SetFileName("");
 }
 
@@ -579,8 +581,9 @@ double Document::SwapDouble(double a)
 // -----------------File I/O ---------------
 /**
  * \brief  Tries to open the file \ref Document::Filename and
- *         checks the preamble when existing.
- * @return The FILE pointer on success. 
+ *         checks the preamble when existing,
+ *         or if the file starts with an ACR-NEMA look-like element.
+ * @return The FILE pointer on success, 0 on failure. 
  */
 std::ifstream *Document::OpenFile()
 {
@@ -623,23 +626,6 @@ std::ifstream *Document::OpenFile()
       return 0;
    }
  
-   //-- 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 ||
-       zero == 0x0005 || zero == 0x0500 || zero == 0x0006 || zero == 0x0600 ||
-       zero == 0x0007 || zero == 0x0700 || zero == 0x0008 || zero == 0x0800 )
-   {
-      std::string msg = Util::Format(
-        "ACR/DICOM starting by 0x(%04x) at the beginning of the file\n", zero);
-      // FIXME : is it a Warning message, or a Debug message?
-      gdcmWarningMacro( msg.c_str() );
-      return Fp;
-   }
    //-- DICOM --
    Fp->seekg(126L, std::ios::cur);  // Once per Document
    char dicm[4]; // = {' ',' ',' ',' '};
@@ -649,12 +635,32 @@ std::ifstream *Document::OpenFile()
       CloseFile();
       return 0;
    }
+   
    if ( memcmp(dicm, "DICM", 4) == 0 )
    {
       HasDCMPreamble = true;
       return Fp;
    }
 
+   //-- 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 ||
+       zero == 0x0005 || zero == 0x0500 || zero == 0x0006 || zero == 0x0600 ||
+       zero == 0x0007 || zero == 0x0700 || zero == 0x0008 || zero == 0x0800 ||
+       zero == 0x0028 || 0x2800    // worse : some ACR-NEMA like files 
+                                   // start 00028 group ?!?      
+       )
+   {
+      std::string msg = Util::Format(
+        "ACR/DICOM starting by 0x(%04x) at the beginning of the file\n", zero);
+      // FIXME : is it a Warning message, or a Debug message?
+      gdcmWarningMacro( msg.c_str() );
+      return Fp;
+   }
+   
    // -- Neither ACR/No Preamble Dicom nor DICOMV3 file
    CloseFile();
    // Don't user Warning nor Error, not to pollute the output
@@ -690,7 +696,7 @@ void Document::WriteContent(std::ofstream *fp, FileType filetype)
    // Skip if user wants to write an ACR-NEMA file
 
    if ( filetype == ImplicitVR || filetype == ExplicitVR ||
-        filetype == JPEG )
+        filetype == JPEG || filetype == JPEG2000 )
    {
       // writing Dicom File Preamble
       char filePreamble[128];
@@ -909,6 +915,27 @@ bool Document::operator<(Document &document)
 
 //-----------------------------------------------------------------------------
 // Protected
+
+/**
+ * \brief Reads a given length of bytes
+ *       (in order to avoid to many CPU time consuming fread-s)
+ * @param l length to read 
+ */
+void Document::ReadBegBuffer(size_t l)
+   throw( FormatError )
+{   
+   Fp->read (BegBuffer, (size_t)l);
+   if ( Fp->fail() )
+   {
+      throw FormatError( "Document::ReadBegBuffer()", " file error." );
+   }
+   if ( Fp->eof() )
+   {
+      throw FormatError( "Document::ReadBegBuffer()", "EOF." );
+   }
+   PtrBegBuffer = BegBuffer;
+   CurrentOffsetPosition+=l;
+}
 /**
  * \brief Reads a supposed to be 16 Bits integer
  *       (swaps it depending on processor endianness) 
@@ -931,6 +958,18 @@ uint16_t Document::ReadInt16()
    return g;
 }
 
+/**
+ * \brief Gets from BegBuffer a supposed to be 16 Bits integer
+ *       (swaps it depending on processor endianness) 
+ * @return read value
+ */
+uint16_t Document::GetInt16()
+{
+   uint16_t g = *((uint16_t*)PtrBegBuffer);
+   g = SwapShort(g);
+   PtrBegBuffer+=2; 
+   return g;
+}
 /**
  * \brief  Reads a supposed to be 32 Bits integer
  *        (swaps it depending on processor endianness)  
@@ -953,6 +992,19 @@ uint32_t Document::ReadInt32()
    return g;
 }
 
+/**
+ * \brief Gets from BegBuffer a supposed to be 32 Bits integer
+ *       (swaps it depending on processor endianness) 
+ * @return read value
+ */
+uint32_t Document::GetInt32()
+{
+   uint32_t g = *((uint32_t*)PtrBegBuffer);
+   g = SwapLong(g); 
+   PtrBegBuffer+=4;
+   return g;
+}
+
 /**
  * \brief   Re-computes the length of the Dicom group 0002.
  */
@@ -1460,9 +1512,9 @@ void Document::FindDocEntryLength( DocEntry *entry )
          // "7.1.2 Data element structure with explicit vr", p 27) must be
          // skipped before proceeding on reading the length on 4 bytes.
 
-         Fp->seekg( 2L, std::ios::cur); // Once per OW,OB,SQ DocEntry
-         uint32_t length32 = ReadInt32();
-
+         //Fp->seekg( 2L, std::ios::cur); // Once per OW,OB,SQ DocEntry
+         uint32_t length32 = ReadInt32(); // Once per OW,OB,SQ DocEntry
+         CurrentOffsetPosition+=4;
          if ( (vr == "OB" || vr == "OW") && length32 == 0xffffffff ) 
          {
             uint32_t lengthOB;
@@ -1499,8 +1551,9 @@ void Document::FindDocEntryLength( DocEntry *entry )
       }
 
       // Length is encoded on 2 bytes.
-      length16 = ReadInt16();
-  
+      //length16 = ReadInt16();
+      length16 = GetInt16();
+
       // 0xffff means that we deal with 'No Length' Sequence 
       //        or 'No Length' SQItem
       if ( length16 == 0xffff) 
@@ -1523,8 +1576,8 @@ void Document::FindDocEntryLength( DocEntry *entry )
      // even if Transfer Syntax is 'Implicit VR ...'
      // --> Except for 'Implicit VR Big Endian Transfer Syntax GE Private' 
      //     where Group 0x0002 is *also* encoded in Implicit VR !
-      
-      FixDocEntryFoundLength( entry, ReadInt32() );
+
+      FixDocEntryFoundLength( entry, GetInt32() /*ReadInt32()*/ );
       return;
    }
 }
@@ -1538,6 +1591,7 @@ uint32_t Document::FindDocEntryLengthOBOrOW()
    throw( FormatUnexpected )
 {
    // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
+   
    long positionOnEntry = Fp->tellg(); // Only for OB,OW DataElements
 
    bool foundSequenceDelimiter = false;
@@ -1547,16 +1601,21 @@ uint32_t Document::FindDocEntryLengthOBOrOW()
    {
       uint16_t group;
       uint16_t elem;
+
       try
       {
-         group = ReadInt16();
-         elem  = ReadInt16();   
+         //group = ReadInt16(); // Once per fragment (if any) of OB,OW DataElements
+         //elem  = ReadInt16(); // Once per fragment (if any) of OB,OW DataElements 
+         ReadBegBuffer(4); // Once per fragment (if any) of OB,OW DataElements
       }
       catch ( FormatError )
       {
          throw FormatError("Unexpected end of file encountered during ",
                            "Document::FindDocEntryLengthOBOrOW()");
       }
+      group = GetInt16();
+      elem  = GetInt16();
+
       // We have to decount the group and element we just read
       totalLength += 4;     
       if ( group != 0xfffe || ( ( elem != 0xe0dd ) && ( elem != 0xe000 ) ) )
@@ -1574,7 +1633,7 @@ uint32_t Document::FindDocEntryLengthOBOrOW()
       {
          foundSequenceDelimiter = true;
       }
-      uint32_t itemLength = ReadInt32();
+      uint32_t itemLength = ReadInt32(); // Once per fragment (if any) of OB,OW DataElements
       // We add 4 bytes since we just read the ItemLength with ReadInt32
       totalLength += itemLength + 4;
       SkipBytes(itemLength);
@@ -1584,7 +1643,7 @@ uint32_t Document::FindDocEntryLengthOBOrOW()
          break;
       }
    }
-   Fp->seekg( positionOnEntry, std::ios::beg); // Only for OB,OW DataElements
+   Fp->seekg( positionOnEntry, std::ios::beg); // Only once for OB,OW DataElements
    return totalLength;
 }
 
@@ -1603,9 +1662,9 @@ VRKey Document::FindDocEntryVR()
    if ( CurrentGroup == 0xfffe )
       return GDCM_VRUNKNOWN;
          
-   long positionOnEntry;     
-   if( Debug::GetWarningFlag() ) 
-     positionOnEntry = Fp->tellg(); // Only in Warning Mode
+   //long positionOnEntry;     
+   //if( Debug::GetWarningFlag() ) 
+   //  positionOnEntry = Fp->tellg(); // Only in Warning Mode
    
    // Warning: we believe this is explicit VR (Value Representation) because
    // we used a heuristic that found "UL" in the first tag and/or
@@ -1619,9 +1678,12 @@ VRKey Document::FindDocEntryVR()
    // if it happens not to be the case.
 
    VRKey vr;
-   Fp->read(&(vr[0]),(size_t)2);
-
-   if ( !CheckDocEntryVR(vr) )
+   //Fp->read(&(vr[0]),(size_t)2);
+   vr[0] = *PtrBegBuffer++;
+   vr[1] = *PtrBegBuffer++;
+   
+   //if ( !CheckDocEntryVR(vr) ) // avoid useless function call
+   if ( !Global::GetVR()->IsValidVR(vr) )
    {
 /*   
 //      std::cout << "================================================================Unknown VR" 
@@ -1634,12 +1696,13 @@ VRKey Document::FindDocEntryVR()
       gdcmWarningMacro( "Unknown VR " << std::hex << "0x(" 
                         << (unsigned int)vr[0] << "|" << (unsigned int)vr[1] 
                         << ")"  
-                        << " at offset : 0x(" << positionOnEntry<< ") for group " << CurrentGroup
+                        << " at offset : 0x(" << CurrentOffsetPosition-4<< ") for group " << CurrentGroup
                         );
 
       //Fp->seekg(positionOnEntry, std::ios::beg); //JPRx
-      Fp->seekg((long)-2, std::ios::cur);// only for unrecognized VR (?!?) 
+      //Fp->seekg((long)-2, std::ios::cur);// only for unrecognized VR (?!?) 
                                          //see :MR_Philips_Intera_PrivateSequenceExplicitVR.dcm
+      PtrBegBuffer-=2;
       return GDCM_VRUNKNOWN;
    }
    return vr;
@@ -1790,7 +1853,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 )
@@ -1866,7 +1929,7 @@ bool Document::CheckSwap()
       // i.e. a total of  136 bytes.
       entCur = deb + 136;
      
-      // group 0x0002 *is always* Explicit VR Sometimes ,
+      // group 0x0002 *is always* Explicit VR Sometimes,
       // even if elem 0002,0010 (Transfer Syntax) tells us the file is
       // *Implicit* VR  (see former 'gdcmData/icone.dcm')
       
@@ -1889,6 +1952,8 @@ bool Document::CheckSwap()
                         << "Looks like a bugged Header!");
       }
       
+      // Here, we assume that the file IS kosher Dicom !
+      // (The meta elements - group 0x0002 - ARE little endian !)
       if ( net2host )
       {
          SwapCode = 4321;
@@ -1904,6 +1969,7 @@ bool Document::CheckSwap()
       // (i.e. after the file preamble and the "DICM" string).
 
       Fp->seekg ( 132L, std::ios::beg); // Once per Document
+      CurrentOffsetPosition = 132;
       return true;
    } // ------------------------------- End of DicomV3 ----------------
 
@@ -1914,7 +1980,7 @@ bool Document::CheckSwap()
    gdcmWarningMacro( "Not a Kosher DICOM Version3 file (no preamble)");
 
    Fp->seekg(0, std::ios::beg); // Once per ACR-NEMA Document
-
+   CurrentOffsetPosition = 0;
    // Let's check 'No Preamble Dicom File' :
    // Should start with group 0x0002
    // and be Explicit Value Representation
@@ -1994,6 +2060,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 )
          {
@@ -2005,6 +2074,7 @@ bool Document::CheckSwap()
             case 0x0006 :
             case 0x0007 :
             case 0x0008 :
+            case 0x0028 :
                SwapCode = 1234;
                Filetype = ACR;
                return true;
@@ -2016,6 +2086,7 @@ bool Document::CheckSwap()
             case 0x0600 :
             case 0x0700 :
             case 0x0800 :
+            case 0x2800 :
                SwapCode = 4321;
                Filetype = ACR;
                return true;
@@ -2082,8 +2153,9 @@ DocEntry *Document::ReadNextDocEntry()
 {
    try
    {
-      CurrentGroup = ReadInt16();
-      CurrentElem  = ReadInt16();
+      ReadBegBuffer(8); // Avoid to many time consuming freads
+      //CurrentGroup = ReadInt16();
+      //CurrentElem  = ReadInt16();
    }
    catch ( FormatError )
    {
@@ -2091,7 +2163,10 @@ DocEntry *Document::ReadNextDocEntry()
       // header parsing has to be considered as finished.
       return 0;
    }
-
+   
+   CurrentGroup = GetInt16();
+   CurrentElem  = GetInt16();
+   
    // In 'true DICOM' files Group 0002 is always little endian
    if ( HasDCMPreamble )
    {
@@ -2158,8 +2233,8 @@ 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 (CurrentGroup != 0xfffe )
+         //if ( newEntry->GetGroup() != 0xfffe ) 
+         if (CurrentGroup != 0xfffe)
          { 
             int offset = Fp->tellg();//Only when heuristic for Explicit/Implicit was wrong
 
@@ -2182,7 +2257,6 @@ DocEntry *Document::ReadNextDocEntry()
    }
 
    newEntry->SetOffset(Fp->tellg());  // for each DocEntry
-   
    return newEntry;
 }
 
@@ -2194,6 +2268,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;
@@ -2266,9 +2357,13 @@ void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem)
       //
       // --> Probabely normal, since we considered we never have 
       // to trust manufacturers.
-      // (we find very often 'Implicit VR' tag, 
+      // (we often find 'Implicit VR' tag, 
       // even when Transfer Syntax tells us it's Explicit ...
       
+       // NEVER trust the meta elements!
+       // (see what ezDICOM does ...)
+             
+      /*
       if ( s ==  TS::ExplicitVRBigEndian )
       {
          gdcmDebugMacro("Transfer Syntax Name = [" 
@@ -2277,7 +2372,20 @@ void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem)
          group = SwapShort(group);
          elem  = SwapShort(elem);
       }
-
+      */
+    //-- Broken ACR  may start with a Shadow Group --
+    // worse : some ACR-NEMA like files start 00028 group ?!? 
+    if ( !( (group >= 0x0001 && group <= 0x0008) || group == 0x0028 ) )
+    {
+       // We trust what we see.
+       SwitchByteSwapCode();
+       group = SwapShort(group);
+       elem  = SwapShort(elem); 
+       // not what we where told (by meta elements) !
+       gdcmDebugMacro("Transfer Syntax Name = ["       
+                       << GetTransferSyntaxName() << "]" );         
+    }
+      
       /// \todo  find a trick to warn user and stop processing
             
       if ( s == TS::DeflatedExplicitVRLittleEndian)