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