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