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