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