]> Creatis software - gdcm.git/blobdiff - src/gdcmDocument.cxx
* ENH: added some utility method that builds a flat dictionnary
[gdcm.git] / src / gdcmDocument.cxx
index 86d8838f3f8f40504f8b8788deab3d40bff6ce78..16adce6fa9f73eb7c9a63c7058b7094c6276c464 100644 (file)
@@ -3,8 +3,8 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmDocument.cxx,v $
   Language:  C++
-  Date:      $Date: 2004/07/19 03:34:11 $
-  Version:   $Revision: 1.50 $
+  Date:      $Date: 2004/09/17 13:11:16 $
+  Version:   $Revision: 1.81 $
                                                                                 
   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:
@@ -82,37 +81,20 @@ 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
- * @param   enable_sequences = true to allow the header 
- *          to be parsed *inside* the SeQuences,
- *          when they have an actual length 
- * \warning enable_sequences *has to be* true for reading PAPYRUS 3.0 files 
- * @param   ignore_shadow to allow skipping the shadow elements, 
- *          to save memory space.
- * \warning The TRUE value for this param has to be used 
- *          with a FALSE value for the 'enable_sequence' param.
- *          ('public elements' may be embedded in 'shadow Sequences')
- */
-gdcmDocument::gdcmDocument( std::string const & filename, 
-                            bool exception_on_error,
-                            bool enable_sequences,
-                            bool ignore_shadow) 
+ * @param   filename file to be opened for parsing
+ */
+gdcmDocument::gdcmDocument( std::string const & filename ) 
               : gdcmElementSet(-1)
 {
-   IgnoreShadow = ignore_shadow;
-   //EnableSequences=enable_sequences;
-   (void)enable_sequences;
-   EnableSequences = true; // JPR // TODO : remove params out of the constructor
    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);
@@ -125,10 +107,7 @@ gdcmDocument::gdcmDocument( std::string const & filename,
    long beg = ftell(Fp);
    lgt -= beg;
    
-   SQDepthLevel=0;
-   
-   long l = ParseDES( this, beg, lgt, false); // le Load sera fait a la volee
-   (void)l; //is l used anywhere ?
+   (void)ParseDES( this, beg, lgt, false); // le Load sera fait a la volee
 
    rewind(Fp);
    
@@ -138,13 +117,31 @@ gdcmDocument::gdcmDocument( std::string const & filename,
    if( PhotometricInterpretation == "PALETTE COLOR " )
    {
       LoadEntryVoidArea(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
+      /// dictionnary. BUT the semantics implied by the three following
+      /// lines state that the corresponding tag contents are in fact
+      /// the ones of a gdcmBinEntry.
+      /// In order to fix things "Quick and Dirty" the dictionnary was
+      /// altered on PURPOUS but now contains a WRONG value.
+      /// In order to fix things and restore the dictionary to its
+      /// correct value, one needs to decided of the semantics by deciding
+      /// wether the following tags are either:
+      /// - multivaluated US, and hence loaded as gdcmValEntry, but afterwards
+      ///   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
       
-      LoadEntryVoidArea(0x0028,0x1221);  // Segmented Red   Palette Color LUT Data
-      LoadEntryVoidArea(0x0028,0x1222);  // Segmented Green Palette Color LUT Data
-      LoadEntryVoidArea(0x0028,0x1223);  // Segmented Blue  Palette Color LUT Data
+      // Segmented Red   Palette Color LUT Data
+      LoadEntryVoidArea(0x0028,0x1221);
+      // Segmented Green Palette Color LUT Data
+      LoadEntryVoidArea(0x0028,0x1222);
+      // Segmented Blue  Palette Color LUT Data
+      LoadEntryVoidArea(0x0028,0x1223);
    } 
    //FIXME later : how to use it?
    LoadEntryVoidArea(0x0028,0x3006);  //LUT Data (CTX dependent) 
@@ -152,7 +149,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
@@ -169,24 +170,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;
-   //EnableSequences=0; // ?!? JPR
-
    SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
    Initialise();
-
    PrintLevel = 1;  // 'Medium' print level by default
 }
 
@@ -202,7 +199,7 @@ gdcmDocument::~gdcmDocument ()
    for (TagDocEntryHT::const_iterator it = TagHT.begin(); 
                                       it != TagHT.end(); ++it )
    { 
-      delete it->second;
+      //delete it->second; //temp remove
    }
    TagHT.clear();
 }
@@ -260,7 +257,7 @@ bool gdcmDocument::SetShaDict(gdcmDict *dict)
  * \brief   Set the shadow dictionary used
  * \param   dictName name of the dictionary to use in shadow
  */
-bool gdcmDocument::SetShaDict(DictKey dictName)
+bool gdcmDocument::SetShaDict(DictKey const & dictName)
 {
    RefShaDict = gdcmGlobal::GetDicts()->GetDict(dictName);
    return !RefShaDict;
@@ -278,8 +275,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;
    }
@@ -298,10 +293,10 @@ 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 don't match.
+ *          no Transfer Syntax, or when the Tranfer Syntaxes doesn't match.
  */
 bool gdcmDocument::IsGivenTransferSyntax(std::string const & syntaxToCheck)
 {
@@ -312,21 +307,22 @@ bool gdcmDocument::IsGivenTransferSyntax(std::string const & syntaxToCheck)
    }
 
    // The entry might be present but not loaded (parsing and loading
-   // happen at differente stages): try loading and proceed with check...
+   // happen at different stages): try loading and proceed with check...
    LoadDocEntrySafe(entry);
    if (gdcmValEntry* valEntry = dynamic_cast< gdcmValEntry* >(entry) )
    {
       std::string transfer = valEntry->GetValue();
-
       // The actual transfer (as read from disk) might be padded. We
       // first need to remove the potential padding. We can make the
       // weak assumption that padding was not executed with digits...
-//      while ( ! isdigit(transfer[transfer.length()-1]) )
-//      {
-//         transfer.erase(transfer.length()-1, 1);
-//      }
-//      if ( transfer == syntaxToCheck )
-      if( transfer.find( syntaxToCheck ) )   //should be faster
+      if  ( transfer.length() == 0 ) { // for brain damaged headers
+         return false;
+      }
+      while ( ! isdigit(transfer[transfer.length()-1]) )
+      {
+         transfer.erase(transfer.length()-1, 1);
+      }
+      if ( transfer == syntaxToCheck )
       {
          return true;
       }
@@ -478,58 +474,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");
-
-  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);
+   Fp = fopen(Filename.c_str(),"rb");
 
-    //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;
 }
 
 /**
@@ -539,7 +523,7 @@ FILE *gdcmDocument::OpenFile(bool exception_on_error)
 bool gdcmDocument::CloseFile()
 {
   int closed = fclose(Fp);
-  Fp = (FILE *)0;
+  Fp = 0;
 
   return closed;
 }
@@ -606,21 +590,22 @@ 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).
  */
-  
+
+/*  
 gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber(
-                                         std::string value, 
+                                         std::string const & value, 
                                          uint16_t group, 
                                          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:
@@ -641,7 +626,95 @@ 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);
+         if (!RemoveEntry(currentEntry))
+         {
+            dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: removal"
+                           " of previous DocEntry failed.");
+            return NULL;
+         }
+         if ( !AddEntry(valEntry))
+         {
+            dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: adding"
+                           " promoted ValEntry 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   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).
+ */
+ // 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, 
+                                         uint16_t group, 
+                                         uint16_t elem,
+                                         std::string const & VR )
+{
+   gdcmValEntry* valEntry = 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
+
+   // 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"
+                        " NewDocEntryByNumber failed.");
+         return NULL;
+      }
+      valEntry = new gdcmValEntry(currentEntry);
+      if ( !AddEntry(valEntry))
+      {
+         dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: AddEntry"
+                        " failed allthough this is a creation.");
+      }
+   }
+   else
+   {
+      valEntry = dynamic_cast< gdcmValEntry* >(currentEntry);
+      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);
@@ -677,42 +750,114 @@ gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber(
 gdcmBinEntry * gdcmDocument::ReplaceOrCreateByNumber(
                                          void *voidArea,
                                          int lgth, 
+                                         uint16_t group, 
+                                         uint16_t elem,
+                                         std::string const & VR )
+{
+   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
+
+   // 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"
+                        " NewDocEntryByNumber failed.");
+         return NULL;
+      }
+      binEntry = new gdcmBinEntry(currentEntry);
+      if ( !AddEntry(binEntry))
+      {
+         dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: AddEntry"
+                        " failed allthough this is a creation.");
+      }
+   }
+   else
+   {
+      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 gdcmBinEntry:
+         binEntry = new gdcmBinEntry(currentEntry);
+         if (!RemoveEntry(currentEntry))
+         {
+            dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: removal"
+                           " of previous DocEntry failed.");
+            return NULL;
+         }
+         if ( !AddEntry(binEntry))
+         {
+            dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: adding"
+                           " promoted BinEntry failed.");
+            return NULL;
+         }
+      }
+   }
+
+   SetEntryByNumber(voidArea, lgth, group, elem);
+
+   return binEntry;
+}  
+
+
+/*
+ * \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)
 {
-   gdcmBinEntry* b = 0;
+   gdcmSeqEntry* b = 0;
    gdcmDocEntry* a = GetDocEntryByNumber( group, elem);
    if (!a)
    {
-      a = NewBinEntryByNumber(group, elem);
+      a = NewSeqEntryByNumber(group, elem);
       if (!a)
       {
          return 0;
       }
 
-      b = new gdcmBinEntry(a);
+      b = new gdcmSeqEntry(a, 1); // FIXME : 1 (Depth)
       AddEntry(b);
-      b->SetVoidArea(voidArea);
    }   
-   SetEntryByNumber(voidArea, lgth, group, elem);
-   //b->SetVoidArea(voidArea);  //what if b == 0 !!
-
    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(const char* value, uint16_t group,
-                                          uint16_t elem ) 
+bool gdcmDocument::ReplaceIfExistByNumber(std::string const & value, 
+                                          uint16_t group, uint16_t elem ) 
 {
-   const std::string v = value;
-   SetEntryByNumber(v, group, elem);
+   SetEntryByNumber(value, group, elem);
 
    return true;
 } 
@@ -724,11 +869,11 @@ bool gdcmDocument::ReplaceIfExistByNumber(const char* value, uint16_t group,
  * \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 )
 {
-   std::string key = gdcmDictEntry::TranslateToKey(group, element );
+   const std::string &key = gdcmDictEntry::TranslateToKey(group, element );
    return TagHT.count(key);
 }
 
@@ -741,7 +886,7 @@ int 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 tagName)
+std::string gdcmDocument::GetEntryByName(TagName const & tagName)
 {
    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
    if( !dictEntry )
@@ -765,7 +910,7 @@ std::string gdcmDocument::GetEntryByName(TagName tagName)
  * @return  Corresponding element value representation when it exists,
  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
  */
-std::string gdcmDocument::GetEntryVRByName(TagName tagName)
+std::string gdcmDocument::GetEntryVRByName(TagName const & tagName)
 {
    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
    if( dictEntry == NULL)
@@ -773,8 +918,8 @@ std::string gdcmDocument::GetEntryVRByName(TagName tagName)
       return GDCM_UNFOUND;
    }
 
-   gdcmDocEntry* elem =  GetDocEntryByNumber(dictEntry->GetGroup(),
-                                             dictEntry->GetElement());
+   gdcmDocEntry* elem = GetDocEntryByNumber(dictEntry->GetGroup(),
+                                            dictEntry->GetElement());
    return elem->GetVR();
 }
 
@@ -847,7 +992,7 @@ int gdcmDocument::GetEntryLengthByNumber(uint16_t group, uint16_t element)
  * @param   tagName name of the searched Dicom Element.
  * @return  true when found
  */
-bool gdcmDocument::SetEntryByName(std::string content,std::string tagName)
+bool gdcmDocument::SetEntryByName(std::string const & content,std::string const & tagName)
 {
    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
    if( !dictEntry )
@@ -867,10 +1012,13 @@ bool gdcmDocument::SetEntryByName(std::string content,std::string tagName)
  * @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 content, 
+bool gdcmDocument::SetEntryByNumber(std::string const & content, 
                                     uint16_t group,
                                     uint16_t element) 
 {
+   int c;
+   int l;
+
    gdcmValEntry* valEntry = GetValEntryByNumber(group, element);
    if (!valEntry )
    {
@@ -878,28 +1026,32 @@ bool gdcmDocument::SetEntryByNumber(std::string content,
                      " ValEntry (try promotion first).");
       return false;
    }
-   // Non even content must be padded with a space (020H).
-   if( content.length() % 2 )
+   // Non even content must be padded with a space (020H)...
+   std::string finalContent = content;
+   if( finalContent.length() % 2 )
    {
-      content += '\0';
+      finalContent += '\0';  // ... therefore we padd with (000H) .!?!
    }      
-   valEntry->SetValue(content);
+   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(content.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;
 } 
 
@@ -924,17 +1076,17 @@ bool gdcmDocument::SetEntryByNumber(void *content,
       return false;
    }
 
-/* Hope Binaray field length is *never* wrong    
+/* Hope Binary field length is *never* wrong    
    if(lgth%2) // Non even length are padded with a space (020H).
    {  
       lgth++;
       //content = content + '\0'; // fing a trick to enlarge a binary field?
    }
 */      
-   gdcmBinEntry * a;
-   a = (gdcmBinEntry *)TagHT[key];           
+   gdcmBinEntry* a = (gdcmBinEntry *)TagHT[key];           
    a->SetVoidArea(content);  
-   //a->SetLength(lgth);  // ???  
+   a->SetLength(lgth);
+
    return true;
 } 
 
@@ -971,8 +1123,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) 
@@ -989,8 +1141,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) 
@@ -1007,10 +1159,10 @@ 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)
+voidgdcmDocument::LoadEntryVoidArea(uint16_t group, uint16_t elem)
 {
    gdcmDocEntry *docElement = GetDocEntryByNumber(group, elem);
    if ( !docElement )
@@ -1033,14 +1185,17 @@ void *gdcmDocument::LoadEntryVoidArea(uint16_t group, uint16_t elem)
       return NULL;
    }
    /// \todo Drop any already existing void area! JPR
-   SetEntryVoidAreaByNumber(a, group, elem);
+   if( !SetEntryVoidAreaByNumber( a, group, elem ) );
+   {
+      dbg.Verbose(0, "gdcmDocument::LoadEntryVoidArea 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 voidArea is going to be loaded
  */
 void *gdcmDocument::LoadEntryVoidArea(gdcmBinEntry *element) 
 {
@@ -1076,14 +1231,16 @@ bool gdcmDocument::SetEntryVoidAreaByNumber(void * area,
                                             uint16_t group, 
                                             uint16_t element) 
 {
-   gdcmTagKey key = gdcmDictEntry::TranslateToKey(group, element);
-   if ( !TagHT.count(key))
+   gdcmDocEntry* currentEntry = GetDocEntryByNumber(group, element);
+   if ( !currentEntry )
    {
       return false;
    }
-      // This was for multimap ?
-    (( gdcmBinEntry *)( ((TagHT.equal_range(key)).first)->second ))->SetVoidArea(area);
-      
+   if ( gdcmBinEntry* binEntry = dynamic_cast<gdcmBinEntry*>(currentEntry) )
+   {
+      binEntry->SetVoidArea( area );
+      return true;
+   }
    return true;
 }
 
@@ -1235,9 +1392,9 @@ 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;
+         a = 0;
    }
    return a;
 } 
@@ -1260,7 +1417,7 @@ uint16_t gdcmDocument::SwapShort(uint16_t a)
 {
    if ( SwapCode == 4321 || SwapCode == 2143 )
    {
-      a =((( a << 8 ) & 0x0ff00 ) | (( a >> 8 ) & 0x00ff ) );
+      a = ((( a << 8 ) & 0x0ff00 ) | (( a >> 8 ) & 0x00ff ) );
    }
    return a;
 }
@@ -1288,10 +1445,8 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
                             bool delim_mode)
 {
    gdcmDocEntry *newDocEntry = 0;
-   gdcmValEntry *newValEntry = 0;
    unsigned long l = 0;
    
-   int depth = set->GetDepthLevel();
    while (true)
    { 
       if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
@@ -1310,13 +1465,29 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
                
          if ( gdcmGlobal::GetVR()->IsVROfGdcmStringRepresentable(vr) )
          {
-            /////// ValEntry
-            newValEntry = new gdcmValEntry(newDocEntry->GetDictEntry());
-            newValEntry->Copy(newDocEntry);
-            newValEntry->SetDepthLevel(depth);
-            set->AddEntry(newValEntry);
-            LoadDocEntry(newValEntry);
-            if (newValEntry->isItemDelimitor())
+         /////////////////////// ValEntry
+            gdcmValEntry* newValEntry =
+               new gdcmValEntry( newDocEntry->GetDictEntry() );
+            newValEntry->Copy( newDocEntry );
+             
+            // 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 ) )
+            {
+               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())
             {
                break;
             }
@@ -1334,11 +1505,28 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
                                "nor BinEntry. Probably unknown VR.");
             }
 
-            ////// BinEntry or UNKOWN VR:
-            gdcmBinEntry *bn = new gdcmBinEntry(newDocEntry->GetDictEntry());
-            bn->Copy(newDocEntry);
-            set->AddEntry(bn);
-            LoadDocEntry(bn);
+         //////////////////// BinEntry or UNKOWN VR:
+            gdcmBinEntry* newBinEntry =
+               new gdcmBinEntry( newDocEntry->GetDictEntry() );
+            newBinEntry->Copy( newDocEntry );
+
+            // 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 );
          }
 
          if (newDocEntry->GetGroup()   == 0x7fe0 && 
@@ -1379,20 +1567,37 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
             }
          }
          // no other way to create it ...
-         gdcmSeqEntry *sq = new gdcmSeqEntry(newDocEntry->GetDictEntry(),
-                                             set->GetDepthLevel());
-         sq->Copy(newDocEntry);
-         sq->SetDelimitorMode(delim_mode);
-         sq->SetDepthLevel(depth);
+         gdcmSeqEntry* newSeqEntry =
+            new gdcmSeqEntry( newDocEntry->GetDictEntry() );
+         newSeqEntry->Copy( newDocEntry );
+         newSeqEntry->SetDelimitorMode( delim_mode );
+
+         // 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 ) )
+         {
+            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
-            long lgt = ParseSQ( sq, 
-                                newDocEntry->GetOffset(),
-                                l, delim_mode);
-            (void)lgt;  //not used...
+            (void)ParseSQ( newSeqEntry, 
+                           newDocEntry->GetOffset(),
+                           l, delim_mode);
          }
-         set->AddEntry(sq);
+         set->AddEntry( newSeqEntry );
          if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
          {
             break;
@@ -1400,7 +1605,6 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
       }
       delete newDocEntry;
    }
-
    return l; // Probably useless 
 }
 
@@ -1408,17 +1612,15 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
  * \brief   Parses a Sequence ( SeqEntry after SeqEntry)
  * @return  parsed length for this level
  */ 
-long gdcmDocument::ParseSQ(gdcmSeqEntry *set,
-                           long offset, long l_max, bool delim_mode)
+long gdcmDocument::ParseSQ( gdcmSeqEntry* seqEntry,
+                            long offset, long l_max, bool delim_mode)
 {
    int SQItemNumber = 0;
    bool dlm_mod;
-   //int depth = set->GetDepthLevel();
-   //(void)depth; //not used
 
    while (true)
    {
-      gdcmDocEntry *newDocEntry = ReadNextDocEntry();   
+      gdcmDocEntrynewDocEntry = ReadNextDocEntry();   
       if ( !newDocEntry )
       {
          // FIXME Should warn user
@@ -1426,9 +1628,9 @@ long gdcmDocument::ParseSQ(gdcmSeqEntry *set,
       }
       if( delim_mode )
       {
-         if ( newDocEntry->isSequenceDelimitor() )
+         if ( newDocEntry->IsSequenceDelimitor() )
          {
-            set->SetSequenceDelimitationItem( newDocEntry );
+            seqEntry->SetSequenceDelimitationItem( newDocEntry );
             break;
          }
       }
@@ -1437,8 +1639,13 @@ long gdcmDocument::ParseSQ(gdcmSeqEntry *set,
           break;
       }
 
-      gdcmSQItem *itemSQ = new gdcmSQItem(set->GetDepthLevel());
-      itemSQ->AddEntry(newDocEntry);
+      gdcmSQItem *itemSQ = new gdcmSQItem( seqEntry->GetDepthLevel() );
+      std::ostringstream newBase;
+      newBase << seqEntry->GetKey()
+              << "/"
+              << SQItemNumber
+              << "#";
+      itemSQ->SetBaseTagKey( newBase.str() );
       unsigned int l = newDocEntry->GetReadLength();
       
       if ( l == 0xffffffff )
@@ -1450,11 +1657,11 @@ long gdcmDocument::ParseSQ(gdcmSeqEntry *set,
          dlm_mod = false;
       }
    
-      int lgr = ParseDES(itemSQ, newDocEntry->GetOffset(), l, dlm_mod);
+      (void)ParseDES(itemSQ, newDocEntry->GetOffset(), l, dlm_mod);
       
-      set->AddEntry(itemSQ, SQItemNumber); 
+      seqEntry->AddEntry( itemSQ, SQItemNumber ); 
       SQItemNumber++;
-      if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
+      if ( !delim_mode && ( ftell(Fp) - offset ) >= l_max )
       {
          break;
       }
@@ -1467,7 +1674,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)
 {
@@ -1503,40 +1710,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);      
-
-      return;  //FIXME FIXME FIXME FIXME ????
-
        // 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;
    }
     
@@ -1544,7 +1753,6 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry)
    if ( IsDocEntryAnInteger(entry) )
    {   
       uint32_t NewInt;
-      std::ostringstream s;
       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
@@ -1594,17 +1802,18 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry)
    //std::string newValue(length,0);
    //item_read = fread(&(newValue[0]), (size_t)length, (size_t)1, Fp);  
    //rah !! I can't believe it could work, normally this is a const char* !!!
-   char str[length];
+   char *str = new char[length+1];
    item_read = fread(str, (size_t)length, (size_t)1, Fp);
+   str[length] = '\0';
    std::string newValue = str;
-   newValue += '\0';
+   delete[] str;
    if ( gdcmValEntry* valEntry = dynamic_cast<gdcmValEntry* >(entry) )
    {  
       if ( item_read != 1 )
       {
          dbg.Verbose(1, "gdcmDocument::LoadDocEntry",
                         "unread element value");
-         valEntry->SetValue("gdcm::UnRead");
+         valEntry->SetValue(GDCM_UNREAD);
          return;
       }
 
@@ -1628,14 +1837,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)
+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() ) 
    {
@@ -1649,8 +1858,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
@@ -1662,7 +1875,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);
@@ -1702,12 +1914,12 @@ void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry)
       // endian encoding". When this is the case, chances are we have got our
       // hands on a big endian encoded file: we switch the swap code to
       // big endian and proceed...
-      if ( (element  == 0x0000) && (length16 == 0x0400) ) 
+      if ( element  == 0x0000 && length16 == 0x0400 ) 
       {
-         if ( ! IsExplicitVRBigEndianTransferSyntax() ) 
+         if ( !IsExplicitVRBigEndianTransferSyntax() ) 
          {
-            dbg.Verbose(0, "gdcmDocument::FindLength", "not explicit VR");
-            errno = 1;
+            throw gdcmFormatError( "gdcmDocument::FindDocEntryLength()",
+                                   " not explicit VR." );
             return;
          }
          length16 = 4;
@@ -1731,11 +1943,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
@@ -1747,14 +1958,14 @@ 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;
    }
 }
 
 /**
  * \brief     Find the Value Representation of the current Dicom Element.
- * @param     Entry
+ * @param     entry
  */
 void gdcmDocument::FindDocEntryVR( gdcmDocEntry *entry )
 {
@@ -1774,7 +1985,7 @@ void gdcmDocument::FindDocEntryVR( gdcmDocEntry *entry )
    // is in explicit VR and try to fix things if it happens not to be
    // the case.
    
-   fread (&vr, (size_t)2,(size_t)1, Fp);
+   fread (vr, (size_t)2,(size_t)1, Fp);
    vr[2] = 0;
 
    if( !CheckDocEntryVR(entry, vr) )
@@ -1797,7 +2008,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
@@ -1815,7 +2026,7 @@ bool gdcmDocument::CheckDocEntryVR(gdcmDocEntry *entry, gdcmVRKey vr)
    // expected VR read happens to be non-ascii characters we consider
    // we hit falsely explicit VR tag.
 
-   if ( (!isalpha(vr[0])) && (!isalpha(vr[1])) )
+   if ( !isalpha(vr[0]) && !isalpha(vr[1]) )
    {
       realExplicit = false;
    }
@@ -1880,7 +2091,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)
@@ -1956,7 +2167,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)
@@ -2010,7 +2221,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) 
 {
@@ -2020,7 +2231,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) 
 {
@@ -2032,6 +2243,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)
@@ -2084,8 +2297,7 @@ void gdcmDocument::FixDocEntryFoundLength(gdcmDocEntry *entry,
       entry->SetReadLength(4); /// \todo a bug is to be fixed !?
    } 
  
-   //////// Deal with sequences, but only on users request:
-   else if ( entry->GetVR() == "SQ" && EnableSequences)
+   else if ( entry->GetVR() == "SQ" )
    {
       foundLength = 0;      // ReadLength is unchanged 
    } 
@@ -2110,7 +2322,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)
@@ -2163,6 +2375,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);
@@ -2171,26 +2384,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;
       }
@@ -2215,6 +2435,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);
@@ -2222,12 +2443,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;
 }
@@ -2238,6 +2457,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);
@@ -2245,12 +2465,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;
 }
@@ -2312,6 +2530,7 @@ bool gdcmDocument::CheckSwap()
    // The easiest case is the one of a DICOM header, since it possesses a
    // file preamble where it suffice to look for the string "DICM".
    int lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, Fp);
+   (void)lgrLue;  //FIXME not used
    
    char *entCur = deb + 128;
    if( memcmp(entCur, "DICM", (size_t)4) == 0 )
@@ -2490,7 +2709,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) 
 {
@@ -2510,7 +2729,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) 
 {
@@ -2536,28 +2755,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()
 {
-   if (errno == 1)
+   uint16_t group;
+   uint16_t elem;
+
+   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;
    }
 
-   uint16_t g = ReadInt16();
-   uint16_t n = ReadInt16();
-   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 NULL;
+      return 0;
    }
+
    newEntry->SetOffset(ftell(Fp));  
 
    return newEntry;
@@ -2584,16 +2814,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)
@@ -2624,23 +2854,23 @@ 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.
  */
 uint32_t gdcmDocument::ReadTagLength(uint16_t testGroup, uint16_t testElement)
 {
-   long PositionOnEntry = ftell(Fp);
-   (void)PositionOnEntry;
+   long positionOnEntry = ftell(Fp);
+   (void)positionOnEntry;
 
    if ( !ReadTag(testGroup, testElement) )
    {
@@ -2663,7 +2893,6 @@ 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
- *
  */
 void gdcmDocument::Parse7FE0 ()
 {
@@ -2702,7 +2931,8 @@ void gdcmDocument::Parse7FE0 ()
          s << "   Read one length: ";
          s << std::hex << individualLength << std::endl;
          dbg.Verbose(0, "gdcmDocument::Parse7FE0: ", s.str().c_str());
-      }              
+      }
+      delete[] basicOffsetTableItemValue;
    }
 
    if ( ! IsRLELossLessTransferSyntax() )
@@ -2756,7 +2986,7 @@ void gdcmDocument::Parse7FE0 ()
 
       // Make sure that at the end of the item we encounter a 'Sequence
       // Delimiter Item':
-      if ( ! ReadTag(0xfffe, 0xe0dd) )
+      if ( !ReadTag(0xfffe, 0xe0dd) )
       {
          dbg.Verbose(0, "gdcmDocument::Parse7FE0: no sequence delimiter item");
          dbg.Verbose(0, "    at end of RLE item sequence");
@@ -2764,6 +2994,97 @@ void gdcmDocument::Parse7FE0 ()
    }
 }
 
+/**
+ * \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) )
+         {
+            ListSQItem& items = seqEntry->GetSQItems();
+            for( ListSQItem::const_iterator item  = items.begin();
+                                            item != items.end();
+                                          ++item)
+            {
+               BuildFlatHashTableRecurse( builtHT, *item );
+            }
+            continue;
+         }
+         builtHT[entry->GetKey()] = entry;
+      }
+      return;
+    }
+
+   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) )
+         {
+            ListSQItem& items = seqEntry->GetSQItems();
+            for( ListSQItem::const_iterator item  = items.begin();
+                                            item != items.end();
+                                          ++item)
+            {
+               BuildFlatHashTableRecurse( builtHT, *item );
+            }
+            continue;
+         }
+         builtHT[entry->GetKey()] = entry;
+      }
+
+   }
+}
+
+/**
+ * \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 olds 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 gdcmElemenSet used
+ *        to build it. Hence if the underlying \ref gdcmElemenSet 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;
+}
+
 
 
 /**
@@ -2776,20 +3097,20 @@ void gdcmDocument::Parse7FE0 ()
 bool gdcmDocument::operator<(gdcmDocument &document)
 {
    // Patient Name
-   std::string s1 = this->GetEntryByNumber(0x0010,0x0010);
+   std::string s1 = GetEntryByNumber(0x0010,0x0010);
    std::string s2 = document.GetEntryByNumber(0x0010,0x0010);
    if(s1 < s2)
    {
       return true;
    }
-   else if(s1 > s2)
+   else if( s1 > s2 )
    {
       return false;
    }
    else
    {
       // Patient ID
-      s1 = this->GetEntryByNumber(0x0010,0x0020);
+      s1 = GetEntryByNumber(0x0010,0x0020);
       s2 = document.GetEntryByNumber(0x0010,0x0020);
       if ( s1 < s2 )
       {
@@ -2797,12 +3118,12 @@ bool gdcmDocument::operator<(gdcmDocument &document)
       }
       else if ( s1 > s2 )
       {
-         return true;
+         return false;
       }
       else
       {
          // Study Instance UID
-         s1 = this->GetEntryByNumber(0x0020,0x000d);
+         s1 = GetEntryByNumber(0x0020,0x000d);
          s2 = document.GetEntryByNumber(0x0020,0x000d);
          if ( s1 < s2 )
          {
@@ -2815,8 +3136,8 @@ bool gdcmDocument::operator<(gdcmDocument &document)
          else
          {
             // Serie Instance UID
-            s1 = this->GetEntryByNumber(0x0020,0x000e);
-            s2 = document.GetEntryByNumber(0x0020,0x000e);
+            s1 = GetEntryByNumber(0x0020,0x000e);
+            s2 = document.GetEntryByNumber(0x0020,0x000e);    
             if ( s1 < s2 )
             {
                return true;