]> Creatis software - gdcm.git/blob - src/gdcmDocument.cxx
* gdcmPython/CMakeLists.txt: SWIG_FLAGS doesn't declare includeall
[gdcm.git] / src / gdcmDocument.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDocument.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/08/02 14:06:57 $
7   Version:   $Revision: 1.64 $
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.htm 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
24 #include "gdcmGlobal.h"
25 #include "gdcmUtil.h"
26 #include "gdcmDebug.h"
27
28 #include <vector>
29
30 // For nthos:
31 #ifdef _MSC_VER
32    #include <winsock.h>
33 #else
34    #include <netinet/in.h>
35 #endif
36
37 #  include <iomanip>
38
39 // Implicit VR Little Endian
40 #define UI1_2_840_10008_1_2      "1.2.840.10008.1.2"
41 // Explicit VR Little Endian
42 #define UI1_2_840_10008_1_2_1    "1.2.840.10008.1.2.1"
43 // Deflated Explicit VR Little Endian
44 #define UI1_2_840_10008_1_2_1_99 "1.2.840.10008.1.2.1.99"
45 // Explicit VR Big Endian
46 #define UI1_2_840_10008_1_2_2    "1.2.840.10008.1.2.2"
47 // JPEG Baseline (Process 1)
48 #define UI1_2_840_10008_1_2_4_50 "1.2.840.10008.1.2.4.50"
49 // JPEG Extended (Process 2 & 4)
50 #define UI1_2_840_10008_1_2_4_51 "1.2.840.10008.1.2.4.51"
51 // JPEG Extended (Process 3 & 5)
52 #define UI1_2_840_10008_1_2_4_52 "1.2.840.10008.1.2.4.52"
53 // JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8)
54 #define UI1_2_840_10008_1_2_4_53 "1.2.840.10008.1.2.4.53"
55 // JPEG Full Progression, Non-Hierarchical (Process 10 & 12)
56 #define UI1_2_840_10008_1_2_4_55 "1.2.840.10008.1.2.4.55"
57 // JPEG Lossless, Non-Hierarchical (Process 14)
58 #define UI1_2_840_10008_1_2_4_57 "1.2.840.10008.1.2.4.57"
59 // JPEG Lossless, Hierarchical, First-Order Prediction (Process 14,
60 // [Selection Value 1])
61 #define UI1_2_840_10008_1_2_4_70 "1.2.840.10008.1.2.4.70"
62 // JPEG 2000 Lossless
63 #define UI1_2_840_10008_1_2_4_90 "1.2.840.10008.1.2.4.90"
64 // JPEG 2000
65 #define UI1_2_840_10008_1_2_4_91 "1.2.840.10008.1.2.4.91"
66 // RLE Lossless
67 #define UI1_2_840_10008_1_2_5    "1.2.840.10008.1.2.5"
68 // UI1_1_2_840_10008_1_2_5
69 #define str2num(str, typeNum) *((typeNum *)(str))
70
71 //-----------------------------------------------------------------------------
72 // Refer to gdcmDocument::CheckSwap()
73 const unsigned int gdcmDocument::HEADER_LENGTH_TO_READ = 256;
74
75 // Refer to gdcmDocument::SetMaxSizeLoadEntry()
76 const unsigned int gdcmDocument::MAX_SIZE_LOAD_ELEMENT_VALUE = 0xfff; // 4096
77 const unsigned int gdcmDocument::MAX_SIZE_PRINT_ELEMENT_VALUE = 0x7fffffff;
78
79 //-----------------------------------------------------------------------------
80 // Constructor / Destructor
81
82 /**
83  * \brief   constructor  
84  * @param   inFilename file to be opened for parsing
85  * @param   exception_on_error whether we throw an exception or not
86  */
87 gdcmDocument::gdcmDocument( std::string const & filename, 
88                             bool exception_on_error) 
89               : gdcmElementSet(-1)
90 {
91    SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE); 
92    Filename = filename;
93    Initialise();
94
95    if ( !OpenFile(exception_on_error))
96    {
97       return;
98    }
99    
100    dbg.Verbose(0, "gdcmDocument::gdcmDocument: starting parsing of file: ",
101                   Filename.c_str());
102    rewind(Fp);
103    
104    fseek(Fp,0L,SEEK_END);
105    long lgt = ftell(Fp);    
106            
107    rewind(Fp);
108    CheckSwap();
109    long beg = ftell(Fp);
110    lgt -= beg;
111    
112    SQDepthLevel = 0;
113    
114    long l = ParseDES( this, beg, lgt, false); // le Load sera fait a la volee
115    (void)l; //is l used anywhere ?
116
117    rewind(Fp);
118    
119    // Load 'non string' values
120       
121    std::string PhotometricInterpretation = GetEntryByNumber(0x0028,0x0004);   
122    if( PhotometricInterpretation == "PALETTE COLOR " )
123    {
124       LoadEntryVoidArea(0x0028,0x1200);  // gray LUT   
125       LoadEntryVoidArea(0x0028,0x1201);  // R    LUT
126       LoadEntryVoidArea(0x0028,0x1202);  // G    LUT
127       LoadEntryVoidArea(0x0028,0x1203);  // B    LUT
128       
129       LoadEntryVoidArea(0x0028,0x1221);  // Segmented Red   Palette Color LUT Data
130       LoadEntryVoidArea(0x0028,0x1222);  // Segmented Green Palette Color LUT Data
131       LoadEntryVoidArea(0x0028,0x1223);  // Segmented Blue  Palette Color LUT Data
132    } 
133    //FIXME later : how to use it?
134    LoadEntryVoidArea(0x0028,0x3006);  //LUT Data (CTX dependent) 
135
136    CloseFile(); 
137   
138    // --------------------------------------------------------------
139    // Special Patch to allow gdcm to read ACR-LibIDO formated images
140    //
141    // if recognition code tells us we deal with a LibIDO image
142    // we switch lineNumber and columnNumber
143    //
144    std::string RecCode;
145    RecCode = GetEntryByNumber(0x0008, 0x0010); // recognition code
146    if (RecCode == "ACRNEMA_LIBIDO_1.1" ||
147        RecCode == "CANRME_AILIBOD1_1." )  // for brain-damaged softwares
148                                           // with "little-endian strings"
149    {
150          Filetype = gdcmACR_LIBIDO; 
151          std::string rows    = GetEntryByNumber(0x0028, 0x0010);
152          std::string columns = GetEntryByNumber(0x0028, 0x0011);
153          SetEntryByNumber(columns, 0x0028, 0x0010);
154          SetEntryByNumber(rows   , 0x0028, 0x0011);
155    }
156    // ----------------- End of Special Patch ---------------- 
157
158    PrintLevel = 1;  // 'Medium' print level by default
159 }
160
161 /**
162  * \brief  constructor 
163  * @param   exception_on_error
164  */
165 gdcmDocument::gdcmDocument(bool exception_on_error) 
166              :gdcmElementSet(-1)
167 {
168    (void)exception_on_error;
169
170    SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
171    Initialise();
172
173    PrintLevel = 1;  // 'Medium' print level by default
174 }
175
176 /**
177  * \brief   Canonical destructor.
178  */
179 gdcmDocument::~gdcmDocument ()
180 {
181    RefPubDict = NULL;
182    RefShaDict = NULL;
183
184    // Recursive clean up of sequences
185    for (TagDocEntryHT::const_iterator it = TagHT.begin(); 
186                                       it != TagHT.end(); ++it )
187    { 
188       delete it->second;
189    }
190    TagHT.clear();
191 }
192
193 //-----------------------------------------------------------------------------
194 // Print
195
196 /**
197   * \brief   Prints The Dict Entries of THE public Dicom Dictionary
198   * @return
199   */  
200 void gdcmDocument::PrintPubDict(std::ostream & os)
201 {
202    RefPubDict->Print(os);
203 }
204
205 /**
206   * \brief   Prints The Dict Entries of THE shadow Dicom Dictionary
207   * @return
208   */
209 void gdcmDocument::PrintShaDict(std::ostream & os)
210 {
211    RefShaDict->Print(os);
212 }
213
214 //-----------------------------------------------------------------------------
215 // Public
216 /**
217  * \brief   Get the public dictionary used
218  */
219 gdcmDict *gdcmDocument::GetPubDict()
220 {
221    return RefPubDict;
222 }
223
224 /**
225  * \brief   Get the shadow dictionary used
226  */
227 gdcmDict *gdcmDocument::GetShaDict()
228 {
229    return RefShaDict;
230 }
231
232 /**
233  * \brief   Set the shadow dictionary used
234  * \param   dict dictionary to use in shadow
235  */
236 bool gdcmDocument::SetShaDict(gdcmDict *dict)
237 {
238    RefShaDict = dict;
239    return !RefShaDict;
240 }
241
242 /**
243  * \brief   Set the shadow dictionary used
244  * \param   dictName name of the dictionary to use in shadow
245  */
246 bool gdcmDocument::SetShaDict(DictKey const & dictName)
247 {
248    RefShaDict = gdcmGlobal::GetDicts()->GetDict(dictName);
249    return !RefShaDict;
250 }
251
252 /**
253  * \brief  This predicate, based on hopefully reasonable heuristics,
254  *         decides whether or not the current gdcmDocument was properly parsed
255  *         and contains the mandatory information for being considered as
256  *         a well formed and usable Dicom/Acr File.
257  * @return true when gdcmDocument is the one of a reasonable Dicom/Acr file,
258  *         false otherwise. 
259  */
260 bool gdcmDocument::IsReadable()
261 {
262    if( Filetype == gdcmUnknown)
263    {
264       std::cout << " gdcmDocument::IsReadable: Filetype " << Filetype
265                << " " << "gdcmUnknown " << gdcmUnknown << std::endl; //JPR
266       dbg.Verbose(0, "gdcmDocument::IsReadable: wrong filetype");
267       return false;
268    }
269
270    if( TagHT.empty() )
271    {
272       dbg.Verbose(0, "gdcmDocument::IsReadable: no tags in internal"
273                      " hash table.");
274       return false;
275    }
276
277    return true;
278 }
279
280
281 /**
282  * \brief   Internal function that checks whether the Transfer Syntax given
283  *          as argument is the one present in the current document.
284  * @param   SyntaxToCheck The transfert syntax we need to check against.
285  * @return  True when SyntaxToCheck corresponds to the Transfer Syntax of
286  *          the current document. False either when the document contains
287  *          no Transfer Syntax, or when the Tranfer Syntaxes doesn't match.
288  */
289 bool gdcmDocument::IsGivenTransferSyntax(std::string const & syntaxToCheck)
290 {
291    gdcmDocEntry *entry = GetDocEntryByNumber(0x0002, 0x0010);
292    if ( !entry )
293    {
294       return false;
295    }
296
297    // The entry might be present but not loaded (parsing and loading
298    // happen at different stages): try loading and proceed with check...
299    LoadDocEntrySafe(entry);
300    if (gdcmValEntry* valEntry = dynamic_cast< gdcmValEntry* >(entry) )
301    {
302       std::string transfer = valEntry->GetValue();
303       // The actual transfer (as read from disk) might be padded. We
304       // first need to remove the potential padding. We can make the
305       // weak assumption that padding was not executed with digits...
306       if  ( transfer.length() == 0 ) { // for brain damaged headers
307          return false;
308       }
309       while ( ! isdigit(transfer[transfer.length()-1]) )
310       {
311          transfer.erase(transfer.length()-1, 1);
312       }
313       if ( transfer == syntaxToCheck )
314       {
315          return true;
316       }
317    }
318    return false;
319 }
320
321 /**
322  * \brief   Determines if the Transfer Syntax of the present document
323  *          corresponds to a Implicit Value Representation of 
324  *          Little Endian.
325  * \sa      \ref gdcmDocument::IsGivenTransferSyntax.
326  * @return  True when ImplicitVRLittleEndian found. False in all other cases.
327  */
328 bool gdcmDocument::IsImplicitVRLittleEndianTransferSyntax()
329 {
330    return IsGivenTransferSyntax(UI1_2_840_10008_1_2);
331 }
332
333 /**
334  * \brief   Determines if the Transfer Syntax was already encountered
335  *          and if it corresponds to a ExplicitVRLittleEndian one.
336  * @return  True when ExplicitVRLittleEndian found. False in all other cases.
337  */
338 bool gdcmDocument::IsExplicitVRLittleEndianTransferSyntax()
339 {
340    return IsGivenTransferSyntax(UI1_2_840_10008_1_2_1);
341 }
342
343 /**
344  * \brief   Determines if the Transfer Syntax was already encountered
345  *          and if it corresponds to a DeflatedExplicitVRLittleEndian one.
346  * @return  True when DeflatedExplicitVRLittleEndian found. False in all other cases.
347  */
348 bool gdcmDocument::IsDeflatedExplicitVRLittleEndianTransferSyntax()
349 {
350    return IsGivenTransferSyntax(UI1_2_840_10008_1_2_1_99);
351 }
352
353 /**
354  * \brief   Determines if the Transfer Syntax was already encountered
355  *          and if it corresponds to a Explicit VR Big Endian one.
356  * @return  True when big endian found. False in all other cases.
357  */
358 bool gdcmDocument::IsExplicitVRBigEndianTransferSyntax()
359 {
360    return IsGivenTransferSyntax(UI1_2_840_10008_1_2_2);
361 }
362
363 /**
364  * \brief   Determines if the Transfer Syntax was already encountered
365  *          and if it corresponds to a JPEGBaseLineProcess1 one.
366  * @return  True when JPEGBaseLineProcess1found. False in all other cases.
367  */
368 bool gdcmDocument::IsJPEGBaseLineProcess1TransferSyntax()
369 {
370    return IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_50);
371 }
372                                                                                 
373 /**
374  * \brief   Determines if the Transfer Syntax was already encountered
375  *          and if it corresponds to a JPEGExtendedProcess2-4 one.
376  * @return  True when JPEGExtendedProcess2-4 found. False in all other cases.
377  */
378 bool gdcmDocument::IsJPEGExtendedProcess2_4TransferSyntax()
379 {
380    return IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_51);
381 }
382                                                                                 
383 /**
384  * \brief   Determines if the Transfer Syntax was already encountered
385  *          and if it corresponds to a JPEGExtendeProcess3-5 one.
386  * @return  True when JPEGExtendedProcess3-5 found. False in all other cases.
387  */
388 bool gdcmDocument::IsJPEGExtendedProcess3_5TransferSyntax()
389 {
390    return IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_52);
391 }
392
393 /**
394  * \brief   Determines if the Transfer Syntax was already encountered
395  *          and if it corresponds to a JPEGSpectralSelectionProcess6-8 one.
396  * @return  True when JPEGSpectralSelectionProcess6-8 found. False in all
397  *          other cases.
398  */
399 bool gdcmDocument::IsJPEGSpectralSelectionProcess6_8TransferSyntax()
400 {
401    return IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_53);
402 }
403
404 /**
405  * \brief   Determines if the Transfer Syntax was already encountered
406  *          and if it corresponds to a RLE Lossless one.
407  * @return  True when RLE Lossless found. False in all
408  *          other cases.
409  */
410 bool gdcmDocument::IsRLELossLessTransferSyntax()
411 {
412    return IsGivenTransferSyntax(UI1_2_840_10008_1_2_5);
413 }
414
415 /**
416  * \brief  Determines if Transfer Syntax was already encountered
417  *          and if it corresponds to a JPEG Lossless one.
418  * @return  True when RLE Lossless found. False in all
419  *          other cases.
420  */
421  
422 bool gdcmDocument::IsJPEGLossless()
423 {
424    return (   IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_55)
425            || IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_57)
426            || IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_70) );
427 }
428                                                                                 
429 /**
430  * \brief   Determines if the Transfer Syntax was already encountered
431  *          and if it corresponds to a JPEG2000 one
432  * @return  True when JPEG2000 (Lossly or LossLess) found. False in all
433  *          other cases.
434  */
435 bool gdcmDocument::IsJPEG2000()
436 {
437    return (   IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_90)
438            || IsGivenTransferSyntax(UI1_2_840_10008_1_2_4_91) );
439 }
440
441 /**
442  * \brief   Predicate for dicom version 3 file.
443  * @return  True when the file is a dicom version 3.
444  */
445 bool gdcmDocument::IsDicomV3()
446 {
447    // Checking if Transfert Syntax exists is enough
448    // Anyway, it's to late check if the 'Preamble' was found ...
449    // And ... would it be a rich idea to check ?
450    // (some 'no Preamble' DICOM images exist !)
451    return GetDocEntryByNumber(0x0002, 0x0010) != NULL;
452 }
453
454 /**
455  * \brief  returns the File Type 
456  *         (ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown)
457  * @return the FileType code
458  */
459 FileType gdcmDocument::GetFileType()
460 {
461    return Filetype;
462 }
463
464 /**
465  * \brief   opens the file
466  * @param   exception_on_error
467  * @return  
468  */
469 FILE *gdcmDocument::OpenFile(bool exception_on_error)
470   throw(gdcmFileError) 
471 {
472   Fp = fopen(Filename.c_str(),"rb");
473
474   if(!Fp)
475   {
476      if(exception_on_error)
477      {
478         throw gdcmFileError("gdcmDocument::gdcmDocument(const char *, bool)");
479      }
480      else
481      {
482         dbg.Verbose(0, "gdcmDocument::OpenFile cannot open file: ",
483                     Filename.c_str());
484         return NULL;
485      }
486   }
487
488   if ( Fp )
489   {
490      uint16_t zero;
491      fread(&zero,  (size_t)2, (size_t)1, Fp);
492
493     //ACR -- or DICOM with no Preamble --
494     if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200 )
495     {
496        return Fp;
497     }
498
499     //DICOM
500     fseek(Fp, 126L, SEEK_CUR);
501     char dicm[4];
502     fread(dicm,  (size_t)4, (size_t)1, Fp);
503     if( memcmp(dicm, "DICM", 4) == 0 )
504     {
505        return Fp;
506     }
507
508     fclose(Fp);
509     dbg.Verbose(0, "gdcmDocument::OpenFile not DICOM/ACR", Filename.c_str());
510   }
511   else
512   {
513     dbg.Verbose(0, "gdcmDocument::OpenFile cannot open file", Filename.c_str());
514   }
515
516   return 0;
517 }
518
519 /**
520  * \brief closes the file  
521  * @return  TRUE if the close was successfull 
522  */
523 bool gdcmDocument::CloseFile()
524 {
525   int closed = fclose(Fp);
526   Fp = 0;
527
528   return closed;
529 }
530
531 /**
532  * \brief Writes in a file all the Header Entries (Dicom Elements) 
533  * @param fp file pointer on an already open file
534  * @param filetype Type of the File to be written 
535  *          (ACR-NEMA, ExplicitVR, ImplicitVR)
536  * \return Always true.
537  */
538 void gdcmDocument::Write(FILE* fp,FileType filetype)
539 {
540    /// \todo move the following lines (and a lot of others, to be written)
541    /// to a future function CheckAndCorrectHeader
542    
543    /// WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA
544    /// no way (check : FileType est un champ de gdcmDocument ...)
545    /// a moins de se livrer a un tres complique ajout des champs manquants.
546    /// faire un CheckAndCorrectHeader (?) 
547  
548    if (filetype == gdcmImplicitVR) 
549    {
550       std::string implicitVRTransfertSyntax = UI1_2_840_10008_1_2;
551       ReplaceOrCreateByNumber(implicitVRTransfertSyntax,0x0002, 0x0010);
552       
553       /// \todo Refer to standards on page 21, chapter 6.2
554       ///       "Value representation": values with a VR of UI shall be
555       ///       padded with a single trailing null
556       ///       in the following case we have to padd manually with a 0
557       
558       SetEntryLengthByNumber(18, 0x0002, 0x0010);
559    } 
560
561    if (filetype == gdcmExplicitVR)
562    {
563       std::string explicitVRTransfertSyntax = UI1_2_840_10008_1_2_1;
564       ReplaceOrCreateByNumber(explicitVRTransfertSyntax,0x0002, 0x0010);
565       
566       /// \todo Refer to standards on page 21, chapter 6.2
567       ///       "Value representation": values with a VR of UI shall be
568       ///       padded with a single trailing null
569       ///       Dans le cas suivant on doit pader manuellement avec un 0
570       
571       SetEntryLengthByNumber(20, 0x0002, 0x0010);
572    }
573   
574 /**
575  * \todo rewrite later, if really usefull
576  *       - 'Group Length' element is optional in DICOM
577  *       - but un-updated odd groups lengthes can causes pb
578  *         (xmedcon breaker)
579  *
580  * if ( (filetype == ImplicitVR) || (filetype == ExplicitVR) )
581  *    UpdateGroupLength(false,filetype);
582  * if ( filetype == ACR)
583  *    UpdateGroupLength(true,ACR);
584  */
585  
586    gdcmElementSet::Write(fp, filetype); // This one is recursive
587
588 }
589
590 /**
591  * \brief   Modifies the value of a given Header Entry (Dicom Element)
592  *          when it exists. Create it with the given value when unexistant.
593  * @param   Value (string) Value to be set
594  * @param   Group   Group number of the Entry 
595  * @param   Elem  Element number of the Entry
596  * \return  pointer to the modified/created Header Entry (NULL when creation
597  *          failed).
598  */
599   
600 gdcmValEntry * gdcmDocument::ReplaceOrCreateByNumber(
601                                          std::string const & value, 
602                                          uint16_t group, 
603                                          uint16_t elem )
604 {
605    gdcmValEntry* valEntry = 0;
606
607    gdcmDocEntry* currentEntry = GetDocEntryByNumber( group, elem);
608    if (!currentEntry)
609    {
610       // The entry wasn't present and we simply create the required ValEntry:
611       currentEntry = NewDocEntryByNumber(group, elem);
612       if (!currentEntry)
613       {
614          dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: call to"
615                         " NewDocEntryByNumber failed.");
616          return NULL;
617       }
618       valEntry = new gdcmValEntry(currentEntry);
619       if ( !AddEntry(valEntry))
620       {
621          dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: AddEntry"
622                         " failed allthough this is a creation.");
623       }
624    }
625    else
626    {
627       valEntry = dynamic_cast< gdcmValEntry* >(currentEntry);
628       if ( !valEntry )
629       {
630          // We need to promote the gdcmDocEntry to a gdcmValEntry:
631          valEntry = new gdcmValEntry(currentEntry);
632          if (!RemoveEntry(currentEntry))
633          {
634             dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: removal"
635                            " of previous DocEntry failed.");
636             return NULL;
637          }
638          if ( !AddEntry(valEntry))
639          {
640             dbg.Verbose(0, "gdcmDocument::ReplaceOrCreateByNumber: adding"
641                            " promoted ValEntry failed.");
642             return NULL;
643          }
644       }
645    }
646
647    SetEntryByNumber(value, group, elem);
648
649    return valEntry;
650 }   
651
652 /*
653  * \brief   Modifies the value of a given Header Entry (Dicom Element)
654  *          when it exists. Create it with the given value when unexistant.
655  * @param   voidArea (binary) value to be set
656  * @param   Group   Group number of the Entry 
657  * @param   Elem  Element number of the Entry
658  * \return  pointer to the modified/created Header Entry (NULL when creation
659  *          failed).
660  */
661 gdcmBinEntry * gdcmDocument::ReplaceOrCreateByNumber(
662                                          void *voidArea,
663                                          int lgth, 
664                                          uint16_t group, 
665                                          uint16_t elem)
666 {
667    gdcmBinEntry* b = 0;
668    gdcmDocEntry* a = GetDocEntryByNumber( group, elem);
669    if (!a)
670    {
671       a = NewBinEntryByNumber(group, elem);
672       if (!a)
673       {
674          return 0;
675       }
676
677       b = new gdcmBinEntry(a);
678       AddEntry(b);
679       b->SetVoidArea(voidArea);
680    }   
681    SetEntryByNumber(voidArea, lgth, group, elem);
682    //b->SetVoidArea(voidArea);  //what if b == 0 !!
683
684    return b;
685 }  
686
687 /**
688  * \brief Set a new value if the invoked element exists
689  *        Seems to be useless !!!
690  * @param Value new element value
691  * @param Group  group number of the Entry 
692  * @param Elem element number of the Entry
693  * \return  boolean 
694  */
695 bool gdcmDocument::ReplaceIfExistByNumber(std::string const & value, 
696                                           uint16_t group, uint16_t elem ) 
697 {
698    SetEntryByNumber(value, group, elem);
699
700    return true;
701
702
703 //-----------------------------------------------------------------------------
704 // Protected
705
706 /**
707  * \brief   Checks if a given Dicom Element exists within the H table
708  * @param   group      Group number of the searched Dicom Element 
709  * @param   element  Element number of the searched Dicom Element 
710  * @return  number of occurences
711  */
712 int gdcmDocument::CheckIfEntryExistByNumber(uint16_t group, uint16_t element )
713 {
714    const std::string &key = gdcmDictEntry::TranslateToKey(group, element );
715    return TagHT.count(key);
716 }
717
718 /**
719  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
720  *          the public and private dictionaries 
721  *          for the element value of a given tag.
722  * \warning Don't use any longer : use GetPubEntryByName
723  * @param   tagName name of the searched element.
724  * @return  Corresponding element value when it exists,
725  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
726  */
727 std::string gdcmDocument::GetEntryByName(TagName const & tagName)
728 {
729    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
730    if( !dictEntry )
731    {
732       return GDCM_UNFOUND;
733    }
734
735    return GetEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement());
736 }
737
738 /**
739  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
740  *          the public and private dictionaries 
741  *          for the element value representation of a given tag.
742  *
743  *          Obtaining the VR (Value Representation) might be needed by caller
744  *          to convert the string typed content to caller's native type 
745  *          (think of C++ vs Python). The VR is actually of a higher level
746  *          of semantics than just the native C++ type.
747  * @param   tagName name of the searched element.
748  * @return  Corresponding element value representation when it exists,
749  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
750  */
751 std::string gdcmDocument::GetEntryVRByName(TagName const & tagName)
752 {
753    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
754    if( dictEntry == NULL)
755    {
756       return GDCM_UNFOUND;
757    }
758
759    gdcmDocEntry* elem = GetDocEntryByNumber(dictEntry->GetGroup(),
760                                             dictEntry->GetElement());
761    return elem->GetVR();
762 }
763
764
765 /**
766  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
767  *          the public and private dictionaries 
768  *          for the element value representation of a given tag.
769  * @param   group Group number of the searched tag.
770  * @param   element Element number of the searched tag.
771  * @return  Corresponding element value representation when it exists,
772  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
773  */
774 std::string gdcmDocument::GetEntryByNumber(uint16_t group, uint16_t element)
775 {
776    gdcmTagKey key = gdcmDictEntry::TranslateToKey(group, element);
777    /// \todo use map methods, instead of multimap JPR
778    if ( !TagHT.count(key))
779    {
780       return GDCM_UNFOUND;
781    }
782
783    return ((gdcmValEntry *)TagHT.find(key)->second)->GetValue();
784 }
785
786 /**
787  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
788  *          the public and private dictionaries 
789  *          for the element value representation of a given tag..
790  *
791  *          Obtaining the VR (Value Representation) might be needed by caller
792  *          to convert the string typed content to caller's native type 
793  *          (think of C++ vs Python). The VR is actually of a higher level
794  *          of semantics than just the native C++ type.
795  * @param   group     Group number of the searched tag.
796  * @param   element Element number of the searched tag.
797  * @return  Corresponding element value representation when it exists,
798  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
799  */
800 std::string gdcmDocument::GetEntryVRByNumber(uint16_t group, uint16_t element)
801 {
802    gdcmDocEntry* elem = GetDocEntryByNumber(group, element);
803    if ( !elem )
804    {
805       return GDCM_UNFOUND;
806    }
807    return elem->GetVR();
808 }
809
810 /**
811  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
812  *          the public and private dictionaries 
813  *          for the value length of a given tag..
814  * @param   group     Group number of the searched tag.
815  * @param   element Element number of the searched tag.
816  * @return  Corresponding element length; -2 if not found
817  */
818 int gdcmDocument::GetEntryLengthByNumber(uint16_t group, uint16_t element)
819 {
820    gdcmDocEntry* elem =  GetDocEntryByNumber(group, element);
821    if ( !elem )
822    {
823       return -2;  //magic number
824    }
825    return elem->GetLength();
826 }
827 /**
828  * \brief   Sets the value (string) of the Header Entry (Dicom Element)
829  * @param   content string value of the Dicom Element
830  * @param   tagName name of the searched Dicom Element.
831  * @return  true when found
832  */
833 bool gdcmDocument::SetEntryByName(std::string const & content,std::string const & tagName)
834 {
835    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
836    if( !dictEntry )
837    {
838       return false;
839    }
840
841    return SetEntryByNumber(content,dictEntry->GetGroup(),
842                                    dictEntry->GetElement());
843 }
844
845 /**
846  * \brief   Accesses an existing gdcmDocEntry (i.e. a Dicom Element)
847  *          through it's (group, element) and modifies it's content with
848  *          the given value.
849  * @param   content new value (string) to substitute with
850  * @param   group     group number of the Dicom Element to modify
851  * @param   element element number of the Dicom Element to modify
852  */
853 bool gdcmDocument::SetEntryByNumber(std::string const & content, 
854                                     uint16_t group,
855                                     uint16_t element) 
856 {
857    gdcmValEntry* valEntry = GetValEntryByNumber(group, element);
858    if (!valEntry )
859    {
860       dbg.Verbose(0, "gdcmDocument::SetEntryByNumber: no corresponding",
861                      " ValEntry (try promotion first).");
862       return false;
863    }
864    // Non even content must be padded with a space (020H)...
865    std::string evenContent = content;
866    if( evenContent.length() % 2 )
867    {
868       evenContent += '\0';  // ... therefore we padd with (000H) .!?!
869    }      
870    valEntry->SetValue(evenContent);
871    
872    // Integers have a special treatement for their length:
873    gdcmVRKey vr = valEntry->GetVR();
874    if( vr == "US" || vr == "SS" )
875    {
876       valEntry->SetLength(2);
877    }
878    else if( vr == "UL" || vr == "SL" )
879    {
880       valEntry->SetLength(4);
881    }
882    else
883    {
884       valEntry->SetLength(evenContent.length());
885    }
886
887    return true;
888
889
890 /**
891  * \brief   Accesses an existing gdcmDocEntry (i.e. a Dicom Element)
892  *          through it's (group, element) and modifies it's content with
893  *          the given value.
894  * @param   content new value (void *) to substitute with
895  * @param   lgth new value length
896  * @param   group     group number of the Dicom Element to modify
897  * @param   element element number of the Dicom Element to modify
898  */
899 bool gdcmDocument::SetEntryByNumber(void *content,
900                                     int lgth, 
901                                     uint16_t group,
902                                     uint16_t element) 
903 {
904    (void)lgth;  //not used
905    gdcmTagKey key = gdcmDictEntry::TranslateToKey(group, element);
906    if ( !TagHT.count(key))
907    {
908       return false;
909    }
910
911 /* Hope Binary field length is *never* wrong    
912    if(lgth%2) // Non even length are padded with a space (020H).
913    {  
914       lgth++;
915       //content = content + '\0'; // fing a trick to enlarge a binary field?
916    }
917 */      
918    gdcmBinEntry* a = (gdcmBinEntry *)TagHT[key];           
919    a->SetVoidArea(content);  
920    //a->SetLength(lgth);  // ???  
921
922    return true;
923
924
925 /**
926  * \brief   Accesses an existing gdcmDocEntry (i.e. a Dicom Element)
927  *          in the PubDocEntrySet of this instance
928  *          through it's (group, element) and modifies it's length with
929  *          the given value.
930  * \warning Use with extreme caution.
931  * @param l new length to substitute with
932  * @param group     group number of the Entry to modify
933  * @param element element number of the Entry to modify
934  * @return  true on success, false otherwise.
935  */
936 bool gdcmDocument::SetEntryLengthByNumber(uint32_t l, 
937                                           uint16_t group, 
938                                           uint16_t element) 
939 {
940    /// \todo use map methods, instead of multimap JPR
941    gdcmTagKey key = gdcmDictEntry::TranslateToKey(group, element);
942    if ( !TagHT.count(key) )
943    {
944       return false;
945    }
946    if ( l % 2 )
947    {
948       l++; // length must be even
949    }
950    ( ((TagHT.equal_range(key)).first)->second )->SetLength(l); 
951
952    return true ;
953 }
954
955 /**
956  * \brief   Gets (from Header) the offset  of a 'non string' element value 
957  *          (LoadElementValues has already be executed)
958  * @param Group   group number of the Entry 
959  * @param Elem  element number of the Entry
960  * @return File Offset of the Element Value 
961  */
962 size_t gdcmDocument::GetEntryOffsetByNumber(uint16_t group, uint16_t elem) 
963 {
964    gdcmDocEntry* entry = GetDocEntryByNumber(group, elem);
965    if (!entry) 
966    {
967       dbg.Verbose(1, "gdcmDocument::GetDocEntryByNumber: no entry present.");
968       return 0;
969    }
970    return entry->GetOffset();
971 }
972
973 /**
974  * \brief   Gets (from Header) a 'non string' element value 
975  *          (LoadElementValues has already be executed)  
976  * @param Group   group number of the Entry 
977  * @param Elem  element number of the Entry
978  * @return Pointer to the 'non string' area
979  */
980 void * gdcmDocument::GetEntryVoidAreaByNumber(uint16_t group, uint16_t elem) 
981 {
982    gdcmDocEntry* entry = GetDocEntryByNumber(group, elem);
983    if (!entry) 
984    {
985       dbg.Verbose(1, "gdcmDocument::GetDocEntryByNumber: no entry");
986       return 0;
987    }
988    return ((gdcmBinEntry *)entry)->GetVoidArea();
989 }
990
991 /**
992  * \brief         Loads (from disk) the element content 
993  *                when a string is not suitable
994  * @param Group   group number of the Entry 
995  * @param Elem  element number of the Entry
996  */
997 void *gdcmDocument::LoadEntryVoidArea(uint16_t group, uint16_t elem)
998 {
999    gdcmDocEntry *docElement = GetDocEntryByNumber(group, elem);
1000    if ( !docElement )
1001    {
1002       return NULL;
1003    }
1004    size_t o =(size_t)docElement->GetOffset();
1005    fseek(Fp, o, SEEK_SET);
1006    size_t l = docElement->GetLength();
1007    char* a = new char[l];
1008    if(!a)
1009    {
1010       dbg.Verbose(0, "gdcmDocument::LoadEntryVoidArea cannot allocate a");
1011       return NULL;
1012    }
1013    size_t l2 = fread(a, 1, l , Fp);
1014    if( l != l2 )
1015    {
1016       delete[] a;
1017       return NULL;
1018    }
1019    /// \todo Drop any already existing void area! JPR
1020    SetEntryVoidAreaByNumber(a, group, elem);
1021
1022    return a;
1023 }
1024 /**
1025  * \brief         Loads (from disk) the element content 
1026  *                when a string is not suitable
1027  * @param Element  Entry whose voidArea is going to be loaded
1028  */
1029 void *gdcmDocument::LoadEntryVoidArea(gdcmBinEntry *element) 
1030 {
1031    size_t o =(size_t)element->GetOffset();
1032    fseek(Fp, o, SEEK_SET);
1033    size_t l = element->GetLength();
1034    char* a = new char[l];
1035    if( !a )
1036    {
1037       dbg.Verbose(0, "gdcmDocument::LoadEntryVoidArea cannot allocate a");
1038       return NULL;
1039    }
1040    element->SetVoidArea((void *)a);
1041    /// \todo check the result 
1042    size_t l2 = fread(a, 1, l , Fp);
1043    if( l != l2 )
1044    {
1045       delete[] a;
1046       return NULL;
1047    }
1048
1049    return a;
1050 }
1051
1052 /**
1053  * \brief   Sets a 'non string' value to a given Dicom Element
1054  * @param   area area containing the 'non string' value
1055  * @param   group     Group number of the searched Dicom Element 
1056  * @param   element Element number of the searched Dicom Element 
1057  * @return  
1058  */
1059 bool gdcmDocument::SetEntryVoidAreaByNumber(void * area,
1060                                             uint16_t group, 
1061                                             uint16_t element) 
1062 {
1063    gdcmTagKey key = gdcmDictEntry::TranslateToKey(group, element);
1064    if ( !TagHT.count(key))
1065    {
1066       return false;
1067    }
1068
1069    // This was for multimap ?
1070    (( gdcmBinEntry *)( ((TagHT.equal_range(key)).first)->second ))->SetVoidArea(area);
1071       
1072    return true;
1073 }
1074
1075 /**
1076  * \brief   Update the entries with the shadow dictionary. 
1077  *          Only non even entries are analyzed       
1078  */
1079 void gdcmDocument::UpdateShaEntries()
1080 {
1081    //gdcmDictEntry *entry;
1082    std::string vr;
1083    
1084    /// \todo TODO : still any use to explore recursively the whole structure?
1085 /*
1086    for(ListTag::iterator it=listEntries.begin();
1087        it!=listEntries.end();
1088        ++it)
1089    {
1090       // Odd group => from public dictionary
1091       if((*it)->GetGroup()%2==0)
1092          continue;
1093
1094       // Peer group => search the corresponding dict entry
1095       if(RefShaDict)
1096          entry=RefShaDict->GetDictEntryByNumber((*it)->GetGroup(),(*it)->GetElement());
1097       else
1098          entry=NULL;
1099
1100       if((*it)->IsImplicitVR())
1101          vr="Implicit";
1102       else
1103          vr=(*it)->GetVR();
1104
1105       (*it)->SetValue(GetDocEntryUnvalue(*it));  // to go on compiling
1106       if(entry){
1107          // Set the new entry and the new value
1108          (*it)->SetDictEntry(entry);
1109          CheckDocEntryVR(*it,vr);
1110
1111          (*it)->SetValue(GetDocEntryValue(*it));    // to go on compiling
1112  
1113       }
1114       else
1115       {
1116          // Remove precedent value transformation
1117          (*it)->SetDictEntry(NewVirtualDictEntry((*it)->GetGroup(),(*it)->GetElement(),vr));
1118       }
1119    }
1120 */   
1121 }
1122
1123 /**
1124  * \brief   Searches within the Header Entries for a Dicom Element of
1125  *          a given tag.
1126  * @param   tagName name of the searched Dicom Element.
1127  * @return  Corresponding Dicom Element when it exists, and NULL
1128  *          otherwise.
1129  */
1130 gdcmDocEntry* gdcmDocument::GetDocEntryByName(std::string const & tagName)
1131 {
1132    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
1133    if( !dictEntry )
1134    {
1135       return NULL;
1136    }
1137
1138   return GetDocEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement());
1139 }
1140
1141 /**
1142  * \brief  retrieves a Dicom Element (the first one) using (group, element)
1143  * \warning (group, element) IS NOT an identifier inside the Dicom Header
1144  *           if you think it's NOT UNIQUE, check the count number
1145  *           and use iterators to retrieve ALL the Dicoms Elements within
1146  *           a given couple (group, element)
1147  * @param   group Group number of the searched Dicom Element 
1148  * @param   element Element number of the searched Dicom Element 
1149  * @return  
1150  */
1151 gdcmDocEntry* gdcmDocument::GetDocEntryByNumber(uint16_t group,
1152                                                 uint16_t element) 
1153 {
1154    gdcmTagKey key = gdcmDictEntry::TranslateToKey(group, element);
1155    if ( !TagHT.count(key))
1156    {
1157       return NULL;
1158    }
1159    return TagHT.find(key)->second;
1160 }
1161
1162 /**
1163  * \brief  Same as \ref gdcmDocument::GetDocEntryByNumber except it only
1164  *         returns a result when the corresponding entry is of type
1165  *         ValEntry.
1166  * @return When present, the corresponding ValEntry. 
1167  */
1168 gdcmValEntry* gdcmDocument::GetValEntryByNumber(uint16_t group,
1169                                                 uint16_t element)
1170 {
1171    gdcmDocEntry* currentEntry = GetDocEntryByNumber(group, element);
1172    if ( !currentEntry )
1173    {
1174       return 0;
1175    }
1176    if ( gdcmValEntry* valEntry = dynamic_cast<gdcmValEntry*>(currentEntry) )
1177    {
1178       return valEntry;
1179    }
1180    dbg.Verbose(0, "gdcmDocument::GetValEntryByNumber: unfound ValEntry.");
1181
1182    return 0;
1183 }
1184
1185 /**
1186  * \brief         Loads the element while preserving the current
1187  *                underlying file position indicator as opposed to
1188  *                to LoadDocEntry that modifies it.
1189  * @param entry   Header Entry whose value shall be loaded. 
1190  * @return  
1191  */
1192 void gdcmDocument::LoadDocEntrySafe(gdcmDocEntry * entry)
1193 {
1194    long PositionOnEntry = ftell(Fp);
1195    LoadDocEntry(entry);
1196    fseek(Fp, PositionOnEntry, SEEK_SET);
1197 }
1198
1199 /**
1200  * \brief   Swaps back the bytes of 4-byte long integer accordingly to
1201  *          processor order.
1202  * @return  The properly swaped 32 bits integer.
1203  */
1204 uint32_t gdcmDocument::SwapLong(uint32_t a)
1205 {
1206    switch (SwapCode)
1207    {
1208       case    0 :
1209          break;
1210       case 4321 :
1211          a=( ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000) | 
1212              ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
1213          break;
1214    
1215       case 3412 :
1216          a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
1217          break;
1218    
1219       case 2143 :
1220          a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
1221          break;
1222       default :
1223          std::cout << "swapCode= " << SwapCode << std::endl;
1224          dbg.Error(" gdcmDocument::SwapLong : unset swap code");
1225          a = 0;
1226    }
1227    return a;
1228
1229
1230 /**
1231  * \brief   Unswaps back the bytes of 4-byte long integer accordingly to
1232  *          processor order.
1233  * @return  The properly unswaped 32 bits integer.
1234  */
1235 uint32_t gdcmDocument::UnswapLong(uint32_t a)
1236 {
1237    return SwapLong(a);
1238 }
1239
1240 /**
1241  * \brief   Swaps the bytes so they agree with the processor order
1242  * @return  The properly swaped 16 bits integer.
1243  */
1244 uint16_t gdcmDocument::SwapShort(uint16_t a)
1245 {
1246    if ( SwapCode == 4321 || SwapCode == 2143 )
1247    {
1248       a = ((( a << 8 ) & 0x0ff00 ) | (( a >> 8 ) & 0x00ff ) );
1249    }
1250    return a;
1251 }
1252
1253 /**
1254  * \brief   Unswaps the bytes so they agree with the processor order
1255  * @return  The properly unswaped 16 bits integer.
1256  */
1257 uint16_t gdcmDocument::UnswapShort(uint16_t a)
1258 {
1259    return SwapShort(a);
1260 }
1261
1262 //-----------------------------------------------------------------------------
1263 // Private
1264
1265 /**
1266  * \brief   Parses a DocEntrySet (Zero-level DocEntries or SQ Item DocEntries)
1267  * @return  length of the parsed set. 
1268  */ 
1269
1270 long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
1271                             long offset,
1272                             long l_max,
1273                             bool delim_mode)
1274 {
1275    gdcmDocEntry *newDocEntry = 0;
1276    gdcmValEntry *newValEntry = 0;
1277    unsigned long l = 0;
1278    
1279    int depth = set->GetDepthLevel();
1280    while (true)
1281    { 
1282       if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
1283       {
1284          break;
1285       }
1286       newDocEntry = ReadNextDocEntry( );
1287       if ( !newDocEntry )
1288       {
1289          break;
1290       }
1291
1292       gdcmVRKey vr = newDocEntry->GetVR();
1293       if ( vr != "SQ" )
1294       {
1295                
1296          if ( gdcmGlobal::GetVR()->IsVROfGdcmStringRepresentable(vr) )
1297          {
1298             /////// ValEntry
1299             newValEntry = new gdcmValEntry(newDocEntry->GetDictEntry());
1300             newValEntry->Copy(newDocEntry);
1301             newValEntry->SetDepthLevel(depth);
1302             set->AddEntry(newValEntry);
1303             LoadDocEntry(newValEntry);
1304             if (newValEntry->IsItemDelimitor())
1305             {
1306                break;
1307             }
1308             if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
1309             {
1310                break;
1311             }
1312          }
1313          else
1314          {
1315             if ( ! gdcmGlobal::GetVR()->IsVROfGdcmBinaryRepresentable(vr) )
1316             { 
1317                 ////// Neither ValEntry NOR BinEntry: should mean UNKOWN VR
1318                 dbg.Verbose(0, "gdcmDocument::ParseDES: neither Valentry, "
1319                                "nor BinEntry. Probably unknown VR.");
1320             }
1321
1322             ////// BinEntry or UNKOWN VR:
1323             gdcmBinEntry *bn = new gdcmBinEntry(newDocEntry->GetDictEntry());
1324             bn->Copy(newDocEntry);
1325             set->AddEntry(bn);
1326             LoadDocEntry(bn);
1327          }
1328
1329          if (newDocEntry->GetGroup()   == 0x7fe0 && 
1330              newDocEntry->GetElement() == 0x0010 )
1331          {
1332              if (newDocEntry->GetReadLength()==0xffffffff)
1333              {
1334                 // Broken US.3405.1.dcm
1335                 Parse7FE0(); // to skip the pixels 
1336                              // (multipart JPEG/RLE are trouble makers)
1337              }
1338              else
1339              {
1340                 SkipToNextDocEntry(newDocEntry);
1341                 l = newDocEntry->GetFullLength(); 
1342              }
1343          }
1344          else
1345          {
1346              // to be sure we are at the beginning 
1347              SkipToNextDocEntry(newDocEntry);
1348              l = newDocEntry->GetFullLength(); 
1349          }
1350       }
1351       else
1352       {
1353          // VR = "SQ"
1354          l = newDocEntry->GetReadLength();            
1355          if ( l != 0 ) // don't mess the delim_mode for zero-length sequence
1356          {
1357             if ( l == 0xffffffff )
1358             {
1359               delim_mode = true;
1360             }
1361             else
1362             {
1363               delim_mode = false;
1364             }
1365          }
1366          // no other way to create it ...
1367          gdcmSeqEntry *sq = new gdcmSeqEntry(newDocEntry->GetDictEntry(),
1368                                              set->GetDepthLevel());
1369          sq->Copy(newDocEntry);
1370          sq->SetDelimitorMode(delim_mode);
1371          sq->SetDepthLevel(depth);
1372
1373          if ( l != 0 )
1374          {  // Don't try to parse zero-length sequences
1375             long lgt = ParseSQ( sq, 
1376                                 newDocEntry->GetOffset(),
1377                                 l, delim_mode);
1378             (void)lgt;  //not used...
1379          }
1380          set->AddEntry(sq);
1381          if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
1382          {
1383             break;
1384          }
1385       }
1386       delete newDocEntry;
1387    }
1388
1389    return l; // Probably useless 
1390 }
1391
1392 /**
1393  * \brief   Parses a Sequence ( SeqEntry after SeqEntry)
1394  * @return  parsed length for this level
1395  */ 
1396 long gdcmDocument::ParseSQ(gdcmSeqEntry *set,
1397                            long offset, long l_max, bool delim_mode)
1398 {
1399    int SQItemNumber = 0;
1400    bool dlm_mod;
1401    //int depth = set->GetDepthLevel();
1402    //(void)depth; //not used
1403
1404    while (true)
1405    {
1406       gdcmDocEntry *newDocEntry = ReadNextDocEntry();   
1407       if ( !newDocEntry )
1408       {
1409          // FIXME Should warn user
1410          break;
1411       }
1412       if( delim_mode )
1413       {
1414          if ( newDocEntry->IsSequenceDelimitor() )
1415          {
1416             set->SetSequenceDelimitationItem( newDocEntry );
1417             break;
1418          }
1419       }
1420       if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
1421       {
1422           break;
1423       }
1424
1425       gdcmSQItem *itemSQ = new gdcmSQItem(set->GetDepthLevel());
1426       itemSQ->AddEntry(newDocEntry);
1427       unsigned int l = newDocEntry->GetReadLength();
1428       
1429       if ( l == 0xffffffff )
1430       {
1431          dlm_mod = true;
1432       }
1433       else
1434       {
1435          dlm_mod = false;
1436       }
1437    
1438       int lgr = ParseDES(itemSQ, newDocEntry->GetOffset(), l, dlm_mod);
1439       (void)lgr;  //FIXME not used
1440       
1441       set->AddEntry(itemSQ, SQItemNumber); 
1442       SQItemNumber++;
1443       if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
1444       {
1445          break;
1446       }
1447    }
1448
1449    int lgth = ftell(Fp) - offset;
1450    return lgth;
1451 }
1452
1453 /**
1454  * \brief         Loads the element content if its length doesn't exceed
1455  *                the value specified with gdcmDocument::SetMaxSizeLoadEntry()
1456  * @param         Entry Header Entry (Dicom Element) to be dealt with
1457  */
1458 void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry)
1459 {
1460    size_t item_read;
1461    uint16_t group  = entry->GetGroup();
1462    std::string  vr = entry->GetVR();
1463    uint32_t length = entry->GetLength();
1464
1465    fseek(Fp, (long)entry->GetOffset(), SEEK_SET);
1466
1467    // A SeQuence "contains" a set of Elements.  
1468    //          (fffe e000) tells us an Element is beginning
1469    //          (fffe e00d) tells us an Element just ended
1470    //          (fffe e0dd) tells us the current SeQuence just ended
1471    if( group == 0xfffe )
1472    {
1473       // NO more value field for SQ !
1474       return;
1475    }
1476
1477    // When the length is zero things are easy:
1478    if ( length == 0 )
1479    {
1480       ((gdcmValEntry *)entry)->SetValue("");
1481       return;
1482    }
1483
1484    // The elements whose length is bigger than the specified upper bound
1485    // are not loaded. Instead we leave a short notice of the offset of
1486    // the element content and it's length.
1487
1488    std::ostringstream s;
1489    if (length > MaxSizeLoadEntry)
1490    {
1491       if (gdcmBinEntry* binEntryPtr = dynamic_cast< gdcmBinEntry* >(entry) )
1492       {         
1493          s << "gdcm::NotLoaded (BinEntry)";
1494          s << " Address:" << (long)entry->GetOffset();
1495          s << " Length:"  << entry->GetLength();
1496          s << " x(" << std::hex << entry->GetLength() << ")";
1497          binEntryPtr->SetValue(s.str());
1498       }
1499       // to be sure we are at the end of the value ...
1500       fseek(Fp, (long)entry->GetOffset()+(long)entry->GetLength(), SEEK_SET);      
1501       // Following return introduced by JPR on version 1.25. Since the 
1502       // treatement of a ValEntry is never executed (doh!) this means
1503       // we were lucky up to now because we NEVER encountered a ValEntry
1504       // whose length was bigger thant MaxSizeLoadEntry !? I can't believe
1505       // this could ever work...
1506       return;  //FIXME FIXME FIXME FIXME JPR ????
1507
1508        // Be carefull : a BinEntry IS_A ValEntry ... 
1509       if (gdcmValEntry* valEntryPtr = dynamic_cast< gdcmValEntry* >(entry) )
1510       {
1511          s << "gdcm::NotLoaded. (ValEntry)";
1512          s << " Address:" << (long)entry->GetOffset();
1513          s << " Length:"  << entry->GetLength();
1514          s << " x(" << std::hex << entry->GetLength() << ")";
1515          valEntryPtr->SetValue(s.str());
1516       }
1517       // to be sure we are at the end of the value ...
1518       fseek(Fp,(long)entry->GetOffset()+(long)entry->GetLength(),SEEK_SET);      
1519
1520       return;
1521    }
1522
1523    // When we find a BinEntry not very much can be done :
1524    if (gdcmBinEntry* binEntryPtr = dynamic_cast< gdcmBinEntry* >(entry) )
1525    {
1526
1527       LoadEntryVoidArea(binEntryPtr);
1528       s << "gdcm::Loaded (BinEntry)";
1529       binEntryPtr->SetValue(s.str());
1530       return;
1531    }
1532     
1533    /// \todo Any compacter code suggested (?)
1534    if ( IsDocEntryAnInteger(entry) )
1535    {   
1536       uint32_t NewInt;
1537       std::ostringstream s;
1538       int nbInt;
1539       // When short integer(s) are expected, read and convert the following 
1540       // n *two characters properly i.e. consider them as short integers as
1541       // opposed to strings.
1542       // Elements with Value Multiplicity > 1
1543       // contain a set of integers (not a single one)       
1544       if (vr == "US" || vr == "SS")
1545       {
1546          nbInt = length / 2;
1547          NewInt = ReadInt16();
1548          s << NewInt;
1549          if (nbInt > 1)
1550          {
1551             for (int i=1; i < nbInt; i++)
1552             {
1553                s << '\\';
1554                NewInt = ReadInt16();
1555                s << NewInt;
1556             }
1557          }
1558       }
1559       // See above comment on multiple integers (mutatis mutandis).
1560       else if (vr == "UL" || vr == "SL")
1561       {
1562          nbInt = length / 4;
1563          NewInt = ReadInt32();
1564          s << NewInt;
1565          if (nbInt > 1)
1566          {
1567             for (int i=1; i < nbInt; i++)
1568             {
1569                s << '\\';
1570                NewInt = ReadInt32();
1571                s << NewInt;
1572             }
1573          }
1574       }
1575 #ifdef GDCM_NO_ANSI_STRING_STREAM
1576       s << std::ends; // to avoid oddities on Solaris
1577 #endif //GDCM_NO_ANSI_STRING_STREAM
1578
1579       ((gdcmValEntry *)entry)->SetValue(s.str());
1580       return;
1581    }
1582    
1583    // We need an additional byte for storing \0 that is not on disk
1584    //std::string newValue(length,0);
1585    //item_read = fread(&(newValue[0]), (size_t)length, (size_t)1, Fp);  
1586    //rah !! I can't believe it could work, normally this is a const char* !!!
1587    char *str = new char[length+1];
1588    item_read = fread(str, (size_t)length, (size_t)1, Fp);
1589    str[length] = '\0';
1590    std::string newValue = str;
1591    delete[] str;
1592    if ( gdcmValEntry* valEntry = dynamic_cast<gdcmValEntry* >(entry) )
1593    {  
1594       if ( item_read != 1 )
1595       {
1596          dbg.Verbose(1, "gdcmDocument::LoadDocEntry",
1597                         "unread element value");
1598          valEntry->SetValue("gdcm::UnRead");
1599          return;
1600       }
1601
1602       if( vr == "UI" )
1603       {
1604          // Because of correspondance with the VR dic
1605          valEntry->SetValue(newValue);
1606       }
1607       else
1608       {
1609          valEntry->SetValue(newValue);
1610       }
1611    }
1612    else
1613    {
1614       dbg.Error(true, "gdcmDocument::LoadDocEntry"
1615                       "Should have a ValEntry, here !");
1616    }
1617 }
1618
1619
1620 /**
1621  * \brief  Find the value Length of the passed Header Entry
1622  * @param  Entry Header Entry whose length of the value shall be loaded. 
1623  */
1624 void gdcmDocument::FindDocEntryLength( gdcmDocEntry *entry )
1625    throw ( gdcmFormatError )
1626 {
1627    uint16_t element = entry->GetElement();
1628    std::string  vr  = entry->GetVR();
1629    uint16_t length16;
1630        
1631    
1632    if ( Filetype == gdcmExplicitVR && !entry->IsImplicitVR() ) 
1633    {
1634       if ( vr == "OB" || vr == "OW" || vr == "SQ" || vr == "UN" ) 
1635       {
1636          // The following reserved two bytes (see PS 3.5-2001, section
1637          // 7.1.2 Data element structure with explicit vr p27) must be
1638          // skipped before proceeding on reading the length on 4 bytes.
1639          fseek(Fp, 2L, SEEK_CUR);
1640          uint32_t length32 = ReadInt32();
1641
1642          if ( vr == "OB" && length32 == 0xffffffff ) 
1643          {
1644             uint32_t lengthOB;
1645             try 
1646             {
1647                lengthOB = FindDocEntryLengthOB();
1648             }
1649             catch ( gdcmFormatUnexpected )
1650             {
1651                // Computing the length failed (this happens with broken
1652                // files like gdcm-JPEG-LossLess3a.dcm). We still have a
1653                // chance to get the pixels by deciding the element goes
1654                // until the end of the file. Hence we artificially fix the
1655                // the length and proceed.
1656                long currentPosition = ftell(Fp);
1657                fseek(Fp,0L,SEEK_END);
1658                long lengthUntilEOF = ftell(Fp) - currentPosition;
1659                fseek(Fp, currentPosition, SEEK_SET);
1660                entry->SetLength(lengthUntilEOF);
1661                return;
1662             }
1663             entry->SetLength(lengthOB);
1664             return;
1665          }
1666          FixDocEntryFoundLength(entry, length32); 
1667          return;
1668       }
1669
1670       // Length is encoded on 2 bytes.
1671       length16 = ReadInt16();
1672       
1673       // We can tell the current file is encoded in big endian (like
1674       // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag
1675       // and it's value is the one of the encoding of a big endian file.
1676       // In order to deal with such big endian encoded files, we have
1677       // (at least) two strategies:
1678       // * when we load the "Transfer Syntax" tag with value of big endian
1679       //   encoding, we raise the proper flags. Then we wait for the end
1680       //   of the META group (0x0002) among which is "Transfer Syntax",
1681       //   before switching the swap code to big endian. We have to postpone
1682       //   the switching of the swap code since the META group is fully encoded
1683       //   in little endian, and big endian coding only starts at the next
1684       //   group. The corresponding code can be hard to analyse and adds
1685       //   many additional unnecessary tests for regular tags.
1686       // * the second strategy consists in waiting for trouble, that shall
1687       //   appear when we find the first group with big endian encoding. This
1688       //   is easy to detect since the length of a "Group Length" tag (the
1689       //   ones with zero as element number) has to be of 4 (0x0004). When we
1690       //   encounter 1024 (0x0400) chances are the encoding changed and we
1691       //   found a group with big endian encoding.
1692       // We shall use this second strategy. In order to make sure that we
1693       // can interpret the presence of an apparently big endian encoded
1694       // length of a "Group Length" without committing a big mistake, we
1695       // add an additional check: we look in the already parsed elements
1696       // for the presence of a "Transfer Syntax" whose value has to be "big
1697       // endian encoding". When this is the case, chances are we have got our
1698       // hands on a big endian encoded file: we switch the swap code to
1699       // big endian and proceed...
1700       if ( element  == 0x0000 && length16 == 0x0400 ) 
1701       {
1702          if ( !IsExplicitVRBigEndianTransferSyntax() ) 
1703          {
1704             throw gdcmFormatError( "gdcmDocument::FindDocEntryLength()",
1705                                    " not explicit VR." );
1706             return;
1707          }
1708          length16 = 4;
1709          SwitchSwapToBigEndian();
1710          // Restore the unproperly loaded values i.e. the group, the element
1711          // and the dictionary entry depending on them.
1712          uint16_t correctGroup = SwapShort( entry->GetGroup() );
1713          uint16_t correctElem  = SwapShort( entry->GetElement() );
1714          gdcmDictEntry* newTag = GetDictEntryByNumber( correctGroup,
1715                                                        correctElem );
1716          if ( !newTag )
1717          {
1718             // This correct tag is not in the dictionary. Create a new one.
1719             newTag = NewVirtualDictEntry(correctGroup, correctElem);
1720          }
1721          // FIXME this can create a memory leaks on the old entry that be
1722          // left unreferenced.
1723          entry->SetDictEntry( newTag );
1724       }
1725        
1726       // Heuristic: well, some files are really ill-formed.
1727       if ( length16 == 0xffff) 
1728       {
1729          // 0xffff means that we deal with 'Unknown Length' Sequence  
1730          length16 = 0;
1731       }
1732       FixDocEntryFoundLength( entry, (uint32_t)length16 );
1733       return;
1734    }
1735    else
1736    {
1737       // Either implicit VR or a non DICOM conformal (see note below) explicit
1738       // VR that ommited the VR of (at least) this element. Farts happen.
1739       // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25
1740       // on Data elements "Implicit and Explicit VR Data Elements shall
1741       // not coexist in a Data Set and Data Sets nested within it".]
1742       // Length is on 4 bytes.
1743       
1744       FixDocEntryFoundLength( entry, ReadInt32() );
1745       return;
1746    }
1747 }
1748
1749 /**
1750  * \brief     Find the Value Representation of the current Dicom Element.
1751  * @param     Entry
1752  */
1753 void gdcmDocument::FindDocEntryVR( gdcmDocEntry *entry )
1754 {
1755    if ( Filetype != gdcmExplicitVR )
1756    {
1757       return;
1758    }
1759
1760    char vr[3];
1761
1762    long positionOnEntry = ftell(Fp);
1763    // Warning: we believe this is explicit VR (Value Representation) because
1764    // we used a heuristic that found "UL" in the first tag. Alas this
1765    // doesn't guarantee that all the tags will be in explicit VR. In some
1766    // cases (see e-film filtered files) one finds implicit VR tags mixed
1767    // within an explicit VR file. Hence we make sure the present tag
1768    // is in explicit VR and try to fix things if it happens not to be
1769    // the case.
1770    
1771    fread (vr, (size_t)2,(size_t)1, Fp);
1772    vr[2] = 0;
1773
1774    if( !CheckDocEntryVR(entry, vr) )
1775    {
1776       fseek(Fp, positionOnEntry, SEEK_SET);
1777       // When this element is known in the dictionary we shall use, e.g. for
1778       // the semantics (see the usage of IsAnInteger), the VR proposed by the
1779       // dictionary entry. Still we have to flag the element as implicit since
1780       // we know now our assumption on expliciteness is not furfilled.
1781       // avoid  .
1782       if ( entry->IsVRUnknown() )
1783       {
1784          entry->SetVR("Implicit");
1785       }
1786       entry->SetImplicitVR();
1787    }
1788 }
1789
1790 /**
1791  * \brief     Check the correspondance between the VR of the header entry
1792  *            and the taken VR. If they are different, the header entry is 
1793  *            updated with the new VR.
1794  * @param     Entry Header Entry to check
1795  * @param     vr    Dicom Value Representation
1796  * @return    false if the VR is incorrect of if the VR isn't referenced
1797  *            otherwise, it returns true
1798 */
1799 bool gdcmDocument::CheckDocEntryVR(gdcmDocEntry *entry, gdcmVRKey vr)
1800 {
1801    char msg[100]; // for sprintf
1802    bool realExplicit = true;
1803
1804    // Assume we are reading a falsely explicit VR file i.e. we reached
1805    // a tag where we expect reading a VR but are in fact we read the
1806    // first to bytes of the length. Then we will interogate (through find)
1807    // the dicom_vr dictionary with oddities like "\004\0" which crashes
1808    // both GCC and VC++ implementations of the STL map. Hence when the
1809    // expected VR read happens to be non-ascii characters we consider
1810    // we hit falsely explicit VR tag.
1811
1812    if ( !isalpha(vr[0]) && !isalpha(vr[1]) )
1813    {
1814       realExplicit = false;
1815    }
1816
1817    // CLEANME searching the dicom_vr at each occurence is expensive.
1818    // PostPone this test in an optional integrity check at the end
1819    // of parsing or only in debug mode.
1820    if ( realExplicit && !gdcmGlobal::GetVR()->Count(vr) )
1821    {
1822       realExplicit = false;
1823    }
1824
1825    if ( !realExplicit ) 
1826    {
1827       // We thought this was explicit VR, but we end up with an
1828       // implicit VR tag. Let's backtrack.   
1829       sprintf(msg,"Falsely explicit vr file (%04x,%04x)\n", 
1830                    entry->GetGroup(), entry->GetElement());
1831       dbg.Verbose(1, "gdcmDocument::FindVR: ",msg);
1832
1833       if( entry->GetGroup() % 2 && entry->GetElement() == 0x0000)
1834       {
1835          // Group length is UL !
1836          gdcmDictEntry* newEntry = NewVirtualDictEntry(
1837                                    entry->GetGroup(), entry->GetElement(),
1838                                    "UL", "FIXME", "Group Length");
1839          entry->SetDictEntry( newEntry );
1840       }
1841       return false;
1842    }
1843
1844    if ( entry->IsVRUnknown() )
1845    {
1846       // When not a dictionary entry, we can safely overwrite the VR.
1847       if( entry->GetElement() == 0x0000 )
1848       {
1849          // Group length is UL !
1850          entry->SetVR("UL");
1851       }
1852       else
1853       {
1854          entry->SetVR(vr);
1855       }
1856    }
1857    else if ( entry->GetVR() != vr ) 
1858    {
1859       // The VR present in the file and the dictionary disagree. We assume
1860       // the file writer knew best and use the VR of the file. Since it would
1861       // be unwise to overwrite the VR of a dictionary (since it would
1862       // compromise it's next user), we need to clone the actual DictEntry
1863       // and change the VR for the read one.
1864       gdcmDictEntry* newEntry = NewVirtualDictEntry(
1865                                 entry->GetGroup(), entry->GetElement(),
1866                                 vr, "FIXME", entry->GetName());
1867       entry->SetDictEntry(newEntry);
1868    }
1869
1870    return true; 
1871 }
1872
1873 /**
1874  * \brief   Get the transformed value of the header entry. The VR value 
1875  *          is used to define the transformation to operate on the value
1876  * \warning NOT end user intended method !
1877  * @param   Entry 
1878  * @return  Transformed entry value
1879  */
1880 std::string gdcmDocument::GetDocEntryValue(gdcmDocEntry *entry)
1881 {
1882    if ( IsDocEntryAnInteger(entry) && entry->IsImplicitVR() )
1883    {
1884       std::string val = ((gdcmValEntry *)entry)->GetValue();
1885       std::string vr  = entry->GetVR();
1886       uint32_t length = entry->GetLength();
1887       std::ostringstream s;
1888       int nbInt;
1889
1890       // When short integer(s) are expected, read and convert the following 
1891       // n * 2 bytes properly i.e. as a multivaluated strings
1892       // (each single value is separated fromthe next one by '\'
1893       // as usual for standard multivaluated filels
1894       // Elements with Value Multiplicity > 1
1895       // contain a set of short integers (not a single one) 
1896    
1897       if( vr == "US" || vr == "SS" )
1898       {
1899          uint16_t newInt16;
1900
1901          nbInt = length / 2;
1902          for (int i=0; i < nbInt; i++) 
1903          {
1904             if( i != 0 )
1905             {
1906                s << '\\';
1907             }
1908             newInt16 = ( val[2*i+0] & 0xFF ) + ( ( val[2*i+1] & 0xFF ) << 8);
1909             newInt16 = SwapShort( newInt16 );
1910             s << newInt16;
1911          }
1912       }
1913
1914       // When integer(s) are expected, read and convert the following 
1915       // n * 4 bytes properly i.e. as a multivaluated strings
1916       // (each single value is separated fromthe next one by '\'
1917       // as usual for standard multivaluated filels
1918       // Elements with Value Multiplicity > 1
1919       // contain a set of integers (not a single one) 
1920       else if( vr == "UL" || vr == "SL" )
1921       {
1922          uint32_t newInt32;
1923
1924          nbInt = length / 4;
1925          for (int i=0; i < nbInt; i++) 
1926          {
1927             if( i != 0)
1928             {
1929                s << '\\';
1930             }
1931             newInt32 = ( val[4*i+0] & 0xFF )
1932                     + (( val[4*i+1] & 0xFF ) <<  8 )
1933                     + (( val[4*i+2] & 0xFF ) << 16 )
1934                     + (( val[4*i+3] & 0xFF ) << 24 );
1935             newInt32 = SwapLong( newInt32 );
1936             s << newInt32;
1937          }
1938       }
1939 #ifdef GDCM_NO_ANSI_STRING_STREAM
1940       s << std::ends; // to avoid oddities on Solaris
1941 #endif //GDCM_NO_ANSI_STRING_STREAM
1942       return s.str();
1943    }
1944
1945    return ((gdcmValEntry *)entry)->GetValue();
1946 }
1947
1948 /**
1949  * \brief   Get the reverse transformed value of the header entry. The VR 
1950  *          value is used to define the reverse transformation to operate on
1951  *          the value
1952  * \warning NOT end user intended method !
1953  * @param   Entry 
1954  * @return  Reverse transformed entry value
1955  */
1956 std::string gdcmDocument::GetDocEntryUnvalue(gdcmDocEntry* entry)
1957 {
1958    if ( IsDocEntryAnInteger(entry) && entry->IsImplicitVR() )
1959    {
1960       std::string vr = entry->GetVR();
1961       std::vector<std::string> tokens;
1962       std::ostringstream s;
1963
1964       if ( vr == "US" || vr == "SS" ) 
1965       {
1966          uint16_t newInt16;
1967
1968          tokens.erase( tokens.begin(), tokens.end()); // clean any previous value
1969          Tokenize (((gdcmValEntry *)entry)->GetValue(), tokens, "\\");
1970          for (unsigned int i=0; i<tokens.size(); i++) 
1971          {
1972             newInt16 = atoi(tokens[i].c_str());
1973             s << (  newInt16        & 0xFF ) 
1974               << (( newInt16 >> 8 ) & 0xFF );
1975          }
1976          tokens.clear();
1977       }
1978       if ( vr == "UL" || vr == "SL")
1979       {
1980          uint32_t newInt32;
1981
1982          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
1983          Tokenize (((gdcmValEntry *)entry)->GetValue(), tokens, "\\");
1984          for (unsigned int i=0; i<tokens.size();i++) 
1985          {
1986             newInt32 = atoi(tokens[i].c_str());
1987             s << (char)(  newInt32         & 0xFF ) 
1988               << (char)(( newInt32 >>  8 ) & 0xFF )
1989               << (char)(( newInt32 >> 16 ) & 0xFF )
1990               << (char)(( newInt32 >> 24 ) & 0xFF );
1991          }
1992          tokens.clear();
1993       }
1994
1995 #ifdef GDCM_NO_ANSI_STRING_STREAM
1996       s << std::ends; // to avoid oddities on Solaris
1997 #endif //GDCM_NO_ANSI_STRING_STREAM
1998       return s.str();
1999    }
2000
2001    return ((gdcmValEntry *)entry)->GetValue();
2002 }
2003
2004 /**
2005  * \brief   Skip a given Header Entry 
2006  * \warning NOT end user intended method !
2007  * @param   entry 
2008  */
2009 void gdcmDocument::SkipDocEntry(gdcmDocEntry *entry) 
2010 {
2011    SkipBytes(entry->GetLength());
2012 }
2013
2014 /**
2015  * \brief   Skips to the begining of the next Header Entry 
2016  * \warning NOT end user intended method !
2017  * @param   entry 
2018  */
2019 void gdcmDocument::SkipToNextDocEntry(gdcmDocEntry *entry) 
2020 {
2021    fseek(Fp, (long)(entry->GetOffset()),     SEEK_SET);
2022    fseek(Fp, (long)(entry->GetReadLength()), SEEK_CUR);
2023 }
2024
2025 /**
2026  * \brief   When the length of an element value is obviously wrong (because
2027  *          the parser went Jabberwocky) one can hope improving things by
2028  *          applying some heuristics.
2029  */
2030 void gdcmDocument::FixDocEntryFoundLength(gdcmDocEntry *entry,
2031                                           uint32_t foundLength)
2032 {
2033    entry->SetReadLength( foundLength ); // will be updated only if a bug is found        
2034    if ( foundLength == 0xffffffff)
2035    {
2036       foundLength = 0;
2037    }
2038    
2039    uint16_t gr = entry->GetGroup();
2040    uint16_t el = entry->GetElement(); 
2041      
2042    if ( foundLength % 2)
2043    {
2044       std::ostringstream s;
2045       s << "Warning : Tag with uneven length "
2046         << foundLength 
2047         <<  " in x(" << std::hex << gr << "," << el <<")" << std::dec;
2048       dbg.Verbose(0, s.str().c_str());
2049    }
2050       
2051    //////// Fix for some naughty General Electric images.
2052    // Allthough not recent many such GE corrupted images are still present
2053    // on Creatis hard disks. Hence this fix shall remain when such images
2054    // are no longer in user (we are talking a few years, here)...
2055    // Note: XMedCom probably uses such a trick since it is able to read
2056    //       those pesky GE images ...
2057    if ( foundLength == 13)
2058    {
2059       // Only happens for this length !
2060       if ( entry->GetGroup()   != 0x0008
2061       || ( entry->GetElement() != 0x0070
2062         && entry->GetElement() != 0x0080 ) )
2063       {
2064          foundLength = 10;
2065          entry->SetReadLength(10); /// \todo a bug is to be fixed !?
2066       }
2067    }
2068
2069    //////// Fix for some brain-dead 'Leonardo' Siemens images.
2070    // Occurence of such images is quite low (unless one leaves close to a
2071    // 'Leonardo' source. Hence, one might consider commenting out the
2072    // following fix on efficiency reasons.
2073    else if ( entry->GetGroup()   == 0x0009 
2074         && ( entry->GetElement() == 0x1113
2075           || entry->GetElement() == 0x1114 ) )
2076    {
2077       foundLength = 4;
2078       entry->SetReadLength(4); /// \todo a bug is to be fixed !?
2079    } 
2080  
2081    else if ( entry->GetVR() == "SQ" )
2082    {
2083       foundLength = 0;      // ReadLength is unchanged 
2084    } 
2085     
2086    //////// We encountered a 'delimiter' element i.e. a tag of the form 
2087    // "fffe|xxxx" which is just a marker. Delimiters length should not be
2088    // taken into account.
2089    else if( entry->GetGroup() == 0xfffe )
2090    {    
2091      // According to the norm, fffe|0000 shouldn't exist. BUT the Philips
2092      // image gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm happens to
2093      // causes extra troubles...
2094      if( entry->GetElement() != 0x0000 )
2095      {
2096         foundLength = 0;
2097      }
2098    } 
2099            
2100    entry->SetUsableLength(foundLength);
2101 }
2102
2103 /**
2104  * \brief   Apply some heuristics to predict whether the considered 
2105  *          element value contains/represents an integer or not.
2106  * @param   Entry The element value on which to apply the predicate.
2107  * @return  The result of the heuristical predicate.
2108  */
2109 bool gdcmDocument::IsDocEntryAnInteger(gdcmDocEntry *entry)
2110 {
2111    uint16_t element = entry->GetElement();
2112    uint16_t group   = entry->GetGroup();
2113    std::string  vr  = entry->GetVR();
2114    uint32_t length  = entry->GetLength();
2115
2116    // When we have some semantics on the element we just read, and if we
2117    // a priori know we are dealing with an integer, then we shall be
2118    // able to swap it's element value properly.
2119    if ( element == 0 )  // This is the group length of the group
2120    {  
2121       if ( length == 4 )
2122       {
2123          return true;
2124       }
2125       else 
2126       {
2127          // Allthough this should never happen, still some images have a
2128          // corrupted group length [e.g. have a glance at offset x(8336) of
2129          // gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm].
2130          // Since for dicom compliant and well behaved headers, the present
2131          // test is useless (and might even look a bit paranoid), when we
2132          // encounter such an ill-formed image, we simply display a warning
2133          // message and proceed on parsing (while crossing fingers).
2134          std::ostringstream s;
2135          int filePosition = ftell(Fp);
2136          s << "Erroneous Group Length element length  on : (" \
2137            << std::hex << group << " , " << element 
2138            << ") -before- position x(" << filePosition << ")"
2139            << "lgt : " << length;
2140          dbg.Verbose(0, "gdcmDocument::IsDocEntryAnInteger", s.str().c_str() );
2141       }
2142    }
2143
2144    if ( vr == "UL" || vr == "US" || vr == "SL" || vr == "SS" )
2145    {
2146       return true;
2147    }
2148    
2149    return false;
2150 }
2151
2152 /**
2153  * \brief  Find the Length till the next sequence delimiter
2154  * \warning NOT end user intended method !
2155  * @return 
2156  */
2157
2158 uint32_t gdcmDocument::FindDocEntryLengthOB()
2159    throw( gdcmFormatUnexpected )
2160 {
2161    // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
2162    long positionOnEntry = ftell(Fp);
2163    bool foundSequenceDelimiter = false;
2164    uint32_t totalLength = 0;
2165
2166    while ( !foundSequenceDelimiter )
2167    {
2168       uint16_t group;
2169       uint16_t elem;
2170       try
2171       {
2172          group = ReadInt16();
2173          elem  = ReadInt16();   
2174       }
2175       catch ( gdcmFormatError )
2176       {
2177          throw gdcmFormatError("gdcmDocument::FindDocEntryLengthOB()",
2178                                " group or element not present.");
2179       }
2180
2181       // We have to decount the group and element we just read
2182       totalLength += 4;
2183      
2184       if ( group != 0xfffe || ( ( elem != 0xe0dd ) && ( elem != 0xe000 ) ) )
2185       {
2186          dbg.Verbose(1, "gdcmDocument::FindDocEntryLengthOB: neither an Item "
2187                         "tag nor a Sequence delimiter tag."); 
2188          fseek(Fp, positionOnEntry, SEEK_SET);
2189          throw gdcmFormatUnexpected("gdcmDocument::FindDocEntryLengthOB()",
2190                                     "Neither an Item tag nor a Sequence "
2191                                     "delimiter tag.");
2192       }
2193
2194       if ( elem == 0xe0dd )
2195       {
2196          foundSequenceDelimiter = true;
2197       }
2198
2199       uint32_t itemLength = ReadInt32();
2200       // We add 4 bytes since we just read the ItemLength with ReadInt32
2201       totalLength += itemLength + 4;
2202       SkipBytes(itemLength);
2203       
2204       if ( foundSequenceDelimiter )
2205       {
2206          break;
2207       }
2208    }
2209    fseek(Fp, positionOnEntry, SEEK_SET);
2210    return totalLength;
2211 }
2212
2213 /**
2214  * \brief Reads a supposed to be 16 Bits integer
2215  *       (swaps it depending on processor endianity) 
2216  * @return read value
2217  */
2218 uint16_t gdcmDocument::ReadInt16()
2219    throw( gdcmFormatError )
2220 {
2221    uint16_t g;
2222    size_t item_read = fread (&g, (size_t)2,(size_t)1, Fp);
2223    if ( item_read != 1 )
2224    {
2225       if( ferror(Fp) )
2226       {
2227          throw gdcmFormatError( "gdcmDocument::ReadInt16()", " file error." );
2228       }
2229       throw gdcmFormatError( "gdcmDocument::ReadInt16()", "EOF." );
2230    }
2231    g = SwapShort(g); 
2232    return g;
2233 }
2234
2235 /**
2236  * \brief  Reads a supposed to be 32 Bits integer
2237  *         (swaps it depending on processor endianity)  
2238  * @return read value
2239  */
2240 uint32_t gdcmDocument::ReadInt32()
2241    throw( gdcmFormatError )
2242 {
2243    uint32_t g;
2244    size_t item_read = fread (&g, (size_t)4,(size_t)1, Fp);
2245    if ( item_read != 1 )
2246    {
2247       if( ferror(Fp) )
2248       {
2249          throw gdcmFormatError( "gdcmDocument::ReadInt16()", " file error." );
2250       }
2251       throw gdcmFormatError( "gdcmDocument::ReadInt32()", "EOF." );
2252    }
2253    g = SwapLong(g);
2254    return g;
2255 }
2256
2257 /**
2258  * \brief skips bytes inside the source file 
2259  * \warning NOT end user intended method !
2260  * @return 
2261  */
2262 void gdcmDocument::SkipBytes(uint32_t nBytes)
2263 {
2264    //FIXME don't dump the returned value
2265    (void)fseek(Fp, (long)nBytes, SEEK_CUR);
2266 }
2267
2268 /**
2269  * \brief Loads all the needed Dictionaries
2270  * \warning NOT end user intended method !   
2271  */
2272 void gdcmDocument::Initialise() 
2273 {
2274    RefPubDict = gdcmGlobal::GetDicts()->GetDefaultPubDict();
2275    RefShaDict = NULL;
2276 }
2277
2278 /**
2279  * \brief   Discover what the swap code is (among little endian, big endian,
2280  *          bad little endian, bad big endian).
2281  *          sw is set
2282  * @return false when we are absolutely sure 
2283  *               it's neither ACR-NEMA nor DICOM
2284  *         true  when we hope ours assuptions are OK
2285  */
2286 bool gdcmDocument::CheckSwap()
2287 {
2288    // The only guaranted way of finding the swap code is to find a
2289    // group tag since we know it's length has to be of four bytes i.e.
2290    // 0x00000004. Finding the swap code in then straigthforward. Trouble
2291    // occurs when we can't find such group...
2292    
2293    uint32_t  x = 4;  // x : for ntohs
2294    bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
2295    uint32_t  s32;
2296    uint16_t  s16;
2297        
2298    char deb[HEADER_LENGTH_TO_READ];
2299     
2300    // First, compare HostByteOrder and NetworkByteOrder in order to
2301    // determine if we shall need to swap bytes (i.e. the Endian type).
2302    if ( x == ntohs(x) )
2303    {
2304       net2host = true;
2305    }
2306    else
2307    {
2308       net2host = false;
2309    }
2310          
2311    // The easiest case is the one of a DICOM header, since it possesses a
2312    // file preamble where it suffice to look for the string "DICM".
2313    int lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, Fp);
2314    (void)lgrLue;  //FIXME not used
2315    
2316    char *entCur = deb + 128;
2317    if( memcmp(entCur, "DICM", (size_t)4) == 0 )
2318    {
2319       dbg.Verbose(1, "gdcmDocument::CheckSwap:", "looks like DICOM Version3");
2320       
2321       // Next, determine the value representation (VR). Let's skip to the
2322       // first element (0002, 0000) and check there if we find "UL" 
2323       // - or "OB" if the 1st one is (0002,0001) -,
2324       // in which case we (almost) know it is explicit VR.
2325       // WARNING: if it happens to be implicit VR then what we will read
2326       // is the length of the group. If this ascii representation of this
2327       // length happens to be "UL" then we shall believe it is explicit VR.
2328       // FIXME: in order to fix the above warning, we could read the next
2329       // element value (or a couple of elements values) in order to make
2330       // sure we are not commiting a big mistake.
2331       // We need to skip :
2332       // * the 128 bytes of File Preamble (often padded with zeroes),
2333       // * the 4 bytes of "DICM" string,
2334       // * the 4 bytes of the first tag (0002, 0000),or (0002, 0001)
2335       // i.e. a total of  136 bytes.
2336       entCur = deb + 136;
2337      
2338       // FIXME : FIXME:
2339       // Sometimes (see : gdcmData/icone.dcm) group 0x0002 *is* Explicit VR,
2340       // but elem 0002,0010 (Transfert Syntax) tells us the file is
2341       // *Implicit* VR.  -and it is !- 
2342       
2343       if( memcmp(entCur, "UL", (size_t)2) == 0 ||
2344           memcmp(entCur, "OB", (size_t)2) == 0 ||
2345           memcmp(entCur, "UI", (size_t)2) == 0 ||
2346           memcmp(entCur, "CS", (size_t)2) == 0 )  // CS, to remove later
2347                                                     // when Write DCM *adds*
2348       // FIXME
2349       // Use gdcmDocument::dicom_vr to test all the possibilities
2350       // instead of just checking for UL, OB and UI !? group 0000 
2351       {
2352          Filetype = gdcmExplicitVR;
2353          dbg.Verbose(1, "gdcmDocument::CheckSwap:",
2354                      "explicit Value Representation");
2355       } 
2356       else 
2357       {
2358          Filetype = gdcmImplicitVR;
2359          dbg.Verbose(1, "gdcmDocument::CheckSwap:",
2360                      "not an explicit Value Representation");
2361       }
2362       
2363       if ( net2host )
2364       {
2365          SwapCode = 4321;
2366          dbg.Verbose(1, "gdcmDocument::CheckSwap:",
2367                         "HostByteOrder != NetworkByteOrder");
2368       }
2369       else 
2370       {
2371          SwapCode = 0;
2372          dbg.Verbose(1, "gdcmDocument::CheckSwap:",
2373                         "HostByteOrder = NetworkByteOrder");
2374       }
2375       
2376       // Position the file position indicator at first tag (i.e.
2377       // after the file preamble and the "DICM" string).
2378       rewind(Fp);
2379       fseek (Fp, 132L, SEEK_SET);
2380       return true;
2381    } // End of DicomV3
2382
2383    // Alas, this is not a DicomV3 file and whatever happens there is no file
2384    // preamble. We can reset the file position indicator to where the data
2385    // is (i.e. the beginning of the file).
2386    dbg.Verbose(1, "gdcmDocument::CheckSwap:", "not a DICOM Version3 file");
2387    rewind(Fp);
2388
2389    // Our next best chance would be to be considering a 'clean' ACR/NEMA file.
2390    // By clean we mean that the length of the first tag is written down.
2391    // If this is the case and since the length of the first group HAS to be
2392    // four (bytes), then determining the proper swap code is straightforward.
2393
2394    entCur = deb + 4;
2395    // We assume the array of char we are considering contains the binary
2396    // representation of a 32 bits integer. Hence the following dirty
2397    // trick :
2398    s32 = *((uint32_t *)(entCur));
2399       
2400    switch( s32 )
2401    {
2402       case 0x00040000 :
2403          SwapCode = 3412;
2404          Filetype = gdcmACR;
2405          return true;
2406       case 0x04000000 :
2407          SwapCode = 4321;
2408          Filetype = gdcmACR;
2409          return true;
2410       case 0x00000400 :
2411          SwapCode = 2143;
2412          Filetype = gdcmACR;
2413          return true;
2414       case 0x00000004 :
2415          SwapCode = 0;
2416          Filetype = gdcmACR;
2417          return true;
2418       default :
2419          // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file.
2420          // It is time for despaired wild guesses. 
2421          // So, let's check if this file wouldn't happen to be 'dirty' ACR/NEMA,
2422          //  i.e. the 'group length' element is not present :     
2423          
2424          //  check the supposed to be 'group number'
2425          //  0x0002 or 0x0004 or 0x0008
2426          //  to determine ' SwapCode' value .
2427          //  Only 0 or 4321 will be possible 
2428          //  (no oportunity to check for the formerly well known
2429          //  ACR-NEMA 'Bad Big Endian' or 'Bad Little Endian' 
2430          //  if unsuccessfull (i.e. neither 0x0002 nor 0x0200 etc -4, 8-) 
2431          //  the file IS NOT ACR-NEMA nor DICOM V3
2432          //  Find a trick to tell it the caller...
2433       
2434          s16 = *((uint16_t *)(deb));
2435       
2436          switch ( s16 )
2437          {
2438             case 0x0002 :
2439             case 0x0004 :
2440             case 0x0008 :      
2441                SwapCode = 0;
2442                Filetype = gdcmACR;
2443                return true;
2444             case 0x0200 :
2445             case 0x0400 :
2446             case 0x0800 : 
2447                SwapCode = 4321;
2448                Filetype = gdcmACR;
2449                return true;
2450             default :
2451                dbg.Verbose(0, "gdcmDocument::CheckSwap:",
2452                      "ACR/NEMA unfound swap info (Really hopeless !)"); 
2453                Filetype = gdcmUnknown;     
2454                return false;
2455          }
2456          // Then the only info we have is the net2host one.
2457          //if (! net2host )
2458          //   SwapCode = 0;
2459          //else
2460          //  SwapCode = 4321;
2461          //return;
2462    }
2463 }
2464
2465 /**
2466  * \brief Restore the unproperly loaded values i.e. the group, the element
2467  *        and the dictionary entry depending on them. 
2468  */
2469 void gdcmDocument::SwitchSwapToBigEndian() 
2470 {
2471    dbg.Verbose(1, "gdcmDocument::SwitchSwapToBigEndian",
2472                   "Switching to BigEndian mode.");
2473    if ( SwapCode == 0    ) 
2474    {
2475       SwapCode = 4321;
2476    }
2477    else if ( SwapCode == 4321 ) 
2478    {
2479       SwapCode = 0;
2480    }
2481    else if ( SwapCode == 3412 ) 
2482    {
2483       SwapCode = 2143;
2484    }
2485    else if ( SwapCode == 2143 )
2486    {
2487       SwapCode = 3412;
2488    }
2489 }
2490
2491 /**
2492  * \brief  during parsing, Header Elements too long are not loaded in memory 
2493  * @param NewSize
2494  */
2495 void gdcmDocument::SetMaxSizeLoadEntry(long newSize) 
2496 {
2497    if ( newSize < 0 )
2498    {
2499       return;
2500    }
2501    if ((uint32_t)newSize >= (uint32_t)0xffffffff )
2502    {
2503       MaxSizeLoadEntry = 0xffffffff;
2504       return;
2505    }
2506    MaxSizeLoadEntry = newSize;
2507 }
2508
2509
2510 /**
2511  * \brief Header Elements too long will not be printed
2512  * \todo  See comments of \ref gdcmDocument::MAX_SIZE_PRINT_ELEMENT_VALUE 
2513  * @param NewSize
2514  */
2515 void gdcmDocument::SetMaxSizePrintEntry(long newSize) 
2516 {
2517    //DOH !! This is exactly SetMaxSizeLoadEntry FIXME FIXME
2518    if ( newSize < 0 )
2519    {
2520       return;
2521    }
2522    if ((uint32_t)newSize >= (uint32_t)0xffffffff )
2523    {
2524       MaxSizePrintEntry = 0xffffffff;
2525       return;
2526    }
2527    MaxSizePrintEntry = newSize;
2528 }
2529
2530
2531
2532 /**
2533  * \brief   Read the next tag but WITHOUT loading it's value
2534  *          (read the 'Group Number', the 'Element Number',
2535  *           gets the Dict Entry
2536  *          gets the VR, gets the length, gets the offset value)
2537  * @return  On succes the newly created DocEntry, NULL on failure.      
2538  */
2539 gdcmDocEntry* gdcmDocument::ReadNextDocEntry()
2540 {
2541    uint16_t group;
2542    uint16_t elem;
2543
2544    try
2545    {
2546       group = ReadInt16();
2547       elem  = ReadInt16();
2548    }
2549    catch ( gdcmFormatError e )
2550    {
2551       // We reached the EOF (or an error occured) therefore 
2552       // header parsing has to be considered as finished.
2553       std::cout << e;
2554       return 0;
2555    }
2556
2557    gdcmDocEntry *newEntry = NewDocEntryByNumber(group, elem);
2558    FindDocEntryVR(newEntry);
2559
2560    try
2561    {
2562       FindDocEntryLength(newEntry);
2563    }
2564    catch ( gdcmFormatError e )
2565    {
2566       // Call it quits
2567       std::cout << e;
2568       delete newEntry;
2569       return 0;
2570    }
2571
2572    newEntry->SetOffset(ftell(Fp));  
2573
2574    return newEntry;
2575 }
2576
2577
2578 /**
2579  * \brief   Generate a free gdcmTagKey i.e. a gdcmTagKey that is not present
2580  *          in the TagHt dictionary.
2581  * @param   group The generated tag must belong to this group.  
2582  * @return  The element of tag with given group which is fee.
2583  */
2584 uint32_t gdcmDocument::GenerateFreeTagKeyInGroup(uint16_t group) 
2585 {
2586    for (uint32_t elem = 0; elem < UINT32_MAX; elem++) 
2587    {
2588       gdcmTagKey key = gdcmDictEntry::TranslateToKey(group, elem);
2589       if (TagHT.count(key) == 0)
2590       {
2591          return elem;
2592       }
2593    }
2594    return UINT32_MAX;
2595 }
2596
2597 /**
2598  * \brief   Assuming the internal file pointer \ref gdcmDocument::fp 
2599  *          is placed at the beginning of a tag check whether this
2600  *          tag is (TestGroup, TestElement).
2601  * \warning On success the internal file pointer \ref gdcmDocument::fp
2602  *          is modified to point after the tag.
2603  *          On failure (i.e. when the tag wasn't the expected tag
2604  *          (TestGroup, TestElement) the internal file pointer
2605  *          \ref gdcmDocument::fp is restored to it's original position.
2606  * @param   TestGroup   The expected group of the tag.
2607  * @param   TestElement The expected Element of the tag.
2608  * @return  True on success, false otherwise.
2609  */
2610 bool gdcmDocument::ReadTag(uint16_t testGroup, uint16_t testElement)
2611 {
2612    long positionOnEntry = ftell(Fp);
2613    long currentPosition = ftell(Fp);          // On debugging purposes
2614
2615    //// Read the Item Tag group and element, and make
2616    // sure they are what we expected:
2617    uint16_t itemTagGroup   = ReadInt16();
2618    uint16_t itemTagElement = ReadInt16();
2619    if ( itemTagGroup != testGroup || itemTagElement != testElement )
2620    {
2621       std::ostringstream s;
2622       s << "   We should have found tag (";
2623       s << std::hex << testGroup << "," << testElement << ")" << std::endl;
2624       s << "   but instead we encountered tag (";
2625       s << std::hex << itemTagGroup << "," << itemTagElement << ")"
2626         << std::endl;
2627       s << "  at address: " << (unsigned)currentPosition << std::endl;
2628       dbg.Verbose(0, "gdcmDocument::ReadItemTagLength: wrong Item Tag found:");
2629       dbg.Verbose(0, s.str().c_str());
2630       fseek(Fp, positionOnEntry, SEEK_SET);
2631
2632       return false;
2633    }
2634    return true;
2635 }
2636
2637 /**
2638  * \brief   Assuming the internal file pointer \ref gdcmDocument::fp 
2639  *          is placed at the beginning of a tag (TestGroup, TestElement),
2640  *          read the length associated to the Tag.
2641  * \warning On success the internal file pointer \ref gdcmDocument::fp
2642  *          is modified to point after the tag and it's length.
2643  *          On failure (i.e. when the tag wasn't the expected tag
2644  *          (TestGroup, TestElement) the internal file pointer
2645  *          \ref gdcmDocument::fp is restored to it's original position.
2646  * @param   TestGroup   The expected group of the tag.
2647  * @param   TestElement The expected Element of the tag.
2648  * @return  On success returns the length associated to the tag. On failure
2649  *          returns 0.
2650  */
2651 uint32_t gdcmDocument::ReadTagLength(uint16_t testGroup, uint16_t testElement)
2652 {
2653    long positionOnEntry = ftell(Fp);
2654    (void)positionOnEntry;
2655
2656    if ( !ReadTag(testGroup, testElement) )
2657    {
2658       return 0;
2659    }
2660                                                                                 
2661    //// Then read the associated Item Length
2662    long currentPosition = ftell(Fp);
2663    uint32_t itemLength  = ReadInt32();
2664    {
2665       std::ostringstream s;
2666       s << "Basic Item Length is: "
2667         << itemLength << std::endl;
2668       s << "  at address: " << (unsigned)currentPosition << std::endl;
2669       dbg.Verbose(0, "gdcmDocument::ReadItemTagLength: ", s.str().c_str());
2670    }
2671    return itemLength;
2672 }
2673
2674 /**
2675  * \brief   Parse pixel data from disk for multi-fragment Jpeg/Rle files
2676  *          No other way so 'skip' the Data
2677  *
2678  */
2679 void gdcmDocument::Parse7FE0 ()
2680 {
2681    gdcmDocEntry* element = GetDocEntryByNumber(0x0002, 0x0010);
2682    if ( !element )
2683    {
2684       // Should warn user FIXME
2685       return;
2686    }
2687       
2688    if (   IsImplicitVRLittleEndianTransferSyntax()
2689        || IsExplicitVRLittleEndianTransferSyntax()
2690        || IsExplicitVRBigEndianTransferSyntax() /// \todo 1.2.2 ??? A verifier !
2691        || IsDeflatedExplicitVRLittleEndianTransferSyntax() )
2692    {
2693       return;
2694    }
2695
2696    // ---------------- for Parsing : Position on begining of Jpeg/RLE Pixels 
2697
2698    //// Read the Basic Offset Table Item Tag length...
2699    uint32_t itemLength = ReadTagLength(0xfffe, 0xe000);
2700
2701    //// ... and then read length[s] itself[themselves]. We don't use
2702    // the values read (BTW  what is the purpous of those lengths ?)
2703    if ( itemLength != 0 )
2704    {
2705       // BTW, what is the purpous of those length anyhow !? 
2706       char* basicOffsetTableItemValue = new char[itemLength + 1];
2707       fread(basicOffsetTableItemValue, itemLength, 1, Fp);
2708
2709       for (unsigned int i=0; i < itemLength; i += 4 )
2710       {
2711          uint32_t individualLength = str2num(&basicOffsetTableItemValue[i],uint32_t);
2712          std::ostringstream s;
2713          s << "   Read one length: ";
2714          s << std::hex << individualLength << std::endl;
2715          dbg.Verbose(0, "gdcmDocument::Parse7FE0: ", s.str().c_str());
2716       }
2717       delete[] basicOffsetTableItemValue;
2718    }
2719
2720    if ( ! IsRLELossLessTransferSyntax() )
2721    {
2722       // JPEG Image
2723       
2724       //// We then skip (not reading them) all the fragments of images:
2725       while ( (itemLength = ReadTagLength(0xfffe, 0xe000)) )
2726       {
2727          SkipBytes(itemLength);
2728       }
2729    }
2730    else
2731    {
2732       // RLE Image
2733       long ftellRes;
2734       long rleSegmentLength[15], fragmentLength;
2735
2736       // While we find some items:
2737       while ( (fragmentLength = ReadTagLength(0xfffe, 0xe000)) )
2738       { 
2739          // Parse fragments of the current Fragment (Frame)    
2740          //------------------ scanning (not reading) fragment pixels
2741          uint32_t nbRleSegments = ReadInt32();
2742  
2743          //// Reading RLE Segments Offset Table
2744          uint32_t rleSegmentOffsetTable[15];
2745          for(int k=1; k<=15; k++)
2746          {
2747             ftellRes = ftell(Fp);
2748             rleSegmentOffsetTable[k] = ReadInt32();
2749          }
2750
2751          // skipping (not reading) RLE Segments
2752          if ( nbRleSegments > 1)
2753          {
2754             for(unsigned int k = 1; k <= nbRleSegments-1; k++)
2755             {
2756                 rleSegmentLength[k] =  rleSegmentOffsetTable[k+1]
2757                                      - rleSegmentOffsetTable[k];
2758                 ftellRes = ftell(Fp);
2759                 SkipBytes(rleSegmentLength[k]);
2760              }
2761           }
2762
2763           rleSegmentLength[nbRleSegments] = fragmentLength 
2764                                           - rleSegmentOffsetTable[nbRleSegments];
2765           ftellRes = ftell(Fp);
2766           SkipBytes(rleSegmentLength[nbRleSegments]);
2767       }
2768
2769       // Make sure that at the end of the item we encounter a 'Sequence
2770       // Delimiter Item':
2771       if ( !ReadTag(0xfffe, 0xe0dd) )
2772       {
2773          dbg.Verbose(0, "gdcmDocument::Parse7FE0: no sequence delimiter item");
2774          dbg.Verbose(0, "    at end of RLE item sequence");
2775       }
2776    }
2777 }
2778
2779
2780
2781 /**
2782  * \brief   Compares two documents, according to \ref gdcmDicomDir rules
2783  * \warning Does NOT work with ACR-NEMA files
2784  * \todo    Find a trick to solve the pb (use RET fields ?)
2785  * @param   document
2786  * @return  true if 'smaller'
2787  */
2788 bool gdcmDocument::operator<(gdcmDocument &document)
2789 {
2790    // Patient Name
2791    std::string s1 = GetEntryByNumber(0x0010,0x0010);
2792    std::string s2 = document.GetEntryByNumber(0x0010,0x0010);
2793    if(s1 < s2)
2794    {
2795       return true;
2796    }
2797    else if(s1 > s2)
2798    {
2799       return false;
2800    }
2801    else
2802    {
2803       // Patient ID
2804       s1 = GetEntryByNumber(0x0010,0x0020);
2805       s2 = document.GetEntryByNumber(0x0010,0x0020);
2806       if ( s1 < s2 )
2807       {
2808          return true;
2809       }
2810       else if ( s1 > s2 )
2811       {
2812          return true;
2813       }
2814       else
2815       {
2816          // Study Instance UID
2817          s1 = GetEntryByNumber(0x0020,0x000d);
2818          s2 = document.GetEntryByNumber(0x0020,0x000d);
2819          if ( s1 < s2 )
2820          {
2821             return true;
2822          }
2823          else if( s1 > s2 )
2824          {
2825             return false;
2826          }
2827          else
2828          {
2829             // Serie Instance UID
2830             s1 = GetEntryByNumber(0x0020,0x000e);
2831             s2 = document.GetEntryByNumber(0x0020,0x000e);
2832             if ( s1 < s2 )
2833             {
2834                return true;
2835             }
2836             else if( s1 > s2 )
2837             {
2838                return false;
2839             }
2840          }
2841       }
2842    }
2843    return false;
2844 }
2845
2846
2847 //-----------------------------------------------------------------------------