]> Creatis software - gdcm.git/blobdiff - src/gdcmDocument.cxx
- now, DicomDir stuff stakes into account the 'new' structure
[gdcm.git] / src / gdcmDocument.cxx
index 36d1703c4d4548d6973ea45e747ad937fa2323db..37966499bb038759d5d188a47fce182a6a0f29ab 100644 (file)
@@ -3,8 +3,8 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmDocument.cxx,v $
   Language:  C++
-  Date:      $Date: 2004/08/01 03:20:23 $
-  Version:   $Revision: 1.63 $
+  Date:      $Date: 2004/08/26 15:29:53 $
+  Version:   $Revision: 1.68 $
                                                                                 
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
@@ -25,7 +25,6 @@
 #include "gdcmUtil.h"
 #include "gdcmDebug.h"
 
-#include <errno.h>
 #include <vector>
 
 // For nthos:
@@ -83,21 +82,19 @@ const unsigned int gdcmDocument::MAX_SIZE_PRINT_ELEMENT_VALUE = 0x7fffffff;
 /**
  * \brief   constructor  
  * @param   inFilename file to be opened for parsing
- * @param   exception_on_error whether we throw an exception or not
  */
-gdcmDocument::gdcmDocument( std::string const & filename, 
-                            bool exception_on_error) 
+gdcmDocument::gdcmDocument( std::string const & filename ) 
               : gdcmElementSet(-1)
 {
    SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE); 
    Filename = filename;
    Initialise();
 
-   if ( !OpenFile(exception_on_error))
+   if ( !OpenFile()
    {
       return;
    }
-   
+
    dbg.Verbose(0, "gdcmDocument::gdcmDocument: starting parsing of file: ",
                   Filename.c_str());
    rewind(Fp);
@@ -137,7 +134,11 @@ gdcmDocument::gdcmDocument( std::string const & filename,
    CloseFile(); 
   
    // --------------------------------------------------------------
-   // Special Patch to allow gdcm to read ACR-LibIDO formated images
+   // Specific code to allow gdcm to read ACR-LibIDO formated images
+   // Note: ACR-LibIDO is an extension of the ACR standard that was
+   //       used at CREATIS. For the time being (say a couple years)
+   //       we keep this kludge to allow a smooth move to gdcm for
+   //       CREATIS developpers (sorry folks).
    //
    // if recognition code tells us we deal with a LibIDO image
    // we switch lineNumber and columnNumber
@@ -154,23 +155,20 @@ gdcmDocument::gdcmDocument( std::string const & filename,
          SetEntryByNumber(columns, 0x0028, 0x0010);
          SetEntryByNumber(rows   , 0x0028, 0x0011);
    }
-   // ----------------- End of Special Patch ---------------- 
+   // ----------------- End of ACR-LibIDO kludge ------------------ 
 
    PrintLevel = 1;  // 'Medium' print level by default
 }
 
 /**
- * \brief  constructor 
- * @param   exception_on_error
+ * \brief This default constructor doesn't parse the file. You should
+ *        then invoke \ref gdcmDocument::SetFileName and then the parsing.
  */
-gdcmDocument::gdcmDocument(bool exception_on_error
+gdcmDocument::gdcmDocument() 
              :gdcmElementSet(-1)
 {
-   (void)exception_on_error;
-
    SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
    Initialise();
-
    PrintLevel = 1;  // 'Medium' print level by default
 }
 
@@ -262,8 +260,6 @@ bool gdcmDocument::IsReadable()
 {
    if( Filetype == gdcmUnknown)
    {
-      std::cout << " gdcmDocument::IsReadable: Filetype " << Filetype
-               << " " << "gdcmUnknown " << gdcmUnknown << std::endl; //JPR
       dbg.Verbose(0, "gdcmDocument::IsReadable: wrong filetype");
       return false;
    }
@@ -463,58 +459,46 @@ FileType gdcmDocument::GetFileType()
 }
 
 /**
- * \brief   opens the file
- * @param   exception_on_error
- * @return  
+ * \brief  Tries to open the file \ref gdcmDocument::Filename and
+ *         checks the preamble when existing.
+ * @return The FILE pointer on success. 
  */
-FILE *gdcmDocument::OpenFile(bool exception_on_error)
-  throw(gdcmFileError) 
+FILE* gdcmDocument::OpenFile()
 {
-  Fp = fopen(Filename.c_str(),"rb");
+   Fp = fopen(Filename.c_str(),"rb");
 
-  if(!Fp)
-  {
-     if(exception_on_error)
-     {
-        throw gdcmFileError("gdcmDocument::gdcmDocument(const char *, bool)");
-     }
-     else
-     {
-        dbg.Verbose(0, "gdcmDocument::OpenFile cannot open file: ",
-                    Filename.c_str());
-        return NULL;
-     }
-  }
-
-  if ( Fp )
-  {
-     uint16_t zero;
-     fread(&zero,  (size_t)2, (size_t)1, Fp);
-
-    //ACR -- or DICOM with no Preamble --
-    if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200 )
-    {
-       return Fp;
-    }
-
-    //DICOM
-    fseek(Fp, 126L, SEEK_CUR);
-    char dicm[4];
-    fread(dicm,  (size_t)4, (size_t)1, Fp);
-    if( memcmp(dicm, "DICM", 4) == 0 )
-    {
-       return Fp;
-    }
-
-    fclose(Fp);
-    dbg.Verbose(0, "gdcmDocument::OpenFile not DICOM/ACR", Filename.c_str());
-  }
-  else
-  {
-    dbg.Verbose(0, "gdcmDocument::OpenFile cannot open file", Filename.c_str());
-  }
-
-  return 0;
+   if(!Fp)
+   {
+      dbg.Verbose( 0,
+                   "gdcmDocument::OpenFile cannot open file: ",
+                   Filename.c_str());
+      return 0;
+   }
+   uint16_t zero;
+   fread(&zero,  (size_t)2, (size_t)1, Fp);
+   //ACR -- or DICOM with no Preamble --
+   if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200 )
+   {
+      return Fp;
+   }
+   //DICOM
+   fseek(Fp, 126L, SEEK_CUR);
+   char dicm[4];
+   fread(dicm,  (size_t)4, (size_t)1, Fp);
+   if( memcmp(dicm, "DICM", 4) == 0 )
+   {
+      return Fp;
+   }
+   fclose(Fp);
+   dbg.Verbose( 0,
+                "gdcmDocument::OpenFile not DICOM/ACR (missing preamble)",
+                Filename.c_str());
+   return 0;
 }
 
 /**
@@ -685,6 +669,35 @@ gdcmBinEntry * gdcmDocument::ReplaceOrCreateByNumber(
    return b;
 }  
 
+
+/*
+ * \brief   Modifies the value of a given Header Entry (Dicom Element)
+ *          when it exists. Create it when unexistant.
+ * @param   Group   Group number of the Entry 
+ * @param   Elem  Element number of the Entry
+ * \return  pointer to the modified/created SeqEntry (NULL when creation
+ *          failed).
+ */
+gdcmSeqEntry * gdcmDocument::ReplaceOrCreateByNumber(
+                                         uint16_t group, 
+                                         uint16_t elem)
+{
+   gdcmSeqEntry* b = 0;
+   gdcmDocEntry* a = GetDocEntryByNumber( group, elem);
+   if (!a)
+   {
+      a = NewSeqEntryByNumber(group, elem);
+      if (!a)
+      {
+         return 0;
+      }
+
+      b = new gdcmSeqEntry(a, 1); // FIXME : 1 (Depth)
+      AddEntry(b);
+   }   
+   return b;
+} 
 /**
  * \brief Set a new value if the invoked element exists
  *        Seems to be useless !!!
@@ -1221,7 +1234,7 @@ uint32_t gdcmDocument::SwapLong(uint32_t a)
          a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
          break;
       default :
-         std::cout << "swapCode= " << SwapCode << std::endl;
+         //std::cout << "swapCode= " << SwapCode << std::endl;
          dbg.Error(" gdcmDocument::SwapLong : unset swap code");
          a = 0;
    }
@@ -1386,7 +1399,6 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
       }
       delete newDocEntry;
    }
-
    return l; // Probably useless 
 }
 
@@ -1499,8 +1511,12 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry)
       }
       // to be sure we are at the end of the value ...
       fseek(Fp, (long)entry->GetOffset()+(long)entry->GetLength(), SEEK_SET);      
-
-      return;  //FIXME FIXME FIXME FIXME ????
+      // Following return introduced by JPR on version 1.25. Since the 
+      // treatement of a ValEntry is never executed (doh!) this means
+      // we were lucky up to now because we NEVER encountered a ValEntry
+      // whose length was bigger thant MaxSizeLoadEntry !? I can't believe
+      // this could ever work...
+      return;  //FIXME FIXME FIXME FIXME JPR ????
 
        // Be carefull : a BinEntry IS_A ValEntry ... 
       if (gdcmValEntry* valEntryPtr = dynamic_cast< gdcmValEntry* >(entry) )
@@ -1531,7 +1547,7 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry)
    if ( IsDocEntryAnInteger(entry) )
    {   
       uint32_t NewInt;
-      std::ostringstream s;
+      //std::ostringstream s; //shadow previous declaration
       int nbInt;
       // When short integer(s) are expected, read and convert the following 
       // n *two characters properly i.e. consider them as short integers as
@@ -1618,12 +1634,12 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry)
  * \brief  Find the value Length of the passed Header Entry
  * @param  Entry Header Entry whose length of the value shall be loaded. 
  */
-void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry)
+void gdcmDocument::FindDocEntryLength( gdcmDocEntry *entry )
+   throw ( gdcmFormatError )
 {
    uint16_t element = entry->GetElement();
    std::string  vr  = entry->GetVR();
-   uint16_t length16;
-       
+   uint16_t length16;       
    
    if ( Filetype == gdcmExplicitVR && !entry->IsImplicitVR() ) 
    {
@@ -1637,8 +1653,12 @@ void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry)
 
          if ( vr == "OB" && length32 == 0xffffffff ) 
          {
-            uint32_t lengthOB = FindDocEntryLengthOB();
-            if ( errno == 1 )
+            uint32_t lengthOB;
+            try 
+            {
+               lengthOB = FindDocEntryLengthOB();
+            }
+            catch ( gdcmFormatUnexpected )
             {
                // Computing the length failed (this happens with broken
                // files like gdcm-JPEG-LossLess3a.dcm). We still have a
@@ -1650,7 +1670,6 @@ void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry)
                long lengthUntilEOF = ftell(Fp) - currentPosition;
                fseek(Fp, currentPosition, SEEK_SET);
                entry->SetLength(lengthUntilEOF);
-               errno = 0;
                return;
             }
             entry->SetLength(lengthOB);
@@ -1694,8 +1713,8 @@ void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry)
       {
          if ( !IsExplicitVRBigEndianTransferSyntax() ) 
          {
-            dbg.Verbose(0, "gdcmDocument::FindLength", "not explicit VR");
-            errno = 1;
+            throw gdcmFormatError( "gdcmDocument::FindDocEntryLength()",
+                                   " not explicit VR." );
             return;
          }
          length16 = 4;
@@ -1719,11 +1738,10 @@ void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry)
       // Heuristic: well, some files are really ill-formed.
       if ( length16 == 0xffff) 
       {
+         // 0xffff means that we deal with 'Unknown Length' Sequence  
          length16 = 0;
-         // Length16= 0xffff means that we deal with
-         // 'Unknown Length' Sequence  
       }
-      FixDocEntryFoundLength(entry, (uint32_t)length16);
+      FixDocEntryFoundLength( entry, (uint32_t)length16 );
       return;
    }
    else
@@ -1735,7 +1753,7 @@ void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry)
       // not coexist in a Data Set and Data Sets nested within it".]
       // Length is on 4 bytes.
       
-      FixDocEntryFoundLength(entry, ReadInt32());
+      FixDocEntryFoundLength( entry, ReadInt32() );
       return;
    }
 }
@@ -2150,6 +2168,7 @@ bool gdcmDocument::IsDocEntryAnInteger(gdcmDocEntry *entry)
  */
 
 uint32_t gdcmDocument::FindDocEntryLengthOB()
+   throw( gdcmFormatUnexpected )
 {
    // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
    long positionOnEntry = ftell(Fp);
@@ -2158,26 +2177,33 @@ uint32_t gdcmDocument::FindDocEntryLengthOB()
 
    while ( !foundSequenceDelimiter )
    {
-      uint16_t g = ReadInt16();
-      uint16_t n = ReadInt16();   
-      if ( errno == 1 )
+      uint16_t group;
+      uint16_t elem;
+      try
       {
-         return 0;
+         group = ReadInt16();
+         elem  = ReadInt16();   
+      }
+      catch ( gdcmFormatError )
+      {
+         throw gdcmFormatError("gdcmDocument::FindDocEntryLengthOB()",
+                               " group or element not present.");
       }
 
       // We have to decount the group and element we just read
       totalLength += 4;
      
-      if ( g != 0xfffe || ( n != 0xe0dd && n != 0xe000 ) )
+      if ( group != 0xfffe || ( ( elem != 0xe0dd ) && ( elem != 0xe000 ) ) )
       {
-         dbg.Verbose(1, "gdcmDocument::FindLengthOB: neither an Item tag "
-                        "nor a Sequence delimiter tag."); 
+         dbg.Verbose(1, "gdcmDocument::FindDocEntryLengthOB: neither an Item "
+                        "tag nor a Sequence delimiter tag."); 
          fseek(Fp, positionOnEntry, SEEK_SET);
-         errno = 1;
-         return 0;
+         throw gdcmFormatUnexpected("gdcmDocument::FindDocEntryLengthOB()",
+                                    "Neither an Item tag nor a Sequence "
+                                    "delimiter tag.");
       }
 
-      if ( n == 0xe0dd )
+      if ( elem == 0xe0dd )
       {
          foundSequenceDelimiter = true;
       }
@@ -2202,6 +2228,7 @@ uint32_t gdcmDocument::FindDocEntryLengthOB()
  * @return read value
  */
 uint16_t gdcmDocument::ReadInt16()
+   throw( gdcmFormatError )
 {
    uint16_t g;
    size_t item_read = fread (&g, (size_t)2,(size_t)1, Fp);
@@ -2209,12 +2236,10 @@ uint16_t gdcmDocument::ReadInt16()
    {
       if( ferror(Fp) )
       {
-         dbg.Verbose(0, "gdcmDocument::ReadInt16", " File Error");
+         throw gdcmFormatError( "gdcmDocument::ReadInt16()", " file error." );
       }
-      errno = 1;
-      return 0;
+      throw gdcmFormatError( "gdcmDocument::ReadInt16()", "EOF." );
    }
-   errno = 0;
    g = SwapShort(g); 
    return g;
 }
@@ -2225,6 +2250,7 @@ uint16_t gdcmDocument::ReadInt16()
  * @return read value
  */
 uint32_t gdcmDocument::ReadInt32()
+   throw( gdcmFormatError )
 {
    uint32_t g;
    size_t item_read = fread (&g, (size_t)4,(size_t)1, Fp);
@@ -2232,12 +2258,10 @@ uint32_t gdcmDocument::ReadInt32()
    {
       if( ferror(Fp) )
       {
-         dbg.Verbose(0, "gdcmDocument::ReadInt32", " File Error");
+         throw gdcmFormatError( "gdcmDocument::ReadInt16()", " file error." );
       }
-      errno = 1;
-      return 0;
+      throw gdcmFormatError( "gdcmDocument::ReadInt32()", "EOF." );
    }
-   errno = 0;
    g = SwapLong(g);
    return g;
 }
@@ -2524,28 +2548,39 @@ void gdcmDocument::SetMaxSizePrintEntry(long newSize)
  *          gets the VR, gets the length, gets the offset value)
  * @return  On succes the newly created DocEntry, NULL on failure.      
  */
-gdcmDocEntry *gdcmDocument::ReadNextDocEntry()
+gdcmDocEntrygdcmDocument::ReadNextDocEntry()
 {
-   uint16_t g = ReadInt16();
-   uint16_t n = ReadInt16();
+   uint16_t group;
+   uint16_t elem;
 
-   if (errno == 1)
+   try
+   {
+      group = ReadInt16();
+      elem  = ReadInt16();
+   }
+   catch ( gdcmFormatError e )
    {
       // We reached the EOF (or an error occured) therefore 
       // header parsing has to be considered as finished.
+      //std::cout << e;
       return 0;
    }
-   gdcmDocEntry *newEntry = NewDocEntryByNumber(g, n);
 
+   gdcmDocEntry *newEntry = NewDocEntryByNumber(group, elem);
    FindDocEntryVR(newEntry);
-   FindDocEntryLength(newEntry);
 
-   if (errno == 1)
+   try
+   {
+      FindDocEntryLength(newEntry);
+   }
+   catch ( gdcmFormatError e )
    {
       // Call it quits
+      //std::cout << e;
       delete newEntry;
       return 0;
    }
+
    newEntry->SetOffset(ftell(Fp));  
 
    return newEntry;