]> Creatis software - gdcm.git/blob - src/gdcmParser.cxx
- ANSIfy gdcmDicomDir.cxx
[gdcm.git] / src / gdcmParser.cxx
1 // gdcmHeader.cxx
2 //-----------------------------------------------------------------------------
3 #include "gdcmParser.h"
4 #include "gdcmUtil.h"
5 #include <errno.h>
6
7 // For nthos:
8 #ifdef _MSC_VER
9    #include <winsock.h>
10 #else
11    #include <netinet/in.h>
12 #endif
13
14 #ifdef GDCM_NO_ANSI_STRING_STREAM
15 #  include <strstream>
16 #  define  ostringstream ostrstream
17 # else
18 #  include <sstream>
19 #endif
20 #  include <iomanip>
21
22 #define UI1_2_840_10008_1_2      "1.2.840.10008.1.2"
23 #define UI1_2_840_10008_1_2_1    "1.2.840.10008.1.2.1"
24 #define UI1_2_840_10008_1_2_2    "1.2.840.10008.1.2.2"
25 #define UI1_2_840_10008_1_2_1_99 "1.2.840.10008.1.2.1.99"
26
27 //-----------------------------------------------------------------------------
28 // Refer to gdcmParser::CheckSwap()
29 const unsigned int gdcmParser::HEADER_LENGTH_TO_READ = 256;
30
31 // Refer to gdcmParser::SetMaxSizeLoadElementValue()
32 const unsigned int gdcmParser::MAX_SIZE_LOAD_ELEMENT_VALUE = 4096;
33
34 //-----------------------------------------------------------------------------
35 // Constructor / Destructor
36 /**
37  * \ingroup gdcmParser
38  * \brief   
39  * @param   InFilename
40  * @param   exception_on_error
41  * @param   enable_sequences = true to allow the header 
42  *          to be parsed *inside* the SeQuences, 
43  *          when they have an actual length 
44  *\TODO    may be we need one more bool, 
45  *         to allow skipping the private elements while parsing the header
46  *         in order to save space         
47  */
48 gdcmParser::gdcmParser(const char *InFilename, 
49                        bool exception_on_error,
50                        bool enable_sequences ) 
51 {
52    enableSequences=enable_sequences;
53    
54    SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
55    filename = InFilename;
56    Initialise();
57
58    if ( !OpenFile(exception_on_error))
59       return;
60    Parse();
61    LoadHeaderEntries();
62    CloseFile();
63
64    wasUpdated = 0;  // will be set to 1 if user adds an entry
65    printLevel = 1;  // 'Medium' print level by default
66 }
67
68 /**
69  * \ingroup gdcmParser
70  * \brief   
71  * @param   exception_on_error
72  */
73 gdcmParser::gdcmParser(bool exception_on_error) 
74 {
75    enableSequences=0;
76
77    SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
78    Initialise();
79
80    wasUpdated = 0;  // will be set to 1 if user adds an entry
81    printLevel = 1;  // 'Medium' print level by default
82 }
83
84 /**
85  * \ingroup gdcmParser
86  * \brief   Canonical destructor.
87  */
88 gdcmParser::~gdcmParser (void) 
89 {
90    RefPubDict = NULL;
91    RefShaDict = NULL;
92 }
93
94 //-----------------------------------------------------------------------------
95 // Print
96 /**
97   * \ingroup gdcmParser
98   * \brief   Prints the Header Entries (Dicom Elements)
99   *          both from the H Table and the chained list
100   * @return
101   */ 
102 void gdcmParser::PrintEntry(std::ostream & os) 
103 {
104    std::ostringstream s;   
105            
106    for (ListTag::iterator i = listEntries.begin();  
107            i != listEntries.end();
108            ++i)
109    {
110            (*i)->SetPrintLevel(printLevel);
111            (*i)->Print(os);   
112    } 
113    os<<s.str();
114 }
115
116 /**
117   * \ingroup gdcmParser
118   * \brief   Prints The Dict Entries of THE public Dicom Dictionnry
119   * @return
120   */  
121 void gdcmParser::PrintPubDict(std::ostream & os) {
122    RefPubDict->Print(os);
123 }
124
125 /**
126   * \ingroup gdcmParser
127   * \brief   Prints The Dict Entries of THE shadow Dicom Dictionnry
128   * @return
129   */
130 void gdcmParser::PrintShaDict(std::ostream & os) {
131    RefShaDict->Print(os);
132 }
133
134 //-----------------------------------------------------------------------------
135 // Public
136 /**
137  * \ingroup gdcmParser
138  * \brief   Get the public dictionary used
139  */
140 gdcmDict *gdcmParser::GetPubDict(void)
141 {
142    return(RefPubDict);
143 }
144
145 /**
146  * \ingroup gdcmParser
147  * \brief   Get the shadow dictionary used
148  */
149 gdcmDict *gdcmParser::GetShaDict(void)
150 {
151    return(RefShaDict);
152 }
153
154 /**
155  * \ingroup gdcmParser
156  * \brief   Set the shadow dictionary used
157  * \param   dict dictionary to use in shadow
158  */
159 bool gdcmParser::SetShaDict(gdcmDict *dict)
160 {
161    RefShaDict=dict;
162    return(!RefShaDict);
163 }
164
165 /**
166  * \ingroup gdcmParser
167  * \brief   Set the shadow dictionary used
168  * \param   dictName name of the dictionary to use in shadow
169  */
170 bool gdcmParser::SetShaDict(DictKey dictName)
171 {
172    RefShaDict=gdcmGlobal::GetDicts()->GetDict(dictName);
173    return(!RefShaDict);
174 }
175
176 /**
177  * \ingroup gdcmParser
178  * \brief  This predicate, based on hopefully reasonable heuristics,
179  *         decides whether or not the current gdcmParser was properly parsed
180  *         and contains the mandatory information for being considered as
181  *         a well formed and usable Dicom/Acr File.
182  * @return true when gdcmParser is the one of a reasonable Dicom/Acr file,
183  *         false otherwise. 
184  */
185 bool gdcmParser::IsReadable(void) 
186 {
187    if(filetype==Unknown)
188       return(false);
189
190    if(listEntries.size()<=0)
191       return(false);
192
193    return(true);
194 }
195
196 /**
197  * \ingroup gdcmParser
198  * \brief   Determines if the Transfer Syntax was already encountered
199  *          and if it corresponds to a ImplicitVRLittleEndian one.
200  *
201  * @return  True when ImplicitVRLittleEndian found. False in all other cases.
202  */
203 bool gdcmParser::IsImplicitVRLittleEndianTransferSyntax(void) 
204 {
205    gdcmHeaderEntry *Element = GetHeaderEntryByNumber(0x0002, 0x0010);
206    if ( !Element )
207       return false;
208    LoadHeaderEntrySafe(Element);
209
210    std::string Transfer = Element->GetValue();
211    if ( Transfer == UI1_2_840_10008_1_2 )
212       return true;
213    return false;
214 }
215
216 /**
217  * \ingroup gdcmParser
218  * \brief   Determines if the Transfer Syntax was already encountered
219  *          and if it corresponds to a ExplicitVRLittleEndian one.
220  *
221  * @return  True when ExplicitVRLittleEndian found. False in all other cases.
222  */
223 bool gdcmParser::IsExplicitVRLittleEndianTransferSyntax(void) 
224 {
225    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
226    if ( !Element )
227       return false;
228    LoadHeaderEntrySafe(Element);
229
230    std::string Transfer = Element->GetValue();
231    if ( Transfer == UI1_2_840_10008_1_2_1 )
232       return true;
233    return false;
234 }
235
236 /**
237  * \ingroup gdcmParser
238  * \brief   Determines if the Transfer Syntax was already encountered
239  *          and if it corresponds to a DeflatedExplicitVRLittleEndian one.
240  *
241  * @return  True when DeflatedExplicitVRLittleEndian found. False in all other cases.
242  */
243 bool gdcmParser::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) 
244 {
245    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
246    if ( !Element )
247       return false;
248    LoadHeaderEntrySafe(Element);
249
250    std::string Transfer = Element->GetValue();
251    if ( Transfer == UI1_2_840_10008_1_2_1_99 )
252       return true;
253    return false;
254 }
255
256 /**
257  * \ingroup gdcmParser
258  * \brief   Determines if the Transfer Syntax was already encountered
259  *          and if it corresponds to a Explicit VR Big Endian one.
260  *
261  * @return  True when big endian found. False in all other cases.
262  */
263 bool gdcmParser::IsExplicitVRBigEndianTransferSyntax(void) 
264 {
265    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
266    if ( !Element )
267       return false;
268    LoadHeaderEntrySafe(Element);
269
270    std::string Transfer = Element->GetValue();
271    if ( Transfer == UI1_2_840_10008_1_2_2 )  //1.2.2 ??? A verifier !
272       return true;
273    return false;
274 }
275
276 /**
277  * \ingroup gdcmParser
278  * \brief  returns the File Type 
279  *         (ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown)
280  * @return 
281  */
282 FileType gdcmParser::GetFileType(void) {
283    return(filetype);
284 }
285
286 /**
287  * \ingroup gdcmParser
288  * \brief   opens the file
289  * @param   exception_on_error
290  * @return  
291  */
292 FILE *gdcmParser::OpenFile(bool exception_on_error)
293   throw(gdcmFileError) 
294 {
295   fp=fopen(filename.c_str(),"rb");
296   if(exception_on_error) 
297   {
298     if(!fp)
299       throw gdcmFileError("gdcmParser::gdcmParser(const char *, bool)");
300   }
301
302   if ( fp ) 
303   {
304      guint16 zero;
305      fread(&zero,  (size_t)2, (size_t)1, fp);
306
307     //ACR -- or DICOM with no Preamble --
308     if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200)
309        return(fp);
310
311     //DICOM
312     fseek(fp, 126L, SEEK_CUR);
313     char dicm[4];
314     fread(dicm,  (size_t)4, (size_t)1, fp);
315     if( memcmp(dicm, "DICM", 4) == 0 )
316        return(fp);
317
318     fclose(fp);
319     dbg.Verbose(0, "gdcmParser::gdcmParser not DICOM/ACR", filename.c_str());
320   }
321   else {
322     dbg.Verbose(0, "gdcmParser::gdcmParser cannot open file", filename.c_str());
323   }
324   return(NULL);
325 }
326
327 /**
328  * \ingroup gdcmParser
329  * \brief closes the file  
330  * @return  TRUE if the close was successfull 
331  */
332 bool gdcmParser::CloseFile(void) 
333 {
334   int closed = fclose(fp);
335   fp = (FILE *)0;
336   if (! closed)
337      return false;
338   return true;
339 }
340
341 /**
342  * \ingroup gdcmParser
343  * \brief 
344  * @param fp file pointer on an already open file
345  * @param   type type of the File to be written 
346  *          (ACR-NEMA, ExplicitVR, ImplicitVR)
347  * @return  always "True" ?!
348  */
349 bool gdcmParser::Write(FILE *fp, FileType type) 
350 {
351 // ==============
352 // TODO The stuff has been rewritten using the chained list instead 
353 //      of the H table
354 //      so we could remove the GroupHT from the gdcmParser
355 // To be checked
356 // =============
357
358    // TODO : move the following lines (and a lot of others, to be written)
359    // to a future function CheckAndCorrectHeader
360    
361         // Question :
362         // Comment pourrait-on savoir si le DcmHeader vient d'un fichier DicomV3 ou non
363         // (FileType est un champ de gdcmParser ...)
364         // WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA
365         // no way 
366         // a moins de se livrer a un tres complique ajout des champs manquants.
367         // faire un CheckAndCorrectHeader (?)  
368          
369
370    if (type == ImplicitVR) 
371    {
372       std::string implicitVRTransfertSyntax = UI1_2_840_10008_1_2;
373       ReplaceOrCreateByNumber(implicitVRTransfertSyntax,0x0002, 0x0010);
374       
375       //FIXME Refer to standards on page 21, chapter 6.2 "Value representation":
376       //      values with a VR of UI shall be padded with a single trailing null
377       //      Dans le cas suivant on doit pader manuellement avec un 0
378       
379       SetEntryLengthByNumber(18, 0x0002, 0x0010);
380    } 
381
382    if (type == ExplicitVR) 
383    {
384       std::string explicitVRTransfertSyntax = UI1_2_840_10008_1_2_1;
385       ReplaceOrCreateByNumber(explicitVRTransfertSyntax,0x0002, 0x0010);
386       
387       //FIXME Refer to standards on page 21, chapter 6.2 "Value representation":
388       //      values with a VR of UI shall be padded with a single trailing null
389       //      Dans le cas suivant on doit pader manuellement avec un 0
390       
391       SetEntryLengthByNumber(20, 0x0002, 0x0010);
392    }
393
394
395    if ( (type == ImplicitVR) || (type == ExplicitVR) )
396       UpdateGroupLength(false,type);
397    if ( type == ACR)
398       UpdateGroupLength(true,ACR);
399
400    WriteEntries(type, fp);
401    return(true);
402  }
403
404 /**
405  * \ingroup gdcmParser
406  * \brief   Modifies the value of a given Header Entry (Dicom Element)
407  *          if it exists; Creates it with the given value if it doesn't
408  * @param   Value passed as a std::string
409  * @param   Group
410  * @param   Elem
411  * \return  boolean
412  */
413 bool gdcmParser::ReplaceOrCreateByNumber(std::string Value, 
414                                         guint16 Group, guint16 Elem ) 
415 {
416    if (CheckIfEntryExistByNumber(Group, Elem) == 0) {
417       gdcmHeaderEntry *a =NewHeaderEntryByNumber(Group, Elem);
418       if (a == NULL) 
419          return false;
420       AddHeaderEntry(a);
421    }   
422    SetEntryByNumber(Value, Group, Elem);
423    return(true);
424 }   
425
426 /**
427  * \ingroup gdcmParser
428  * \brief   Modifies the value of a given Header Entry (Dicom Element)
429  *          if it exists; Creates it with the given value if it doesn't
430  * @param   Value passed as a char*
431  * @param   Group
432  * @param   Elem
433  * \return  boolean 
434  * 
435  */
436 bool gdcmParser::ReplaceOrCreateByNumber(char* Value, guint16 Group, guint16 Elem ) 
437 {
438    gdcmHeaderEntry* nvHeaderEntry=NewHeaderEntryByNumber(Group, Elem);
439
440    if(!nvHeaderEntry)
441       return(false);
442
443    AddHeaderEntry(nvHeaderEntry);
444
445    std::string v = Value;       
446    SetEntryByNumber(v, Group, Elem);
447    return(true);
448 }  
449
450 /**
451  * \ingroup gdcmParser
452  * \brief   Set a new value if the invoked element exists
453  *          Seems to be useless !!!
454  * @param   Value
455  * @param   Group
456  * @param   Elem
457  * \return  boolean 
458  */
459 bool gdcmParser::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 Elem ) 
460 {
461    std::string v = Value;       
462    SetEntryByNumber(v, Group, Elem);
463    return true;
464
465
466 //-----------------------------------------------------------------------------
467 // Protected
468 /**
469  * \ingroup gdcmParser
470  * \brief   Checks if a given Dicom Element exists
471  * \        within the H table
472  * @param   group Group   number of the searched Dicom Element 
473  * @param   element  Element number of the searched Dicom Element 
474  * @return  number of occurences
475  */
476 int gdcmParser::CheckIfEntryExistByNumber(guint16 group, guint16 element ) 
477 {
478         std::string key = gdcmDictEntry::TranslateToKey(group, element );
479         return (tagHT.count(key));
480 }
481
482 /**
483  * \ingroup gdcmParser
484  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
485  *          the public and private dictionaries 
486  *          for the element value of a given tag.
487  * \warning Don't use any longer : use GetPubEntryByName
488  * @param   tagName name of the searched element.
489  * @return  Corresponding element value when it exists,
490  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
491  */
492 std::string gdcmParser::GetEntryByName(std::string tagName) 
493 {
494    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
495    if( dictEntry == NULL)
496       return GDCM_UNFOUND;
497
498    return(GetEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement()));  
499 }
500
501 /**
502  * \ingroup gdcmParser
503  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
504  *          the public and private dictionaries 
505  *          for the element value representation of a given tag.
506  *
507  *          Obtaining the VR (Value Representation) might be needed by caller
508  *          to convert the string typed content to caller's native type 
509  *          (think of C++ vs Python). The VR is actually of a higher level
510  *          of semantics than just the native C++ type.
511  * @param   tagName name of the searched element.
512  * @return  Corresponding element value representation when it exists,
513  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
514  */
515 std::string gdcmParser::GetEntryVRByName(std::string tagName) 
516 {
517    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
518    if( dictEntry == NULL)
519       return GDCM_UNFOUND;
520
521    gdcmHeaderEntry* elem =  GetHeaderEntryByNumber(dictEntry->GetGroup(),
522                                                    dictEntry->GetElement());                                    
523    return elem->GetVR();
524 }
525
526 /**
527  * \ingroup gdcmParser
528  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
529  *          the public and private dictionaries 
530  *          for the element value representation of a given tag.
531  * @param   group Group of the searched tag.
532  * @param   element Element of the searched tag.
533  * @return  Corresponding element value representation when it exists,
534  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
535  */
536 std::string gdcmParser::GetEntryByNumber(guint16 group, guint16 element) 
537 {
538    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
539    if ( ! tagHT.count(key))
540       return GDCM_UNFOUND;
541    return tagHT.find(key)->second->GetValue();
542 }
543
544 /**
545  * \ingroup gdcmParser
546  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
547  *          the public and private dictionaries 
548  *          for the element value representation of a given tag..
549  *
550  *          Obtaining the VR (Value Representation) might be needed by caller
551  *          to convert the string typed content to caller's native type 
552  *          (think of C++ vs Python). The VR is actually of a higher level
553  *          of semantics than just the native C++ type.
554  * @param   group Group of the searched tag.
555  * @param   element Element of the searched tag.
556  * @return  Corresponding element value representation when it exists,
557  *          and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
558  */
559 std::string gdcmParser::GetEntryVRByNumber(guint16 group, guint16 element) 
560 {
561    gdcmHeaderEntry* elem =  GetHeaderEntryByNumber(group, element);
562    if ( !elem )
563       return GDCM_UNFOUND;
564    return elem->GetVR();
565 }
566
567 /**
568  * \ingroup gdcmParser
569  * \brief   Sets the value (string) of the Header Entry (Dicom Element)
570  * @param   content string value of the Dicom Element
571  * @param   tagName name of the searched Dicom Element.
572  * @return  true when found
573  */
574 bool gdcmParser::SetEntryByName(std::string content,std::string tagName) 
575 {
576    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
577    if( dictEntry == NULL)
578       return false;                                 
579
580    return(SetEntryByNumber(content,dictEntry->GetGroup(),
581                                    dictEntry->GetElement()));
582 }
583
584 /**
585  * \ingroup gdcmParser
586  * \brief   Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element)
587  *          through it's (group, element) and modifies it's content with
588  *          the given value.
589  * \warning Don't use any longer : use SetPubEntryByNumber
590  * @param   content new value to substitute with
591  * @param   group   group of the Dicom Element to modify
592  * @param   element element of the Dicom Element to modify
593  */
594 bool gdcmParser::SetEntryByNumber(std::string content, 
595                                   guint16 group,
596                                   guint16 element) 
597 {
598    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
599    if ( ! tagHT.count(key))
600       return false;
601    int l = content.length();
602    if(l%2) // Odd length are padded with a space (020H).
603    {  
604       l++;
605       content = content + '\0';
606    }
607       
608    //tagHT[key]->SetValue(content);   
609    gdcmHeaderEntry * a;
610    IterHT p;
611    TagHeaderEntryHT::iterator p2;
612    // DO NOT remove the following lines : they explain the stuff   
613    //p= tagHT.equal_range(key); // get a pair of iterators first-last synonym
614    //p2=p.first;                // iterator on the first synonym 
615    //a=p2->second;              // H Table target column (2-nd col)
616     
617    // or, easier :
618    a = ((tagHT.equal_range(key)).first)->second; 
619        
620    a-> SetValue(content); 
621    
622    //std::string vr = tagHT[key]->GetVR();
623    std::string vr = a->GetVR();
624    
625    guint32 lgr;
626    if( (vr == "US") || (vr == "SS") ) 
627       lgr = 2;
628    else if( (vr == "UL") || (vr == "SL") )
629       lgr = 4;
630    else
631       lgr = l;     
632
633    //tagHT[key]->SetLength(lgr);
634    a->SetLength(lgr);   
635    return true;
636 }                                         
637
638 /**
639  * \ingroup gdcmParser
640  * \brief   Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element)
641  *          in the PubHeaderEntrySet of this instance
642  *          through it's (group, element) and modifies it's length with
643  *          the given value.
644  * \warning Use with extreme caution.
645  * @param   length new length to substitute with
646  * @param   group   group of the entry to modify
647  * @param   element element of the Entry to modify
648  * @return  1 on success, 0 otherwise.
649  */
650
651 bool gdcmParser::SetEntryLengthByNumber(guint32 length, 
652                                         guint16 group, guint16 element) 
653 {
654    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
655    if ( ! tagHT.count(key))
656       return false;
657    if (length%2) length++; // length must be even
658    //tagHT[key]->SetLength(length);
659    ( ((tagHT.equal_range(key)).first)->second )->SetLength(length);      
660          
661    return true ;                
662 }
663
664 /**
665  * \ingroup gdcmParser
666  * \brief   Gets (from Header) the offset  of a 'non string' element value 
667  * \        (LoadElementValues has already be executed)
668  * @param   Group
669  * @param   Elem
670  * @return File Offset of the Element Value 
671  */
672 size_t gdcmParser::GetEntryOffsetByNumber(guint16 Group, guint16 Elem) 
673 {
674    gdcmHeaderEntry* Entry = GetHeaderEntryByNumber(Group, Elem);         
675    if (!Entry) 
676    {
677       dbg.Verbose(1, "gdcmParser::GetHeaderEntryByNumber",
678                       "failed to Locate gdcmHeaderEntry");
679       return (size_t)0;
680    }
681    return Entry->GetOffset();
682 }
683
684 /**
685  * \ingroup gdcmParser
686  * \brief   Gets (from Header) a 'non string' element value 
687  * \        (LoadElementValues has already be executed)  
688  * @param   Group
689  * @param   Elem
690  * @return Pointer to the 'non string' area
691  */
692 void * gdcmParser::GetEntryVoidAreaByNumber(guint16 Group, guint16 Elem) 
693 {
694    gdcmHeaderEntry* Entry = GetHeaderEntryByNumber(Group, Elem);         
695    if (!Entry) 
696    {
697       dbg.Verbose(1, "gdcmParser::GetHeaderEntryByNumber",
698                   "failed to Locate gdcmHeaderEntry");
699       return (NULL);
700    }
701    return Entry->GetVoidArea();
702 }
703
704 /**
705  * \ingroup       gdcmParser
706  * \brief         Loads (from disk) the element content 
707  *                when a string is not suitable
708  */
709 void *gdcmParser::LoadEntryVoidArea(guint16 Group, guint16 Elem) 
710 {
711    gdcmHeaderEntry * Element= GetHeaderEntryByNumber(Group, Elem);
712    if ( !Element )
713       return NULL;
714    size_t o =(size_t)Element->GetOffset();
715    fseek(fp, o, SEEK_SET);
716    int l=Element->GetLength();
717    void * a = malloc(l);
718    if(!a) 
719         return NULL;
720
721    SetEntryVoidAreaByNumber(a, Group, Elem);
722    // TODO check the result 
723    size_t l2 = fread(a, 1, l ,fp);
724    if(l != l2) 
725    {
726         free(a);
727         return NULL;
728    }
729    return a;  
730 }
731
732 /**
733  * \ingroup gdcmParser
734  * \brief   Sets a 'non string' value to a given Dicom Element
735  * @param   area
736  * @param   group Group number of the searched Dicom Element 
737  * @param   element Element number of the searched Dicom Element 
738  * @return  
739  */
740 bool gdcmParser::SetEntryVoidAreaByNumber(void * area,guint16 group, guint16 element) 
741 {
742    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
743    if ( ! tagHT.count(key))
744       return false;
745    //tagHT[key]->SetVoidArea(area);
746    ( ((tagHT.equal_range(key)).first)->second )->SetVoidArea(area);      
747    return true;
748 }
749
750 /**
751  * \ingroup gdcmParser
752  * \brief   Update the entries with the shadow dictionary. Only odd entries are
753  *          analized
754  */
755 void gdcmParser::UpdateShaEntries(void)
756 {
757    gdcmDictEntry *entry;
758    std::string vr;
759
760    for(ListTag::iterator it=listEntries.begin();
761        it!=listEntries.end();
762        ++it)
763    {
764       // Odd group => from public dictionary
765       if((*it)->GetGroup()%2==0)
766          continue;
767
768       // Peer group => search the corresponding dict entry
769       if(RefShaDict)
770          entry=RefShaDict->GetDictEntryByNumber((*it)->GetGroup(),(*it)->GetElement());
771       else
772          entry=NULL;
773
774       if((*it)->IsImplicitVR())
775          vr="Implicit";
776       else
777          vr=(*it)->GetVR();
778
779       (*it)->SetValue(GetHeaderEntryUnvalue(*it));
780       if(entry)
781       {
782          // Set the new entry and the new value
783          (*it)->SetDictEntry(entry);
784          CheckHeaderEntryVR(*it,vr);
785
786          (*it)->SetValue(GetHeaderEntryValue(*it));
787       }
788       else
789       {
790          // Remove precedent value transformation
791          (*it)->SetDictEntry(NewVirtualDictEntry((*it)->GetGroup(),(*it)->GetElement(),vr));
792       }
793    }
794 }
795
796 /**
797  * \ingroup gdcmParser
798  * \brief   Searches within the Header Entries for a Dicom Element of
799  *          a given tag.
800  * @param   tagName name of the searched Dicom Element.
801  * @return  Corresponding Dicom Element when it exists, and NULL
802  *          otherwise.
803  */
804  gdcmHeaderEntry *gdcmParser::GetHeaderEntryByName(std::string tagName) 
805  {
806    gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); 
807    if( dictEntry == NULL)
808       return NULL;
809
810   return(GetHeaderEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement()));
811 }
812
813 /**
814  * \ingroup gdcmParser
815  * \brief  retrieves a Dicom Element (the first one) using (group, element)
816  * \ warning (group, element) IS NOT an identifier inside the Dicom Header
817  *           if you think it's NOT UNIQUE, check the count number
818  *           and use iterators to retrieve ALL the Dicoms Elements within
819  *           a given couple (group, element)
820  * @param   group Group number of the searched Dicom Element 
821  * @param   element Element number of the searched Dicom Element 
822  * @return  
823  */
824 gdcmHeaderEntry* gdcmParser::GetHeaderEntryByNumber(guint16 group, guint16 element) 
825 {
826    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
827    if ( ! tagHT.count(key))
828       return NULL;
829    return tagHT.find(key)->second;
830 }
831
832 /**
833  * \ingroup       gdcmParser
834  * \brief         Loads the element while preserving the current
835  *                underlying file position indicator as opposed to
836  *                to LoadHeaderEntry that modifies it.
837  * @param entry   Header Entry whose value shall be loaded. 
838  * @return  
839  */
840 void gdcmParser::LoadHeaderEntrySafe(gdcmHeaderEntry * entry) 
841 {
842    long PositionOnEntry = ftell(fp);
843    LoadHeaderEntry(entry);
844    fseek(fp, PositionOnEntry, SEEK_SET);
845 }
846
847 /**
848  * \ingroup gdcmParser
849  * \brief   Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
850  * \warning : to be re-written using the chained list instead of the H table.
851  * \warning : DO NOT use (doesn't work any longer because of the multimap)
852  * \todo : to be re-written using the chained list instead of the H table
853  * @param   SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files)
854  * @param   type Type of the File (ExplicitVR,ImplicitVR, ACR, ...) 
855  */
856 void gdcmParser::UpdateGroupLength(bool SkipSequence, FileType type) 
857 {
858    guint16 gr, el;
859    std::string vr;
860    
861    gdcmHeaderEntry *elem;
862    char trash[10];
863    std::string str_trash;
864    
865    GroupKey key;
866    GroupHT groupHt;  // to hold the length of each group
867    TagKey tk;
868    // remember :
869    // typedef std::map<GroupKey, int> GroupHT;
870    
871    gdcmHeaderEntry *elemZ;
872   
873    // for each Tag in the DCM Header
874    
875    for (TagHeaderEntryHT::iterator tag2 = tagHT.begin(); 
876         tag2 != tagHT.end();
877         ++tag2)
878    {
879       elem  = tag2->second;
880       gr = elem->GetGroup();
881       el = elem->GetElement();
882       vr = elem->GetVR(); 
883                  
884       sprintf(trash, "%04x", gr);
885       key = trash;              // generate 'group tag'
886       
887       // if the caller decided not to take SEQUENCEs into account 
888       // e.g : he wants to write an ACR-NEMA File 
889                 
890       if (SkipSequence && vr == "SQ") 
891          continue;
892       
893       // Still unsolved problem :
894       // we cannot find the 'Sequence Delimitation Item'
895       // since it's at the end of the Hash Table
896       // (fffe,e0dd) 
897        
898       // pas SEQUENCE en ACR-NEMA
899       // WARNING : 
900       // --> la descente a l'interieur' des SQ 
901       // devrait etre faite avec une liste chainee, pas avec une HTable...
902             
903       if ( groupHt.count(key) == 0) // we just read the first elem of a given group
904       { 
905          if (el == 0x0000) // the first elem is 0x0000
906          {            
907             groupHt[key] = 0;         // initialize group length 
908          } 
909          else 
910          {
911             groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
912          } 
913       } 
914       else // any elem but the first
915       {   
916          if (type == ExplicitVR) 
917          {
918             if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) 
919             {
920                groupHt[key] +=  4; // explicit VR AND OB, OW, SQ : 4 more bytes
921             }
922          }
923          groupHt[key] += 2 + 2 + 4 + elem->GetLength(); 
924       } 
925    }
926
927    unsigned short int gr_bid;
928   
929    for (GroupHT::iterator g = groupHt.begin(); // for each group we found
930         g != groupHt.end();
931         ++g)
932    { 
933       // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
934       //        warning: unsigned int format, different type arg
935       sscanf(g->first.c_str(),"%x",&gr_bid);
936       tk = g->first + "|0000";                  // generate the element full tag
937                      
938       if ( tagHT.count(tk) == 0) // if element 0x0000 not found
939       {                 
940          gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");       
941          elemZ = new gdcmHeaderEntry(tagZ);
942          elemZ->SetLength(4);
943          AddHeaderEntry(elemZ);                         // create it
944       } 
945       else 
946       {
947          elemZ=GetHeaderEntryByNumber(gr_bid, 0x0000);
948       }     
949       sprintf(trash ,"%d",g->second);
950       str_trash=trash;
951       elemZ->SetValue(str_trash);
952    }   
953 }
954
955 /**
956  * \ingroup gdcmParser
957  * \brief   writes on disc according to the requested format
958  * \        (ACR-NEMA, ExplicitVR, ImplicitVR) the image
959  * \ warning does NOT add the missing elements in the header :
960  * \         it's up to the user doing it !
961  * \         (function CheckHeaderCoherence to be written)
962  * @param   type type of the File to be written 
963  *          (ACR-NEMA, ExplicitVR, ImplicitVR)
964  * @param   _fp already open file pointer
965  */
966 void gdcmParser::WriteEntries(FileType type, FILE * _fp) 
967 {
968    guint16 gr, el;
969    guint32 lgr;
970    const char * val;
971    std::string vr;
972    guint32 val_uint32;
973    guint16 val_uint16;
974    
975    std::vector<std::string> tokens;
976    
977    //  uses now listEntries to iterate, not TagHt!
978    //
979    //        pb : gdcmParser.Add does NOT update listEntries
980    //       TODO : find a trick (in STL?) to do it, at low cost !
981
982    void *ptr;
983
984    // TODO (?) tester les echecs en ecriture (apres chaque fwrite)
985
986    for (ListTag::iterator tag2=listEntries.begin();
987         tag2 != listEntries.end();
988         ++tag2)
989    {
990       gr =  (*tag2)->GetGroup();
991       el =  (*tag2)->GetElement();
992       lgr = (*tag2)->GetLength();
993       val = (*tag2)->GetValue().c_str();
994       vr =  (*tag2)->GetVR();
995       
996       if ( type == ACR ) 
997       { 
998          if (gr < 0x0008)   continue; // ignore pure DICOM V3 groups
999          if (gr %2)         continue; // ignore shadow groups
1000          if (vr == "SQ" )   continue; // ignore Sequences
1001                    // TODO : find a trick to *skip* the SeQuences !
1002                    // Not only ignore the SQ element
1003          if (gr == 0xfffe ) continue; // ignore delimiters
1004       } 
1005
1006       fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp);  //group
1007       fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp);  //element
1008
1009       if ( (type == ExplicitVR) && (gr <= 0x0002) ) 
1010       {
1011          // EXPLICIT VR
1012          guint16 z=0, shortLgr;
1013          fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
1014
1015          if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) 
1016          {
1017             fwrite ( &z,  (size_t)2 ,(size_t)1 ,_fp);
1018             fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
1019
1020          } 
1021          else 
1022          {
1023             shortLgr=lgr;
1024             fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
1025          }
1026       } 
1027       else // IMPLICIT VR
1028       { 
1029          fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
1030       }
1031
1032       if (vr == "US" || vr == "SS") 
1033       {
1034          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
1035          Tokenize ((*tag2)->GetValue(), tokens, "\\");
1036          for (unsigned int i=0; i<tokens.size();i++) 
1037          {
1038             val_uint16 = atoi(tokens[i].c_str());
1039             ptr = &val_uint16;
1040             fwrite ( ptr,(size_t)2 ,(size_t)1 ,_fp);
1041          }
1042          tokens.clear();
1043          continue;
1044       }
1045       if (vr == "UL" || vr == "SL") 
1046       {
1047          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
1048          Tokenize ((*tag2)->GetValue(), tokens, "\\");
1049          for (unsigned int i=0; i<tokens.size();i++) 
1050          {
1051             val_uint32 = atoi(tokens[i].c_str());
1052             ptr = &val_uint32;
1053             fwrite ( ptr,(size_t)4 ,(size_t)1 ,_fp);
1054          }
1055          tokens.clear();
1056          continue;
1057       }     
1058       // Pixels are never loaded in the element !
1059       if ((gr == 0x7fe0) && (el == 0x0010) ) 
1060          break;
1061
1062       fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
1063    }
1064 }
1065
1066 /**
1067  * \ingroup gdcmParser
1068  * \brief   Swaps back the bytes of 4-byte long integer accordingly to
1069  *          processor order.
1070  * @return  The properly swaped 32 bits integer.
1071  */
1072 guint32 gdcmParser::SwapLong(guint32 a) 
1073 {
1074    switch (sw) 
1075    {
1076       case    0 :
1077          break;
1078       case 4321 :
1079          a=( ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000) | 
1080              ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
1081          break;
1082    
1083       case 3412 :
1084          a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
1085          break;
1086    
1087       case 2143 :
1088          a=( ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
1089          break;
1090       default :
1091          dbg.Error(" gdcmParser::SwapLong : unset swap code");
1092          a=0;
1093    }
1094    return(a);
1095 }
1096
1097 /**
1098  * \ingroup gdcmParser
1099  * \brief   Unswaps back the bytes of 4-byte long integer accordingly to
1100  *          processor order.
1101  * @return  The properly unswaped 32 bits integer.
1102  */
1103 guint32 gdcmParser::UnswapLong(guint32 a) 
1104 {
1105    return (SwapLong(a));
1106 }
1107
1108 /**
1109  * \ingroup gdcmParser
1110  * \brief   Swaps the bytes so they agree with the processor order
1111  * @return  The properly swaped 16 bits integer.
1112  */
1113 guint16 gdcmParser::SwapShort(guint16 a) 
1114 {
1115    if ( (sw==4321)  || (sw==2143) )
1116       a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff));
1117    return (a);
1118 }
1119
1120 /**
1121  * \ingroup gdcmParser
1122  * \brief   Unswaps the bytes so they agree with the processor order
1123  * @return  The properly unswaped 16 bits integer.
1124  */
1125 guint16 gdcmParser::UnswapShort(guint16 a) 
1126 {
1127    return (SwapShort(a));
1128 }
1129
1130 //-----------------------------------------------------------------------------
1131 // Private
1132 /**
1133  * \ingroup gdcmParser
1134  * \brief   Parses the header of the file but WITHOUT loading element values.
1135  */
1136 void gdcmParser::Parse(bool exception_on_error) throw(gdcmFormatError) 
1137 {
1138    gdcmHeaderEntry *newHeaderEntry = (gdcmHeaderEntry *)0;
1139    
1140    rewind(fp);
1141    CheckSwap();
1142    while ( (newHeaderEntry = ReadNextHeaderEntry()) ) 
1143    {
1144       SkipHeaderEntry(newHeaderEntry);
1145       AddHeaderEntry(newHeaderEntry);
1146    }
1147 }
1148
1149 /**
1150  * \ingroup gdcmParser
1151  * \brief   Loads the element values of all the Header Entries pointed in the
1152  *          public Chained List.
1153  */
1154 void gdcmParser::LoadHeaderEntries(void) 
1155 {
1156    rewind(fp);
1157    for (ListTag::iterator i = GetListEntry().begin();
1158       i != GetListEntry().end();
1159       ++i)
1160    {
1161       LoadHeaderEntry(*i);
1162    }
1163             
1164    rewind(fp);
1165
1166    // Load 'non string' values   
1167    std::string PhotometricInterpretation = GetEntryByNumber(0x0028,0x0004);   
1168    if( PhotometricInterpretation == "PALETTE COLOR " )
1169    {
1170       LoadEntryVoidArea(0x0028,0x1200);  // gray LUT   
1171       LoadEntryVoidArea(0x0028,0x1201);  // R    LUT
1172       LoadEntryVoidArea(0x0028,0x1202);  // G    LUT
1173       LoadEntryVoidArea(0x0028,0x1203);  // B    LUT
1174       
1175       LoadEntryVoidArea(0x0028,0x1221);  // Segmented Red   Palette Color LUT Data
1176       LoadEntryVoidArea(0x0028,0x1222);  // Segmented Green Palette Color LUT Data
1177       LoadEntryVoidArea(0x0028,0x1223);  // Segmented Blue  Palette Color LUT Data
1178    }
1179
1180    // --------------------------------------------------------------
1181    // Special Patch to allow gdcm to read ACR-LibIDO formated images
1182    //
1183    // if recognition code tells us we deal with a LibIDO image
1184    // we switch lineNumber and columnNumber
1185    //
1186    std::string RecCode; 
1187    RecCode = GetEntryByNumber(0x0008, 0x0010); // recognition code
1188    if (RecCode == "ACRNEMA_LIBIDO_1.1" ||
1189        RecCode == "CANRME_AILIBOD1_1." ) 
1190    {
1191          filetype = ACR_LIBIDO; 
1192          std::string rows    = GetEntryByNumber(0x0028, 0x0010);
1193          std::string columns = GetEntryByNumber(0x0028, 0x0011);
1194          SetEntryByNumber(columns, 0x0028, 0x0010);
1195          SetEntryByNumber(rows   , 0x0028, 0x0011);
1196    }
1197    // ----------------- End of Special Patch ----------------
1198 }
1199
1200 /**
1201  * \ingroup       gdcmParser
1202  * \brief         Loads the element content if it's length is not bigger
1203  *                than the value specified with
1204  *                gdcmParser::SetMaxSizeLoadEntry()
1205  * @param         Entry Header Entry (Dicom Element) to be dealt with
1206  */
1207 void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry *Entry) 
1208 {
1209    size_t item_read;
1210    guint16 group  = Entry->GetGroup();
1211    std::string  vr= Entry->GetVR();
1212    guint32 length = Entry->GetLength();
1213    bool SkipLoad  = false;
1214
1215    fseek(fp, (long)Entry->GetOffset(), SEEK_SET);
1216    
1217    // the test was commented out to 'go inside' the SeQuences
1218    // we don't any longer skip them !
1219     
1220    // if( vr == "SQ" )  //  (DO NOT remove this comment)
1221    //    SkipLoad = true;
1222
1223    // A SeQuence "contains" a set of Elements.  
1224    //          (fffe e000) tells us an Element is beginning
1225    //          (fffe e00d) tells us an Element just ended
1226    //          (fffe e0dd) tells us the current SeQuence just ended
1227    if( group == 0xfffe )
1228       SkipLoad = true;
1229
1230    if ( SkipLoad ) 
1231    {
1232       Entry->SetLength(0);
1233       Entry->SetValue("gdcm::Skipped");
1234       return;
1235    }
1236
1237    // When the length is zero things are easy:
1238    if ( length == 0 ) 
1239    {
1240       Entry->SetValue("");
1241       return;
1242    }
1243
1244    // The elements whose length is bigger than the specified upper bound
1245    // are not loaded. Instead we leave a short notice of the offset of
1246    // the element content and it's length.
1247    if (length > MaxSizeLoadEntry) 
1248    {
1249       std::ostringstream s;
1250       s << "gdcm::NotLoaded.";
1251       s << " Address:" << (long)Entry->GetOffset();
1252       s << " Length:"  << Entry->GetLength();
1253       s << " x(" << std::hex << Entry->GetLength() << ")";
1254       Entry->SetValue(s.str());
1255       return;
1256    }
1257    
1258    // When integer(s) are expected, read and convert the following 
1259    // n *(two or four bytes)
1260    // properly i.e. as integers as opposed to a strings.        
1261    // Elements with Value Multiplicity > 1
1262    // contain a set of integers (not a single one) 
1263         
1264    // Any compacter code suggested (?)
1265    if ( IsHeaderEntryAnInteger(Entry) ) 
1266    {
1267       guint32 NewInt;
1268       std::ostringstream s;
1269       int nbInt;
1270       if (vr == "US" || vr == "SS")
1271       {
1272          nbInt = length / 2;
1273          NewInt = ReadInt16();
1274          s << NewInt;
1275          if (nbInt > 1) 
1276          {
1277             for (int i=1; i < nbInt; i++) 
1278             {
1279                s << '\\';
1280                NewInt = ReadInt16();
1281                s << NewInt;
1282             }
1283          }
1284                         
1285       }
1286       else if (vr == "UL" || vr == "SL") 
1287       {
1288          nbInt = length / 4;
1289          NewInt = ReadInt32();
1290          s << NewInt;
1291          if (nbInt > 1) 
1292          {
1293             for (int i=1; i < nbInt; i++) 
1294             {
1295                s << '\\';
1296                NewInt = ReadInt32();
1297                s << NewInt;
1298             }
1299          }
1300       }
1301 #ifdef GDCM_NO_ANSI_STRING_STREAM
1302       s << std::ends; // to avoid oddities on Solaris
1303 #endif //GDCM_NO_ANSI_STRING_STREAM
1304       Entry->SetValue(s.str());
1305       return;   
1306    }
1307    
1308    // We need an additional byte for storing \0 that is not on disk
1309    std::string NewValue(length,0);
1310    item_read = fread(&(NewValue[0]), (size_t)length, (size_t)1, fp);
1311    if ( item_read != 1 ) 
1312    {
1313       dbg.Verbose(1, "gdcmParser::LoadElementValue","unread element value");
1314       Entry->SetValue("gdcm::UnRead");
1315       return;
1316    }
1317
1318    if( (vr == "UI") ) // Because of correspondance with the VR dic
1319       Entry->SetValue(NewValue.c_str());
1320    else
1321       Entry->SetValue(NewValue);
1322 }
1323
1324 /**
1325  * \ingroup gdcmParser
1326  * \brief   add a new Dicom Element pointer to 
1327  *          the H Table and to the chained List
1328  * \warning push_bash in listEntries ONLY during ParseHeader
1329  * \todo    something to allow further Elements addition,
1330  * \        when position to be taken care of     
1331  * @param   newHeaderEntry
1332  */
1333 void gdcmParser::AddHeaderEntry(gdcmHeaderEntry *newHeaderEntry) 
1334 {
1335    tagHT.insert( PairHT( newHeaderEntry->GetKey(),newHeaderEntry) );
1336    listEntries.push_back(newHeaderEntry); 
1337    wasUpdated = 1;
1338 }
1339
1340 /**
1341  * \ingroup gdcmParser
1342  * \brief   
1343  * @param   Entry Header Entry whose length of the value shall be loaded. 
1344
1345  * @return 
1346  */
1347  void gdcmParser::FindHeaderEntryLength (gdcmHeaderEntry *Entry) 
1348  {
1349    guint16 element = Entry->GetElement();
1350    guint16 group   = Entry->GetGroup();
1351    std::string  vr = Entry->GetVR();
1352    guint16 length16;
1353    if( (element == 0x0010) && (group == 0x7fe0) ) 
1354    {
1355       dbg.SetDebug(-1);
1356       dbg.Verbose(2, "gdcmParser::FindLength: ",
1357                      "we reached 7fe0 0010");
1358    }   
1359    
1360    if ( (filetype == ExplicitVR) && (! Entry->IsImplicitVR()) ) 
1361    {
1362       if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) 
1363       {
1364          // The following reserved two bytes (see PS 3.5-2001, section
1365          // 7.1.2 Data element structure with explicit vr p27) must be
1366          // skipped before proceeding on reading the length on 4 bytes.
1367          fseek(fp, 2L, SEEK_CUR);
1368          guint32 length32 = ReadInt32();
1369
1370          if ( (vr == "OB") && (length32 == 0xffffffff) ) 
1371          {
1372             Entry->SetLength(FindHeaderEntryLengthOB());
1373             return;
1374          }
1375          FixHeaderEntryFoundLength(Entry, length32); 
1376          return;
1377       }
1378
1379       // Length is encoded on 2 bytes.
1380       length16 = ReadInt16();
1381       
1382       // We can tell the current file is encoded in big endian (like
1383       // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag
1384       // and it's value is the one of the encoding of a big endian file.
1385       // In order to deal with such big endian encoded files, we have
1386       // (at least) two strategies:
1387       // * when we load the "Transfer Syntax" tag with value of big endian
1388       //   encoding, we raise the proper flags. Then we wait for the end
1389       //   of the META group (0x0002) among which is "Transfer Syntax",
1390       //   before switching the swap code to big endian. We have to postpone
1391       //   the switching of the swap code since the META group is fully encoded
1392       //   in little endian, and big endian coding only starts at the next
1393       //   group. The corresponding code can be hard to analyse and adds
1394       //   many additional unnecessary tests for regular tags.
1395       // * the second strategy consists in waiting for trouble, that shall
1396       //   appear when we find the first group with big endian encoding. This
1397       //   is easy to detect since the length of a "Group Length" tag (the
1398       //   ones with zero as element number) has to be of 4 (0x0004). When we
1399       //   encounter 1024 (0x0400) chances are the encoding changed and we
1400       //   found a group with big endian encoding.
1401       // We shall use this second strategy. In order to make sure that we
1402       // can interpret the presence of an apparently big endian encoded
1403       // length of a "Group Length" without committing a big mistake, we
1404       // add an additional check: we look in the already parsed elements
1405       // for the presence of a "Transfer Syntax" whose value has to be "big
1406       // endian encoding". When this is the case, chances are we have got our
1407       // hands on a big endian encoded file: we switch the swap code to
1408       // big endian and proceed...
1409       if ( (element  == 0x0000) && (length16 == 0x0400) ) 
1410       {
1411          if ( ! IsExplicitVRBigEndianTransferSyntax() ) 
1412          {
1413             dbg.Verbose(0, "gdcmParser::FindLength", "not explicit VR");
1414             errno = 1;
1415             return;
1416          }
1417          length16 = 4;
1418          SwitchSwapToBigEndian();
1419          // Restore the unproperly loaded values i.e. the group, the element
1420          // and the dictionary entry depending on them.
1421          guint16 CorrectGroup   = SwapShort(Entry->GetGroup());
1422          guint16 CorrectElem    = SwapShort(Entry->GetElement());
1423          gdcmDictEntry * NewTag = GetDictEntryByNumber(CorrectGroup,
1424                                                        CorrectElem);
1425          if (!NewTag) 
1426          {
1427             // This correct tag is not in the dictionary. Create a new one.
1428             NewTag = NewVirtualDictEntry(CorrectGroup, CorrectElem);
1429          }
1430          // FIXME this can create a memory leaks on the old entry that be
1431          // left unreferenced.
1432          Entry->SetDictEntry(NewTag);
1433       }
1434        
1435       // Heuristic: well some files are really ill-formed.
1436       if ( length16 == 0xffff) 
1437       {
1438          length16 = 0;
1439          //dbg.Verbose(0, "gdcmParser::FindLength",
1440          //            "Erroneous element length fixed.");
1441          // Actually, length= 0xffff means that we deal with
1442          // Unknown Sequence Length 
1443       }
1444
1445       FixHeaderEntryFoundLength(Entry, (guint32)length16);
1446       return;
1447    }
1448    else
1449    {
1450       // Either implicit VR or a non DICOM conformal (see not below) explicit
1451       // VR that ommited the VR of (at least) this element. Farts happen.
1452       // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25
1453       // on Data elements "Implicit and Explicit VR Data Elements shall
1454       // not coexist in a Data Set and Data Sets nested within it".]
1455       // Length is on 4 bytes.
1456       FixHeaderEntryFoundLength(Entry, ReadInt32());
1457       return;
1458    }
1459 }
1460
1461 /**
1462  * \ingroup   gdcmParser
1463  * \brief     Find the Value Representation of the current Dicom Element.
1464  * @param     Entry
1465  */
1466 void gdcmParser::FindHeaderEntryVR( gdcmHeaderEntry *Entry) 
1467 {
1468    if (filetype != ExplicitVR)
1469       return;
1470
1471    char VR[3];
1472    int lgrLue;
1473
1474    long PositionOnEntry = ftell(fp);
1475    // Warning: we believe this is explicit VR (Value Representation) because
1476    // we used a heuristic that found "UL" in the first tag. Alas this
1477    // doesn't guarantee that all the tags will be in explicit VR. In some
1478    // cases (see e-film filtered files) one finds implicit VR tags mixed
1479    // within an explicit VR file. Hence we make sure the present tag
1480    // is in explicit VR and try to fix things if it happens not to be
1481    // the case.
1482    
1483    lgrLue=fread (&VR, (size_t)2,(size_t)1, fp);
1484    VR[2]=0;
1485    if(!CheckHeaderEntryVR(Entry,VR))
1486    {
1487       fseek(fp, PositionOnEntry, SEEK_SET);
1488       // When this element is known in the dictionary we shall use, e.g. for
1489       // the semantics (see the usage of IsAnInteger), the VR proposed by the
1490       // dictionary entry. Still we have to flag the element as implicit since
1491       // we know now our assumption on expliciteness is not furfilled.
1492       // avoid  .
1493       if ( Entry->IsVRUnknown() )
1494          Entry->SetVR("Implicit");
1495       Entry->SetImplicitVR();
1496    }
1497 }
1498
1499 /**
1500  * \ingroup   gdcmParser
1501  * \brief     Check the correspondance between the VR of the header entry
1502  *            and the taken VR. If they are different, the header entry is 
1503  *            updated with the new VR.
1504  * @param     Entry
1505  * @param     VR
1506  * @return    false if the VR is incorrect of if the VR isn't referenced
1507  *            otherwise, it returns true
1508 */
1509 bool gdcmParser::CheckHeaderEntryVR(gdcmHeaderEntry *Entry, VRKey vr)
1510 {
1511    char msg[100]; // for sprintf
1512    bool RealExplicit = true;
1513
1514    // Assume we are reading a falsely explicit VR file i.e. we reached
1515    // a tag where we expect reading a VR but are in fact we read the
1516    // first to bytes of the length. Then we will interogate (through find)
1517    // the dicom_vr dictionary with oddities like "\004\0" which crashes
1518    // both GCC and VC++ implementations of the STL map. Hence when the
1519    // expected VR read happens to be non-ascii characters we consider
1520    // we hit falsely explicit VR tag.
1521
1522    if ( (!isalpha(vr[0])) && (!isalpha(vr[1])) )
1523       RealExplicit = false;
1524
1525    // CLEANME searching the dicom_vr at each occurence is expensive.
1526    // PostPone this test in an optional integrity check at the end
1527    // of parsing or only in debug mode.
1528    if ( RealExplicit && !gdcmGlobal::GetVR()->Count(vr) )
1529       RealExplicit= false;
1530
1531    if ( !RealExplicit ) 
1532    {
1533       // We thought this was explicit VR, but we end up with an
1534       // implicit VR tag. Let's backtrack.   
1535       sprintf(msg,"Falsely explicit vr file (%04x,%04x)\n", 
1536                    Entry->GetGroup(),Entry->GetElement());
1537       dbg.Verbose(1, "gdcmParser::FindVR: ",msg);
1538
1539       return(false);
1540    }
1541
1542    if ( Entry->IsVRUnknown() ) 
1543    {
1544       // When not a dictionary entry, we can safely overwrite the VR.
1545       Entry->SetVR(vr);
1546    }
1547    else if ( Entry->GetVR() != vr ) 
1548    {
1549       // The VR present in the file and the dictionary disagree. We assume
1550       // the file writer knew best and use the VR of the file. Since it would
1551       // be unwise to overwrite the VR of a dictionary (since it would
1552       // compromise it's next user), we need to clone the actual DictEntry
1553       // and change the VR for the read one.
1554       gdcmDictEntry* NewEntry = NewVirtualDictEntry(
1555                                  Entry->GetGroup(),Entry->GetElement(),
1556                                  vr,"FIXME",Entry->GetName());
1557       Entry->SetDictEntry(NewEntry);
1558    }
1559    return(true); 
1560 }
1561
1562 /**
1563  * \ingroup gdcmParser
1564  * \brief   Get the transformed value of the header entry. The VR value 
1565  *          is used to define the transformation to operate on the value
1566  * \warning NOT end user intended method !
1567  * @param   Entry 
1568  * @return  Transformed entry value
1569  */
1570 std::string gdcmParser::GetHeaderEntryValue(gdcmHeaderEntry *Entry)
1571 {
1572    if ( (IsHeaderEntryAnInteger(Entry)) && (Entry->IsImplicitVR()) )
1573    {
1574       std::string val=Entry->GetValue();
1575       std::string vr=Entry->GetVR();
1576       guint32 length = Entry->GetLength();
1577       std::ostringstream s;
1578       int nbInt;
1579
1580       if (vr == "US" || vr == "SS")
1581       {
1582          guint16 NewInt16;
1583
1584          nbInt = length / 2;
1585          for (int i=0; i < nbInt; i++) 
1586          {
1587             if(i!=0)
1588                s << '\\';
1589             NewInt16 = (val[2*i+0]&0xFF)+((val[2*i+1]&0xFF)<<8);
1590             NewInt16 = SwapShort(NewInt16);
1591             s << NewInt16;
1592          }
1593       }
1594
1595       else if (vr == "UL" || vr == "SL")
1596       {
1597          guint32 NewInt32;
1598
1599          nbInt = length / 4;
1600          for (int i=0; i < nbInt; i++) 
1601          {
1602             if(i!=0)
1603                s << '\\';
1604             NewInt32= (val[4*i+0]&0xFF)+((val[4*i+1]&0xFF)<<8)+
1605                      ((val[4*i+2]&0xFF)<<16)+((val[4*i+3]&0xFF)<<24);
1606             NewInt32=SwapLong(NewInt32);
1607             s << NewInt32;
1608          }
1609       }
1610
1611 #ifdef GDCM_NO_ANSI_STRING_STREAM
1612       s << std::ends; // to avoid oddities on Solaris
1613 #endif //GDCM_NO_ANSI_STRING_STREAM
1614       return(s.str());
1615    }
1616
1617    return(Entry->GetValue());
1618 }
1619
1620 /**
1621  * \ingroup gdcmParser
1622  * \brief   Get the reverse transformed value of the header entry. The VR 
1623  *          value is used to define the reverse transformation to operate on
1624  *          the value
1625  * \warning NOT end user intended method !
1626  * @param   Entry 
1627  * @return  Reverse transformed entry value
1628  */
1629 std::string gdcmParser::GetHeaderEntryUnvalue(gdcmHeaderEntry *Entry)
1630 {
1631    if ( (IsHeaderEntryAnInteger(Entry)) && (Entry->IsImplicitVR()) )
1632    {
1633       std::string vr=Entry->GetVR();
1634       std::ostringstream s;
1635       std::vector<std::string> tokens;
1636
1637       if (vr == "US" || vr == "SS") 
1638       {
1639          guint16 NewInt16;
1640
1641          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
1642          Tokenize (Entry->GetValue(), tokens, "\\");
1643          for (unsigned int i=0; i<tokens.size();i++) 
1644          {
1645             NewInt16 = atoi(tokens[i].c_str());
1646             s<<(NewInt16&0xFF)<<((NewInt16>>8)&0xFF);
1647          }
1648          tokens.clear();
1649       }
1650       if (vr == "UL" || vr == "SL") 
1651       {
1652          guint32 NewInt32;
1653
1654          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
1655          Tokenize (Entry->GetValue(), tokens, "\\");
1656          for (unsigned int i=0; i<tokens.size();i++) 
1657          {
1658             NewInt32 = atoi(tokens[i].c_str());
1659             s<<(char)(NewInt32&0xFF)<<(char)((NewInt32>>8)&0xFF)
1660                <<(char)((NewInt32>>16)&0xFF)<<(char)((NewInt32>>24)&0xFF);
1661          }
1662          tokens.clear();
1663       }
1664
1665 #ifdef GDCM_NO_ANSI_STRING_STREAM
1666       s << std::ends; // to avoid oddities on Solaris
1667 #endif //GDCM_NO_ANSI_STRING_STREAM
1668       return(s.str());
1669    }
1670
1671    return(Entry->GetValue());
1672 }
1673
1674 /**
1675  * \ingroup gdcmParser
1676  * \brief   Skip a given Header Entry 
1677  * \warning NOT end user intended method !
1678  * @param   entry 
1679  */
1680 void gdcmParser::SkipHeaderEntry(gdcmHeaderEntry *entry) 
1681 {
1682     SkipBytes(entry->GetLength());
1683 }
1684
1685 /**
1686  * \ingroup gdcmParser
1687  * \brief   When the length of an element value is obviously wrong (because
1688  *          the parser went Jabberwocky) one can hope improving things by
1689  *          applying this heuristic.
1690  */
1691 void gdcmParser::FixHeaderEntryFoundLength(gdcmHeaderEntry *Entry, guint32 FoundLength) 
1692 {
1693    Entry->SetReadLength(FoundLength); // will be updated only if a bug is found
1694                      
1695    if ( FoundLength == 0xffffffff) 
1696    {
1697       FoundLength = 0;
1698    }
1699       
1700    // Sorry for the patch!  
1701    // XMedCom did the trick to read some nasty GE images ...
1702    else if (FoundLength == 13) 
1703    {
1704       // The following 'if' will be removed when there is no more
1705       // images on Creatis HDs with a 13 length for Manufacturer...
1706       if ( (Entry->GetGroup() != 0x0008) ||  
1707            ( (Entry->GetElement() != 0x0070) && (Entry->GetElement() != 0x0080) ) ) {
1708       // end of remove area
1709          FoundLength =10;
1710          Entry->SetReadLength(10); // a bug is to be fixed
1711       }
1712    }
1713
1714    // to fix some garbage 'Leonardo' Siemens images
1715    // May be commented out to avoid overhead
1716    else if ( (Entry->GetGroup() == 0x0009) &&
1717        ( (Entry->GetElement() == 0x1113) || (Entry->GetElement() == 0x1114) ) )
1718    {
1719       FoundLength =4;
1720       Entry->SetReadLength(4); // a bug is to be fixed 
1721    } 
1722    // end of fix
1723          
1724    // to try to 'go inside' SeQuences (with length), and not to skip them        
1725    else if ( Entry->GetVR() == "SQ") 
1726    { 
1727       if (enableSequences)    // only if the user does want to !
1728          FoundLength =0;         
1729    } 
1730     
1731    // a SeQuence Element is beginning                                          
1732    // Let's forget it's length                                                 
1733    // (we want to 'go inside')  
1734
1735    // Pb : *normaly*  fffe|e000 is just a marker, its length *should be* zero
1736    // in gdcm-MR-PHILIPS-16-Multi-Seq.dcm we find lengthes as big as 28800
1737    // if we set the length to zero IsHeaderEntryAnInteger() breaks...
1738    // if we don't, we lost 28800 characters from the Header :-(
1739                                                  
1740    else if(Entry->GetGroup() == 0xfffe)
1741    { 
1742                        // sometimes, length seems to be wrong                                      
1743       FoundLength =0;  // some more clever checking to be done !
1744                        // I give up!
1745                        // only  gdcm-MR-PHILIPS-16-Multi-Seq.dcm
1746                        // causes troubles :-(                                                     
1747    }     
1748     
1749    Entry->SetUsableLength(FoundLength);
1750 }
1751
1752 /**
1753  * \ingroup gdcmParser
1754  * \brief   Apply some heuristics to predict wether the considered 
1755  *          element value contains/represents an integer or not.
1756  * @param   Entry The element value on which to apply the predicate.
1757  * @return  The result of the heuristical predicate.
1758  */
1759 bool gdcmParser::IsHeaderEntryAnInteger(gdcmHeaderEntry *Entry) 
1760 {
1761    guint16 element = Entry->GetElement();
1762    guint16 group   = Entry->GetGroup();
1763    std::string  vr = Entry->GetVR();
1764    guint32 length  = Entry->GetLength();
1765
1766    // When we have some semantics on the element we just read, and if we
1767    // a priori know we are dealing with an integer, then we shall be
1768    // able to swap it's element value properly.
1769    if ( element == 0 )  // This is the group length of the group
1770    {  
1771       if (length == 4)
1772          return true;
1773       else 
1774       {
1775          std::ostringstream s;
1776          s << "Erroneous Group Length element length  on :" \
1777            << std::hex << group << " , " << element;
1778          dbg.Error("gdcmParser::IsHeaderEntryAnInteger",
1779             s.str().c_str());     
1780       }
1781    }
1782    if ( (vr == "UL") || (vr == "US") || (vr == "SL") || (vr == "SS") )
1783       return true;
1784    
1785    return false;
1786 }
1787
1788 /**
1789  * \ingroup gdcmParser
1790  * \brief   
1791  *
1792  * @return 
1793  */
1794  guint32 gdcmParser::FindHeaderEntryLengthOB(void) 
1795  {
1796    // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
1797    guint16 g;
1798    guint16 n; 
1799    long PositionOnEntry = ftell(fp);
1800    bool FoundSequenceDelimiter = false;
1801    guint32 TotalLength = 0;
1802    guint32 ItemLength;
1803
1804    while ( ! FoundSequenceDelimiter) 
1805    {
1806       g = ReadInt16();
1807       n = ReadInt16();   
1808       if (errno == 1)
1809          return 0;
1810       TotalLength += 4;  // We even have to decount the group and element 
1811      
1812       if ( g != 0xfffe && g!=0xb00c ) /*for bogus header */ 
1813       {
1814          char msg[100]; // for sprintf. Sorry
1815          sprintf(msg,"wrong group (%04x) for an item sequence (%04x,%04x)\n",g, g,n);
1816          dbg.Verbose(1, "gdcmParser::FindLengthOB: ",msg); 
1817          errno = 1;
1818          return 0;
1819       }
1820       if ( n == 0xe0dd || ( g==0xb00c && n==0x0eb6 ) ) /* for bogus header  */ 
1821          FoundSequenceDelimiter = true;
1822       else if ( n != 0xe000 )
1823       {
1824          char msg[100];  // for sprintf. Sorry
1825          sprintf(msg,"wrong element (%04x) for an item sequence (%04x,%04x)\n",
1826                       n, g,n);
1827          dbg.Verbose(1, "gdcmParser::FindLengthOB: ",msg);
1828          errno = 1;
1829          return 0;
1830       }
1831       ItemLength = ReadInt32();
1832       TotalLength += ItemLength + 4;  // We add 4 bytes since we just read
1833                                       // the ItemLength with ReadInt32                                     
1834       SkipBytes(ItemLength);
1835    }
1836    fseek(fp, PositionOnEntry, SEEK_SET);
1837    return TotalLength;
1838 }
1839
1840 /**
1841  * \ingroup gdcmParser
1842  * \brief Reads a supposed to be 16 Bits integer
1843  * \     (swaps it depending on processor endianity) 
1844  *
1845  * @return integer acts as a boolean
1846  */
1847 guint16 gdcmParser::ReadInt16(void) 
1848 {
1849    guint16 g;
1850    size_t item_read;
1851    item_read = fread (&g, (size_t)2,(size_t)1, fp);
1852    if ( item_read != 1 ) 
1853    {
1854       if(ferror(fp)) 
1855          dbg.Verbose(0, "gdcmParser::ReadInt16", " File Error");
1856       errno = 1;
1857       return 0;
1858    }
1859    errno = 0;
1860    g = SwapShort(g);
1861    return g;
1862 }
1863
1864 /**
1865  * \ingroup gdcmParser
1866  * \brief  Reads a supposed to be 32 Bits integer
1867  * \       (swaps it depending on processor endianity)  
1868  *
1869  * @return 
1870  */
1871 guint32 gdcmParser::ReadInt32(void) 
1872 {
1873    guint32 g;
1874    size_t item_read;
1875    item_read = fread (&g, (size_t)4,(size_t)1, fp);
1876    if ( item_read != 1 ) 
1877    { 
1878      if(ferror(fp)) 
1879          dbg.Verbose(0, "gdcmParser::ReadInt32", " File Error");   
1880       errno = 1;
1881       return 0;
1882    }
1883    errno = 0;   
1884    g = SwapLong(g);
1885    return g;
1886 }
1887
1888 /**
1889  * \ingroup gdcmParser
1890  * \brief   
1891  *
1892  * @return 
1893  */
1894 void gdcmParser::SkipBytes(guint32 NBytes) 
1895 {
1896    //FIXME don't dump the returned value
1897    (void)fseek(fp, (long)NBytes, SEEK_CUR);
1898 }
1899
1900 /**
1901  * \ingroup gdcmParser
1902  * \brief   
1903  */
1904 void gdcmParser::Initialise(void) 
1905 {
1906    RefPubDict = gdcmGlobal::GetDicts()->GetDefaultPubDict();
1907    RefShaDict = (gdcmDict*)0;
1908 }
1909
1910 /**
1911  * \ingroup gdcmParser
1912  * \brief   Discover what the swap code is (among little endian, big endian,
1913  *          bad little endian, bad big endian).
1914  *
1915  */
1916 void gdcmParser::CheckSwap()
1917 {
1918    // Fourth semantics:
1919    //
1920    // ---> Warning : This fourth field is NOT part 
1921    //                of the 'official' Dicom Dictionnary
1922    //                and should NOT be used.
1923    //                (Not defined for all the groups
1924    //                 may be removed in a future release)
1925    //
1926    // CMD      Command        
1927    // META     Meta Information 
1928    // DIR      Directory
1929    // ID
1930    // PAT      Patient
1931    // ACQ      Acquisition
1932    // REL      Related
1933    // IMG      Image
1934    // SDY      Study
1935    // VIS      Visit 
1936    // WAV      Waveform
1937    // PRC
1938    // DEV      Device
1939    // NMI      Nuclear Medicine
1940    // MED
1941    // BFS      Basic Film Session
1942    // BFB      Basic Film Box
1943    // BIB      Basic Image Box
1944    // BAB
1945    // IOB
1946    // PJ
1947    // PRINTER
1948    // RT       Radio Therapy
1949    // DVH   
1950    // SSET
1951    // RES      Results
1952    // CRV      Curve
1953    // OLY      Overlays
1954    // PXL      Pixels
1955    // DL       Delimiters
1956    //
1957
1958    // The only guaranted way of finding the swap code is to find a
1959    // group tag since we know it's length has to be of four bytes i.e.
1960    // 0x00000004. Finding the swap code in then straigthforward. Trouble
1961    // occurs when we can't find such group...
1962    guint32  s;
1963    guint32  x=4;  // x : for ntohs
1964    bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
1965     
1966    int lgrLue;
1967    char *entCur;
1968    char deb[HEADER_LENGTH_TO_READ];
1969     
1970    // First, compare HostByteOrder and NetworkByteOrder in order to
1971    // determine if we shall need to swap bytes (i.e. the Endian type).
1972    if (x==ntohs(x))
1973       net2host = true;
1974    else
1975       net2host = false; 
1976     //cout << net2host << endl;
1977          
1978    // The easiest case is the one of a DICOM header, since it possesses a
1979    // file preamble where it suffice to look for the string "DICM".
1980    lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, fp);
1981    
1982    entCur = deb + 128;
1983    if(memcmp(entCur, "DICM", (size_t)4) == 0) 
1984    {
1985       dbg.Verbose(1, "gdcmParser::CheckSwap:", "looks like DICOM Version3");
1986       // Next, determine the value representation (VR). Let's skip to the
1987       // first element (0002, 0000) and check there if we find "UL" 
1988       // - or "OB" if the 1st one is (0002,0001) -,
1989       // in which case we (almost) know it is explicit VR.
1990       // WARNING: if it happens to be implicit VR then what we will read
1991       // is the length of the group. If this ascii representation of this
1992       // length happens to be "UL" then we shall believe it is explicit VR.
1993       // FIXME: in order to fix the above warning, we could read the next
1994       // element value (or a couple of elements values) in order to make
1995       // sure we are not commiting a big mistake.
1996       // We need to skip :
1997       // * the 128 bytes of File Preamble (often padded with zeroes),
1998       // * the 4 bytes of "DICM" string,
1999       // * the 4 bytes of the first tag (0002, 0000),or (0002, 0001)
2000       // i.e. a total of  136 bytes.
2001       entCur = deb + 136;
2002       // FIXME
2003       // Use gdcmParser::dicom_vr to test all the possibilities
2004       // instead of just checking for UL, OB and UI !?
2005       if(  (memcmp(entCur, "UL", (size_t)2) == 0) ||
2006           (memcmp(entCur, "OB", (size_t)2) == 0) ||
2007           (memcmp(entCur, "UI", (size_t)2) == 0) )   
2008       {
2009          filetype = ExplicitVR;
2010          dbg.Verbose(1, "gdcmParser::CheckSwap:",
2011                      "explicit Value Representation");
2012       } 
2013       else 
2014       {
2015          filetype = ImplicitVR;
2016          dbg.Verbose(1, "gdcmParser::CheckSwap:",
2017                      "not an explicit Value Representation");
2018       }
2019       if (net2host) 
2020       {
2021          sw = 4321;
2022          dbg.Verbose(1, "gdcmParser::CheckSwap:",
2023                         "HostByteOrder != NetworkByteOrder");
2024       } 
2025       else 
2026       {
2027          sw = 0;
2028          dbg.Verbose(1, "gdcmParser::CheckSwap:",
2029                         "HostByteOrder = NetworkByteOrder");
2030       }
2031       
2032       // Position the file position indicator at first tag (i.e.
2033       // after the file preamble and the "DICM" string).
2034       rewind(fp);
2035       fseek (fp, 132L, SEEK_SET);
2036       return;
2037    } // End of DicomV3
2038
2039    // Alas, this is not a DicomV3 file and whatever happens there is no file
2040    // preamble. We can reset the file position indicator to where the data
2041    // is (i.e. the beginning of the file).
2042    dbg.Verbose(1, "gdcmParser::CheckSwap:", "not a DICOM Version3 file");
2043    rewind(fp);
2044
2045    // Our next best chance would be to be considering a 'clean' ACR/NEMA file.
2046    // By clean we mean that the length of the first tag is written down.
2047    // If this is the case and since the length of the first group HAS to be
2048    // four (bytes), then determining the proper swap code is straightforward.
2049
2050    entCur = deb + 4;
2051    // We assume the array of char we are considering contains the binary
2052    // representation of a 32 bits integer. Hence the following dirty
2053    // trick :
2054    s = *((guint32 *)(entCur));
2055    
2056    switch (s)
2057    {
2058       case 0x00040000 :
2059          sw = 3412;
2060          filetype = ACR;
2061          return;
2062       case 0x04000000 :
2063          sw = 4321;
2064          filetype = ACR;
2065          return;
2066       case 0x00000400 :
2067          sw = 2143;
2068          filetype = ACR;
2069          return;
2070       case 0x00000004 :
2071          sw = 0;
2072          filetype = ACR;
2073          return;
2074       default :
2075          dbg.Verbose(0, "gdcmParser::CheckSwap:",
2076                         "ACR/NEMA unfound swap info (time to raise bets)");
2077    }
2078
2079    // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file.
2080    // It is time for despaired wild guesses. So, let's assume this file
2081    // happens to be 'dirty' ACR/NEMA, i.e. the length of the group is
2082    // not present. Then the only info we have is the net2host one.
2083    filetype = Unknown;
2084    if (! net2host )
2085       sw = 0;
2086    else
2087       sw = 4321;
2088    return;
2089 }
2090
2091 /**
2092  * \ingroup gdcmParser
2093  * \brief   
2094  */
2095 void gdcmParser::SwitchSwapToBigEndian(void) 
2096 {
2097    dbg.Verbose(1, "gdcmParser::SwitchSwapToBigEndian",
2098                   "Switching to BigEndian mode.");
2099    if ( sw == 0    ) 
2100    {
2101       sw = 4321;
2102       return;
2103    }
2104    if ( sw == 4321 ) 
2105    {
2106       sw = 0;
2107       return;
2108    }
2109    if ( sw == 3412 ) 
2110    {
2111       sw = 2143;
2112       return;
2113    }
2114    if ( sw == 2143 )
2115       sw = 3412;
2116 }
2117
2118 /**
2119  * \ingroup gdcmParser
2120  * \brief   
2121  * @param NewSize
2122  * @return 
2123  */
2124 void gdcmParser::SetMaxSizeLoadEntry(long NewSize) 
2125 {
2126    if (NewSize < 0)
2127       return;
2128    if ((guint32)NewSize >= (guint32)0xffffffff) 
2129    {
2130       MaxSizeLoadEntry = 0xffffffff;
2131       return;
2132    }
2133    MaxSizeLoadEntry = NewSize;
2134 }
2135
2136 /**
2137  * \ingroup gdcmParser
2138  * \brief   Searches both the public and the shadow dictionary (when they
2139  *          exist) for the presence of the DictEntry with given name.
2140  *          The public dictionary has precedence on the shadow one.
2141  * @param   Name name of the searched DictEntry
2142  * @return  Corresponding DictEntry when it exists, NULL otherwise.
2143  */
2144 gdcmDictEntry *gdcmParser::GetDictEntryByName(std::string Name) 
2145 {
2146    gdcmDictEntry *found = (gdcmDictEntry *)0;
2147    if (!RefPubDict && !RefShaDict) 
2148    {
2149       dbg.Verbose(0, "gdcmParser::GetDictEntry",
2150                      "we SHOULD have a default dictionary");
2151    }
2152    if (RefPubDict) 
2153    {
2154       found = RefPubDict->GetDictEntryByName(Name);
2155       if (found)
2156          return found;
2157    }
2158    if (RefShaDict) 
2159    {
2160       found = RefShaDict->GetDictEntryByName(Name);
2161       if (found)
2162          return found;
2163    }
2164    return found;
2165 }
2166
2167 /**
2168  * \ingroup gdcmParser
2169  * \brief   Searches both the public and the shadow dictionary (when they
2170  *          exist) for the presence of the DictEntry with given
2171  *          group and element. The public dictionary has precedence on the
2172  *          shadow one.
2173  * @param   group   group of the searched DictEntry
2174  * @param   element element of the searched DictEntry
2175  * @return  Corresponding DictEntry when it exists, NULL otherwise.
2176  */
2177 gdcmDictEntry *gdcmParser::GetDictEntryByNumber(guint16 group,guint16 element) 
2178 {
2179    gdcmDictEntry *found = (gdcmDictEntry *)0;
2180    if (!RefPubDict && !RefShaDict) 
2181    {
2182       dbg.Verbose(0, "gdcmParser::GetDictEntry",
2183                      "we SHOULD have a default dictionary");
2184    }
2185    if (RefPubDict) 
2186    {
2187       found = RefPubDict->GetDictEntryByNumber(group, element);
2188       if (found)
2189          return found;
2190    }
2191    if (RefShaDict) 
2192    {
2193       found = RefShaDict->GetDictEntryByNumber(group, element);
2194       if (found)
2195          return found;
2196    }
2197    return found;
2198 }
2199
2200 /**
2201  * \ingroup gdcmParser
2202  * \brief   Read the next tag but WITHOUT loading it's value
2203  * @return  On succes the newly created HeaderEntry, NULL on failure.      
2204  */
2205 gdcmHeaderEntry *gdcmParser::ReadNextHeaderEntry(void) 
2206 {
2207    guint16 g,n;
2208    gdcmHeaderEntry *NewEntry;
2209    
2210    g = ReadInt16();
2211    n = ReadInt16();
2212       
2213    if (errno == 1)
2214       // We reached the EOF (or an error occured) and header parsing
2215       // has to be considered as finished.
2216       return (gdcmHeaderEntry *)0;
2217    
2218    NewEntry = NewHeaderEntryByNumber(g, n);
2219    FindHeaderEntryVR(NewEntry);
2220    FindHeaderEntryLength(NewEntry);
2221         
2222    if (errno == 1) 
2223    {
2224       // Call it quits
2225       return NULL;
2226    }
2227    NewEntry->SetOffset(ftell(fp));  
2228    //if ( (g==0x7fe0) && (n==0x0010) ) 
2229    return NewEntry;
2230 }
2231
2232 /**
2233  * \ingroup gdcmParser
2234  * \brief   Build a new Element Value from all the low level arguments. 
2235  *          Check for existence of dictionary entry, and build
2236  *          a default one when absent.
2237  * @param   Name    Name of the underlying DictEntry
2238  */
2239 gdcmHeaderEntry *gdcmParser::NewHeaderEntryByName(std::string Name) 
2240 {
2241    gdcmDictEntry *NewTag = GetDictEntryByName(Name);
2242    if (!NewTag)
2243       NewTag = NewVirtualDictEntry(0xffff, 0xffff, "LO", "Unknown", Name);
2244
2245    gdcmHeaderEntry* NewEntry = new gdcmHeaderEntry(NewTag);
2246    if (!NewEntry) 
2247    {
2248       dbg.Verbose(1, "gdcmParser::ObtainHeaderEntryByName",
2249                   "failed to allocate gdcmHeaderEntry");
2250       return (gdcmHeaderEntry *)0;
2251    }
2252    return NewEntry;
2253 }  
2254
2255 /**
2256  * \ingroup gdcmParser
2257  * \brief   Request a new virtual dict entry to the dict set
2258  * @param   group  group   of the underlying DictEntry
2259  * @param   elem   element of the underlying DictEntry
2260  * @param   vr     VR of the underlying DictEntry
2261  * @param   fourth owner group
2262  * @param   name   english name
2263  */
2264 gdcmDictEntry *gdcmParser::NewVirtualDictEntry(guint16 group, guint16 element,
2265                                                std::string vr,
2266                                                std::string fourth,
2267                                                std::string name)
2268 {
2269    return gdcmGlobal::GetDicts()->NewVirtualDictEntry(group,element,vr,fourth,name);
2270 }
2271
2272 /**
2273  * \ingroup gdcmParser
2274  * \brief   Build a new Element Value from all the low level arguments. 
2275  *          Check for existence of dictionary entry, and build
2276  *          a default one when absent.
2277  * @param   Group group   of the underlying DictEntry
2278  * @param   Elem  element of the underlying DictEntry
2279  */
2280 gdcmHeaderEntry *gdcmParser::NewHeaderEntryByNumber(guint16 Group, guint16 Elem) 
2281 {
2282    // Find out if the tag we encountered is in the dictionaries:
2283    gdcmDictEntry *DictEntry = GetDictEntryByNumber(Group, Elem);
2284    if (!DictEntry)
2285       DictEntry = NewVirtualDictEntry(Group, Elem);
2286
2287    gdcmHeaderEntry *NewEntry = new gdcmHeaderEntry(DictEntry);
2288    if (!NewEntry) 
2289    {
2290       dbg.Verbose(1, "gdcmParser::NewHeaderEntryByNumber",
2291                   "failed to allocate gdcmHeaderEntry");
2292       return NULL;
2293    }
2294    return NewEntry;
2295 }
2296
2297 /**
2298  * \ingroup gdcmParser
2299  * \brief   Small utility function that creates a new manually crafted
2300  *          (as opposed as read from the file) gdcmHeaderEntry with user
2301  *          specified name and adds it to the public tag hash table.
2302  * \note    A fake TagKey is generated so the PubDict can keep it's coherence.
2303  * @param   NewTagName The name to be given to this new tag.
2304  * @param   VR The Value Representation to be given to this new tag.
2305  * @return  The newly hand crafted Element Value.
2306  */
2307 gdcmHeaderEntry *gdcmParser::NewManualHeaderEntryToPubDict(std::string NewTagName, 
2308                                                            std::string VR) 
2309 {
2310    gdcmHeaderEntry *NewEntry = NULL;
2311    guint32 StuffGroup = 0xffff;   // Group to be stuffed with additional info
2312    guint32 FreeElem = 0;
2313    gdcmDictEntry *DictEntry = NULL;
2314
2315    FreeElem = GenerateFreeTagKeyInGroup(StuffGroup);
2316    if (FreeElem == UINT32_MAX) 
2317    {
2318       dbg.Verbose(1, "gdcmHeader::NewManualHeaderEntryToPubDict",
2319                      "Group 0xffff in Public Dict is full");
2320       return NULL;
2321    }
2322
2323    DictEntry = NewVirtualDictEntry(StuffGroup, FreeElem,
2324                                 VR, "GDCM", NewTagName);
2325    NewEntry = new gdcmHeaderEntry(DictEntry);
2326    AddHeaderEntry(NewEntry);
2327    return NewEntry;
2328 }
2329
2330 /**
2331  * \ingroup gdcmParser
2332  * \brief   Generate a free TagKey i.e. a TagKey that is not present
2333  *          in the TagHt dictionary.
2334  * @param   group The generated tag must belong to this group.  
2335  * @return  The element of tag with given group which is fee.
2336  */
2337 guint32 gdcmParser::GenerateFreeTagKeyInGroup(guint16 group) 
2338 {
2339    for (guint32 elem = 0; elem < UINT32_MAX; elem++) 
2340    {
2341       TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
2342       if (tagHT.count(key) == 0)
2343          return elem;
2344    }
2345    return UINT32_MAX;
2346 }
2347
2348 //-----------------------------------------------------------------------------