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