]> Creatis software - gdcm.git/blob - src/gdcmDocument.cxx
ab150ec1196e13b5ab4c52f2f0e2dae1c8305131
[gdcm.git] / src / gdcmDocument.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDocument.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/11/05 21:23:46 $
7   Version:   $Revision: 1.118 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmDocument.h"
20 #include "gdcmValEntry.h"
21 #include "gdcmBinEntry.h"
22 #include "gdcmSeqEntry.h"
23 #include "gdcmGlobal.h"
24 #include "gdcmUtil.h"
25 #include "gdcmDebug.h"
26
27 #include <vector>
28 #include <iomanip>
29
30 // For nthos:
31 #ifdef _MSC_VER
32    #include <winsock.h>
33 #else
34    #include <netinet/in.h>
35 #endif
36
37 namespace gdcm 
38 {
39 static const char *TransferSyntaxStrings[] =  {
40   // Implicit VR Little Endian
41   "1.2.840.10008.1.2",
42   // Explicit VR Little Endian
43   "1.2.840.10008.1.2.1",
44   // Deflated Explicit VR Little Endian
45   "1.2.840.10008.1.2.1.99",
46   // Explicit VR Big Endian
47   "1.2.840.10008.1.2.2",
48   // JPEG Baseline (Process 1)
49   "1.2.840.10008.1.2.4.50",
50   // JPEG Extended (Process 2 & 4)
51   "1.2.840.10008.1.2.4.51",
52   // JPEG Extended (Process 3 & 5)
53   "1.2.840.10008.1.2.4.52",
54   // JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8)
55   "1.2.840.10008.1.2.4.53",
56   // JPEG Full Progression, Non-Hierarchical (Process 10 & 12)
57   "1.2.840.10008.1.2.4.55",
58   // JPEG Lossless, Non-Hierarchical (Process 14)
59   "1.2.840.10008.1.2.4.57",
60   // JPEG Lossless, Hierarchical, First-Order Prediction (Process 14, [Selection Value 1])
61   "1.2.840.10008.1.2.4.70",
62   // JPEG 2000 Lossless
63   "1.2.840.10008.1.2.4.90",
64   // JPEG 2000
65   "1.2.840.10008.1.2.4.91",
66   // RLE Lossless
67   "1.2.840.10008.1.2.5",
68   // Unknown
69   "Unknown Transfer Syntax"
70 };
71
72 //-----------------------------------------------------------------------------
73 // Refer to Document::CheckSwap()
74 const unsigned int Document::HEADER_LENGTH_TO_READ = 256;
75
76 // Refer to Document::SetMaxSizeLoadEntry()
77 const unsigned int Document::MAX_SIZE_LOAD_ELEMENT_VALUE = 0xfff; // 4096
78 const unsigned int Document::MAX_SIZE_PRINT_ELEMENT_VALUE = 0x7fffffff;
79
80 //-----------------------------------------------------------------------------
81 // Constructor / Destructor
82
83 /**
84  * \brief   constructor  
85  * @param   filename file to be opened for parsing
86  */
87 Document::Document( std::string const & filename ) : ElementSet(-1)
88 {
89    SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE); 
90    Filename = filename;
91    Initialise();
92
93    if ( !OpenFile() )
94    {
95       return;
96    }
97
98    dbg.Verbose(0, "Document::Document: starting parsing of file: ",
99                   Filename.c_str());
100    Fp->seekg( 0,  std::ios_base::beg);
101    
102    Fp->seekg(0,  std::ios_base::end);
103    long lgt = Fp->tellg();
104            
105    Fp->seekg( 0,  std::ios_base::beg);
106    CheckSwap();
107    long beg = Fp->tellg();
108    lgt -= beg;
109    
110    ParseDES( this, beg, lgt, false); // le Load sera fait a la volee
111
112    Fp->seekg( 0,  std::ios_base::beg);
113    
114    // Load 'non string' values
115       
116    std::string PhotometricInterpretation = GetEntryByNumber(0x0028,0x0004);   
117    if( PhotometricInterpretation == "PALETTE COLOR " )
118    {
119       LoadEntryBinArea(0x0028,0x1200);  // gray LUT   
120       /// FIXME FIXME FIXME
121       /// The tags refered by the three following lines used to be CORRECTLY
122       /// defined as having an US Value Representation in the public
123       /// dictionnary. BUT the semantics implied by the three following
124       /// lines state that the corresponding tag contents are in fact
125       /// the ones of a BinEntry.
126       /// In order to fix things "Quick and Dirty" the dictionnary was
127       /// altered on PURPOUS but now contains a WRONG value.
128       /// In order to fix things and restore the dictionary to its
129       /// correct value, one needs to decided of the semantics by deciding
130       /// wether the following tags are either:
131       /// - multivaluated US, and hence loaded as ValEntry, but afterwards
132       ///   also used as BinEntry, which requires the proper conversion,
133       /// - OW, and hence loaded as BinEntry, but afterwards also used
134       ///   as ValEntry, which requires the proper conversion.
135       LoadEntryBinArea(0x0028,0x1201);  // R    LUT
136       LoadEntryBinArea(0x0028,0x1202);  // G    LUT
137       LoadEntryBinArea(0x0028,0x1203);  // B    LUT
138       
139       // Segmented Red   Palette Color LUT Data
140       LoadEntryBinArea(0x0028,0x1221);
141       // Segmented Green Palette Color LUT Data
142       LoadEntryBinArea(0x0028,0x1222);
143       // Segmented Blue  Palette Color LUT Data
144       LoadEntryBinArea(0x0028,0x1223);
145    } 
146    //FIXME later : how to use it?
147    LoadEntryBinArea(0x0028,0x3006);  //LUT Data (CTX dependent) 
148
149    CloseFile(); 
150   
151    // --------------------------------------------------------------
152    // Specific code to allow gdcm to read ACR-LibIDO formated images
153    // Note: ACR-LibIDO is an extension of the ACR standard that was
154    //       used at CREATIS. For the time being (say a couple years)
155    //       we keep this kludge to allow a smooth move to gdcm for
156    //       CREATIS developpers (sorry folks).
157    //
158    // if recognition code tells us we deal with a LibIDO image
159    // we switch lineNumber and columnNumber
160    //
161    std::string RecCode;
162    RecCode = GetEntryByNumber(0x0008, 0x0010); // recognition code
163    if (RecCode == "ACRNEMA_LIBIDO_1.1" ||
164        RecCode == "CANRME_AILIBOD1_1." )  // for brain-damaged softwares
165                                           // with "little-endian strings"
166    {
167          Filetype = ACR_LIBIDO; 
168          std::string rows    = GetEntryByNumber(0x0028, 0x0010);
169          std::string columns = GetEntryByNumber(0x0028, 0x0011);
170          SetEntryByNumber(columns, 0x0028, 0x0010);
171          SetEntryByNumber(rows   , 0x0028, 0x0011);
172    }
173    // ----------------- End of ACR-LibIDO kludge ------------------ 
174
175    PrintLevel = 1;  // 'Medium' print level by default
176 }
177
178 /**
179  * \brief This default constructor doesn't parse the file. You should
180  *        then invoke \ref Document::SetFileName and then the parsing.
181  */
182 Document::Document() : ElementSet(-1)
183 {
184    SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
185    Initialise();
186    PrintLevel = 1;  // 'Medium' print level by default
187 }
188
189 /**
190  * \brief   Canonical destructor.
191  */
192 Document::~Document ()
193 {
194    RefPubDict = NULL;
195    RefShaDict = NULL;
196
197    // Recursive clean up of sequences
198    for (TagDocEntryHT::const_iterator it = TagHT.begin(); 
199                                       it != TagHT.end(); ++it )
200    { 
201       //delete it->second; //temp remove
202    }
203    TagHT.clear();
204    delete RLEInfo;
205    delete JPEGInfo;
206 }
207
208 //-----------------------------------------------------------------------------
209 // Print
210
211 /**
212   * \brief   Prints The Dict Entries of THE public Dicom Dictionary
213   * @return
214   */  
215 void Document::PrintPubDict(std::ostream & os)
216 {
217    RefPubDict->Print(os);
218 }
219
220 /**
221   * \brief   Prints The Dict Entries of THE shadow Dicom Dictionary
222   * @return
223   */
224 void Document::PrintShaDict(std::ostream & os)
225 {
226    RefShaDict->Print(os);
227 }
228
229 //-----------------------------------------------------------------------------
230 // Public
231 /**
232  * \brief   Get the public dictionary used
233  */
234 Dict* Document::GetPubDict()
235 {
236    return RefPubDict;
237 }
238
239 /**
240  * \brief   Get the shadow dictionary used
241  */
242 Dict* Document::GetShaDict()
243 {
244    return RefShaDict;
245 }
246
247 /**
248  * \brief   Set the shadow dictionary used
249  * \param   dict dictionary to use in shadow
250  */
251 bool Document::SetShaDict(Dict *dict)
252 {
253    RefShaDict = dict;
254    return !RefShaDict;
255 }
256
257 /**
258  * \brief   Set the shadow dictionary used
259  * \param   dictName name of the dictionary to use in shadow
260  */
261 bool Document::SetShaDict(DictKey const & dictName)
262 {
263    RefShaDict = Global::GetDicts()->GetDict(dictName);
264    return !RefShaDict;
265 }
266
267 /**
268  * \brief  This predicate, based on hopefully reasonable heuristics,
269  *         decides whether or not the current Document was properly parsed
270  *         and contains the mandatory information for being considered as
271  *         a well formed and usable Dicom/Acr File.
272  * @return true when Document is the one of a reasonable Dicom/Acr file,
273  *         false otherwise. 
274  */
275 bool Document::IsReadable()
276 {
277    if( Filetype == Unknown)
278    {
279       dbg.Verbose(0, "Document::IsReadable: wrong filetype");
280       return false;
281    }
282
283    if( TagHT.empty() )
284    {
285       dbg.Verbose(0, "Document::IsReadable: no tags in internal"
286                      " hash table.");
287       return false;
288    }
289
290    return true;
291 }
292
293
294 /**
295  * \brief   Internal function that checks whether the Transfer Syntax given
296  *          as argument is the one present in the current document.
297  * @param   syntaxToCheck The transfert syntax we need to check against.
298  * @return  True when SyntaxToCheck corresponds to the Transfer Syntax of
299  *          the current document. False either when the document contains
300  *          no Transfer Syntax, or when the Tranfer Syntaxes doesn't match.
301  */
302 TransferSyntaxType Document::GetTransferSyntax()
303 {
304    DocEntry *entry = GetDocEntryByNumber(0x0002, 0x0010);
305    if ( !entry )
306    {
307       return UnknownTS;
308    }
309
310    // The entry might be present but not loaded (parsing and loading
311    // happen at different stages): try loading and proceed with check...
312    LoadDocEntrySafe(entry);
313    if (ValEntry* valEntry = dynamic_cast< ValEntry* >(entry) )
314    {
315       std::string transfer = valEntry->GetValue();
316       // The actual transfer (as read from disk) might be padded. We
317       // first need to remove the potential padding. We can make the
318       // weak assumption that padding was not executed with digits...
319       if  ( transfer.length() == 0 )
320       {
321          // for brain damaged headers
322          return UnknownTS;
323       }
324       while ( !isdigit(transfer[transfer.length()-1]) )
325       {
326          transfer.erase(transfer.length()-1, 1);
327       }
328       for (int i = 0; TransferSyntaxStrings[i] != NULL; i++)
329       {
330          if ( TransferSyntaxStrings[i] == transfer )
331          {
332             return TransferSyntaxType(i);
333          }
334       }
335    }
336    return UnknownTS;
337 }
338
339 bool Document::IsJPEGLossless()
340 {
341    TransferSyntaxType r = GetTransferSyntax();
342    return    r ==  JPEGFullProgressionProcess10_12
343           || r == JPEGLosslessProcess14
344           || r == JPEGLosslessProcess14_1;
345 }
346                                                                                 
347 /**
348  * \brief   Determines if the Transfer Syntax was already encountered
349  *          and if it corresponds to a JPEG2000 one
350  * @return  True when JPEG2000 (Lossly or LossLess) found. False in all
351  *          other cases.
352  */
353 bool Document::IsJPEG2000()
354 {
355    TransferSyntaxType r = GetTransferSyntax();
356    return r == JPEG2000Lossless || r == JPEG2000;
357 }
358
359 /**
360  * \brief   Determines if the Transfer Syntax corresponds to any form
361  *          of Jpeg encoded Pixel data.
362  * @return  True when any form of JPEG found. False otherwise.
363  */
364 bool Document::IsJPEG()
365 {
366    TransferSyntaxType r = GetTransferSyntax();
367    return r == JPEGBaselineProcess1 
368      || r == JPEGExtendedProcess2_4
369      || r == JPEGExtendedProcess3_5
370      || r == JPEGSpectralSelectionProcess6_8
371      ||      IsJPEGLossless()
372      ||      IsJPEG2000();
373 }
374
375 /**
376  * \brief   Determines if the Transfer Syntax corresponds to encapsulated
377  *          of encoded Pixel Data (as opposed to native).
378  * @return  True when encapsulated. False when native.
379  */
380 bool Document::IsEncapsulate()
381 {
382    TransferSyntaxType r = GetTransferSyntax();
383    return IsJPEG() || r == RLELossless;
384 }
385
386 /**
387  * \brief   Predicate for dicom version 3 file.
388  * @return  True when the file is a dicom version 3.
389  */
390 bool Document::IsDicomV3()
391 {
392    // Checking if Transfert Syntax exists is enough
393    // Anyway, it's to late check if the 'Preamble' was found ...
394    // And ... would it be a rich idea to check ?
395    // (some 'no Preamble' DICOM images exist !)
396    return GetDocEntryByNumber(0x0002, 0x0010) != NULL;
397 }
398
399 /**
400  * \brief  returns the File Type 
401  *         (ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown)
402  * @return the FileType code
403  */
404 FileType Document::GetFileType()
405 {
406    return Filetype;
407 }
408
409 /**
410  * \brief  Tries to open the file \ref Document::Filename and
411  *         checks the preamble when existing.
412  * @return The FILE pointer on success. 
413  */
414 std::ifstream* Document::OpenFile()
415 {
416    Fp = new std::ifstream(Filename.c_str(), std::ios::in | std::ios::binary);
417
418    if(!Fp)
419    {
420       dbg.Verbose( 0,
421                    "Document::OpenFile cannot open file: ",
422                    Filename.c_str());
423       return 0;
424    }
425  
426    uint16_t zero;
427    Fp->read((char*)&zero,  (size_t)2 );
428  
429    //ACR -- or DICOM with no Preamble --
430    if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200 )
431    {
432       return Fp;
433    }
434  
435    //DICOM
436    Fp->seekg(126L, std::ios_base::cur);
437    char dicm[4];
438    Fp->read(dicm,  (size_t)4);
439    if( memcmp(dicm, "DICM", 4) == 0 )
440    {
441       return Fp;
442    }
443  
444    Fp->close();
445    dbg.Verbose( 0,
446                 "Document::OpenFile not DICOM/ACR (missing preamble)",
447                 Filename.c_str());
448  
449    return 0;
450 }
451
452 /**
453  * \brief closes the file  
454  * @return  TRUE if the close was successfull 
455  */
456 bool Document::CloseFile()
457 {
458   Fp->close();
459   delete Fp;
460   Fp = 0;
461
462   return true; //FIXME how do we detect a non-close ifstream ?
463 }
464
465 /**
466  * \brief Writes in a file all the Header Entries (Dicom Elements) 
467  * @param fp file pointer on an already open file
468  * @param filetype Type of the File to be written 
469  *          (ACR-NEMA, ExplicitVR, ImplicitVR)
470  * \return Always true.
471  */
472 void Document::Write(std::ofstream* fp, FileType filetype)
473 {
474    /// \todo move the following lines (and a lot of others, to be written)
475    /// to a future function CheckAndCorrectHeader  
476    /// (necessary if user wants to write a DICOM V3 file
477    /// starting from an  ACR-NEMA (V2)  Header
478
479    if (filetype == ImplicitVR) 
480    {
481       std::string ts = 
482          Util::DicomString( TransferSyntaxStrings[ImplicitVRLittleEndian] );
483       ReplaceOrCreateByNumber(ts, 0x0002, 0x0010);
484       
485       /// \todo Refer to standards on page 21, chapter 6.2
486       ///       "Value representation": values with a VR of UI shall be
487       ///       padded with a single trailing null
488       ///       in the following case we have to padd manually with a 0
489       
490       SetEntryLengthByNumber(18, 0x0002, 0x0010);
491    } 
492
493    if (filetype == ExplicitVR)
494    {
495       std::string ts = 
496          Util::DicomString( TransferSyntaxStrings[ExplicitVRLittleEndian] );
497       ReplaceOrCreateByNumber(ts, 0x0002, 0x0010); //LEAK
498       
499       /// \todo Refer to standards on page 21, chapter 6.2
500       ///       "Value representation": values with a VR of UI shall be
501       ///       padded with a single trailing null
502       ///       Dans le cas suivant on doit pader manuellement avec un 0
503       
504       SetEntryLengthByNumber(20, 0x0002, 0x0010);
505    }
506   
507 /**
508  * \todo rewrite later, if really usefull
509  *       - 'Group Length' element is optional in DICOM
510  *       - but un-updated odd groups lengthes can causes pb
511  *         (xmedcon breaker)
512  *
513  * if ( (filetype == ImplicitVR) || (filetype == ExplicitVR) )
514  *    UpdateGroupLength(false,filetype);
515  * if ( filetype == ACR)
516  *    UpdateGroupLength(true,ACR);
517  */
518  
519    ElementSet::Write(fp, filetype); // This one is recursive
520
521 }
522
523 /**
524  * \brief   Modifies the value of a given Header Entry (Dicom Element)
525  *          when it exists. Create it with the given value when unexistant.
526  * @param   value (string) Value to be set
527  * @param   group   Group number of the Entry 
528  * @param   elem  Element number of the Entry
529  * @param   VR  V(alue) R(epresentation) of the Entry -if private Entry-
530  * \return  pointer to the modified/created Header Entry (NULL when creation
531  *          failed).
532  */ 
533 ValEntry* Document::ReplaceOrCreateByNumber(
534                                          std::string const & value, 
535                                          uint16_t group, 
536                                          uint16_t elem,
537                                          TagName const & vr )
538 {
539    ValEntry* valEntry = 0;
540    DocEntry* currentEntry = GetDocEntryByNumber( group, elem);
541    
542    if (!currentEntry)
543    {
544       // check if (group,element) DictEntry exists
545       // if it doesn't, create an entry in DictSet::VirtualEntry
546       // and use it
547
548    // Find out if the tag we received is in the dictionaries:
549       Dict *pubDict = Global::GetDicts()->GetDefaultPubDict();
550       DictEntry* dictEntry = pubDict->GetDictEntryByNumber(group, elem);
551       if (!dictEntry)
552       {
553          currentEntry = NewDocEntryByNumber(group, elem, vr);
554       }
555       else
556       {
557          currentEntry = NewDocEntryByNumber(group, elem);
558       }
559
560       if (!currentEntry)
561       {
562          dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: call to"
563                         " NewDocEntryByNumber failed.");
564          return NULL;
565       }
566       valEntry = new ValEntry(currentEntry);
567       if ( !AddEntry(valEntry))
568       {
569          delete valEntry;
570          dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: AddEntry"
571                         " failed allthough this is a creation.");
572       }
573       // This is the reason why NewDocEntryByNumber are a real
574       // bad habit !!! FIXME
575       delete currentEntry;
576    }
577    else
578    {
579       valEntry = dynamic_cast< ValEntry* >(currentEntry);
580       if ( !valEntry ) // Euuuuh? It wasn't a ValEntry
581                        // then we change it to a ValEntry ?
582                        // Shouldn't it be considered as an error ?
583       {
584          // We need to promote the DocEntry to a ValEntry:
585          valEntry = new ValEntry(currentEntry);
586          if (!RemoveEntry(currentEntry))
587          {
588             delete valEntry;
589             dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: removal"
590                            " of previous DocEntry failed.");
591             return NULL;
592          }
593          if ( !AddEntry(valEntry))
594          {
595             delete valEntry;
596             dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: adding"
597                            " promoted ValEntry failed.");
598             return NULL;
599          }
600       }
601    }
602
603    SetEntryByNumber(value, group, elem);
604
605    return valEntry;
606 }   
607
608 /*
609  * \brief   Modifies the value of a given Header Entry (Dicom Element)
610  *          when it exists. Create it with the given value when unexistant.
611  * @param   binArea (binary) value to be set
612  * @param   Group   Group number of the Entry 
613  * @param   Elem  Element number of the Entry
614  * \return  pointer to the modified/created Header Entry (NULL when creation
615  *          failed).
616  */
617 BinEntry* Document::ReplaceOrCreateByNumber(
618                                          uint8_t* binArea,
619                                          int lgth, 
620                                          uint16_t group, 
621                                          uint16_t elem,
622                                          TagName const & vr )
623 {
624    BinEntry* binEntry = 0;
625    DocEntry* currentEntry = GetDocEntryByNumber( group, elem);
626    if (!currentEntry)
627    {
628
629       // check if (group,element) DictEntry exists
630       // if it doesn't, create an entry in DictSet::VirtualEntry
631       // and use it
632
633    // Find out if the tag we received is in the dictionaries:
634       Dict *pubDict = Global::GetDicts()->GetDefaultPubDict();
635       DictEntry *dictEntry = pubDict->GetDictEntryByNumber(group, elem);
636
637       if (!dictEntry)
638       {
639          currentEntry = NewDocEntryByNumber(group, elem, vr);
640       }
641       else
642       {
643          currentEntry = NewDocEntryByNumber(group, elem);
644       }
645       if (!currentEntry)
646       {
647          dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: call to"
648                         " NewDocEntryByNumber failed.");
649          return NULL;
650       }
651       binEntry = new BinEntry(currentEntry);
652       if ( !AddEntry(binEntry))
653       {
654          dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: AddEntry"
655                         " failed allthough this is a creation.");
656       }
657    }
658    else
659    {
660       binEntry = dynamic_cast< BinEntry* >(currentEntry);
661       if ( !binEntry ) // Euuuuh? It wasn't a BinEntry
662                        // then we change it to a BinEntry ?
663                        // Shouldn't it be considered as an error ?
664       {
665          // We need to promote the DocEntry to a BinEntry:
666          binEntry = new BinEntry(currentEntry);
667          if (!RemoveEntry(currentEntry))
668          {
669             dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: removal"
670                            " of previous DocEntry failed.");
671             return NULL;
672          }
673          if ( !AddEntry(binEntry))
674          {
675             dbg.Verbose(0, "Document::ReplaceOrCreateByNumber: adding"
676                            " promoted BinEntry failed.");
677             return NULL;
678          }
679       }
680    }
681
682    SetEntryByNumber(binArea, lgth, group, elem);
683
684    return binEntry;
685 }  
686
687
688 /*
689  * \brief   Modifies the value of a given Header Entry (Dicom Element)
690  *          when it exists. Create it when unexistant.
691  * @param   Group   Group number of the Entry 
692  * @param   Elem  Element number of the Entry
693  * \return  pointer to the modified/created SeqEntry (NULL when creation
694  *          failed).
695  */
696 SeqEntry* Document::ReplaceOrCreateByNumber( uint16_t group, uint16_t elem)
697 {
698    SeqEntry* b = 0;
699    DocEntry* a = GetDocEntryByNumber( group, elem);
700    if (!a)
701    {
702       a = NewSeqEntryByNumber(group, elem);
703       if (!a)
704       {
705          return 0;
706       }
707
708       b = new SeqEntry(a, 1); // FIXME : 1 (Depth)
709       AddEntry(b);
710    }   
711    return b;
712
713  
714 /**
715  * \brief Set a new value if the invoked element exists
716  *        Seems to be useless !!!
717  * @param value new element value
718  * @param group  group number of the Entry 
719  * @param elem element number of the Entry
720  * \return  boolean 
721  */
722 bool Document::ReplaceIfExistByNumber(std::string const & value, 
723                                       uint16_t group, uint16_t elem ) 
724 {
725    SetEntryByNumber(value, group, elem);
726
727    return true;
728
729
730 //-----------------------------------------------------------------------------
731 // Protected
732
733 /**
734  * \brief   Checks if a given Dicom Element exists within the H table
735  * @param   group      Group number of the searched Dicom Element 
736  * @param   element  Element number of the searched Dicom Element 
737  * @return true is found
738  */
739 bool Document::CheckIfEntryExistByNumber(uint16_t group, uint16_t element )
740 {
741    const std::string &key = DictEntry::TranslateToKey(group, element );
742    return TagHT.count(key) != 0;
743 }
744
745 /**
746  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
747  *          the public and private dictionaries 
748  *          for the element value of a given tag.
749  * \warning Don't use any longer : use GetPubEntryByName
750  * @param   tagName name of the searched element.
751  * @return  Corresponding element value when it exists,
752  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
753  */
754 std::string Document::GetEntryByName(TagName const & tagName)
755 {
756    DictEntry* dictEntry = RefPubDict->GetDictEntryByName(tagName); 
757    if( !dictEntry )
758    {
759       return GDCM_UNFOUND;
760    }
761
762    return GetEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement());
763 }
764
765 /**
766  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
767  *          the public and private dictionaries 
768  *          for the element value representation of a given tag.
769  *
770  *          Obtaining the VR (Value Representation) might be needed by caller
771  *          to convert the string typed content to caller's native type 
772  *          (think of C++ vs Python). The VR is actually of a higher level
773  *          of semantics than just the native C++ type.
774  * @param   tagName name of the searched element.
775  * @return  Corresponding element value representation when it exists,
776  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
777  */
778 std::string Document::GetEntryVRByName(TagName const& tagName)
779 {
780    DictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
781    if( dictEntry == NULL)
782    {
783       return GDCM_UNFOUND;
784    }
785
786    DocEntry* elem = GetDocEntryByNumber(dictEntry->GetGroup(),
787                                         dictEntry->GetElement());
788    return elem->GetVR();
789 }
790
791 /**
792  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
793  *          the public and private dictionaries 
794  *          for the element value representation of a given tag.
795  * @param   group Group number of the searched tag.
796  * @param   element Element number of the searched tag.
797  * @return  Corresponding element value representation when it exists,
798  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
799  */
800 std::string Document::GetEntryByNumber(uint16_t group, uint16_t element)
801 {
802    TagKey key = DictEntry::TranslateToKey(group, element);
803    /// \todo use map methods, instead of multimap JPR
804    if ( !TagHT.count(key))
805    {
806       return GDCM_UNFOUND;
807    }
808
809    return ((ValEntry *)TagHT.find(key)->second)->GetValue();
810 }
811
812 /**
813  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
814  *          the public and private dictionaries 
815  *          for the element value representation of a given tag..
816  *
817  *          Obtaining the VR (Value Representation) might be needed by caller
818  *          to convert the string typed content to caller's native type 
819  *          (think of C++ vs Python). The VR is actually of a higher level
820  *          of semantics than just the native C++ type.
821  * @param   group     Group number of the searched tag.
822  * @param   element Element number of the searched tag.
823  * @return  Corresponding element value representation when it exists,
824  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
825  */
826 std::string Document::GetEntryVRByNumber(uint16_t group, uint16_t element)
827 {
828    DocEntry* elem = GetDocEntryByNumber(group, element);
829    if ( !elem )
830    {
831       return GDCM_UNFOUND;
832    }
833    return elem->GetVR();
834 }
835
836 /**
837  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
838  *          the public and private dictionaries 
839  *          for the value length of a given tag..
840  * @param   group     Group number of the searched tag.
841  * @param   element Element number of the searched tag.
842  * @return  Corresponding element length; -2 if not found
843  */
844 int Document::GetEntryLengthByNumber(uint16_t group, uint16_t element)
845 {
846    DocEntry* elem =  GetDocEntryByNumber(group, element);
847    if ( !elem )
848    {
849       return -2;  //magic number
850    }
851    return elem->GetLength();
852 }
853 /**
854  * \brief   Sets the value (string) of the Header Entry (Dicom Element)
855  * @param   content string value of the Dicom Element
856  * @param   tagName name of the searched Dicom Element.
857  * @return  true when found
858  */
859 bool Document::SetEntryByName(std::string const & content,
860                               TagName const & tagName)
861 {
862    DictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
863    if( !dictEntry )
864    {
865       return false;
866    }
867
868    return SetEntryByNumber(content,dictEntry->GetGroup(),
869                                    dictEntry->GetElement());
870 }
871
872 /**
873  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
874  *          through it's (group, element) and modifies it's content with
875  *          the given value.
876  * @param   content new value (string) to substitute with
877  * @param   group     group number of the Dicom Element to modify
878  * @param   element element number of the Dicom Element to modify
879  */
880 bool Document::SetEntryByNumber(std::string const& content, 
881                                 uint16_t group, uint16_t element) 
882 {
883    int c;
884    int l;
885
886    ValEntry* valEntry = GetValEntryByNumber(group, element);
887    if (!valEntry )
888    {
889       dbg.Verbose(0, "Document::SetEntryByNumber: no corresponding",
890                      " ValEntry (try promotion first).");
891       return false;
892    }
893    // Non even content must be padded with a space (020H)...
894    std::string finalContent = Util::DicomString( content.c_str() );
895    assert( !(finalContent.size() % 2) );
896    valEntry->SetValue(finalContent);
897
898    // Integers have a special treatement for their length:
899
900    l = finalContent.length();
901    if ( l != 0) // To avoid to be cheated by 'zero length' integers
902    {   
903       VRKey vr = valEntry->GetVR();
904       if( vr == "US" || vr == "SS" )
905       {
906          // for multivaluated items
907          c = Util::CountSubstring(content, "\\") + 1;
908          l = c*2;
909       }
910       else if( vr == "UL" || vr == "SL" )
911       {
912          // for multivaluated items
913          c = Util::CountSubstring(content, "\\") + 1;
914          l = c*4;;
915       }
916    }
917    valEntry->SetLength(l);
918    return true;
919
920
921 /**
922  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
923  *          through it's (group, element) and modifies it's content with
924  *          the given value.
925  * @param   content new value (void*  -> uint8_t*) to substitute with
926  * @param   lgth new value length
927  * @param   group     group number of the Dicom Element to modify
928  * @param   element element number of the Dicom Element to modify
929  */
930 bool Document::SetEntryByNumber(uint8_t*content, int lgth, 
931                                 uint16_t group, uint16_t element) 
932 {
933    (void)lgth;  //not used
934    TagKey key = DictEntry::TranslateToKey(group, element);
935    if ( !TagHT.count(key))
936    {
937       return false;
938    }
939
940 /* Hope Binary field length is *never* wrong    
941    if(lgth%2) // Non even length are padded with a space (020H).
942    {  
943       lgth++;
944       //content = content + '\0'; // fing a trick to enlarge a binary field?
945    }
946 */      
947    BinEntry* a = (BinEntry *)TagHT[key];           
948    a->SetBinArea(content);  
949    a->SetLength(lgth);
950    a->SetValue(GDCM_BINLOADED);
951
952    return true;
953
954
955 /**
956  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
957  *          in the PubDocEntrySet of this instance
958  *          through it's (group, element) and modifies it's length with
959  *          the given value.
960  * \warning Use with extreme caution.
961  * @param l new length to substitute with
962  * @param group     group number of the Entry to modify
963  * @param element element number of the Entry to modify
964  * @return  true on success, false otherwise.
965  */
966 bool Document::SetEntryLengthByNumber(uint32_t l, 
967                                       uint16_t group, uint16_t element) 
968 {
969    /// \todo use map methods, instead of multimap JPR
970    TagKey key = DictEntry::TranslateToKey(group, element);
971    if ( !TagHT.count(key) )
972    {
973       return false;
974    }
975    if ( l % 2 )
976    {
977       l++; // length must be even
978    }
979    ( ((TagHT.equal_range(key)).first)->second )->SetLength(l); 
980
981    return true ;
982 }
983
984 /**
985  * \brief   Gets (from Header) the offset  of a 'non string' element value 
986  *          (LoadElementValues has already be executed)
987  * @param group   group number of the Entry 
988  * @param elem  element number of the Entry
989  * @return File Offset of the Element Value 
990  */
991 size_t Document::GetEntryOffsetByNumber(uint16_t group, uint16_t elem) 
992 {
993    DocEntry* entry = GetDocEntryByNumber(group, elem);
994    if (!entry) 
995    {
996       dbg.Verbose(1, "Document::GetDocEntryByNumber: no entry present.");
997       return 0;
998    }
999    return entry->GetOffset();
1000 }
1001
1002 /**
1003  * \brief   Gets (from Header) a 'non string' element value 
1004  *          (LoadElementValues has already be executed)  
1005  * @param group   group number of the Entry 
1006  * @param elem  element number of the Entry
1007  * @return Pointer to the 'non string' area
1008  */
1009 void*  Document::GetEntryBinAreaByNumber(uint16_t group, uint16_t elem) 
1010 {
1011    DocEntry* entry = GetDocEntryByNumber(group, elem);
1012    if (!entry) 
1013    {
1014       dbg.Verbose(1, "Document::GetDocEntryByNumber: no entry");
1015       return 0;
1016    }
1017    if ( BinEntry* binEntry = dynamic_cast<BinEntry*>(entry) )
1018    {
1019       return binEntry->GetBinArea();
1020    }
1021
1022    return 0;
1023 }
1024
1025 /**
1026  * \brief         Loads (from disk) the element content 
1027  *                when a string is not suitable
1028  * @param group   group number of the Entry 
1029  * @param elem  element number of the Entry
1030  */
1031 void* Document::LoadEntryBinArea(uint16_t group, uint16_t elem)
1032 {
1033    DocEntry *docElement = GetDocEntryByNumber(group, elem);
1034    if ( !docElement )
1035    {
1036       return NULL;
1037    }
1038    size_t o =(size_t)docElement->GetOffset();
1039    Fp->seekg( o, std::ios_base::beg);
1040    size_t l = docElement->GetLength();
1041    uint8_t* a = new uint8_t[l];
1042    if(!a)
1043    {
1044       dbg.Verbose(0, "Document::LoadEntryBinArea cannot allocate a");
1045       return NULL;
1046    }
1047    Fp->read((char*)a, l);
1048    if( Fp->fail() || Fp->eof() )//Fp->gcount() == 1
1049    {
1050       delete[] a;
1051       return NULL;
1052    }
1053   /// \todo Drop any already existing void area! JPR
1054    if( !SetEntryBinAreaByNumber( a, group, elem ) )
1055    {
1056       dbg.Verbose(0, "Document::LoadEntryBinArea setting failed.");
1057    }
1058    return a;
1059 }
1060 /**
1061  * \brief         Loads (from disk) the element content 
1062  *                when a string is not suitable
1063  * @param element  Entry whose binArea is going to be loaded
1064  */
1065 void* Document::LoadEntryBinArea(BinEntry* element) 
1066 {
1067    size_t o =(size_t)element->GetOffset();
1068    Fp->seekg(o, std::ios_base::beg);
1069    size_t l = element->GetLength();
1070    uint8_t* a = new uint8_t[l];
1071    if( !a )
1072    {
1073       dbg.Verbose(0, "Document::LoadEntryBinArea cannot allocate a");
1074       return NULL;
1075    }
1076    element->SetBinArea((uint8_t*)a);
1077    /// \todo check the result 
1078    Fp->read((char*)a, l);
1079    if( Fp->fail() || Fp->eof()) //Fp->gcount() == 1
1080    {
1081       delete[] a;
1082       return NULL;
1083    }
1084
1085    return a;
1086 }
1087
1088 /**
1089  * \brief   Sets a 'non string' value to a given Dicom Element
1090  * @param   area area containing the 'non string' value
1091  * @param   group     Group number of the searched Dicom Element 
1092  * @param   element Element number of the searched Dicom Element 
1093  * @return  
1094  */
1095 bool Document::SetEntryBinAreaByNumber(uint8_t* area,
1096                                        uint16_t group, uint16_t element) 
1097 {
1098    DocEntry* currentEntry = GetDocEntryByNumber(group, element);
1099    if ( !currentEntry )
1100    {
1101       return false;
1102    }
1103    if ( BinEntry* binEntry = dynamic_cast<BinEntry*>(currentEntry) )
1104    {
1105       binEntry->SetBinArea( area );
1106       return true;
1107    }
1108    return true;
1109 }
1110
1111 /**
1112  * \brief   Update the entries with the shadow dictionary. 
1113  *          Only non even entries are analyzed       
1114  */
1115 void Document::UpdateShaEntries()
1116 {
1117    //DictEntry *entry;
1118    std::string vr;
1119    
1120    /// \todo TODO : still any use to explore recursively the whole structure?
1121 /*
1122    for(ListTag::iterator it=listEntries.begin();
1123        it!=listEntries.end();
1124        ++it)
1125    {
1126       // Odd group => from public dictionary
1127       if((*it)->GetGroup()%2==0)
1128          continue;
1129
1130       // Peer group => search the corresponding dict entry
1131       if(RefShaDict)
1132          entry=RefShaDict->GetDictEntryByNumber((*it)->GetGroup(),(*it)->GetElement());
1133       else
1134          entry=NULL;
1135
1136       if((*it)->IsImplicitVR())
1137          vr="Implicit";
1138       else
1139          vr=(*it)->GetVR();
1140
1141       (*it)->SetValue(GetDocEntryUnvalue(*it));  // to go on compiling
1142       if(entry){
1143          // Set the new entry and the new value
1144          (*it)->SetDictEntry(entry);
1145          CheckDocEntryVR(*it,vr);
1146
1147          (*it)->SetValue(GetDocEntryValue(*it));    // to go on compiling
1148  
1149       }
1150       else
1151       {
1152          // Remove precedent value transformation
1153          (*it)->SetDictEntry(NewVirtualDictEntry((*it)->GetGroup(),(*it)->GetElement(),vr));
1154       }
1155    }
1156 */   
1157 }
1158
1159 /**
1160  * \brief   Searches within the Header Entries for a Dicom Element of
1161  *          a given tag.
1162  * @param   tagName name of the searched Dicom Element.
1163  * @return  Corresponding Dicom Element when it exists, and NULL
1164  *          otherwise.
1165  */
1166 DocEntry* Document::GetDocEntryByName(TagName const & tagName)
1167 {
1168    DictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
1169    if( !dictEntry )
1170    {
1171       return NULL;
1172    }
1173
1174   return GetDocEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement());
1175 }
1176
1177 /**
1178  * \brief  retrieves a Dicom Element (the first one) using (group, element)
1179  * \warning (group, element) IS NOT an identifier inside the Dicom Header
1180  *           if you think it's NOT UNIQUE, check the count number
1181  *           and use iterators to retrieve ALL the Dicoms Elements within
1182  *           a given couple (group, element)
1183  * @param   group Group number of the searched Dicom Element 
1184  * @param   element Element number of the searched Dicom Element 
1185  * @return  
1186  */
1187 DocEntry* Document::GetDocEntryByNumber(uint16_t group, uint16_t element) 
1188 {
1189    TagKey key = DictEntry::TranslateToKey(group, element);
1190    if ( !TagHT.count(key))
1191    {
1192       return NULL;
1193    }
1194    return TagHT.find(key)->second;
1195 }
1196
1197 /**
1198  * \brief  Same as \ref Document::GetDocEntryByNumber except it only
1199  *         returns a result when the corresponding entry is of type
1200  *         ValEntry.
1201  * @return When present, the corresponding ValEntry. 
1202  */
1203 ValEntry* Document::GetValEntryByNumber(uint16_t group, uint16_t element)
1204 {
1205    DocEntry* currentEntry = GetDocEntryByNumber(group, element);
1206    if ( !currentEntry )
1207    {
1208       return 0;
1209    }
1210    if ( ValEntry* valEntry = dynamic_cast<ValEntry*>(currentEntry) )
1211    {
1212       return valEntry;
1213    }
1214    dbg.Verbose(0, "Document::GetValEntryByNumber: unfound ValEntry.");
1215
1216    return 0;
1217 }
1218
1219 /**
1220  * \brief         Loads the element while preserving the current
1221  *                underlying file position indicator as opposed to
1222  *                to LoadDocEntry that modifies it.
1223  * @param entry   Header Entry whose value shall be loaded. 
1224  * @return  
1225  */
1226 void Document::LoadDocEntrySafe(DocEntry * entry)
1227 {
1228    long PositionOnEntry = Fp->tellg();
1229    LoadDocEntry(entry);
1230    Fp->seekg(PositionOnEntry, std::ios_base::beg);
1231 }
1232
1233 /**
1234  * \brief   Swaps back the bytes of 4-byte long integer accordingly to
1235  *          processor order.
1236  * @return  The properly swaped 32 bits integer.
1237  */
1238 uint32_t Document::SwapLong(uint32_t a)
1239 {
1240    switch (SwapCode)
1241    {
1242       case    0 :
1243          break;
1244       case 4321 :
1245          a=( ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000) | 
1246              ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
1247          break;
1248    
1249       case 3412 :
1250          a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
1251          break;
1252    
1253       case 2143 :
1254          a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
1255          break;
1256       default :
1257          //std::cout << "swapCode= " << SwapCode << std::endl;
1258          dbg.Error(" Document::SwapLong : unset swap code");
1259          a = 0;
1260    }
1261    return a;
1262
1263
1264 /**
1265  * \brief   Unswaps back the bytes of 4-byte long integer accordingly to
1266  *          processor order.
1267  * @return  The properly unswaped 32 bits integer.
1268  */
1269 uint32_t Document::UnswapLong(uint32_t a)
1270 {
1271    return SwapLong(a);
1272 }
1273
1274 /**
1275  * \brief   Swaps the bytes so they agree with the processor order
1276  * @return  The properly swaped 16 bits integer.
1277  */
1278 uint16_t Document::SwapShort(uint16_t a)
1279 {
1280    if ( SwapCode == 4321 || SwapCode == 2143 )
1281    {
1282       a = ((( a << 8 ) & 0x0ff00 ) | (( a >> 8 ) & 0x00ff ) );
1283    }
1284    return a;
1285 }
1286
1287 /**
1288  * \brief   Unswaps the bytes so they agree with the processor order
1289  * @return  The properly unswaped 16 bits integer.
1290  */
1291 uint16_t Document::UnswapShort(uint16_t a)
1292 {
1293    return SwapShort(a);
1294 }
1295
1296 //-----------------------------------------------------------------------------
1297 // Private
1298
1299 /**
1300  * \brief   Parses a DocEntrySet (Zero-level DocEntries or SQ Item DocEntries)
1301  * @return  length of the parsed set. 
1302  */ 
1303 void Document::ParseDES(DocEntrySet *set, long offset, 
1304                         long l_max, bool delim_mode)
1305 {
1306    DocEntry *newDocEntry = 0;
1307    
1308    while (true)
1309    { 
1310       if ( !delim_mode && (Fp->tellg()-offset) >= l_max)
1311       {
1312          break;
1313       }
1314       newDocEntry = ReadNextDocEntry( );
1315       if ( !newDocEntry )
1316       {
1317          break;
1318       }
1319
1320       VRKey vr = newDocEntry->GetVR();
1321       if ( vr != "SQ" )
1322       {
1323                
1324          if ( Global::GetVR()->IsVROfGdcmStringRepresentable(vr) )
1325          {
1326          /////////////////////// ValEntry
1327             ValEntry* newValEntry =
1328                new ValEntry( newDocEntry->GetDictEntry() );
1329             newValEntry->Copy( newDocEntry );
1330              
1331             // When "set" is a Document, then we are at the top of the
1332             // hierarchy and the Key is simply of the form ( group, elem )...
1333             if (Document* dummy = dynamic_cast< Document* > ( set ) )
1334             {
1335                (void)dummy;
1336                newValEntry->SetKey( newValEntry->GetKey() );
1337             }
1338             // ...but when "set" is a SQItem, we are inserting this new
1339             // valEntry in a sequence item. Hence the key has the
1340             // generalized form (refer to \ref BaseTagKey):
1341             if (SQItem* parentSQItem = dynamic_cast< SQItem* > ( set ) )
1342             {
1343                newValEntry->SetKey(  parentSQItem->GetBaseTagKey()
1344                                    + newValEntry->GetKey() );
1345             }
1346              
1347             set->AddEntry( newValEntry );
1348             LoadDocEntry( newValEntry );
1349             if (newValEntry->IsItemDelimitor())
1350             {
1351                break;
1352             }
1353             if ( !delim_mode && (Fp->tellg()-offset) >= l_max)
1354             {
1355                break;
1356             }
1357          }
1358          else
1359          {
1360             if ( ! Global::GetVR()->IsVROfGdcmBinaryRepresentable(vr) )
1361             { 
1362                 ////// Neither ValEntry NOR BinEntry: should mean UNKOWN VR
1363                 dbg.Verbose(0, "Document::ParseDES: neither Valentry, "
1364                                "nor BinEntry. Probably unknown VR.");
1365             }
1366
1367          //////////////////// BinEntry or UNKOWN VR:
1368             BinEntry* newBinEntry =
1369                new BinEntry( newDocEntry->GetDictEntry() );  //LEAK
1370             newBinEntry->Copy( newDocEntry );
1371
1372             // When "this" is a Document the Key is simply of the
1373             // form ( group, elem )...
1374             if (Document* dummy = dynamic_cast< Document* > ( set ) )
1375             {
1376                (void)dummy;
1377                newBinEntry->SetKey( newBinEntry->GetKey() );
1378             }
1379             // but when "this" is a SQItem, we are inserting this new
1380             // valEntry in a sequence item, and the kay has the
1381             // generalized form (refer to \ref BaseTagKey):
1382             if (SQItem* parentSQItem = dynamic_cast< SQItem* > ( set ) )
1383             {
1384                newBinEntry->SetKey(  parentSQItem->GetBaseTagKey()
1385                                    + newBinEntry->GetKey() );
1386             }
1387
1388             set->AddEntry( newBinEntry );
1389             LoadDocEntry( newBinEntry );
1390          }
1391
1392          if (    ( newDocEntry->GetGroup()   == 0x7fe0 )
1393               && ( newDocEntry->GetElement() == 0x0010 ) )
1394          {
1395              TransferSyntaxType ts = GetTransferSyntax();
1396              if ( ts == RLELossless ) 
1397              {
1398                 long PositionOnEntry = Fp->tellg();
1399                 Fp->seekg( newDocEntry->GetOffset(), std::ios_base::beg );
1400                 ComputeRLEInfo();
1401                 Fp->seekg( PositionOnEntry, std::ios_base::beg );
1402              }
1403              else if ( IsJPEG() )
1404              {
1405                 long PositionOnEntry = Fp->tellg();
1406                 Fp->seekg( newDocEntry->GetOffset(), std::ios_base::beg );
1407                 ComputeJPEGFragmentInfo();
1408                 Fp->seekg( PositionOnEntry, std::ios_base::beg );
1409              }
1410          }
1411     
1412          // Just to make sure we are at the beginning of next entry.
1413          SkipToNextDocEntry(newDocEntry);
1414       }
1415       else
1416       {
1417          // VR = "SQ"
1418          unsigned long l = newDocEntry->GetReadLength();            
1419          if ( l != 0 ) // don't mess the delim_mode for zero-length sequence
1420          {
1421             if ( l == 0xffffffff )
1422             {
1423               delim_mode = true;
1424             }
1425             else
1426             {
1427               delim_mode = false;
1428             }
1429          }
1430          // no other way to create it ...
1431          SeqEntry* newSeqEntry =
1432             new SeqEntry( newDocEntry->GetDictEntry() );
1433          newSeqEntry->Copy( newDocEntry );
1434          newSeqEntry->SetDelimitorMode( delim_mode );
1435
1436          // At the top of the hierarchy, stands a Document. When "set"
1437          // is a Document, then we are building the first depth level.
1438          // Hence the SeqEntry we are building simply has a depth
1439          // level of one:
1440          if (Document* dummy = dynamic_cast< Document* > ( set ) )
1441          {
1442             (void)dummy;
1443             newSeqEntry->SetDepthLevel( 1 );
1444             newSeqEntry->SetKey( newSeqEntry->GetKey() );
1445          }
1446          // But when "set" is allready a SQItem, we are building a nested
1447          // sequence, and hence the depth level of the new SeqEntry
1448          // we are building, is one level deeper:
1449          if (SQItem* parentSQItem = dynamic_cast< SQItem* > ( set ) )
1450          {
1451             newSeqEntry->SetDepthLevel( parentSQItem->GetDepthLevel() + 1 );
1452             newSeqEntry->SetKey(  parentSQItem->GetBaseTagKey()
1453                                 + newSeqEntry->GetKey() );
1454          }
1455
1456          if ( l != 0 )
1457          {  // Don't try to parse zero-length sequences
1458             ParseSQ( newSeqEntry, 
1459                      newDocEntry->GetOffset(),
1460                      l, delim_mode);
1461          }
1462          set->AddEntry( newSeqEntry );
1463          if ( !delim_mode && (Fp->tellg()-offset) >= l_max)
1464          {
1465             break;
1466          }
1467       }
1468       delete newDocEntry;
1469    }
1470 }
1471
1472 /**
1473  * \brief   Parses a Sequence ( SeqEntry after SeqEntry)
1474  * @return  parsed length for this level
1475  */ 
1476 void Document::ParseSQ( SeqEntry* seqEntry,
1477                         long offset, long l_max, bool delim_mode)
1478 {
1479    int SQItemNumber = 0;
1480    bool dlm_mod;
1481
1482    while (true)
1483    {
1484       DocEntry* newDocEntry = ReadNextDocEntry();   
1485       if ( !newDocEntry )
1486       {
1487          // FIXME Should warn user
1488          break;
1489       }
1490       if( delim_mode )
1491       {
1492          if ( newDocEntry->IsSequenceDelimitor() )
1493          {
1494             seqEntry->SetSequenceDelimitationItem( newDocEntry );
1495             break;
1496          }
1497       }
1498       if ( !delim_mode && (Fp->tellg()-offset) >= l_max)
1499       {
1500           break;
1501       }
1502
1503       SQItem *itemSQ = new SQItem( seqEntry->GetDepthLevel() );
1504       std::ostringstream newBase;
1505       newBase << seqEntry->GetKey()
1506               << "/"
1507               << SQItemNumber
1508               << "#";
1509       itemSQ->SetBaseTagKey( newBase.str() );
1510       unsigned int l = newDocEntry->GetReadLength();
1511       
1512       if ( l == 0xffffffff )
1513       {
1514          dlm_mod = true;
1515       }
1516       else
1517       {
1518          dlm_mod = false;
1519       }
1520    
1521       ParseDES(itemSQ, newDocEntry->GetOffset(), l, dlm_mod);
1522       
1523       seqEntry->AddEntry( itemSQ, SQItemNumber ); 
1524       SQItemNumber++;
1525       if ( !delim_mode && ( Fp->tellg() - offset ) >= l_max )
1526       {
1527          break;
1528       }
1529    }
1530 }
1531
1532 /**
1533  * \brief         Loads the element content if its length doesn't exceed
1534  *                the value specified with Document::SetMaxSizeLoadEntry()
1535  * @param         entry Header Entry (Dicom Element) to be dealt with
1536  */
1537 void Document::LoadDocEntry(DocEntry* entry)
1538 {
1539    uint16_t group  = entry->GetGroup();
1540    std::string  vr = entry->GetVR();
1541    uint32_t length = entry->GetLength();
1542
1543    Fp->seekg((long)entry->GetOffset(), std::ios_base::beg);
1544
1545    // A SeQuence "contains" a set of Elements.  
1546    //          (fffe e000) tells us an Element is beginning
1547    //          (fffe e00d) tells us an Element just ended
1548    //          (fffe e0dd) tells us the current SeQuence just ended
1549    if( group == 0xfffe )
1550    {
1551       // NO more value field for SQ !
1552       return;
1553    }
1554
1555    // When the length is zero things are easy:
1556    if ( length == 0 )
1557    {
1558       ((ValEntry *)entry)->SetValue("");
1559       return;
1560    }
1561
1562    // The elements whose length is bigger than the specified upper bound
1563    // are not loaded. Instead we leave a short notice of the offset of
1564    // the element content and it's length.
1565
1566    std::ostringstream s;
1567    if (length > MaxSizeLoadEntry)
1568    {
1569       if (BinEntry* binEntryPtr = dynamic_cast< BinEntry* >(entry) )
1570       {  
1571          //s << "gdcm::NotLoaded (BinEntry)";
1572          s << GDCM_NOTLOADED;
1573          s << " Address:" << (long)entry->GetOffset();
1574          s << " Length:"  << entry->GetLength();
1575          s << " x(" << std::hex << entry->GetLength() << ")";
1576          binEntryPtr->SetValue(s.str());
1577       }
1578        // Be carefull : a BinEntry IS_A ValEntry ... 
1579       else if (ValEntry* valEntryPtr = dynamic_cast< ValEntry* >(entry) )
1580       {
1581         // s << "gdcm::NotLoaded. (ValEntry)";
1582          s << GDCM_NOTLOADED;  
1583          s << " Address:" << (long)entry->GetOffset();
1584          s << " Length:"  << entry->GetLength();
1585          s << " x(" << std::hex << entry->GetLength() << ")";
1586          valEntryPtr->SetValue(s.str());
1587       }
1588       else
1589       {
1590          // fusible
1591          std::cout<< "MaxSizeLoadEntry exceeded, neither a BinEntry "
1592                   << "nor a ValEntry ?! Should never print that !" << std::endl;
1593       }
1594
1595       // to be sure we are at the end of the value ...
1596       Fp->seekg((long)entry->GetOffset()+(long)entry->GetLength(),
1597                 std::ios_base::beg);
1598       return;
1599    }
1600
1601    // When we find a BinEntry not very much can be done :
1602    if (BinEntry* binEntryPtr = dynamic_cast< BinEntry* >(entry) )
1603    {
1604       s << GDCM_BINLOADED;
1605       binEntryPtr->SetValue(s.str());
1606       LoadEntryBinArea(binEntryPtr); // last one, not to erase length !
1607       return;
1608    }
1609     
1610    /// \todo Any compacter code suggested (?)
1611    if ( IsDocEntryAnInteger(entry) )
1612    {   
1613       uint32_t NewInt;
1614       int nbInt;
1615       // When short integer(s) are expected, read and convert the following 
1616       // n *two characters properly i.e. consider them as short integers as
1617       // opposed to strings.
1618       // Elements with Value Multiplicity > 1
1619       // contain a set of integers (not a single one)       
1620       if (vr == "US" || vr == "SS")
1621       {
1622          nbInt = length / 2;
1623          NewInt = ReadInt16();
1624          s << NewInt;
1625          if (nbInt > 1)
1626          {
1627             for (int i=1; i < nbInt; i++)
1628             {
1629                s << '\\';
1630                NewInt = ReadInt16();
1631                s << NewInt;
1632             }
1633          }
1634       }
1635       // See above comment on multiple integers (mutatis mutandis).
1636       else if (vr == "UL" || vr == "SL")
1637       {
1638          nbInt = length / 4;
1639          NewInt = ReadInt32();
1640          s << NewInt;
1641          if (nbInt > 1)
1642          {
1643             for (int i=1; i < nbInt; i++)
1644             {
1645                s << '\\';
1646                NewInt = ReadInt32();
1647                s << NewInt;
1648             }
1649          }
1650       }
1651 #ifdef GDCM_NO_ANSI_STRING_STREAM
1652       s << std::ends; // to avoid oddities on Solaris
1653 #endif //GDCM_NO_ANSI_STRING_STREAM
1654
1655       ((ValEntry *)entry)->SetValue(s.str());
1656       return;
1657    }
1658    
1659   // FIXME: We need an additional byte for storing \0 that is not on disk
1660    char *str = new char[length+1];
1661    Fp->read(str, (size_t)length);
1662    str[length] = '\0'; //this is only useful when length is odd
1663    // Special DicomString call to properly handle \0 and even length
1664    std::string newValue;
1665    if( length % 2 )
1666    {
1667       newValue = Util::DicomString(str, length+1);
1668       //dbg.Verbose(0, "Warning: bad length: ", length );
1669       dbg.Verbose(0, "For string :",  newValue.c_str()); 
1670       // Since we change the length of string update it length
1671       entry->SetReadLength(length+1);
1672    }
1673    else
1674    {
1675       newValue = Util::DicomString(str, length);
1676    }
1677    delete[] str;
1678
1679    if ( ValEntry* valEntry = dynamic_cast<ValEntry* >(entry) )
1680    {
1681       if ( Fp->fail() || Fp->eof())//Fp->gcount() == 1
1682       {
1683          dbg.Verbose(1, "Document::LoadDocEntry",
1684                         "unread element value");
1685          valEntry->SetValue(GDCM_UNREAD);
1686          return;
1687       }
1688
1689       if( vr == "UI" )
1690       {
1691          // Because of correspondance with the VR dic
1692          valEntry->SetValue(newValue);
1693       }
1694       else
1695       {
1696          valEntry->SetValue(newValue);
1697       }
1698    }
1699    else
1700    {
1701       dbg.Error(true, "Document::LoadDocEntry"
1702                       "Should have a ValEntry, here !");
1703    }
1704 }
1705
1706
1707 /**
1708  * \brief  Find the value Length of the passed Header Entry
1709  * @param  entry Header Entry whose length of the value shall be loaded. 
1710  */
1711 void Document::FindDocEntryLength( DocEntry *entry )
1712    throw ( FormatError )
1713 {
1714    uint16_t element = entry->GetElement();
1715    std::string  vr  = entry->GetVR();
1716    uint16_t length16;       
1717    
1718    if ( Filetype == ExplicitVR && !entry->IsImplicitVR() ) 
1719    {
1720       if ( vr == "OB" || vr == "OW" || vr == "SQ" || vr == "UN" ) 
1721       {
1722          // The following reserved two bytes (see PS 3.5-2003, section
1723          // "7.1.2 Data element structure with explicit vr", p 27) must be
1724          // skipped before proceeding on reading the length on 4 bytes.
1725          Fp->seekg( 2L, std::ios_base::cur);
1726          uint32_t length32 = ReadInt32();
1727
1728          if ( (vr == "OB" || vr == "OW") && length32 == 0xffffffff ) 
1729          {
1730             uint32_t lengthOB;
1731             try 
1732             {
1733                /// \todo rename that to FindDocEntryLengthOBOrOW since
1734                ///       the above test is on both OB and OW...
1735                lengthOB = FindDocEntryLengthOB();
1736             }
1737             catch ( FormatUnexpected )
1738             {
1739                // Computing the length failed (this happens with broken
1740                // files like gdcm-JPEG-LossLess3a.dcm). We still have a
1741                // chance to get the pixels by deciding the element goes
1742                // until the end of the file. Hence we artificially fix the
1743                // the length and proceed.
1744                long currentPosition = Fp->tellg();
1745                Fp->seekg(0L,std::ios_base::end);
1746                long lengthUntilEOF = Fp->tellg() - currentPosition;
1747                Fp->seekg(currentPosition, std::ios_base::beg);
1748                entry->SetLength(lengthUntilEOF);
1749                return;
1750             }
1751             entry->SetLength(lengthOB);
1752             return;
1753          }
1754          FixDocEntryFoundLength(entry, length32); 
1755          return;
1756       }
1757
1758       // Length is encoded on 2 bytes.
1759       length16 = ReadInt16();
1760       
1761       // We can tell the current file is encoded in big endian (like
1762       // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag
1763       // and it's value is the one of the encoding of a big endian file.
1764       // In order to deal with such big endian encoded files, we have
1765       // (at least) two strategies:
1766       // * when we load the "Transfer Syntax" tag with value of big endian
1767       //   encoding, we raise the proper flags. Then we wait for the end
1768       //   of the META group (0x0002) among which is "Transfer Syntax",
1769       //   before switching the swap code to big endian. We have to postpone
1770       //   the switching of the swap code since the META group is fully encoded
1771       //   in little endian, and big endian coding only starts at the next
1772       //   group. The corresponding code can be hard to analyse and adds
1773       //   many additional unnecessary tests for regular tags.
1774       // * the second strategy consists in waiting for trouble, that shall
1775       //   appear when we find the first group with big endian encoding. This
1776       //   is easy to detect since the length of a "Group Length" tag (the
1777       //   ones with zero as element number) has to be of 4 (0x0004). When we
1778       //   encounter 1024 (0x0400) chances are the encoding changed and we
1779       //   found a group with big endian encoding.
1780       // We shall use this second strategy. In order to make sure that we
1781       // can interpret the presence of an apparently big endian encoded
1782       // length of a "Group Length" without committing a big mistake, we
1783       // add an additional check: we look in the already parsed elements
1784       // for the presence of a "Transfer Syntax" whose value has to be "big
1785       // endian encoding". When this is the case, chances are we have got our
1786       // hands on a big endian encoded file: we switch the swap code to
1787       // big endian and proceed...
1788       if ( element  == 0x0000 && length16 == 0x0400 ) 
1789       {
1790          TransferSyntaxType ts = GetTransferSyntax();
1791          if ( ts != ExplicitVRBigEndian ) 
1792          {
1793             throw FormatError( "Document::FindDocEntryLength()",
1794                                " not explicit VR." );
1795             return;
1796          }
1797          length16 = 4;
1798          SwitchSwapToBigEndian();
1799          // Restore the unproperly loaded values i.e. the group, the element
1800          // and the dictionary entry depending on them.
1801          uint16_t correctGroup = SwapShort( entry->GetGroup() );
1802          uint16_t correctElem  = SwapShort( entry->GetElement() );
1803          DictEntry* newTag = GetDictEntryByNumber( correctGroup,
1804                                                        correctElem );
1805          if ( !newTag )
1806          {
1807             // This correct tag is not in the dictionary. Create a new one.
1808             newTag = NewVirtualDictEntry(correctGroup, correctElem);
1809          }
1810          // FIXME this can create a memory leaks on the old entry that be
1811          // left unreferenced.
1812          entry->SetDictEntry( newTag );
1813       }
1814        
1815       // Heuristic: well, some files are really ill-formed.
1816       if ( length16 == 0xffff) 
1817       {
1818          // 0xffff means that we deal with 'Unknown Length' Sequence  
1819          length16 = 0;
1820       }
1821       FixDocEntryFoundLength( entry, (uint32_t)length16 );
1822       return;
1823    }
1824    else
1825    {
1826       // Either implicit VR or a non DICOM conformal (see note below) explicit
1827       // VR that ommited the VR of (at least) this element. Farts happen.
1828       // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25
1829       // on Data elements "Implicit and Explicit VR Data Elements shall
1830       // not coexist in a Data Set and Data Sets nested within it".]
1831       // Length is on 4 bytes.
1832       
1833       FixDocEntryFoundLength( entry, ReadInt32() );
1834       return;
1835    }
1836 }
1837
1838 /**
1839  * \brief     Find the Value Representation of the current Dicom Element.
1840  * @param     entry
1841  */
1842 void Document::FindDocEntryVR( DocEntry *entry )
1843 {
1844    if ( Filetype != ExplicitVR )
1845    {
1846       return;
1847    }
1848
1849    char vr[3];
1850
1851    long positionOnEntry = Fp->tellg();
1852    // Warning: we believe this is explicit VR (Value Representation) because
1853    // we used a heuristic that found "UL" in the first tag. Alas this
1854    // doesn't guarantee that all the tags will be in explicit VR. In some
1855    // cases (see e-film filtered files) one finds implicit VR tags mixed
1856    // within an explicit VR file. Hence we make sure the present tag
1857    // is in explicit VR and try to fix things if it happens not to be
1858    // the case.
1859    
1860    Fp->read (vr, (size_t)2);
1861    vr[2] = 0;
1862
1863    if( !CheckDocEntryVR(entry, vr) )
1864    {
1865       Fp->seekg(positionOnEntry, std::ios_base::beg);
1866       // When this element is known in the dictionary we shall use, e.g. for
1867       // the semantics (see the usage of IsAnInteger), the VR proposed by the
1868       // dictionary entry. Still we have to flag the element as implicit since
1869       // we know now our assumption on expliciteness is not furfilled.
1870       // avoid  .
1871       if ( entry->IsVRUnknown() )
1872       {
1873          entry->SetVR("Implicit");
1874       }
1875       entry->SetImplicitVR();
1876    }
1877 }
1878
1879 /**
1880  * \brief     Check the correspondance between the VR of the header entry
1881  *            and the taken VR. If they are different, the header entry is 
1882  *            updated with the new VR.
1883  * @param     entry Header Entry to check
1884  * @param     vr    Dicom Value Representation
1885  * @return    false if the VR is incorrect of if the VR isn't referenced
1886  *            otherwise, it returns true
1887 */
1888 bool Document::CheckDocEntryVR(DocEntry *entry, VRKey vr)
1889 {
1890    std::string msg;
1891    bool realExplicit = true;
1892
1893    // Assume we are reading a falsely explicit VR file i.e. we reached
1894    // a tag where we expect reading a VR but are in fact we read the
1895    // first to bytes of the length. Then we will interogate (through find)
1896    // the dicom_vr dictionary with oddities like "\004\0" which crashes
1897    // both GCC and VC++ implementations of the STL map. Hence when the
1898    // expected VR read happens to be non-ascii characters we consider
1899    // we hit falsely explicit VR tag.
1900
1901    if ( !isalpha(vr[0]) && !isalpha(vr[1]) )
1902    {
1903       realExplicit = false;
1904    }
1905
1906    // CLEANME searching the dicom_vr at each occurence is expensive.
1907    // PostPone this test in an optional integrity check at the end
1908    // of parsing or only in debug mode.
1909    if ( realExplicit && !Global::GetVR()->Count(vr) )
1910    {
1911       realExplicit = false;
1912    }
1913
1914    if ( !realExplicit ) 
1915    {
1916       // We thought this was explicit VR, but we end up with an
1917       // implicit VR tag. Let's backtrack.   
1918       msg = Util::Format("Falsely explicit vr file (%04x,%04x)\n", 
1919                     entry->GetGroup(), entry->GetElement());
1920       dbg.Verbose(1, "Document::FindVR: ", msg.c_str());
1921
1922       if( entry->GetGroup() % 2 && entry->GetElement() == 0x0000)
1923       {
1924          // Group length is UL !
1925          DictEntry* newEntry = NewVirtualDictEntry(
1926                                    entry->GetGroup(), entry->GetElement(),
1927                                    "UL", "FIXME", "Group Length");
1928          entry->SetDictEntry( newEntry );
1929       }
1930       return false;
1931    }
1932
1933    if ( entry->IsVRUnknown() )
1934    {
1935       // When not a dictionary entry, we can safely overwrite the VR.
1936       if( entry->GetElement() == 0x0000 )
1937       {
1938          // Group length is UL !
1939          entry->SetVR("UL");
1940       }
1941       else
1942       {
1943          entry->SetVR(vr);
1944       }
1945    }
1946    else if ( entry->GetVR() != vr ) 
1947    {
1948       // The VR present in the file and the dictionary disagree. We assume
1949       // the file writer knew best and use the VR of the file. Since it would
1950       // be unwise to overwrite the VR of a dictionary (since it would
1951       // compromise it's next user), we need to clone the actual DictEntry
1952       // and change the VR for the read one.
1953       DictEntry* newEntry = NewVirtualDictEntry(
1954                                 entry->GetGroup(), entry->GetElement(),
1955                                 vr, "FIXME", entry->GetName());
1956       entry->SetDictEntry(newEntry);
1957    }
1958
1959    return true; 
1960 }
1961
1962 /**
1963  * \brief   Get the transformed value of the header entry. The VR value 
1964  *          is used to define the transformation to operate on the value
1965  * \warning NOT end user intended method !
1966  * @param   entry entry to tranform
1967  * @return  Transformed entry value
1968  */
1969 std::string Document::GetDocEntryValue(DocEntry *entry)
1970 {
1971    if ( IsDocEntryAnInteger(entry) && entry->IsImplicitVR() )
1972    {
1973       std::string val = ((ValEntry *)entry)->GetValue();
1974       std::string vr  = entry->GetVR();
1975       uint32_t length = entry->GetLength();
1976       std::ostringstream s;
1977       int nbInt;
1978
1979       // When short integer(s) are expected, read and convert the following 
1980       // n * 2 bytes properly i.e. as a multivaluated strings
1981       // (each single value is separated fromthe next one by '\'
1982       // as usual for standard multivaluated filels
1983       // Elements with Value Multiplicity > 1
1984       // contain a set of short integers (not a single one) 
1985    
1986       if( vr == "US" || vr == "SS" )
1987       {
1988          uint16_t newInt16;
1989
1990          nbInt = length / 2;
1991          for (int i=0; i < nbInt; i++) 
1992          {
1993             if( i != 0 )
1994             {
1995                s << '\\';
1996             }
1997             newInt16 = ( val[2*i+0] & 0xFF ) + ( ( val[2*i+1] & 0xFF ) << 8);
1998             newInt16 = SwapShort( newInt16 );
1999             s << newInt16;
2000          }
2001       }
2002
2003       // When integer(s) are expected, read and convert the following 
2004       // n * 4 bytes properly i.e. as a multivaluated strings
2005       // (each single value is separated fromthe next one by '\'
2006       // as usual for standard multivaluated filels
2007       // Elements with Value Multiplicity > 1
2008       // contain a set of integers (not a single one) 
2009       else if( vr == "UL" || vr == "SL" )
2010       {
2011          uint32_t newInt32;
2012
2013          nbInt = length / 4;
2014          for (int i=0; i < nbInt; i++) 
2015          {
2016             if( i != 0)
2017             {
2018                s << '\\';
2019             }
2020             newInt32 = ( val[4*i+0] & 0xFF )
2021                     + (( val[4*i+1] & 0xFF ) <<  8 )
2022                     + (( val[4*i+2] & 0xFF ) << 16 )
2023                     + (( val[4*i+3] & 0xFF ) << 24 );
2024             newInt32 = SwapLong( newInt32 );
2025             s << newInt32;
2026          }
2027       }
2028 #ifdef GDCM_NO_ANSI_STRING_STREAM
2029       s << std::ends; // to avoid oddities on Solaris
2030 #endif //GDCM_NO_ANSI_STRING_STREAM
2031       return s.str();
2032    }
2033
2034    return ((ValEntry *)entry)->GetValue();
2035 }
2036
2037 /**
2038  * \brief   Get the reverse transformed value of the header entry. The VR 
2039  *          value is used to define the reverse transformation to operate on
2040  *          the value
2041  * \warning NOT end user intended method !
2042  * @param   entry Entry to reverse transform
2043  * @return  Reverse transformed entry value
2044  */
2045 std::string Document::GetDocEntryUnvalue(DocEntry* entry)
2046 {
2047    if ( IsDocEntryAnInteger(entry) && entry->IsImplicitVR() )
2048    {
2049       std::string vr = entry->GetVR();
2050       std::vector<std::string> tokens;
2051       std::ostringstream s;
2052
2053       if ( vr == "US" || vr == "SS" ) 
2054       {
2055          uint16_t newInt16;
2056
2057          tokens.erase( tokens.begin(), tokens.end()); // clean any previous value
2058          Util::Tokenize (((ValEntry *)entry)->GetValue(), tokens, "\\");
2059          for (unsigned int i=0; i<tokens.size(); i++) 
2060          {
2061             newInt16 = atoi(tokens[i].c_str());
2062             s << (  newInt16        & 0xFF ) 
2063               << (( newInt16 >> 8 ) & 0xFF );
2064          }
2065          tokens.clear();
2066       }
2067       if ( vr == "UL" || vr == "SL")
2068       {
2069          uint32_t newInt32;
2070
2071          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
2072          Util::Tokenize (((ValEntry *)entry)->GetValue(), tokens, "\\");
2073          for (unsigned int i=0; i<tokens.size();i++) 
2074          {
2075             newInt32 = atoi(tokens[i].c_str());
2076             s << (char)(  newInt32         & 0xFF ) 
2077               << (char)(( newInt32 >>  8 ) & 0xFF )
2078               << (char)(( newInt32 >> 16 ) & 0xFF )
2079               << (char)(( newInt32 >> 24 ) & 0xFF );
2080          }
2081          tokens.clear();
2082       }
2083
2084 #ifdef GDCM_NO_ANSI_STRING_STREAM
2085       s << std::ends; // to avoid oddities on Solaris
2086 #endif //GDCM_NO_ANSI_STRING_STREAM
2087       return s.str();
2088    }
2089
2090    return ((ValEntry *)entry)->GetValue();
2091 }
2092
2093 /**
2094  * \brief   Skip a given Header Entry 
2095  * \warning NOT end user intended method !
2096  * @param   entry entry to skip
2097  */
2098 void Document::SkipDocEntry(DocEntry *entry) 
2099 {
2100    SkipBytes(entry->GetLength());
2101 }
2102
2103 /**
2104  * \brief   Skips to the begining of the next Header Entry 
2105  * \warning NOT end user intended method !
2106  * @param   entry entry to skip
2107  */
2108 void Document::SkipToNextDocEntry(DocEntry *entry) 
2109 {
2110    Fp->seekg((long)(entry->GetOffset()),     std::ios_base::beg);
2111    Fp->seekg( (long)(entry->GetReadLength()), std::ios_base::cur);
2112 }
2113
2114 /**
2115  * \brief   When the length of an element value is obviously wrong (because
2116  *          the parser went Jabberwocky) one can hope improving things by
2117  *          applying some heuristics.
2118  * @param   entry entry to check
2119  * @param   foundLength fist assumption about length    
2120  */
2121 void Document::FixDocEntryFoundLength(DocEntry *entry,
2122                                       uint32_t foundLength)
2123 {
2124    entry->SetReadLength( foundLength ); // will be updated only if a bug is found        
2125    if ( foundLength == 0xffffffff)
2126    {
2127       foundLength = 0;
2128    }
2129    
2130    uint16_t gr = entry->GetGroup();
2131    uint16_t el = entry->GetElement(); 
2132      
2133    if ( foundLength % 2)
2134    {
2135       std::ostringstream s;
2136       s << "Warning : Tag with uneven length "
2137         << foundLength 
2138         <<  " in x(" << std::hex << gr << "," << el <<")" << std::dec;
2139       dbg.Verbose(0, s.str().c_str());
2140    }
2141       
2142    //////// Fix for some naughty General Electric images.
2143    // Allthough not recent many such GE corrupted images are still present
2144    // on Creatis hard disks. Hence this fix shall remain when such images
2145    // are no longer in user (we are talking a few years, here)...
2146    // Note: XMedCom probably uses such a trick since it is able to read
2147    //       those pesky GE images ...
2148    if ( foundLength == 13)
2149    {
2150       // Only happens for this length !
2151       if ( entry->GetGroup()   != 0x0008
2152       || ( entry->GetElement() != 0x0070
2153         && entry->GetElement() != 0x0080 ) )
2154       {
2155          foundLength = 10;
2156          entry->SetReadLength(10); /// \todo a bug is to be fixed !?
2157       }
2158    }
2159
2160    //////// Fix for some brain-dead 'Leonardo' Siemens images.
2161    // Occurence of such images is quite low (unless one leaves close to a
2162    // 'Leonardo' source. Hence, one might consider commenting out the
2163    // following fix on efficiency reasons.
2164    else if ( entry->GetGroup()   == 0x0009 
2165         && ( entry->GetElement() == 0x1113
2166           || entry->GetElement() == 0x1114 ) )
2167    {
2168       foundLength = 4;
2169       entry->SetReadLength(4); /// \todo a bug is to be fixed !?
2170    } 
2171  
2172    else if ( entry->GetVR() == "SQ" )
2173    {
2174       foundLength = 0;      // ReadLength is unchanged 
2175    } 
2176     
2177    //////// We encountered a 'delimiter' element i.e. a tag of the form 
2178    // "fffe|xxxx" which is just a marker. Delimiters length should not be
2179    // taken into account.
2180    else if( entry->GetGroup() == 0xfffe )
2181    {    
2182      // According to the norm, fffe|0000 shouldn't exist. BUT the Philips
2183      // image gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm happens to
2184      // causes extra troubles...
2185      if( entry->GetElement() != 0x0000 )
2186      {
2187         foundLength = 0;
2188      }
2189    } 
2190            
2191    entry->SetUsableLength(foundLength);
2192 }
2193
2194 /**
2195  * \brief   Apply some heuristics to predict whether the considered 
2196  *          element value contains/represents an integer or not.
2197  * @param   entry The element value on which to apply the predicate.
2198  * @return  The result of the heuristical predicate.
2199  */
2200 bool Document::IsDocEntryAnInteger(DocEntry *entry)
2201 {
2202    uint16_t element = entry->GetElement();
2203    uint16_t group   = entry->GetGroup();
2204    const std::string & vr  = entry->GetVR();
2205    uint32_t length  = entry->GetLength();
2206
2207    // When we have some semantics on the element we just read, and if we
2208    // a priori know we are dealing with an integer, then we shall be
2209    // able to swap it's element value properly.
2210    if ( element == 0 )  // This is the group length of the group
2211    {  
2212       if ( length == 4 )
2213       {
2214          return true;
2215       }
2216       else 
2217       {
2218          // Allthough this should never happen, still some images have a
2219          // corrupted group length [e.g. have a glance at offset x(8336) of
2220          // gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm].
2221          // Since for dicom compliant and well behaved headers, the present
2222          // test is useless (and might even look a bit paranoid), when we
2223          // encounter such an ill-formed image, we simply display a warning
2224          // message and proceed on parsing (while crossing fingers).
2225          std::ostringstream s;
2226          long filePosition = Fp->tellg();
2227          s << "Erroneous Group Length element length  on : (" \
2228            << std::hex << group << " , " << element 
2229            << ") -before- position x(" << filePosition << ")"
2230            << "lgt : " << length;
2231          dbg.Verbose(0, "Document::IsDocEntryAnInteger", s.str().c_str() );
2232       }
2233    }
2234
2235    if ( vr == "UL" || vr == "US" || vr == "SL" || vr == "SS" )
2236    {
2237       return true;
2238    }
2239    
2240    return false;
2241 }
2242
2243 /**
2244  * \brief  Find the Length till the next sequence delimiter
2245  * \warning NOT end user intended method !
2246  * @return 
2247  */
2248
2249 uint32_t Document::FindDocEntryLengthOB()
2250    throw( FormatUnexpected )
2251 {
2252    // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
2253    long positionOnEntry = Fp->tellg();
2254    bool foundSequenceDelimiter = false;
2255    uint32_t totalLength = 0;
2256
2257    while ( !foundSequenceDelimiter )
2258    {
2259       uint16_t group;
2260       uint16_t elem;
2261       try
2262       {
2263          group = ReadInt16();
2264          elem  = ReadInt16();   
2265       }
2266       catch ( FormatError )
2267       {
2268          throw FormatError("Document::FindDocEntryLengthOB()",
2269                            " group or element not present.");
2270       }
2271
2272       // We have to decount the group and element we just read
2273       totalLength += 4;
2274      
2275       if ( group != 0xfffe || ( ( elem != 0xe0dd ) && ( elem != 0xe000 ) ) )
2276       {
2277          dbg.Verbose(1, "Document::FindDocEntryLengthOB: neither an Item "
2278                         "tag nor a Sequence delimiter tag."); 
2279          Fp->seekg(positionOnEntry, std::ios_base::beg);
2280          throw FormatUnexpected("Document::FindDocEntryLengthOB()",
2281                                 "Neither an Item tag nor a Sequence "
2282                                 "delimiter tag.");
2283       }
2284
2285       if ( elem == 0xe0dd )
2286       {
2287          foundSequenceDelimiter = true;
2288       }
2289
2290       uint32_t itemLength = ReadInt32();
2291       // We add 4 bytes since we just read the ItemLength with ReadInt32
2292       totalLength += itemLength + 4;
2293       SkipBytes(itemLength);
2294       
2295       if ( foundSequenceDelimiter )
2296       {
2297          break;
2298       }
2299    }
2300    Fp->seekg( positionOnEntry, std::ios_base::beg);
2301    return totalLength;
2302 }
2303
2304 /**
2305  * \brief Reads a supposed to be 16 Bits integer
2306  *       (swaps it depending on processor endianity) 
2307  * @return read value
2308  */
2309 uint16_t Document::ReadInt16()
2310    throw( FormatError )
2311 {
2312    uint16_t g;
2313    Fp->read ((char*)&g, (size_t)2);
2314    if ( Fp->fail() )
2315    {
2316       throw FormatError( "Document::ReadInt16()", " file error." );
2317    }
2318    if( Fp->eof() )
2319    {
2320       throw FormatError( "Document::ReadInt16()", "EOF." );
2321    }
2322    g = SwapShort(g); 
2323    return g;
2324 }
2325
2326 /**
2327  * \brief  Reads a supposed to be 32 Bits integer
2328  *         (swaps it depending on processor endianity)  
2329  * @return read value
2330  */
2331 uint32_t Document::ReadInt32()
2332    throw( FormatError )
2333 {
2334    uint32_t g;
2335    Fp->read ((char*)&g, (size_t)4);
2336    if ( Fp->fail() )
2337    {
2338       throw FormatError( "Document::ReadInt32()", " file error." );
2339    }
2340    if( Fp->eof() )
2341    {
2342       throw FormatError( "Document::ReadInt32()", "EOF." );
2343    }
2344    g = SwapLong(g);
2345    return g;
2346 }
2347
2348 /**
2349  * \brief skips bytes inside the source file 
2350  * \warning NOT end user intended method !
2351  * @return 
2352  */
2353 void Document::SkipBytes(uint32_t nBytes)
2354 {
2355    //FIXME don't dump the returned value
2356    Fp->seekg((long)nBytes, std::ios_base::cur);
2357 }
2358
2359 /**
2360  * \brief Loads all the needed Dictionaries
2361  * \warning NOT end user intended method !   
2362  */
2363 void Document::Initialise() 
2364 {
2365    RefPubDict = Global::GetDicts()->GetDefaultPubDict();
2366    RefShaDict = NULL;
2367    RLEInfo  = new RLEFramesInfo;
2368    JPEGInfo = new JPEGFragmentsInfo;
2369 }
2370
2371 /**
2372  * \brief   Discover what the swap code is (among little endian, big endian,
2373  *          bad little endian, bad big endian).
2374  *          sw is set
2375  * @return false when we are absolutely sure 
2376  *               it's neither ACR-NEMA nor DICOM
2377  *         true  when we hope ours assuptions are OK
2378  */
2379 bool Document::CheckSwap()
2380 {
2381    // The only guaranted way of finding the swap code is to find a
2382    // group tag since we know it's length has to be of four bytes i.e.
2383    // 0x00000004. Finding the swap code in then straigthforward. Trouble
2384    // occurs when we can't find such group...
2385    
2386    uint32_t  x = 4;  // x : for ntohs
2387    bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
2388    uint32_t  s32;
2389    uint16_t  s16;
2390        
2391    char deb[HEADER_LENGTH_TO_READ];
2392     
2393    // First, compare HostByteOrder and NetworkByteOrder in order to
2394    // determine if we shall need to swap bytes (i.e. the Endian type).
2395    if ( x == ntohs(x) )
2396    {
2397       net2host = true;
2398    }
2399    else
2400    {
2401       net2host = false;
2402    }
2403          
2404    // The easiest case is the one of a DICOM header, since it possesses a
2405    // file preamble where it suffice to look for the string "DICM".
2406    Fp->read(deb, HEADER_LENGTH_TO_READ);
2407    
2408    char *entCur = deb + 128;
2409    if( memcmp(entCur, "DICM", (size_t)4) == 0 )
2410    {
2411       dbg.Verbose(1, "Document::CheckSwap:", "looks like DICOM Version3");
2412       
2413       // Next, determine the value representation (VR). Let's skip to the
2414       // first element (0002, 0000) and check there if we find "UL" 
2415       // - or "OB" if the 1st one is (0002,0001) -,
2416       // in which case we (almost) know it is explicit VR.
2417       // WARNING: if it happens to be implicit VR then what we will read
2418       // is the length of the group. If this ascii representation of this
2419       // length happens to be "UL" then we shall believe it is explicit VR.
2420       // FIXME: in order to fix the above warning, we could read the next
2421       // element value (or a couple of elements values) in order to make
2422       // sure we are not commiting a big mistake.
2423       // We need to skip :
2424       // * the 128 bytes of File Preamble (often padded with zeroes),
2425       // * the 4 bytes of "DICM" string,
2426       // * the 4 bytes of the first tag (0002, 0000),or (0002, 0001)
2427       // i.e. a total of  136 bytes.
2428       entCur = deb + 136;
2429      
2430       // FIXME : FIXME:
2431       // Sometimes (see : gdcmData/icone.dcm) group 0x0002 *is* Explicit VR,
2432       // but elem 0002,0010 (Transfert Syntax) tells us the file is
2433       // *Implicit* VR.  -and it is !- 
2434       
2435       if( memcmp(entCur, "UL", (size_t)2) == 0 ||
2436           memcmp(entCur, "OB", (size_t)2) == 0 ||
2437           memcmp(entCur, "UI", (size_t)2) == 0 ||
2438           memcmp(entCur, "CS", (size_t)2) == 0 )  // CS, to remove later
2439                                                     // when Write DCM *adds*
2440       // FIXME
2441       // Use Document::dicom_vr to test all the possibilities
2442       // instead of just checking for UL, OB and UI !? group 0000 
2443       {
2444          Filetype = ExplicitVR;
2445          dbg.Verbose(1, "Document::CheckSwap:",
2446                      "explicit Value Representation");
2447       } 
2448       else 
2449       {
2450          Filetype = ImplicitVR;
2451          dbg.Verbose(1, "Document::CheckSwap:",
2452                      "not an explicit Value Representation");
2453       }
2454       
2455       if ( net2host )
2456       {
2457          SwapCode = 4321;
2458          dbg.Verbose(1, "Document::CheckSwap:",
2459                         "HostByteOrder != NetworkByteOrder");
2460       }
2461       else 
2462       {
2463          SwapCode = 0;
2464          dbg.Verbose(1, "Document::CheckSwap:",
2465                         "HostByteOrder = NetworkByteOrder");
2466       }
2467       
2468       // Position the file position indicator at first tag (i.e.
2469       // after the file preamble and the "DICM" string).
2470       Fp->seekg(0, std::ios_base::beg);
2471       Fp->seekg ( 132L, std::ios_base::beg);
2472       return true;
2473    } // End of DicomV3
2474
2475    // Alas, this is not a DicomV3 file and whatever happens there is no file
2476    // preamble. We can reset the file position indicator to where the data
2477    // is (i.e. the beginning of the file).
2478    dbg.Verbose(1, "Document::CheckSwap:", "not a DICOM Version3 file");
2479    Fp->seekg(0, std::ios_base::beg);
2480
2481    // Our next best chance would be to be considering a 'clean' ACR/NEMA file.
2482    // By clean we mean that the length of the first tag is written down.
2483    // If this is the case and since the length of the first group HAS to be
2484    // four (bytes), then determining the proper swap code is straightforward.
2485
2486    entCur = deb + 4;
2487    // We assume the array of char we are considering contains the binary
2488    // representation of a 32 bits integer. Hence the following dirty
2489    // trick :
2490    s32 = *((uint32_t *)(entCur));
2491       
2492    switch( s32 )
2493    {
2494       case 0x00040000 :
2495          SwapCode = 3412;
2496          Filetype = ACR;
2497          return true;
2498       case 0x04000000 :
2499          SwapCode = 4321;
2500          Filetype = ACR;
2501          return true;
2502       case 0x00000400 :
2503          SwapCode = 2143;
2504          Filetype = ACR;
2505          return true;
2506       case 0x00000004 :
2507          SwapCode = 0;
2508          Filetype = ACR;
2509          return true;
2510       default :
2511          // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file.
2512          // It is time for despaired wild guesses. 
2513          // So, let's check if this file wouldn't happen to be 'dirty' ACR/NEMA,
2514          //  i.e. the 'group length' element is not present :     
2515          
2516          //  check the supposed to be 'group number'
2517          //  0x0002 or 0x0004 or 0x0008
2518          //  to determine ' SwapCode' value .
2519          //  Only 0 or 4321 will be possible 
2520          //  (no oportunity to check for the formerly well known
2521          //  ACR-NEMA 'Bad Big Endian' or 'Bad Little Endian' 
2522          //  if unsuccessfull (i.e. neither 0x0002 nor 0x0200 etc -4, 8-) 
2523          //  the file IS NOT ACR-NEMA nor DICOM V3
2524          //  Find a trick to tell it the caller...
2525       
2526          s16 = *((uint16_t *)(deb));
2527       
2528          switch ( s16 )
2529          {
2530             case 0x0002 :
2531             case 0x0004 :
2532             case 0x0008 :      
2533                SwapCode = 0;
2534                Filetype = ACR;
2535                return true;
2536             case 0x0200 :
2537             case 0x0400 :
2538             case 0x0800 : 
2539                SwapCode = 4321;
2540                Filetype = ACR;
2541                return true;
2542             default :
2543                dbg.Verbose(0, "Document::CheckSwap:",
2544                      "ACR/NEMA unfound swap info (Really hopeless !)"); 
2545                Filetype = Unknown;     
2546                return false;
2547          }
2548          // Then the only info we have is the net2host one.
2549          //if (! net2host )
2550          //   SwapCode = 0;
2551          //else
2552          //  SwapCode = 4321;
2553          //return;
2554    }
2555 }
2556
2557 /**
2558  * \brief Restore the unproperly loaded values i.e. the group, the element
2559  *        and the dictionary entry depending on them. 
2560  */
2561 void Document::SwitchSwapToBigEndian() 
2562 {
2563    dbg.Verbose(1, "Document::SwitchSwapToBigEndian",
2564                   "Switching to BigEndian mode.");
2565    if ( SwapCode == 0    ) 
2566    {
2567       SwapCode = 4321;
2568    }
2569    else if ( SwapCode == 4321 ) 
2570    {
2571       SwapCode = 0;
2572    }
2573    else if ( SwapCode == 3412 ) 
2574    {
2575       SwapCode = 2143;
2576    }
2577    else if ( SwapCode == 2143 )
2578    {
2579       SwapCode = 3412;
2580    }
2581 }
2582
2583 /**
2584  * \brief  during parsing, Header Elements too long are not loaded in memory 
2585  * @param newSize
2586  */
2587 void Document::SetMaxSizeLoadEntry(long newSize) 
2588 {
2589    if ( newSize < 0 )
2590    {
2591       return;
2592    }
2593    if ((uint32_t)newSize >= (uint32_t)0xffffffff )
2594    {
2595       MaxSizeLoadEntry = 0xffffffff;
2596       return;
2597    }
2598    MaxSizeLoadEntry = newSize;
2599 }
2600
2601
2602 /**
2603  * \brief Header Elements too long will not be printed
2604  * \todo  See comments of \ref Document::MAX_SIZE_PRINT_ELEMENT_VALUE 
2605  * @param newSize
2606  */
2607 void Document::SetMaxSizePrintEntry(long newSize) 
2608 {
2609    //DOH !! This is exactly SetMaxSizeLoadEntry FIXME FIXME
2610    if ( newSize < 0 )
2611    {
2612       return;
2613    }
2614    if ((uint32_t)newSize >= (uint32_t)0xffffffff )
2615    {
2616       MaxSizePrintEntry = 0xffffffff;
2617       return;
2618    }
2619    MaxSizePrintEntry = newSize;
2620 }
2621
2622
2623
2624 /**
2625  * \brief   Read the next tag but WITHOUT loading it's value
2626  *          (read the 'Group Number', the 'Element Number',
2627  *           gets the Dict Entry
2628  *          gets the VR, gets the length, gets the offset value)
2629  * @return  On succes the newly created DocEntry, NULL on failure.      
2630  */
2631 DocEntry* Document::ReadNextDocEntry()
2632 {
2633    uint16_t group;
2634    uint16_t elem;
2635
2636    try
2637    {
2638       group = ReadInt16();
2639       elem  = ReadInt16();
2640    }
2641    catch ( FormatError e )
2642    {
2643       // We reached the EOF (or an error occured) therefore 
2644       // header parsing has to be considered as finished.
2645       //std::cout << e;
2646       return 0;
2647    }
2648
2649    DocEntry *newEntry = NewDocEntryByNumber(group, elem);
2650    FindDocEntryVR(newEntry);
2651
2652    try
2653    {
2654       FindDocEntryLength(newEntry);
2655    }
2656    catch ( FormatError e )
2657    {
2658       // Call it quits
2659       //std::cout << e;
2660       delete newEntry;
2661       return 0;
2662    }
2663
2664    newEntry->SetOffset(Fp->tellg());  
2665
2666    return newEntry;
2667 }
2668
2669
2670 /**
2671  * \brief   Generate a free TagKey i.e. a TagKey that is not present
2672  *          in the TagHt dictionary.
2673  * @param   group The generated tag must belong to this group.  
2674  * @return  The element of tag with given group which is fee.
2675  */
2676 uint32_t Document::GenerateFreeTagKeyInGroup(uint16_t group) 
2677 {
2678    for (uint32_t elem = 0; elem < UINT32_MAX; elem++) 
2679    {
2680       TagKey key = DictEntry::TranslateToKey(group, elem);
2681       if (TagHT.count(key) == 0)
2682       {
2683          return elem;
2684       }
2685    }
2686    return UINT32_MAX;
2687 }
2688
2689 /**
2690  * \brief   Assuming the internal file pointer \ref Document::Fp 
2691  *          is placed at the beginning of a tag check whether this
2692  *          tag is (TestGroup, TestElement).
2693  * \warning On success the internal file pointer \ref Document::Fp
2694  *          is modified to point after the tag.
2695  *          On failure (i.e. when the tag wasn't the expected tag
2696  *          (TestGroup, TestElement) the internal file pointer
2697  *          \ref Document::Fp is restored to it's original position.
2698  * @param   testGroup   The expected group of the tag.
2699  * @param   testElement The expected Element of the tag.
2700  * @return  True on success, false otherwise.
2701  */
2702 bool Document::ReadTag(uint16_t testGroup, uint16_t testElement)
2703 {
2704    long positionOnEntry = Fp->tellg();
2705    long currentPosition = Fp->tellg();          // On debugging purposes
2706
2707    //// Read the Item Tag group and element, and make
2708    // sure they are what we expected:
2709    uint16_t itemTagGroup;
2710    uint16_t itemTagElement;
2711    try
2712    {
2713       itemTagGroup   = ReadInt16();
2714       itemTagElement = ReadInt16();
2715    }
2716    catch ( FormatError e )
2717    {
2718       //std::cerr << e << std::endl;
2719       return false;
2720    }
2721    if ( itemTagGroup != testGroup || itemTagElement != testElement )
2722    {
2723       std::ostringstream s;
2724       s << "   We should have found tag (";
2725       s << std::hex << testGroup << "," << testElement << ")" << std::endl;
2726       s << "   but instead we encountered tag (";
2727       s << std::hex << itemTagGroup << "," << itemTagElement << ")"
2728         << std::endl;
2729       s << "  at address: " << (unsigned)currentPosition << std::endl;
2730       dbg.Verbose(0, "Document::ReadItemTagLength: wrong Item Tag found:");
2731       dbg.Verbose(0, s.str().c_str());
2732       Fp->seekg(positionOnEntry, std::ios_base::beg);
2733
2734       return false;
2735    }
2736    return true;
2737 }
2738
2739 /**
2740  * \brief   Assuming the internal file pointer \ref Document::Fp 
2741  *          is placed at the beginning of a tag (TestGroup, TestElement),
2742  *          read the length associated to the Tag.
2743  * \warning On success the internal file pointer \ref Document::Fp
2744  *          is modified to point after the tag and it's length.
2745  *          On failure (i.e. when the tag wasn't the expected tag
2746  *          (TestGroup, TestElement) the internal file pointer
2747  *          \ref Document::Fp is restored to it's original position.
2748  * @param   testGroup   The expected group of the tag.
2749  * @param   testElement The expected Element of the tag.
2750  * @return  On success returns the length associated to the tag. On failure
2751  *          returns 0.
2752  */
2753 uint32_t Document::ReadTagLength(uint16_t testGroup, uint16_t testElement)
2754 {
2755    long positionOnEntry = Fp->tellg();
2756    (void)positionOnEntry;
2757
2758    if ( !ReadTag(testGroup, testElement) )
2759    {
2760       return 0;
2761    }
2762                                                                                 
2763    //// Then read the associated Item Length
2764    long currentPosition = Fp->tellg();
2765    uint32_t itemLength  = ReadInt32();
2766    {
2767       std::ostringstream s;
2768       s << "Basic Item Length is: "
2769         << itemLength << std::endl;
2770       s << "  at address: " << (unsigned)currentPosition << std::endl;
2771       dbg.Verbose(0, "Document::ReadItemTagLength: ", s.str().c_str());
2772    }
2773    return itemLength;
2774 }
2775
2776 /**
2777  * \brief When parsing the Pixel Data of an encapsulated file, read
2778  *        the basic offset table (when present, and BTW dump it).
2779  */
2780 void Document::ReadAndSkipEncapsulatedBasicOffsetTable()
2781 {
2782    //// Read the Basic Offset Table Item Tag length...
2783    uint32_t itemLength = ReadTagLength(0xfffe, 0xe000);
2784
2785    // When present, read the basic offset table itself.
2786    // Notes: - since the presence of this basic offset table is optional
2787    //          we can't rely on it for the implementation, and we will simply
2788    //          trash it's content (when present).
2789    //        - still, when present, we could add some further checks on the
2790    //          lengths, but we won't bother with such fuses for the time being.
2791    if ( itemLength != 0 )
2792    {
2793       char* basicOffsetTableItemValue = new char[itemLength + 1];
2794       Fp->read(basicOffsetTableItemValue, itemLength);
2795
2796 #ifdef GDCM_DEBUG
2797       for (unsigned int i=0; i < itemLength; i += 4 )
2798       {
2799          uint32_t individualLength = str2num( &basicOffsetTableItemValue[i],
2800                                               uint32_t);
2801          std::ostringstream s;
2802          s << "   Read one length: ";
2803          s << std::hex << individualLength << std::endl;
2804          dbg.Verbose(0,
2805                      "Document::ReadAndSkipEncapsulatedBasicOffsetTable: ",
2806                      s.str().c_str());
2807       }
2808 #endif //GDCM_DEBUG
2809
2810       delete[] basicOffsetTableItemValue;
2811    }
2812 }
2813
2814 /**
2815  * \brief Parse pixel data from disk of [multi-]fragment RLE encoding.
2816  *        Compute the RLE extra information and store it in \ref RLEInfo
2817  *        for later pixel retrieval usage.
2818  */
2819 void Document::ComputeRLEInfo()
2820 {
2821    TransferSyntaxType ts = GetTransferSyntax();
2822    if ( ts != RLELossless )
2823    {
2824       return;
2825    }
2826
2827    // Encoded pixel data: for the time being we are only concerned with
2828    // Jpeg or RLE Pixel data encodings.
2829    // As stated in PS 3.5-2003, section 8.2 p44:
2830    // "If sent in Encapsulated Format (i.e. other than the Native Format) the
2831    //  value representation OB is used".
2832    // Hence we expect an OB value representation. Concerning OB VR,
2833    // the section PS 3.5-2003, section A.4.c p 58-59, states:
2834    // "For the Value Representations OB and OW, the encoding shall meet the
2835    //   following specifications depending on the Data element tag:"
2836    //   [...snip...]
2837    //    - the first item in the sequence of items before the encoded pixel
2838    //      data stream shall be basic offset table item. The basic offset table
2839    //      item value, however, is not required to be present"
2840
2841    ReadAndSkipEncapsulatedBasicOffsetTable();
2842
2843    // Encapsulated RLE Compressed Images (see PS 3.5-2003, Annex G)
2844    // Loop on the individual frame[s] and store the information
2845    // on the RLE fragments in a RLEFramesInfo.
2846    // Note: - when only a single frame is present, this is a
2847    //         classical image.
2848    //       - when more than one frame are present, then we are in 
2849    //         the case of a multi-frame image.
2850    long frameLength;
2851    while ( (frameLength = ReadTagLength(0xfffe, 0xe000)) )
2852    { 
2853       // Parse the RLE Header and store the corresponding RLE Segment
2854       // Offset Table information on fragments of this current Frame.
2855       // Note that the fragment pixels themselves are not loaded
2856       // (but just skipped).
2857       long frameOffset = Fp->tellg();
2858
2859       uint32_t nbRleSegments = ReadInt32();
2860       if ( nbRleSegments > 16 )
2861       {
2862          // There should be at most 15 segments (refer to RLEFrame class)
2863          dbg.Verbose(0, "Document::ComputeRLEInfo: too many segments.");
2864       }
2865  
2866       uint32_t rleSegmentOffsetTable[15];
2867       for( int k = 1; k <= 15; k++ )
2868       {
2869          rleSegmentOffsetTable[k] = ReadInt32();
2870       }
2871
2872       // Deduce from both the RLE Header and the frameLength the
2873       // fragment length, and again store this info in a
2874       // RLEFramesInfo.
2875       long rleSegmentLength[15];
2876       // skipping (not reading) RLE Segments
2877       if ( nbRleSegments > 1)
2878       {
2879          for(unsigned int k = 1; k <= nbRleSegments-1; k++)
2880          {
2881              rleSegmentLength[k] =  rleSegmentOffsetTable[k+1]
2882                                   - rleSegmentOffsetTable[k];
2883              SkipBytes(rleSegmentLength[k]);
2884           }
2885        }
2886
2887        rleSegmentLength[nbRleSegments] = frameLength 
2888                                       - rleSegmentOffsetTable[nbRleSegments];
2889        SkipBytes(rleSegmentLength[nbRleSegments]);
2890
2891        // Store the collected info
2892        RLEFrame* newFrameInfo = new RLEFrame;
2893        newFrameInfo->NumberFragments = nbRleSegments;
2894        for( unsigned int uk = 1; uk <= nbRleSegments; uk++ )
2895        {
2896           newFrameInfo->Offset[uk] = frameOffset + rleSegmentOffsetTable[uk];
2897           newFrameInfo->Length[uk] = rleSegmentLength[uk];
2898        }
2899        RLEInfo->Frames.push_back( newFrameInfo );
2900    }
2901
2902    // Make sure that at the end of the item we encounter a 'Sequence
2903    // Delimiter Item':
2904    if ( !ReadTag(0xfffe, 0xe0dd) )
2905    {
2906       dbg.Verbose(0, "Document::ComputeRLEInfo: no sequence delimiter ");
2907       dbg.Verbose(0, "    item at end of RLE item sequence");
2908    }
2909 }
2910
2911 /**
2912  * \brief Parse pixel data from disk of [multi-]fragment Jpeg encoding.
2913  *        Compute the jpeg extra information (fragment[s] offset[s] and
2914  *        length) and store it[them] in \ref JPEGInfo for later pixel
2915  *        retrieval usage.
2916  */
2917 void Document::ComputeJPEGFragmentInfo()
2918 {
2919    // If you need to, look for comments of ComputeRLEInfo().
2920    if ( ! IsJPEG() )
2921    {
2922       return;
2923    }
2924
2925    ReadAndSkipEncapsulatedBasicOffsetTable();
2926
2927    // Loop on the fragments[s] and store the parsed information in a
2928    // JPEGInfo.
2929    long fragmentLength;
2930    while ( (fragmentLength = ReadTagLength(0xfffe, 0xe000)) )
2931    { 
2932       long fragmentOffset = Fp->tellg();
2933
2934        // Store the collected info
2935        JPEGFragment* newFragment = new JPEGFragment;
2936        newFragment->Offset = fragmentOffset;
2937        newFragment->Length = fragmentLength;
2938        JPEGInfo->Fragments.push_back( newFragment );
2939
2940        SkipBytes( fragmentLength );
2941    }
2942
2943    // Make sure that at the end of the item we encounter a 'Sequence
2944    // Delimiter Item':
2945    if ( !ReadTag(0xfffe, 0xe0dd) )
2946    {
2947       dbg.Verbose(0, "Document::ComputeRLEInfo: no sequence delimiter ");
2948       dbg.Verbose(0, "    item at end of JPEG item sequence");
2949    }
2950 }
2951
2952 /**
2953  * \brief Walk recursively the given \ref DocEntrySet, and feed
2954  *        the given hash table (\ref TagDocEntryHT) with all the
2955  *        \ref DocEntry (Dicom entries) encountered.
2956  *        This method does the job for \ref BuildFlatHashTable.
2957  * @param builtHT Where to collect all the \ref DocEntry encountered
2958  *        when recursively walking the given set.
2959  * @param set The structure to be traversed (recursively).
2960  */
2961 void Document::BuildFlatHashTableRecurse( TagDocEntryHT& builtHT,
2962                                           DocEntrySet* set )
2963
2964    if (ElementSet* elementSet = dynamic_cast< ElementSet* > ( set ) )
2965    {
2966       TagDocEntryHT const & currentHT = elementSet->GetTagHT();
2967       for( TagDocEntryHT::const_iterator i  = currentHT.begin();
2968                                          i != currentHT.end();
2969                                        ++i)
2970       {
2971          DocEntry* entry = i->second;
2972          if ( SeqEntry* seqEntry = dynamic_cast<SeqEntry*>(entry) )
2973          {
2974             const ListSQItem& items = seqEntry->GetSQItems();
2975             for( ListSQItem::const_iterator item  = items.begin();
2976                                             item != items.end();
2977                                           ++item)
2978             {
2979                BuildFlatHashTableRecurse( builtHT, *item );
2980             }
2981             continue;
2982          }
2983          builtHT[entry->GetKey()] = entry;
2984       }
2985       return;
2986     }
2987
2988    if (SQItem* SQItemSet = dynamic_cast< SQItem* > ( set ) )
2989    {
2990       const ListDocEntry& currentList = SQItemSet->GetDocEntries();
2991       for (ListDocEntry::const_iterator i  = currentList.begin();
2992                                         i != currentList.end();
2993                                       ++i)
2994       {
2995          DocEntry* entry = *i;
2996          if ( SeqEntry* seqEntry = dynamic_cast<SeqEntry*>(entry) )
2997          {
2998             const ListSQItem& items = seqEntry->GetSQItems();
2999             for( ListSQItem::const_iterator item  = items.begin();
3000                                             item != items.end();
3001                                           ++item)
3002             {
3003                BuildFlatHashTableRecurse( builtHT, *item );
3004             }
3005             continue;
3006          }
3007          builtHT[entry->GetKey()] = entry;
3008       }
3009
3010    }
3011 }
3012
3013 /**
3014  * \brief Build a \ref TagDocEntryHT (i.e. a std::map<>) from the current
3015  *        Document.
3016  *
3017  *        The structure used by a Document (through \ref ElementSet),
3018  *        in order to old the parsed entries of a Dicom header, is a recursive
3019  *        one. This is due to the fact that the sequences (when present)
3020  *        can be nested. Additionaly, the sequence items (represented in
3021  *        gdcm as \ref SQItem) add an extra complexity to the data
3022  *        structure. Hence, a gdcm user whishing to visit all the entries of
3023  *        a Dicom header will need to dig in the gdcm internals (which
3024  *        implies exposing all the internal data structures to the API).
3025  *        In order to avoid this burden to the user, \ref BuildFlatHashTable
3026  *        recursively builds a temporary hash table, which holds all the
3027  *        Dicom entries in a flat structure (a \ref TagDocEntryHT i.e. a
3028  *        std::map<>).
3029  * \warning Of course there is NO integrity constrain between the 
3030  *        returned \ref TagDocEntryHT and the \ref ElementSet used
3031  *        to build it. Hence if the underlying \ref ElementSet is
3032  *        altered, then it is the caller responsability to invoke 
3033  *        \ref BuildFlatHashTable again...
3034  * @return The flat std::map<> we juste build.
3035  */
3036 TagDocEntryHT* Document::BuildFlatHashTable()
3037 {
3038    TagDocEntryHT* FlatHT = new TagDocEntryHT;
3039    BuildFlatHashTableRecurse( *FlatHT, this );
3040    return FlatHT;
3041 }
3042
3043
3044
3045 /**
3046  * \brief   Compares two documents, according to \ref DicomDir rules
3047  * \warning Does NOT work with ACR-NEMA files
3048  * \todo    Find a trick to solve the pb (use RET fields ?)
3049  * @param   document
3050  * @return  true if 'smaller'
3051  */
3052 bool Document::operator<(Document &document)
3053 {
3054    // Patient Name
3055    std::string s1 = GetEntryByNumber(0x0010,0x0010);
3056    std::string s2 = document.GetEntryByNumber(0x0010,0x0010);
3057    if(s1 < s2)
3058    {
3059       return true;
3060    }
3061    else if( s1 > s2 )
3062    {
3063       return false;
3064    }
3065    else
3066    {
3067       // Patient ID
3068       s1 = GetEntryByNumber(0x0010,0x0020);
3069       s2 = document.GetEntryByNumber(0x0010,0x0020);
3070       if ( s1 < s2 )
3071       {
3072          return true;
3073       }
3074       else if ( s1 > s2 )
3075       {
3076          return false;
3077       }
3078       else
3079       {
3080          // Study Instance UID
3081          s1 = GetEntryByNumber(0x0020,0x000d);
3082          s2 = document.GetEntryByNumber(0x0020,0x000d);
3083          if ( s1 < s2 )
3084          {
3085             return true;
3086          }
3087          else if( s1 > s2 )
3088          {
3089             return false;
3090          }
3091          else
3092          {
3093             // Serie Instance UID
3094             s1 = GetEntryByNumber(0x0020,0x000e);
3095             s2 = document.GetEntryByNumber(0x0020,0x000e);    
3096             if ( s1 < s2 )
3097             {
3098                return true;
3099             }
3100             else if( s1 > s2 )
3101             {
3102                return false;
3103             }
3104          }
3105       }
3106    }
3107    return false;
3108 }
3109
3110 } // end namespace gdcm
3111
3112 //-----------------------------------------------------------------------------