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