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