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