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