]> Creatis software - gdcm.git/blobdiff - src/gdcmDocument.cxx
dealing with 'zero length' integers
[gdcm.git] / src / gdcmDocument.cxx
index b61275492c3fd049074daf3b40f2b38925064a48..cdcdd9cb1b69e1b335a8fd568573075c8f76e8d2 100644 (file)
@@ -3,8 +3,8 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmDocument.cxx,v $
   Language:  C++
-  Date:      $Date: 2004/08/16 04:34:56 $
-  Version:   $Revision: 1.67 $
+  Date:      $Date: 2004/09/13 07:49:36 $
+  Version:   $Revision: 1.75 $
                                                                                 
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
@@ -81,7 +81,7 @@ const unsigned int gdcmDocument::MAX_SIZE_PRINT_ELEMENT_VALUE = 0x7fffffff;
 
 /**
  * \brief   constructor  
- * @param   inFilename file to be opened for parsing
+ * @param   filename file to be opened for parsing
  */
 gdcmDocument::gdcmDocument( std::string const & filename ) 
               : gdcmElementSet(-1)
@@ -94,7 +94,7 @@ gdcmDocument::gdcmDocument( std::string const & filename )
    {
       return;
    }
-   
+
    dbg.Verbose(0, "gdcmDocument::gdcmDocument: starting parsing of file: ",
                   Filename.c_str());
    rewind(Fp);
@@ -260,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;
    }
@@ -280,7 +278,7 @@ bool gdcmDocument::IsReadable()
 /**
  * \brief   Internal function that checks whether the Transfer Syntax given
  *          as argument is the one present in the current document.
- * @param   SyntaxToCheck The transfert syntax we need to check against.
+ * @param   syntaxToCheck The transfert syntax we need to check against.
  * @return  True when SyntaxToCheck corresponds to the Transfer Syntax of
  *          the current document. False either when the document contains
  *          no Transfer Syntax, or when the Tranfer Syntaxes doesn't match.
@@ -577,9 +575,9 @@ void gdcmDocument::Write(FILE* fp,FileType filetype)
 /**
  * \brief   Modifies the value of a given Header Entry (Dicom Element)
  *          when it exists. Create it with the given value when unexistant.
- * @param   Value (string) Value to be set
- * @param   Group   Group number of the Entry 
- * @param   Elem  Element number of the Entry
+ * @param   value (string) Value to be set
+ * @param   group   Group number of the Entry 
+ * @param   elem  Element number of the Entry
  * \return  pointer to the modified/created Header Entry (NULL when creation
  *          failed).
  */
@@ -590,8 +588,8 @@ gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber(
                                          uint16_t elem )
 {
    gdcmValEntry* valEntry = 0;
-
    gdcmDocEntry* currentEntry = GetDocEntryByNumber( group, elem);
+   
    if (!currentEntry)
    {
       // The entry wasn't present and we simply create the required ValEntry:
@@ -612,7 +610,9 @@ gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber(
    else
    {
       valEntry = dynamic_cast< gdcmValEntry* >(currentEntry);
-      if ( !valEntry )
+      if ( !valEntry ) // Euuuuh? It wasn't a ValEntry
+                       // then we change it to a ValEntry ?
+                       // Shouldn't it be considered as an error ?
       {
          // We need to promote the gdcmDocEntry to a gdcmValEntry:
          valEntry = new gdcmValEntry(currentEntry);
@@ -664,19 +664,49 @@ gdcmBinEntry * gdcmDocument::ReplaceOrCreateByNumber(
       b = new gdcmBinEntry(a);
       AddEntry(b);
       b->SetVoidArea(voidArea);
-   }   
+   } 
+
    SetEntryByNumber(voidArea, lgth, group, elem);
    //b->SetVoidArea(voidArea);  //what if b == 0 !!
 
    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 !!!
- * @param Value new element value
- * @param Group  group number of the Entry 
- * @param Elem element number of the Entry
+ * @param value new element value
+ * @param group  group number of the Entry 
+ * @param elem element number of the Entry
  * \return  boolean 
  */
 bool gdcmDocument::ReplaceIfExistByNumber(std::string const & value, 
@@ -694,9 +724,9 @@ bool gdcmDocument::ReplaceIfExistByNumber(std::string const & value,
  * \brief   Checks if a given Dicom Element exists 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
+ * @return true is found
  */
-int gdcmDocument::CheckIfEntryExistByNumber(uint16_t group, uint16_t element )
+bool gdcmDocument::CheckIfEntryExistByNumber(uint16_t group, uint16_t element )
 {
    const std::string &key = gdcmDictEntry::TranslateToKey(group, element );
    return TagHT.count(key);
@@ -841,6 +871,9 @@ bool gdcmDocument::SetEntryByNumber(std::string const & content,
                                     uint16_t group,
                                     uint16_t element) 
 {
+   int c;
+   int l;
+
    gdcmValEntry* valEntry = GetValEntryByNumber(group, element);
    if (!valEntry )
    {
@@ -849,28 +882,31 @@ bool gdcmDocument::SetEntryByNumber(std::string const & content,
       return false;
    }
    // Non even content must be padded with a space (020H)...
-   std::string evenContent = content;
-   if( evenContent.length() % 2 )
+   std::string finalContent = content;
+   if( finalContent.length() % 2 )
    {
-      evenContent += '\0';  // ... therefore we padd with (000H) .!?!
+      finalContent += '\0';  // ... therefore we padd with (000H) .!?!
    }      
-   valEntry->SetValue(evenContent);
+   valEntry->SetValue(finalContent);
    
    // Integers have a special treatement for their length:
-   gdcmVRKey vr = valEntry->GetVR();
-   if( vr == "US" || vr == "SS" )
-   {
-      valEntry->SetLength(2);
-   }
-   else if( vr == "UL" || vr == "SL" )
-   {
-      valEntry->SetLength(4);
-   }
-   else
-   {
-      valEntry->SetLength(evenContent.length());
-   }
 
+   l = finalContent.length();
+   if ( l != 0) // To avoid to be cheated by 'zero length' integers
+   {   
+      gdcmVRKey vr = valEntry->GetVR();
+      if( vr == "US" || vr == "SS" )
+      {
+         c = CountSubstring(content, "\\") + 1; // for multivaluated items
+         l = c*2;
+      }
+      else if( vr == "UL" || vr == "SL" )
+      {
+         c = CountSubstring(content, "\\") + 1; // for multivaluated items
+         l = c*4;;
+      }
+   }
+   valEntry->SetLength(l);
    return true;
 } 
 
@@ -904,7 +940,7 @@ bool gdcmDocument::SetEntryByNumber(void *content,
 */      
    gdcmBinEntry* a = (gdcmBinEntry *)TagHT[key];           
    a->SetVoidArea(content);  
-   //a->SetLength(lgth);  // ???  
+   a->SetLength(lgth);
 
    return true;
 } 
@@ -942,8 +978,8 @@ bool gdcmDocument::SetEntryLengthByNumber(uint32_t l,
 /**
  * \brief   Gets (from Header) the offset  of a 'non string' element value 
  *          (LoadElementValues has already be executed)
- * @param Group   group number of the Entry 
- * @param Elem  element number of the Entry
+ * @param group   group number of the Entry 
+ * @param elem  element number of the Entry
  * @return File Offset of the Element Value 
  */
 size_t gdcmDocument::GetEntryOffsetByNumber(uint16_t group, uint16_t elem) 
@@ -960,8 +996,8 @@ size_t gdcmDocument::GetEntryOffsetByNumber(uint16_t group, uint16_t elem)
 /**
  * \brief   Gets (from Header) a 'non string' element value 
  *          (LoadElementValues has already be executed)  
- * @param Group   group number of the Entry 
- * @param Elem  element number of the Entry
+ * @param group   group number of the Entry 
+ * @param elem  element number of the Entry
  * @return Pointer to the 'non string' area
  */
 void * gdcmDocument::GetEntryVoidAreaByNumber(uint16_t group, uint16_t elem) 
@@ -978,8 +1014,8 @@ void * gdcmDocument::GetEntryVoidAreaByNumber(uint16_t group, uint16_t elem)
 /**
  * \brief         Loads (from disk) the element content 
  *                when a string is not suitable
- * @param Group   group number of the Entry 
- * @param Elem  element number of the Entry
+ * @param group   group number of the Entry 
+ * @param elem  element number of the Entry
  */
 void *gdcmDocument::LoadEntryVoidArea(uint16_t group, uint16_t elem)
 {
@@ -1003,7 +1039,7 @@ void *gdcmDocument::LoadEntryVoidArea(uint16_t group, uint16_t elem)
       delete[] a;
       return NULL;
    }
-   /// \todo Drop any already existing void area! JPR
+   /// \TODO Drop any already existing void area! JPR
    SetEntryVoidAreaByNumber(a, group, elem);
 
    return a;
@@ -1011,7 +1047,7 @@ void *gdcmDocument::LoadEntryVoidArea(uint16_t group, uint16_t elem)
 /**
  * \brief         Loads (from disk) the element content 
  *                when a string is not suitable
- * @param Element  Entry whose voidArea is going to be loaded
+ * @param element  Entry whose voidArea is going to be loaded
  */
 void *gdcmDocument::LoadEntryVoidArea(gdcmBinEntry *element) 
 {
@@ -1207,7 +1243,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;
    }
@@ -1372,7 +1408,6 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
       }
       delete newDocEntry;
    }
-
    return l; // Probably useless 
 }
 
@@ -1440,7 +1475,7 @@ long gdcmDocument::ParseSQ(gdcmSeqEntry *set,
 /**
  * \brief         Loads the element content if its length doesn't exceed
  *                the value specified with gdcmDocument::SetMaxSizeLoadEntry()
- * @param         Entry Header Entry (Dicom Element) to be dealt with
+ * @param         entry Header Entry (Dicom Element) to be dealt with
  */
 void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry)
 {
@@ -1476,44 +1511,42 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry)
    if (length > MaxSizeLoadEntry)
    {
       if (gdcmBinEntry* binEntryPtr = dynamic_cast< gdcmBinEntry* >(entry) )
-      {         
-         s << "gdcm::NotLoaded (BinEntry)";
+      {  
+         //s << "gdcm::NotLoaded (BinEntry)";
+         s << GDCM_NOTLOADED;
          s << " Address:" << (long)entry->GetOffset();
          s << " Length:"  << entry->GetLength();
          s << " x(" << std::hex << entry->GetLength() << ")";
          binEntryPtr->SetValue(s.str());
       }
-      // to be sure we are at the end of the value ...
-      fseek(Fp, (long)entry->GetOffset()+(long)entry->GetLength(), SEEK_SET);      
-      // 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) )
+      else if (gdcmValEntry* valEntryPtr = dynamic_cast< gdcmValEntry* >(entry) )
       {
-         s << "gdcm::NotLoaded. (ValEntry)";
+        // s << "gdcm::NotLoaded. (ValEntry)";
+         s << GDCM_NOTLOADED;  
          s << " Address:" << (long)entry->GetOffset();
          s << " Length:"  << entry->GetLength();
          s << " x(" << std::hex << entry->GetLength() << ")";
          valEntryPtr->SetValue(s.str());
       }
+      else
+      {
+         // fusible
+         std::cout<< "MaxSizeLoadEntry exceeded, neither a BinEntry "
+                  << "nor a ValEntry ?! Should never print that !" << std::endl;
+      }
+
       // to be sure we are at the end of the value ...
       fseek(Fp,(long)entry->GetOffset()+(long)entry->GetLength(),SEEK_SET);      
-
       return;
    }
 
    // When we find a BinEntry not very much can be done :
    if (gdcmBinEntry* binEntryPtr = dynamic_cast< gdcmBinEntry* >(entry) )
    {
-
-      LoadEntryVoidArea(binEntryPtr);
       s << "gdcm::Loaded (BinEntry)";
       binEntryPtr->SetValue(s.str());
+      LoadEntryVoidArea(binEntryPtr); // last one, not to erase length !
       return;
    }
     
@@ -1582,7 +1615,7 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry)
       {
          dbg.Verbose(1, "gdcmDocument::LoadDocEntry",
                         "unread element value");
-         valEntry->SetValue("gdcm::UnRead");
+         valEntry->SetValue(GDCM_UNREAD);
          return;
       }
 
@@ -1606,15 +1639,14 @@ 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. 
+ * @param  entry Header Entry whose length of the value shall be loaded. 
  */
 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() ) 
    {
@@ -1735,7 +1767,7 @@ void gdcmDocument::FindDocEntryLength( gdcmDocEntry *entry )
 
 /**
  * \brief     Find the Value Representation of the current Dicom Element.
- * @param     Entry
+ * @param     entry
  */
 void gdcmDocument::FindDocEntryVR( gdcmDocEntry *entry )
 {
@@ -1778,7 +1810,7 @@ void gdcmDocument::FindDocEntryVR( gdcmDocEntry *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 Header Entry to check
+ * @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
@@ -1861,7 +1893,7 @@ bool gdcmDocument::CheckDocEntryVR(gdcmDocEntry *entry, gdcmVRKey vr)
  * \brief   Get the transformed value of the header entry. The VR value 
  *          is used to define the transformation to operate on the value
  * \warning NOT end user intended method !
- * @param   Entry 
+ * @param   entry entry to tranform
  * @return  Transformed entry value
  */
 std::string gdcmDocument::GetDocEntryValue(gdcmDocEntry *entry)
@@ -1937,7 +1969,7 @@ std::string gdcmDocument::GetDocEntryValue(gdcmDocEntry *entry)
  *          value is used to define the reverse transformation to operate on
  *          the value
  * \warning NOT end user intended method !
- * @param   Entry 
+ * @param   entry Entry to reverse transform
  * @return  Reverse transformed entry value
  */
 std::string gdcmDocument::GetDocEntryUnvalue(gdcmDocEntry* entry)
@@ -1991,7 +2023,7 @@ std::string gdcmDocument::GetDocEntryUnvalue(gdcmDocEntry* entry)
 /**
  * \brief   Skip a given Header Entry 
  * \warning NOT end user intended method !
- * @param   entry 
+ * @param   entry entry to skip
  */
 void gdcmDocument::SkipDocEntry(gdcmDocEntry *entry) 
 {
@@ -2001,7 +2033,7 @@ void gdcmDocument::SkipDocEntry(gdcmDocEntry *entry)
 /**
  * \brief   Skips to the begining of the next Header Entry 
  * \warning NOT end user intended method !
- * @param   entry 
+ * @param   entry entry to skip
  */
 void gdcmDocument::SkipToNextDocEntry(gdcmDocEntry *entry) 
 {
@@ -2013,6 +2045,8 @@ void gdcmDocument::SkipToNextDocEntry(gdcmDocEntry *entry)
  * \brief   When the length of an element value is obviously wrong (because
  *          the parser went Jabberwocky) one can hope improving things by
  *          applying some heuristics.
+ * @param   entry entry to check
+ * @param   foundLength fist assumption about length    
  */
 void gdcmDocument::FixDocEntryFoundLength(gdcmDocEntry *entry,
                                           uint32_t foundLength)
@@ -2090,7 +2124,7 @@ void gdcmDocument::FixDocEntryFoundLength(gdcmDocEntry *entry,
 /**
  * \brief   Apply some heuristics to predict whether the considered 
  *          element value contains/represents an integer or not.
- * @param   Entry The element value on which to apply the predicate.
+ * @param   entry The element value on which to apply the predicate.
  * @return  The result of the heuristical predicate.
  */
 bool gdcmDocument::IsDocEntryAnInteger(gdcmDocEntry *entry)
@@ -2477,7 +2511,7 @@ void gdcmDocument::SwitchSwapToBigEndian()
 
 /**
  * \brief  during parsing, Header Elements too long are not loaded in memory 
- * @param NewSize
+ * @param newSize
  */
 void gdcmDocument::SetMaxSizeLoadEntry(long newSize) 
 {
@@ -2497,7 +2531,7 @@ void gdcmDocument::SetMaxSizeLoadEntry(long newSize)
 /**
  * \brief Header Elements too long will not be printed
  * \todo  See comments of \ref gdcmDocument::MAX_SIZE_PRINT_ELEMENT_VALUE 
- * @param NewSize
+ * @param newSize
  */
 void gdcmDocument::SetMaxSizePrintEntry(long newSize) 
 {
@@ -2582,16 +2616,16 @@ uint32_t gdcmDocument::GenerateFreeTagKeyInGroup(uint16_t group)
 }
 
 /**
- * \brief   Assuming the internal file pointer \ref gdcmDocument::f
+ * \brief   Assuming the internal file pointer \ref gdcmDocument::F
  *          is placed at the beginning of a tag check whether this
  *          tag is (TestGroup, TestElement).
- * \warning On success the internal file pointer \ref gdcmDocument::fp
+ * \warning On success the internal file pointer \ref gdcmDocument::Fp
  *          is modified to point after the tag.
  *          On failure (i.e. when the tag wasn't the expected tag
  *          (TestGroup, TestElement) the internal file pointer
- *          \ref gdcmDocument::fp is restored to it's original position.
- * @param   TestGroup   The expected group of the tag.
- * @param   TestElement The expected Element of the tag.
+ *          \ref gdcmDocument::Fp is restored to it's original position.
+ * @param   testGroup   The expected group of the tag.
+ * @param   testElement The expected Element of the tag.
  * @return  True on success, false otherwise.
  */
 bool gdcmDocument::ReadTag(uint16_t testGroup, uint16_t testElement)
@@ -2622,16 +2656,16 @@ bool gdcmDocument::ReadTag(uint16_t testGroup, uint16_t testElement)
 }
 
 /**
- * \brief   Assuming the internal file pointer \ref gdcmDocument::f
+ * \brief   Assuming the internal file pointer \ref gdcmDocument::F
  *          is placed at the beginning of a tag (TestGroup, TestElement),
  *          read the length associated to the Tag.
- * \warning On success the internal file pointer \ref gdcmDocument::fp
+ * \warning On success the internal file pointer \ref gdcmDocument::Fp
  *          is modified to point after the tag and it's length.
  *          On failure (i.e. when the tag wasn't the expected tag
  *          (TestGroup, TestElement) the internal file pointer
- *          \ref gdcmDocument::fp is restored to it's original position.
- * @param   TestGroup   The expected group of the tag.
- * @param   TestElement The expected Element of the tag.
+ *          \ref gdcmDocument::Fp is restored to it's original position.
+ * @param   testGroup   The expected group of the tag.
+ * @param   testElement The expected Element of the tag.
  * @return  On success returns the length associated to the tag. On failure
  *          returns 0.
  */
@@ -2781,7 +2815,7 @@ bool gdcmDocument::operator<(gdcmDocument &document)
    {
       return true;
    }
-   else if(s1 > s2)
+   else if( s1 > s2 )
    {
       return false;
    }
@@ -2796,7 +2830,7 @@ bool gdcmDocument::operator<(gdcmDocument &document)
       }
       else if ( s1 > s2 )
       {
-         return true;
+         return false;
       }
       else
       {
@@ -2815,7 +2849,7 @@ bool gdcmDocument::operator<(gdcmDocument &document)
          {
             // Serie Instance UID
             s1 = GetEntryByNumber(0x0020,0x000e);
-            s2 = document.GetEntryByNumber(0x0020,0x000e);
+            s2 = document.GetEntryByNumber(0x0020,0x000e);    
             if ( s1 < s2 )
             {
                return true;