]> Creatis software - gdcm.git/blobdiff - src/gdcmDocument.cxx
* CLEANUP_ROUND (9) for gdcmPixelConvert
[gdcm.git] / src / gdcmDocument.cxx
index 4f066856bf08417e41d9e88954427a4b730bbdd5..9d3d59ea0717c461339377ef9e3acd388e8d540d 100644 (file)
@@ -3,12 +3,12 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmDocument.cxx,v $
   Language:  C++
-  Date:      $Date: 2004/09/15 03:50:48 $
-  Version:   $Revision: 1.78 $
+  Date:      $Date: 2004/10/08 08:38:54 $
+  Version:   $Revision: 1.98 $
                                                                                 
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
-  http://www.creatis.insa-lyon.fr/Public/Gdcm/License.htm for details.
+  http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
                                                                                 
      This software is distributed WITHOUT ANY WARRANTY; without even
      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
@@ -20,7 +20,6 @@
 #include "gdcmValEntry.h"
 #include "gdcmBinEntry.h"
 #include "gdcmSeqEntry.h"
-
 #include "gdcmGlobal.h"
 #include "gdcmUtil.h"
 #include "gdcmDebug.h"
@@ -107,9 +106,7 @@ gdcmDocument::gdcmDocument( std::string const & filename )
    long beg = ftell(Fp);
    lgt -= beg;
    
-   SQDepthLevel = 0;
-   
-   (void)ParseDES( this, beg, lgt, false); // le Load sera fait a la volee
+   ParseDES( this, beg, lgt, false); // le Load sera fait a la volee
 
    rewind(Fp);
    
@@ -118,7 +115,7 @@ gdcmDocument::gdcmDocument( std::string const & filename )
    std::string PhotometricInterpretation = GetEntryByNumber(0x0028,0x0004);   
    if( PhotometricInterpretation == "PALETTE COLOR " )
    {
-      LoadEntryVoidArea(0x0028,0x1200);  // gray LUT   
+      LoadEntryBinArea(0x0028,0x1200);  // gray LUT   
       /// FIXME FIXME FIXME
       /// The tags refered by the three following lines used to be CORRECTLY
       /// defined as having an US Value Representation in the public
@@ -134,19 +131,19 @@ gdcmDocument::gdcmDocument( std::string const & filename )
       ///   also used as gdcmBinEntry, which requires the proper conversion,
       /// - OW, and hence loaded as gdcmBinEntry, but afterwards also used
       ///   as gdcmValEntry, which requires the proper conversion.
-      LoadEntryVoidArea(0x0028,0x1201);  // R    LUT
-      LoadEntryVoidArea(0x0028,0x1202);  // G    LUT
-      LoadEntryVoidArea(0x0028,0x1203);  // B    LUT
+      LoadEntryBinArea(0x0028,0x1201);  // R    LUT
+      LoadEntryBinArea(0x0028,0x1202);  // G    LUT
+      LoadEntryBinArea(0x0028,0x1203);  // B    LUT
       
       // Segmented Red   Palette Color LUT Data
-      LoadEntryVoidArea(0x0028,0x1221);
+      LoadEntryBinArea(0x0028,0x1221);
       // Segmented Green Palette Color LUT Data
-      LoadEntryVoidArea(0x0028,0x1222);
+      LoadEntryBinArea(0x0028,0x1222);
       // Segmented Blue  Palette Color LUT Data
-      LoadEntryVoidArea(0x0028,0x1223);
+      LoadEntryBinArea(0x0028,0x1223);
    } 
    //FIXME later : how to use it?
-   LoadEntryVoidArea(0x0028,0x3006);  //LUT Data (CTX dependent) 
+   LoadEntryBinArea(0x0028,0x3006);  //LUT Data (CTX dependent) 
 
    CloseFile(); 
   
@@ -232,7 +229,7 @@ void gdcmDocument::PrintShaDict(std::ostream & os)
 /**
  * \brief   Get the public dictionary used
  */
-gdcmDict *gdcmDocument::GetPubDict()
+gdcmDictgdcmDocument::GetPubDict()
 {
    return RefPubDict;
 }
@@ -240,7 +237,7 @@ gdcmDict *gdcmDocument::GetPubDict()
 /**
  * \brief   Get the shadow dictionary used
  */
-gdcmDict *gdcmDocument::GetShaDict()
+gdcmDictgdcmDocument::GetShaDict()
 {
    return RefShaDict;
 }
@@ -452,6 +449,22 @@ bool gdcmDocument::IsJPEG2000()
            || IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_91) );
 }
 
+/**
+ * \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 gdcmDocument::IsEncapsulateTransferSyntax()
+{
+   return (   IsJPEGBaseLineProcess1TransferSyntax()
+           || IsJPEGExtendedProcess2_4TransferSyntax()
+           || IsJPEGExtendedProcess3_5TransferSyntax()
+           || IsJPEGSpectralSelectionProcess6_8TransferSyntax()
+           || IsRLELossLessTransferSyntax()
+           || IsJPEGLossless()
+           || IsJPEG2000() );
+}
+
 /**
  * \brief   Predicate for dicom version 3 file.
  * @return  True when the file is a dicom version 3.
@@ -540,13 +553,10 @@ bool gdcmDocument::CloseFile()
 void gdcmDocument::Write(FILE* fp,FileType filetype)
 {
    /// \todo move the following lines (and a lot of others, to be written)
-   /// to a future function CheckAndCorrectHeader
-   
-   /// WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA
-   /// no way (check : FileType est un champ de gdcmDocument ...)
-   /// a moins de se livrer a un tres complique ajout des champs manquants.
-   /// faire un CheckAndCorrectHeader (?) 
+   /// to a future function CheckAndCorrectHeader  
+   /// (necessary if user wants to write a DICOM V3 file
+   /// starting from an  ACR-NEMA (V2)  gdcmHeader
+
    if (filetype == gdcmImplicitVR) 
    {
       std::string implicitVRTransfertSyntax = UI1_2_840_10008_1_2;
@@ -595,22 +605,37 @@ void gdcmDocument::Write(FILE* fp,FileType filetype)
  * @param   value (string) Value to be set
  * @param   group   Group number of the Entry 
  * @param   elem  Element number of the Entry
+ * @param   VR  V(alue) R(epresentation) of the Entry -if private Entry-
  * \return  pointer to the modified/created Header Entry (NULL when creation
  *          failed).
- */
-  
-gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber(
+ */ 
+gdcmValEntry* gdcmDocument::ReplaceOrCreateByNumber(
                                          std::string const & value, 
                                          uint16_t group, 
-                                         uint16_t elem )
+                                         uint16_t elem,
+                                         std::string const & VR )
 {
    gdcmValEntry* valEntry = 0;
    gdcmDocEntry* currentEntry = GetDocEntryByNumber( group, elem);
    
    if (!currentEntry)
    {
-      // The entry wasn't present and we simply create the required ValEntry:
-      currentEntry = NewDocEntryByNumber(group, elem);
+      // check if (group,element) DictEntry exists
+      // if it doesn't, create an entry in gdcmDictSet::VirtualEntry
+      // and use it
+
+   // Find out if the tag we received is in the dictionaries:
+      gdcmDict *pubDict = gdcmGlobal::GetDicts()->GetDefaultPubDict();
+      gdcmDictEntry* dictEntry = pubDict->GetDictEntryByNumber(group, elem);
+      if (!dictEntry)
+      {
+         currentEntry = NewDocEntryByNumber(group, elem,VR);
+      }
+      else
+      {
+         currentEntry = NewDocEntryByNumber(group, elem);
+      }
+
       if (!currentEntry)
       {
          dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: call to"
@@ -653,33 +678,27 @@ gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber(
    return valEntry;
 }   
 
-/**
+/*
  * \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   VR  V(alue) R(epresentation) of the Entry -if private Entry-
+ * @param   binArea (binary) 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).
  */
- // TODO : write something clever, using default value for VR
- //        to avoid code duplication
- //        (I don't know how to tell NewDocEntryByNumber
- //         that ReplaceOrCreateByNumber  was called with a default value)
-gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber(
-                                         std::string const & value, 
+gdcmBinEntry* gdcmDocument::ReplaceOrCreateByNumber(
+                                         uint8_t* binArea,
+                                         int lgth, 
                                          uint16_t group, 
                                          uint16_t elem,
-                                         std::string const & VR )
+                                         std::string const& VR )
 {
-   gdcmValEntry* valEntry = 0;
+   gdcmBinEntry* binEntry = 0;
    gdcmDocEntry* currentEntry = GetDocEntryByNumber( group, elem);
-   
    if (!currentEntry)
    {
+
       // check if (group,element) DictEntry exists
       // if it doesn't, create an entry in gdcmDictSet::VirtualEntry
       // and use it
@@ -687,23 +706,23 @@ gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber(
    // Find out if the tag we received is in the dictionaries:
       gdcmDict *pubDict = gdcmGlobal::GetDicts()->GetDefaultPubDict();
       gdcmDictEntry *dictEntry = pubDict->GetDictEntryByNumber(group, elem);
+
       if (!dictEntry)
       {
-         currentEntry = NewDocEntryByNumber(group, elem,VR);
+         currentEntry = NewDocEntryByNumber(group, elem, VR);
       }
       else
       {
          currentEntry = NewDocEntryByNumber(group, elem);
       }
-
       if (!currentEntry)
       {
          dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: call to"
                         " NewDocEntryByNumber failed.");
          return NULL;
       }
-      valEntry = new gdcmValEntry(currentEntry);
-      if ( !AddEntry(valEntry))
+      binEntry = new gdcmBinEntry(currentEntry);
+      if ( !AddEntry(binEntry))
       {
          dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: AddEntry"
                         " failed allthough this is a creation.");
@@ -711,66 +730,31 @@ gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber(
    }
    else
    {
-      valEntry = dynamic_cast< gdcmValEntry* >(currentEntry);
-      if ( !valEntry ) // Euuuuh? It wasn't a ValEntry
-                       // then we change it to a ValEntry ?
+      binEntry = dynamic_cast< gdcmBinEntry* >(currentEntry);
+      if ( !binEntry ) // Euuuuh? It wasn't a BinEntry
+                       // then we change it to a BinEntry ?
                        // Shouldn't it be considered as an error ?
       {
-         // We need to promote the gdcmDocEntry to a gdcmValEntry:
-         valEntry = new gdcmValEntry(currentEntry);
+         // We need to promote the gdcmDocEntry to a gdcmBinEntry:
+         binEntry = new gdcmBinEntry(currentEntry);
          if (!RemoveEntry(currentEntry))
          {
             dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: removal"
                            " of previous DocEntry failed.");
             return NULL;
          }
-         if ( !AddEntry(valEntry))
+         if ( !AddEntry(binEntry))
          {
             dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: adding"
-                           " promoted ValEntry failed.");
+                           " promoted BinEntry failed.");
             return NULL;
          }
       }
    }
 
-   SetEntryByNumber(value, group, elem);
-
-   return valEntry;
-}   
-
-/*
- * \brief   Modifies the value of a given Header Entry (Dicom Element)
- *          when it exists. Create it with the given value when unexistant.
- * @param   voidArea (binary) 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).
- */
-gdcmBinEntry * gdcmDocument::ReplaceOrCreateByNumber(
-                                         void *voidArea,
-                                         int lgth, 
-                                         uint16_t group, 
-                                         uint16_t elem)
-{
-   gdcmBinEntry* b = 0;
-   gdcmDocEntry* a = GetDocEntryByNumber( group, elem);
-   if (!a)
-   {
-      a = NewBinEntryByNumber(group, elem);
-      if (!a)
-      {
-         return 0;
-      }
-
-      b = new gdcmBinEntry(a);
-      AddEntry(b);
-      b->SetVoidArea(voidArea);
-   } 
-
-   SetEntryByNumber(voidArea, lgth, group, elem);
+   SetEntryByNumber(binArea, lgth, group, elem);
 
-   return b;
+   return binEntry;
 }  
 
 
@@ -782,7 +766,7 @@ gdcmBinEntry * gdcmDocument::ReplaceOrCreateByNumber(
  * \return  pointer to the modified/created SeqEntry (NULL when creation
  *          failed).
  */
-gdcmSeqEntry * gdcmDocument::ReplaceOrCreateByNumber(
+gdcmSeqEntry* gdcmDocument::ReplaceOrCreateByNumber(
                                          uint16_t group, 
                                          uint16_t elem)
 {
@@ -842,9 +826,9 @@ bool gdcmDocument::CheckIfEntryExistByNumber(uint16_t group, uint16_t element )
  * @return  Corresponding element value when it exists,
  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
  */
-std::string gdcmDocument::GetEntryByName(TagName const & tagName)
+std::string gdcmDocument::GetEntryByName(TagName const& tagName)
 {
-   gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
+   gdcmDictEntrydictEntry = RefPubDict->GetDictEntryByName(tagName); 
    if( !dictEntry )
    {
       return GDCM_UNFOUND;
@@ -866,7 +850,7 @@ std::string gdcmDocument::GetEntryByName(TagName const & tagName)
  * @return  Corresponding element value representation when it exists,
  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
  */
-std::string gdcmDocument::GetEntryVRByName(TagName const & tagName)
+std::string gdcmDocument::GetEntryVRByName(TagName const& tagName)
 {
    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
    if( dictEntry == NULL)
@@ -879,7 +863,6 @@ std::string gdcmDocument::GetEntryVRByName(TagName const & tagName)
    return elem->GetVR();
 }
 
-
 /**
  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
  *          the public and private dictionaries 
@@ -968,7 +951,7 @@ bool gdcmDocument::SetEntryByName(std::string const & content,std::string const
  * @param   group     group number of the Dicom Element to modify
  * @param   element element number of the Dicom Element to modify
  */
-bool gdcmDocument::SetEntryByNumber(std::string const & content, 
+bool gdcmDocument::SetEntryByNumber(std::string const& content, 
                                     uint16_t group,
                                     uint16_t element) 
 {
@@ -1015,12 +998,12 @@ bool gdcmDocument::SetEntryByNumber(std::string const & content,
  * \brief   Accesses an existing gdcmDocEntry (i.e. a Dicom Element)
  *          through it's (group, element) and modifies it's content with
  *          the given value.
- * @param   content new value (void *) to substitute with
+ * @param   content new value (void*  -> uint8_t*) to substitute with
  * @param   lgth new value length
  * @param   group     group number of the Dicom Element to modify
  * @param   element element number of the Dicom Element to modify
  */
-bool gdcmDocument::SetEntryByNumber(void *content,
+bool gdcmDocument::SetEntryByNumber(uint8_t*content,
                                     int lgth, 
                                     uint16_t group,
                                     uint16_t element) 
@@ -1040,8 +1023,9 @@ bool gdcmDocument::SetEntryByNumber(void *content,
    }
 */      
    gdcmBinEntry* a = (gdcmBinEntry *)TagHT[key];           
-   a->SetVoidArea(content);  
+   a->SetBinArea(content);  
    a->SetLength(lgth);
+   a->SetValue(GDCM_BINLOADED);
 
    return true;
 } 
@@ -1101,7 +1085,7 @@ size_t gdcmDocument::GetEntryOffsetByNumber(uint16_t group, uint16_t elem)
  * @param elem  element number of the Entry
  * @return Pointer to the 'non string' area
  */
-void * gdcmDocument::GetEntryVoidAreaByNumber(uint16_t group, uint16_t elem) 
+void*  gdcmDocument::GetEntryBinAreaByNumber(uint16_t group, uint16_t elem) 
 {
    gdcmDocEntry* entry = GetDocEntryByNumber(group, elem);
    if (!entry) 
@@ -1109,7 +1093,7 @@ void * gdcmDocument::GetEntryVoidAreaByNumber(uint16_t group, uint16_t elem)
       dbg.Verbose(1, "gdcmDocument::GetDocEntryByNumber: no entry");
       return 0;
    }
-   return ((gdcmBinEntry *)entry)->GetVoidArea();
+   return ((gdcmBinEntry *)entry)->GetBinArea();
 }
 
 /**
@@ -1118,7 +1102,7 @@ void * gdcmDocument::GetEntryVoidAreaByNumber(uint16_t group, uint16_t elem)
  * @param group   group number of the Entry 
  * @param elem  element number of the Entry
  */
-void* gdcmDocument::LoadEntryVoidArea(uint16_t group, uint16_t elem)
+void* gdcmDocument::LoadEntryBinArea(uint16_t group, uint16_t elem)
 {
    gdcmDocEntry *docElement = GetDocEntryByNumber(group, elem);
    if ( !docElement )
@@ -1128,10 +1112,10 @@ void* gdcmDocument::LoadEntryVoidArea(uint16_t group, uint16_t elem)
    size_t o =(size_t)docElement->GetOffset();
    fseek(Fp, o, SEEK_SET);
    size_t l = docElement->GetLength();
-   char* a = new char[l];
+   uint8_t* a = new uint8_t[l];
    if(!a)
    {
-      dbg.Verbose(0, "gdcmDocument::LoadEntryVoidArea cannot allocate a");
+      dbg.Verbose(0, "gdcmDocument::LoadEntryBinArea cannot allocate a");
       return NULL;
    }
    size_t l2 = fread(a, 1, l , Fp);
@@ -1140,31 +1124,30 @@ void* gdcmDocument::LoadEntryVoidArea(uint16_t group, uint16_t elem)
       delete[] a;
       return NULL;
    }
-   /// \TODO Drop any already existing void area! JPR
-   if( !SetEntryVoidAreaByNumber( a, group, elem ) );
+   /// \todo Drop any already existing void area! JPR
+   if( !SetEntryBinAreaByNumber( a, group, elem ) );
    {
-      dbg.Verbose(0, "gdcmDocument::LoadEntryVoidArea setting failed.");
+      dbg.Verbose(0, "gdcmDocument::LoadEntryBinArea setting failed.");
    }
-
    return a;
 }
 /**
  * \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 binArea is going to be loaded
  */
-void *gdcmDocument::LoadEntryVoidArea(gdcmBinEntry *element) 
+void* gdcmDocument::LoadEntryBinArea(gdcmBinEntry* element) 
 {
    size_t o =(size_t)element->GetOffset();
    fseek(Fp, o, SEEK_SET);
    size_t l = element->GetLength();
-   char* a = new char[l];
+   uint8_t* a = new uint8_t[l];
    if( !a )
    {
-      dbg.Verbose(0, "gdcmDocument::LoadEntryVoidArea cannot allocate a");
+      dbg.Verbose(0, "gdcmDocument::LoadEntryBinArea cannot allocate a");
       return NULL;
    }
-   element->SetVoidArea((void *)a);
+   element->SetBinArea((uint8_t*)a);
    /// \todo check the result 
    size_t l2 = fread(a, 1, l , Fp);
    if( l != l2 )
@@ -1183,7 +1166,7 @@ void *gdcmDocument::LoadEntryVoidArea(gdcmBinEntry *element)
  * @param   element Element number of the searched Dicom Element 
  * @return  
  */
-bool gdcmDocument::SetEntryVoidAreaByNumber(void * area,
+bool gdcmDocument::SetEntryBinAreaByNumber(uint8_t* area,
                                             uint16_t group, 
                                             uint16_t element) 
 {
@@ -1194,7 +1177,7 @@ bool gdcmDocument::SetEntryVoidAreaByNumber(void * area,
    }
    if ( gdcmBinEntry* binEntry = dynamic_cast<gdcmBinEntry*>(currentEntry) )
    {
-      binEntry->SetVoidArea( area );
+      binEntry->SetBinArea( area );
       return true;
    }
    return true;
@@ -1394,16 +1377,13 @@ uint16_t gdcmDocument::UnswapShort(uint16_t a)
  * \brief   Parses a DocEntrySet (Zero-level DocEntries or SQ Item DocEntries)
  * @return  length of the parsed set. 
  */ 
-
-long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
+void gdcmDocument::ParseDES(gdcmDocEntrySet *set,
                             long offset,
                             long l_max,
                             bool delim_mode)
 {
    gdcmDocEntry *newDocEntry = 0;
-   unsigned long l = 0;
    
-   int depth = set->GetDepthLevel();
    while (true)
    { 
       if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
@@ -1422,11 +1402,27 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
                
          if ( gdcmGlobal::GetVR()->IsVROfGdcmStringRepresentable(vr) )
          {
-            /////// ValEntry
+         /////////////////////// ValEntry
             gdcmValEntry* newValEntry =
                new gdcmValEntry( newDocEntry->GetDictEntry() );
             newValEntry->Copy( newDocEntry );
-            newValEntry->SetKey( set->GetBaseTagKey() + newValEntry->GetKey() );
+             
+            // When "set" is a gdcmDocument, then we are at the top of the
+            // hierarchy and the Key is simply of the form ( group, elem )...
+            if (gdcmDocument* dummy = dynamic_cast< gdcmDocument* > ( set ) )
+            {
+               (void)dummy;
+               newValEntry->SetKey( newValEntry->GetKey() );
+            }
+            // ...but when "set" is a gdcmSQItem, we are inserting this new
+            // valEntry in a sequence item. Hence the key has the
+            // generalized form (refer to \ref gdcmBaseTagKey):
+            if (gdcmSQItem* parentSQItem = dynamic_cast< gdcmSQItem* > ( set ) )
+            {
+               newValEntry->SetKey(  parentSQItem->GetBaseTagKey()
+                                   + newValEntry->GetKey() );
+            }
+             
             set->AddEntry( newValEntry );
             LoadDocEntry( newValEntry );
             if (newValEntry->IsItemDelimitor())
@@ -1447,11 +1443,26 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
                                "nor BinEntry. Probably unknown VR.");
             }
 
-            ////// BinEntry or UNKOWN VR:
+         //////////////////// BinEntry or UNKOWN VR:
             gdcmBinEntry* newBinEntry =
                new gdcmBinEntry( newDocEntry->GetDictEntry() );
             newBinEntry->Copy( newDocEntry );
-            newBinEntry->SetKey( set->GetBaseTagKey() + newBinEntry->GetKey() );
+
+            // When "this" is a gdcmDocument the Key is simply of the
+            // form ( group, elem )...
+            if (gdcmDocument* dummy = dynamic_cast< gdcmDocument* > ( set ) )
+            {
+               newBinEntry->SetKey( newBinEntry->GetKey() );
+            }
+            // but when "this" is a SQItem, we are inserting this new
+            // valEntry in a sequence item, and the kay has the
+            // generalized form (refer to \ref gdcmBaseTagKey):
+            if (gdcmSQItem* parentSQItem = dynamic_cast< gdcmSQItem* > ( set ) )
+            {
+               newBinEntry->SetKey(  parentSQItem->GetBaseTagKey()
+                                   + newBinEntry->GetKey() );
+            }
+
             set->AddEntry( newBinEntry );
             LoadDocEntry( newBinEntry );
          }
@@ -1459,29 +1470,28 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
          if (newDocEntry->GetGroup()   == 0x7fe0 && 
              newDocEntry->GetElement() == 0x0010 )
          {
-             if (newDocEntry->GetReadLength()==0xffffffff)
+             if ( IsRLELossLessTransferSyntax() ) 
              {
-                // Broken US.3405.1.dcm
-                Parse7FE0(); // to skip the pixels 
-                             // (multipart JPEG/RLE are trouble makers)
+                long PositionOnEntry = ftell(Fp);
+                fseek(Fp, newDocEntry->GetOffset(), SEEK_SET);
+                ComputeRLEInfo();
+                fseek(Fp, PositionOnEntry, SEEK_SET);
              }
              else
              {
                 SkipToNextDocEntry(newDocEntry);
-                l = newDocEntry->GetFullLength(); 
              }
          }
          else
          {
              // to be sure we are at the beginning 
              SkipToNextDocEntry(newDocEntry);
-             l = newDocEntry->GetFullLength(); 
          }
       }
       else
       {
          // VR = "SQ"
-         l = newDocEntry->GetReadLength();            
+         unsigned long l = newDocEntry->GetReadLength();            
          if ( l != 0 ) // don't mess the delim_mode for zero-length sequence
          {
             if ( l == 0xffffffff )
@@ -1495,18 +1505,35 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
          }
          // no other way to create it ...
          gdcmSeqEntry* newSeqEntry =
-            new gdcmSeqEntry( newDocEntry->GetDictEntry(),
-                              set->GetDepthLevel() );
+            new gdcmSeqEntry( newDocEntry->GetDictEntry() );
          newSeqEntry->Copy( newDocEntry );
          newSeqEntry->SetDelimitorMode( delim_mode );
-         newSeqEntry->SetDepthLevel( depth );
-         newSeqEntry->SetKey( set->GetBaseTagKey() + newSeqEntry->GetKey() );
+
+         // At the top of the hierarchy, stands a gdcmDocument. When "set"
+         // is a gdcmDocument, then we are building the first depth level.
+         // Hence the gdcmSeqEntry we are building simply has a depth
+         // level of one:
+         if (gdcmDocument* dummy = dynamic_cast< gdcmDocument* > ( set ) )
+         {
+            (void)dummy;
+            newSeqEntry->SetDepthLevel( 1 );
+            newSeqEntry->SetKey( newSeqEntry->GetKey() );
+         }
+         // But when "set" is allready a SQItem, we are building a nested
+         // sequence, and hence the depth level of the new gdcmSeqEntry
+         // we are building, is one level deeper:
+         if (gdcmSQItem* parentSQItem = dynamic_cast< gdcmSQItem* > ( set ) )
+         {
+            newSeqEntry->SetDepthLevel( parentSQItem->GetDepthLevel() + 1 );
+            newSeqEntry->SetKey(  parentSQItem->GetBaseTagKey()
+                                + newSeqEntry->GetKey() );
+         }
 
          if ( l != 0 )
          {  // Don't try to parse zero-length sequences
-            (void)ParseSQ( newSeqEntry, 
-                           newDocEntry->GetOffset(),
-                           l, delim_mode);
+            ParseSQ( newSeqEntry, 
+                     newDocEntry->GetOffset(),
+                     l, delim_mode);
          }
          set->AddEntry( newSeqEntry );
          if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
@@ -1516,14 +1543,13 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
       }
       delete newDocEntry;
    }
-   return l; // Probably useless 
 }
 
 /**
  * \brief   Parses a Sequence ( SeqEntry after SeqEntry)
  * @return  parsed length for this level
  */ 
-long gdcmDocument::ParseSQ( gdcmSeqEntry* seqEntry,
+void gdcmDocument::ParseSQ( gdcmSeqEntry* seqEntry,
                             long offset, long l_max, bool delim_mode)
 {
    int SQItemNumber = 0;
@@ -1568,7 +1594,7 @@ long gdcmDocument::ParseSQ( gdcmSeqEntry* seqEntry,
          dlm_mod = false;
       }
    
-      (void)ParseDES(itemSQ, newDocEntry->GetOffset(), l, dlm_mod);
+      ParseDES(itemSQ, newDocEntry->GetOffset(), l, dlm_mod);
       
       seqEntry->AddEntry( itemSQ, SQItemNumber ); 
       SQItemNumber++;
@@ -1577,9 +1603,6 @@ long gdcmDocument::ParseSQ( gdcmSeqEntry* seqEntry,
          break;
       }
    }
-
-   int lgth = ftell(Fp) - offset;
-   return lgth;
 }
 
 /**
@@ -1654,9 +1677,9 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry)
    // When we find a BinEntry not very much can be done :
    if (gdcmBinEntry* binEntryPtr = dynamic_cast< gdcmBinEntry* >(entry) )
    {
-      s << "gdcm::Loaded (BinEntry)";
+      s << GDCM_BINLOADED;
       binEntryPtr->SetValue(s.str());
-      LoadEntryVoidArea(binEntryPtr); // last one, not to erase length !
+      LoadEntryBinArea(binEntryPtr); // last one, not to erase length !
       return;
    }
     
@@ -1761,17 +1784,19 @@ void gdcmDocument::FindDocEntryLength( gdcmDocEntry *entry )
    {
       if ( vr == "OB" || vr == "OW" || vr == "SQ" || vr == "UN" ) 
       {
-         // The following reserved two bytes (see PS 3.5-2001, section
-         // 7.1.2 Data element structure with explicit vr p27) must be
+         // The following reserved two bytes (see PS 3.5-2003, section
+         // "7.1.2 Data element structure with explicit vr", p 27) must be
          // skipped before proceeding on reading the length on 4 bytes.
          fseek(Fp, 2L, SEEK_CUR);
          uint32_t length32 = ReadInt32();
 
-         if ( vr == "OB" && length32 == 0xffffffff ) 
+         if ( (vr == "OB" || vr == "OW") && length32 == 0xffffffff ) 
          {
             uint32_t lengthOB;
             try 
             {
+               /// \todo rename that to FindDocEntryLengthOBOrOW since
+               ///       the above test is on both OB and OW...
                lengthOB = FindDocEntryLengthOB();
             }
             catch ( gdcmFormatUnexpected )
@@ -2802,110 +2827,213 @@ uint32_t gdcmDocument::ReadTagLength(uint16_t testGroup, uint16_t testElement)
 }
 
 /**
- * \brief   Parse pixel data from disk for multi-fragment Jpeg/Rle files
- *          No other way so 'skip' the Data
- *
+ * \brief Parse pixel data from disk of [multi-]fragment RLE encoding.
+ *        Compute the RLE extra information and store it in \ref RLEInfo
+ *        for later pixel retrieval usage.
  */
-void gdcmDocument::Parse7FE0 ()
+void gdcmDocument::ComputeRLEInfo()
 {
-   gdcmDocEntry* element = GetDocEntryByNumber(0x0002, 0x0010);
-   if ( !element )
-   {
-      // Should warn user FIXME
-      return;
-   }
-      
-   if (   IsImplicitVRLittleEndianTransferSyntax()
-       || IsExplicitVRLittleEndianTransferSyntax()
-       || IsExplicitVRBigEndianTransferSyntax() /// \todo 1.2.2 ??? A verifier !
-       || IsDeflatedExplicitVRLittleEndianTransferSyntax() )
+   if ( ! IsRLELossLessTransferSyntax() )
    {
       return;
    }
-
-   // ---------------- for Parsing : Position on begining of Jpeg/RLE Pixels 
+   // Encoded pixel data: for the time being we are only concerned with
+   // Jpeg or RLE Pixel data encodings.
+   // As stated in PS 3.5-2003, section 8.2 p44:
+   // "If sent in Encapsulated Format (i.e. other than the Native Format) the
+   //  value representation OB is used".
+   // Hence we expect an OB value representation. Concerning OB VR,
+   // the section PS 3.5-2003, section A.4.c p 58-59, states:
+   // "For the Value Representations OB and OW, the encoding shall meet the
+   //   following specifications depending on the Data element tag:"
+   //   [...snip...]
+   //    - the first item in the sequence of items before the encoded pixel
+   //      data stream shall be basic offset table item. The basic offset table
+   //      item value, however, is not required to be present"
 
    //// Read the Basic Offset Table Item Tag length...
    uint32_t itemLength = ReadTagLength(0xfffe, 0xe000);
 
-   //// ... and then read length[s] itself[themselves]. We don't use
-   // the values read (BTW  what is the purpous of those lengths ?)
+   // When present, read the basic offset table itself.
+   // Notes: - since the presence of this basic offset table is optional
+   //          we can't rely on it for the implementation, and we will simply
+   //          trash it's content (when present).
+   //        - still, when present, we could add some further checks on the
+   //          lengths, but we won't bother with such fuses for the time being.
    if ( itemLength != 0 )
    {
-      // BTW, what is the purpous of those length anyhow !? 
       char* basicOffsetTableItemValue = new char[itemLength + 1];
       fread(basicOffsetTableItemValue, itemLength, 1, Fp);
 
       for (unsigned int i=0; i < itemLength; i += 4 )
       {
-         uint32_t individualLength = str2num(&basicOffsetTableItemValue[i],uint32_t);
+         uint32_t individualLength = str2num( &basicOffsetTableItemValue[i],
+                                              uint32_t);
          std::ostringstream s;
          s << "   Read one length: ";
          s << std::hex << individualLength << std::endl;
-         dbg.Verbose(0, "gdcmDocument::Parse7FE0: ", s.str().c_str());
+         dbg.Verbose(0, "gdcmDocument::ComputeRLEInfo: ", s.str().c_str());
       }
       delete[] basicOffsetTableItemValue;
    }
 
-   if ( ! IsRLELossLessTransferSyntax() )
-   {
-      // JPEG Image
-      
-      //// We then skip (not reading them) all the fragments of images:
-      while ( (itemLength = ReadTagLength(0xfffe, 0xe000)) )
+   // Encapsulated RLE Compressed Images (see PS 3.5-2003, Annex G)
+   // Loop on the frame[s] and store the parsed information in a
+   // gdcmRLEFramesInfo.
+   long frameLength;
+
+   // Loop on the individual frame[s] and store the information
+   // on the RLE fragments in a gdcmRLEFramesInfo.
+   // Note: - when only a single frame is present, this is a
+   //         classical image.
+   //       - when more than one frame are present, then we are in 
+   //         the case of a multi-frame image.
+   while ( (frameLength = ReadTagLength(0xfffe, 0xe000)) )
+   { 
+      // Parse the RLE Header and store the corresponding RLE Segment
+      // Offset Table information on fragments of this current Frame.
+      // Note that the fragment pixels themselves are not loaded
+      // (but just skipped).
+      long frameOffset = ftell(Fp);
+
+      uint32_t nbRleSegments = ReadInt32();
+      uint32_t rleSegmentOffsetTable[15];
+      for( int k = 1; k <= 15; k++ )
       {
-         SkipBytes(itemLength);
+         rleSegmentOffsetTable[k] = ReadInt32();
       }
+
+      // Deduce from both the RLE Header and the frameLength the
+      // fragment length, and again store this info in a
+      // gdcmRLEFramesInfo.
+      long rleSegmentLength[15];
+      // skipping (not reading) RLE Segments
+      if ( nbRleSegments > 1)
+      {
+         for(unsigned int k = 1; k <= nbRleSegments-1; k++)
+         {
+             rleSegmentLength[k] =  rleSegmentOffsetTable[k+1]
+                                  - rleSegmentOffsetTable[k];
+             SkipBytes(rleSegmentLength[k]);
+          }
+       }
+
+       rleSegmentLength[nbRleSegments] = frameLength 
+                                      - rleSegmentOffsetTable[nbRleSegments];
+       SkipBytes(rleSegmentLength[nbRleSegments]);
+
+       // Store the collected info
+       gdcmRLEFrame* newFrameInfo = new gdcmRLEFrame;
+       newFrameInfo->NumberFragments = nbRleSegments;
+       for( unsigned int uk = 1; uk <= nbRleSegments; uk++ )
+       {
+          newFrameInfo->Offset[uk] = frameOffset + rleSegmentOffsetTable[uk];
+          newFrameInfo->Length[uk] = rleSegmentLength[uk];
+       }
+       RLEInfo.Frames.push_back( newFrameInfo );
    }
-   else
+
+   // Make sure that at the end of the item we encounter a 'Sequence
+   // Delimiter Item':
+   if ( !ReadTag(0xfffe, 0xe0dd) )
    {
-      // RLE Image
-      long ftellRes;
-      long rleSegmentLength[15], fragmentLength;
+      dbg.Verbose(0, "gdcmDocument::ComputeRLEInfo: no sequence delimiter ");
+      dbg.Verbose(0, "    item at end of RLE item sequence");
+   }
+}
 
-      // While we find some items:
-      while ( (fragmentLength = ReadTagLength(0xfffe, 0xe000)) )
-      { 
-         // Parse fragments of the current Fragment (Frame)    
-         //------------------ scanning (not reading) fragment pixels
-         uint32_t nbRleSegments = ReadInt32();
-         //// Reading RLE Segments Offset Table
-         uint32_t rleSegmentOffsetTable[15];
-         for(int k=1; k<=15; k++)
+/**
+ * \brief Walk recursively the given \ref gdcmDocEntrySet, and feed
+ *        the given hash table (\ref TagDocEntryHT) with all the
+ *        \ref gdcmDocEntry (Dicom entries) encountered.
+ *        This method does the job for \ref BuildFlatHashTable.
+ * @param builtHT Where to collect all the \ref gdcmDocEntry encountered
+ *        when recursively walking the given set.
+ * @param set The structure to be traversed (recursively).
+ */
+void gdcmDocument::BuildFlatHashTableRecurse( TagDocEntryHT& builtHT,
+                                              gdcmDocEntrySet* set )
+{ 
+   if (gdcmElementSet* elementSet = dynamic_cast< gdcmElementSet* > ( set ) )
+   {
+      TagDocEntryHT* currentHT = elementSet->GetTagHT();
+      for( TagDocEntryHT::const_iterator i  = currentHT->begin();
+                                         i != currentHT->end();
+                                       ++i)
+      {
+         gdcmDocEntry* entry = i->second;
+         if ( gdcmSeqEntry* seqEntry = dynamic_cast<gdcmSeqEntry*>(entry) )
          {
-            ftellRes = ftell(Fp);
-            rleSegmentOffsetTable[k] = ReadInt32();
+            ListSQItem& items = seqEntry->GetSQItems();
+            for( ListSQItem::const_iterator item  = items.begin();
+                                            item != items.end();
+                                          ++item)
+            {
+               BuildFlatHashTableRecurse( builtHT, *item );
+            }
+            continue;
          }
+         builtHT[entry->GetKey()] = entry;
+      }
+      return;
+    }
 
-         // skipping (not reading) RLE Segments
-         if ( nbRleSegments > 1)
+   if (gdcmSQItem* SQItemSet = dynamic_cast< gdcmSQItem* > ( set ) )
+   {
+      ListDocEntry& currentList = SQItemSet->GetDocEntries();
+      for (ListDocEntry::iterator i  = currentList.begin();
+                                  i != currentList.end();
+                                ++i)
+      {
+         gdcmDocEntry* entry = *i;
+         if ( gdcmSeqEntry* seqEntry = dynamic_cast<gdcmSeqEntry*>(entry) )
          {
-            for(unsigned int k = 1; k <= nbRleSegments-1; k++)
+            ListSQItem& items = seqEntry->GetSQItems();
+            for( ListSQItem::const_iterator item  = items.begin();
+                                            item != items.end();
+                                          ++item)
             {
-                rleSegmentLength[k] =  rleSegmentOffsetTable[k+1]
-                                     - rleSegmentOffsetTable[k];
-                ftellRes = ftell(Fp);
-                SkipBytes(rleSegmentLength[k]);
-             }
-          }
-
-          rleSegmentLength[nbRleSegments] = fragmentLength 
-                                          - rleSegmentOffsetTable[nbRleSegments];
-          ftellRes = ftell(Fp);
-          SkipBytes(rleSegmentLength[nbRleSegments]);
+               BuildFlatHashTableRecurse( builtHT, *item );
+            }
+            continue;
+         }
+         builtHT[entry->GetKey()] = entry;
       }
 
-      // Make sure that at the end of the item we encounter a 'Sequence
-      // Delimiter Item':
-      if ( !ReadTag(0xfffe, 0xe0dd) )
-      {
-         dbg.Verbose(0, "gdcmDocument::Parse7FE0: no sequence delimiter item");
-         dbg.Verbose(0, "    at end of RLE item sequence");
-      }
    }
 }
 
+/**
+ * \brief Build a \ref TagDocEntryHT (i.e. a std::map<>) from the current
+ *        gdcmDocument.
+ *
+ *        The structure used by a gdcmDocument (through \ref gdcmElementSet),
+ *        in order to old the parsed entries of a Dicom header, is a recursive
+ *        one. This is due to the fact that the sequences (when present)
+ *        can be nested. Additionaly, the sequence items (represented in
+ *        gdcm as \ref gdcmSQItem) add an extra complexity to the data
+ *        structure. Hence, a gdcm user whishing to visit all the entries of
+ *        a Dicom header will need to dig in the gdcm internals (which
+ *        implies exposing all the internal data structures to the API).
+ *        In order to avoid this burden to the user, \ref BuildFlatHashTable
+ *        recursively builds a temporary hash table, which holds all the
+ *        Dicom entries in a flat structure (a \ref TagDocEntryHT i.e. a
+ *        std::map<>).
+ * \warning Of course there is NO integrity constrain between the 
+ *        returned \ref TagDocEntryHT and the \ref gdcmElementSet used
+ *        to build it. Hence if the underlying \ref gdcmElementSet is
+ *        altered, then it is the caller responsability to invoke 
+ *        \ref BuildFlatHashTable again...
+ * @return The flat std::map<> we juste build.
+ */
+TagDocEntryHT* gdcmDocument::BuildFlatHashTable()
+{
+   TagDocEntryHT* FlatHT = new TagDocEntryHT;
+   BuildFlatHashTableRecurse( *FlatHT, this );
+   return FlatHT;
+}
+
 
 
 /**