]> Creatis software - gdcm.git/blob - src/gdcmHeader.cxx
faa95f7bccd4fcffd175453a3da4f9426066f316
[gdcm.git] / src / gdcmHeader.cxx
1 // gdcmHeader.cxx
2
3 #include "gdcm.h"
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 <map>
14 #include <sstream>
15 #include "gdcmUtil.h"
16
17 #define HEADER_LENGTH_TO_READ           256     // on ne lit plus que le debut
18 #define _MaxSizeLoadElementValue_       1024    // longueur au dela de laquelle on ne charge plus les valeurs 
19
20 //FIXME: this looks dirty to me...
21
22 #define str2num(str, typeNum) *((typeNum *)(str))
23
24 // str est un pointeur dans un tableau de caractères, qui doit contenir, 
25 // à cet endroit la, la représentation binaire d'un entier (16 ou 32 bits)
26 // je veux récupérer ça ... dans un entier.
27 // s'il y a une autre solution, évitant des cast et les indirections,
28 // je suis preneur
29
30 VRHT * gdcmHeader::dicom_vr = (VRHT*)0;
31
32 void gdcmHeader::Initialise(void) {
33         if (!gdcmHeader::dicom_vr)
34                 InitVRDict();
35         Dicts = new gdcmDictSet();
36         RefPubDict = Dicts->GetDefaultPubDict();
37         RefShaDict = (gdcmDict*)0;
38 }
39
40
41 gdcmHeader::gdcmHeader(const char *InFilename, bool exception_on_error) 
42   throw(gdcmFileError) {
43   SetMaxSizeLoadElementValue(_MaxSizeLoadElementValue_);
44   filename = InFilename;
45   Initialise();
46   fp=fopen(InFilename,"rb");
47   if(exception_on_error) {
48     if(!fp)
49       throw gdcmFileError("gdcmHeader::gdcmHeader(const char *, bool)");
50   }
51   else
52     dbg.Error(!fp, "gdcmHeader::gdcmHeader cannot open file", InFilename);
53   ParseHeader();
54   AddAndDefaultElements();
55 }
56
57
58 gdcmHeader::~gdcmHeader (void) {
59         fclose(fp);
60         return;
61 }
62
63 void gdcmHeader::InitVRDict (void) {
64         if (dicom_vr) {
65                 dbg.Verbose(0, "gdcmHeader::InitVRDict:", "VR dictionary allready set");
66                 return;
67         }
68         VRHT *vr = new VRHT;
69         (*vr)["AE"] = "Application Entity";       // At most 16 bytes
70         (*vr)["AS"] = "Age String";               // Exactly 4 bytes
71         (*vr)["AT"] = "Attribute Tag";            // 2 16-bit unsigned short integers
72         (*vr)["CS"] = "Code String";              // At most 16 bytes
73         (*vr)["DA"] = "Date";                     // Exactly 8 bytes
74         (*vr)["DS"] = "Decimal String";           // At most 16 bytes
75         (*vr)["DT"] = "Date Time";                // At most 26 bytes
76         (*vr)["FL"] = "Floating Point Single";    // 32-bit IEEE 754:1985 float
77         (*vr)["FD"] = "Floating Point Double";    // 64-bit IEEE 754:1985 double
78         (*vr)["IS"] = "Integer String";           // At most 12 bytes
79         (*vr)["LO"] = "Long String";              // At most 64 chars
80         (*vr)["LT"] = "Long Text";                // At most 10240 chars
81         (*vr)["OB"] = "Other Byte String";        // String of bytes (vr independant)
82         (*vr)["OW"] = "Other Word String";        // String of 16-bit words (vr dep)
83         (*vr)["PN"] = "Person Name";              // At most 64 chars
84         (*vr)["SH"] = "Short String";             // At most 16 chars
85         (*vr)["SL"] = "Signed Long";              // Exactly 4 bytes
86         (*vr)["SQ"] = "Sequence of Items";        // Not Applicable
87         (*vr)["SS"] = "Signed Short";             // Exactly 2 bytes
88         (*vr)["ST"] = "Short Text";               // At most 1024 chars
89         (*vr)["TM"] = "Time";                     // At most 16 bytes
90         (*vr)["UI"] = "Unique Identifier";        // At most 64 bytes
91         (*vr)["UL"] = "Unsigned Long ";           // Exactly 4 bytes
92         (*vr)["UN"] = "Unknown";                  // Any length of bytes
93         (*vr)["US"] = "Unsigned Short ";          // Exactly 2 bytes
94         (*vr)["UT"] = "Unlimited Text";           // At most 2^32 -1 chars
95    dicom_vr = vr;       
96 }
97
98 /**
99  * \ingroup gdcmHeader
100  * \brief   Discover what the swap code is (among little endian, big endian,
101  *          bad little endian, bad big endian).
102  *
103  */
104 void gdcmHeader::CheckSwap()
105 {
106         // The only guaranted way of finding the swap code is to find a
107         // group tag since we know it's length has to be of four bytes i.e.
108         // 0x00000004. Finding the swap code in then straigthforward. Trouble
109         // occurs when we can't find such group...
110         guint32  s;
111         guint32  x=4;  // x : pour ntohs
112         bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
113          
114         int lgrLue;
115         char * entCur;
116         char deb[HEADER_LENGTH_TO_READ];
117          
118         // First, compare HostByteOrder and NetworkByteOrder in order to
119         // determine if we shall need to swap bytes (i.e. the Endian type).
120         if (x==ntohs(x))
121                 net2host = true;
122         else
123                 net2host = false;
124         
125         // The easiest case is the one of a DICOM header, since it possesses a
126         // file preamble where it suffice to look for the string "DICM".
127         lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, fp);
128         
129         entCur = deb + 128;
130         if(memcmp(entCur, "DICM", (size_t)4) == 0) {
131                 filetype = TrueDicom;
132                 dbg.Verbose(1, "gdcmHeader::CheckSwap:", "looks like DICOM Version3");
133         } else {
134                 filetype = Unknown;
135                 dbg.Verbose(1, "gdcmHeader::CheckSwap:", "not a DICOM Version3 file");
136         }
137
138         if(filetype == TrueDicom) {
139                 // Next, determine the value representation (VR). Let's skip to the
140                 // first element (0002, 0000) and check there if we find "UL", in
141                 // which case we (almost) know it is explicit VR.
142                 // WARNING: if it happens to be implicit VR then what we will read
143                 // is the length of the group. If this ascii representation of this
144                 // length happens to be "UL" then we shall believe it is explicit VR.
145                 // FIXME: in order to fix the above warning, we could read the next
146                 // element value (or a couple of elements values) in order to make
147                 // sure we are not commiting a big mistake.
148                 // We need to skip :
149                 // * the 128 bytes of File Preamble (often padded with zeroes),
150                 // * the 4 bytes of "DICM" string,
151                 // * the 4 bytes of the first tag (0002, 0000),
152                 // i.e. a total of  136 bytes.
153                 entCur = deb + 136;
154                 if(memcmp(entCur, "UL", (size_t)2) == 0) {
155                         filetype = ExplicitVR;
156                         dbg.Verbose(1, "gdcmHeader::CheckSwap:",
157                                     "explicit Value Representation");
158                 } else {
159                         filetype = ImplicitVR;
160                         dbg.Verbose(1, "gdcmHeader::CheckSwap:",
161                                     "not an explicit Value Representation");
162                 }
163
164                 if (net2host) {
165                         sw = 4321;
166                         dbg.Verbose(1, "gdcmHeader::CheckSwap:",
167                                        "HostByteOrder != NetworkByteOrder");
168                 } else {
169                         sw = 0;
170                         dbg.Verbose(1, "gdcmHeader::CheckSwap:",
171                                        "HostByteOrder = NetworkByteOrder");
172                 }
173                 
174                 // Position the file position indicator at first tag (i.e.
175                 // after the file preamble and the "DICM" string).
176                 rewind(fp);
177                 fseek (fp, 132L, SEEK_SET);
178                 return;
179         } // End of TrueDicom
180
181         // Alas, this is not a DicomV3 file and whatever happens there is no file
182         // preamble. We can reset the file position indicator to where the data
183         // is (i.e. the beginning of the file).
184         rewind(fp);
185
186         // Our next best chance would be to be considering a 'clean' ACR/NEMA file.
187         // By clean we mean that the length of the first tag is written down.
188         // If this is the case and since the length of the first group HAS to be
189         // four (bytes), then determining the proper swap code is straightforward.
190
191         entCur = deb + 4;
192         s = str2num(entCur, guint32);
193         
194         switch (s) {
195         case 0x00040000 :
196                 sw = 3412;
197                 filetype = ACR;
198                 return;
199         case 0x04000000 :
200                 sw = 4321;
201                 filetype = ACR;
202                 return;
203         case 0x00000400 :
204                 sw = 2143;
205                 filetype = ACR;
206                 return;
207         case 0x00000004 :
208                 sw = 0;
209                 filetype = ACR;
210                 return;
211         default :
212                 dbg.Verbose(0, "gdcmHeader::CheckSwap:",
213                                "ACR/NEMA unfound swap info (time to raise bets)");
214         }
215
216         // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file.
217         // It is time for despaired wild guesses. So, let's assume this file
218         // happens to be 'dirty' ACR/NEMA, i.e. the length of the group is
219         // not present. Then the only info we have is the net2host one.
220         if (! net2host )
221                 sw = 0;
222         else
223                 sw = 4321;
224         return;
225 }
226
227 void gdcmHeader::SwitchSwapToBigEndian(void) {
228         dbg.Verbose(1, "gdcmHeader::SwitchSwapToBigEndian",
229                        "Switching to BigEndian mode.");
230         if ( sw == 0    ) {
231                 sw = 4321;
232                 return;
233         }
234         if ( sw == 4321 ) {
235                 sw = 0;
236                 return;
237         }
238         if ( sw == 3412 ) {
239                 sw = 2143;
240                 return;
241         }
242         if ( sw == 2143 )
243                 sw = 3412;
244 }
245
246 void gdcmHeader::GetPixels(size_t lgrTotale, void* _Pixels) {
247         size_t pixelsOffset; 
248         pixelsOffset = GetPixelOffset();
249         fseek(fp, pixelsOffset, SEEK_SET);
250         fread(_Pixels, 1, lgrTotale, fp);
251 }
252
253
254
255 /**
256  * \ingroup   gdcmHeader
257  * \brief     Find the value representation of the current tag.
258  */
259 void gdcmHeader::FindVR( ElValue *ElVal) {
260         if (filetype != ExplicitVR)
261                 return;
262
263         char VR[3];
264         string vr;
265         int lgrLue;
266         long PositionOnEntry = ftell(fp);
267         // Warning: we believe this is explicit VR (Value Representation) because
268         // we used a heuristic that found "UL" in the first tag. Alas this
269         // doesn't guarantee that all the tags will be in explicit VR. In some
270         // cases (see e-film filtered files) one finds implicit VR tags mixed
271         // within an explicit VR file. Hence we make sure the present tag
272         // is in explicit VR and try to fix things if it happens not to be
273         // the case.
274         bool RealExplicit = true;
275         
276         lgrLue=fread (&VR, (size_t)2,(size_t)1, fp);
277         VR[2]=0;
278         vr = string(VR);
279                 
280         // Assume we are reading a falsely explicit VR file i.e. we reached
281         // a tag where we expect reading a VR but are in fact we read the
282         // first to bytes of the length. Then we will interogate (through find)
283         // the dicom_vr dictionary with oddities like "\004\0" which crashes
284         // both GCC and VC++ implementations of the STL map. Hence when the
285         // expected VR read happens to be non-ascii characters we consider
286         // we hit falsely explicit VR tag.
287
288         if ( (!isalpha(VR[0])) && (!isalpha(VR[1])) )
289                 RealExplicit = false;
290
291         // CLEANME searching the dicom_vr at each occurence is expensive.
292         // PostPone this test in an optional integrity check at the end
293         // of parsing or only in debug mode.
294         if ( RealExplicit && !dicom_vr->count(vr) )
295                 RealExplicit = false;
296
297         if ( RealExplicit ) {
298                 if ( ElVal->IsVrUnknown() ) {
299                         // When not a dictionary entry, we can safely overwrite the vr.
300                         ElVal->SetVR(vr);
301                         return; 
302                 }
303                 if ( ElVal->GetVR() == vr ) {
304                         // The vr we just read and the dictionary agree. Nothing to do.
305                         return;
306                 }
307                 // The vr present in the file and the dictionary disagree. We assume
308                 // the file writer knew best and use the vr of the file. Since it would
309                 // be unwise to overwrite the vr of a dictionary (since it would
310                 // compromise it's next user), we need to clone the actual DictEntry
311                 // and change the vr for the read one.
312                 gdcmDictEntry* NewTag = new gdcmDictEntry(ElVal->GetGroup(),
313                                            ElVal->GetElement(),
314                                            vr,
315                                            "FIXME",
316                                            ElVal->GetName());
317                 ElVal->SetDictEntry(NewTag);
318                 return; 
319         }
320         
321         // We thought this was explicit VR, but we end up with an
322         // implicit VR tag. Let's backtrack.
323         dbg.Verbose(1, "gdcmHeader::FindVR:", "Falsely explicit vr file");
324         fseek(fp, PositionOnEntry, SEEK_SET);
325         // When this element is known in the dictionary we shall use, e.g. for
326         // the semantics (see  the usage of IsAnInteger), the vr proposed by the
327         // dictionary entry. Still we have to flag the element as implicit since
328         // we know now our assumption on expliciteness is not furfilled.
329         // avoid  .
330         if ( ElVal->IsVrUnknown() )
331                 ElVal->SetVR("Implicit");
332         ElVal->SetImplicitVr();
333 }
334
335 /**
336  * \ingroup gdcmHeader
337  * \brief   Determines if the Transfer Syntax was allready encountered
338  *          and if it corresponds to a ImplicitVRLittleEndian one.
339  *
340  * @return  True when ImplicitVRLittleEndian found. False in all other cases.
341  */
342 bool gdcmHeader::IsImplicitVRLittleEndianTransferSyntax(void) {
343         ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
344         if ( !Element )
345                 return false;
346         LoadElementValueSafe(Element);
347         string Transfer = Element->GetValue();
348         if ( Transfer == "1.2.840.10008.1.2" )
349                 return true;
350         return false;
351 }
352
353 /**
354  * \ingroup gdcmHeader
355  * \brief   Determines if the Transfer Syntax was allready encountered
356  *          and if it corresponds to a ExplicitVRLittleEndian one.
357  *
358  * @return  True when ExplicitVRLittleEndian found. False in all other cases.
359  */
360 bool gdcmHeader::IsExplicitVRLittleEndianTransferSyntax(void) {
361         ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
362         if ( !Element )
363                 return false;
364         LoadElementValueSafe(Element);
365         string Transfer = Element->GetValue();
366         if ( Transfer == "1.2.840.10008.1.2.1" )
367                 return true;
368         return false;
369 }
370
371 /**
372  * \ingroup gdcmHeader
373  * \brief   Determines if the Transfer Syntax was allready encountered
374  *          and if it corresponds to a DeflatedExplicitVRLittleEndian one.
375  *
376  * @return  True when DeflatedExplicitVRLittleEndian found. False in all other cases.
377  */
378 bool gdcmHeader::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) {
379         ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
380         if ( !Element )
381                 return false;
382         LoadElementValueSafe(Element);
383         string Transfer = Element->GetValue();
384         if ( Transfer == "1.2.840.10008.1.2.1.99" )
385                 return true;
386         return false;
387 }
388
389
390 /**
391  * \ingroup gdcmHeader
392  * \brief   Determines if the Transfer Syntax was allready encountered
393  *          and if it corresponds to a Explicit VR Big Endian one.
394  *
395  * @return  True when big endian found. False in all other cases.
396  */
397 bool gdcmHeader::IsExplicitVRBigEndianTransferSyntax(void) {
398         ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
399         if ( !Element )
400                 return false;
401         LoadElementValueSafe(Element);
402         string Transfer = Element->GetValue();
403         if ( Transfer == "1.2.840.10008.1.2.2" )
404                 return true;
405         return false;
406 }
407
408
409 /**
410  * \ingroup gdcmHeader
411  * \brief   Determines if the Transfer Syntax was allready encountered
412  *          and if it corresponds to a JPEGBaseLineProcess1 one.
413  *
414  * @return  True when JPEGBaseLineProcess1found. False in all other cases.
415  */
416 bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) {
417         ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
418         if ( !Element )
419                 return false;
420         LoadElementValueSafe(Element);
421         string Transfer = Element->GetValue();
422         if ( Transfer == "1.2.840.10008.1.2.4.50" )
423                 return true;
424         return false;
425 }
426
427 /**
428  * \ingroup gdcmHeader
429  * \brief   Determines if the Transfer Syntax was allready encountered
430  *          and if it corresponds to a JPEGExtendedProcess2-4 one.
431  *
432  * @return  True when JPEGExtendedProcess2-4 found. False in all other cases.
433  */
434 bool gdcmHeader::IsJPEGExtendedProcess2_4TransferSyntax(void) {
435         ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
436         if ( !Element )
437                 return false;
438         LoadElementValueSafe(Element);
439         string Transfer = Element->GetValue();
440         if ( Transfer == "1.2.840.10008.1.2.4.51" )
441                 return true;
442         return false;
443 }
444
445
446 /**
447  * \ingroup gdcmHeader
448  * \brief   Determines if the Transfer Syntax was allready encountered
449  *          and if it corresponds to a JPEGExtendeProcess3-5 one.
450  *
451  * @return  True when JPEGExtendedProcess3-5 found. False in all other cases.
452  */
453 bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) {
454         ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
455         if ( !Element )
456                 return false;
457         LoadElementValueSafe(Element);
458         string Transfer = Element->GetValue();
459         if ( Transfer == "1.2.840.10008.1.2.4.52" )
460                 return true;
461         return false;
462 }
463
464 /**
465  * \ingroup gdcmHeader
466  * \brief   Determines if the Transfer Syntax was allready encountered
467  *          and if it corresponds to a JPEGSpectralSelectionProcess6-8 one.
468  *
469  * @return  True when JPEGSpectralSelectionProcess6-8 found. False in all other cases.
470  */
471 bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) {
472         ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
473         if ( !Element )
474                 return false;
475         LoadElementValueSafe(Element);
476         string Transfer = Element->GetValue();
477         if ( Transfer == "1.2.840.10008.1.2.4.53" )
478                 return true;
479         return false;
480 }
481
482 //
483 // Euhhhhhhh
484 // Il y en a encore DIX-SEPT, comme ça.
485 // Il faudrait trouver qq chose + rusé ...
486 //
487 // --> probablement TOUS les supprimer (Eric dixit)
488 //
489
490
491 void gdcmHeader::FixFoundLength(ElValue * ElVal, guint32 FoundLength) {
492         // Heuristic: a final fix.
493         if ( FoundLength == 0xffffffff)
494                 FoundLength = 0;
495         ElVal->SetLength(FoundLength);
496 }
497
498 guint32 gdcmHeader::FindLengthOB(void) {
499         // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
500         guint16 g;
501         guint16 n; 
502         long PositionOnEntry = ftell(fp);
503         bool FoundSequenceDelimiter = false;
504         guint32 TotalLength = 0;
505         guint32 ItemLength;
506
507         while ( ! FoundSequenceDelimiter) {
508                 g = ReadInt16();
509                 n = ReadInt16();
510                 if (errno == 1)
511                         return 0;
512                 TotalLength += 4;  // We even have to decount the group and element 
513                 if ( g != 0xfffe ) {
514                         dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",
515                                     "wrong group for an item sequence.");
516                         errno = 1;
517                         return 0;
518                 }
519                 if ( n == 0xe0dd )
520                         FoundSequenceDelimiter = true;
521                 else if ( n != 0xe000) {
522                         dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",
523                                     "wrong element for an item sequence.");
524                         errno = 1;
525                         return 0;
526                 }
527                 ItemLength = ReadInt32();
528                 TotalLength += ItemLength + 4;  // We add 4 bytes since we just read
529                                                 // the ItemLength with ReadInt32
530                 SkipBytes(ItemLength);
531         }
532         fseek(fp, PositionOnEntry, SEEK_SET);
533         return TotalLength;
534 }
535
536 void gdcmHeader::FindLength(ElValue * ElVal) {
537         guint16 element = ElVal->GetElement();
538         string  vr      = ElVal->GetVR();
539         guint16 length16;
540         
541         if ( (filetype == ExplicitVR) && ! ElVal->IsImplicitVr() ) {
542
543                 if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) {
544                         // The following reserved two bytes (see PS 3.5-2001, section
545                         // 7.1.2 Data element structure with explicit vr p27) must be
546                         // skipped before proceeding on reading the length on 4 bytes.
547                         fseek(fp, 2L, SEEK_CUR);
548                         guint32 length32 = ReadInt32();
549                         if ( (vr == "OB") && (length32 == 0xffffffff) ) {
550                                 ElVal->SetLength(FindLengthOB());
551                                 return;
552                         }
553                         FixFoundLength(ElVal, length32);
554                         return;
555                 }
556
557                 // Length is encoded on 2 bytes.
558                 length16 = ReadInt16();
559                 
560                 // We can tell the current file is encoded in big endian (like
561                 // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag
562                 // and it's value is the one of the encoding of a big endian file.
563                 // In order to deal with such big endian encoded files, we have
564                 // (at least) two strategies:
565                 // * when we load the "Transfer Syntax" tag with value of big endian
566                 //   encoding, we raise the proper flags. Then we wait for the end
567                 //   of the META group (0x0002) among which is "Transfer Syntax",
568                 //   before switching the swap code to big endian. We have to postpone
569                 //   the switching of the swap code since the META group is fully encoded
570                 //   in little endian, and big endian coding only starts at the next
571                 //   group. The corresponding code can be hard to analyse and adds
572                 //   many additional unnecessary tests for regular tags.
573                 // * the second strategy consists in waiting for trouble, that shall appear
574                 //   when we find the first group with big endian encoding. This is
575                 //   easy to detect since the length of a "Group Length" tag (the
576                 //   ones with zero as element number) has to be of 4 (0x0004). When we
577                 //   encouter 1024 (0x0400) chances are the encoding changed and we
578                 //   found a group with big endian encoding.
579                 // We shall use this second strategy. In order make sure that we
580                 // can interpret the presence of an apparently big endian encoded
581                 // length of a "Group Length" without committing a big mistake, we
582                 // add an additional check: we look in the allready parsed elements
583                 // for the presence of a "Transfer Syntax" whose value has to be "big
584                 // endian encoding". When this is the case, chances are we got our
585                 // hands on a big endian encoded file: we switch the swap code to
586                 // big endian and proceed...
587                 if ( (element  == 0x000) && (length16 == 0x0400) ) {
588                         if ( ! IsExplicitVRBigEndianTransferSyntax() ) {
589                                 dbg.Verbose(0, "gdcmHeader::FindLength", "not explicit VR");
590                                 errno = 1;
591                                 return;
592                         }
593                         length16 = 4;
594                         SwitchSwapToBigEndian();
595                         // Restore the unproperly loaded values i.e. the group, the element
596                         // and the dictionary entry depending on them.
597                         guint16 CorrectGroup   = SwapShort(ElVal->GetGroup());
598                         guint16 CorrectElem    = SwapShort(ElVal->GetElement());
599                         gdcmDictEntry * NewTag = GetDictEntryByKey(CorrectGroup, CorrectElem);
600                         if (!NewTag) {
601                                 // This correct tag is not in the dictionary. Create a new one.
602                                 NewTag = new gdcmDictEntry(CorrectGroup, CorrectElem);
603                         }
604                         // FIXME this can create a memory leaks on the old entry that be
605                         // left unreferenced.
606                         ElVal->SetDictEntry(NewTag);
607                 }
608                  
609                 // Heuristic: well some files are really ill-formed.
610                 if ( length16 == 0xffff) {
611                         length16 = 0;
612                         dbg.Verbose(0, "gdcmHeader::FindLength",
613                                     "Erroneous element length fixed.");
614                 }
615                 FixFoundLength(ElVal, (guint32)length16);
616                 return;
617         }
618
619         // Either implicit VR or a non DICOM conformal (see not below) explicit
620         // VR that ommited the VR of (at least) this element. Farts happen.
621         // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25
622         // on Data elements "Implicit and Explicit VR Data Elements shall
623         // not coexist in a Data Set and Data Sets nested within it".]
624         // Length is on 4 bytes.
625         FixFoundLength(ElVal, ReadInt32());
626 }
627
628 /**
629  * \ingroup gdcmHeader
630  * \brief   Swaps back the bytes of 4-byte long integer accordingly to
631  *          processor order.
632  *
633  * @return  The suggested integer.
634  */
635 guint32 gdcmHeader::SwapLong(guint32 a) {
636         // FIXME: il pourrait y avoir un pb pour les entiers negatifs ...
637         switch (sw) {
638         case    0 :
639                 break;
640         case 4321 :
641                 a=(   ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000)    | 
642                       ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
643                 break;
644         
645         case 3412 :
646                 a=(   ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
647                 break;
648         
649         case 2143 :
650                 a=(    ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
651                 break;
652         default :
653                 dbg.Error(" gdcmHeader::SwapLong : unset swap code");
654                 a=0;
655         }
656         return(a);
657 }
658
659 /**
660  * \ingroup gdcmHeader
661  * \brief   Swaps the bytes so they agree with the processor order
662  * @return  The properly swaped 16 bits integer.
663  */
664 guint16 gdcmHeader::SwapShort(guint16 a) {
665         if ( (sw==4321)  || (sw==2143) )
666                 a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff));
667         return (a);
668 }
669
670 void gdcmHeader::SkipBytes(guint32 NBytes) {
671         //FIXME don't dump the returned value
672         (void)fseek(fp, (long)NBytes, SEEK_CUR);
673 }
674
675 void gdcmHeader::SkipElementValue(ElValue * ElVal) {
676         SkipBytes(ElVal->GetLength());
677 }
678
679 void gdcmHeader::SetMaxSizeLoadElementValue(long NewSize) {
680         if (NewSize < 0)
681                 return;
682         if ((guint32)NewSize >= (guint32)0xffffffff) {
683                 MaxSizeLoadElementValue = 0xffffffff;
684                 return;
685         }
686         MaxSizeLoadElementValue = NewSize;
687 }
688
689 /**
690  * \ingroup       gdcmHeader
691  * \brief         Loads the element content if it's length is not bigger
692  *                than the value specified with
693  *                gdcmHeader::SetMaxSizeLoadElementValue()
694  */
695 void gdcmHeader::LoadElementValue(ElValue * ElVal) {
696         size_t item_read;
697         guint16 group  = ElVal->GetGroup();
698         guint16 elem   = ElVal->GetElement();
699         string  vr     = ElVal->GetVR();
700         guint32 length = ElVal->GetLength();
701         bool SkipLoad  = false;
702
703         fseek(fp, (long)ElVal->GetOffset(), SEEK_SET);
704         
705         // Sequences not treated yet !
706         //
707         // Ne faudrait-il pas au contraire trouver immediatement
708         // une maniere 'propre' de traiter les sequences (vr = SQ)
709         // car commencer par les ignorer risque de conduire a qq chose
710         // qui pourrait ne pas etre generalisable
711         //
712         if( vr == "SQ" )
713                 SkipLoad = true;
714
715         // Heuristic : a sequence "contains" a set of tags (called items). It looks
716         // like the last tag of a sequence (the one that terminates the sequence)
717         // has a group of 0xfffe (with a dummy length).
718         if( group == 0xfffe )
719                 SkipLoad = true;
720
721         // The group length doesn't represent data to be loaded in memory, since
722         // each element of the group shall be loaded individualy.
723         if( elem == 0 )
724                 //SkipLoad = true;              // modif sauvage JPR
725                                                                 // On charge la longueur du groupe
726                                                                 // quand l'element 0x0000 est présent !
727
728         if ( SkipLoad ) {
729                           // FIXME the following skip is not necessary
730                 SkipElementValue(ElVal);
731                 ElVal->SetLength(0);
732                 ElVal->SetValue("gdcm::Skipped");
733                 return;
734         }
735
736         // When the length is zero things are easy:
737         if ( length == 0 ) {
738                 ElVal->SetValue("");
739                 return;
740         }
741
742         // The elements whose length is bigger than the specified upper bound
743         // are not loaded. Instead we leave a short notice of the offset of
744         // the element content and it's length.
745         if (length > MaxSizeLoadElementValue) {
746                 ostringstream s;
747                 s << "gdcm::NotLoaded.";
748                 s << " Address:" << (long)ElVal->GetOffset();
749                 s << " Length:"  << ElVal->GetLength();
750                 ElVal->SetValue(s.str());
751                 return;
752         }
753         
754         // When an integer is expected, read and convert the following two or
755         // four bytes properly i.e. as an integer as opposed to a string.
756         if ( IsAnInteger(ElVal) ) {
757                 guint32 NewInt;
758                 if( length == 2 ) {
759                         NewInt = ReadInt16();
760                 } else if( length == 4 ) {
761                         NewInt = ReadInt32();
762                 } else
763                         dbg.Error(true, "LoadElementValue: Inconsistency when reading Int.");
764                 
765                 //FIXME: make the following an util fonction
766                 ostringstream s;
767                 s << NewInt;
768                 ElVal->SetValue(s.str());
769                 return;
770         }
771         
772         // FIXME The exact size should be length if we move to strings or whatever
773         char* NewValue = (char*)malloc(length+1);
774         if( !NewValue) {
775                 dbg.Verbose(1, "LoadElementValue: Failed to allocate NewValue");
776                 return;
777         }
778         NewValue[length]= 0;
779         
780         item_read = fread(NewValue, (size_t)length, (size_t)1, fp);
781         if ( item_read != 1 ) {
782                 free(NewValue);
783                 dbg.Verbose(1, "gdcmHeader::LoadElementValue","unread element value");
784                 ElVal->SetValue("gdcm::UnRead");
785                 return;
786         }
787         ElVal->SetValue(NewValue);
788 }
789
790 /**
791  * \ingroup       gdcmHeader
792  * \brief         Loads the element while preserving the current
793  *                underlying file position indicator as opposed to
794  *                to LoadElementValue that modifies it.
795  * @param ElVal   Element whose value shall be loaded. 
796  * @return  
797  */
798 void gdcmHeader::LoadElementValueSafe(ElValue * ElVal) {
799         long PositionOnEntry = ftell(fp);
800         LoadElementValue(ElVal);
801         fseek(fp, PositionOnEntry, SEEK_SET);
802 }
803
804
805 guint16 gdcmHeader::ReadInt16(void) {
806         guint16 g;
807         size_t item_read;
808         item_read = fread (&g, (size_t)2,(size_t)1, fp);
809         errno = 0;
810         if ( item_read != 1 ) {
811                 dbg.Verbose(1, "gdcmHeader::ReadInt16", " File read error");
812                 errno = 1;
813                 return 0;
814         }
815         g = SwapShort(g);
816         return g;
817 }
818
819 guint32 gdcmHeader::ReadInt32(void) {
820         guint32 g;
821         size_t item_read;
822         item_read = fread (&g, (size_t)4,(size_t)1, fp);
823         errno = 0;
824         if ( item_read != 1 ) {
825                 dbg.Verbose(1, "gdcmHeader::ReadInt32", " File read error");
826                 errno = 1;
827                 return 0;
828         }
829         g = SwapLong(g);
830         return g;
831 }
832
833 /**
834  * \ingroup gdcmHeader
835  * \brief   Build a new Element Value from all the low level arguments. 
836  *          Check for existence of dictionary entry, and build
837  *          a default one when absent.
838  * @param   Group group   of the underlying DictEntry
839  * @param   Elem  element of the underlying DictEntry
840  */
841 ElValue* gdcmHeader::NewElValueByKey(guint16 Group, guint16 Elem) {
842         // Find out if the tag we encountered is in the dictionaries:
843         gdcmDictEntry * NewTag = GetDictEntryByKey(Group, Elem);
844         if (!NewTag)
845                 NewTag = new gdcmDictEntry(Group, Elem);
846
847         ElValue* NewElVal = new ElValue(NewTag);
848         if (!NewElVal) {
849                 dbg.Verbose(1, "gdcmHeader::NewElValueByKey",
850                             "failed to allocate ElValue");
851                 return (ElValue*)0;
852         }
853    return NewElVal;
854 }
855
856 /**
857  * \ingroup gdcmHeader
858  * \brief   Build a new Element Value from all the low level arguments. 
859  *          Check for existence of dictionary entry, and build
860  *          a default one when absent.
861  * @param   Name    Name of the underlying DictEntry
862  */
863 ElValue* gdcmHeader::NewElValueByName(string Name) {
864
865    gdcmDictEntry * NewTag = GetDictEntryByName(Name);
866    if (!NewTag)
867       NewTag = new gdcmDictEntry(0xffff, 0xffff, "LO", "Unknown", Name);
868
869    ElValue* NewElVal = new ElValue(NewTag);
870    if (!NewElVal) {
871       dbg.Verbose(1, "gdcmHeader::ObtainElValueByName",
872                   "failed to allocate ElValue");
873       return (ElValue*)0;
874    }
875    return NewElVal;
876 }  
877
878
879 /**
880  * \ingroup gdcmHeader
881  * \brief   Read the next tag without loading it's value
882  * @return  On succes the newly created ElValue, NULL on failure.      
883  */
884
885 ElValue * gdcmHeader::ReadNextElement(void) {
886         guint16 g;
887         guint16 n;
888         ElValue * NewElVal;
889         
890         g = ReadInt16();
891         n = ReadInt16();
892         if (errno == 1)
893                 // We reached the EOF (or an error occured) and header parsing
894                 // has to be considered as finished.
895                 return (ElValue *)0;
896         
897         NewElVal = NewElValueByKey(g, n);
898         FindVR(NewElVal);
899         FindLength(NewElVal);
900         if (errno == 1)
901                 // Call it quits
902                 return (ElValue *)0;
903         NewElVal->SetOffset(ftell(fp));
904         return NewElVal;
905 }
906
907 bool gdcmHeader::IsAnInteger(ElValue * ElVal) {
908         guint16 group   = ElVal->GetGroup();
909         guint16 element = ElVal->GetElement();
910         string  vr      = ElVal->GetVR();
911         guint32 length  = ElVal->GetLength();
912
913         // When we have some semantics on the element we just read, and if we
914         // a priori know we are dealing with an integer, then we shall be
915         // able to swap it's element value properly.
916         if ( element == 0 )  {  // This is the group length of the group
917                 if (length == 4)
918                         return true;
919                 else
920                         dbg.Error("gdcmHeader::IsAnInteger",
921                                   "Erroneous Group Length element length.");
922         }
923         
924         if ( group % 2 != 0 )
925                 // We only have some semantics on documented elements, which are
926                 // the even ones.
927                 return false;
928         
929         if ( (length != 4) && ( length != 2) )
930                 // Swapping only make sense on integers which are 2 or 4 bytes long.
931                 return false;
932         
933         if ( (vr == "UL") || (vr == "US") || (vr == "SL") || (vr == "SS") )
934                 return true;
935         
936         if ( (group == 0x0028) && (element == 0x0005) )
937                 // The "Image Dimensions" tag is retained from ACR/NEMA and contains
938                 // the number of dimensions of the contained object (1 for Signal,
939                 // 2 for Image, 3 for Volume, 4 for Sequence).
940                 return true;
941         
942         if ( (group == 0x0028) && (element == 0x0200) )
943                 // This tag is retained from ACR/NEMA
944                 return true;
945         
946         return false;
947 }
948
949 /**
950  * \ingroup gdcmHeader
951  * \brief   Recover the offset (from the beginning of the file) of the pixels.
952  */
953 size_t gdcmHeader::GetPixelOffset(void) {
954         // If this file complies with the norm we should encounter the
955         // "Image Location" tag (0x0028,  0x0200). This tag contains the
956         // the group that contains the pixel data (hence the "Pixel Data"
957         // is found by indirection through the "Image Location").
958         // Inside the group pointed by "Image Location" the searched element
959         // is conventionally the element 0x0010 (when the norm is respected).
960         //    When the "Image Location" is absent we default to group 0x7fe0.
961         guint16 grPixel;
962         guint16 numPixel;
963         string ImageLocation = GetPubElValByName("Image Location");
964         if ( ImageLocation == "gdcm::Unfound" ) {
965                 grPixel = 0x7fe0;
966         } else {
967                 grPixel = (guint16) atoi( ImageLocation.c_str() );
968         }
969         if (grPixel != 0x7fe0)
970                 // FIXME is this still necessary ?
971                 // Now, this looks like an old dirty fix for Philips imager
972                 numPixel = 0x1010;
973         else
974                 numPixel = 0x0010;
975         ElValue* PixelElement = PubElVals.GetElementByNumber(grPixel, numPixel);
976         if (PixelElement)
977                 return PixelElement->GetOffset();
978         else
979                 return 0;
980 }
981
982 /**
983  * \ingroup gdcmHeader
984  * \brief   Searches both the public and the shadow dictionary (when they
985  *          exist) for the presence of the DictEntry with given
986  *          group and element. The public dictionary has precedence on the
987  *          shadow one.
988  * @param   group   group of the searched DictEntry
989  * @param   element element of the searched DictEntry
990  * @return  Corresponding DictEntry when it exists, NULL otherwise.
991  */
992 gdcmDictEntry * gdcmHeader::GetDictEntryByKey(guint16 group, guint16 element) {
993         gdcmDictEntry * found = (gdcmDictEntry*)0;
994         if (!RefPubDict && !RefShaDict) {
995                 dbg.Verbose(0, "FIXME in gdcmHeader::GetDictEntry",
996                      "we SHOULD have a default dictionary");
997         }
998         if (RefPubDict) {
999                 found = RefPubDict->GetTagByKey(group, element);
1000                 if (found)
1001                         return found;
1002         }
1003         if (RefShaDict) {
1004                 found = RefShaDict->GetTagByKey(group, element);
1005                 if (found)
1006                         return found;
1007         }
1008         return found;
1009 }
1010
1011 /**
1012  * \ingroup gdcmHeader
1013  * \brief   Searches both the public and the shadow dictionary (when they
1014  *          exist) for the presence of the DictEntry with given name.
1015  *          The public dictionary has precedence on the shadow one.
1016  * @earam   Name name of the searched DictEntry
1017  * @return  Corresponding DictEntry when it exists, NULL otherwise.
1018  */
1019 gdcmDictEntry * gdcmHeader::GetDictEntryByName(string Name) {
1020         gdcmDictEntry * found = (gdcmDictEntry*)0;
1021         if (!RefPubDict && !RefShaDict) {
1022                 dbg.Verbose(0, "FIXME in gdcmHeader::GetDictEntry",
1023                      "we SHOULD have a default dictionary");
1024         }
1025         if (RefPubDict) {
1026                 found = RefPubDict->GetTagByName(Name);
1027                 if (found)
1028                         return found;
1029         }
1030         if (RefShaDict) {
1031                 found = RefShaDict->GetTagByName(Name);
1032                 if (found)
1033                         return found;
1034         }
1035         return found;
1036 }
1037
1038 string gdcmHeader::GetPubElValByNumber(guint16 group, guint16 element) {
1039         return PubElVals.GetElValueByNumber(group, element);
1040 }
1041
1042 string gdcmHeader::GetPubElValRepByNumber(guint16 group, guint16 element) {
1043         ElValue* elem =  PubElVals.GetElementByNumber(group, element);
1044         if ( !elem )
1045                 return "gdcm::Unfound";
1046         return elem->GetVR();
1047 }
1048
1049 string gdcmHeader::GetPubElValByName(string TagName) {
1050         return PubElVals.GetElValueByName(TagName);
1051 }
1052
1053 string gdcmHeader::GetPubElValRepByName(string TagName) {
1054         ElValue* elem =  PubElVals.GetElementByName(TagName);
1055         if ( !elem )
1056                 return "gdcm::Unfound";
1057         return elem->GetVR();
1058 }
1059
1060 string gdcmHeader::GetShaElValByNumber(guint16 group, guint16 element) {
1061         return ShaElVals.GetElValueByNumber(group, element);
1062 }
1063
1064 string gdcmHeader::GetShaElValRepByNumber(guint16 group, guint16 element) {
1065         ElValue* elem =  ShaElVals.GetElementByNumber(group, element);
1066         if ( !elem )
1067                 return "gdcm::Unfound";
1068         return elem->GetVR();
1069 }
1070
1071 string gdcmHeader::GetShaElValByName(string TagName) {
1072         return ShaElVals.GetElValueByName(TagName);
1073 }
1074
1075 string gdcmHeader::GetShaElValRepByName(string TagName) {
1076         ElValue* elem =  ShaElVals.GetElementByName(TagName);
1077         if ( !elem )
1078                 return "gdcm::Unfound";
1079         return elem->GetVR();
1080 }
1081
1082 string gdcmHeader::GetElValByNumber(guint16 group, guint16 element) {
1083         string pub = GetPubElValByNumber(group, element);
1084         if (pub.length())
1085                 return pub;
1086         return GetShaElValByNumber(group, element);
1087 }
1088
1089 string gdcmHeader::GetElValRepByNumber(guint16 group, guint16 element) {
1090         string pub = GetPubElValRepByNumber(group, element);
1091         if (pub.length())
1092                 return pub;
1093         return GetShaElValRepByNumber(group, element);
1094 }
1095
1096 string gdcmHeader::GetElValByName(string TagName) {
1097         string pub = GetPubElValByName(TagName);
1098         if (pub.length())
1099                 return pub;
1100         return GetShaElValByName(TagName);
1101 }
1102
1103 string gdcmHeader::GetElValRepByName(string TagName) {
1104         string pub = GetPubElValRepByName(TagName);
1105         if (pub.length())
1106                 return pub;
1107         return GetShaElValRepByName(TagName);
1108 }
1109
1110 /**
1111  * \ingroup gdcmHeader
1112  * \brief   Accesses an existing ElValue in the PubElVals of this instance
1113  *          through it's (group, element) and modifies it's content with
1114  *          the given value.
1115  * @param   content new value to substitute with
1116  * @param   group   group of the ElVal to modify
1117  * @param   element element of the ElVal to modify
1118  */
1119 int gdcmHeader::SetPubElValByNumber(string content, guint16 group,
1120                                     guint16 element)
1121 {
1122         //CLEANME TagKey key = gdcmDictEntry::TranslateToKey(group, element);
1123         //CLEANME PubElVals.tagHt[key]->SetValue(content);
1124         return (  PubElVals.SetElValueByNumber (content, group, element) );
1125 }
1126
1127 /**
1128  * \ingroup gdcmHeader
1129  * \brief   Accesses an existing ElValue in the PubElVals of this instance
1130  *          through tag name and modifies it's content with the given value.
1131  * @param   content new value to substitute with
1132  * @param   TagName name of the tag to be modified
1133  */
1134 int gdcmHeader::SetPubElValByName(string content, string TagName) {
1135         //CLEANME TagKey key = gdcmDictEntry::TranslateToKey(group, element);
1136         //CLEANME PubElVals.tagHt[key]->SetValue(content);
1137         return (  PubElVals.SetElValueByName (content, TagName) );
1138 }
1139
1140 /**
1141  * \ingroup gdcmHeader
1142  * \brief   Accesses an existing ElValue in the ShaElVals of this instance
1143  *          through it's (group, element) and modifies it's content with
1144  *          the given value.
1145  * @param   content new value to substitute with
1146  * @param   group   group of the ElVal to modify
1147  * @param   element element of the ElVal to modify
1148  */
1149 int gdcmHeader::SetShaElValByNumber(string content,
1150                                     guint16 group, guint16 element)
1151 {
1152         return (  ShaElVals.SetElValueByNumber (content, group, element) );
1153 }
1154
1155 /**
1156  * \ingroup gdcmHeader
1157  * \brief   Accesses an existing ElValue in the ShaElVals of this instance
1158  *          through tag name and modifies it's content with the given value.
1159  * @param   content new value to substitute with
1160  * @param   TagName name of the tag to be modified
1161  */
1162 int gdcmHeader::SetShaElValByName(string content, string TagName) {
1163         return (  ShaElVals.SetElValueByName (content, TagName) );
1164 }
1165
1166 /**
1167  * \ingroup gdcmHeader
1168  * \brief   Parses the header of the file but WITHOUT loading element values.
1169  */
1170 void gdcmHeader::ParseHeader(bool exception_on_error) throw(gdcmFormatError) {
1171         ElValue * newElValue = (ElValue *)0;
1172         
1173         rewind(fp);
1174         CheckSwap();
1175         while ( (newElValue = ReadNextElement()) ) {
1176                 SkipElementValue(newElValue);
1177                 PubElVals.Add(newElValue);
1178         }
1179 }
1180
1181 /**
1182  * \ingroup gdcmHeader
1183  * \brief   Once the header is parsed add some gdcm convenience/helper elements
1184  *          in the ElValSet. For example add:
1185  *          - gdcmImageType which is an entry containing a short for the
1186  *            type of image and whose value ranges in 
1187  *               I8   (unsigned 8 bit image)
1188  *               I16  (unsigned 8 bit image)
1189  *               IS16 (signed 8 bit image)
1190  *          - gdcmXsize, gdcmYsize, gdcmZsize whose values are respectively
1191  *            the ones of the official DICOM fields Rows, Columns and Planes.
1192  */
1193 void gdcmHeader::AddAndDefaultElements(void) {
1194         ElValue* NewEntry = (ElValue*)0;
1195
1196         NewEntry = NewElValueByName("gdcmXSize");
1197         NewEntry->SetValue(GetElValByName("Rows"));
1198         PubElVals.Add(NewEntry);
1199
1200         NewEntry = NewElValueByName("gdcmYSize");
1201         NewEntry->SetValue(GetElValByName("Columns"));
1202         PubElVals.Add(NewEntry);
1203
1204         NewEntry = NewElValueByName("gdcmZSize");
1205         NewEntry->SetValue(GetElValByName("Planes"));
1206         PubElVals.Add(NewEntry);
1207 }
1208
1209 /**
1210  * \ingroup gdcmHeader
1211  * \brief   Loads the element values of all the elements present in the
1212  *          public tag based hash table.
1213  */
1214 void gdcmHeader::LoadElements(void) {
1215         rewind(fp);   
1216         TagElValueHT ht = PubElVals.GetTagHt();
1217         for (TagElValueHT::iterator tag = ht.begin(); tag != ht.end(); ++tag) {
1218                 LoadElementValue(tag->second);
1219                 }
1220 }
1221
1222 void gdcmHeader::PrintPubElVal(ostream & os) {
1223         PubElVals.Print(os);
1224 }
1225
1226 void gdcmHeader::PrintPubDict(ostream & os) {
1227         RefPubDict->Print(os);
1228 }