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