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