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