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