]> Creatis software - gdcm.git/blobdiff - src/gdcmDocument.cxx
BUG: There was some duplicated code I didnt see. This fix D.Clunie problem I was...
[gdcm.git] / src / gdcmDocument.cxx
index 2bb417caf6d661b48c81fee68038ecf4138f3326..60b3e5a98b389d1c7ed8bebbe6046bfd11eb3171 100644 (file)
@@ -3,8 +3,8 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmDocument.cxx,v $
   Language:  C++
-  Date:      $Date: 2005/01/11 11:37:13 $
-  Version:   $Revision: 1.173 $
+  Date:      $Date: 2005/01/12 17:10:15 $
+  Version:   $Revision: 1.184 $
                                                                                 
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
 
 namespace gdcm 
 {
-//-----------------------------------------------------------------------------
-static const char *TransferSyntaxStrings[] =  {
-  // Implicit VR Little Endian
-  "1.2.840.10008.1.2",
-  // Implicit VR Big Endian DLX (G.E Private)
-  "1.2.840.113619.5.2",
-  // Explicit VR Little Endian
-  "1.2.840.10008.1.2.1",
-  // Deflated Explicit VR Little Endian
-  "1.2.840.10008.1.2.1.99",
-  // Explicit VR Big Endian
-  "1.2.840.10008.1.2.2",
-  // JPEG Baseline (Process 1)
-  "1.2.840.10008.1.2.4.50",
-  // JPEG Extended (Process 2 & 4)
-  "1.2.840.10008.1.2.4.51",
-  // JPEG Extended (Process 3 & 5)
-  "1.2.840.10008.1.2.4.52",
-  // JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8)
-  "1.2.840.10008.1.2.4.53",
-  // JPEG Full Progression, Non-Hierarchical (Process 10 & 12)
-  "1.2.840.10008.1.2.4.55",
-  // JPEG Lossless, Non-Hierarchical (Process 14)
-  "1.2.840.10008.1.2.4.57",
-  // JPEG Lossless, Hierarchical, First-Order Prediction (Process 14, [Selection Value 1])
-  "1.2.840.10008.1.2.4.70",
-  // JPEG 2000 Lossless
-  "1.2.840.10008.1.2.4.90",
-  // JPEG 2000
-  "1.2.840.10008.1.2.4.91",
-  // RLE Lossless
-  "1.2.840.10008.1.2.5",
-  // Unknown
-  "Unknown Transfer Syntax"
-};
 
 //-----------------------------------------------------------------------------
 // Refer to Document::CheckSwap()
@@ -115,6 +80,7 @@ Document::Document( std::string const &filename ) : ElementSet(-1)
    long lgt = Fp->tellg();
            
    Fp->seekg( 0,  std::ios::beg);
+
    CheckSwap();
    long beg = Fp->tellg();
    lgt -= beg;
@@ -136,7 +102,7 @@ Document::Document( std::string const &filename ) : ElementSet(-1)
       /// lines state that the corresponding tag contents are in fact
       /// the ones of a BinEntry.
       /// In order to fix things "Quick and Dirty" the dictionnary was
-      /// altered on PURPOUS but now contains a WRONG value.
+      /// altered on PURPOSE but now contains a WRONG value.
       /// In order to fix things and restore the dictionary to its
       /// correct value, one needs to decided of the semantics by deciding
       /// wether the following tags are either:
@@ -195,7 +161,7 @@ Document::Document() : ElementSet(-1)
 
    SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
    Initialise();
-   SwapCode = 0;
+   SwapCode = 1234;
    Filetype = ExplicitVR;
    Group0002Parsed = false;
 }
@@ -304,12 +270,12 @@ bool Document::IsReadable()
  *          value from disk when only parsing occured).
  * @return  The encountered Transfer Syntax of the current document.
  */
-TransferSyntaxType Document::GetTransferSyntax()
+std::string Document::GetTransferSyntax()
 {
    DocEntry *entry = GetDocEntry(0x0002, 0x0010);
    if ( !entry )
    {
-      return UnknownTS;
+      return GDCM_UNKNOWN;
    }
 
    // The entry might be present but not loaded (parsing and loading
@@ -324,68 +290,15 @@ TransferSyntaxType Document::GetTransferSyntax()
       if  ( transfer.length() == 0 )
       {
          // for brain damaged headers
-         return UnknownTS;
+         return GDCM_UNKNOWN;
       }
       while ( !isdigit((unsigned char)transfer[transfer.length()-1]) )
       {
          transfer.erase(transfer.length()-1, 1);
       }
-      for (int i = 0; TransferSyntaxStrings[i] != NULL; i++)
-      {
-         if ( TransferSyntaxStrings[i] == transfer )
-         {
-            return TransferSyntaxType(i);
-         }
-      }
+      return transfer;
    }
-   return UnknownTS;
-}
-
-bool Document::IsJPEGLossless()
-{
-   TransferSyntaxType r = GetTransferSyntax();
-   return    r ==  JPEGFullProgressionProcess10_12
-          || r == JPEGLosslessProcess14
-          || r == JPEGLosslessProcess14_1;
-}
-                                                                                
-/**
- * \brief   Determines if the Transfer Syntax was already encountered
- *          and if it corresponds to a JPEG2000 one
- * @return  True when JPEG2000 (Lossly or LossLess) found. False in all
- *          other cases.
- */
-bool Document::IsJPEG2000()
-{
-   TransferSyntaxType r = GetTransferSyntax();
-   return r == JPEG2000Lossless || r == JPEG2000;
-}
-
-/**
- * \brief   Determines if the Transfer Syntax corresponds to any form
- *          of Jpeg encoded Pixel data.
- * @return  True when any form of JPEG found. False otherwise.
- */
-bool Document::IsJPEG()
-{
-   TransferSyntaxType r = GetTransferSyntax();
-   return r == JPEGBaselineProcess1 
-     || r == JPEGExtendedProcess2_4
-     || r == JPEGExtendedProcess3_5
-     || r == JPEGSpectralSelectionProcess6_8
-     ||      IsJPEGLossless()
-     ||      IsJPEG2000();
-}
-
-/**
- * \brief   Determines if the Transfer Syntax corresponds to encapsulated
- *          of encoded Pixel Data (as opposed to native).
- * @return  True when encapsulated. False when native.
- */
-bool Document::IsEncapsulate()
-{
-   TransferSyntaxType r = GetTransferSyntax();
-   return IsJPEG() || r == RLELossless;
+   return GDCM_UNKNOWN;
 }
 
 /**
@@ -739,11 +652,6 @@ bool Document::ReplaceIfExist(std::string const &value,
    return true;
 } 
 
-std::string Document::GetTransferSyntaxValue(TransferSyntaxType type)
-{
-   return TransferSyntaxStrings[type];
-}
-
 //-----------------------------------------------------------------------------
 // Protected
 
@@ -1103,20 +1011,18 @@ uint32_t Document::SwapLong(uint32_t a)
 {
    switch (SwapCode)
    {
-      case    0 :
+      case 1234 :
          break;
       case 4321 :
          a=( ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000) | 
              ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
-         break;
-   
+         break;   
       case 3412 :
          a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
-         break;
-   
+         break;  
       case 2143 :
          a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
-         break;
+      break;
       default :
          gdcmErrorMacro( "Unset swap code:" << SwapCode );
          a = 0;
@@ -1199,7 +1105,9 @@ void Document::ParseDES(DocEntrySet *set, long offset,
             if ( ! Global::GetVR()->IsVROfBinaryRepresentable(vr) )
             { 
                 ////// Neither ValEntry NOR BinEntry: should mean UNKOWN VR
-                gdcmVerboseMacro( "Neither Valentry, nor BinEntry." 
+                gdcmVerboseMacro( std::hex << newDocEntry->GetGroup() 
+                                  << "|" << newDocEntry->GetElement()
+                                  << " : Neither Valentry, nor BinEntry." 
                                   "Probably unknown VR.");
             }
 
@@ -1273,15 +1181,15 @@ void Document::ParseDES(DocEntrySet *set, long offset,
          if (    ( newDocEntry->GetGroup()   == 0x7fe0 )
               && ( newDocEntry->GetElement() == 0x0010 ) )
          {
-             TransferSyntaxType ts = GetTransferSyntax();
-             if ( ts == RLELossless ) 
+             std::string ts = GetTransferSyntax();
+             if ( Global::GetTS()->IsRLELossless(ts) ) 
              {
                 long positionOnEntry = Fp->tellg();
                 Fp->seekg( newDocEntry->GetOffset(), std::ios::beg );
                 ComputeRLEInfo();
                 Fp->seekg( positionOnEntry, std::ios::beg );
              }
-             else if ( IsJPEG() )
+             else if ( Global::GetTS()->IsJPEG(ts) )
              {
                 long positionOnEntry = Fp->tellg();
                 Fp->seekg( newDocEntry->GetOffset(), std::ios::beg );
@@ -1321,7 +1229,7 @@ void Document::ParseDES(DocEntrySet *set, long offset,
             newSeqEntry->SetDepthLevel( 1 );
             newSeqEntry->SetKey( newSeqEntry->GetKey() );
          }
-         // But when "set" is allready a SQItem, we are building a nested
+         // But when "set" is already a SQItem, we are building a nested
          // sequence, and hence the depth level of the new SeqEntry
          // we are building, is one level deeper:
          if (SQItem *parentSQItem = dynamic_cast< SQItem* > ( set ) )
@@ -1639,6 +1547,14 @@ void Document::FindDocEntryLength( DocEntry *entry )
 
       // Length is encoded on 2 bytes.
       length16 = ReadInt16();
+
+      // FIXME : This heuristic supposes that the first group following
+      //         group 0002 *has* and element 0000.
+      // BUT ... Element 0000 is optionnal :-(
+
+
+   // Fixed using : HandleOutOfGroup0002()
+   //              (first hereafter strategy ...)
       
       // We can tell the current file is encoded in big endian (like
       // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag
@@ -1659,6 +1575,8 @@ void Document::FindDocEntryLength( DocEntry *entry )
       //   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.
+      //---> Unfortunately, element 0000 is optional.
+      //---> This will not work when missing!
       // 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
@@ -1667,37 +1585,40 @@ void Document::FindDocEntryLength( DocEntry *entry )
       // 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 ) 
-      {
-         TransferSyntaxType ts = GetTransferSyntax();
-         if ( ts != ExplicitVRBigEndian ) 
-         {
-            throw FormatError( "Document::FindDocEntryLength()",
-                               " not explicit VR." );
-            return;
-         }
-         length16 = 4;
-         SwitchByteSwapCode();
+
+ //
+ //     if ( element  == 0x0000 && length16 == 0x0400 ) 
+ //     {
+ //        std::string ts = GetTransferSyntax();
+ //        if ( Global::GetTS()->GetSpecialTransferSyntax(ts) 
+ //               != TS::ExplicitVRBigEndian ) 
+ //        {
+ //           throw FormatError( "Document::FindDocEntryLength()",
+ //                              " not explicit VR." );
+ //          return;
+ //       }
+ //       length16 = 4;
+ //       SwitchByteSwapCode();
 
          // Restore the unproperly loaded values i.e. the group, the element
          // and the dictionary entry depending on them.
-         uint16_t correctGroup = SwapShort( entry->GetGroup() );
-         uint16_t correctElem  = SwapShort( entry->GetElement() );
-         DictEntry *newTag = GetDictEntry( correctGroup, correctElem );
-         if ( !newTag )
-         {
+//        uint16_t correctGroup = SwapShort( entry->GetGroup() );
+//         uint16_t correctElem  = SwapShort( entry->GetElement() );
+//         DictEntry *newTag = GetDictEntry( correctGroup, correctElem );         if ( !newTag )
+//         {
             // This correct tag is not in the dictionary. Create a new one.
-            newTag = NewVirtualDictEntry(correctGroup, correctElem);
-         }
+//            newTag = NewVirtualDictEntry(correctGroup, correctElem);
+//         }
          // FIXME this can create a memory leaks on the old entry that be
          // left unreferenced.
-         entry->SetDictEntry( newTag );
-      }
-       
-      // Heuristic: well, some files are really ill-formed.
+//         entry->SetDictEntry( newTag );
+//      }
+
+  
+      // 0xffff means that we deal with 'No Length' Sequence 
+      //        or 'No Length' SQItem
       if ( length16 == 0xffff) 
-      {
-         // 0xffff means that we deal with 'Unknown Length' Sequence  
+      {           
          length16 = 0;
       }
       FixDocEntryFoundLength( entry, (uint32_t)length16 );
@@ -2200,25 +2121,24 @@ bool Document::CheckSwap()
       net2host = false;
    }
          
-   // The easiest case is the one of a DICOM header, since it possesses a
-   // file preamble where it suffice to look for the string "DICM".
+   // The easiest case is the one of a 'true' DICOM header, we just have
+   // to look for the string "DICM" inside the file preamble.
    Fp->read(deb, 256);
    
    char *entCur = deb + 128;
    if( memcmp(entCur, "DICM", (size_t)4) == 0 )
    {
-      gdcmVerboseMacro( "Looks like DICOM Version3" );
+      gdcmVerboseMacro( "Looks like DICOM Version3 (preamble + DCM)" );
       
-      // Next, determine the value representation (VR). Let's skip to the
-      // first element (0002, 0000) and check there if we find "UL" 
-      // - or "OB" if the 1st one is (0002,0001) -,
+      // Group 0002 should always be VR, and the first element 0000
+      // Let's be carefull (so many wrong headers ...)
+      // and determine the value representation (VR) : 
+      // Let's skip to the first element (0002,0000) and check there if we find
+      // "UL"  - or "OB" if the 1st one is (0002,0001) -,
       // in which case we (almost) know it is explicit VR.
       // WARNING: if it happens to be implicit VR then what we will read
       // is the length of the group. If this ascii representation of this
       // length happens to be "UL" then we shall believe it is explicit VR.
-      // FIXME: in order to fix the above warning, we could read the next
-      // element value (or a couple of elements values) in order to make
-      // sure we are not commiting a big mistake.
       // We need to skip :
       // * the 128 bytes of File Preamble (often padded with zeroes),
       // * the 4 bytes of "DICM" string,
@@ -2226,27 +2146,27 @@ bool Document::CheckSwap()
       // i.e. a total of  136 bytes.
       entCur = deb + 136;
      
-      // FIXME : FIXME:
-      // Sometimes (see : gdcmData/icone.dcm) group 0x0002 *is* Explicit VR,
-      // but elem 0002,0010 (Transfer Syntax) tells us the file is
-      // *Implicit* VR.  -and it is !- 
+      // 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')
       
       if( memcmp(entCur, "UL", (size_t)2) == 0 ||
           memcmp(entCur, "OB", (size_t)2) == 0 ||
           memcmp(entCur, "UI", (size_t)2) == 0 ||
           memcmp(entCur, "CS", (size_t)2) == 0 )  // CS, to remove later
-                                                    // when Write DCM *adds*
+                                                  // when Write DCM *adds*
       // FIXME
       // Use Document::dicom_vr to test all the possibilities
       // instead of just checking for UL, OB and UI !? group 0000 
       {
          Filetype = ExplicitVR;
-         gdcmVerboseMacro( "Explicit Value Representation");
+         gdcmVerboseMacro( "Group 0002 : Explicit Value Representation");
       } 
       else 
       {
          Filetype = ImplicitVR;
-         gdcmVerboseMacro( "Not an explicit Value Representation");
+         gdcmVerboseMacro( "Group 0002 :Not an explicit Value Representation;"
+                        << "Looks like a bugged Header!");
       }
       
       if ( net2host )
@@ -2256,12 +2176,12 @@ bool Document::CheckSwap()
       }
       else 
       {
-         SwapCode = 0;
+         SwapCode = 1234;
          gdcmVerboseMacro( "HostByteOrder = NetworkByteOrder");
       }
       
-      // Position the file position indicator at first tag (i.e.
-      // after the file preamble and the "DICM" string).
+      // Position the file position indicator at first tag 
+      // (i.e. after the file preamble and the "DICM" string).
       Fp->seekg(0, std::ios::beg);
       Fp->seekg ( 132L, std::ios::beg);
       return true;
@@ -2299,7 +2219,7 @@ bool Document::CheckSwap()
          Filetype = ACR;
          return true;
       case 0x00000004 :
-         SwapCode = 0;
+         SwapCode = 1234;
          Filetype = ACR;
          return true;
       default :
@@ -2330,7 +2250,7 @@ bool Document::CheckSwap()
             case 0x0006 :
             case 0x0007 :
             case 0x0008 :
-               SwapCode = 0;
+               SwapCode = 1234;
                Filetype = ACR;
                return true;
             case 0x0100 :
@@ -2349,12 +2269,6 @@ bool Document::CheckSwap()
                Filetype = Unknown;
                return false;
          }
-         // Then the only info we have is the net2host one.
-         //if (! net2host )
-         //   SwapCode = 0;
-         //else
-         //  SwapCode = 4321;
-         //return;
    }
 }
 
@@ -2365,14 +2279,14 @@ bool Document::CheckSwap()
  */
 void Document::SwitchByteSwapCode() 
 {
-   gdcmVerboseMacro( "Switching Byte Swap code.");
-   if ( SwapCode == 0    ) 
+   gdcmVerboseMacro( "Switching Byte Swap code from "<< SwapCode);
+   if ( SwapCode == 1234 ) 
    {
       SwapCode = 4321;
    }
    else if ( SwapCode == 4321 ) 
    {
-      SwapCode = 0;
+      SwapCode = 1234;
    }
    else if ( SwapCode == 3412 ) 
    {
@@ -2431,7 +2345,7 @@ void Document::SetMaxSizePrintEntry(long newSize)
  *          apparent reason
  * @return  no return
  */
-void Document::HandleBrokenEndian(uint16_t group, uint16_t elem)
+void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem)
 {
    // Endian reversion. Some files contain groups of tags with reversed endianess.
    static int reversedEndian = 0;
@@ -2453,6 +2367,35 @@ void Document::HandleBrokenEndian(uint16_t group, uint16_t elem)
    }
 }
 
+/**
+ * \brief Accesses the info from 0002,0010 : Transfer Syntax and TS
+ *        else 1.
+ * @return The full Transfer Syntax Name (as opposed to Transfer Syntax UID)
+ */
+std::string Document::GetTransferSyntaxName()
+{
+   // use the TS (TS : Transfer Syntax)
+   std::string transferSyntax = GetEntry(0x0002,0x0010);
+
+   if ( (transferSyntax.find(GDCM_NOTLOADED) < transferSyntax.length()) )
+   {
+      gdcmErrorMacro( "Transfer Syntax not loaded. " << std::endl
+               << "Better you increase MAX_SIZE_LOAD_ELEMENT_VALUE" );
+      return "Uncompressed ACR-NEMA";
+   }
+   if ( transferSyntax == GDCM_UNFOUND )
+   {
+      gdcmVerboseMacro( "Unfound Transfer Syntax (0002,0010)");
+      return "Uncompressed ACR-NEMA";
+   }
+
+   // we do it only when we need it
+   const TSKey &tsName = Global::GetTS()->GetValue( transferSyntax );
+
+   // Global::GetTS() is a global static you shall never try to delete it!
+   return tsName;
+}
+
 /**
  * \brief   Group 0002 is always coded Little Endian
  *          whatever Transfer Syntax is
@@ -2464,25 +2407,24 @@ void Document::HandleOutOfGroup0002(uint16_t group)
    if ( !Group0002Parsed && group != 0x0002)
    {
       Group0002Parsed = true;
-     // we just came out of group 0002
-     // if Transfer syntax is Big Endian we have to change CheckSwap
+      // we just came out of group 0002
+      // if Transfer syntax is Big Endian we have to change CheckSwap
 
-      TagKey key = DictEntry::TranslateToKey(0x0002, 0x0010);
-      if ( !TagHT.count(key))
+      std::string ts = GetTransferSyntax();
+      if ( !Global::GetTS()->IsTransferSyntax(ts) )
       {
-         gdcmVerboseMacro("True DICOM File, with NO Tansfer Syntax ?!?");
+         gdcmVerboseMacro("True DICOM File, with NO Tansfer Syntax: " << ts );
          return;
       }
 
-   // FIXME Strangely, this works with 
-   //'Implicit VR Transfer Syntax (GE Private)
-
-       if ( ((ValEntry *)TagHT.find(key)->second)->GetValue()
-               == "Explicit VR - Big Endian" )
-       {
-          gdcmVerboseMacro("Tansfer Syntax = Explicit VR - Big Endian");
-          SwitchByteSwapCode();
-        }
+      // FIXME Strangely, this works with 
+      //'Implicit VR Transfer Syntax (GE Private)
+      if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian )
+      {
+         gdcmVerboseMacro("Transfer Syntax Name = [" 
+                        << GetTransferSyntaxName() << "]" );
+         SwitchByteSwapCode();
+      }
    }
 }
 
@@ -2514,7 +2456,7 @@ DocEntry *Document::ReadNextDocEntry()
    // Sometimes file contains groups of tags with reversed endianess.
    HandleBrokenEndian(group, elem);
 
-// In 'true DICOM' files Group 0002 is allways little endian
+// In 'true DICOM' files Group 0002 is always little endian
    if ( HasDCMPreamble )
       HandleOutOfGroup0002(group);
  
@@ -2626,10 +2568,7 @@ bool Document::ReadTag(uint16_t testGroup, uint16_t testElement)
        << std::hex << testGroup << "," << testElement << ")" << std::endl
        << "   but instead we encountered tag ("
        << std::hex << itemTagGroup << "," << itemTagElement << ")"
-       << std::dec
-       << "  at address: " << (unsigned int)currentPosition 
-       << std::hex 
-       << "  0x(" << (unsigned int)currentPosition  << ")" 
+       << "  at address: " << "  0x(" << (unsigned int)currentPosition  << ")" 
        ) ;
       Fp->seekg(positionOnEntry, std::ios::beg);
 
@@ -2668,7 +2607,7 @@ uint32_t Document::ReadTagLength(uint16_t testGroup, uint16_t testElement)
    {
       gdcmVerboseMacro( "Basic Item Length is: "
         << itemLength << std::endl
-        << "  at address: " << (unsigned int)currentPosition);
+        << "  at address: " << std::hex << (unsigned int)currentPosition);
    }
    return itemLength;
 }
@@ -2714,8 +2653,8 @@ void Document::ReadAndSkipEncapsulatedBasicOffsetTable()
  */
 void Document::ComputeRLEInfo()
 {
-   TransferSyntaxType ts = GetTransferSyntax();
-   if ( ts != RLELossless )
+   std::string ts = GetTransferSyntax();
+   if ( !Global::GetTS()->IsRLELossless(ts) ) 
    {
       return;
    }
@@ -2812,7 +2751,8 @@ void Document::ComputeRLEInfo()
 void Document::ComputeJPEGFragmentInfo()
 {
    // If you need to, look for comments of ComputeRLEInfo().
-   if ( ! IsJPEG() )
+   std::string ts = GetTransferSyntax();
+   if ( ! Global::GetTS()->IsJPEG(ts) )
    {
       return;
    }