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