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