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