9 #include <netinet/in.h>
11 #include <cctype> // for isalpha
14 #include "gdcmHeader.h"
16 // Refer to gdcmHeader::CheckSwap()
17 #define HEADER_LENGTH_TO_READ 256
18 // Refer to gdcmHeader::SetMaxSizeLoadElementValue()
19 #define _MaxSizeLoadElementValue_ 1024
21 VRHT * gdcmHeader::dicom_vr = (VRHT*)0;
23 void gdcmHeader::Initialise(void) {
24 if (!gdcmHeader::dicom_vr)
26 Dicts = new gdcmDictSet();
27 RefPubDict = Dicts->GetDefaultPubDict();
28 RefShaDict = (gdcmDict*)0;
31 gdcmHeader::gdcmHeader(const char *InFilename, bool exception_on_error)
32 throw(gdcmFileError) {
33 SetMaxSizeLoadElementValue(_MaxSizeLoadElementValue_);
34 filename = InFilename;
36 fp=fopen(InFilename,"rb");
37 if(exception_on_error) {
39 throw gdcmFileError("gdcmHeader::gdcmHeader(const char *, bool)");
42 dbg.Error(!fp, "gdcmHeader::gdcmHeader cannot open file", InFilename);
44 AddAndDefaultElements();
48 gdcmHeader::~gdcmHeader (void) {
49 //FIXME obviously there is much to be done here !
54 void gdcmHeader::InitVRDict (void) {
56 dbg.Verbose(0, "gdcmHeader::InitVRDict:", "VR dictionary allready set");
60 (*vr)["AE"] = "Application Entity"; // At most 16 bytes
61 (*vr)["AS"] = "Age String"; // Exactly 4 bytes
62 (*vr)["AT"] = "Attribute Tag"; // 2 16-bit unsigned short integers
63 (*vr)["CS"] = "Code String"; // At most 16 bytes
64 (*vr)["DA"] = "Date"; // Exactly 8 bytes
65 (*vr)["DS"] = "Decimal String"; // At most 16 bytes
66 (*vr)["DT"] = "Date Time"; // At most 26 bytes
67 (*vr)["FL"] = "Floating Point Single"; // 32-bit IEEE 754:1985 float
68 (*vr)["FD"] = "Floating Point Double"; // 64-bit IEEE 754:1985 double
69 (*vr)["IS"] = "Integer String"; // At most 12 bytes
70 (*vr)["LO"] = "Long String"; // At most 64 chars
71 (*vr)["LT"] = "Long Text"; // At most 10240 chars
72 (*vr)["OB"] = "Other Byte String"; // String of bytes (vr independant)
73 (*vr)["OW"] = "Other Word String"; // String of 16-bit words (vr dep)
74 (*vr)["PN"] = "Person Name"; // At most 64 chars
75 (*vr)["SH"] = "Short String"; // At most 16 chars
76 (*vr)["SL"] = "Signed Long"; // Exactly 4 bytes
77 (*vr)["SQ"] = "Sequence of Items"; // Not Applicable
78 (*vr)["SS"] = "Signed Short"; // Exactly 2 bytes
79 (*vr)["ST"] = "Short Text"; // At most 1024 chars
80 (*vr)["TM"] = "Time"; // At most 16 bytes
81 (*vr)["UI"] = "Unique Identifier"; // At most 64 bytes
82 (*vr)["UL"] = "Unsigned Long "; // Exactly 4 bytes
83 (*vr)["UN"] = "Unknown"; // Any length of bytes
84 (*vr)["US"] = "Unsigned Short "; // Exactly 2 bytes
85 (*vr)["UT"] = "Unlimited Text"; // At most 2^32 -1 chars
91 * \brief Discover what the swap code is (among little endian, big endian,
92 * bad little endian, bad big endian).
95 void gdcmHeader::CheckSwap()
97 // The only guaranted way of finding the swap code is to find a
98 // group tag since we know it's length has to be of four bytes i.e.
99 // 0x00000004. Finding the swap code in then straigthforward. Trouble
100 // occurs when we can't find such group...
102 guint32 x=4; // x : pour ntohs
103 bool net2host; // true when HostByteOrder is the same as NetworkByteOrder
107 char deb[HEADER_LENGTH_TO_READ];
109 // First, compare HostByteOrder and NetworkByteOrder in order to
110 // determine if we shall need to swap bytes (i.e. the Endian type).
116 // The easiest case is the one of a DICOM header, since it possesses a
117 // file preamble where it suffice to look for the string "DICM".
118 lgrLue = fread(deb, 1, HEADER_LENGTH_TO_READ, fp);
121 if(memcmp(entCur, "DICM", (size_t)4) == 0) {
122 filetype = TrueDicom;
123 dbg.Verbose(1, "gdcmHeader::CheckSwap:", "looks like DICOM Version3");
126 dbg.Verbose(1, "gdcmHeader::CheckSwap:", "not a DICOM Version3 file");
129 if(filetype == TrueDicom) {
130 // Next, determine the value representation (VR). Let's skip to the
131 // first element (0002, 0000) and check there if we find "UL", in
132 // which case we (almost) know it is explicit VR.
133 // WARNING: if it happens to be implicit VR then what we will read
134 // is the length of the group. If this ascii representation of this
135 // length happens to be "UL" then we shall believe it is explicit VR.
136 // FIXME: in order to fix the above warning, we could read the next
137 // element value (or a couple of elements values) in order to make
138 // sure we are not commiting a big mistake.
140 // * the 128 bytes of File Preamble (often padded with zeroes),
141 // * the 4 bytes of "DICM" string,
142 // * the 4 bytes of the first tag (0002, 0000),
143 // i.e. a total of 136 bytes.
145 if(memcmp(entCur, "UL", (size_t)2) == 0) {
146 filetype = ExplicitVR;
147 dbg.Verbose(1, "gdcmHeader::CheckSwap:",
148 "explicit Value Representation");
150 filetype = ImplicitVR;
151 dbg.Verbose(1, "gdcmHeader::CheckSwap:",
152 "not an explicit Value Representation");
157 dbg.Verbose(1, "gdcmHeader::CheckSwap:",
158 "HostByteOrder != NetworkByteOrder");
161 dbg.Verbose(1, "gdcmHeader::CheckSwap:",
162 "HostByteOrder = NetworkByteOrder");
165 // Position the file position indicator at first tag (i.e.
166 // after the file preamble and the "DICM" string).
168 fseek (fp, 132L, SEEK_SET);
170 } // End of TrueDicom
172 // Alas, this is not a DicomV3 file and whatever happens there is no file
173 // preamble. We can reset the file position indicator to where the data
174 // is (i.e. the beginning of the file).
177 // Our next best chance would be to be considering a 'clean' ACR/NEMA file.
178 // By clean we mean that the length of the first tag is written down.
179 // If this is the case and since the length of the first group HAS to be
180 // four (bytes), then determining the proper swap code is straightforward.
183 // We assume the array of char we are considering contains the binary
184 // representation of a 32 bits integer. Hence the following dirty
186 s = *((guint32 *)(entCur));
206 dbg.Verbose(0, "gdcmHeader::CheckSwap:",
207 "ACR/NEMA unfound swap info (time to raise bets)");
210 // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file.
211 // It is time for despaired wild guesses. So, let's assume this file
212 // happens to be 'dirty' ACR/NEMA, i.e. the length of the group is
213 // not present. Then the only info we have is the net2host one.
221 void gdcmHeader::SwitchSwapToBigEndian(void) {
222 dbg.Verbose(1, "gdcmHeader::SwitchSwapToBigEndian",
223 "Switching to BigEndian mode.");
240 void gdcmHeader::GetPixels(size_t lgrTotale, void* _Pixels) {
242 pixelsOffset = GetPixelOffset();
243 fseek(fp, pixelsOffset, SEEK_SET);
244 fread(_Pixels, 1, lgrTotale, fp);
250 * \ingroup gdcmHeader
251 * \brief Find the value representation of the current tag.
253 void gdcmHeader::FindVR( ElValue *ElVal) {
254 if (filetype != ExplicitVR)
260 long PositionOnEntry = ftell(fp);
261 // Warning: we believe this is explicit VR (Value Representation) because
262 // we used a heuristic that found "UL" in the first tag. Alas this
263 // doesn't guarantee that all the tags will be in explicit VR. In some
264 // cases (see e-film filtered files) one finds implicit VR tags mixed
265 // within an explicit VR file. Hence we make sure the present tag
266 // is in explicit VR and try to fix things if it happens not to be
268 bool RealExplicit = true;
270 lgrLue=fread (&VR, (size_t)2,(size_t)1, fp);
274 // Assume we are reading a falsely explicit VR file i.e. we reached
275 // a tag where we expect reading a VR but are in fact we read the
276 // first to bytes of the length. Then we will interogate (through find)
277 // the dicom_vr dictionary with oddities like "\004\0" which crashes
278 // both GCC and VC++ implementations of the STL map. Hence when the
279 // expected VR read happens to be non-ascii characters we consider
280 // we hit falsely explicit VR tag.
282 if ( (!isalpha(VR[0])) && (!isalpha(VR[1])) )
283 RealExplicit = false;
285 // CLEANME searching the dicom_vr at each occurence is expensive.
286 // PostPone this test in an optional integrity check at the end
287 // of parsing or only in debug mode.
288 if ( RealExplicit && !dicom_vr->count(vr) )
289 RealExplicit = false;
291 if ( RealExplicit ) {
292 if ( ElVal->IsVrUnknown() ) {
293 // When not a dictionary entry, we can safely overwrite the vr.
297 if ( ElVal->GetVR() == vr ) {
298 // The vr we just read and the dictionary agree. Nothing to do.
301 // The vr present in the file and the dictionary disagree. We assume
302 // the file writer knew best and use the vr of the file. Since it would
303 // be unwise to overwrite the vr of a dictionary (since it would
304 // compromise it's next user), we need to clone the actual DictEntry
305 // and change the vr for the read one.
306 gdcmDictEntry* NewTag = new gdcmDictEntry(ElVal->GetGroup(),
311 ElVal->SetDictEntry(NewTag);
315 // We thought this was explicit VR, but we end up with an
316 // implicit VR tag. Let's backtrack.
317 dbg.Verbose(1, "gdcmHeader::FindVR:", "Falsely explicit vr file");
318 fseek(fp, PositionOnEntry, SEEK_SET);
319 // When this element is known in the dictionary we shall use, e.g. for
320 // the semantics (see the usage of IsAnInteger), the vr proposed by the
321 // dictionary entry. Still we have to flag the element as implicit since
322 // we know now our assumption on expliciteness is not furfilled.
324 if ( ElVal->IsVrUnknown() )
325 ElVal->SetVR("Implicit");
326 ElVal->SetImplicitVr();
330 * \ingroup gdcmHeader
331 * \brief Determines if the Transfer Syntax was allready encountered
332 * and if it corresponds to a ImplicitVRLittleEndian one.
334 * @return True when ImplicitVRLittleEndian found. False in all other cases.
336 bool gdcmHeader::IsImplicitVRLittleEndianTransferSyntax(void) {
337 ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
340 LoadElementValueSafe(Element);
341 string Transfer = Element->GetValue();
342 if ( Transfer == "1.2.840.10008.1.2" )
348 * \ingroup gdcmHeader
349 * \brief Determines if the Transfer Syntax was allready encountered
350 * and if it corresponds to a ExplicitVRLittleEndian one.
352 * @return True when ExplicitVRLittleEndian found. False in all other cases.
354 bool gdcmHeader::IsExplicitVRLittleEndianTransferSyntax(void) {
355 ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
358 LoadElementValueSafe(Element);
359 string Transfer = Element->GetValue();
360 if ( Transfer == "1.2.840.10008.1.2.1" )
366 * \ingroup gdcmHeader
367 * \brief Determines if the Transfer Syntax was allready encountered
368 * and if it corresponds to a DeflatedExplicitVRLittleEndian one.
370 * @return True when DeflatedExplicitVRLittleEndian found. False in all other cases.
372 bool gdcmHeader::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) {
373 ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
376 LoadElementValueSafe(Element);
377 string Transfer = Element->GetValue();
378 if ( Transfer == "1.2.840.10008.1.2.1.99" )
384 * \ingroup gdcmHeader
385 * \brief Determines if the Transfer Syntax was allready encountered
386 * and if it corresponds to a Explicit VR Big Endian one.
388 * @return True when big endian found. False in all other cases.
390 bool gdcmHeader::IsExplicitVRBigEndianTransferSyntax(void) {
391 ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
394 LoadElementValueSafe(Element);
395 string Transfer = Element->GetValue();
396 if ( Transfer == "1.2.840.10008.1.2.2" )
402 * \ingroup gdcmHeader
403 * \brief Determines if the Transfer Syntax was allready encountered
404 * and if it corresponds to a JPEGBaseLineProcess1 one.
406 * @return True when JPEGBaseLineProcess1found. False in all other cases.
408 bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) {
409 ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
412 LoadElementValueSafe(Element);
413 string Transfer = Element->GetValue();
414 if ( Transfer == "1.2.840.10008.1.2.4.50" )
420 * \ingroup gdcmHeader
421 * \brief Determines if the Transfer Syntax was allready encountered
422 * and if it corresponds to a JPEGExtendedProcess2-4 one.
424 * @return True when JPEGExtendedProcess2-4 found. False in all other cases.
426 bool gdcmHeader::IsJPEGExtendedProcess2_4TransferSyntax(void) {
427 ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
430 LoadElementValueSafe(Element);
431 string Transfer = Element->GetValue();
432 if ( Transfer == "1.2.840.10008.1.2.4.51" )
438 * \ingroup gdcmHeader
439 * \brief Determines if the Transfer Syntax was allready encountered
440 * and if it corresponds to a JPEGExtendeProcess3-5 one.
442 * @return True when JPEGExtendedProcess3-5 found. False in all other cases.
444 bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) {
445 ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
448 LoadElementValueSafe(Element);
449 string Transfer = Element->GetValue();
450 if ( Transfer == "1.2.840.10008.1.2.4.52" )
456 * \ingroup gdcmHeader
457 * \brief Determines if the Transfer Syntax was allready encountered
458 * and if it corresponds to a JPEGSpectralSelectionProcess6-8 one.
460 * @return True when JPEGSpectralSelectionProcess6-8 found. False in all
463 bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) {
464 ElValue* Element = PubElVals.GetElementByNumber(0x0002, 0x0010);
467 LoadElementValueSafe(Element);
468 string Transfer = Element->GetValue();
469 if ( Transfer == "1.2.840.10008.1.2.4.53" )
475 * \ingroup gdcmHeader
476 * \brief When the length of an element value is obviously wrong (because
477 * the parser went Jabberwocky) one can hope improving things by
478 * applying this heuristic.
480 void gdcmHeader::FixFoundLength(ElValue * ElVal, guint32 FoundLength) {
481 if ( FoundLength == 0xffffffff)
483 ElVal->SetLength(FoundLength);
486 guint32 gdcmHeader::FindLengthOB(void) {
487 // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
490 long PositionOnEntry = ftell(fp);
491 bool FoundSequenceDelimiter = false;
492 guint32 TotalLength = 0;
495 while ( ! FoundSequenceDelimiter) {
500 TotalLength += 4; // We even have to decount the group and element
502 dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",
503 "wrong group for an item sequence.");
508 FoundSequenceDelimiter = true;
509 else if ( n != 0xe000) {
510 dbg.Verbose(1, "gdcmHeader::FindLengthOB: ",
511 "wrong element for an item sequence.");
515 ItemLength = ReadInt32();
516 TotalLength += ItemLength + 4; // We add 4 bytes since we just read
517 // the ItemLength with ReadInt32
518 SkipBytes(ItemLength);
520 fseek(fp, PositionOnEntry, SEEK_SET);
524 void gdcmHeader::FindLength(ElValue * ElVal) {
525 guint16 element = ElVal->GetElement();
526 string vr = ElVal->GetVR();
529 if ( (filetype == ExplicitVR) && ! ElVal->IsImplicitVr() ) {
531 if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) {
532 // The following reserved two bytes (see PS 3.5-2001, section
533 // 7.1.2 Data element structure with explicit vr p27) must be
534 // skipped before proceeding on reading the length on 4 bytes.
535 fseek(fp, 2L, SEEK_CUR);
536 guint32 length32 = ReadInt32();
537 if ( (vr == "OB") && (length32 == 0xffffffff) ) {
538 ElVal->SetLength(FindLengthOB());
541 FixFoundLength(ElVal, length32);
545 // Length is encoded on 2 bytes.
546 length16 = ReadInt16();
548 // We can tell the current file is encoded in big endian (like
549 // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag
550 // and it's value is the one of the encoding of a big endian file.
551 // In order to deal with such big endian encoded files, we have
552 // (at least) two strategies:
553 // * when we load the "Transfer Syntax" tag with value of big endian
554 // encoding, we raise the proper flags. Then we wait for the end
555 // of the META group (0x0002) among which is "Transfer Syntax",
556 // before switching the swap code to big endian. We have to postpone
557 // the switching of the swap code since the META group is fully encoded
558 // in little endian, and big endian coding only starts at the next
559 // group. The corresponding code can be hard to analyse and adds
560 // many additional unnecessary tests for regular tags.
561 // * the second strategy consists in waiting for trouble, that shall
562 // appear when we find the first group with big endian encoding. This
563 // is easy to detect since the length of a "Group Length" tag (the
564 // ones with zero as element number) has to be of 4 (0x0004). When we
565 // encouter 1024 (0x0400) chances are the encoding changed and we
566 // found a group with big endian encoding.
567 // We shall use this second strategy. In order to make sure that we
568 // can interpret the presence of an apparently big endian encoded
569 // length of a "Group Length" without committing a big mistake, we
570 // add an additional check: we look in the allready parsed elements
571 // for the presence of a "Transfer Syntax" whose value has to be "big
572 // endian encoding". When this is the case, chances are we have got our
573 // hands on a big endian encoded file: we switch the swap code to
574 // big endian and proceed...
575 if ( (element == 0x000) && (length16 == 0x0400) ) {
576 if ( ! IsExplicitVRBigEndianTransferSyntax() ) {
577 dbg.Verbose(0, "gdcmHeader::FindLength", "not explicit VR");
582 SwitchSwapToBigEndian();
583 // Restore the unproperly loaded values i.e. the group, the element
584 // and the dictionary entry depending on them.
585 guint16 CorrectGroup = SwapShort(ElVal->GetGroup());
586 guint16 CorrectElem = SwapShort(ElVal->GetElement());
587 gdcmDictEntry * NewTag = GetDictEntryByKey(CorrectGroup, CorrectElem);
589 // This correct tag is not in the dictionary. Create a new one.
590 NewTag = new gdcmDictEntry(CorrectGroup, CorrectElem);
592 // FIXME this can create a memory leaks on the old entry that be
593 // left unreferenced.
594 ElVal->SetDictEntry(NewTag);
597 // Heuristic: well some files are really ill-formed.
598 if ( length16 == 0xffff) {
600 dbg.Verbose(0, "gdcmHeader::FindLength",
601 "Erroneous element length fixed.");
603 FixFoundLength(ElVal, (guint32)length16);
607 // Either implicit VR or a non DICOM conformal (see not below) explicit
608 // VR that ommited the VR of (at least) this element. Farts happen.
609 // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25
610 // on Data elements "Implicit and Explicit VR Data Elements shall
611 // not coexist in a Data Set and Data Sets nested within it".]
612 // Length is on 4 bytes.
613 FixFoundLength(ElVal, ReadInt32());
617 * \ingroup gdcmHeader
618 * \brief Swaps back the bytes of 4-byte long integer accordingly to
621 * @return The suggested integer.
623 guint32 gdcmHeader::SwapLong(guint32 a) {
624 // FIXME: il pourrait y avoir un pb pour les entiers negatifs ...
629 a=( ((a<<24) & 0xff000000) | ((a<<8) & 0x00ff0000) |
630 ((a>>8) & 0x0000ff00) | ((a>>24) & 0x000000ff) );
634 a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
638 a=( ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) );
641 dbg.Error(" gdcmHeader::SwapLong : unset swap code");
648 * \ingroup gdcmHeader
649 * \brief Swaps the bytes so they agree with the processor order
650 * @return The properly swaped 16 bits integer.
652 guint16 gdcmHeader::SwapShort(guint16 a) {
653 if ( (sw==4321) || (sw==2143) )
654 a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff));
658 void gdcmHeader::SkipBytes(guint32 NBytes) {
659 //FIXME don't dump the returned value
660 (void)fseek(fp, (long)NBytes, SEEK_CUR);
663 void gdcmHeader::SkipElementValue(ElValue * ElVal) {
664 SkipBytes(ElVal->GetLength());
667 void gdcmHeader::SetMaxSizeLoadElementValue(long NewSize) {
670 if ((guint32)NewSize >= (guint32)0xffffffff) {
671 MaxSizeLoadElementValue = 0xffffffff;
674 MaxSizeLoadElementValue = NewSize;
678 * \ingroup gdcmHeader
679 * \brief Loads the element content if it's length is not bigger
680 * than the value specified with
681 * gdcmHeader::SetMaxSizeLoadElementValue()
683 void gdcmHeader::LoadElementValue(ElValue * ElVal) {
685 guint16 group = ElVal->GetGroup();
686 guint16 elem = ElVal->GetElement();
687 string vr = ElVal->GetVR();
688 guint32 length = ElVal->GetLength();
689 bool SkipLoad = false;
691 fseek(fp, (long)ElVal->GetOffset(), SEEK_SET);
693 // Sequences not treated yet !
695 // Ne faudrait-il pas au contraire trouver immediatement
696 // une maniere 'propre' de traiter les sequences (vr = SQ)
697 // car commencer par les ignorer risque de conduire a qq chose
698 // qui pourrait ne pas etre generalisable
703 // Heuristic : a sequence "contains" a set of tags (called items). It looks
704 // like the last tag of a sequence (the one that terminates the sequence)
705 // has a group of 0xfffe (with a dummy length).
706 if( group == 0xfffe )
709 // The group length doesn't represent data to be loaded in memory, since
710 // each element of the group shall be loaded individualy.
712 //SkipLoad = true; // modif sauvage JPR
713 // On charge la longueur du groupe
714 // quand l'element 0x0000 est présent !
717 // FIXME the following skip is not necessary
718 SkipElementValue(ElVal);
720 ElVal->SetValue("gdcm::Skipped");
724 // When the length is zero things are easy:
730 // The elements whose length is bigger than the specified upper bound
731 // are not loaded. Instead we leave a short notice of the offset of
732 // the element content and it's length.
733 if (length > MaxSizeLoadElementValue) {
735 s << "gdcm::NotLoaded.";
736 s << " Address:" << (long)ElVal->GetOffset();
737 s << " Length:" << ElVal->GetLength();
738 ElVal->SetValue(s.str());
742 // When an integer is expected, read and convert the following two or
743 // four bytes properly i.e. as an integer as opposed to a string.
744 if ( IsAnInteger(ElVal) ) {
747 NewInt = ReadInt16();
748 } else if( length == 4 ) {
749 NewInt = ReadInt32();
751 dbg.Error(true, "LoadElementValue: Inconsistency when reading Int.");
753 //FIXME: make the following an util fonction
756 ElVal->SetValue(s.str());
760 // FIXME The exact size should be length if we move to strings or whatever
761 char* NewValue = (char*)malloc(length+1);
763 dbg.Verbose(1, "LoadElementValue: Failed to allocate NewValue");
768 item_read = fread(NewValue, (size_t)length, (size_t)1, fp);
769 if ( item_read != 1 ) {
771 dbg.Verbose(1, "gdcmHeader::LoadElementValue","unread element value");
772 ElVal->SetValue("gdcm::UnRead");
775 ElVal->SetValue(NewValue);
779 * \ingroup gdcmHeader
780 * \brief Loads the element while preserving the current
781 * underlying file position indicator as opposed to
782 * to LoadElementValue that modifies it.
783 * @param ElVal Element whose value shall be loaded.
786 void gdcmHeader::LoadElementValueSafe(ElValue * ElVal) {
787 long PositionOnEntry = ftell(fp);
788 LoadElementValue(ElVal);
789 fseek(fp, PositionOnEntry, SEEK_SET);
793 guint16 gdcmHeader::ReadInt16(void) {
796 item_read = fread (&g, (size_t)2,(size_t)1, fp);
798 if ( item_read != 1 ) {
799 dbg.Verbose(1, "gdcmHeader::ReadInt16", " File read error");
807 guint32 gdcmHeader::ReadInt32(void) {
810 item_read = fread (&g, (size_t)4,(size_t)1, fp);
812 if ( item_read != 1 ) {
813 dbg.Verbose(1, "gdcmHeader::ReadInt32", " File read error");
822 * \ingroup gdcmHeader
823 * \brief Build a new Element Value from all the low level arguments.
824 * Check for existence of dictionary entry, and build
825 * a default one when absent.
826 * @param Group group of the underlying DictEntry
827 * @param Elem element of the underlying DictEntry
829 ElValue* gdcmHeader::NewElValueByKey(guint16 Group, guint16 Elem) {
830 // Find out if the tag we encountered is in the dictionaries:
831 gdcmDictEntry * NewTag = GetDictEntryByKey(Group, Elem);
833 NewTag = new gdcmDictEntry(Group, Elem);
835 ElValue* NewElVal = new ElValue(NewTag);
837 dbg.Verbose(1, "gdcmHeader::NewElValueByKey",
838 "failed to allocate ElValue");
845 * \ingroup gdcmHeader
846 * \brief Build a new Element Value from all the low level arguments.
847 * Check for existence of dictionary entry, and build
848 * a default one when absent.
849 * @param Name Name of the underlying DictEntry
851 ElValue* gdcmHeader::NewElValueByName(string Name) {
853 gdcmDictEntry * NewTag = GetDictEntryByName(Name);
855 NewTag = new gdcmDictEntry(0xffff, 0xffff, "LO", "Unknown", Name);
857 ElValue* NewElVal = new ElValue(NewTag);
859 dbg.Verbose(1, "gdcmHeader::ObtainElValueByName",
860 "failed to allocate ElValue");
867 * \ingroup gdcmHeader
868 * \brief Read the next tag but WITHOUT loading it's value
869 * @return On succes the newly created ElValue, NULL on failure.
871 ElValue * gdcmHeader::ReadNextElement(void) {
879 // We reached the EOF (or an error occured) and header parsing
880 // has to be considered as finished.
883 NewElVal = NewElValueByKey(g, n);
885 FindLength(NewElVal);
889 NewElVal->SetOffset(ftell(fp));
894 * \ingroup gdcmHeader
895 * \brief Apply some heuristics to predict wether the considered
896 * element value contains/represents an integer or not.
897 * @param ElVal The element value on which to apply the predicate.
898 * @return The result of the heuristical predicate.
900 bool gdcmHeader::IsAnInteger(ElValue * ElVal) {
901 guint16 group = ElVal->GetGroup();
902 guint16 element = ElVal->GetElement();
903 string vr = ElVal->GetVR();
904 guint32 length = ElVal->GetLength();
906 // When we have some semantics on the element we just read, and if we
907 // a priori know we are dealing with an integer, then we shall be
908 // able to swap it's element value properly.
909 if ( element == 0 ) { // This is the group length of the group
913 dbg.Error("gdcmHeader::IsAnInteger",
914 "Erroneous Group Length element length.");
917 if ( group % 2 != 0 )
918 // We only have some semantics on documented elements, which are
922 if ( (length != 4) && ( length != 2) )
923 // Swapping only make sense on integers which are 2 or 4 bytes long.
926 if ( (vr == "UL") || (vr == "US") || (vr == "SL") || (vr == "SS") )
929 if ( (group == 0x0028) && (element == 0x0005) )
930 // The "Image Dimensions" tag is retained from ACR/NEMA and contains
931 // the number of dimensions of the contained object (1 for Signal,
932 // 2 for Image, 3 for Volume, 4 for Sequence).
935 if ( (group == 0x0028) && (element == 0x0200) )
936 // This tag is retained from ACR/NEMA
943 * \ingroup gdcmHeader
944 * \brief Recover the offset (from the beginning of the file) of the pixels.
946 size_t gdcmHeader::GetPixelOffset(void) {
947 // If this file complies with the norm we should encounter the
948 // "Image Location" tag (0x0028, 0x0200). This tag contains the
949 // the group that contains the pixel data (hence the "Pixel Data"
950 // is found by indirection through the "Image Location").
951 // Inside the group pointed by "Image Location" the searched element
952 // is conventionally the element 0x0010 (when the norm is respected).
953 // When the "Image Location" is absent we default to group 0x7fe0.
956 string ImageLocation = GetPubElValByName("Image Location");
957 if ( ImageLocation == "gdcm::Unfound" ) {
960 grPixel = (guint16) atoi( ImageLocation.c_str() );
962 if (grPixel != 0x7fe0)
963 // FIXME is this still necessary ?
964 // Now, this looks like an old dirty fix for Philips imager
968 ElValue* PixelElement = PubElVals.GetElementByNumber(grPixel, numPixel);
970 return PixelElement->GetOffset();
976 * \ingroup gdcmHeader
977 * \brief Searches both the public and the shadow dictionary (when they
978 * exist) for the presence of the DictEntry with given
979 * group and element. The public dictionary has precedence on the
981 * @param group group of the searched DictEntry
982 * @param element element of the searched DictEntry
983 * @return Corresponding DictEntry when it exists, NULL otherwise.
985 gdcmDictEntry * gdcmHeader::GetDictEntryByKey(guint16 group, guint16 element) {
986 gdcmDictEntry * found = (gdcmDictEntry*)0;
987 if (!RefPubDict && !RefShaDict) {
988 dbg.Verbose(0, "FIXME in gdcmHeader::GetDictEntry",
989 "we SHOULD have a default dictionary");
992 found = RefPubDict->GetTagByKey(group, element);
997 found = RefShaDict->GetTagByKey(group, element);
1005 * \ingroup gdcmHeader
1006 * \brief Searches both the public and the shadow dictionary (when they
1007 * exist) for the presence of the DictEntry with given name.
1008 * The public dictionary has precedence on the shadow one.
1009 * @param Name name of the searched DictEntry
1010 * @return Corresponding DictEntry when it exists, NULL otherwise.
1012 gdcmDictEntry * gdcmHeader::GetDictEntryByName(string Name) {
1013 gdcmDictEntry * found = (gdcmDictEntry*)0;
1014 if (!RefPubDict && !RefShaDict) {
1015 dbg.Verbose(0, "FIXME in gdcmHeader::GetDictEntry",
1016 "we SHOULD have a default dictionary");
1019 found = RefPubDict->GetTagByName(Name);
1024 found = RefShaDict->GetTagByName(Name);
1032 * \ingroup gdcmHeader
1033 * \brief Searches within the public dictionary for element value of
1035 * @param group Group of the researched tag.
1036 * @param element Element of the researched tag.
1037 * @return Corresponding element value when it exists, and the string
1038 * "gdcm::Unfound" otherwise.
1040 string gdcmHeader::GetPubElValByNumber(guint16 group, guint16 element) {
1041 return PubElVals.GetElValueByNumber(group, element);
1045 * \ingroup gdcmHeader
1046 * \brief Searches within the public dictionary for element value
1047 * representation of a given tag.
1049 * Obtaining the VR (Value Representation) might be needed by caller
1050 * to convert the string typed content to caller's native type
1051 * (think of C++ vs Python). The VR is actually of a higher level
1052 * of semantics than just the native C++ type.
1053 * @param group Group of the researched tag.
1054 * @param element Element of the researched tag.
1055 * @return Corresponding element value representation when it exists,
1056 * and the string "gdcm::Unfound" otherwise.
1058 string gdcmHeader::GetPubElValRepByNumber(guint16 group, guint16 element) {
1059 ElValue* elem = PubElVals.GetElementByNumber(group, element);
1061 return "gdcm::Unfound";
1062 return elem->GetVR();
1066 * \ingroup gdcmHeader
1067 * \brief Searches within the public dictionary for element value of
1069 * @param TagName name of the researched element.
1070 * @return Corresponding element value when it exists, and the string
1071 * "gdcm::Unfound" otherwise.
1073 string gdcmHeader::GetPubElValByName(string TagName) {
1074 return PubElVals.GetElValueByName(TagName);
1078 * \ingroup gdcmHeader
1079 * \brief Searches within the elements parsed with the public dictionary for
1080 * the element value representation of a given tag.
1082 * Obtaining the VR (Value Representation) might be needed by caller
1083 * to convert the string typed content to caller's native type
1084 * (think of C++ vs Python). The VR is actually of a higher level
1085 * of semantics than just the native C++ type.
1086 * @param TagName name of the researched element.
1087 * @return Corresponding element value representation when it exists,
1088 * and the string "gdcm::Unfound" otherwise.
1090 string gdcmHeader::GetPubElValRepByName(string TagName) {
1091 ElValue* elem = PubElVals.GetElementByName(TagName);
1093 return "gdcm::Unfound";
1094 return elem->GetVR();
1098 * \ingroup gdcmHeader
1099 * \brief Searches within elements parsed with the SHADOW dictionary
1100 * for the element value of a given tag.
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.
1106 string gdcmHeader::GetShaElValByNumber(guint16 group, guint16 element) {
1107 return ShaElVals.GetElValueByNumber(group, element);
1111 * \ingroup gdcmHeader
1112 * \brief Searches within the elements parsed with the SHADOW dictionary
1113 * for the element value representation of a given tag.
1115 * Obtaining the VR (Value Representation) might be needed by caller
1116 * to convert the string typed content to caller's native type
1117 * (think of C++ vs Python). The VR is actually of a higher level
1118 * of semantics than just the native C++ type.
1119 * @param group Group of the researched tag.
1120 * @param element Element of the researched tag.
1121 * @return Corresponding element value representation when it exists,
1122 * and the string "gdcm::Unfound" otherwise.
1124 string gdcmHeader::GetShaElValRepByNumber(guint16 group, guint16 element) {
1125 ElValue* elem = ShaElVals.GetElementByNumber(group, element);
1127 return "gdcm::Unfound";
1128 return elem->GetVR();
1132 * \ingroup gdcmHeader
1133 * \brief Searches within the elements parsed with the shadow dictionary
1134 * for an element value of given tag.
1135 * @param TagName name of the researched element.
1136 * @return Corresponding element value when it exists, and the string
1137 * "gdcm::Unfound" otherwise.
1139 string gdcmHeader::GetShaElValByName(string TagName) {
1140 return ShaElVals.GetElValueByName(TagName);
1144 * \ingroup gdcmHeader
1145 * \brief Searches within the elements parsed with the shadow dictionary for
1146 * the element value representation of a given tag.
1148 * Obtaining the VR (Value Representation) might be needed by caller
1149 * to convert the string typed content to caller's native type
1150 * (think of C++ vs Python). The VR is actually of a higher level
1151 * of semantics than just the native C++ type.
1152 * @param TagName name of the researched element.
1153 * @return Corresponding element value representation when it exists,
1154 * and the string "gdcm::Unfound" otherwise.
1156 string gdcmHeader::GetShaElValRepByName(string TagName) {
1157 ElValue* elem = ShaElVals.GetElementByName(TagName);
1159 return "gdcm::Unfound";
1160 return elem->GetVR();
1164 * \ingroup gdcmHeader
1165 * \brief Searches within elements parsed with the public dictionary
1166 * and then within the elements parsed with the shadow dictionary
1167 * for the element value of a given tag.
1168 * @param group Group of the researched tag.
1169 * @param element Element of the researched tag.
1170 * @return Corresponding element value representation when it exists,
1171 * and the string "gdcm::Unfound" otherwise.
1173 string gdcmHeader::GetElValByNumber(guint16 group, guint16 element) {
1174 string pub = GetPubElValByNumber(group, element);
1177 return GetShaElValByNumber(group, element);
1181 * \ingroup gdcmHeader
1182 * \brief Searches within elements parsed with the public dictionary
1183 * and then within the elements parsed with the shadow dictionary
1184 * for the element value representation of a given tag.
1186 * Obtaining the VR (Value Representation) might be needed by caller
1187 * to convert the string typed content to caller's native type
1188 * (think of C++ vs Python). The VR is actually of a higher level
1189 * of semantics than just the native C++ type.
1190 * @param group Group of the researched tag.
1191 * @param element Element of the researched tag.
1192 * @return Corresponding element value representation when it exists,
1193 * and the string "gdcm::Unfound" otherwise.
1195 string gdcmHeader::GetElValRepByNumber(guint16 group, guint16 element) {
1196 string pub = GetPubElValRepByNumber(group, element);
1199 return GetShaElValRepByNumber(group, element);
1203 * \ingroup gdcmHeader
1204 * \brief Searches within elements parsed with the public dictionary
1205 * and then within the elements parsed with the shadow dictionary
1206 * for the element value of a given tag.
1207 * @param TagName name of the researched element.
1208 * @return Corresponding element value when it exists,
1209 * and the string "gdcm::Unfound" otherwise.
1211 string gdcmHeader::GetElValByName(string TagName) {
1212 string pub = GetPubElValByName(TagName);
1215 return GetShaElValByName(TagName);
1219 * \ingroup gdcmHeader
1220 * \brief Searches within elements parsed with the public dictionary
1221 * and then within the elements parsed with the shadow dictionary
1222 * for the element value representation of a given tag.
1224 * Obtaining the VR (Value Representation) might be needed by caller
1225 * to convert the string typed content to caller's native type
1226 * (think of C++ vs Python). The VR is actually of a higher level
1227 * of semantics than just the native C++ type.
1228 * @param TagName name of the researched element.
1229 * @return Corresponding element value representation when it exists,
1230 * and the string "gdcm::Unfound" otherwise.
1232 string gdcmHeader::GetElValRepByName(string TagName) {
1233 string pub = GetPubElValRepByName(TagName);
1236 return GetShaElValRepByName(TagName);
1240 * \ingroup gdcmHeader
1241 * \brief Accesses an existing ElValue in the PubElVals of this instance
1242 * through it's (group, element) and modifies it's content with
1244 * @param content new value to substitute with
1245 * @param group group of the ElVal to modify
1246 * @param element element of the ElVal to modify
1248 int gdcmHeader::SetPubElValByNumber(string content, guint16 group,
1251 return ( PubElVals.SetElValueByNumber (content, group, element) );
1255 * \ingroup gdcmHeader
1256 * \brief Accesses an existing ElValue in the PubElVals of this instance
1257 * through tag name and modifies it's content with the given value.
1258 * @param content new value to substitute with
1259 * @param TagName name of the tag to be modified
1261 int gdcmHeader::SetPubElValByName(string content, string TagName) {
1262 return ( PubElVals.SetElValueByName (content, TagName) );
1266 * \ingroup gdcmHeader
1267 * \brief Accesses an existing ElValue in the ShaElVals of this instance
1268 * through it's (group, element) and modifies it's content with
1270 * @param content new value to substitute with
1271 * @param group group of the ElVal to modify
1272 * @param element element of the ElVal to modify
1274 int gdcmHeader::SetShaElValByNumber(string content,
1275 guint16 group, guint16 element)
1277 return ( ShaElVals.SetElValueByNumber (content, group, element) );
1281 * \ingroup gdcmHeader
1282 * \brief Accesses an existing ElValue in the ShaElVals of this instance
1283 * through tag name and modifies it's content with the given value.
1284 * @param content new value to substitute with
1285 * @param TagName name of the tag to be modified
1287 int gdcmHeader::SetShaElValByName(string content, string TagName) {
1288 return ( ShaElVals.SetElValueByName (content, TagName) );
1292 * \ingroup gdcmHeader
1293 * \brief Parses the header of the file but WITHOUT loading element values.
1295 void gdcmHeader::ParseHeader(bool exception_on_error) throw(gdcmFormatError) {
1296 ElValue * newElValue = (ElValue *)0;
1300 while ( (newElValue = ReadNextElement()) ) {
1301 SkipElementValue(newElValue);
1302 PubElVals.Add(newElValue);
1307 * \ingroup gdcmHeader
1308 * \brief Once the header is parsed add some gdcm convenience/helper elements
1309 * in the ElValSet. For example add:
1310 * - gdcmImageType which is an entry containing a short for the
1311 * type of image and whose value ranges in
1312 * I8 (unsigned 8 bit image)
1313 * I16 (unsigned 8 bit image)
1314 * IS16 (signed 8 bit image)
1315 * - gdcmXsize, gdcmYsize, gdcmZsize whose values are respectively
1316 * the ones of the official DICOM fields Rows, Columns and Planes.
1318 void gdcmHeader::AddAndDefaultElements(void) {
1319 ElValue* NewEntry = (ElValue*)0;
1321 NewEntry = NewElValueByName("gdcmXSize");
1322 NewEntry->SetValue(GetElValByName("Rows"));
1323 PubElVals.Add(NewEntry);
1325 NewEntry = NewElValueByName("gdcmYSize");
1326 NewEntry->SetValue(GetElValByName("Columns"));
1327 PubElVals.Add(NewEntry);
1329 NewEntry = NewElValueByName("gdcmZSize");
1330 NewEntry->SetValue(GetElValByName("Planes"));
1331 PubElVals.Add(NewEntry);
1335 * \ingroup gdcmHeader
1336 * \brief Loads the element values of all the elements present in the
1337 * public tag based hash table.
1339 void gdcmHeader::LoadElements(void) {
1341 TagElValueHT ht = PubElVals.GetTagHt();
1342 for (TagElValueHT::iterator tag = ht.begin(); tag != ht.end(); ++tag) {
1343 LoadElementValue(tag->second);
1347 void gdcmHeader::PrintPubElVal(ostream & os) {
1348 PubElVals.Print(os);
1351 void gdcmHeader::PrintPubDict(ostream & os) {
1352 RefPubDict->Print(os);