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