]> Creatis software - gdcm.git/blob - src/gdcmDocument.cxx
update ChangeLog
[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 09:51:02 $
7   Version:   $Revision: 1.37 $
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
825    // Non even content must be padded with a space (020H).
826    if((content.length())%2)
827       content = content + '\0';
828       
829    ValEntry->SetValue(content);
830    
831    // Integers have a special treatement for their length:
832    VRKey vr = ValEntry->GetVR();
833    if( (vr == "US") || (vr == "SS") ) 
834       ValEntry->SetLength(2);
835    else if( (vr == "UL") || (vr == "SL") )
836       ValEntry->SetLength(4);
837    else
838       ValEntry->SetLength(content.length());
839
840    return true;
841
842
843 /**
844  * \brief   Accesses an existing gdcmDocEntry (i.e. a Dicom Element)
845  *          through it's (group, element) and modifies it's content with
846  *          the given value.
847  * @param   content new value (void *) to substitute with
848  * @param   group     group number of the Dicom Element to modify
849  * @param   element element number of the Dicom Element to modify
850  */
851 bool gdcmDocument::SetEntryByNumber(void *content,
852                                   int lgth, 
853                                   guint16 group,
854                                   guint16 element) 
855 {
856    (void)lgth;  //not used
857    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
858    if ( ! tagHT.count(key))
859       return false;
860
861 /* Hope Binray field length is never wrong    
862    if(lgth%2) // Non even length are padded with a space (020H).
863    {  
864       lgth++;
865       //content = content + '\0'; // fing a trick to enlarge a binary field?
866    }
867 */      
868    gdcmBinEntry * a;
869    a = (gdcmBinEntry *)tagHT[key];           
870    a->SetVoidArea(content);  
871    //a->SetLength(lgth);  // ???  
872    return true;
873
874
875 /**
876  * \brief   Accesses an existing gdcmDocEntry (i.e. a Dicom Element)
877  *          in the PubDocEntrySet of this instance
878  *          through it's (group, element) and modifies it's length with
879  *          the given value.
880  * \warning Use with extreme caution.
881  * @param l new length to substitute with
882  * @param group     group number of the Entry to modify
883  * @param element element number of the Entry to modify
884  * @return  true on success, false otherwise.
885  */
886 bool gdcmDocument::SetEntryLengthByNumber(guint32 l, 
887                                         guint16 group, 
888                                         guint16 element) 
889 {
890    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
891    if ( ! tagHT.count(key))
892       return false;
893    if (l%2) l++; // length must be even
894    ( ((tagHT.equal_range(key)).first)->second )->SetLength(l); 
895
896    return true ;
897 }
898
899 /**
900  * \brief   Gets (from Header) the offset  of a 'non string' element value 
901  *          (LoadElementValues has already be executed)
902  * @param Group   group number of the Entry 
903  * @param Elem  element number of the Entry
904  * @return File Offset of the Element Value 
905  */
906 size_t gdcmDocument::GetEntryOffsetByNumber(guint16 Group, guint16 Elem) 
907 {
908    gdcmDocEntry* Entry = GetDocEntryByNumber(Group, Elem);
909    if (!Entry) 
910    {
911       dbg.Verbose(1, "gdcmDocument::GetDocEntryByNumber: no entry present.");
912       return (size_t)0;
913    }
914    return Entry->GetOffset();
915 }
916
917 /**
918  * \brief   Gets (from Header) a 'non string' element value 
919  *          (LoadElementValues has already be executed)  
920  * @param Group   group number of the Entry 
921  * @param Elem  element number of the Entry
922  * @return Pointer to the 'non string' area
923  */
924 void * gdcmDocument::GetEntryVoidAreaByNumber(guint16 Group, guint16 Elem) 
925 {
926    gdcmDocEntry* Entry = GetDocEntryByNumber(Group, Elem);
927    if (!Entry) 
928    {
929       dbg.Verbose(1, "gdcmDocument::GetDocEntryByNumber: no entry");
930       return (NULL);
931    }
932    return ((gdcmBinEntry *)Entry)->GetVoidArea();
933 }
934
935 /**
936  * \brief         Loads (from disk) the element content 
937  *                when a string is not suitable
938  * @param Group   group number of the Entry 
939  * @param Elem  element number of the Entry
940  */
941 void *gdcmDocument::LoadEntryVoidArea(guint16 Group, guint16 Elem) 
942 {
943    gdcmDocEntry * Element= GetDocEntryByNumber(Group, Elem);
944    if ( !Element )
945       return NULL;
946    size_t o =(size_t)Element->GetOffset();
947    fseek(fp, o, SEEK_SET);
948    size_t l = Element->GetLength();
949    char* a = new char[l];
950    if(!a) {
951       dbg.Verbose(0, "gdcmDocument::LoadEntryVoidArea cannot allocate a");
952       return NULL;
953    }
954    SetEntryVoidAreaByNumber(a, Group, Elem);
955    /// \todo check the result 
956    size_t l2 = fread(a, 1, l ,fp);
957    if(l != l2) 
958    {
959       delete[] a;
960       return NULL;
961    }
962    return a;  
963 }
964 /**
965  * \brief         Loads (from disk) the element content 
966  *                when a string is not suitable
967  * @param Element  Entry whose voidArea is going to be loaded
968  */
969 void *gdcmDocument::LoadEntryVoidArea(gdcmBinEntry *Element) 
970 {
971    size_t o =(size_t)Element->GetOffset();
972    fseek(fp, o, SEEK_SET);
973    size_t l = Element->GetLength();
974    char* a = new char[l];
975    if(!a) {
976       dbg.Verbose(0, "gdcmDocument::LoadEntryVoidArea cannot allocate a");
977       return NULL;
978    }
979    Element->SetVoidArea((void *)a);
980    /// \todo check the result 
981    size_t l2 = fread(a, 1, l ,fp);
982    if(l != l2) 
983    {
984       delete[] a;
985       return NULL;
986    }
987    return a;  
988 }
989
990 /**
991  * \brief   Sets a 'non string' value to a given Dicom Element
992  * @param   area area containing the 'non string' value
993  * @param   group     Group number of the searched Dicom Element 
994  * @param   element Element number of the searched Dicom Element 
995  * @return  
996  */
997 bool gdcmDocument::SetEntryVoidAreaByNumber(void * area,
998                                           guint16 group, 
999                                           guint16 element) 
1000 {
1001    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
1002    if ( ! tagHT.count(key))
1003       return false;
1004       // This was for multimap ?
1005     (( gdcmBinEntry *)( ((tagHT.equal_range(key)).first)->second ))->SetVoidArea(area);
1006       
1007    return true;
1008 }
1009
1010 /**
1011  * \brief   Update the entries with the shadow dictionary. 
1012  *          Only non even entries are analyzed       
1013  */
1014 void gdcmDocument::UpdateShaEntries(void) {
1015    //gdcmDictEntry *entry;
1016    std::string vr;
1017    
1018    /// \todo TODO : still any use to explore recursively the whole structure?
1019 /*
1020    for(ListTag::iterator it=listEntries.begin();
1021        it!=listEntries.end();
1022        ++it)
1023    {
1024       // Odd group => from public dictionary
1025       if((*it)->GetGroup()%2==0)
1026          continue;
1027
1028       // Peer group => search the corresponding dict entry
1029       if(RefShaDict)
1030          entry=RefShaDict->GetDictEntryByNumber((*it)->GetGroup(),(*it)->GetElement());
1031       else
1032          entry=NULL;
1033
1034       if((*it)->IsImplicitVR())
1035          vr="Implicit";
1036       else
1037          vr=(*it)->GetVR();
1038
1039       (*it)->SetValue(GetDocEntryUnvalue(*it));  // to go on compiling
1040       if(entry){
1041          // Set the new entry and the new value
1042          (*it)->SetDictEntry(entry);
1043          CheckDocEntryVR(*it,vr);
1044
1045          (*it)->SetValue(GetDocEntryValue(*it));    // to go on compiling
1046  
1047       }
1048       else
1049       {
1050          // Remove precedent value transformation
1051          (*it)->SetDictEntry(NewVirtualDictEntry((*it)->GetGroup(),(*it)->GetElement(),vr));
1052       }
1053    }
1054 */   
1055 }
1056
1057 /**
1058  * \brief   Searches within the Header Entries for a Dicom Element of
1059  *          a given tag.
1060  * @param   tagName name of the searched Dicom Element.
1061  * @return  Corresponding Dicom Element when it exists, and NULL
1062  *          otherwise.
1063  */
1064  gdcmDocEntry *gdcmDocument::GetDocEntryByName(std::string tagName) {
1065    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
1066    if( dictEntry == NULL)
1067       return NULL;
1068
1069   return(GetDocEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement()));
1070 }
1071
1072 /**
1073  * \brief  retrieves a Dicom Element (the first one) using (group, element)
1074  * \warning (group, element) IS NOT an identifier inside the Dicom Header
1075  *           if you think it's NOT UNIQUE, check the count number
1076  *           and use iterators to retrieve ALL the Dicoms Elements within
1077  *           a given couple (group, element)
1078  * @param   group Group number of the searched Dicom Element 
1079  * @param   element Element number of the searched Dicom Element 
1080  * @return  
1081  */
1082 gdcmDocEntry* gdcmDocument::GetDocEntryByNumber(guint16 group, guint16 element) 
1083 {
1084    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
1085    if ( ! tagHT.count(key))
1086       return NULL;
1087    return tagHT.find(key)->second;
1088 }
1089
1090 /**
1091  * \brief  Same as \ref gdcmDocument::GetDocEntryByNumber except it only
1092  *         returns a result when the corresponding entry is of type
1093  *         ValEntry.
1094  * @return When present, the corresponding ValEntry. 
1095  */
1096 gdcmValEntry* gdcmDocument::GetValEntryByNumber(guint16 group, guint16 element)
1097 {
1098   gdcmDocEntry* CurrentEntry = GetDocEntryByNumber(group, element);
1099   if (! CurrentEntry)
1100      return (gdcmValEntry*)0;
1101   if ( gdcmValEntry* ValEntry = dynamic_cast<gdcmValEntry*>(CurrentEntry) )
1102   {
1103      return ValEntry;
1104   }
1105   dbg.Verbose(0, "gdcmDocument::GetValEntryByNumber: unfound ValEntry.");
1106   return (gdcmValEntry*)0;
1107 }
1108
1109 /**
1110  * \brief         Loads the element while preserving the current
1111  *                underlying file position indicator as opposed to
1112  *                to LoadDocEntry that modifies it.
1113  * @param entry   Header Entry whose value shall be loaded. 
1114  * @return  
1115  */
1116 void gdcmDocument::LoadDocEntrySafe(gdcmDocEntry * entry) {
1117    long PositionOnEntry = ftell(fp);
1118    LoadDocEntry(entry);
1119    fseek(fp, PositionOnEntry, SEEK_SET);
1120 }
1121
1122 /**
1123  * \brief   Swaps back the bytes of 4-byte long integer accordingly to
1124  *          processor order.
1125  * @return  The properly swaped 32 bits integer.
1126  */
1127 guint32 gdcmDocument::SwapLong(guint32 a) {
1128    switch (sw) {
1129       case    0 :
1130          break;
1131       case 4321 :
1132          a=( ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000) | 
1133              ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
1134          break;
1135    
1136       case 3412 :
1137          a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
1138          break;
1139    
1140       case 2143 :
1141          a=( ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
1142          break;
1143       default :
1144          std::cout << "swapCode= " << sw << std::endl;
1145          dbg.Error(" gdcmDocument::SwapLong : unset swap code");
1146          a=0;
1147    }
1148    return a;
1149
1150
1151 /**
1152  * \brief   Unswaps back the bytes of 4-byte long integer accordingly to
1153  *          processor order.
1154  * @return  The properly unswaped 32 bits integer.
1155  */
1156 guint32 gdcmDocument::UnswapLong(guint32 a) {
1157    return SwapLong(a);
1158 }
1159
1160 /**
1161  * \brief   Swaps the bytes so they agree with the processor order
1162  * @return  The properly swaped 16 bits integer.
1163  */
1164 guint16 gdcmDocument::SwapShort(guint16 a) {
1165    if ( (sw==4321)  || (sw==2143) )
1166       a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff));
1167    return a;
1168 }
1169
1170 /**
1171  * \brief   Unswaps the bytes so they agree with the processor order
1172  * @return  The properly unswaped 16 bits integer.
1173  */
1174 guint16 gdcmDocument::UnswapShort(guint16 a) {
1175    return SwapShort(a);
1176 }
1177
1178 //-----------------------------------------------------------------------------
1179 // Private
1180
1181 /**
1182  * \brief   Parses a DocEntrySet (Zero-level DocEntries or SQ Item DocEntries)
1183  * @return  length of the parsed set. 
1184  */ 
1185
1186 long gdcmDocument::ParseDES(gdcmDocEntrySet *set, long offset, long l_max, bool delim_mode) {
1187
1188    gdcmDocEntry *NewDocEntry = (gdcmDocEntry *)0;
1189    gdcmValEntry *NewValEntry = (gdcmValEntry *)0;
1190    gdcmBinEntry *bn;   
1191    gdcmSeqEntry *sq;
1192    VRKey vr;
1193    unsigned long l = 0;
1194    int depth; 
1195    
1196    depth = set->GetDepthLevel();     
1197    while (true) { 
1198    
1199       if ( !delim_mode && ftell(fp)-offset >= l_max) { 
1200          break;  
1201       }
1202       NewDocEntry = ReadNextDocEntry( );
1203       if (!NewDocEntry)
1204          break;
1205      // NewDocEntry->Print(); cout << endl; //JPR
1206       vr = NewDocEntry->GetVR();
1207       if (vr!="SQ")
1208       {
1209                
1210          if ( gdcmGlobal::GetVR()->IsVROfGdcmStringRepresentable(vr) )
1211          {
1212             /////// ValEntry
1213             NewValEntry = new gdcmValEntry(NewDocEntry->GetDictEntry());
1214             NewValEntry->Copy(NewDocEntry);
1215             NewValEntry->SetDepthLevel(depth);
1216             set->AddEntry(NewValEntry);
1217             LoadDocEntry(NewValEntry);
1218             if (NewValEntry->isItemDelimitor())
1219                break;
1220             if ( !delim_mode && ftell(fp)-offset >= l_max)
1221             {
1222                break;
1223             }
1224          }
1225          else
1226          {
1227             if ( ! gdcmGlobal::GetVR()->IsVROfGdcmBinaryRepresentable(vr) )
1228             { 
1229                 ////// Neither ValEntry NOR BinEntry: should mean UNKOWN VR
1230                 dbg.Verbose(0, "gdcmDocument::ParseDES: neither Valentry, "
1231                                "nor BinEntry. Probably unknown VR.");
1232             }
1233
1234             ////// BinEntry or UNKOWN VR:
1235             bn = new gdcmBinEntry(NewDocEntry->GetDictEntry());
1236             bn->Copy(NewDocEntry);
1237             set->AddEntry(bn);
1238             LoadDocEntry(bn);
1239          }
1240
1241          if (NewDocEntry->GetGroup()   == 0x7fe0 && 
1242              NewDocEntry->GetElement() == 0x0010 )
1243          {
1244              if (NewDocEntry->GetReadLength()==0xffffffff)
1245              {
1246                 // Broken US.3405.1.dcm
1247                 Parse7FE0(); // to skip the pixels 
1248                              // (multipart JPEG/RLE are trouble makers)
1249              }
1250              else
1251              {
1252                 SkipToNextDocEntry(NewDocEntry);
1253                 l = NewDocEntry->GetFullLength(); 
1254              }
1255          }
1256          else
1257          {
1258              // to be sure we are at the beginning 
1259              SkipToNextDocEntry(NewDocEntry);
1260              l = NewDocEntry->GetFullLength(); 
1261          }
1262       }
1263       else
1264       {   // VR = "SQ"
1265       
1266          l=NewDocEntry->GetReadLength();            
1267          if (l != 0) // don't mess the delim_mode for zero-length sequence
1268             if (l == 0xffffffff)
1269               delim_mode = true;
1270             else
1271               delim_mode = false;
1272          // no other way to create it ...
1273          sq = new gdcmSeqEntry(NewDocEntry->GetDictEntry(),
1274                                set->GetDepthLevel());
1275          sq->Copy(NewDocEntry);
1276          sq->SetDelimitorMode(delim_mode);
1277          sq->SetDepthLevel(depth);
1278
1279          if (l != 0)
1280          {  // Don't try to parse zero-length sequences
1281             long lgt = ParseSQ( sq, 
1282                                 NewDocEntry->GetOffset(),
1283                                 l, delim_mode);
1284             (void)lgt;  //not used...
1285          }
1286          set->AddEntry(sq);
1287          if ( !delim_mode && ftell(fp)-offset >= l_max)
1288          {
1289             break;
1290          }
1291       }
1292       delete NewDocEntry;
1293    }
1294    return l; // Probably useless 
1295 }
1296
1297 /**
1298  * \brief   Parses a Sequence ( SeqEntry after SeqEntry)
1299  * @return  parsed length for this level
1300  */ 
1301 long gdcmDocument::ParseSQ(gdcmSeqEntry *set,
1302                            long offset, long l_max, bool delim_mode)
1303 {
1304    int SQItemNumber = 0;
1305
1306    gdcmDocEntry *NewDocEntry = (gdcmDocEntry *)0;
1307    gdcmSQItem *itemSQ;
1308    bool dlm_mod;
1309    int lgr, lgth;
1310    unsigned int l;
1311    int depth = set->GetDepthLevel();
1312    (void)depth; //not used
1313
1314    while (true) {
1315
1316       NewDocEntry = ReadNextDocEntry();   
1317       if (!NewDocEntry)
1318          break;
1319       if(delim_mode) {   
1320          if (NewDocEntry->isSequenceDelimitor()) {
1321             set->SetSequenceDelimitationItem(NewDocEntry);
1322             break;
1323           }
1324       }
1325       if (!delim_mode && (ftell(fp)-offset) >= l_max) {
1326           break;
1327       }
1328
1329       itemSQ = new gdcmSQItem(set->GetDepthLevel());
1330       itemSQ->AddEntry(NewDocEntry);
1331       l= NewDocEntry->GetReadLength();
1332       
1333       if (l == 0xffffffff)
1334          dlm_mod = true;
1335       else
1336          dlm_mod=false;
1337    
1338       lgr=ParseDES(itemSQ, NewDocEntry->GetOffset(), l, dlm_mod);
1339       
1340       set->AddEntry(itemSQ,SQItemNumber); 
1341       SQItemNumber ++;
1342       if (!delim_mode && (ftell(fp)-offset) >= l_max) {
1343          break;
1344       }
1345    }
1346    lgth = ftell(fp) - offset;
1347    return lgth;
1348 }
1349
1350 /**
1351  * \brief         Loads the element content if its length doesn't exceed
1352  *                the value specified with gdcmDocument::SetMaxSizeLoadEntry()
1353  * @param         Entry Header Entry (Dicom Element) to be dealt with
1354  */
1355 void gdcmDocument::LoadDocEntry(gdcmDocEntry *Entry)
1356 {
1357    size_t item_read;
1358    guint16 group  = Entry->GetGroup();
1359    std::string  vr= Entry->GetVR();
1360    guint32 length = Entry->GetLength();
1361
1362    fseek(fp, (long)Entry->GetOffset(), SEEK_SET);
1363
1364    // A SeQuence "contains" a set of Elements.  
1365    //          (fffe e000) tells us an Element is beginning
1366    //          (fffe e00d) tells us an Element just ended
1367    //          (fffe e0dd) tells us the current SeQuence just ended
1368    if( group == 0xfffe ) {
1369       // NO more value field for SQ !
1370       return;
1371    }
1372
1373    // When the length is zero things are easy:
1374    if ( length == 0 ) {
1375       ((gdcmValEntry *)Entry)->SetValue("");
1376       return;
1377    }
1378
1379    // The elements whose length is bigger than the specified upper bound
1380    // are not loaded. Instead we leave a short notice of the offset of
1381    // the element content and it's length.
1382
1383    std::ostringstream s;
1384    if (length > MaxSizeLoadEntry) {
1385       if (gdcmBinEntry* BinEntryPtr = dynamic_cast< gdcmBinEntry* >(Entry) )
1386       {         
1387          s << "gdcm::NotLoaded (BinEntry)";
1388          s << " Address:" << (long)Entry->GetOffset();
1389          s << " Length:"  << Entry->GetLength();
1390          s << " x(" << std::hex << Entry->GetLength() << ")";
1391          BinEntryPtr->SetValue(s.str());
1392       }
1393       // to be sure we are at the end of the value ...
1394       fseek(fp,(long)Entry->GetOffset()+(long)Entry->GetLength(),SEEK_SET);      
1395       return;
1396        // Be carefull : a BinEntry IS_A ValEntry ... 
1397       if (gdcmValEntry* ValEntryPtr = dynamic_cast< gdcmValEntry* >(Entry) )
1398       {
1399          s << "gdcm::NotLoaded. (ValEntry)";
1400          s << " Address:" << (long)Entry->GetOffset();
1401          s << " Length:"  << Entry->GetLength();
1402          s << " x(" << std::hex << Entry->GetLength() << ")";
1403          ValEntryPtr->SetValue(s.str());
1404       }
1405       // to be sure we are at the end of the value ...
1406       fseek(fp,(long)Entry->GetOffset()+(long)Entry->GetLength(),SEEK_SET);      
1407       return;
1408    }
1409
1410    // When we find a BinEntry not very much can be done :
1411    if (gdcmBinEntry* BinEntryPtr = dynamic_cast< gdcmBinEntry* >(Entry) ) {
1412
1413       LoadEntryVoidArea(BinEntryPtr);
1414       s << "gdcm::Loaded (BinEntry)";
1415       BinEntryPtr->SetValue(s.str());
1416       return;
1417    }
1418  
1419     
1420    // Any compacter code suggested (?)
1421    if ( IsDocEntryAnInteger(Entry) ) {   
1422       guint32 NewInt;
1423       std::ostringstream s;
1424       int nbInt;
1425    // When short integer(s) are expected, read and convert the following 
1426    // n *two characters properly i.e. as short integers as opposed to strings.
1427    // Elements with Value Multiplicity > 1
1428    // contain a set of integers (not a single one)       
1429       if (vr == "US" || vr == "SS") {
1430          nbInt = length / 2;
1431          NewInt = ReadInt16();
1432          s << NewInt;
1433          if (nbInt > 1){
1434             for (int i=1; i < nbInt; i++) {
1435                s << '\\';
1436                NewInt = ReadInt16();
1437                s << NewInt;
1438             }
1439          }
1440       }
1441    // When integer(s) are expected, read and convert the following 
1442    // n * four characters properly i.e. as integers as opposed to strings.
1443    // Elements with Value Multiplicity > 1
1444    // contain a set of integers (not a single one)           
1445       else if (vr == "UL" || vr == "SL") {
1446          nbInt = length / 4;
1447          NewInt = ReadInt32();
1448          s << NewInt;
1449          if (nbInt > 1) {
1450             for (int i=1; i < nbInt; i++) {
1451                s << '\\';
1452                NewInt = ReadInt32();
1453                s << NewInt;
1454             }
1455          }
1456       }
1457 #ifdef GDCM_NO_ANSI_STRING_STREAM
1458       s << std::ends; // to avoid oddities on Solaris
1459 #endif //GDCM_NO_ANSI_STRING_STREAM
1460
1461       ((gdcmValEntry *)Entry)->SetValue(s.str());
1462       return;
1463    }
1464    
1465    // We need an additional byte for storing \0 that is not on disk
1466    std::string NewValue(length,0);
1467    item_read = fread(&(NewValue[0]), (size_t)length, (size_t)1, fp);
1468    if (gdcmValEntry* ValEntry = dynamic_cast< gdcmValEntry* >(Entry) ) {  
1469       if ( item_read != 1 ) {
1470          dbg.Verbose(1, "gdcmDocument::LoadElementValue","unread element value");
1471          ValEntry->SetValue("gdcm::UnRead");
1472          return;
1473       }
1474
1475       if( (vr == "UI") ) // Because of correspondance with the VR dic
1476          ValEntry->SetValue(NewValue.c_str());
1477       else
1478          ValEntry->SetValue(NewValue);
1479    } else {
1480    // fusible
1481       std::cout << "Should have a ValEntry, here !" << std::endl;
1482    }
1483
1484 }
1485
1486
1487 /**
1488  * \brief  Find the value Length of the passed Header Entry
1489  * @param  Entry Header Entry whose length of the value shall be loaded. 
1490  */
1491  void gdcmDocument::FindDocEntryLength (gdcmDocEntry *Entry) {
1492    guint16 element = Entry->GetElement();
1493    //guint16 group   = Entry->GetGroup(); //FIXME
1494    std::string  vr = Entry->GetVR();
1495    guint16 length16;
1496        
1497    
1498    if ( (Filetype == gdcmExplicitVR) && (! Entry->IsImplicitVR()) ) 
1499    {
1500       if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) 
1501       {
1502          // The following reserved two bytes (see PS 3.5-2001, section
1503          // 7.1.2 Data element structure with explicit vr p27) must be
1504          // skipped before proceeding on reading the length on 4 bytes.
1505          fseek(fp, 2L, SEEK_CUR);
1506          guint32 length32 = ReadInt32();
1507
1508          if ( (vr == "OB") && (length32 == 0xffffffff) ) 
1509          {
1510             Entry->SetLength(FindDocEntryLengthOB());
1511             return;
1512          }
1513          FixDocEntryFoundLength(Entry, length32); 
1514          return;
1515       }
1516
1517       // Length is encoded on 2 bytes.
1518       length16 = ReadInt16();
1519       
1520       // We can tell the current file is encoded in big endian (like
1521       // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag
1522       // and it's value is the one of the encoding of a big endian file.
1523       // In order to deal with such big endian encoded files, we have
1524       // (at least) two strategies:
1525       // * when we load the "Transfer Syntax" tag with value of big endian
1526       //   encoding, we raise the proper flags. Then we wait for the end
1527       //   of the META group (0x0002) among which is "Transfer Syntax",
1528       //   before switching the swap code to big endian. We have to postpone
1529       //   the switching of the swap code since the META group is fully encoded
1530       //   in little endian, and big endian coding only starts at the next
1531       //   group. The corresponding code can be hard to analyse and adds
1532       //   many additional unnecessary tests for regular tags.
1533       // * the second strategy consists in waiting for trouble, that shall
1534       //   appear when we find the first group with big endian encoding. This
1535       //   is easy to detect since the length of a "Group Length" tag (the
1536       //   ones with zero as element number) has to be of 4 (0x0004). When we
1537       //   encounter 1024 (0x0400) chances are the encoding changed and we
1538       //   found a group with big endian encoding.
1539       // We shall use this second strategy. In order to make sure that we
1540       // can interpret the presence of an apparently big endian encoded
1541       // length of a "Group Length" without committing a big mistake, we
1542       // add an additional check: we look in the already parsed elements
1543       // for the presence of a "Transfer Syntax" whose value has to be "big
1544       // endian encoding". When this is the case, chances are we have got our
1545       // hands on a big endian encoded file: we switch the swap code to
1546       // big endian and proceed...
1547       if ( (element  == 0x0000) && (length16 == 0x0400) ) 
1548       {
1549          if ( ! IsExplicitVRBigEndianTransferSyntax() ) 
1550          {
1551             dbg.Verbose(0, "gdcmDocument::FindLength", "not explicit VR");
1552             errno = 1;
1553             return;
1554          }
1555          length16 = 4;
1556          SwitchSwapToBigEndian();
1557          // Restore the unproperly loaded values i.e. the group, the element
1558          // and the dictionary entry depending on them.
1559          guint16 CorrectGroup   = SwapShort(Entry->GetGroup());
1560          guint16 CorrectElem    = SwapShort(Entry->GetElement());
1561          gdcmDictEntry * NewTag = GetDictEntryByNumber(CorrectGroup,
1562                                                        CorrectElem);
1563          if (!NewTag) 
1564          {
1565             // This correct tag is not in the dictionary. Create a new one.
1566             NewTag = NewVirtualDictEntry(CorrectGroup, CorrectElem);
1567          }
1568          // FIXME this can create a memory leaks on the old entry that be
1569          // left unreferenced.
1570          Entry->SetDictEntry(NewTag);
1571       }
1572        
1573       // Heuristic: well, some files are really ill-formed.
1574       if ( length16 == 0xffff) 
1575       {
1576          length16 = 0;
1577          // Length16= 0xffff means that we deal with
1578          // 'Unknown Length' Sequence  
1579       }
1580       FixDocEntryFoundLength(Entry, (guint32)length16);
1581       return;
1582    }
1583    else
1584    {
1585       // Either implicit VR or a non DICOM conformal (see note below) explicit
1586       // VR that ommited the VR of (at least) this element. Farts happen.
1587       // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25
1588       // on Data elements "Implicit and Explicit VR Data Elements shall
1589       // not coexist in a Data Set and Data Sets nested within it".]
1590       // Length is on 4 bytes.
1591       
1592       FixDocEntryFoundLength(Entry, ReadInt32());
1593       return;
1594    }
1595 }
1596
1597 /**
1598  * \brief     Find the Value Representation of the current Dicom Element.
1599  * @param     Entry
1600  */
1601 void gdcmDocument::FindDocEntryVR( gdcmDocEntry *Entry) 
1602 {
1603    if (Filetype != gdcmExplicitVR)
1604       return;
1605
1606    char VR[3];
1607
1608    long PositionOnEntry = ftell(fp);
1609    // Warning: we believe this is explicit VR (Value Representation) because
1610    // we used a heuristic that found "UL" in the first tag. Alas this
1611    // doesn't guarantee that all the tags will be in explicit VR. In some
1612    // cases (see e-film filtered files) one finds implicit VR tags mixed
1613    // within an explicit VR file. Hence we make sure the present tag
1614    // is in explicit VR and try to fix things if it happens not to be
1615    // the case.
1616    
1617    (void)fread (&VR, (size_t)2,(size_t)1, fp);
1618    VR[2]=0;
1619    if(!CheckDocEntryVR(Entry,VR))
1620    {
1621       fseek(fp, PositionOnEntry, SEEK_SET);
1622       // When this element is known in the dictionary we shall use, e.g. for
1623       // the semantics (see the usage of IsAnInteger), the VR proposed by the
1624       // dictionary entry. Still we have to flag the element as implicit since
1625       // we know now our assumption on expliciteness is not furfilled.
1626       // avoid  .
1627       if ( Entry->IsVRUnknown() )
1628          Entry->SetVR("Implicit");
1629       Entry->SetImplicitVR();
1630    }
1631 }
1632
1633 /**
1634  * \brief     Check the correspondance between the VR of the header entry
1635  *            and the taken VR. If they are different, the header entry is 
1636  *            updated with the new VR.
1637  * @param     Entry Header Entry to check
1638  * @param     vr    Dicom Value Representation
1639  * @return    false if the VR is incorrect of if the VR isn't referenced
1640  *            otherwise, it returns true
1641 */
1642 bool gdcmDocument::CheckDocEntryVR(gdcmDocEntry *Entry, VRKey vr)
1643 {
1644    char msg[100]; // for sprintf
1645    bool RealExplicit = true;
1646
1647    // Assume we are reading a falsely explicit VR file i.e. we reached
1648    // a tag where we expect reading a VR but are in fact we read the
1649    // first to bytes of the length. Then we will interogate (through find)
1650    // the dicom_vr dictionary with oddities like "\004\0" which crashes
1651    // both GCC and VC++ implementations of the STL map. Hence when the
1652    // expected VR read happens to be non-ascii characters we consider
1653    // we hit falsely explicit VR tag.
1654
1655    if ( (!isalpha(vr[0])) && (!isalpha(vr[1])) )
1656       RealExplicit = false;
1657
1658    // CLEANME searching the dicom_vr at each occurence is expensive.
1659    // PostPone this test in an optional integrity check at the end
1660    // of parsing or only in debug mode.
1661    if ( RealExplicit && !gdcmGlobal::GetVR()->Count(vr) )
1662       RealExplicit= false;
1663
1664    if ( !RealExplicit ) 
1665    {
1666       // We thought this was explicit VR, but we end up with an
1667       // implicit VR tag. Let's backtrack.   
1668       sprintf(msg,"Falsely explicit vr file (%04x,%04x)\n", 
1669                    Entry->GetGroup(),Entry->GetElement());
1670       dbg.Verbose(1, "gdcmDocument::FindVR: ",msg);
1671       if (Entry->GetGroup()%2 && Entry->GetElement() == 0x0000) { // Group length is UL !
1672          gdcmDictEntry* NewEntry = NewVirtualDictEntry(
1673                                    Entry->GetGroup(),Entry->GetElement(),
1674                                    "UL","FIXME","Group Length");
1675          Entry->SetDictEntry(NewEntry);     
1676       }
1677       return false;
1678    }
1679
1680    if ( Entry->IsVRUnknown() ) 
1681    {
1682       // When not a dictionary entry, we can safely overwrite the VR.
1683       if (Entry->GetElement() == 0x0000) { // Group length is UL !
1684          Entry->SetVR("UL");
1685       } else {
1686          Entry->SetVR(vr);
1687       }
1688    }
1689    else if ( Entry->GetVR() != vr ) 
1690    {
1691       // The VR present in the file and the dictionary disagree. We assume
1692       // the file writer knew best and use the VR of the file. Since it would
1693       // be unwise to overwrite the VR of a dictionary (since it would
1694       // compromise it's next user), we need to clone the actual DictEntry
1695       // and change the VR for the read one.
1696       gdcmDictEntry* NewEntry = NewVirtualDictEntry(
1697                                  Entry->GetGroup(),Entry->GetElement(),
1698                                  vr,"FIXME",Entry->GetName());
1699       Entry->SetDictEntry(NewEntry);
1700    }
1701    return true; 
1702 }
1703
1704 /**
1705  * \brief   Get the transformed value of the header entry. The VR value 
1706  *          is used to define the transformation to operate on the value
1707  * \warning NOT end user intended method !
1708  * @param   Entry 
1709  * @return  Transformed entry value
1710  */
1711 std::string gdcmDocument::GetDocEntryValue(gdcmDocEntry *Entry)
1712 {
1713    if ( (IsDocEntryAnInteger(Entry)) && (Entry->IsImplicitVR()) )
1714    {
1715       std::string val=((gdcmValEntry *)Entry)->GetValue();
1716       std::string vr=Entry->GetVR();
1717       guint32 length = Entry->GetLength();
1718       std::ostringstream s;
1719       int nbInt;
1720
1721    // When short integer(s) are expected, read and convert the following 
1722    // n * 2 bytes properly i.e. as a multivaluated strings
1723    // (each single value is separated fromthe next one by '\'
1724    // as usual for standard multivaluated filels
1725    // Elements with Value Multiplicity > 1
1726    // contain a set of short integers (not a single one) 
1727    
1728       if (vr == "US" || vr == "SS")
1729       {
1730          guint16 NewInt16;
1731
1732          nbInt = length / 2;
1733          for (int i=0; i < nbInt; i++) 
1734          {
1735             if(i!=0)
1736                s << '\\';
1737             NewInt16 = (val[2*i+0]&0xFF)+((val[2*i+1]&0xFF)<<8);
1738             NewInt16 = SwapShort(NewInt16);
1739             s << NewInt16;
1740          }
1741       }
1742
1743    // When integer(s) are expected, read and convert the following 
1744    // n * 4 bytes properly i.e. as a multivaluated strings
1745    // (each single value is separated fromthe next one by '\'
1746    // as usual for standard multivaluated filels
1747    // Elements with Value Multiplicity > 1
1748    // contain a set of integers (not a single one) 
1749       else if (vr == "UL" || vr == "SL")
1750       {
1751          guint32 NewInt32;
1752
1753          nbInt = length / 4;
1754          for (int i=0; i < nbInt; i++) 
1755          {
1756             if(i!=0)
1757                s << '\\';
1758             NewInt32= (val[4*i+0]&0xFF)+((val[4*i+1]&0xFF)<<8)+
1759                      ((val[4*i+2]&0xFF)<<16)+((val[4*i+3]&0xFF)<<24);
1760             NewInt32=SwapLong(NewInt32);
1761             s << NewInt32;
1762          }
1763       }
1764 #ifdef GDCM_NO_ANSI_STRING_STREAM
1765       s << std::ends; // to avoid oddities on Solaris
1766 #endif //GDCM_NO_ANSI_STRING_STREAM
1767       return s.str();
1768    }
1769
1770    return ((gdcmValEntry *)Entry)->GetValue();
1771 }
1772
1773 /**
1774  * \brief   Get the reverse transformed value of the header entry. The VR 
1775  *          value is used to define the reverse transformation to operate on
1776  *          the value
1777  * \warning NOT end user intended method !
1778  * @param   Entry 
1779  * @return  Reverse transformed entry value
1780  */
1781 std::string gdcmDocument::GetDocEntryUnvalue(gdcmDocEntry *Entry)
1782 {
1783    if ( (IsDocEntryAnInteger(Entry)) && (Entry->IsImplicitVR()) )
1784    {
1785       std::string vr=Entry->GetVR();
1786       std::ostringstream s;
1787       std::vector<std::string> tokens;
1788
1789       if (vr == "US" || vr == "SS") 
1790       {
1791          guint16 NewInt16;
1792
1793          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
1794          Tokenize (((gdcmValEntry *)Entry)->GetValue(), tokens, "\\");
1795          for (unsigned int i=0; i<tokens.size();i++) 
1796          {
1797             NewInt16 = atoi(tokens[i].c_str());
1798             s<<(NewInt16&0xFF)<<((NewInt16>>8)&0xFF);
1799          }
1800          tokens.clear();
1801       }
1802       if (vr == "UL" || vr == "SL") 
1803       {
1804          guint32 NewInt32;
1805
1806          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
1807          Tokenize (((gdcmValEntry *)Entry)->GetValue(), tokens, "\\");
1808          for (unsigned int i=0; i<tokens.size();i++) 
1809          {
1810             NewInt32 = atoi(tokens[i].c_str());
1811             s<<(char)(NewInt32&0xFF)<<(char)((NewInt32>>8)&0xFF)
1812                <<(char)((NewInt32>>16)&0xFF)<<(char)((NewInt32>>24)&0xFF);
1813          }
1814          tokens.clear();
1815       }
1816
1817 #ifdef GDCM_NO_ANSI_STRING_STREAM
1818       s << std::ends; // to avoid oddities on Solaris
1819 #endif //GDCM_NO_ANSI_STRING_STREAM
1820       return s.str();
1821    }
1822
1823    return ((gdcmValEntry *)Entry)->GetValue();
1824 }
1825
1826 /**
1827  * \brief   Skip a given Header Entry 
1828  * \warning NOT end user intended method !
1829  * @param   entry 
1830  */
1831 void gdcmDocument::SkipDocEntry(gdcmDocEntry *entry) 
1832 {
1833    SkipBytes(entry->GetLength());
1834 }
1835
1836 /**
1837  * \brief   Skips to the begining of the next Header Entry 
1838  * \warning NOT end user intended method !
1839  * @param   entry 
1840  */
1841 void gdcmDocument::SkipToNextDocEntry(gdcmDocEntry *entry) 
1842 {
1843    (void)fseek(fp, (long)(entry->GetOffset()),     SEEK_SET);
1844    (void)fseek(fp, (long)(entry->GetReadLength()), SEEK_CUR);
1845 }
1846
1847 /**
1848  * \brief   When the length of an element value is obviously wrong (because
1849  *          the parser went Jabberwocky) one can hope improving things by
1850  *          applying some heuristics.
1851  */
1852 void gdcmDocument::FixDocEntryFoundLength(gdcmDocEntry *Entry,
1853                                           guint32 FoundLength)
1854 {
1855    Entry->SetReadLength(FoundLength); // will be updated only if a bug is found        
1856    if ( FoundLength == 0xffffffff) {
1857       FoundLength = 0;
1858    }
1859    
1860    guint16 gr =Entry->GetGroup();
1861    guint16 el =Entry->GetElement(); 
1862      
1863    if (FoundLength%2) {
1864       std::ostringstream s;
1865       s << "Warning : Tag with uneven length "
1866         << FoundLength 
1867         <<  " in x(" << std::hex << gr << "," << el <<")" << std::dec;
1868       dbg.Verbose(0, s.str().c_str());
1869    }
1870       
1871    //////// Fix for some naughty General Electric images.
1872    // Allthough not recent many such GE corrupted images are still present
1873    // on Creatis hard disks. Hence this fix shall remain when such images
1874    // are no longer in user (we are talking a few years, here)...
1875    // Note: XMedCom probably uses such a trick since it is able to read
1876    //       those pesky GE images ...
1877    if (FoundLength == 13) {  // Only happens for this length !
1878       if (   (Entry->GetGroup() != 0x0008)
1879           || (   (Entry->GetElement() != 0x0070)
1880               && (Entry->GetElement() != 0x0080) ) )
1881       {
1882          FoundLength = 10;
1883          Entry->SetReadLength(10); /// \todo a bug is to be fixed !?
1884       }
1885    }
1886
1887    //////// Fix for some brain-dead 'Leonardo' Siemens images.
1888    // Occurence of such images is quite low (unless one leaves close to a
1889    // 'Leonardo' source. Hence, one might consider commenting out the
1890    // following fix on efficiency reasons.
1891    else
1892    if (   (Entry->GetGroup() == 0x0009)
1893        && (   (Entry->GetElement() == 0x1113)
1894            || (Entry->GetElement() == 0x1114) ) )
1895    {
1896       FoundLength = 4;
1897       Entry->SetReadLength(4); /// \todo a bug is to be fixed !?
1898    } 
1899  
1900    //////// Deal with sequences, but only on users request:
1901    else
1902    if ( ( Entry->GetVR() == "SQ") && enableSequences)
1903    {
1904          FoundLength = 0;      // ReadLength is unchanged 
1905    } 
1906     
1907    //////// We encountered a 'delimiter' element i.e. a tag of the form 
1908    // "fffe|xxxx" which is just a marker. Delimiters length should not be
1909    // taken into account.
1910    else
1911    if(Entry->GetGroup() == 0xfffe)
1912    {    
1913      // According to the norm, fffe|0000 shouldn't exist. BUT the Philips
1914      // image gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm happens to
1915      // causes extra troubles...
1916      if( Entry->GetElement() != 0x0000 )
1917      {
1918         FoundLength = 0;
1919      }
1920    } 
1921            
1922    Entry->SetUsableLength(FoundLength);
1923 }
1924
1925 /**
1926  * \brief   Apply some heuristics to predict whether the considered 
1927  *          element value contains/represents an integer or not.
1928  * @param   Entry The element value on which to apply the predicate.
1929  * @return  The result of the heuristical predicate.
1930  */
1931 bool gdcmDocument::IsDocEntryAnInteger(gdcmDocEntry *Entry) {
1932    guint16 element = Entry->GetElement();
1933    guint16 group   = Entry->GetGroup();
1934    std::string  vr = Entry->GetVR();
1935    guint32 length  = Entry->GetLength();
1936
1937    // When we have some semantics on the element we just read, and if we
1938    // a priori know we are dealing with an integer, then we shall be
1939    // able to swap it's element value properly.
1940    if ( element == 0 )  // This is the group length of the group
1941    {  
1942       if (length == 4)
1943          return true;
1944       else 
1945       {
1946          // Allthough this should never happen, still some images have a
1947          // corrupted group length [e.g. have a glance at offset x(8336) of
1948          // gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm].
1949          // Since for dicom compliant and well behaved headers, the present
1950          // test is useless (and might even look a bit paranoid), when we
1951          // encounter such an ill-formed image, we simply display a warning
1952          // message and proceed on parsing (while crossing fingers).
1953          std::ostringstream s;
1954          int filePosition = ftell(fp);
1955          s << "Erroneous Group Length element length  on : (" \
1956            << std::hex << group << " , " << element 
1957            << ") -before- position x(" << filePosition << ")"
1958            << "lgt : " << length;
1959          dbg.Verbose(0, "gdcmDocument::IsDocEntryAnInteger", s.str().c_str() );
1960       }
1961    }
1962
1963    if ( (vr == "UL") || (vr == "US") || (vr == "SL") || (vr == "SS") )
1964       return true;
1965    
1966    return false;
1967 }
1968
1969 /**
1970  * \brief  Find the Length till the next sequence delimiter
1971  * \warning NOT end user intended method !
1972  * @return 
1973  */
1974
1975  guint32 gdcmDocument::FindDocEntryLengthOB(void)  {
1976    // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
1977    guint16 g;
1978    guint16 n; 
1979    long PositionOnEntry = ftell(fp);
1980    bool FoundSequenceDelimiter = false;
1981    guint32 TotalLength = 0;
1982    guint32 ItemLength;
1983
1984    while ( ! FoundSequenceDelimiter) 
1985    {
1986       g = ReadInt16();
1987       n = ReadInt16();   
1988       if (errno == 1)
1989          return 0;
1990       TotalLength += 4;  // We even have to decount the group and element 
1991      
1992       if ( g != 0xfffe && g!=0xb00c ) //for bogus header  
1993       {
1994          char msg[100]; // for sprintf. Sorry
1995          sprintf(msg,"wrong group (%04x) for an item sequence (%04x,%04x)\n",g, g,n);
1996          dbg.Verbose(1, "gdcmDocument::FindLengthOB: ",msg); 
1997          errno = 1;
1998          return 0;
1999       }
2000       if ( n == 0xe0dd || ( g==0xb00c && n==0x0eb6 ) ) // for bogus header 
2001          FoundSequenceDelimiter = true;
2002       else if ( n != 0xe000 )
2003       {
2004          char msg[100];  // for sprintf. Sorry
2005          sprintf(msg,"wrong element (%04x) for an item sequence (%04x,%04x)\n",
2006                       n, g,n);
2007          dbg.Verbose(1, "gdcmDocument::FindLengthOB: ",msg);
2008          errno = 1;
2009          return 0;
2010       }
2011       ItemLength = ReadInt32();
2012       TotalLength += ItemLength + 4;  // We add 4 bytes since we just read
2013                                       // the ItemLength with ReadInt32                                     
2014       SkipBytes(ItemLength);
2015    }
2016    fseek(fp, PositionOnEntry, SEEK_SET);
2017    return TotalLength;
2018 }
2019
2020 /**
2021  * \brief Reads a supposed to be 16 Bits integer
2022  *       (swaps it depending on processor endianity) 
2023  * @return read value
2024  */
2025 guint16 gdcmDocument::ReadInt16() {
2026    guint16 g;
2027    size_t item_read;
2028    item_read = fread (&g, (size_t)2,(size_t)1, fp);
2029    if ( item_read != 1 ) {
2030       if(ferror(fp)) 
2031          dbg.Verbose(0, "gdcmDocument::ReadInt16", " File Error");
2032       errno = 1;
2033       return 0;
2034    }
2035    errno = 0;
2036    g = SwapShort(g);   
2037    return g;
2038 }
2039
2040 /**
2041  * \brief  Reads a supposed to be 32 Bits integer
2042  *         (swaps it depending on processor endianity)  
2043  * @return read value
2044  */
2045 guint32 gdcmDocument::ReadInt32() {
2046    guint32 g;
2047    size_t item_read;
2048    item_read = fread (&g, (size_t)4,(size_t)1, fp);
2049    if ( item_read != 1 ) { 
2050      if(ferror(fp)) 
2051          dbg.Verbose(0, "gdcmDocument::ReadInt32", " File Error");   
2052       errno = 1;
2053       return 0;
2054    }
2055    errno = 0;   
2056    g = SwapLong(g);
2057    return g;
2058 }
2059
2060 /**
2061  * \brief skips bytes inside the source file 
2062  * \warning NOT end user intended method !
2063  * @return 
2064  */
2065 void gdcmDocument::SkipBytes(guint32 NBytes) {
2066    //FIXME don't dump the returned value
2067    (void)fseek(fp, (long)NBytes, SEEK_CUR);
2068 }
2069
2070 /**
2071  * \brief Loads all the needed Dictionaries
2072  * \warning NOT end user intended method !   
2073  */
2074 void gdcmDocument::Initialise(void) 
2075 {
2076    RefPubDict = gdcmGlobal::GetDicts()->GetDefaultPubDict();
2077    RefShaDict = NULL;
2078 }
2079
2080 /**
2081  * \brief   Discover what the swap code is (among little endian, big endian,
2082  *          bad little endian, bad big endian).
2083  *          sw is set
2084  * @return false when we are absolutely sure 
2085  *               it's neither ACR-NEMA nor DICOM
2086  *         true  when we hope ours assuptions are OK
2087  */
2088 bool gdcmDocument::CheckSwap() {
2089
2090    // The only guaranted way of finding the swap code is to find a
2091    // group tag since we know it's length has to be of four bytes i.e.
2092    // 0x00000004. Finding the swap code in then straigthforward. Trouble
2093    // occurs when we can't find such group...
2094    
2095    guint32  x=4;  // x : for ntohs
2096    bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
2097    guint32  s32;
2098    guint16  s16;
2099        
2100    int lgrLue;
2101    char *entCur;
2102    char deb[HEADER_LENGTH_TO_READ];
2103     
2104    // First, compare HostByteOrder and NetworkByteOrder in order to
2105    // determine if we shall need to swap bytes (i.e. the Endian type).
2106    if (x==ntohs(x))
2107       net2host = true;
2108    else
2109       net2host = false; 
2110          
2111    // The easiest case is the one of a DICOM header, since it possesses a
2112    // file preamble where it suffice to look for the string "DICM".
2113    lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, fp);
2114    
2115    entCur = deb + 128;
2116    if(memcmp(entCur, "DICM", (size_t)4) == 0) {
2117       dbg.Verbose(1, "gdcmDocument::CheckSwap:", "looks like DICOM Version3");
2118       
2119       // Next, determine the value representation (VR). Let's skip to the
2120       // first element (0002, 0000) and check there if we find "UL" 
2121       // - or "OB" if the 1st one is (0002,0001) -,
2122       // in which case we (almost) know it is explicit VR.
2123       // WARNING: if it happens to be implicit VR then what we will read
2124       // is the length of the group. If this ascii representation of this
2125       // length happens to be "UL" then we shall believe it is explicit VR.
2126       // FIXME: in order to fix the above warning, we could read the next
2127       // element value (or a couple of elements values) in order to make
2128       // sure we are not commiting a big mistake.
2129       // We need to skip :
2130       // * the 128 bytes of File Preamble (often padded with zeroes),
2131       // * the 4 bytes of "DICM" string,
2132       // * the 4 bytes of the first tag (0002, 0000),or (0002, 0001)
2133       // i.e. a total of  136 bytes.
2134       entCur = deb + 136;
2135      
2136       // FIXME : FIXME:
2137       // Sometimes (see : gdcmData/icone.dcm) group 0x0002 *is* Explicit VR,
2138       // but elem 0002,0010 (Transfert Syntax) tells us the file is
2139       // *Implicit* VR.  -and it is !- 
2140       
2141       if( (memcmp(entCur, "UL", (size_t)2) == 0) ||
2142           (memcmp(entCur, "OB", (size_t)2) == 0) ||
2143           (memcmp(entCur, "UI", (size_t)2) == 0) ||
2144           (memcmp(entCur, "CS", (size_t)2) == 0) )  // CS, to remove later
2145                                                     // when Write DCM *adds*
2146       // FIXME
2147       // Use gdcmDocument::dicom_vr to test all the possibilities
2148       // instead of just checking for UL, OB and UI !? group 0000 
2149       {
2150          Filetype = gdcmExplicitVR;
2151          dbg.Verbose(1, "gdcmDocument::CheckSwap:",
2152                      "explicit Value Representation");
2153       } 
2154       else 
2155       {
2156          Filetype = gdcmImplicitVR;
2157          dbg.Verbose(1, "gdcmDocument::CheckSwap:",
2158                      "not an explicit Value Representation");
2159       }
2160       
2161       if (net2host) 
2162       {
2163          sw = 4321;
2164          dbg.Verbose(1, "gdcmDocument::CheckSwap:",
2165                         "HostByteOrder != NetworkByteOrder");
2166       } 
2167       else 
2168       {
2169          sw = 0;
2170          dbg.Verbose(1, "gdcmDocument::CheckSwap:",
2171                         "HostByteOrder = NetworkByteOrder");
2172       }
2173       
2174       // Position the file position indicator at first tag (i.e.
2175       // after the file preamble and the "DICM" string).
2176       rewind(fp);
2177       fseek (fp, 132L, SEEK_SET);
2178       return true;
2179    } // End of DicomV3
2180
2181    // Alas, this is not a DicomV3 file and whatever happens there is no file
2182    // preamble. We can reset the file position indicator to where the data
2183    // is (i.e. the beginning of the file).
2184    dbg.Verbose(1, "gdcmDocument::CheckSwap:", "not a DICOM Version3 file");
2185    rewind(fp);
2186
2187    // Our next best chance would be to be considering a 'clean' ACR/NEMA file.
2188    // By clean we mean that the length of the first tag is written down.
2189    // If this is the case and since the length of the first group HAS to be
2190    // four (bytes), then determining the proper swap code is straightforward.
2191
2192    entCur = deb + 4;
2193    // We assume the array of char we are considering contains the binary
2194    // representation of a 32 bits integer. Hence the following dirty
2195    // trick :
2196    s32 = *((guint32 *)(entCur));
2197       
2198    switch (s32) {
2199       case 0x00040000 :
2200          sw = 3412;
2201          Filetype = gdcmACR;
2202          return true;
2203       case 0x04000000 :
2204          sw = 4321;
2205          Filetype = gdcmACR;
2206          return true;
2207       case 0x00000400 :
2208          sw = 2143;
2209          Filetype = gdcmACR;
2210          return true;
2211       case 0x00000004 :
2212          sw = 0;
2213          Filetype = gdcmACR;
2214          return true;
2215       default :
2216
2217       // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file.
2218       // It is time for despaired wild guesses. 
2219       // So, let's check if this file wouldn't happen to be 'dirty' ACR/NEMA,
2220       //  i.e. the 'group length' element is not present :     
2221       
2222       //  check the supposed to be 'group number'
2223       //  0x0002 or 0x0004 or 0x0008
2224       //  to determine ' sw' value .
2225       //  Only 0 or 4321 will be possible 
2226       //  (no oportunity to check for the formerly well known
2227       //  ACR-NEMA 'Bad Big Endian' or 'Bad Little Endian' 
2228       //  if unsuccessfull (i.e. neither 0x0002 nor 0x0200 etc -4, 8-) 
2229       //  the file IS NOT ACR-NEMA nor DICOM V3
2230       //  Find a trick to tell it the caller...
2231       
2232       s16 = *((guint16 *)(deb));
2233       
2234       switch (s16) {
2235       case 0x0002 :
2236       case 0x0004 :
2237       case 0x0008 :      
2238          sw = 0;
2239          Filetype = gdcmACR;
2240          return true;
2241       case 0x0200 :
2242       case 0x0400 :
2243       case 0x0800 : 
2244          sw = 4321;
2245          Filetype = gdcmACR;
2246          return true;
2247       default :
2248          dbg.Verbose(0, "gdcmDocument::CheckSwap:",
2249                      "ACR/NEMA unfound swap info (Really hopeless !)"); 
2250          Filetype = gdcmUnknown;     
2251          return false;
2252       }
2253       
2254       // Then the only info we have is the net2host one.
2255       //if (! net2host )
2256          //   sw = 0;
2257          //else
2258          //  sw = 4321;
2259          //return;
2260    }
2261 }
2262
2263 /**
2264  * \brief Restore the unproperly loaded values i.e. the group, the element
2265  *        and the dictionary entry depending on them. 
2266  */
2267 void gdcmDocument::SwitchSwapToBigEndian(void) 
2268 {
2269    dbg.Verbose(1, "gdcmDocument::SwitchSwapToBigEndian",
2270                   "Switching to BigEndian mode.");
2271    if ( sw == 0    ) 
2272    {
2273       sw = 4321;
2274       return;
2275    }
2276    if ( sw == 4321 ) 
2277    {
2278       sw = 0;
2279       return;
2280    }
2281    if ( sw == 3412 ) 
2282    {
2283       sw = 2143;
2284       return;
2285    }
2286    if ( sw == 2143 )
2287       sw = 3412;
2288 }
2289
2290 /**
2291  * \brief  during parsing, Header Elements too long are not loaded in memory 
2292  * @param NewSize
2293  */
2294 void gdcmDocument::SetMaxSizeLoadEntry(long NewSize) 
2295 {
2296    if (NewSize < 0)
2297       return;
2298    if ((guint32)NewSize >= (guint32)0xffffffff) 
2299    {
2300       MaxSizeLoadEntry = 0xffffffff;
2301       return;
2302    }
2303    MaxSizeLoadEntry = NewSize;
2304 }
2305
2306
2307 /**
2308  * \brief Header Elements too long will not be printed
2309  * \todo  See comments of \ref gdcmDocument::MAX_SIZE_PRINT_ELEMENT_VALUE 
2310  * @param NewSize
2311  */
2312 void gdcmDocument::SetMaxSizePrintEntry(long NewSize) 
2313 {
2314    if (NewSize < 0)
2315       return;
2316    if ((guint32)NewSize >= (guint32)0xffffffff) 
2317    {
2318       MaxSizePrintEntry = 0xffffffff;
2319       return;
2320    }
2321    MaxSizePrintEntry = NewSize;
2322 }
2323
2324
2325
2326 /**
2327  * \brief   Read the next tag but WITHOUT loading it's value
2328  *          (read the 'Group Number', the 'Element Number',
2329  *           gets the Dict Entry
2330  *          gets the VR, gets the length, gets the offset value)
2331  * @return  On succes the newly created DocEntry, NULL on failure.      
2332  */
2333 gdcmDocEntry *gdcmDocument::ReadNextDocEntry(void) {
2334    guint16 g,n;
2335    gdcmDocEntry *NewEntry;
2336    g = ReadInt16();
2337    n = ReadInt16();
2338       
2339    if (errno == 1)
2340       // We reached the EOF (or an error occured) therefore 
2341       // header parsing has to be considered as finished.
2342       return (gdcmDocEntry *)0;
2343
2344    NewEntry = NewDocEntryByNumber(g, n);
2345    FindDocEntryVR(NewEntry);
2346    FindDocEntryLength(NewEntry);
2347
2348    if (errno == 1) {
2349       // Call it quits
2350       delete NewEntry;
2351       return NULL;
2352    }
2353    NewEntry->SetOffset(ftell(fp));  
2354    return NewEntry;
2355 }
2356
2357
2358 /**
2359  * \brief   Generate a free TagKey i.e. a TagKey that is not present
2360  *          in the TagHt dictionary.
2361  * @param   group The generated tag must belong to this group.  
2362  * @return  The element of tag with given group which is fee.
2363  */
2364 guint32 gdcmDocument::GenerateFreeTagKeyInGroup(guint16 group) 
2365 {
2366    for (guint32 elem = 0; elem < UINT32_MAX; elem++) 
2367    {
2368       TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
2369       if (tagHT.count(key) == 0)
2370          return elem;
2371    }
2372    return UINT32_MAX;
2373 }
2374
2375
2376 /**
2377  * \brief   Assuming the internal file pointer \ref gdcmDocument::fp 
2378  *          is placed at the beginning of a tag (TestGroup, TestElement),
2379  *          read the length associated to the Tag.
2380  * \warning On success the internal file pointer \ref gdcmDocument::fp
2381  *          is modified to point after the tag and it's length.
2382  *          On failure (i.e. when the tag wasn't the expected tag
2383  *          (TestGroup, TestElement) the internal file pointer
2384  *          \ref gdcmDocument::fp is restored to it's original position.
2385  * @param   TestGroup   The expected group of the tag.
2386  * @param   TestElement The expected Element of the tag.
2387  * @return  On success returns the length associated to the tag. On failure
2388  *          returns 0.
2389  */
2390 guint32 gdcmDocument::ReadTagLength(guint16 TestGroup, guint16 TestElement)
2391 {
2392    guint16 ItemTagGroup;
2393    guint16 ItemTagElement; 
2394    long PositionOnEntry = ftell(fp);
2395    long CurrentPosition = ftell(fp);          // On debugging purposes
2396
2397    //// Read the Item Tag group and element, and make
2398    // sure they are respectively 0xfffe and 0xe000:
2399    ItemTagGroup   = ReadInt16();
2400    ItemTagElement = ReadInt16();
2401    if ( (ItemTagGroup != TestGroup) || (ItemTagElement != TestElement ) )
2402    {
2403       std::ostringstream s;
2404       s << "   We should have found tag (";
2405       s << std::hex << TestGroup << "," << TestElement << ")" << std::endl;
2406       s << "   but instead we encountered tag (";
2407       s << std::hex << ItemTagGroup << "," << ItemTagElement << ")"
2408         << std::endl;
2409       s << "  at address: " << (unsigned)CurrentPosition << std::endl;
2410       dbg.Verbose(0, "gdcmDocument::ReadItemTagLength: wrong Item Tag found:");
2411       dbg.Verbose(0, s.str().c_str());
2412       fseek(fp, PositionOnEntry, SEEK_SET);
2413       return 0;
2414    }
2415                                                                                 
2416    //// Then read the associated Item Length
2417    CurrentPosition=ftell(fp);
2418    guint32 ItemLength;
2419    ItemLength = ReadInt32();
2420    {
2421       std::ostringstream s;
2422       s << "Basic Item Length is: "
2423         << ItemLength << std::endl;
2424       s << "  at address: " << (unsigned)CurrentPosition << std::endl;
2425       dbg.Verbose(0, "gdcmDocument::ReadItemTagLength: ", s.str().c_str());
2426    }
2427    return ItemLength;
2428 }
2429
2430 /**
2431  * \brief   Read the length of an exptected Item tag i.e. (0xfffe, 0xe000).
2432  * \sa      \ref gdcmDocument::ReadTagLength
2433  * \warning See warning of \ref gdcmDocument::ReadTagLength
2434  * @return  On success returns the length associated to the item tag.
2435  *          On failure returns 0.
2436  */ 
2437 guint32 gdcmDocument::ReadItemTagLength(void)
2438 {
2439    return ReadTagLength(0xfffe, 0xe000);
2440 }
2441
2442 /**
2443  * \brief   Read the length of an expected Sequence Delimiter tag i.e.
2444  *          (0xfffe, 0xe0dd).
2445  * \sa      \ref gdcmDocument::ReadTagLength
2446  * \warning See warning of \ref gdcmDocument::ReadTagLength
2447  * @return  On success returns the length associated to the Sequence
2448  *          Delimiter tag. On failure returns 0.
2449  */
2450 guint32 gdcmDocument::ReadSequenceDelimiterTagLength(void)
2451 {
2452    return ReadTagLength(0xfffe, 0xe0dd);
2453 }
2454
2455
2456 /**
2457  * \brief   Parse pixel data from disk for multi-fragment Jpeg/Rle files
2458  *          No other way so 'skip' the Data
2459  *
2460  */
2461
2462 void gdcmDocument::Parse7FE0 (void)
2463 {
2464    gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010);
2465    if ( !Element )
2466       return;
2467       
2468    if (   IsImplicitVRLittleEndianTransferSyntax()
2469        || IsExplicitVRLittleEndianTransferSyntax()
2470        || IsExplicitVRBigEndianTransferSyntax() /// \todo 1.2.2 ??? A verifier !
2471        || IsDeflatedExplicitVRLittleEndianTransferSyntax() )
2472       return;
2473       
2474    // ---------------- for Parsing : Position on begining of Jpeg/RLE Pixels 
2475
2476    //// Read the Basic Offset Table Item Tag length...
2477    guint32 ItemLength = ReadItemTagLength();
2478
2479    //// ... and then read length[s] itself[themselves]. We don't use
2480    // the values read (BTW  what is the purpous of those lengths ?)
2481    if (ItemLength != 0) {
2482       // BTW, what is the purpous of those length anyhow !? 
2483       char * BasicOffsetTableItemValue = new char[ItemLength + 1];
2484       fread(BasicOffsetTableItemValue, ItemLength, 1, fp); 
2485       for (unsigned int i=0; i < ItemLength; i += 4){
2486          guint32 IndividualLength;
2487          IndividualLength = str2num(&BasicOffsetTableItemValue[i],guint32);
2488          std::ostringstream s;
2489          s << "   Read one length: ";
2490          s << std::hex << IndividualLength << std::endl;
2491          dbg.Verbose(0, "gdcmDocument::Parse7FE0: ", s.str().c_str());
2492       }              
2493    }
2494
2495    if ( ! IsRLELossLessTransferSyntax() )
2496    {
2497       // JPEG Image
2498       
2499       //// We then skip (not reading them) all the fragments of images:
2500       while ( (ItemLength = ReadItemTagLength()) )
2501       {
2502          SkipBytes(ItemLength);
2503       } 
2504
2505    }
2506    else
2507    {
2508       // RLE Image
2509       long ftellRes;
2510       long RleSegmentLength[15], fragmentLength;
2511
2512       // while 'Sequence Delimiter Item' (fffe,e0dd) not found
2513       while ( (fragmentLength = ReadSequenceDelimiterTagLength()) )
2514       { 
2515          // Parse fragments of the current Fragment (Frame)    
2516          //------------------ scanning (not reading) fragment pixels
2517          guint32 nbRleSegments = ReadInt32();
2518          printf("   Nb of RLE Segments : %d\n",nbRleSegments);
2519  
2520          //// Reading RLE Segments Offset Table
2521          guint32 RleSegmentOffsetTable[15];
2522          for(int k=1; k<=15; k++) {
2523             ftellRes=ftell(fp);
2524             RleSegmentOffsetTable[k] = ReadInt32();
2525             printf("        at : %x Offset Segment %d : %d (%x)\n",
2526                     (unsigned)ftellRes,k,RleSegmentOffsetTable[k],
2527                     RleSegmentOffsetTable[k]);
2528          }
2529
2530          // skipping (not reading) RLE Segments
2531          if (nbRleSegments>1) {
2532             for(unsigned int k=1; k<=nbRleSegments-1; k++) { 
2533                 RleSegmentLength[k]=   RleSegmentOffsetTable[k+1]
2534                                      - RleSegmentOffsetTable[k];
2535                 ftellRes=ftell(fp);
2536                 printf ("  Segment %d : Length = %d x(%x) Start at %x\n",
2537                         k,(unsigned)RleSegmentLength[k],
2538                        (unsigned)RleSegmentLength[k], (unsigned)ftellRes);
2539                 SkipBytes(RleSegmentLength[k]);    
2540              }
2541           }
2542
2543           RleSegmentLength[nbRleSegments]= fragmentLength 
2544                                          - RleSegmentOffsetTable[nbRleSegments];
2545           ftellRes=ftell(fp);
2546           printf ("  Segment %d : Length = %d x(%x) Start at %x\n",
2547                   nbRleSegments,(unsigned)RleSegmentLength[nbRleSegments],
2548                   (unsigned)RleSegmentLength[nbRleSegments],(unsigned)ftellRes);
2549           SkipBytes(RleSegmentLength[nbRleSegments]); 
2550       } 
2551    }
2552 }
2553
2554
2555
2556 /**
2557  * \brief   Compares two documents, according to \ref gdcmDicomDir rules
2558  * \warning Does NOT work with ACR-NEMA files
2559  * \todo    Find a trick to solve the pb (use RET fields ?)
2560  * @param   document
2561  * @return  true if 'smaller'
2562  */
2563 bool gdcmDocument::operator<(gdcmDocument &document)
2564 {
2565    std::string s1,s2;
2566                                                                                 
2567    // Patient Name
2568    s1=this->GetEntryByNumber(0x0010,0x0010);
2569    s2=document.GetEntryByNumber(0x0010,0x0010);
2570    if(s1 < s2)
2571       return true;
2572    else if(s1 > s2)
2573       return false;
2574    else
2575    {
2576       // Patient ID
2577       s1=this->GetEntryByNumber(0x0010,0x0020);
2578       s2=document.GetEntryByNumber(0x0010,0x0020);
2579       if (s1 < s2)
2580          return true;
2581       else if (s1 > s2)
2582          return true;
2583       else
2584       {
2585          // Study Instance UID
2586          s1=this->GetEntryByNumber(0x0020,0x000d);
2587          s2=document.GetEntryByNumber(0x0020,0x000d);
2588          if (s1 < s2)
2589             return true;
2590          else if(s1 > s2)
2591             return false;
2592          else
2593          {
2594             // Serie Instance UID
2595             s1=this->GetEntryByNumber(0x0020,0x000e);
2596             s2=document.GetEntryByNumber(0x0020,0x000e);
2597             if (s1 < s2)
2598                return true;
2599             else if(s1 > s2)
2600                return false;
2601          }
2602       }
2603    }
2604    return false;
2605 }
2606
2607
2608 //-----------------------------------------------------------------------------