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