]> Creatis software - gdcm.git/blobdiff - src/gdcmParser.cxx
comments added
[gdcm.git] / src / gdcmParser.cxx
index b442206bc19ab9498087475d8ec9b1901a8b0b6d..70c859fdf0f018b68d9640a99e7a75e8f6789052 100644 (file)
    // DL       Delimiters
    //
 
+   // Other usefull abreviations :
+   //Radiographic view associated with Patient Position (0018,5100).
+   //  Defined Terms:
+   // 
+   //  AP = Anterior/Posterior 
+   //  PA = Posterior/Anterior 
+   //  LL = Left Lateral 
+   //  RL = Right Lateral 
+   //  RLD = Right Lateral Decubitus 
+   //  LLD  = Left Lateral Decubitus 
+   //  RLO = Right Lateral Oblique 
+   //  LLO = Left Lateral Oblique  
+
 //-----------------------------------------------------------------------------
 // Refer to gdcmParser::CheckSwap()
 const unsigned int gdcmParser::HEADER_LENGTH_TO_READ = 256;
@@ -238,7 +251,6 @@ bool gdcmParser::IsReadable(void) {
  * \ingroup gdcmParser
  * \brief   Determines if the Transfer Syntax was already encountered
  *          and if it corresponds to a ImplicitVRLittleEndian one.
- *
  * @return  True when ImplicitVRLittleEndian found. False in all other cases.
  */
 bool gdcmParser::IsImplicitVRLittleEndianTransferSyntax(void) {
@@ -257,7 +269,6 @@ bool gdcmParser::IsImplicitVRLittleEndianTransferSyntax(void) {
  * \ingroup gdcmParser
  * \brief   Determines if the Transfer Syntax was already encountered
  *          and if it corresponds to a ExplicitVRLittleEndian one.
- *
  * @return  True when ExplicitVRLittleEndian found. False in all other cases.
  */
 bool gdcmParser::IsExplicitVRLittleEndianTransferSyntax(void) {
@@ -276,7 +287,6 @@ bool gdcmParser::IsExplicitVRLittleEndianTransferSyntax(void) {
  * \ingroup gdcmParser
  * \brief   Determines if the Transfer Syntax was already encountered
  *          and if it corresponds to a DeflatedExplicitVRLittleEndian one.
- *
  * @return  True when DeflatedExplicitVRLittleEndian found. False in all other cases.
  */
 bool gdcmParser::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) {
@@ -295,7 +305,6 @@ bool gdcmParser::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) {
  * \ingroup gdcmParser
  * \brief   Determines if the Transfer Syntax was already encountered
  *          and if it corresponds to a Explicit VR Big Endian one.
- *
  * @return  True when big endian found. False in all other cases.
  */
 bool gdcmParser::IsExplicitVRBigEndianTransferSyntax(void) {
@@ -314,7 +323,7 @@ bool gdcmParser::IsExplicitVRBigEndianTransferSyntax(void) {
  * \ingroup gdcmParser
  * \brief  returns the File Type 
  *         (ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown)
- * @return 
+ * @return the FileType code
  */
 FileType gdcmParser::GetFileType(void) {
    return(filetype);
@@ -434,7 +443,7 @@ bool gdcmParser::Write(FILE *fp, FileType type) {
       UpdateGroupLength(true,ACR);
 */
 
-   WriteEntries(type, fp);
+   WriteEntries(fp,type);
    return(true);
  }
 
@@ -445,7 +454,7 @@ bool gdcmParser::Write(FILE *fp, FileType type) {
  * @param   Value passed as a std::string
  * @param   Group
  * @param   Elem
- * \return  boolean
+ * \return  false only if new element creation fails
  */
 bool gdcmParser::ReplaceOrCreateByNumber(std::string Value, 
                                          guint16 Group, 
@@ -465,8 +474,8 @@ bool gdcmParser::ReplaceOrCreateByNumber(std::string Value,
  * \brief   Modifies the value of a given Header Entry (Dicom Element)
  *          if it exists; Creates it with the given value if it doesn't
  * @param   Value passed as a char*
- * @param   Group
- * @param   Elem
+ * @param Group   group of the Entry 
+ * @param Elem element of the Entry
  * \return  boolean 
  * 
  */
@@ -487,9 +496,9 @@ bool gdcmParser::ReplaceOrCreateByNumber(char* Value, guint16 Group, guint16 Ele
  * \ingroup gdcmParser
  * \brief   Set a new value if the invoked element exists
  *          Seems to be useless !!!
- * @param   Value
- * @param   Group
- * @param   Elem
+ * @param Value new element value
+ * @param Group   group of the Entry 
+ * @param Elem element of the Entry
  * \return  boolean 
  */
 bool gdcmParser::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 Elem ) 
@@ -501,10 +510,11 @@ bool gdcmParser::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 Elem
 
 //-----------------------------------------------------------------------------
 // Protected
+
 /**
  * \ingroup gdcmParser
  * \brief   Checks if a given Dicom Element exists
- * \        within the H table
+ *          within the H table
  * @param   group Group   number of the searched Dicom Element 
  * @param   element  Element number of the searched Dicom Element 
  * @return  number of occurences
@@ -629,7 +639,7 @@ bool gdcmParser::SetEntryByNumber(std::string content,
    if ( ! tagHT.count(key))
       return false;
    int l = content.length();
-   if(l%2) // Odd length are padded with a space (020H).
+   if(l%2) // Non even length are padded with a space (020H).
    {  
       l++;
       content = content + '\0';
@@ -669,21 +679,20 @@ bool gdcmParser::SetEntryByNumber(std::string content,
  *          through it's (group, element) and modifies it's length with
  *          the given value.
  * \warning Use with extreme caution.
- * @param   length new length to substitute with
- * @param   group   group of the entry to modify
- * @param   element element of the Entry to modify
+ * @param l new length to substitute with
+ * @param group   group of the Entry to modify
+ * @param element element of the Entry to modify
  * @return  1 on success, 0 otherwise.
  */
-
-bool gdcmParser::SetEntryLengthByNumber(guint32 length, 
+bool gdcmParser::SetEntryLengthByNumber(guint32 l, 
                                         guint16 group, 
                                        guint16 element) 
 {
    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
    if ( ! tagHT.count(key))
       return false;
-   if (length%2) length++; // length must be even
-   ( ((tagHT.equal_range(key)).first)->second )->SetLength(length);     
+   if (l%2) l++; // length must be even
+   ( ((tagHT.equal_range(key)).first)->second )->SetLength(l);  
         
    return true ;               
 }
@@ -691,9 +700,9 @@ bool gdcmParser::SetEntryLengthByNumber(guint32 length,
 /**
  * \ingroup gdcmParser
  * \brief   Gets (from Header) the offset  of a 'non string' element value 
- * \        (LoadElementValues has already be executed)
- * @param   Group
- * @param   Elem
+ *          (LoadElementValues has already be executed)
+ * @param Group   group of the Entry 
+ * @param Elem element of the Entry
  * @return File Offset of the Element Value 
  */
 size_t gdcmParser::GetEntryOffsetByNumber(guint16 Group, guint16 Elem) 
@@ -711,9 +720,9 @@ size_t gdcmParser::GetEntryOffsetByNumber(guint16 Group, guint16 Elem)
 /**
  * \ingroup gdcmParser
  * \brief   Gets (from Header) a 'non string' element value 
- * \        (LoadElementValues has already be executed)  
- * @param   Group
- * @param   Elem
+ *          (LoadElementValues has already be executed)  
+ * @param Group   group of the Entry 
+ * @param Elem element of the Entry
  * @return Pointer to the 'non string' area
  */
 void * gdcmParser::GetEntryVoidAreaByNumber(guint16 Group, guint16 Elem) 
@@ -732,8 +741,8 @@ void * gdcmParser::GetEntryVoidAreaByNumber(guint16 Group, guint16 Elem)
  * \ingroup       gdcmParser
  * \brief         Loads (from disk) the element content 
  *                when a string is not suitable
- * @param   Group
- * @param   Elem
+ * @param Group   group of the Entry 
+ * @param Elem element of the Entry
  */
 void *gdcmParser::LoadEntryVoidArea(guint16 Group, guint16 Elem) 
 {
@@ -780,8 +789,8 @@ bool gdcmParser::SetEntryVoidAreaByNumber(void * area,
 
 /**
  * \ingroup gdcmParser
- * \brief   Update the entries with the shadow dictionary. Only odd entries are
- *          analized
+ * \brief   Update the entries with the shadow dictionary. 
+ *          Only non even entries are  analyzed       
  */
 void gdcmParser::UpdateShaEntries(void) {
    gdcmDictEntry *entry;
@@ -841,7 +850,7 @@ void gdcmParser::UpdateShaEntries(void) {
 /**
  * \ingroup gdcmParser
  * \brief  retrieves a Dicom Element (the first one) using (group, element)
- * \ warning (group, element) IS NOT an identifier inside the Dicom Header
+ * \warning (group, element) IS NOT an identifier inside the Dicom Header
  *           if you think it's NOT UNIQUE, check the count number
  *           and use iterators to retrieve ALL the Dicoms Elements within
  *           a given couple (group, element)
@@ -994,20 +1003,21 @@ void gdcmParser::UpdateGroupLength(bool SkipSequence, FileType type) {
 /**
  * \ingroup gdcmParser
  * \brief   writes on disc according to the requested format
- * \        (ACR-NEMA, ExplicitVR, ImplicitVR) the image
- * \ warning does NOT add the missing elements in the header :
- * \         it's up to the user doing it !
- * \         (function CheckHeaderCoherence to be written)
- * \ warning DON'T try, right now, to write a DICOM image
- * \         from an ACR Header (meta elements will be missing!)
+ *          (ACR-NEMA, ExplicitVR, ImplicitVR) the image
+ * \warning does NOT add the missing elements in the header :
+ *           it's up to the user doing it !
+ *           (function CheckHeaderCoherence to be written)
+ * \warning DON'T try, right now, to write a DICOM image
+ *           from an ACR Header (meta elements will be missing!)
  * @param   type type of the File to be written 
  *          (ACR-NEMA, ExplicitVR, ImplicitVR)
  * @param   _fp already open file pointer
  */
-void gdcmParser::WriteEntries(FileType type, FILE * _fp) 
+void gdcmParser::WriteEntries(FILE *_fp,FileType type)
 {
    guint16 gr, el;
    guint32 lgr;
+   std::string value;
    const char * val;
    std::string vr;
    guint32 val_uint32;
@@ -1024,7 +1034,7 @@ void gdcmParser::WriteEntries(FileType type, FILE * _fp)
    //       TODO : find a trick (in STL?) to do it, at low cost !
 
    void *ptr;
-      
+
    // TODO (?) tester les echecs en ecriture (apres chaque fwrite)
    int compte =0;
    
@@ -1032,11 +1042,19 @@ void gdcmParser::WriteEntries(FileType type, FILE * _fp)
         tag2 != listEntries.end();
         ++tag2)
    {
-      gr =  (*tag2)->GetGroup();
-      el =  (*tag2)->GetElement();
-      lgr = (*tag2)->GetReadLength();
-      val = (*tag2)->GetValue().c_str();
-      vr =  (*tag2)->GetVR();
+      // === Deal with the length
+      //     --------------------
+      if(((*tag2)->GetLength())%2==1)
+      {
+         (*tag2)->SetValue((*tag2)->GetValue()+"\0");
+         (*tag2)->SetLength((*tag2)->GetLength()+1);
+      }
+
+      gr    = (*tag2)->GetGroup();
+      el    = (*tag2)->GetElement();
+      lgr   = (*tag2)->GetReadLength();
+      val   = (*tag2)->GetValue().c_str();
+      vr    = (*tag2)->GetVR();
       voidArea = (*tag2)->GetVoidArea();
       
       if ( type == ACR ) 
@@ -1052,38 +1070,39 @@ void gdcmParser::WriteEntries(FileType type, FILE * _fp)
       fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp);  //group
       fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp);  //element
       
-      // === Deal with the length
-      //     --------------------
-      
       // if ( (type == ExplicitVR) && (gr <= 0x0002) ) // ?!?  < 2  
       if ( (type == ExplicitVR) || (type == DICOMDIR) )      
       {
          // EXPLICIT VR
          guint16 z=0, shortLgr;
-        if (vr == "Unknown") { // Unknown was 'written'         
+         if (vr == "unkn") 
+         { // Unknown was 'written'     
             shortLgr=lgr;
             fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
             fwrite ( &z,  (size_t)2 ,(size_t)1 ,_fp);
-        } else {        
-            if (gr != 0xfffe) { // NO value for 'delimiters'
-             if (vr == "Unknown") // Unknown was 'written'
-                fwrite(&z,(size_t)2 ,(size_t)1 ,_fp);
-             else       
-                 fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
+         } 
+         else 
+         {
+            if (gr != 0xfffe) 
+            { // NO value for 'delimiters'
+               if (vr == "unkn") // Unknown was 'written'
+                  fwrite(&z,(size_t)2 ,(size_t)1 ,_fp);
+               else     
+                  fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
             }
-        
-            if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") || gr == 0xfffe) // JPR
+
+            if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") || gr == 0xfffe)
             {
                if (gr != 0xfffe)
-                 fwrite ( &z,  (size_t)2 ,(size_t)1 ,_fp);
-               fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
+                  fwrite ( &z,  (size_t)2 ,(size_t)1 ,_fp);
+                  fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
             } 
             else 
             {
                shortLgr=lgr;
                fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
             }
-        }
+         }
       } 
       else // IMPLICIT VR 
       { 
@@ -1095,9 +1114,10 @@ void gdcmParser::WriteEntries(FileType type, FILE * _fp)
       if (vr == "SQ")  continue; // no "value" to write for the SEQuences
       if (gr == 0xfffe)continue;
       
-      if (voidArea != NULL) { // there is a 'non string' LUT, overlay, etc
+      if (voidArea != NULL) 
+      { // there is a 'non string' LUT, overlay, etc
          fwrite ( voidArea,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
-        continue;            
+         continue;            
       }
       
       if (vr == "US" || vr == "SS") 
@@ -1133,7 +1153,7 @@ void gdcmParser::WriteEntries(FileType type, FILE * _fp)
             
       if ((gr == GrPixel) && (el == NumPixel) ) {
          compte++;
-        if (compte == countGrPixel) // we passed *all* the GrPixel,NumPixel   
+         if (compte == countGrPixel) // we passed *all* the GrPixel,NumPixel   
             break;
       }       
       fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
@@ -1389,8 +1409,9 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry *Entry)  {
  * \brief   add a new Dicom Element pointer to 
  *          the H Table and to the chained List
  * \warning push_bash in listEntries ONLY during ParseHeader
- * \TODO    something to allow further Elements addition,
- * \        when position to be taken care of     
+ * \todo    something to allow further Elements addition,
+ *          (at their right place in the chained list)
+ *          when position to be taken care of     
  * @param   newHeaderEntry
  */
 void gdcmParser::AddHeaderEntry(gdcmHeaderEntry *newHeaderEntry) {
@@ -1403,7 +1424,6 @@ void gdcmParser::AddHeaderEntry(gdcmHeaderEntry *newHeaderEntry) {
  * \ingroup gdcmParser
  * \brief   
  * @param   Entry Header Entry whose length of the value shall be loaded. 
-
  * @return 
  */
  void gdcmParser::FindHeaderEntryLength (gdcmHeaderEntry *Entry) {
@@ -1413,7 +1433,7 @@ void gdcmParser::AddHeaderEntry(gdcmHeaderEntry *newHeaderEntry) {
    guint16 length16;
    if( (element == NumPixel) && (group == GrPixel) ) 
    {
-      dbg.SetDebug(-1);
+      dbg.SetDebug(GDCM_DEBUG);
       dbg.Verbose(2, "gdcmParser::FindLength: ",
                      "we reached (GrPixel,NumPixel)");
    }   
@@ -1530,7 +1550,6 @@ void gdcmParser::FindHeaderEntryVR( gdcmHeaderEntry *Entry)
       return;
 
    char VR[3];
-   int lgrLue;
 
    long PositionOnEntry = ftell(fp);
    // Warning: we believe this is explicit VR (Value Representation) because
@@ -1541,7 +1560,7 @@ void gdcmParser::FindHeaderEntryVR( gdcmHeaderEntry *Entry)
    // is in explicit VR and try to fix things if it happens not to be
    // the case.
    
-   lgrLue=fread (&VR, (size_t)2,(size_t)1, fp);
+   int lgrLue=fread (&VR, (size_t)2,(size_t)1, fp); // lgrLue not used
    VR[2]=0;
    if(!CheckHeaderEntryVR(Entry,VR))
    {
@@ -1562,8 +1581,8 @@ void gdcmParser::FindHeaderEntryVR( gdcmHeaderEntry *Entry)
  * \brief     Check the correspondance between the VR of the header entry
  *            and the taken VR. If they are different, the header entry is 
  *            updated with the new VR.
- * @param     Entry
- * @param     VR
+ * @param     Entry Header Entry to check
+ * @param     vr    Dicom Value Representation
  * @return    false if the VR is incorrect of if the VR isn't referenced
  *            otherwise, it returns true
 */
@@ -1596,14 +1615,23 @@ bool gdcmParser::CheckHeaderEntryVR(gdcmHeaderEntry *Entry, VRKey vr)
       sprintf(msg,"Falsely explicit vr file (%04x,%04x)\n", 
                    Entry->GetGroup(),Entry->GetElement());
       dbg.Verbose(1, "gdcmParser::FindVR: ",msg);
-
+      if (Entry->GetGroup()%2 && Entry->GetElement() == 0x0000) { // Group length is UL !
+         gdcmDictEntry* NewEntry = NewVirtualDictEntry(
+                                   Entry->GetGroup(),Entry->GetElement(),
+                                   "UL","FIXME","Group Length");
+         Entry->SetDictEntry(NewEntry);                                                                              
+      }
       return(false);
    }
 
    if ( Entry->IsVRUnknown() ) 
    {
       // When not a dictionary entry, we can safely overwrite the VR.
-      Entry->SetVR(vr);
+      if (Entry->GetElement() == 0x0000) { // Group length is UL !
+         Entry->SetVR("UL");
+      } else {
+         Entry->SetVR(vr);
+      }
    }
    else if ( Entry->GetVR() != vr ) 
    {
@@ -1668,7 +1696,6 @@ std::string gdcmParser::GetHeaderEntryValue(gdcmHeaderEntry *Entry)
             s << NewInt32;
          }
       }
-
 #ifdef GDCM_NO_ANSI_STRING_STREAM
       s << std::ends; // to avoid oddities on Solaris
 #endif //GDCM_NO_ANSI_STRING_STREAM
@@ -1761,8 +1788,10 @@ void gdcmParser::FixHeaderEntryFoundLength(gdcmHeaderEntry *Entry, guint32 Found
    guint16 el =Entry->GetElement(); 
      
    if (FoundLength%2) {
-      std::cout << "Warning : Tag with uneven length " << FoundLength 
-         <<  "in x(" << std::hex << gr << "," << el <<")" << std::endl;
+      std::ostringstream s;
+      s << "Warning : Tag with uneven length " << FoundLength 
+         <<  " in x(" << std::hex << gr << "," << el <<")" << std::dec;
+      dbg.Verbose(0,s.str().c_str());
    }
       
    // Sorry for the patch!  
@@ -1864,7 +1893,7 @@ bool gdcmParser::IsHeaderEntryAnInteger(gdcmHeaderEntry *Entry) {
 /**
  * \ingroup gdcmParser
  * \brief   
- *
+ * \warning NOT end user intended method !
  * @return 
  */
  guint32 gdcmParser::FindHeaderEntryLengthOB(void)  {
@@ -1915,8 +1944,7 @@ bool gdcmParser::IsHeaderEntryAnInteger(gdcmHeaderEntry *Entry) {
 /**
  * \ingroup gdcmParser
  * \brief Reads a supposed to be 16 Bits integer
- * \     (swaps it depending on processor endianity) 
- *
+ *       (swaps it depending on processor endianity) 
  * @return read value
  */
 guint16 gdcmParser::ReadInt16(void) {
@@ -1937,8 +1965,7 @@ guint16 gdcmParser::ReadInt16(void) {
 /**
  * \ingroup gdcmParser
  * \brief  Reads a supposed to be 32 Bits integer
- * \       (swaps it depending on processor endianity)  
- *
+ *         (swaps it depending on processor endianity)  
  * @return read value
  */
 guint32 gdcmParser::ReadInt32(void) {
@@ -1959,7 +1986,7 @@ guint32 gdcmParser::ReadInt32(void) {
 /**
  * \ingroup gdcmParser
  * \brief   
- *
+ * \warning NOT end user intended method !
  * @return 
  */
 void gdcmParser::SkipBytes(guint32 NBytes) {
@@ -2191,7 +2218,7 @@ void gdcmParser::SwitchSwapToBigEndian(void)
 
 /**
  * \ingroup gdcmParser
- * \brief   
+ * \brief  during parsing, Header Elements too long are not loaded in memory 
  * @param NewSize
  */
 void gdcmParser::SetMaxSizeLoadEntry(long NewSize) 
@@ -2209,8 +2236,9 @@ void gdcmParser::SetMaxSizeLoadEntry(long NewSize)
 
 /**
  * \ingroup gdcmParser
- * \brief
- * \warning TODO : not yet usable 
+ * \brief Header Elements too long will not be printed
+ * \warning 
+ * \todo : not yet usable 
  *          (see MAX_SIZE_PRINT_ELEMENT_VALUE 
  *           in gdcmHeaderEntry gdcmLoadEntry)
  *             
@@ -2300,7 +2328,6 @@ gdcmDictEntry *gdcmParser::GetDictEntryByNumber(guint16 group,guint16 element)
 gdcmHeaderEntry *gdcmParser::ReadNextHeaderEntry(void) {
    guint16 g,n;
    gdcmHeaderEntry *NewEntry;
-   
    g = ReadInt16();
    n = ReadInt16();
       
@@ -2341,7 +2368,7 @@ gdcmHeaderEntry *gdcmParser::NewHeaderEntryByName(std::string Name)
 {
    gdcmDictEntry *NewTag = GetDictEntryByName(Name);
    if (!NewTag)
-      NewTag = NewVirtualDictEntry(0xffff, 0xffff, "LO", "Unknown", Name);
+      NewTag = NewVirtualDictEntry(0xffff, 0xffff, "LO", "unkn", Name);
 
    gdcmHeaderEntry* NewEntry = new gdcmHeaderEntry(NewTag);
    if (!NewEntry) 
@@ -2357,7 +2384,7 @@ gdcmHeaderEntry *gdcmParser::NewHeaderEntryByName(std::string Name)
  * \ingroup gdcmParser
  * \brief   Request a new virtual dict entry to the dict set
  * @param   group  group   of the underlying DictEntry
- * @param   elem   element of the underlying DictEntry
+ * @param   element  element of the underlying DictEntry
  * @param   vr     VR of the underlying DictEntry
  * @param   fourth owner group
  * @param   name   english name