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