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