]> Creatis software - gdcm.git/blob - src/gdcmDocument.cxx
36d1703c4d4548d6973ea45e747ad937fa2323db
[gdcm.git] / src / gdcmDocument.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDocument.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/08/01 03:20:23 $
7   Version:   $Revision: 1.63 $
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 const & 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 = 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 const & 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(std::string const & value, 
697                                           uint16_t group, uint16_t elem ) 
698 {
699    SetEntryByNumber(value, group, elem);
700
701    return true;
702
703
704 //-----------------------------------------------------------------------------
705 // Protected
706
707 /**
708  * \brief   Checks if a given Dicom Element exists within the H table
709  * @param   group      Group number of the searched Dicom Element 
710  * @param   element  Element number of the searched Dicom Element 
711  * @return  number of occurences
712  */
713 int gdcmDocument::CheckIfEntryExistByNumber(uint16_t group, uint16_t element )
714 {
715    const std::string &key = gdcmDictEntry::TranslateToKey(group, element );
716    return TagHT.count(key);
717 }
718
719 /**
720  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
721  *          the public and private dictionaries 
722  *          for the element value of a given tag.
723  * \warning Don't use any longer : use GetPubEntryByName
724  * @param   tagName name of the searched element.
725  * @return  Corresponding element value when it exists,
726  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
727  */
728 std::string gdcmDocument::GetEntryByName(TagName const & tagName)
729 {
730    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
731    if( !dictEntry )
732    {
733       return GDCM_UNFOUND;
734    }
735
736    return GetEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement());
737 }
738
739 /**
740  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
741  *          the public and private dictionaries 
742  *          for the element value representation of a given tag.
743  *
744  *          Obtaining the VR (Value Representation) might be needed by caller
745  *          to convert the string typed content to caller's native type 
746  *          (think of C++ vs Python). The VR is actually of a higher level
747  *          of semantics than just the native C++ type.
748  * @param   tagName name of the searched element.
749  * @return  Corresponding element value representation when it exists,
750  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
751  */
752 std::string gdcmDocument::GetEntryVRByName(TagName const & tagName)
753 {
754    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
755    if( dictEntry == NULL)
756    {
757       return GDCM_UNFOUND;
758    }
759
760    gdcmDocEntry* elem = GetDocEntryByNumber(dictEntry->GetGroup(),
761                                             dictEntry->GetElement());
762    return elem->GetVR();
763 }
764
765
766 /**
767  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
768  *          the public and private dictionaries 
769  *          for the element value representation of a given tag.
770  * @param   group Group number of the searched tag.
771  * @param   element Element number of the searched tag.
772  * @return  Corresponding element value representation when it exists,
773  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
774  */
775 std::string gdcmDocument::GetEntryByNumber(uint16_t group, uint16_t element)
776 {
777    gdcmTagKey key = gdcmDictEntry::TranslateToKey(group, element);
778    /// \todo use map methods, instead of multimap JPR
779    if ( !TagHT.count(key))
780    {
781       return GDCM_UNFOUND;
782    }
783
784    return ((gdcmValEntry *)TagHT.find(key)->second)->GetValue();
785 }
786
787 /**
788  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
789  *          the public and private dictionaries 
790  *          for the element value representation of a given tag..
791  *
792  *          Obtaining the VR (Value Representation) might be needed by caller
793  *          to convert the string typed content to caller's native type 
794  *          (think of C++ vs Python). The VR is actually of a higher level
795  *          of semantics than just the native C++ type.
796  * @param   group     Group number of the searched tag.
797  * @param   element Element number of the searched tag.
798  * @return  Corresponding element value representation when it exists,
799  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
800  */
801 std::string gdcmDocument::GetEntryVRByNumber(uint16_t group, uint16_t element)
802 {
803    gdcmDocEntry* elem = GetDocEntryByNumber(group, element);
804    if ( !elem )
805    {
806       return GDCM_UNFOUND;
807    }
808    return elem->GetVR();
809 }
810
811 /**
812  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
813  *          the public and private dictionaries 
814  *          for the value length of a given tag..
815  * @param   group     Group number of the searched tag.
816  * @param   element Element number of the searched tag.
817  * @return  Corresponding element length; -2 if not found
818  */
819 int gdcmDocument::GetEntryLengthByNumber(uint16_t group, uint16_t element)
820 {
821    gdcmDocEntry* elem =  GetDocEntryByNumber(group, element);
822    if ( !elem )
823    {
824       return -2;  //magic number
825    }
826    return elem->GetLength();
827 }
828 /**
829  * \brief   Sets the value (string) of the Header Entry (Dicom Element)
830  * @param   content string value of the Dicom Element
831  * @param   tagName name of the searched Dicom Element.
832  * @return  true when found
833  */
834 bool gdcmDocument::SetEntryByName(std::string const & content,std::string const & tagName)
835 {
836    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
837    if( !dictEntry )
838    {
839       return false;
840    }
841
842    return SetEntryByNumber(content,dictEntry->GetGroup(),
843                                    dictEntry->GetElement());
844 }
845
846 /**
847  * \brief   Accesses an existing gdcmDocEntry (i.e. a Dicom Element)
848  *          through it's (group, element) and modifies it's content with
849  *          the given value.
850  * @param   content new value (string) to substitute with
851  * @param   group     group number of the Dicom Element to modify
852  * @param   element element number of the Dicom Element to modify
853  */
854 bool gdcmDocument::SetEntryByNumber(std::string const & content, 
855                                     uint16_t group,
856                                     uint16_t element) 
857 {
858    gdcmValEntry* valEntry = GetValEntryByNumber(group, element);
859    if (!valEntry )
860    {
861       dbg.Verbose(0, "gdcmDocument::SetEntryByNumber: no corresponding",
862                      " ValEntry (try promotion first).");
863       return false;
864    }
865    // Non even content must be padded with a space (020H)...
866    std::string evenContent = content;
867    if( evenContent.length() % 2 )
868    {
869       evenContent += '\0';  // ... therefore we padd with (000H) .!?!
870    }      
871    valEntry->SetValue(evenContent);
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(evenContent.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 = (gdcmBinEntry *)TagHT[key];           
920    a->SetVoidArea(content);  
921    //a->SetLength(lgth);  // ???  
922
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
1070    // This was for multimap ?
1071    (( gdcmBinEntry *)( ((TagHT.equal_range(key)).first)->second ))->SetVoidArea(area);
1072       
1073    return true;
1074 }
1075
1076 /**
1077  * \brief   Update the entries with the shadow dictionary. 
1078  *          Only non even entries are analyzed       
1079  */
1080 void gdcmDocument::UpdateShaEntries()
1081 {
1082    //gdcmDictEntry *entry;
1083    std::string vr;
1084    
1085    /// \todo TODO : still any use to explore recursively the whole structure?
1086 /*
1087    for(ListTag::iterator it=listEntries.begin();
1088        it!=listEntries.end();
1089        ++it)
1090    {
1091       // Odd group => from public dictionary
1092       if((*it)->GetGroup()%2==0)
1093          continue;
1094
1095       // Peer group => search the corresponding dict entry
1096       if(RefShaDict)
1097          entry=RefShaDict->GetDictEntryByNumber((*it)->GetGroup(),(*it)->GetElement());
1098       else
1099          entry=NULL;
1100
1101       if((*it)->IsImplicitVR())
1102          vr="Implicit";
1103       else
1104          vr=(*it)->GetVR();
1105
1106       (*it)->SetValue(GetDocEntryUnvalue(*it));  // to go on compiling
1107       if(entry){
1108          // Set the new entry and the new value
1109          (*it)->SetDictEntry(entry);
1110          CheckDocEntryVR(*it,vr);
1111
1112          (*it)->SetValue(GetDocEntryValue(*it));    // to go on compiling
1113  
1114       }
1115       else
1116       {
1117          // Remove precedent value transformation
1118          (*it)->SetDictEntry(NewVirtualDictEntry((*it)->GetGroup(),(*it)->GetElement(),vr));
1119       }
1120    }
1121 */   
1122 }
1123
1124 /**
1125  * \brief   Searches within the Header Entries for a Dicom Element of
1126  *          a given tag.
1127  * @param   tagName name of the searched Dicom Element.
1128  * @return  Corresponding Dicom Element when it exists, and NULL
1129  *          otherwise.
1130  */
1131 gdcmDocEntry* gdcmDocument::GetDocEntryByName(std::string const & tagName)
1132 {
1133    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
1134    if( !dictEntry )
1135    {
1136       return NULL;
1137    }
1138
1139   return GetDocEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement());
1140 }
1141
1142 /**
1143  * \brief  retrieves a Dicom Element (the first one) using (group, element)
1144  * \warning (group, element) IS NOT an identifier inside the Dicom Header
1145  *           if you think it's NOT UNIQUE, check the count number
1146  *           and use iterators to retrieve ALL the Dicoms Elements within
1147  *           a given couple (group, element)
1148  * @param   group Group number of the searched Dicom Element 
1149  * @param   element Element number of the searched Dicom Element 
1150  * @return  
1151  */
1152 gdcmDocEntry* gdcmDocument::GetDocEntryByNumber(uint16_t group,
1153                                                 uint16_t element) 
1154 {
1155    gdcmTagKey key = gdcmDictEntry::TranslateToKey(group, element);
1156    if ( !TagHT.count(key))
1157    {
1158       return NULL;
1159    }
1160    return TagHT.find(key)->second;
1161 }
1162
1163 /**
1164  * \brief  Same as \ref gdcmDocument::GetDocEntryByNumber except it only
1165  *         returns a result when the corresponding entry is of type
1166  *         ValEntry.
1167  * @return When present, the corresponding ValEntry. 
1168  */
1169 gdcmValEntry* gdcmDocument::GetValEntryByNumber(uint16_t group,
1170                                                 uint16_t element)
1171 {
1172    gdcmDocEntry* currentEntry = GetDocEntryByNumber(group, element);
1173    if ( !currentEntry )
1174    {
1175       return 0;
1176    }
1177    if ( gdcmValEntry* valEntry = dynamic_cast<gdcmValEntry*>(currentEntry) )
1178    {
1179       return valEntry;
1180    }
1181    dbg.Verbose(0, "gdcmDocument::GetValEntryByNumber: unfound ValEntry.");
1182
1183    return 0;
1184 }
1185
1186 /**
1187  * \brief         Loads the element while preserving the current
1188  *                underlying file position indicator as opposed to
1189  *                to LoadDocEntry that modifies it.
1190  * @param entry   Header Entry whose value shall be loaded. 
1191  * @return  
1192  */
1193 void gdcmDocument::LoadDocEntrySafe(gdcmDocEntry * entry)
1194 {
1195    long PositionOnEntry = ftell(Fp);
1196    LoadDocEntry(entry);
1197    fseek(Fp, PositionOnEntry, SEEK_SET);
1198 }
1199
1200 /**
1201  * \brief   Swaps back the bytes of 4-byte long integer accordingly to
1202  *          processor order.
1203  * @return  The properly swaped 32 bits integer.
1204  */
1205 uint32_t gdcmDocument::SwapLong(uint32_t a)
1206 {
1207    switch (SwapCode)
1208    {
1209       case    0 :
1210          break;
1211       case 4321 :
1212          a=( ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000) | 
1213              ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
1214          break;
1215    
1216       case 3412 :
1217          a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
1218          break;
1219    
1220       case 2143 :
1221          a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
1222          break;
1223       default :
1224          std::cout << "swapCode= " << SwapCode << std::endl;
1225          dbg.Error(" gdcmDocument::SwapLong : unset swap code");
1226          a = 0;
1227    }
1228    return a;
1229
1230
1231 /**
1232  * \brief   Unswaps back the bytes of 4-byte long integer accordingly to
1233  *          processor order.
1234  * @return  The properly unswaped 32 bits integer.
1235  */
1236 uint32_t gdcmDocument::UnswapLong(uint32_t a)
1237 {
1238    return SwapLong(a);
1239 }
1240
1241 /**
1242  * \brief   Swaps the bytes so they agree with the processor order
1243  * @return  The properly swaped 16 bits integer.
1244  */
1245 uint16_t gdcmDocument::SwapShort(uint16_t a)
1246 {
1247    if ( SwapCode == 4321 || SwapCode == 2143 )
1248    {
1249       a = ((( a << 8 ) & 0x0ff00 ) | (( a >> 8 ) & 0x00ff ) );
1250    }
1251    return a;
1252 }
1253
1254 /**
1255  * \brief   Unswaps the bytes so they agree with the processor order
1256  * @return  The properly unswaped 16 bits integer.
1257  */
1258 uint16_t gdcmDocument::UnswapShort(uint16_t a)
1259 {
1260    return SwapShort(a);
1261 }
1262
1263 //-----------------------------------------------------------------------------
1264 // Private
1265
1266 /**
1267  * \brief   Parses a DocEntrySet (Zero-level DocEntries or SQ Item DocEntries)
1268  * @return  length of the parsed set. 
1269  */ 
1270
1271 long gdcmDocument::ParseDES(gdcmDocEntrySet *set,
1272                             long offset,
1273                             long l_max,
1274                             bool delim_mode)
1275 {
1276    gdcmDocEntry *newDocEntry = 0;
1277    gdcmValEntry *newValEntry = 0;
1278    unsigned long l = 0;
1279    
1280    int depth = set->GetDepthLevel();
1281    while (true)
1282    { 
1283       if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
1284       {
1285          break;
1286       }
1287       newDocEntry = ReadNextDocEntry( );
1288       if ( !newDocEntry )
1289       {
1290          break;
1291       }
1292
1293       gdcmVRKey vr = newDocEntry->GetVR();
1294       if ( vr != "SQ" )
1295       {
1296                
1297          if ( gdcmGlobal::GetVR()->IsVROfGdcmStringRepresentable(vr) )
1298          {
1299             /////// ValEntry
1300             newValEntry = new gdcmValEntry(newDocEntry->GetDictEntry());
1301             newValEntry->Copy(newDocEntry);
1302             newValEntry->SetDepthLevel(depth);
1303             set->AddEntry(newValEntry);
1304             LoadDocEntry(newValEntry);
1305             if (newValEntry->IsItemDelimitor())
1306             {
1307                break;
1308             }
1309             if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
1310             {
1311                break;
1312             }
1313          }
1314          else
1315          {
1316             if ( ! gdcmGlobal::GetVR()->IsVROfGdcmBinaryRepresentable(vr) )
1317             { 
1318                 ////// Neither ValEntry NOR BinEntry: should mean UNKOWN VR
1319                 dbg.Verbose(0, "gdcmDocument::ParseDES: neither Valentry, "
1320                                "nor BinEntry. Probably unknown VR.");
1321             }
1322
1323             ////// BinEntry or UNKOWN VR:
1324             gdcmBinEntry *bn = new gdcmBinEntry(newDocEntry->GetDictEntry());
1325             bn->Copy(newDocEntry);
1326             set->AddEntry(bn);
1327             LoadDocEntry(bn);
1328          }
1329
1330          if (newDocEntry->GetGroup()   == 0x7fe0 && 
1331              newDocEntry->GetElement() == 0x0010 )
1332          {
1333              if (newDocEntry->GetReadLength()==0xffffffff)
1334              {
1335                 // Broken US.3405.1.dcm
1336                 Parse7FE0(); // to skip the pixels 
1337                              // (multipart JPEG/RLE are trouble makers)
1338              }
1339              else
1340              {
1341                 SkipToNextDocEntry(newDocEntry);
1342                 l = newDocEntry->GetFullLength(); 
1343              }
1344          }
1345          else
1346          {
1347              // to be sure we are at the beginning 
1348              SkipToNextDocEntry(newDocEntry);
1349              l = newDocEntry->GetFullLength(); 
1350          }
1351       }
1352       else
1353       {
1354          // VR = "SQ"
1355          l = newDocEntry->GetReadLength();            
1356          if ( l != 0 ) // don't mess the delim_mode for zero-length sequence
1357          {
1358             if ( l == 0xffffffff )
1359             {
1360               delim_mode = true;
1361             }
1362             else
1363             {
1364               delim_mode = false;
1365             }
1366          }
1367          // no other way to create it ...
1368          gdcmSeqEntry *sq = new gdcmSeqEntry(newDocEntry->GetDictEntry(),
1369                                              set->GetDepthLevel());
1370          sq->Copy(newDocEntry);
1371          sq->SetDelimitorMode(delim_mode);
1372          sq->SetDepthLevel(depth);
1373
1374          if ( l != 0 )
1375          {  // Don't try to parse zero-length sequences
1376             long lgt = ParseSQ( sq, 
1377                                 newDocEntry->GetOffset(),
1378                                 l, delim_mode);
1379             (void)lgt;  //not used...
1380          }
1381          set->AddEntry(sq);
1382          if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
1383          {
1384             break;
1385          }
1386       }
1387       delete newDocEntry;
1388    }
1389
1390    return l; // Probably useless 
1391 }
1392
1393 /**
1394  * \brief   Parses a Sequence ( SeqEntry after SeqEntry)
1395  * @return  parsed length for this level
1396  */ 
1397 long gdcmDocument::ParseSQ(gdcmSeqEntry *set,
1398                            long offset, long l_max, bool delim_mode)
1399 {
1400    int SQItemNumber = 0;
1401    bool dlm_mod;
1402    //int depth = set->GetDepthLevel();
1403    //(void)depth; //not used
1404
1405    while (true)
1406    {
1407       gdcmDocEntry *newDocEntry = ReadNextDocEntry();   
1408       if ( !newDocEntry )
1409       {
1410          // FIXME Should warn user
1411          break;
1412       }
1413       if( delim_mode )
1414       {
1415          if ( newDocEntry->IsSequenceDelimitor() )
1416          {
1417             set->SetSequenceDelimitationItem( newDocEntry );
1418             break;
1419          }
1420       }
1421       if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
1422       {
1423           break;
1424       }
1425
1426       gdcmSQItem *itemSQ = new gdcmSQItem(set->GetDepthLevel());
1427       itemSQ->AddEntry(newDocEntry);
1428       unsigned int l = newDocEntry->GetReadLength();
1429       
1430       if ( l == 0xffffffff )
1431       {
1432          dlm_mod = true;
1433       }
1434       else
1435       {
1436          dlm_mod = false;
1437       }
1438    
1439       int lgr = ParseDES(itemSQ, newDocEntry->GetOffset(), l, dlm_mod);
1440       (void)lgr;  //FIXME not used
1441       
1442       set->AddEntry(itemSQ, SQItemNumber); 
1443       SQItemNumber++;
1444       if ( !delim_mode && (ftell(Fp)-offset) >= l_max)
1445       {
1446          break;
1447       }
1448    }
1449
1450    int lgth = ftell(Fp) - offset;
1451    return lgth;
1452 }
1453
1454 /**
1455  * \brief         Loads the element content if its length doesn't exceed
1456  *                the value specified with gdcmDocument::SetMaxSizeLoadEntry()
1457  * @param         Entry Header Entry (Dicom Element) to be dealt with
1458  */
1459 void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry)
1460 {
1461    size_t item_read;
1462    uint16_t group  = entry->GetGroup();
1463    std::string  vr = entry->GetVR();
1464    uint32_t length = entry->GetLength();
1465
1466    fseek(Fp, (long)entry->GetOffset(), SEEK_SET);
1467
1468    // A SeQuence "contains" a set of Elements.  
1469    //          (fffe e000) tells us an Element is beginning
1470    //          (fffe e00d) tells us an Element just ended
1471    //          (fffe e0dd) tells us the current SeQuence just ended
1472    if( group == 0xfffe )
1473    {
1474       // NO more value field for SQ !
1475       return;
1476    }
1477
1478    // When the length is zero things are easy:
1479    if ( length == 0 )
1480    {
1481       ((gdcmValEntry *)entry)->SetValue("");
1482       return;
1483    }
1484
1485    // The elements whose length is bigger than the specified upper bound
1486    // are not loaded. Instead we leave a short notice of the offset of
1487    // the element content and it's length.
1488
1489    std::ostringstream s;
1490    if (length > MaxSizeLoadEntry)
1491    {
1492       if (gdcmBinEntry* binEntryPtr = dynamic_cast< gdcmBinEntry* >(entry) )
1493       {         
1494          s << "gdcm::NotLoaded (BinEntry)";
1495          s << " Address:" << (long)entry->GetOffset();
1496          s << " Length:"  << entry->GetLength();
1497          s << " x(" << std::hex << entry->GetLength() << ")";
1498          binEntryPtr->SetValue(s.str());
1499       }
1500       // to be sure we are at the end of the value ...
1501       fseek(Fp, (long)entry->GetOffset()+(long)entry->GetLength(), SEEK_SET);      
1502
1503       return;  //FIXME FIXME FIXME FIXME ????
1504
1505        // Be carefull : a BinEntry IS_A ValEntry ... 
1506       if (gdcmValEntry* valEntryPtr = dynamic_cast< gdcmValEntry* >(entry) )
1507       {
1508          s << "gdcm::NotLoaded. (ValEntry)";
1509          s << " Address:" << (long)entry->GetOffset();
1510          s << " Length:"  << entry->GetLength();
1511          s << " x(" << std::hex << entry->GetLength() << ")";
1512          valEntryPtr->SetValue(s.str());
1513       }
1514       // to be sure we are at the end of the value ...
1515       fseek(Fp,(long)entry->GetOffset()+(long)entry->GetLength(),SEEK_SET);      
1516
1517       return;
1518    }
1519
1520    // When we find a BinEntry not very much can be done :
1521    if (gdcmBinEntry* binEntryPtr = dynamic_cast< gdcmBinEntry* >(entry) )
1522    {
1523
1524       LoadEntryVoidArea(binEntryPtr);
1525       s << "gdcm::Loaded (BinEntry)";
1526       binEntryPtr->SetValue(s.str());
1527       return;
1528    }
1529     
1530    /// \todo Any compacter code suggested (?)
1531    if ( IsDocEntryAnInteger(entry) )
1532    {   
1533       uint32_t NewInt;
1534       std::ostringstream s;
1535       int nbInt;
1536       // When short integer(s) are expected, read and convert the following 
1537       // n *two characters properly i.e. consider them as short integers as
1538       // opposed to strings.
1539       // Elements with Value Multiplicity > 1
1540       // contain a set of integers (not a single one)       
1541       if (vr == "US" || vr == "SS")
1542       {
1543          nbInt = length / 2;
1544          NewInt = ReadInt16();
1545          s << NewInt;
1546          if (nbInt > 1)
1547          {
1548             for (int i=1; i < nbInt; i++)
1549             {
1550                s << '\\';
1551                NewInt = ReadInt16();
1552                s << NewInt;
1553             }
1554          }
1555       }
1556       // See above comment on multiple integers (mutatis mutandis).
1557       else if (vr == "UL" || vr == "SL")
1558       {
1559          nbInt = length / 4;
1560          NewInt = ReadInt32();
1561          s << NewInt;
1562          if (nbInt > 1)
1563          {
1564             for (int i=1; i < nbInt; i++)
1565             {
1566                s << '\\';
1567                NewInt = ReadInt32();
1568                s << NewInt;
1569             }
1570          }
1571       }
1572 #ifdef GDCM_NO_ANSI_STRING_STREAM
1573       s << std::ends; // to avoid oddities on Solaris
1574 #endif //GDCM_NO_ANSI_STRING_STREAM
1575
1576       ((gdcmValEntry *)entry)->SetValue(s.str());
1577       return;
1578    }
1579    
1580    // We need an additional byte for storing \0 that is not on disk
1581    //std::string newValue(length,0);
1582    //item_read = fread(&(newValue[0]), (size_t)length, (size_t)1, Fp);  
1583    //rah !! I can't believe it could work, normally this is a const char* !!!
1584    char *str = new char[length+1];
1585    item_read = fread(str, (size_t)length, (size_t)1, Fp);
1586    str[length] = '\0';
1587    std::string newValue = str;
1588    delete[] str;
1589    if ( gdcmValEntry* valEntry = dynamic_cast<gdcmValEntry* >(entry) )
1590    {  
1591       if ( item_read != 1 )
1592       {
1593          dbg.Verbose(1, "gdcmDocument::LoadDocEntry",
1594                         "unread element value");
1595          valEntry->SetValue("gdcm::UnRead");
1596          return;
1597       }
1598
1599       if( vr == "UI" )
1600       {
1601          // Because of correspondance with the VR dic
1602          valEntry->SetValue(newValue);
1603       }
1604       else
1605       {
1606          valEntry->SetValue(newValue);
1607       }
1608    }
1609    else
1610    {
1611       dbg.Error(true, "gdcmDocument::LoadDocEntry"
1612                       "Should have a ValEntry, here !");
1613    }
1614 }
1615
1616
1617 /**
1618  * \brief  Find the value Length of the passed Header Entry
1619  * @param  Entry Header Entry whose length of the value shall be loaded. 
1620  */
1621 void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry)
1622 {
1623    uint16_t element = entry->GetElement();
1624    std::string  vr  = entry->GetVR();
1625    uint16_t length16;
1626        
1627    
1628    if ( Filetype == gdcmExplicitVR && !entry->IsImplicitVR() ) 
1629    {
1630       if ( vr == "OB" || vr == "OW" || vr == "SQ" || vr == "UN" ) 
1631       {
1632          // The following reserved two bytes (see PS 3.5-2001, section
1633          // 7.1.2 Data element structure with explicit vr p27) must be
1634          // skipped before proceeding on reading the length on 4 bytes.
1635          fseek(Fp, 2L, SEEK_CUR);
1636          uint32_t length32 = ReadInt32();
1637
1638          if ( vr == "OB" && length32 == 0xffffffff ) 
1639          {
1640             uint32_t lengthOB = FindDocEntryLengthOB();
1641             if ( errno == 1 )
1642             {
1643                // Computing the length failed (this happens with broken
1644                // files like gdcm-JPEG-LossLess3a.dcm). We still have a
1645                // chance to get the pixels by deciding the element goes
1646                // until the end of the file. Hence we artificially fix the
1647                // the length and proceed.
1648                long currentPosition = ftell(Fp);
1649                fseek(Fp,0L,SEEK_END);
1650                long lengthUntilEOF = ftell(Fp) - currentPosition;
1651                fseek(Fp, currentPosition, SEEK_SET);
1652                entry->SetLength(lengthUntilEOF);
1653                errno = 0;
1654                return;
1655             }
1656             entry->SetLength(lengthOB);
1657             return;
1658          }
1659          FixDocEntryFoundLength(entry, length32); 
1660          return;
1661       }
1662
1663       // Length is encoded on 2 bytes.
1664       length16 = ReadInt16();
1665       
1666       // We can tell the current file is encoded in big endian (like
1667       // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag
1668       // and it's value is the one of the encoding of a big endian file.
1669       // In order to deal with such big endian encoded files, we have
1670       // (at least) two strategies:
1671       // * when we load the "Transfer Syntax" tag with value of big endian
1672       //   encoding, we raise the proper flags. Then we wait for the end
1673       //   of the META group (0x0002) among which is "Transfer Syntax",
1674       //   before switching the swap code to big endian. We have to postpone
1675       //   the switching of the swap code since the META group is fully encoded
1676       //   in little endian, and big endian coding only starts at the next
1677       //   group. The corresponding code can be hard to analyse and adds
1678       //   many additional unnecessary tests for regular tags.
1679       // * the second strategy consists in waiting for trouble, that shall
1680       //   appear when we find the first group with big endian encoding. This
1681       //   is easy to detect since the length of a "Group Length" tag (the
1682       //   ones with zero as element number) has to be of 4 (0x0004). When we
1683       //   encounter 1024 (0x0400) chances are the encoding changed and we
1684       //   found a group with big endian encoding.
1685       // We shall use this second strategy. In order to make sure that we
1686       // can interpret the presence of an apparently big endian encoded
1687       // length of a "Group Length" without committing a big mistake, we
1688       // add an additional check: we look in the already parsed elements
1689       // for the presence of a "Transfer Syntax" whose value has to be "big
1690       // endian encoding". When this is the case, chances are we have got our
1691       // hands on a big endian encoded file: we switch the swap code to
1692       // big endian and proceed...
1693       if ( element  == 0x0000 && length16 == 0x0400 ) 
1694       {
1695          if ( !IsExplicitVRBigEndianTransferSyntax() ) 
1696          {
1697             dbg.Verbose(0, "gdcmDocument::FindLength", "not explicit VR");
1698             errno = 1;
1699             return;
1700          }
1701          length16 = 4;
1702          SwitchSwapToBigEndian();
1703          // Restore the unproperly loaded values i.e. the group, the element
1704          // and the dictionary entry depending on them.
1705          uint16_t correctGroup = SwapShort( entry->GetGroup() );
1706          uint16_t correctElem  = SwapShort( entry->GetElement() );
1707          gdcmDictEntry* newTag = GetDictEntryByNumber( correctGroup,
1708                                                        correctElem );
1709          if ( !newTag )
1710          {
1711             // This correct tag is not in the dictionary. Create a new one.
1712             newTag = NewVirtualDictEntry(correctGroup, correctElem);
1713          }
1714          // FIXME this can create a memory leaks on the old entry that be
1715          // left unreferenced.
1716          entry->SetDictEntry( newTag );
1717       }
1718        
1719       // Heuristic: well, some files are really ill-formed.
1720       if ( length16 == 0xffff) 
1721       {
1722          length16 = 0;
1723          // Length16= 0xffff means that we deal with
1724          // 'Unknown Length' Sequence  
1725       }
1726       FixDocEntryFoundLength(entry, (uint32_t)length16);
1727       return;
1728    }
1729    else
1730    {
1731       // Either implicit VR or a non DICOM conformal (see note below) explicit
1732       // VR that ommited the VR of (at least) this element. Farts happen.
1733       // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25
1734       // on Data elements "Implicit and Explicit VR Data Elements shall
1735       // not coexist in a Data Set and Data Sets nested within it".]
1736       // Length is on 4 bytes.
1737       
1738       FixDocEntryFoundLength(entry, ReadInt32());
1739       return;
1740    }
1741 }
1742
1743 /**
1744  * \brief     Find the Value Representation of the current Dicom Element.
1745  * @param     Entry
1746  */
1747 void gdcmDocument::FindDocEntryVR( gdcmDocEntry *entry )
1748 {
1749    if ( Filetype != gdcmExplicitVR )
1750    {
1751       return;
1752    }
1753
1754    char vr[3];
1755
1756    long positionOnEntry = ftell(Fp);
1757    // Warning: we believe this is explicit VR (Value Representation) because
1758    // we used a heuristic that found "UL" in the first tag. Alas this
1759    // doesn't guarantee that all the tags will be in explicit VR. In some
1760    // cases (see e-film filtered files) one finds implicit VR tags mixed
1761    // within an explicit VR file. Hence we make sure the present tag
1762    // is in explicit VR and try to fix things if it happens not to be
1763    // the case.
1764    
1765    fread (vr, (size_t)2,(size_t)1, Fp);
1766    vr[2] = 0;
1767
1768    if( !CheckDocEntryVR(entry, vr) )
1769    {
1770       fseek(Fp, positionOnEntry, SEEK_SET);
1771       // When this element is known in the dictionary we shall use, e.g. for
1772       // the semantics (see the usage of IsAnInteger), the VR proposed by the
1773       // dictionary entry. Still we have to flag the element as implicit since
1774       // we know now our assumption on expliciteness is not furfilled.
1775       // avoid  .
1776       if ( entry->IsVRUnknown() )
1777       {
1778          entry->SetVR("Implicit");
1779       }
1780       entry->SetImplicitVR();
1781    }
1782 }
1783
1784 /**
1785  * \brief     Check the correspondance between the VR of the header entry
1786  *            and the taken VR. If they are different, the header entry is 
1787  *            updated with the new VR.
1788  * @param     Entry Header Entry to check
1789  * @param     vr    Dicom Value Representation
1790  * @return    false if the VR is incorrect of if the VR isn't referenced
1791  *            otherwise, it returns true
1792 */
1793 bool gdcmDocument::CheckDocEntryVR(gdcmDocEntry *entry, gdcmVRKey vr)
1794 {
1795    char msg[100]; // for sprintf
1796    bool realExplicit = true;
1797
1798    // Assume we are reading a falsely explicit VR file i.e. we reached
1799    // a tag where we expect reading a VR but are in fact we read the
1800    // first to bytes of the length. Then we will interogate (through find)
1801    // the dicom_vr dictionary with oddities like "\004\0" which crashes
1802    // both GCC and VC++ implementations of the STL map. Hence when the
1803    // expected VR read happens to be non-ascii characters we consider
1804    // we hit falsely explicit VR tag.
1805
1806    if ( !isalpha(vr[0]) && !isalpha(vr[1]) )
1807    {
1808       realExplicit = false;
1809    }
1810
1811    // CLEANME searching the dicom_vr at each occurence is expensive.
1812    // PostPone this test in an optional integrity check at the end
1813    // of parsing or only in debug mode.
1814    if ( realExplicit && !gdcmGlobal::GetVR()->Count(vr) )
1815    {
1816       realExplicit = false;
1817    }
1818
1819    if ( !realExplicit ) 
1820    {
1821       // We thought this was explicit VR, but we end up with an
1822       // implicit VR tag. Let's backtrack.   
1823       sprintf(msg,"Falsely explicit vr file (%04x,%04x)\n", 
1824                    entry->GetGroup(), entry->GetElement());
1825       dbg.Verbose(1, "gdcmDocument::FindVR: ",msg);
1826
1827       if( entry->GetGroup() % 2 && entry->GetElement() == 0x0000)
1828       {
1829          // Group length is UL !
1830          gdcmDictEntry* newEntry = NewVirtualDictEntry(
1831                                    entry->GetGroup(), entry->GetElement(),
1832                                    "UL", "FIXME", "Group Length");
1833          entry->SetDictEntry( newEntry );
1834       }
1835       return false;
1836    }
1837
1838    if ( entry->IsVRUnknown() )
1839    {
1840       // When not a dictionary entry, we can safely overwrite the VR.
1841       if( entry->GetElement() == 0x0000 )
1842       {
1843          // Group length is UL !
1844          entry->SetVR("UL");
1845       }
1846       else
1847       {
1848          entry->SetVR(vr);
1849       }
1850    }
1851    else if ( entry->GetVR() != vr ) 
1852    {
1853       // The VR present in the file and the dictionary disagree. We assume
1854       // the file writer knew best and use the VR of the file. Since it would
1855       // be unwise to overwrite the VR of a dictionary (since it would
1856       // compromise it's next user), we need to clone the actual DictEntry
1857       // and change the VR for the read one.
1858       gdcmDictEntry* newEntry = NewVirtualDictEntry(
1859                                 entry->GetGroup(), entry->GetElement(),
1860                                 vr, "FIXME", entry->GetName());
1861       entry->SetDictEntry(newEntry);
1862    }
1863
1864    return true; 
1865 }
1866
1867 /**
1868  * \brief   Get the transformed value of the header entry. The VR value 
1869  *          is used to define the transformation to operate on the value
1870  * \warning NOT end user intended method !
1871  * @param   Entry 
1872  * @return  Transformed entry value
1873  */
1874 std::string gdcmDocument::GetDocEntryValue(gdcmDocEntry *entry)
1875 {
1876    if ( IsDocEntryAnInteger(entry) && entry->IsImplicitVR() )
1877    {
1878       std::string val = ((gdcmValEntry *)entry)->GetValue();
1879       std::string vr  = entry->GetVR();
1880       uint32_t length = entry->GetLength();
1881       std::ostringstream s;
1882       int nbInt;
1883
1884       // When short integer(s) are expected, read and convert the following 
1885       // n * 2 bytes properly i.e. as a multivaluated strings
1886       // (each single value is separated fromthe next one by '\'
1887       // as usual for standard multivaluated filels
1888       // Elements with Value Multiplicity > 1
1889       // contain a set of short integers (not a single one) 
1890    
1891       if( vr == "US" || vr == "SS" )
1892       {
1893          uint16_t newInt16;
1894
1895          nbInt = length / 2;
1896          for (int i=0; i < nbInt; i++) 
1897          {
1898             if( i != 0 )
1899             {
1900                s << '\\';
1901             }
1902             newInt16 = ( val[2*i+0] & 0xFF ) + ( ( val[2*i+1] & 0xFF ) << 8);
1903             newInt16 = SwapShort( newInt16 );
1904             s << newInt16;
1905          }
1906       }
1907
1908       // When integer(s) are expected, read and convert the following 
1909       // n * 4 bytes properly i.e. as a multivaluated strings
1910       // (each single value is separated fromthe next one by '\'
1911       // as usual for standard multivaluated filels
1912       // Elements with Value Multiplicity > 1
1913       // contain a set of integers (not a single one) 
1914       else if( vr == "UL" || vr == "SL" )
1915       {
1916          uint32_t newInt32;
1917
1918          nbInt = length / 4;
1919          for (int i=0; i < nbInt; i++) 
1920          {
1921             if( i != 0)
1922             {
1923                s << '\\';
1924             }
1925             newInt32 = ( val[4*i+0] & 0xFF )
1926                     + (( val[4*i+1] & 0xFF ) <<  8 )
1927                     + (( val[4*i+2] & 0xFF ) << 16 )
1928                     + (( val[4*i+3] & 0xFF ) << 24 );
1929             newInt32 = SwapLong( newInt32 );
1930             s << newInt32;
1931          }
1932       }
1933 #ifdef GDCM_NO_ANSI_STRING_STREAM
1934       s << std::ends; // to avoid oddities on Solaris
1935 #endif //GDCM_NO_ANSI_STRING_STREAM
1936       return s.str();
1937    }
1938
1939    return ((gdcmValEntry *)entry)->GetValue();
1940 }
1941
1942 /**
1943  * \brief   Get the reverse transformed value of the header entry. The VR 
1944  *          value is used to define the reverse transformation to operate on
1945  *          the value
1946  * \warning NOT end user intended method !
1947  * @param   Entry 
1948  * @return  Reverse transformed entry value
1949  */
1950 std::string gdcmDocument::GetDocEntryUnvalue(gdcmDocEntry* entry)
1951 {
1952    if ( IsDocEntryAnInteger(entry) && entry->IsImplicitVR() )
1953    {
1954       std::string vr = entry->GetVR();
1955       std::vector<std::string> tokens;
1956       std::ostringstream s;
1957
1958       if ( vr == "US" || vr == "SS" ) 
1959       {
1960          uint16_t newInt16;
1961
1962          tokens.erase( tokens.begin(), tokens.end()); // clean any previous value
1963          Tokenize (((gdcmValEntry *)entry)->GetValue(), tokens, "\\");
1964          for (unsigned int i=0; i<tokens.size(); i++) 
1965          {
1966             newInt16 = atoi(tokens[i].c_str());
1967             s << (  newInt16        & 0xFF ) 
1968               << (( newInt16 >> 8 ) & 0xFF );
1969          }
1970          tokens.clear();
1971       }
1972       if ( vr == "UL" || vr == "SL")
1973       {
1974          uint32_t newInt32;
1975
1976          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
1977          Tokenize (((gdcmValEntry *)entry)->GetValue(), tokens, "\\");
1978          for (unsigned int i=0; i<tokens.size();i++) 
1979          {
1980             newInt32 = atoi(tokens[i].c_str());
1981             s << (char)(  newInt32         & 0xFF ) 
1982               << (char)(( newInt32 >>  8 ) & 0xFF )
1983               << (char)(( newInt32 >> 16 ) & 0xFF )
1984               << (char)(( newInt32 >> 24 ) & 0xFF );
1985          }
1986          tokens.clear();
1987       }
1988
1989 #ifdef GDCM_NO_ANSI_STRING_STREAM
1990       s << std::ends; // to avoid oddities on Solaris
1991 #endif //GDCM_NO_ANSI_STRING_STREAM
1992       return s.str();
1993    }
1994
1995    return ((gdcmValEntry *)entry)->GetValue();
1996 }
1997
1998 /**
1999  * \brief   Skip a given Header Entry 
2000  * \warning NOT end user intended method !
2001  * @param   entry 
2002  */
2003 void gdcmDocument::SkipDocEntry(gdcmDocEntry *entry) 
2004 {
2005    SkipBytes(entry->GetLength());
2006 }
2007
2008 /**
2009  * \brief   Skips to the begining of the next Header Entry 
2010  * \warning NOT end user intended method !
2011  * @param   entry 
2012  */
2013 void gdcmDocument::SkipToNextDocEntry(gdcmDocEntry *entry) 
2014 {
2015    fseek(Fp, (long)(entry->GetOffset()),     SEEK_SET);
2016    fseek(Fp, (long)(entry->GetReadLength()), SEEK_CUR);
2017 }
2018
2019 /**
2020  * \brief   When the length of an element value is obviously wrong (because
2021  *          the parser went Jabberwocky) one can hope improving things by
2022  *          applying some heuristics.
2023  */
2024 void gdcmDocument::FixDocEntryFoundLength(gdcmDocEntry *entry,
2025                                           uint32_t foundLength)
2026 {
2027    entry->SetReadLength( foundLength ); // will be updated only if a bug is found        
2028    if ( foundLength == 0xffffffff)
2029    {
2030       foundLength = 0;
2031    }
2032    
2033    uint16_t gr = entry->GetGroup();
2034    uint16_t el = entry->GetElement(); 
2035      
2036    if ( foundLength % 2)
2037    {
2038       std::ostringstream s;
2039       s << "Warning : Tag with uneven length "
2040         << foundLength 
2041         <<  " in x(" << std::hex << gr << "," << el <<")" << std::dec;
2042       dbg.Verbose(0, s.str().c_str());
2043    }
2044       
2045    //////// Fix for some naughty General Electric images.
2046    // Allthough not recent many such GE corrupted images are still present
2047    // on Creatis hard disks. Hence this fix shall remain when such images
2048    // are no longer in user (we are talking a few years, here)...
2049    // Note: XMedCom probably uses such a trick since it is able to read
2050    //       those pesky GE images ...
2051    if ( foundLength == 13)
2052    {
2053       // Only happens for this length !
2054       if ( entry->GetGroup()   != 0x0008
2055       || ( entry->GetElement() != 0x0070
2056         && entry->GetElement() != 0x0080 ) )
2057       {
2058          foundLength = 10;
2059          entry->SetReadLength(10); /// \todo a bug is to be fixed !?
2060       }
2061    }
2062
2063    //////// Fix for some brain-dead 'Leonardo' Siemens images.
2064    // Occurence of such images is quite low (unless one leaves close to a
2065    // 'Leonardo' source. Hence, one might consider commenting out the
2066    // following fix on efficiency reasons.
2067    else if ( entry->GetGroup()   == 0x0009 
2068         && ( entry->GetElement() == 0x1113
2069           || entry->GetElement() == 0x1114 ) )
2070    {
2071       foundLength = 4;
2072       entry->SetReadLength(4); /// \todo a bug is to be fixed !?
2073    } 
2074  
2075    else if ( entry->GetVR() == "SQ" )
2076    {
2077       foundLength = 0;      // ReadLength is unchanged 
2078    } 
2079     
2080    //////// We encountered a 'delimiter' element i.e. a tag of the form 
2081    // "fffe|xxxx" which is just a marker. Delimiters length should not be
2082    // taken into account.
2083    else if( entry->GetGroup() == 0xfffe )
2084    {    
2085      // According to the norm, fffe|0000 shouldn't exist. BUT the Philips
2086      // image gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm happens to
2087      // causes extra troubles...
2088      if( entry->GetElement() != 0x0000 )
2089      {
2090         foundLength = 0;
2091      }
2092    } 
2093            
2094    entry->SetUsableLength(foundLength);
2095 }
2096
2097 /**
2098  * \brief   Apply some heuristics to predict whether the considered 
2099  *          element value contains/represents an integer or not.
2100  * @param   Entry The element value on which to apply the predicate.
2101  * @return  The result of the heuristical predicate.
2102  */
2103 bool gdcmDocument::IsDocEntryAnInteger(gdcmDocEntry *entry)
2104 {
2105    uint16_t element = entry->GetElement();
2106    uint16_t group   = entry->GetGroup();
2107    std::string  vr  = entry->GetVR();
2108    uint32_t length  = entry->GetLength();
2109
2110    // When we have some semantics on the element we just read, and if we
2111    // a priori know we are dealing with an integer, then we shall be
2112    // able to swap it's element value properly.
2113    if ( element == 0 )  // This is the group length of the group
2114    {  
2115       if ( length == 4 )
2116       {
2117          return true;
2118       }
2119       else 
2120       {
2121          // Allthough this should never happen, still some images have a
2122          // corrupted group length [e.g. have a glance at offset x(8336) of
2123          // gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm].
2124          // Since for dicom compliant and well behaved headers, the present
2125          // test is useless (and might even look a bit paranoid), when we
2126          // encounter such an ill-formed image, we simply display a warning
2127          // message and proceed on parsing (while crossing fingers).
2128          std::ostringstream s;
2129          int filePosition = ftell(Fp);
2130          s << "Erroneous Group Length element length  on : (" \
2131            << std::hex << group << " , " << element 
2132            << ") -before- position x(" << filePosition << ")"
2133            << "lgt : " << length;
2134          dbg.Verbose(0, "gdcmDocument::IsDocEntryAnInteger", s.str().c_str() );
2135       }
2136    }
2137
2138    if ( vr == "UL" || vr == "US" || vr == "SL" || vr == "SS" )
2139    {
2140       return true;
2141    }
2142    
2143    return false;
2144 }
2145
2146 /**
2147  * \brief  Find the Length till the next sequence delimiter
2148  * \warning NOT end user intended method !
2149  * @return 
2150  */
2151
2152 uint32_t gdcmDocument::FindDocEntryLengthOB()
2153 {
2154    // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
2155    long positionOnEntry = ftell(Fp);
2156    bool foundSequenceDelimiter = false;
2157    uint32_t totalLength = 0;
2158
2159    while ( !foundSequenceDelimiter )
2160    {
2161       uint16_t g = ReadInt16();
2162       uint16_t n = ReadInt16();   
2163       if ( errno == 1 )
2164       {
2165          return 0;
2166       }
2167
2168       // We have to decount the group and element we just read
2169       totalLength += 4;
2170      
2171       if ( g != 0xfffe || ( n != 0xe0dd && n != 0xe000 ) )
2172       {
2173          dbg.Verbose(1, "gdcmDocument::FindLengthOB: neither an Item tag "
2174                         "nor a Sequence delimiter tag."); 
2175          fseek(Fp, positionOnEntry, SEEK_SET);
2176          errno = 1;
2177          return 0;
2178       }
2179
2180       if ( n == 0xe0dd )
2181       {
2182          foundSequenceDelimiter = true;
2183       }
2184
2185       uint32_t itemLength = ReadInt32();
2186       // We add 4 bytes since we just read the ItemLength with ReadInt32
2187       totalLength += itemLength + 4;
2188       SkipBytes(itemLength);
2189       
2190       if ( foundSequenceDelimiter )
2191       {
2192          break;
2193       }
2194    }
2195    fseek(Fp, positionOnEntry, SEEK_SET);
2196    return totalLength;
2197 }
2198
2199 /**
2200  * \brief Reads a supposed to be 16 Bits integer
2201  *       (swaps it depending on processor endianity) 
2202  * @return read value
2203  */
2204 uint16_t gdcmDocument::ReadInt16()
2205 {
2206    uint16_t g;
2207    size_t item_read = fread (&g, (size_t)2,(size_t)1, Fp);
2208    if ( item_read != 1 )
2209    {
2210       if( ferror(Fp) )
2211       {
2212          dbg.Verbose(0, "gdcmDocument::ReadInt16", " File Error");
2213       }
2214       errno = 1;
2215       return 0;
2216    }
2217    errno = 0;
2218    g = SwapShort(g); 
2219    return g;
2220 }
2221
2222 /**
2223  * \brief  Reads a supposed to be 32 Bits integer
2224  *         (swaps it depending on processor endianity)  
2225  * @return read value
2226  */
2227 uint32_t gdcmDocument::ReadInt32()
2228 {
2229    uint32_t g;
2230    size_t item_read = fread (&g, (size_t)4,(size_t)1, Fp);
2231    if ( item_read != 1 )
2232    {
2233       if( ferror(Fp) )
2234       {
2235          dbg.Verbose(0, "gdcmDocument::ReadInt32", " File Error");
2236       }
2237       errno = 1;
2238       return 0;
2239    }
2240    errno = 0;
2241    g = SwapLong(g);
2242    return g;
2243 }
2244
2245 /**
2246  * \brief skips bytes inside the source file 
2247  * \warning NOT end user intended method !
2248  * @return 
2249  */
2250 void gdcmDocument::SkipBytes(uint32_t nBytes)
2251 {
2252    //FIXME don't dump the returned value
2253    (void)fseek(Fp, (long)nBytes, SEEK_CUR);
2254 }
2255
2256 /**
2257  * \brief Loads all the needed Dictionaries
2258  * \warning NOT end user intended method !   
2259  */
2260 void gdcmDocument::Initialise() 
2261 {
2262    RefPubDict = gdcmGlobal::GetDicts()->GetDefaultPubDict();
2263    RefShaDict = NULL;
2264 }
2265
2266 /**
2267  * \brief   Discover what the swap code is (among little endian, big endian,
2268  *          bad little endian, bad big endian).
2269  *          sw is set
2270  * @return false when we are absolutely sure 
2271  *               it's neither ACR-NEMA nor DICOM
2272  *         true  when we hope ours assuptions are OK
2273  */
2274 bool gdcmDocument::CheckSwap()
2275 {
2276    // The only guaranted way of finding the swap code is to find a
2277    // group tag since we know it's length has to be of four bytes i.e.
2278    // 0x00000004. Finding the swap code in then straigthforward. Trouble
2279    // occurs when we can't find such group...
2280    
2281    uint32_t  x = 4;  // x : for ntohs
2282    bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
2283    uint32_t  s32;
2284    uint16_t  s16;
2285        
2286    char deb[HEADER_LENGTH_TO_READ];
2287     
2288    // First, compare HostByteOrder and NetworkByteOrder in order to
2289    // determine if we shall need to swap bytes (i.e. the Endian type).
2290    if ( x == ntohs(x) )
2291    {
2292       net2host = true;
2293    }
2294    else
2295    {
2296       net2host = false;
2297    }
2298          
2299    // The easiest case is the one of a DICOM header, since it possesses a
2300    // file preamble where it suffice to look for the string "DICM".
2301    int lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, Fp);
2302    (void)lgrLue;  //FIXME not used
2303    
2304    char *entCur = deb + 128;
2305    if( memcmp(entCur, "DICM", (size_t)4) == 0 )
2306    {
2307       dbg.Verbose(1, "gdcmDocument::CheckSwap:", "looks like DICOM Version3");
2308       
2309       // Next, determine the value representation (VR). Let's skip to the
2310       // first element (0002, 0000) and check there if we find "UL" 
2311       // - or "OB" if the 1st one is (0002,0001) -,
2312       // in which case we (almost) know it is explicit VR.
2313       // WARNING: if it happens to be implicit VR then what we will read
2314       // is the length of the group. If this ascii representation of this
2315       // length happens to be "UL" then we shall believe it is explicit VR.
2316       // FIXME: in order to fix the above warning, we could read the next
2317       // element value (or a couple of elements values) in order to make
2318       // sure we are not commiting a big mistake.
2319       // We need to skip :
2320       // * the 128 bytes of File Preamble (often padded with zeroes),
2321       // * the 4 bytes of "DICM" string,
2322       // * the 4 bytes of the first tag (0002, 0000),or (0002, 0001)
2323       // i.e. a total of  136 bytes.
2324       entCur = deb + 136;
2325      
2326       // FIXME : FIXME:
2327       // Sometimes (see : gdcmData/icone.dcm) group 0x0002 *is* Explicit VR,
2328       // but elem 0002,0010 (Transfert Syntax) tells us the file is
2329       // *Implicit* VR.  -and it is !- 
2330       
2331       if( memcmp(entCur, "UL", (size_t)2) == 0 ||
2332           memcmp(entCur, "OB", (size_t)2) == 0 ||
2333           memcmp(entCur, "UI", (size_t)2) == 0 ||
2334           memcmp(entCur, "CS", (size_t)2) == 0 )  // CS, to remove later
2335                                                     // when Write DCM *adds*
2336       // FIXME
2337       // Use gdcmDocument::dicom_vr to test all the possibilities
2338       // instead of just checking for UL, OB and UI !? group 0000 
2339       {
2340          Filetype = gdcmExplicitVR;
2341          dbg.Verbose(1, "gdcmDocument::CheckSwap:",
2342                      "explicit Value Representation");
2343       } 
2344       else 
2345       {
2346          Filetype = gdcmImplicitVR;
2347          dbg.Verbose(1, "gdcmDocument::CheckSwap:",
2348                      "not an explicit Value Representation");
2349       }
2350       
2351       if ( net2host )
2352       {
2353          SwapCode = 4321;
2354          dbg.Verbose(1, "gdcmDocument::CheckSwap:",
2355                         "HostByteOrder != NetworkByteOrder");
2356       }
2357       else 
2358       {
2359          SwapCode = 0;
2360          dbg.Verbose(1, "gdcmDocument::CheckSwap:",
2361                         "HostByteOrder = NetworkByteOrder");
2362       }
2363       
2364       // Position the file position indicator at first tag (i.e.
2365       // after the file preamble and the "DICM" string).
2366       rewind(Fp);
2367       fseek (Fp, 132L, SEEK_SET);
2368       return true;
2369    } // End of DicomV3
2370
2371    // Alas, this is not a DicomV3 file and whatever happens there is no file
2372    // preamble. We can reset the file position indicator to where the data
2373    // is (i.e. the beginning of the file).
2374    dbg.Verbose(1, "gdcmDocument::CheckSwap:", "not a DICOM Version3 file");
2375    rewind(Fp);
2376
2377    // Our next best chance would be to be considering a 'clean' ACR/NEMA file.
2378    // By clean we mean that the length of the first tag is written down.
2379    // If this is the case and since the length of the first group HAS to be
2380    // four (bytes), then determining the proper swap code is straightforward.
2381
2382    entCur = deb + 4;
2383    // We assume the array of char we are considering contains the binary
2384    // representation of a 32 bits integer. Hence the following dirty
2385    // trick :
2386    s32 = *((uint32_t *)(entCur));
2387       
2388    switch( s32 )
2389    {
2390       case 0x00040000 :
2391          SwapCode = 3412;
2392          Filetype = gdcmACR;
2393          return true;
2394       case 0x04000000 :
2395          SwapCode = 4321;
2396          Filetype = gdcmACR;
2397          return true;
2398       case 0x00000400 :
2399          SwapCode = 2143;
2400          Filetype = gdcmACR;
2401          return true;
2402       case 0x00000004 :
2403          SwapCode = 0;
2404          Filetype = gdcmACR;
2405          return true;
2406       default :
2407          // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file.
2408          // It is time for despaired wild guesses. 
2409          // So, let's check if this file wouldn't happen to be 'dirty' ACR/NEMA,
2410          //  i.e. the 'group length' element is not present :     
2411          
2412          //  check the supposed to be 'group number'
2413          //  0x0002 or 0x0004 or 0x0008
2414          //  to determine ' SwapCode' value .
2415          //  Only 0 or 4321 will be possible 
2416          //  (no oportunity to check for the formerly well known
2417          //  ACR-NEMA 'Bad Big Endian' or 'Bad Little Endian' 
2418          //  if unsuccessfull (i.e. neither 0x0002 nor 0x0200 etc -4, 8-) 
2419          //  the file IS NOT ACR-NEMA nor DICOM V3
2420          //  Find a trick to tell it the caller...
2421       
2422          s16 = *((uint16_t *)(deb));
2423       
2424          switch ( s16 )
2425          {
2426             case 0x0002 :
2427             case 0x0004 :
2428             case 0x0008 :      
2429                SwapCode = 0;
2430                Filetype = gdcmACR;
2431                return true;
2432             case 0x0200 :
2433             case 0x0400 :
2434             case 0x0800 : 
2435                SwapCode = 4321;
2436                Filetype = gdcmACR;
2437                return true;
2438             default :
2439                dbg.Verbose(0, "gdcmDocument::CheckSwap:",
2440                      "ACR/NEMA unfound swap info (Really hopeless !)"); 
2441                Filetype = gdcmUnknown;     
2442                return false;
2443          }
2444          // Then the only info we have is the net2host one.
2445          //if (! net2host )
2446          //   SwapCode = 0;
2447          //else
2448          //  SwapCode = 4321;
2449          //return;
2450    }
2451 }
2452
2453 /**
2454  * \brief Restore the unproperly loaded values i.e. the group, the element
2455  *        and the dictionary entry depending on them. 
2456  */
2457 void gdcmDocument::SwitchSwapToBigEndian() 
2458 {
2459    dbg.Verbose(1, "gdcmDocument::SwitchSwapToBigEndian",
2460                   "Switching to BigEndian mode.");
2461    if ( SwapCode == 0    ) 
2462    {
2463       SwapCode = 4321;
2464    }
2465    else if ( SwapCode == 4321 ) 
2466    {
2467       SwapCode = 0;
2468    }
2469    else if ( SwapCode == 3412 ) 
2470    {
2471       SwapCode = 2143;
2472    }
2473    else if ( SwapCode == 2143 )
2474    {
2475       SwapCode = 3412;
2476    }
2477 }
2478
2479 /**
2480  * \brief  during parsing, Header Elements too long are not loaded in memory 
2481  * @param NewSize
2482  */
2483 void gdcmDocument::SetMaxSizeLoadEntry(long newSize) 
2484 {
2485    if ( newSize < 0 )
2486    {
2487       return;
2488    }
2489    if ((uint32_t)newSize >= (uint32_t)0xffffffff )
2490    {
2491       MaxSizeLoadEntry = 0xffffffff;
2492       return;
2493    }
2494    MaxSizeLoadEntry = newSize;
2495 }
2496
2497
2498 /**
2499  * \brief Header Elements too long will not be printed
2500  * \todo  See comments of \ref gdcmDocument::MAX_SIZE_PRINT_ELEMENT_VALUE 
2501  * @param NewSize
2502  */
2503 void gdcmDocument::SetMaxSizePrintEntry(long newSize) 
2504 {
2505    //DOH !! This is exactly SetMaxSizeLoadEntry FIXME FIXME
2506    if ( newSize < 0 )
2507    {
2508       return;
2509    }
2510    if ((uint32_t)newSize >= (uint32_t)0xffffffff )
2511    {
2512       MaxSizePrintEntry = 0xffffffff;
2513       return;
2514    }
2515    MaxSizePrintEntry = newSize;
2516 }
2517
2518
2519
2520 /**
2521  * \brief   Read the next tag but WITHOUT loading it's value
2522  *          (read the 'Group Number', the 'Element Number',
2523  *           gets the Dict Entry
2524  *          gets the VR, gets the length, gets the offset value)
2525  * @return  On succes the newly created DocEntry, NULL on failure.      
2526  */
2527 gdcmDocEntry *gdcmDocument::ReadNextDocEntry()
2528 {
2529    uint16_t g = ReadInt16();
2530    uint16_t n = ReadInt16();
2531
2532    if (errno == 1)
2533    {
2534       // We reached the EOF (or an error occured) therefore 
2535       // header parsing has to be considered as finished.
2536       return 0;
2537    }
2538    gdcmDocEntry *newEntry = NewDocEntryByNumber(g, n);
2539
2540    FindDocEntryVR(newEntry);
2541    FindDocEntryLength(newEntry);
2542
2543    if (errno == 1)
2544    {
2545       // Call it quits
2546       delete newEntry;
2547       return 0;
2548    }
2549    newEntry->SetOffset(ftell(Fp));  
2550
2551    return newEntry;
2552 }
2553
2554
2555 /**
2556  * \brief   Generate a free gdcmTagKey i.e. a gdcmTagKey that is not present
2557  *          in the TagHt dictionary.
2558  * @param   group The generated tag must belong to this group.  
2559  * @return  The element of tag with given group which is fee.
2560  */
2561 uint32_t gdcmDocument::GenerateFreeTagKeyInGroup(uint16_t group) 
2562 {
2563    for (uint32_t elem = 0; elem < UINT32_MAX; elem++) 
2564    {
2565       gdcmTagKey key = gdcmDictEntry::TranslateToKey(group, elem);
2566       if (TagHT.count(key) == 0)
2567       {
2568          return elem;
2569       }
2570    }
2571    return UINT32_MAX;
2572 }
2573
2574 /**
2575  * \brief   Assuming the internal file pointer \ref gdcmDocument::fp 
2576  *          is placed at the beginning of a tag check whether this
2577  *          tag is (TestGroup, TestElement).
2578  * \warning On success the internal file pointer \ref gdcmDocument::fp
2579  *          is modified to point after the tag.
2580  *          On failure (i.e. when the tag wasn't the expected tag
2581  *          (TestGroup, TestElement) the internal file pointer
2582  *          \ref gdcmDocument::fp is restored to it's original position.
2583  * @param   TestGroup   The expected group of the tag.
2584  * @param   TestElement The expected Element of the tag.
2585  * @return  True on success, false otherwise.
2586  */
2587 bool gdcmDocument::ReadTag(uint16_t testGroup, uint16_t testElement)
2588 {
2589    long positionOnEntry = ftell(Fp);
2590    long currentPosition = ftell(Fp);          // On debugging purposes
2591
2592    //// Read the Item Tag group and element, and make
2593    // sure they are what we expected:
2594    uint16_t itemTagGroup   = ReadInt16();
2595    uint16_t itemTagElement = ReadInt16();
2596    if ( itemTagGroup != testGroup || itemTagElement != testElement )
2597    {
2598       std::ostringstream s;
2599       s << "   We should have found tag (";
2600       s << std::hex << testGroup << "," << testElement << ")" << std::endl;
2601       s << "   but instead we encountered tag (";
2602       s << std::hex << itemTagGroup << "," << itemTagElement << ")"
2603         << std::endl;
2604       s << "  at address: " << (unsigned)currentPosition << std::endl;
2605       dbg.Verbose(0, "gdcmDocument::ReadItemTagLength: wrong Item Tag found:");
2606       dbg.Verbose(0, s.str().c_str());
2607       fseek(Fp, positionOnEntry, SEEK_SET);
2608
2609       return false;
2610    }
2611    return true;
2612 }
2613
2614 /**
2615  * \brief   Assuming the internal file pointer \ref gdcmDocument::fp 
2616  *          is placed at the beginning of a tag (TestGroup, TestElement),
2617  *          read the length associated to the Tag.
2618  * \warning On success the internal file pointer \ref gdcmDocument::fp
2619  *          is modified to point after the tag and it's length.
2620  *          On failure (i.e. when the tag wasn't the expected tag
2621  *          (TestGroup, TestElement) the internal file pointer
2622  *          \ref gdcmDocument::fp is restored to it's original position.
2623  * @param   TestGroup   The expected group of the tag.
2624  * @param   TestElement The expected Element of the tag.
2625  * @return  On success returns the length associated to the tag. On failure
2626  *          returns 0.
2627  */
2628 uint32_t gdcmDocument::ReadTagLength(uint16_t testGroup, uint16_t testElement)
2629 {
2630    long positionOnEntry = ftell(Fp);
2631    (void)positionOnEntry;
2632
2633    if ( !ReadTag(testGroup, testElement) )
2634    {
2635       return 0;
2636    }
2637                                                                                 
2638    //// Then read the associated Item Length
2639    long currentPosition = ftell(Fp);
2640    uint32_t itemLength  = ReadInt32();
2641    {
2642       std::ostringstream s;
2643       s << "Basic Item Length is: "
2644         << itemLength << std::endl;
2645       s << "  at address: " << (unsigned)currentPosition << std::endl;
2646       dbg.Verbose(0, "gdcmDocument::ReadItemTagLength: ", s.str().c_str());
2647    }
2648    return itemLength;
2649 }
2650
2651 /**
2652  * \brief   Parse pixel data from disk for multi-fragment Jpeg/Rle files
2653  *          No other way so 'skip' the Data
2654  *
2655  */
2656 void gdcmDocument::Parse7FE0 ()
2657 {
2658    gdcmDocEntry* element = GetDocEntryByNumber(0x0002, 0x0010);
2659    if ( !element )
2660    {
2661       // Should warn user FIXME
2662       return;
2663    }
2664       
2665    if (   IsImplicitVRLittleEndianTransferSyntax()
2666        || IsExplicitVRLittleEndianTransferSyntax()
2667        || IsExplicitVRBigEndianTransferSyntax() /// \todo 1.2.2 ??? A verifier !
2668        || IsDeflatedExplicitVRLittleEndianTransferSyntax() )
2669    {
2670       return;
2671    }
2672
2673    // ---------------- for Parsing : Position on begining of Jpeg/RLE Pixels 
2674
2675    //// Read the Basic Offset Table Item Tag length...
2676    uint32_t itemLength = ReadTagLength(0xfffe, 0xe000);
2677
2678    //// ... and then read length[s] itself[themselves]. We don't use
2679    // the values read (BTW  what is the purpous of those lengths ?)
2680    if ( itemLength != 0 )
2681    {
2682       // BTW, what is the purpous of those length anyhow !? 
2683       char* basicOffsetTableItemValue = new char[itemLength + 1];
2684       fread(basicOffsetTableItemValue, itemLength, 1, Fp);
2685
2686       for (unsigned int i=0; i < itemLength; i += 4 )
2687       {
2688          uint32_t individualLength = str2num(&basicOffsetTableItemValue[i],uint32_t);
2689          std::ostringstream s;
2690          s << "   Read one length: ";
2691          s << std::hex << individualLength << std::endl;
2692          dbg.Verbose(0, "gdcmDocument::Parse7FE0: ", s.str().c_str());
2693       }
2694       delete[] basicOffsetTableItemValue;
2695    }
2696
2697    if ( ! IsRLELossLessTransferSyntax() )
2698    {
2699       // JPEG Image
2700       
2701       //// We then skip (not reading them) all the fragments of images:
2702       while ( (itemLength = ReadTagLength(0xfffe, 0xe000)) )
2703       {
2704          SkipBytes(itemLength);
2705       }
2706    }
2707    else
2708    {
2709       // RLE Image
2710       long ftellRes;
2711       long rleSegmentLength[15], fragmentLength;
2712
2713       // While we find some items:
2714       while ( (fragmentLength = ReadTagLength(0xfffe, 0xe000)) )
2715       { 
2716          // Parse fragments of the current Fragment (Frame)    
2717          //------------------ scanning (not reading) fragment pixels
2718          uint32_t nbRleSegments = ReadInt32();
2719  
2720          //// Reading RLE Segments Offset Table
2721          uint32_t rleSegmentOffsetTable[15];
2722          for(int k=1; k<=15; k++)
2723          {
2724             ftellRes = ftell(Fp);
2725             rleSegmentOffsetTable[k] = ReadInt32();
2726          }
2727
2728          // skipping (not reading) RLE Segments
2729          if ( nbRleSegments > 1)
2730          {
2731             for(unsigned int k = 1; k <= nbRleSegments-1; k++)
2732             {
2733                 rleSegmentLength[k] =  rleSegmentOffsetTable[k+1]
2734                                      - rleSegmentOffsetTable[k];
2735                 ftellRes = ftell(Fp);
2736                 SkipBytes(rleSegmentLength[k]);
2737              }
2738           }
2739
2740           rleSegmentLength[nbRleSegments] = fragmentLength 
2741                                           - rleSegmentOffsetTable[nbRleSegments];
2742           ftellRes = ftell(Fp);
2743           SkipBytes(rleSegmentLength[nbRleSegments]);
2744       }
2745
2746       // Make sure that at the end of the item we encounter a 'Sequence
2747       // Delimiter Item':
2748       if ( !ReadTag(0xfffe, 0xe0dd) )
2749       {
2750          dbg.Verbose(0, "gdcmDocument::Parse7FE0: no sequence delimiter item");
2751          dbg.Verbose(0, "    at end of RLE item sequence");
2752       }
2753    }
2754 }
2755
2756
2757
2758 /**
2759  * \brief   Compares two documents, according to \ref gdcmDicomDir rules
2760  * \warning Does NOT work with ACR-NEMA files
2761  * \todo    Find a trick to solve the pb (use RET fields ?)
2762  * @param   document
2763  * @return  true if 'smaller'
2764  */
2765 bool gdcmDocument::operator<(gdcmDocument &document)
2766 {
2767    // Patient Name
2768    std::string s1 = GetEntryByNumber(0x0010,0x0010);
2769    std::string s2 = document.GetEntryByNumber(0x0010,0x0010);
2770    if(s1 < s2)
2771    {
2772       return true;
2773    }
2774    else if(s1 > s2)
2775    {
2776       return false;
2777    }
2778    else
2779    {
2780       // Patient ID
2781       s1 = GetEntryByNumber(0x0010,0x0020);
2782       s2 = document.GetEntryByNumber(0x0010,0x0020);
2783       if ( s1 < s2 )
2784       {
2785          return true;
2786       }
2787       else if ( s1 > s2 )
2788       {
2789          return true;
2790       }
2791       else
2792       {
2793          // Study Instance UID
2794          s1 = GetEntryByNumber(0x0020,0x000d);
2795          s2 = document.GetEntryByNumber(0x0020,0x000d);
2796          if ( s1 < s2 )
2797          {
2798             return true;
2799          }
2800          else if( s1 > s2 )
2801          {
2802             return false;
2803          }
2804          else
2805          {
2806             // Serie Instance UID
2807             s1 = GetEntryByNumber(0x0020,0x000e);
2808             s2 = document.GetEntryByNumber(0x0020,0x000e);
2809             if ( s1 < s2 )
2810             {
2811                return true;
2812             }
2813             else if( s1 > s2 )
2814             {
2815                return false;
2816             }
2817          }
2818       }
2819    }
2820    return false;
2821 }
2822
2823
2824 //-----------------------------------------------------------------------------