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