]> Creatis software - gdcm.git/blob - src/gdcmHeader.cxx
82c31a0fa29d00f8664537d6cf6ff56c9df250d0
[gdcm.git] / src / gdcmHeader.cxx
1 // gdcmHeader.cxx
2
3 #include <stdio.h>
4 #include <cerrno>
5 // For nthos:
6 #ifdef _MSC_VER
7 #include <winsock.h>
8 #else
9 #include <netinet/in.h>
10 #endif
11 #include <cctype>    // for isalpha
12 #include <sstream>
13 #include "gdcmUtil.h"
14 #include "gdcmHeader.h"
15
16 // Refer to gdcmHeader::CheckSwap()
17 #define HEADER_LENGTH_TO_READ       256
18 // Refer to gdcmHeader::SetMaxSizeLoadElementValue()
19 #define _MaxSizeLoadElementValue_   1024
20
21 gdcmVR * gdcmHeader::dicom_vr = (gdcmVR*)0;
22 gdcmDictSet * gdcmHeader::Dicts    = (gdcmDictSet*)0;
23
24 void gdcmHeader::Initialise(void) {
25    if (!gdcmHeader::dicom_vr)
26       gdcmHeader::dicom_vr = gdcmGlobal::GetVR();
27    if (!gdcmHeader::Dicts)
28       gdcmHeader::Dicts = gdcmGlobal::GetDicts();
29    RefPubDict = Dicts->GetDefaultPubDict();
30    RefShaDict = (gdcmDict*)0;
31 }
32
33 gdcmHeader::gdcmHeader(const char *InFilename, bool exception_on_error) {
34   SetMaxSizeLoadElementValue(_MaxSizeLoadElementValue_);
35   filename = InFilename;
36   Initialise();
37   OpenFile(exception_on_error);
38   ParseHeader();
39   LoadElements();
40   CloseFile();
41 }
42
43 bool gdcmHeader::OpenFile(bool exception_on_error)
44   throw(gdcmFileError) {
45   fp=fopen(filename.c_str(),"rb");
46   if(exception_on_error) {
47     if(!fp)
48       throw gdcmFileError("gdcmHeader::gdcmHeader(const char *, bool)");
49   }
50   else
51     dbg.Error(!fp, "gdcmHeader::gdcmHeader cannot open file", filename.c_str());
52   if ( fp )
53      return true;
54   return false;
55 }
56
57 bool gdcmHeader::CloseFile(void) {
58   int closed = fclose(fp);
59   fp = (FILE *)0;
60   if (! closed)
61      return false;
62   return true;
63 }
64
65 gdcmHeader::~gdcmHeader (void) {
66    dicom_vr = (gdcmVR*)0;
67    Dicts    = (gdcmDictSet*)0;
68    RefPubDict = (gdcmDict*)0;
69    RefShaDict = (gdcmDict*)0;
70    return;
71 }
72
73 // Fourth semantics:
74 // CMD      Command        
75 // META     Meta Information 
76 // DIR      Directory
77 // ID
78 // PAT      Patient
79 // ACQ      Acquisition
80 // REL      Related
81 // IMG      Image
82 // SDY      Study
83 // VIS      Visit 
84 // WAV      Waveform
85 // PRC
86 // DEV      Device
87 // NMI      Nuclear Medicine
88 // MED
89 // BFS      Basic Film Session
90 // BFB      Basic Film Box
91 // BIB      Basic Image Box
92 // BAB
93 // IOB
94 // PJ
95 // PRINTER
96 // RT       Radio Therapy
97 // DVH   
98 // SSET
99 // RES      Results
100 // CRV      Curve
101 // OLY      Overlays
102 // PXL      Pixels
103 //
104
105 /**
106  * \ingroup gdcmHeader
107  * \brief   Discover what the swap code is (among little endian, big endian,
108  *          bad little endian, bad big endian).
109  *
110  */
111 void gdcmHeader::CheckSwap()
112 {
113    // The only guaranted way of finding the swap code is to find a
114    // group tag since we know it's length has to be of four bytes i.e.
115    // 0x00000004. Finding the swap code in then straigthforward. Trouble
116    // occurs when we can't find such group...
117    guint32  s;
118    guint32  x=4;  // x : pour ntohs
119    bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
120     
121    int lgrLue;
122    char * entCur;
123    char deb[HEADER_LENGTH_TO_READ];
124     
125    // First, compare HostByteOrder and NetworkByteOrder in order to
126    // determine if we shall need to swap bytes (i.e. the Endian type).
127    if (x==ntohs(x))
128       net2host = true;
129    else
130       net2host = false;
131    
132    // The easiest case is the one of a DICOM header, since it possesses a
133    // file preamble where it suffice to look for the string "DICM".
134    lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, fp);
135    
136    entCur = deb + 128;
137    if(memcmp(entCur, "DICM", (size_t)4) == 0) {
138       dbg.Verbose(1, "gdcmHeader::CheckSwap:", "looks like DICOM Version3");
139       // Next, determine the value representation (VR). Let's skip to the
140       // first element (0002, 0000) and check there if we find "UL" 
141       // - or "OB" if the 1st one is (0002,0001) -,
142       // in which case we (almost) know it is explicit VR.
143       // WARNING: if it happens to be implicit VR then what we will read
144       // is the length of the group. If this ascii representation of this
145       // length happens to be "UL" then we shall believe it is explicit VR.
146       // FIXME: in order to fix the above warning, we could read the next
147       // element value (or a couple of elements values) in order to make
148       // sure we are not commiting a big mistake.
149       // We need to skip :
150       // * the 128 bytes of File Preamble (often padded with zeroes),
151       // * the 4 bytes of "DICM" string,
152       // * the 4 bytes of the first tag (0002, 0000),or (0002, 0001)
153       // i.e. a total of  136 bytes.
154       entCur = deb + 136;
155       // FIXME
156       // Use gdcmHeader::dicom_vr to test all the possibilities
157       // instead of just checking for UL, OB and UI !?
158       if(  (memcmp(entCur, "UL", (size_t)2) == 0) ||
159           (memcmp(entCur, "OB", (size_t)2) == 0) ||
160           (memcmp(entCur, "UI", (size_t)2) == 0) )
161         {
162          filetype = ExplicitVR;
163          dbg.Verbose(1, "gdcmHeader::CheckSwap:",
164                      "explicit Value Representation");
165       } else {
166          filetype = ImplicitVR;
167          dbg.Verbose(1, "gdcmHeader::CheckSwap:",
168                      "not an explicit Value Representation");
169       }
170
171       if (net2host) {
172          sw = 4321;
173          dbg.Verbose(1, "gdcmHeader::CheckSwap:",
174                         "HostByteOrder != NetworkByteOrder");
175       } else {
176          sw = 0;
177          dbg.Verbose(1, "gdcmHeader::CheckSwap:",
178                         "HostByteOrder = NetworkByteOrder");
179       }
180       
181       // Position the file position indicator at first tag (i.e.
182       // after the file preamble and the "DICM" string).
183       rewind(fp);
184       fseek (fp, 132L, SEEK_SET);
185       return;
186    } // End of DicomV3
187
188    // Alas, this is not a DicomV3 file and whatever happens there is no file
189    // preamble. We can reset the file position indicator to where the data
190    // is (i.e. the beginning of the file).
191     dbg.Verbose(1, "gdcmHeader::CheckSwap:", "not a DICOM Version3 file");
192    rewind(fp);
193
194    // Our next best chance would be to be considering a 'clean' ACR/NEMA file.
195    // By clean we mean that the length of the first tag is written down.
196    // If this is the case and since the length of the first group HAS to be
197    // four (bytes), then determining the proper swap code is straightforward.
198
199    entCur = deb + 4;
200    // We assume the array of char we are considering contains the binary
201    // representation of a 32 bits integer. Hence the following dirty
202    // trick :
203    s = *((guint32 *)(entCur));
204    
205    switch (s) {
206    case 0x00040000 :
207       sw = 3412;
208       filetype = ACR;
209       return;
210    case 0x04000000 :
211       sw = 4321;
212       filetype = ACR;
213       return;
214    case 0x00000400 :
215       sw = 2143;
216       filetype = ACR;
217       return;
218    case 0x00000004 :
219       sw = 0;
220       filetype = ACR;
221       return;
222    default :
223       dbg.Verbose(0, "gdcmHeader::CheckSwap:",
224                      "ACR/NEMA unfound swap info (time to raise bets)");
225    }
226
227    // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file.
228    // It is time for despaired wild guesses. So, let's assume this file
229    // happens to be 'dirty' ACR/NEMA, i.e. the length of the group is
230    // not present. Then the only info we have is the net2host one.
231    filetype = Unknown;
232    if (! net2host )
233       sw = 0;
234    else
235       sw = 4321;
236    return;
237 }
238
239 void gdcmHeader::SwitchSwapToBigEndian(void) {
240    dbg.Verbose(1, "gdcmHeader::SwitchSwapToBigEndian",
241                   "Switching to BigEndian mode.");
242    if ( sw == 0    ) {
243       sw = 4321;
244       return;
245    }
246    if ( sw == 4321 ) {
247       sw = 0;
248       return;
249    }
250    if ( sw == 3412 ) {
251       sw = 2143;
252       return;
253    }
254    if ( sw == 2143 )
255       sw = 3412;
256 }
257
258 /**
259  * \ingroup   gdcmHeader
260  * \brief     Find the value representation of the current tag.
261  */
262 void gdcmHeader::FindVR( gdcmElValue *ElVal) {
263    if (filetype != ExplicitVR)
264       return;
265
266    char VR[3];
267    string vr;
268    int lgrLue;
269    long PositionOnEntry = ftell(fp);
270    // Warning: we believe this is explicit VR (Value Representation) because
271    // we used a heuristic that found "UL" in the first tag. Alas this
272    // doesn't guarantee that all the tags will be in explicit VR. In some
273    // cases (see e-film filtered files) one finds implicit VR tags mixed
274    // within an explicit VR file. Hence we make sure the present tag
275    // is in explicit VR and try to fix things if it happens not to be
276    // the case.
277    bool RealExplicit = true;
278    
279    lgrLue=fread (&VR, (size_t)2,(size_t)1, fp);
280    VR[2]=0;
281    vr = string(VR);
282       
283    // Assume we are reading a falsely explicit VR file i.e. we reached
284    // a tag where we expect reading a VR but are in fact we read the
285    // first to bytes of the length. Then we will interogate (through find)
286    // the dicom_vr dictionary with oddities like "\004\0" which crashes
287    // both GCC and VC++ implementations of the STL map. Hence when the
288    // expected VR read happens to be non-ascii characters we consider
289    // we hit falsely explicit VR tag.
290
291    if ( (!isalpha(VR[0])) && (!isalpha(VR[1])) )
292       RealExplicit = false;
293
294    // CLEANME searching the dicom_vr at each occurence is expensive.
295    // PostPone this test in an optional integrity check at the end
296    // of parsing or only in debug mode.
297    if ( RealExplicit && !dicom_vr->Count(vr) )
298       RealExplicit= false;
299
300    if ( RealExplicit ) {
301       if ( ElVal->IsVrUnknown() ) {
302          // When not a dictionary entry, we can safely overwrite the vr.
303          ElVal->SetVR(vr);
304          return; 
305       }
306       if ( ElVal->GetVR() == vr ) {
307          // The vr we just read and the dictionary agree. Nothing to do.
308          return;
309       }
310       // The vr present in the file and the dictionary disagree. We assume
311       // the file writer knew best and use the vr of the file. Since it would
312       // be unwise to overwrite the vr of a dictionary (since it would
313       // compromise it's next user), we need to clone the actual DictEntry
314       // and change the vr for the read one.
315       gdcmDictEntry* NewTag = new gdcmDictEntry(ElVal->GetGroup(),
316                                  ElVal->GetElement(),
317                                  vr,
318                                  "FIXME",
319                                  ElVal->GetName());
320       ElVal->SetDictEntry(NewTag);
321       return; 
322    }
323    
324    // We thought this was explicit VR, but we end up with an
325    // implicit VR tag. Let's backtrack.
326    dbg.Verbose(1, "gdcmHeader::FindVR:", "Falsely explicit vr file");
327    fseek(fp, PositionOnEntry, SEEK_SET);
328    // When this element is known in the dictionary we shall use, e.g. for
329    // the semantics (see  the usage of IsAnInteger), the vr proposed by the
330    // dictionary entry. Still we have to flag the element as implicit since
331    // we know now our assumption on expliciteness is not furfilled.
332    // avoid  .
333    if ( ElVal->IsVrUnknown() )
334       ElVal->SetVR("Implicit");
335    ElVal->SetImplicitVr();
336 }
337
338 /**
339  * \ingroup gdcmHeader
340  * \brief   Determines if the Transfer Syntax was allready encountered
341  *          and if it corresponds to a ImplicitVRLittleEndian one.
342  *
343  * @return  True when ImplicitVRLittleEndian found. False in all other cases.
344  */
345 bool gdcmHeader::IsImplicitVRLittleEndianTransferSyntax(void) {
346    gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
347    if ( !Element )
348       return false;
349    LoadElementValueSafe(Element);
350    string Transfer = Element->GetValue();
351    if ( Transfer == "1.2.840.10008.1.2" )
352       return true;
353    return false;
354 }
355
356 /**
357  * \ingroup gdcmHeader
358  * \brief   Determines if the Transfer Syntax was allready encountered
359  *          and if it corresponds to a ExplicitVRLittleEndian one.
360  *
361  * @return  True when ExplicitVRLittleEndian found. False in all other cases.
362  */
363 bool gdcmHeader::IsExplicitVRLittleEndianTransferSyntax(void) {
364    gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
365    if ( !Element )
366       return false;
367    LoadElementValueSafe(Element);
368    string Transfer = Element->GetValue();
369    if ( Transfer == "1.2.840.10008.1.2.1" )
370       return true;
371    return false;
372 }
373
374 /**
375  * \ingroup gdcmHeader
376  * \brief   Determines if the Transfer Syntax was allready encountered
377  *          and if it corresponds to a DeflatedExplicitVRLittleEndian one.
378  *
379  * @return  True when DeflatedExplicitVRLittleEndian found. False in all other cases.
380  */
381 bool gdcmHeader::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) {
382    gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
383    if ( !Element )
384       return false;
385    LoadElementValueSafe(Element);
386    string Transfer = Element->GetValue();
387    if ( Transfer == "1.2.840.10008.1.2.1.99" )
388       return true;
389    return false;
390 }
391
392 /**
393  * \ingroup gdcmHeader
394  * \brief   Determines if the Transfer Syntax was allready encountered
395  *          and if it corresponds to a Explicit VR Big Endian one.
396  *
397  * @return  True when big endian found. False in all other cases.
398  */
399 bool gdcmHeader::IsExplicitVRBigEndianTransferSyntax(void) {
400    gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
401    if ( !Element )
402       return false;
403    LoadElementValueSafe(Element);
404    string Transfer = Element->GetValue();
405    if ( Transfer == "1.2.840.10008.1.2.2" )  //1.2.2 ??? A verifier !
406       return true;
407    return false;
408 }
409
410 /**
411  * \ingroup gdcmHeader
412  * \brief   Determines if the Transfer Syntax was allready encountered
413  *          and if it corresponds to a JPEGBaseLineProcess1 one.
414  *
415  * @return  True when JPEGBaseLineProcess1found. False in all other cases.
416  */
417 bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) {
418    gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
419    if ( !Element )
420       return false;
421    LoadElementValueSafe(Element);
422    string Transfer = Element->GetValue();
423    if ( Transfer == "1.2.840.10008.1.2.4.50" )
424       return true;
425    return false;
426 }
427
428 // faire qq chose d'intelligent a la place de Ã§a
429
430 bool gdcmHeader::IsJPEGLossless(void) {
431    gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
432    if ( !Element )
433       return false;
434    LoadElementValueSafe(Element);
435    const char * Transfert = Element->GetValue().c_str();
436    if ( memcmp(Transfert+strlen(Transfert)-2 ,"70",2)==0) return true;
437    if ( memcmp(Transfert+strlen(Transfert)-2 ,"55",2)==0) return true;
438    return false;
439 }
440
441
442 /**
443  * \ingroup gdcmHeader
444  * \brief   Determines if the Transfer Syntax was allready encountered
445  *          and if it corresponds to a JPEGExtendedProcess2-4 one.
446  *
447  * @return  True when JPEGExtendedProcess2-4 found. False in all other cases.
448  */
449 bool gdcmHeader::IsJPEGExtendedProcess2_4TransferSyntax(void) {
450    gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
451    if ( !Element )
452       return false;
453    LoadElementValueSafe(Element);
454    string Transfer = Element->GetValue();
455    if ( Transfer == "1.2.840.10008.1.2.4.51" )
456       return true;
457    return false;
458 }
459
460 /**
461  * \ingroup gdcmHeader
462  * \brief   Determines if the Transfer Syntax was allready encountered
463  *          and if it corresponds to a JPEGExtendeProcess3-5 one.
464  *
465  * @return  True when JPEGExtendedProcess3-5 found. False in all other cases.
466  */
467 bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) {
468    gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
469    if ( !Element )
470       return false;
471    LoadElementValueSafe(Element);
472    string Transfer = Element->GetValue();
473    if ( Transfer == "1.2.840.10008.1.2.4.52" )
474       return true;
475    return false;
476 }
477
478 /**
479  * \ingroup gdcmHeader
480  * \brief   Determines if the Transfer Syntax was allready encountered
481  *          and if it corresponds to a JPEGSpectralSelectionProcess6-8 one.
482  *
483  * @return  True when JPEGSpectralSelectionProcess6-8 found. False in all
484  *          other cases.
485  */
486 bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) {
487    gdcmElValue* Element = PubElValSet.GetElementByNumber(0x0002, 0x0010);
488    if ( !Element )
489       return false;
490    LoadElementValueSafe(Element);
491    string Transfer = Element->GetValue();
492    if ( Transfer == "1.2.840.10008.1.2.4.53" )
493       return true;
494    return false;
495 }
496 /**
497  * \ingroup gdcmHeader
498  * \brief   Predicate for dicom version 3 file.
499  * @return  True when the file is a dicom version 3.
500  */
501 bool gdcmHeader::IsDicomV3(void) {
502    if (   (filetype == ExplicitVR)
503        || (filetype == ImplicitVR) )
504       return true;
505    return false;
506 }
507
508 /**
509  * \ingroup gdcmHeader
510  * \brief   When the length of an element value is obviously wrong (because
511  *          the parser went Jabberwocky) one can hope improving things by
512  *          applying this heuristic.
513  */
514 void gdcmHeader::FixFoundLength(gdcmElValue * ElVal, guint32 FoundLength) {
515    if ( FoundLength == 0xffffffff)
516       FoundLength = 0;
517    ElVal->SetLength(FoundLength);
518 }
519
520 guint32 gdcmHeader::FindLengthOB(void) {
521    // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
522    guint16 g;
523    guint16 n; 
524    long PositionOnEntry = ftell(fp);
525    bool FoundSequenceDelimiter = false;
526    guint32 TotalLength = 0;
527    guint32 ItemLength;
528
529    while ( ! FoundSequenceDelimiter) {
530       g = ReadInt16();
531       n = ReadInt16();
532       if (errno == 1)
533          return 0;
534       TotalLength += 4;  // We even have to decount the group and element 
535       if ( g != 0xfffe ) {
536          dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",
537                      "wrong group for an item sequence.");
538          errno = 1;
539          return 0;
540       }
541       if ( n == 0xe0dd )
542          FoundSequenceDelimiter = true;
543       else if ( n != 0xe000) {
544          dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",
545                      "wrong element for an item sequence.");
546          errno = 1;
547          return 0;
548       }
549       ItemLength = ReadInt32();
550       TotalLength += ItemLength + 4;  // We add 4 bytes since we just read
551                                       // the ItemLength with ReadInt32
552       SkipBytes(ItemLength);
553    }
554    fseek(fp, PositionOnEntry, SEEK_SET);
555    return TotalLength;
556 }
557
558 void gdcmHeader::FindLength(gdcmElValue * ElVal) {
559    guint16 element = ElVal->GetElement();
560    string  vr      = ElVal->GetVR();
561    guint16 length16;
562    
563    if ( (filetype == ExplicitVR) && ! ElVal->IsImplicitVr() ) {
564
565       if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) {
566          // The following reserved two bytes (see PS 3.5-2001, section
567          // 7.1.2 Data element structure with explicit vr p27) must be
568          // skipped before proceeding on reading the length on 4 bytes.
569          fseek(fp, 2L, SEEK_CUR);
570          guint32 length32 = ReadInt32();
571          if ( (vr == "OB") && (length32 == 0xffffffff) ) {
572             ElVal->SetLength(FindLengthOB());
573             return;
574          }
575          FixFoundLength(ElVal, length32);
576          return;
577       }
578
579       // Length is encoded on 2 bytes.
580       length16 = ReadInt16();
581       
582       // We can tell the current file is encoded in big endian (like
583       // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag
584       // and it's value is the one of the encoding of a big endian file.
585       // In order to deal with such big endian encoded files, we have
586       // (at least) two strategies:
587       // * when we load the "Transfer Syntax" tag with value of big endian
588       //   encoding, we raise the proper flags. Then we wait for the end
589       //   of the META group (0x0002) among which is "Transfer Syntax",
590       //   before switching the swap code to big endian. We have to postpone
591       //   the switching of the swap code since the META group is fully encoded
592       //   in little endian, and big endian coding only starts at the next
593       //   group. The corresponding code can be hard to analyse and adds
594       //   many additional unnecessary tests for regular tags.
595       // * the second strategy consists in waiting for trouble, that shall
596       //   appear when we find the first group with big endian encoding. This
597       //   is easy to detect since the length of a "Group Length" tag (the
598       //   ones with zero as element number) has to be of 4 (0x0004). When we
599       //   encouter 1024 (0x0400) chances are the encoding changed and we
600       //   found a group with big endian encoding.
601       // We shall use this second strategy. In order to make sure that we
602       // can interpret the presence of an apparently big endian encoded
603       // length of a "Group Length" without committing a big mistake, we
604       // add an additional check: we look in the allready parsed elements
605       // for the presence of a "Transfer Syntax" whose value has to be "big
606       // endian encoding". When this is the case, chances are we have got our
607       // hands on a big endian encoded file: we switch the swap code to
608       // big endian and proceed...
609       if ( (element  == 0x000) && (length16 == 0x0400) ) {
610          if ( ! IsExplicitVRBigEndianTransferSyntax() ) {
611             dbg.Verbose(0, "gdcmHeader::FindLength", "not explicit VR");
612             errno = 1;
613             return;
614          }
615          length16 = 4;
616          SwitchSwapToBigEndian();
617          // Restore the unproperly loaded values i.e. the group, the element
618          // and the dictionary entry depending on them.
619          guint16 CorrectGroup   = SwapShort(ElVal->GetGroup());
620          guint16 CorrectElem    = SwapShort(ElVal->GetElement());
621          gdcmDictEntry * NewTag = GetDictEntryByNumber(CorrectGroup,
622                                                        CorrectElem);
623          if (!NewTag) {
624             // This correct tag is not in the dictionary. Create a new one.
625             NewTag = new gdcmDictEntry(CorrectGroup, CorrectElem);
626          }
627          // FIXME this can create a memory leaks on the old entry that be
628          // left unreferenced.
629          ElVal->SetDictEntry(NewTag);
630       }
631        
632       // Heuristic: well some files are really ill-formed.
633       if ( length16 == 0xffff) {
634          length16 = 0;
635          dbg.Verbose(0, "gdcmHeader::FindLength",
636                      "Erroneous element length fixed.");
637       }
638       FixFoundLength(ElVal, (guint32)length16);
639       return;
640    }
641
642    // Either implicit VR or a non DICOM conformal (see not below) explicit
643    // VR that ommited the VR of (at least) this element. Farts happen.
644    // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25
645    // on Data elements "Implicit and Explicit VR Data Elements shall
646    // not coexist in a Data Set and Data Sets nested within it".]
647    // Length is on 4 bytes.
648    FixFoundLength(ElVal, ReadInt32());
649 }
650
651 /**
652  * \ingroup gdcmHeader
653  * \brief   Swaps back the bytes of 4-byte long integer accordingly to
654  *          processor order.
655  *
656  * @return  The suggested integer.
657  */
658 guint32 gdcmHeader::SwapLong(guint32 a) {
659    switch (sw) {
660    case    0 :
661       break;
662    case 4321 :
663       a=(   ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000)    | 
664             ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
665       break;
666    
667    case 3412 :
668       a=(   ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
669       break;
670    
671    case 2143 :
672       a=(    ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
673       break;
674    default :
675       dbg.Error(" gdcmHeader::SwapLong : unset swap code");
676       a=0;
677    }
678    return(a);
679 }
680
681 /**
682  * \ingroup gdcmHeader
683  * \brief   Swaps the bytes so they agree with the processor order
684  * @return  The properly swaped 16 bits integer.
685  */
686 guint16 gdcmHeader::SwapShort(guint16 a) {
687    if ( (sw==4321)  || (sw==2143) )
688       a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff));
689    return (a);
690 }
691
692 void gdcmHeader::SkipBytes(guint32 NBytes) {
693    //FIXME don't dump the returned value
694    (void)fseek(fp, (long)NBytes, SEEK_CUR);
695 }
696
697 void gdcmHeader::SkipElementValue(gdcmElValue * ElVal) {
698    SkipBytes(ElVal->GetLength());
699 }
700
701 void gdcmHeader::SetMaxSizeLoadElementValue(long NewSize) {
702    if (NewSize < 0)
703       return;
704    if ((guint32)NewSize >= (guint32)0xffffffff) {
705       MaxSizeLoadElementValue = 0xffffffff;
706       return;
707    }
708    MaxSizeLoadElementValue = NewSize;
709 }
710
711 /**
712  * \ingroup       gdcmHeader
713  * \brief         Loads the element content if it's length is not bigger
714  *                than the value specified with
715  *                gdcmHeader::SetMaxSizeLoadElementValue()
716  */
717 void gdcmHeader::LoadElementValue(gdcmElValue * ElVal) {
718    size_t item_read;
719    guint16 group  = ElVal->GetGroup();
720    guint16 elem   = ElVal->GetElement();
721    string  vr     = ElVal->GetVR();
722    guint32 length = ElVal->GetLength();
723    bool SkipLoad  = false;
724
725    fseek(fp, (long)ElVal->GetOffset(), SEEK_SET);
726    
727    // FIXME Sequences not treated yet !
728    //
729    // Ne faudrait-il pas au contraire trouver immediatement
730    // une maniere 'propre' de traiter les sequences (vr = SQ)
731    // car commencer par les ignorer risque de conduire a qq chose
732    // qui pourrait ne pas etre generalisable
733    // Well, I'm expecting your code !!!
734     
735    if( vr == "SQ" )
736       SkipLoad = true;
737
738    // Heuristic : a sequence "contains" a set of tags (called items). It looks
739    // like the last tag of a sequence (the one that terminates the sequence)
740    // has a group of 0xfffe (with a dummy length).
741    if( group == 0xfffe )
742       SkipLoad = true;
743
744    if ( SkipLoad ) {
745       ElVal->SetLength(0);
746       ElVal->SetValue("gdcm::Skipped");
747       return;
748    }
749
750    // When the length is zero things are easy:
751    if ( length == 0 ) {
752       ElVal->SetValue("");
753       return;
754    }
755
756    // The elements whose length is bigger than the specified upper bound
757    // are not loaded. Instead we leave a short notice of the offset of
758    // the element content and it's length.
759    if (length > MaxSizeLoadElementValue) {
760       ostringstream s;
761       s << "gdcm::NotLoaded.";
762       s << " Address:" << (long)ElVal->GetOffset();
763       s << " Length:"  << ElVal->GetLength();
764       ElVal->SetValue(s.str());
765       return;
766    }
767    
768    // When an integer is expected, read and convert the following two or
769    // four bytes properly i.e. as an integer as opposed to a string.
770         
771         // pour les elements de Value Multiplicity > 1
772         // on aura en fait une serie d'entiers
773         
774         // on devrait pouvoir faire + compact (?)
775                 
776         if ( IsAnInteger(ElVal) ) {
777                 guint32 NewInt;
778                 ostringstream s;
779                 int nbInt;
780                 if (vr == "US" || vr == "SS") {
781                         nbInt = length / 2;
782                         NewInt = ReadInt16();
783                         s << NewInt;
784                         if (nbInt > 1) {
785                                 for (int i=1; i < nbInt; i++) {
786                                         s << '\\';
787                                         NewInt = ReadInt16();
788                                         s << NewInt;
789                                 }
790                         }
791                         
792                 } else if (vr == "UL" || vr == "SL") {
793                         nbInt = length / 4;
794                         NewInt = ReadInt32();
795                         s << NewInt;
796                         if (nbInt > 1) {
797                                 for (int i=1; i < nbInt; i++) {
798                                         s << '\\';
799                                         NewInt = ReadInt32();
800                                         s << NewInt;
801                                 }
802                         }
803                 }                                       
804                 ElVal->SetValue(s.str());
805                 return; 
806         }
807    
808    // We need an additional byte for storing \0 that is not on disk
809    char* NewValue = (char*)malloc(length+1);
810    if( !NewValue) {
811       dbg.Verbose(1, "LoadElementValue: Failed to allocate NewValue");
812       return;
813    }
814    NewValue[length]= 0;
815    
816    item_read = fread(NewValue, (size_t)length, (size_t)1, fp);
817    if ( item_read != 1 ) {
818       free(NewValue);
819       dbg.Verbose(1, "gdcmHeader::LoadElementValue","unread element value");
820       ElVal->SetValue("gdcm::UnRead");
821       return;
822    }
823    ElVal->SetValue(NewValue);
824    free(NewValue);
825 }
826
827 /**
828  * \ingroup       gdcmHeader
829  * \brief         Loads the element while preserving the current
830  *                underlying file position indicator as opposed to
831  *                to LoadElementValue that modifies it.
832  * @param ElVal   Element whose value shall be loaded. 
833  * @return  
834  */
835 void gdcmHeader::LoadElementValueSafe(gdcmElValue * ElVal) {
836    long PositionOnEntry = ftell(fp);
837    LoadElementValue(ElVal);
838    fseek(fp, PositionOnEntry, SEEK_SET);
839 }
840
841
842 guint16 gdcmHeader::ReadInt16(void) {
843    guint16 g;
844    size_t item_read;
845    item_read = fread (&g, (size_t)2,(size_t)1, fp);
846    errno = 0;
847    if ( item_read != 1 ) {
848       dbg.Verbose(1, "gdcmHeader::ReadInt16", " File read error");
849       errno = 1;
850       return 0;
851    }
852    g = SwapShort(g);
853    return g;
854 }
855
856 guint32 gdcmHeader::ReadInt32(void) {
857    guint32 g;
858    size_t item_read;
859    item_read = fread (&g, (size_t)4,(size_t)1, fp);
860    errno = 0;
861    if ( item_read != 1 ) {
862       dbg.Verbose(1, "gdcmHeader::ReadInt32", " File read error");
863       errno = 1;
864       return 0;
865    }
866    g = SwapLong(g);
867    return g;
868 }
869
870 /**
871  * \ingroup gdcmHeader
872  * \brief   Build a new Element Value from all the low level arguments. 
873  *          Check for existence of dictionary entry, and build
874  *          a default one when absent.
875  * @param   Group group   of the underlying DictEntry
876  * @param   Elem  element of the underlying DictEntry
877  */
878 gdcmElValue* gdcmHeader::NewElValueByNumber(guint16 Group, guint16 Elem) {
879    // Find out if the tag we encountered is in the dictionaries:
880    gdcmDictEntry * NewTag = GetDictEntryByNumber(Group, Elem);
881    if (!NewTag)
882       NewTag = new gdcmDictEntry(Group, Elem);
883
884    gdcmElValue* NewElVal = new gdcmElValue(NewTag);
885    if (!NewElVal) {
886       dbg.Verbose(1, "gdcmHeader::NewElValueByNumber",
887                   "failed to allocate gdcmElValue");
888       return (gdcmElValue*)0;
889    }
890    return NewElVal;
891 }
892
893 /**
894  * \ingroup gdcmHeader
895  * \brief   TODO
896  * @param   
897  */
898 int gdcmHeader::ReplaceOrCreateByNumber(string Value, guint16 Group, guint16 Elem ) {
899
900         gdcmElValue* nvElValue=NewElValueByNumber(Group, Elem);
901         PubElValSet.Add(nvElValue);     
902         PubElValSet.SetElValueByNumber(Value, Group, Elem);
903         return(1);
904 }   
905
906
907 /**
908  * \ingroup gdcmHeader
909  * \brief   Build a new Element Value from all the low level arguments. 
910  *          Check for existence of dictionary entry, and build
911  *          a default one when absent.
912  * @param   Name    Name of the underlying DictEntry
913  */
914 gdcmElValue* gdcmHeader::NewElValueByName(string Name) {
915
916    gdcmDictEntry * NewTag = GetDictEntryByName(Name);
917    if (!NewTag)
918       NewTag = new gdcmDictEntry(0xffff, 0xffff, "LO", "Unknown", Name);
919
920    gdcmElValue* NewElVal = new gdcmElValue(NewTag);
921    if (!NewElVal) {
922       dbg.Verbose(1, "gdcmHeader::ObtainElValueByName",
923                   "failed to allocate gdcmElValue");
924       return (gdcmElValue*)0;
925    }
926    return NewElVal;
927 }  
928
929 /**
930  * \ingroup gdcmHeader
931  * \brief   Read the next tag but WITHOUT loading it's value
932  * @return  On succes the newly created ElValue, NULL on failure.      
933  */
934 gdcmElValue * gdcmHeader::ReadNextElement(void) {
935   
936    guint16 g,n;
937    gdcmElValue * NewElVal;
938    
939    g = ReadInt16();
940    n = ReadInt16();
941    if (errno == 1)
942       // We reached the EOF (or an error occured) and header parsing
943       // has to be considered as finished.
944       return (gdcmElValue *)0;
945    
946    NewElVal = NewElValueByNumber(g, n);
947    FindVR(NewElVal);
948    FindLength(NewElVal);
949    if (errno == 1)
950       // Call it quits
951       return (gdcmElValue *)0;
952    NewElVal->SetOffset(ftell(fp));
953    return NewElVal;
954 }
955
956 /**
957  * \ingroup gdcmHeader
958  * \brief   Apply some heuristics to predict wether the considered 
959  *          element value contains/represents an integer or not.
960  * @param   ElVal The element value on which to apply the predicate.
961  * @return  The result of the heuristical predicate.
962  */
963 bool gdcmHeader::IsAnInteger(gdcmElValue * ElVal) {
964    guint16 group   = ElVal->GetGroup();
965    guint16 element = ElVal->GetElement();
966    string  vr      = ElVal->GetVR();
967    guint32 length  = ElVal->GetLength();
968
969    // When we have some semantics on the element we just read, and if we
970    // a priori know we are dealing with an integer, then we shall be
971    // able to swap it's element value properly.
972    if ( element == 0 )  {  // This is the group length of the group
973       if (length == 4)
974          return true;
975       else {
976          printf("Erroneous Group Length element length %d\n",length);
977                     
978          dbg.Error("gdcmHeader::IsAnInteger",
979                    "Erroneous Group Length element length.");     
980       }
981    }
982  
983    if ( (vr == "UL") || (vr == "US") || (vr == "SL") || (vr == "SS") )
984       return true;
985    
986    return false;
987 }
988
989 /**
990  * \ingroup gdcmHeader
991  * \brief   Recover the offset (from the beginning of the file) of the pixels.
992  */
993 size_t gdcmHeader::GetPixelOffset(void) {
994    // If this file complies with the norm we should encounter the
995    // "Image Location" tag (0x0028,  0x0200). This tag contains the
996    // the group that contains the pixel data (hence the "Pixel Data"
997    // is found by indirection through the "Image Location").
998    // Inside the group pointed by "Image Location" the searched element
999    // is conventionally the element 0x0010 (when the norm is respected).
1000    // When the "Image Location" is absent we default to group 0x7fe0.
1001    guint16 grPixel;
1002    guint16 numPixel;
1003    string ImageLocation = GetPubElValByName("Image Location");
1004    if ( ImageLocation == "gdcm::Unfound" ) {
1005       grPixel = 0x7fe0;
1006    } else {
1007       grPixel = (guint16) atoi( ImageLocation.c_str() );
1008    }
1009    if (grPixel != 0x7fe0)
1010       // This is a kludge for old dirty Philips imager.
1011       numPixel = 0x1010;
1012    else
1013       numPixel = 0x0010;
1014    gdcmElValue* PixelElement = PubElValSet.GetElementByNumber(grPixel,
1015                                                               numPixel);
1016    if (PixelElement)
1017       return PixelElement->GetOffset();
1018    else
1019       return 0;
1020 }
1021
1022 /**
1023  * \ingroup gdcmHeader
1024  * \brief   Searches both the public and the shadow dictionary (when they
1025  *          exist) for the presence of the DictEntry with given
1026  *          group and element. The public dictionary has precedence on the
1027  *          shadow one.
1028  * @param   group   group of the searched DictEntry
1029  * @param   element element of the searched DictEntry
1030  * @return  Corresponding DictEntry when it exists, NULL otherwise.
1031  */
1032 gdcmDictEntry * gdcmHeader::GetDictEntryByNumber(guint16 group,
1033                                                  guint16 element) {
1034    gdcmDictEntry * found = (gdcmDictEntry*)0;
1035    if (!RefPubDict && !RefShaDict) {
1036       dbg.Verbose(0, "gdcmHeader::GetDictEntry",
1037                      "we SHOULD have a default dictionary");
1038    }
1039    if (RefPubDict) {
1040       found = RefPubDict->GetTagByNumber(group, element);
1041       if (found)
1042          return found;
1043    }
1044    if (RefShaDict) {
1045       found = RefShaDict->GetTagByNumber(group, element);
1046       if (found)
1047          return found;
1048    }
1049    return found;
1050 }
1051
1052 /**
1053  * \ingroup gdcmHeader
1054  * \brief   Searches both the public and the shadow dictionary (when they
1055  *          exist) for the presence of the DictEntry with given name.
1056  *          The public dictionary has precedence on the shadow one.
1057  * @param   Name name of the searched DictEntry
1058  * @return  Corresponding DictEntry when it exists, NULL otherwise.
1059  */
1060 gdcmDictEntry * gdcmHeader::GetDictEntryByName(string Name) {
1061    gdcmDictEntry * found = (gdcmDictEntry*)0;
1062    if (!RefPubDict && !RefShaDict) {
1063       dbg.Verbose(0, "gdcmHeader::GetDictEntry",
1064                      "we SHOULD have a default dictionary");
1065    }
1066    if (RefPubDict) {
1067       found = RefPubDict->GetTagByName(Name);
1068       if (found)
1069          return found;
1070    }
1071    if (RefShaDict) {
1072       found = RefShaDict->GetTagByName(Name);
1073       if (found)
1074          return found;
1075    }
1076    return found;
1077 }
1078
1079 /**
1080  * \ingroup gdcmHeader
1081  * \brief   Searches within the public dictionary for element value of
1082  *          a given tag.
1083  * @param   group Group of the researched tag.
1084  * @param   element Element of the researched tag.
1085  * @return  Corresponding element value when it exists, and the string
1086  *          "gdcm::Unfound" otherwise.
1087  */
1088 string gdcmHeader::GetPubElValByNumber(guint16 group, guint16 element) {
1089    return PubElValSet.GetElValueByNumber(group, element);
1090 }
1091
1092 /**
1093  * \ingroup gdcmHeader
1094  * \brief   Searches within the public dictionary for element value
1095  *          representation of a given tag.
1096  *
1097  *          Obtaining the VR (Value Representation) might be needed by caller
1098  *          to convert the string typed content to caller's native type 
1099  *          (think of C++ vs Python). The VR is actually of a higher level
1100  *          of semantics than just the native C++ type.
1101  * @param   group Group of the researched tag.
1102  * @param   element Element of the researched tag.
1103  * @return  Corresponding element value representation when it exists,
1104  *          and the string "gdcm::Unfound" otherwise.
1105  */
1106 string gdcmHeader::GetPubElValRepByNumber(guint16 group, guint16 element) {
1107    gdcmElValue* elem =  PubElValSet.GetElementByNumber(group, element);
1108    if ( !elem )
1109       return "gdcm::Unfound";
1110    return elem->GetVR();
1111 }
1112
1113 /**
1114  * \ingroup gdcmHeader
1115  * \brief   Searches within the public dictionary for element value of
1116  *          a given tag.
1117  * @param   TagName name of the researched element.
1118  * @return  Corresponding element value when it exists, and the string
1119  *          "gdcm::Unfound" otherwise.
1120  */
1121 string gdcmHeader::GetPubElValByName(string TagName) {
1122    return PubElValSet.GetElValueByName(TagName);
1123 }
1124
1125 /**
1126  * \ingroup gdcmHeader
1127  * \brief   Searches within the elements parsed with the public dictionary for
1128  *          the element value representation of a given tag.
1129  *
1130  *          Obtaining the VR (Value Representation) might be needed by caller
1131  *          to convert the string typed content to caller's native type 
1132  *          (think of C++ vs Python). The VR is actually of a higher level
1133  *          of semantics than just the native C++ type.
1134  * @param   TagName name of the researched element.
1135  * @return  Corresponding element value representation when it exists,
1136  *          and the string "gdcm::Unfound" otherwise.
1137  */
1138 string gdcmHeader::GetPubElValRepByName(string TagName) {
1139    gdcmElValue* elem =  PubElValSet.GetElementByName(TagName);
1140    if ( !elem )
1141       return "gdcm::Unfound";
1142    return elem->GetVR();
1143 }
1144
1145 /**
1146  * \ingroup gdcmHeader
1147  * \brief   Searches within elements parsed with the SHADOW dictionary 
1148  *          for the element value of a given tag.
1149  * @param   group Group of the researched tag.
1150  * @param   element Element of the researched tag.
1151  * @return  Corresponding element value representation when it exists,
1152  *          and the string "gdcm::Unfound" otherwise.
1153  */
1154 string gdcmHeader::GetShaElValByNumber(guint16 group, guint16 element) {
1155    return ShaElValSet.GetElValueByNumber(group, element);
1156 }
1157
1158 /**
1159  * \ingroup gdcmHeader
1160  * \brief   Searches within the elements parsed with the SHADOW dictionary
1161  *          for the element value representation of a given tag.
1162  *
1163  *          Obtaining the VR (Value Representation) might be needed by caller
1164  *          to convert the string typed content to caller's native type 
1165  *          (think of C++ vs Python). The VR is actually of a higher level
1166  *          of semantics than just the native C++ type.
1167  * @param   group Group of the researched tag.
1168  * @param   element Element of the researched tag.
1169  * @return  Corresponding element value representation when it exists,
1170  *          and the string "gdcm::Unfound" otherwise.
1171  */
1172 string gdcmHeader::GetShaElValRepByNumber(guint16 group, guint16 element) {
1173    gdcmElValue* elem =  ShaElValSet.GetElementByNumber(group, element);
1174    if ( !elem )
1175       return "gdcm::Unfound";
1176    return elem->GetVR();
1177 }
1178
1179 /**
1180  * \ingroup gdcmHeader
1181  * \brief   Searches within the elements parsed with the shadow dictionary
1182  *          for an element value of given tag.
1183  * @param   TagName name of the researched element.
1184  * @return  Corresponding element value when it exists, and the string
1185  *          "gdcm::Unfound" otherwise.
1186  */
1187 string gdcmHeader::GetShaElValByName(string TagName) {
1188    return ShaElValSet.GetElValueByName(TagName);
1189 }
1190
1191 /**
1192  * \ingroup gdcmHeader
1193  * \brief   Searches within the elements parsed with the shadow dictionary for
1194  *          the element value representation of a given tag.
1195  *
1196  *          Obtaining the VR (Value Representation) might be needed by caller
1197  *          to convert the string typed content to caller's native type 
1198  *          (think of C++ vs Python). The VR is actually of a higher level
1199  *          of semantics than just the native C++ type.
1200  * @param   TagName name of the researched element.
1201  * @return  Corresponding element value representation when it exists,
1202  *          and the string "gdcm::Unfound" otherwise.
1203  */
1204 string gdcmHeader::GetShaElValRepByName(string TagName) {
1205    gdcmElValue* elem =  ShaElValSet.GetElementByName(TagName);
1206    if ( !elem )
1207       return "gdcm::Unfound";
1208    return elem->GetVR();
1209 }
1210
1211 /**
1212  * \ingroup gdcmHeader
1213  * \brief   Searches within elements parsed with the public dictionary 
1214  *          and then within the elements parsed with the shadow dictionary
1215  *          for the element value of a given tag.
1216  * @param   group Group of the researched tag.
1217  * @param   element Element of the researched tag.
1218  * @return  Corresponding element value representation when it exists,
1219  *          and the string "gdcm::Unfound" otherwise.
1220  */
1221 string gdcmHeader::GetElValByNumber(guint16 group, guint16 element) {
1222    string pub = GetPubElValByNumber(group, element);
1223    if (pub.length())
1224       return pub;
1225    return GetShaElValByNumber(group, element);
1226 }
1227
1228 /**
1229  * \ingroup gdcmHeader
1230  * \brief   Searches within elements parsed with the public dictionary 
1231  *          and then within the elements parsed with the shadow dictionary
1232  *          for the element value representation of a given tag.
1233  *
1234  *          Obtaining the VR (Value Representation) might be needed by caller
1235  *          to convert the string typed content to caller's native type 
1236  *          (think of C++ vs Python). The VR is actually of a higher level
1237  *          of semantics than just the native C++ type.
1238  * @param   group Group of the researched tag.
1239  * @param   element Element of the researched tag.
1240  * @return  Corresponding element value representation when it exists,
1241  *          and the string "gdcm::Unfound" otherwise.
1242  */
1243 string gdcmHeader::GetElValRepByNumber(guint16 group, guint16 element) {
1244    string pub = GetPubElValRepByNumber(group, element);
1245    if (pub.length())
1246       return pub;
1247    return GetShaElValRepByNumber(group, element);
1248 }
1249
1250 /**
1251  * \ingroup gdcmHeader
1252  * \brief   Searches within elements parsed with the public dictionary 
1253  *          and then within the elements parsed with the shadow dictionary
1254  *          for the element value of a given tag.
1255  * @param   TagName name of the researched element.
1256  * @return  Corresponding element value when it exists,
1257  *          and the string "gdcm::Unfound" otherwise.
1258  */
1259 string gdcmHeader::GetElValByName(string TagName) {
1260    string pub = GetPubElValByName(TagName);
1261    if (pub.length())
1262       return pub;
1263    return GetShaElValByName(TagName);
1264 }
1265
1266 /**
1267  * \ingroup gdcmHeader
1268  * \brief   Searches within elements parsed with the public dictionary 
1269  *          and then within the elements parsed with the shadow dictionary
1270  *          for the element value representation of a given tag.
1271  *
1272  *          Obtaining the VR (Value Representation) might be needed by caller
1273  *          to convert the string typed content to caller's native type 
1274  *          (think of C++ vs Python). The VR is actually of a higher level
1275  *          of semantics than just the native C++ type.
1276  * @param   TagName name of the researched element.
1277  * @return  Corresponding element value representation when it exists,
1278  *          and the string "gdcm::Unfound" otherwise.
1279  */
1280 string gdcmHeader::GetElValRepByName(string TagName) {
1281    string pub = GetPubElValRepByName(TagName);
1282    if (pub.length())
1283       return pub;
1284    return GetShaElValRepByName(TagName);
1285 }
1286
1287 /**
1288  * \ingroup gdcmHeader
1289  * \brief   Accesses an existing gdcmElValue in the PubElValSet of this instance
1290  *          through it's (group, element) and modifies it's content with
1291  *          the given value.
1292  * @param   content new value to substitute with
1293  * @param   group   group of the ElVal to modify
1294  * @param   element element of the ElVal to modify
1295  */
1296 int gdcmHeader::SetPubElValByNumber(string content, guint16 group,
1297                                     guint16 element)
1298 {
1299    return (  PubElValSet.SetElValueByNumber (content, group, element) );
1300 }
1301
1302 /**
1303  * \ingroup gdcmHeader
1304  * \brief   Accesses an existing gdcmElValue in the PubElValSet of this instance
1305  *          through tag name and modifies it's content with the given value.
1306  * @param   content new value to substitute with
1307  * @param   TagName name of the tag to be modified
1308  */
1309 int gdcmHeader::SetPubElValByName(string content, string TagName) {
1310    return (  PubElValSet.SetElValueByName (content, TagName) );
1311 }
1312
1313 /**
1314  * \ingroup gdcmHeader
1315  * \brief   Accesses an existing gdcmElValue in the PubElValSet of this instance
1316  *          through it's (group, element) and modifies it's length with
1317  *          the given value.
1318  * \warning Use with extreme caution.
1319  * @param   length new length to substitute with
1320  * @param   group   group of the ElVal to modify
1321  * @param   element element of the ElVal to modify
1322  * @return  1 on success, 0 otherwise.
1323  */
1324
1325 int gdcmHeader::SetPubElValLengthByNumber(guint32 length, guint16 group,
1326                                     guint16 element) {
1327         return (  PubElValSet.SetElValueLengthByNumber (length, group, element) );
1328 }
1329
1330 /**
1331  * \ingroup gdcmHeader
1332  * \brief   Accesses an existing gdcmElValue in the ShaElValSet of this instance
1333  *          through it's (group, element) and modifies it's content with
1334  *          the given value.
1335  * @param   content new value to substitute with
1336  * @param   group   group of the ElVal to modify
1337  * @param   element element of the ElVal to modify
1338  * @return  1 on success, 0 otherwise.
1339  */
1340 int gdcmHeader::SetShaElValByNumber(string content,
1341                                     guint16 group, guint16 element) {
1342    return (  ShaElValSet.SetElValueByNumber (content, group, element) );
1343 }
1344
1345 /**
1346  * \ingroup gdcmHeader
1347  * \brief   Accesses an existing gdcmElValue in the ShaElValSet of this instance
1348  *          through tag name and modifies it's content with the given value.
1349  * @param   content new value to substitute with
1350  * @param   TagName name of the tag to be modified
1351  */
1352 int gdcmHeader::SetShaElValByName(string content, string TagName) {
1353    return (  ShaElValSet.SetElValueByName (content, TagName) );
1354 }
1355
1356 /**
1357  * \ingroup gdcmHeader
1358  * \brief   Parses the header of the file but WITHOUT loading element values.
1359  */
1360 void gdcmHeader::ParseHeader(bool exception_on_error) throw(gdcmFormatError) {
1361    gdcmElValue * newElValue = (gdcmElValue *)0;
1362    
1363    rewind(fp);
1364    CheckSwap();
1365    while ( (newElValue = ReadNextElement()) ) {
1366       SkipElementValue(newElValue);
1367       PubElValSet.Add(newElValue);
1368    }
1369 }
1370
1371 /**
1372  * \ingroup gdcmHeader
1373  * \brief   Retrieve the number of columns of image.
1374  * @return  The encountered size when found, 0 by default.
1375  */
1376 int gdcmHeader::GetXSize(void) {
1377    // We cannot check for "Columns" because the "Columns" tag is present
1378    // both in IMG (0028,0011) and OLY (6000,0011) sections of the dictionary.
1379    string StrSize = GetPubElValByNumber(0x0028,0x0011);
1380    if (StrSize == "gdcm::Unfound")
1381       return 0;
1382    return atoi(StrSize.c_str());
1383 }
1384
1385 /**
1386  * \ingroup gdcmHeader
1387  * \brief   Retrieve the number of lines of image.
1388  * \warning The defaulted value is 1 as opposed to gdcmHeader::GetXSize()
1389  * @return  The encountered size when found, 1 by default.
1390  */
1391 int gdcmHeader::GetYSize(void) {
1392    // We cannot check for "Rows" because the "Rows" tag is present
1393    // both in IMG (0028,0010) and OLY (6000,0010) sections of the dictionary.
1394    string StrSize = GetPubElValByNumber(0x0028,0x0010);
1395    if (StrSize != "gdcm::Unfound")
1396       return atoi(StrSize.c_str());
1397    if ( IsDicomV3() )
1398       return 0;
1399    else
1400       // The Rows (0028,0010) entry is optional for ACR/NEMA. It might
1401       // hence be a signal (1d image). So we default to 1:
1402       return 1;
1403 }
1404
1405 /**
1406  * \ingroup gdcmHeader
1407  * \brief   Retrieve the number of planes of volume or the number
1408  *          of frames of a multiframe.
1409  * \warning When present we consider the "Number of Frames" as the third
1410  *          dimension. When absent we consider the third dimension as
1411  *          being the "Planes" tag content.
1412  * @return  The encountered size when found, 1 by default.
1413  */
1414 int gdcmHeader::GetZSize(void) {
1415    // Both in DicomV3 and ACR/Nema the consider the "Number of Frames"
1416    // as the third dimension.
1417    string StrSize = GetPubElValByNumber(0x0028,0x0008);
1418    if (StrSize != "gdcm::Unfound")
1419       return atoi(StrSize.c_str());
1420
1421    // We then consider the "Planes" entry as the third dimension [we
1422    // cannot retrieve by name since "Planes tag is present both in
1423    // IMG (0028,0012) and OLY (6000,0012) sections of the dictionary]. 
1424    StrSize = GetPubElValByNumber(0x0028,0x0012);
1425    if (StrSize != "gdcm::Unfound")
1426       return atoi(StrSize.c_str());
1427    return 1;
1428 }
1429
1430 /**
1431  * \ingroup gdcmHeader
1432  * \brief   Build the Pixel Type of the image.
1433  *          Possible values are:
1434  *          - U8  unsigned  8 bit,
1435  *          - S8    signed  8 bit,
1436  *          - U16 unsigned 16 bit,
1437  *          - S16   signed 16 bit,
1438  *          - U32 unsigned 32 bit,
1439  *          - S32   signed 32 bit,
1440  * \warning 12 bit images appear as 16 bit.
1441  * @return 
1442  */
1443 string gdcmHeader::GetPixelType(void) {
1444    string BitsAlloc;
1445    BitsAlloc = GetElValByName("Bits Allocated");
1446    if (BitsAlloc == "gdcm::Unfound") {
1447       dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated");
1448       BitsAlloc = string("16");
1449    }
1450    if (BitsAlloc == "12")
1451       BitsAlloc = string("16");
1452
1453    string Signed;
1454    Signed = GetElValByName("Pixel Representation");
1455    if (Signed == "gdcm::Unfound") {
1456       dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation");
1457       BitsAlloc = string("0");
1458    }
1459    if (Signed == "0")
1460       Signed = string("U");
1461    else
1462       Signed = string("S");
1463
1464    return( BitsAlloc + Signed);
1465 }
1466
1467 /**
1468  * \ingroup gdcmHeader
1469  * \brief  This predicate, based on hopefully reasonnable heuristics,
1470  *         decides whether or not the current gdcmHeader was properly parsed
1471  *         and contains the mandatory information for being considered as
1472  *         a well formed and usable image.
1473  * @return true when gdcmHeader is the one of a reasonable Dicom file,
1474  *         false otherwise. 
1475  */
1476 bool gdcmHeader::IsReadable(void) {
1477    if (   GetElValByName("Image Dimensions") != "gdcm::Unfound"
1478       && atoi(GetElValByName("Image Dimensions").c_str()) > 4 ) {
1479       return false;
1480    }
1481    if (  GetElValByName("Bits Allocated") == "gdcm::Unfound" )
1482       return false;
1483    if (  GetElValByName("Bits Stored") == "gdcm::Unfound" )
1484       return false;
1485    if (  GetElValByName("High Bit") == "gdcm::Unfound" )
1486       return false;
1487    if (  GetElValByName("Pixel Representation") == "gdcm::Unfound" )
1488       return false;
1489    return true;
1490 }
1491
1492 /**
1493  * \ingroup gdcmHeader
1494  * \brief   Small utility function that creates a new manually crafted
1495  *          (as opposed as read from the file) gdcmElValue with user
1496  *          specified name and adds it to the public tag hash table.
1497  * \note    A fake TagKey is generated so the PubDict can keep it's coherence.
1498  * @param   NewTagName The name to be given to this new tag.
1499  * @param   VR The Value Representation to be given to this new tag.
1500  * @ return The newly hand crafted Element Value.
1501  */
1502 gdcmElValue* gdcmHeader::NewManualElValToPubDict(string NewTagName, string VR) {
1503    gdcmElValue* NewElVal = (gdcmElValue*)0;
1504    guint32 StuffGroup = 0xffff;   // Group to be stuffed with additional info
1505    guint32 FreeElem = 0;
1506    gdcmDictEntry* NewEntry = (gdcmDictEntry*)0;
1507
1508    FreeElem = PubElValSet.GenerateFreeTagKeyInGroup(StuffGroup);
1509    if (FreeElem == UINT32_MAX) {
1510       dbg.Verbose(1, "gdcmHeader::NewManualElValToPubDict",
1511                      "Group 0xffff in Public Dict is full");
1512       return (gdcmElValue*)0;
1513    }
1514    NewEntry = new gdcmDictEntry(StuffGroup, FreeElem,
1515                                 VR, "GDCM", NewTagName);
1516    NewElVal = new gdcmElValue(NewEntry);
1517    PubElValSet.Add(NewElVal);
1518    return NewElVal;
1519
1520 }
1521
1522 /**
1523  * \ingroup gdcmHeader
1524  * \brief   Loads the element values of all the elements present in the
1525  *          public tag based hash table.
1526  */
1527 void gdcmHeader::LoadElements(void) {
1528    rewind(fp);   
1529    TagElValueHT ht = PubElValSet.GetTagHt();
1530    for (TagElValueHT::iterator tag = ht.begin(); tag != ht.end(); ++tag) {
1531       LoadElementValue(tag->second);
1532       }
1533 }
1534
1535 void gdcmHeader::PrintPubElVal(ostream & os) {
1536    PubElValSet.Print(os);
1537 }
1538
1539 void gdcmHeader::PrintPubDict(ostream & os) {
1540    RefPubDict->Print(os);
1541 }
1542
1543 int gdcmHeader::Write(FILE * fp, FileType type) {
1544    return PubElValSet.Write(fp, type);
1545 }