X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmHeader.cxx;h=d3e99c2062ff83f549af69c9ff94646fdd29910b;hb=8afb2999a90aefbce7662c43fe19dad237d49331;hp=ef794b93d2a0f54b14829ece21ea537ce070f7a8;hpb=0e907c927c8511d4c57eb72912821ac18226ef85;p=gdcm.git diff --git a/src/gdcmHeader.cxx b/src/gdcmHeader.cxx index ef794b93..d3e99c20 100644 --- a/src/gdcmHeader.cxx +++ b/src/gdcmHeader.cxx @@ -38,6 +38,7 @@ void gdcmHeader::Initialise(void) { } gdcmHeader::gdcmHeader (const char* InFilename) { + SetMaxSizeLoadElementValue(1024); filename = InFilename; Initialise(); fp=fopen(InFilename,"rw"); @@ -56,32 +57,32 @@ void gdcmHeader::InitVRDict (void) { return; } VRHT *vr = new VRHT; - (*vr)["AE"] = "Application Entity"; // 16 car max - (*vr)["AS"] = "Age String"; // 4 car fixe - (*vr)["AT"] = "Attribute Tag"; // 2 unsigned short int - (*vr)["CS"] = "Code String"; // 16 car max - (*vr)["DA"] = "Date"; // 8 car fixe - (*vr)["DS"] = "Decimal String"; // Decimal codé Binaire 16 max - (*vr)["DT"] = "Date Time"; // 26 car max - (*vr)["FL"] = "Floating Point Single"; // 4 octets IEEE 754:1985 - (*vr)["FD"] = "Floating Point Double"; // 8 octets IEEE 754:1985 - (*vr)["IS"] = "Integer String"; // en format externe 12 max - (*vr)["LO"] = "Long String"; // 64 octets max - (*vr)["LT"] = "Long Text"; // 10240 max - (*vr)["OB"] = "Other Byte String"; - (*vr)["OW"] = "Other Word String"; - (*vr)["PN"] = "Person Name"; - (*vr)["SH"] = "Short String"; // 16 car max - (*vr)["SL"] = "Signed Long"; + (*vr)["AE"] = "Application Entity"; // At most 16 bytes + (*vr)["AS"] = "Age String"; // Exactly 4 bytes + (*vr)["AT"] = "Attribute Tag"; // 2 16-bit unsigned short integers + (*vr)["CS"] = "Code String"; // At most 16 bytes + (*vr)["DA"] = "Date"; // Exactly 8 bytes + (*vr)["DS"] = "Decimal String"; // At most 16 bytes + (*vr)["DT"] = "Date Time"; // At most 26 bytes + (*vr)["FL"] = "Floating Point Single"; // 32-bit IEEE 754:1985 float + (*vr)["FD"] = "Floating Point Double"; // 64-bit IEEE 754:1985 double + (*vr)["IS"] = "Integer String"; // At most 12 bytes + (*vr)["LO"] = "Long String"; // At most 64 chars + (*vr)["LT"] = "Long Text"; // At most 10240 chars + (*vr)["OB"] = "Other Byte String"; // String of bytes (vr independant) + (*vr)["OW"] = "Other Word String"; // String of 16-bit words (vr dep) + (*vr)["PN"] = "Person Name"; // At most 64 chars + (*vr)["SH"] = "Short String"; // At most 16 chars + (*vr)["SL"] = "Signed Long"; // Exactly 4 bytes (*vr)["SQ"] = "Sequence of Items"; // Not Applicable - (*vr)["SS"] = "Signed Short"; // 2 octets - (*vr)["ST"] = "Short Text"; // 1024 car max - (*vr)["TM"] = "Time"; // 16 car max - (*vr)["UI"] = "Unique Identifier"; // 64 car max - (*vr)["UN"] = "Unknown"; - (*vr)["UT"] = "Unlimited Text"; // 2 puissance 32 -1 car max - (*vr)["UL"] = "Unsigned Long "; // 4 octets fixe - (*vr)["US"] = "Unsigned Short "; // 2 octets fixe + (*vr)["SS"] = "Signed Short"; // Exactly 2 bytes + (*vr)["ST"] = "Short Text"; // At most 1024 chars + (*vr)["TM"] = "Time"; // At most 16 bytes + (*vr)["UI"] = "Unique Identifier"; // At most 64 bytes + (*vr)["UL"] = "Unsigned Long "; // Exactly 4 bytes + (*vr)["UN"] = "Unknown"; // Any length of bytes + (*vr)["US"] = "Unsigned Short "; // Exactly 2 bytes + (*vr)["UT"] = "Unlimited Text"; // At most 2^32 -1 chars dicom_vr = vr; } @@ -225,7 +226,8 @@ void gdcmHeader::CheckSwap() } void gdcmHeader::SwitchSwapToBigEndian(void) { - dbg.Verbose(0, "gdcmHeader::FindLength", "Switching to BigEndian mode."); + dbg.Verbose(1, "gdcmHeader::SwitchSwapToBigEndian", + "Switching to BigEndian mode."); if ( sw == 0 ) { sw = 4321; return; @@ -282,6 +284,9 @@ void gdcmHeader::SwitchSwapToBigEndian(void) { */ void gdcmHeader::FindVR( ElValue *ElVal) { + if (filetype != ExplicitVR) + return; + char VR[3]; string vr; int lgrLue; @@ -295,9 +300,6 @@ void gdcmHeader::FindVR( ElValue *ElVal) { // the case. bool RealExplicit = true; - if (filetype != ExplicitVR) - return; - lgrLue=fread (&VR, (size_t)2,(size_t)1, fp); VR[2]=0; vr = string(VR); @@ -320,8 +322,26 @@ void gdcmHeader::FindVR( ElValue *ElVal) { RealExplicit = false; if ( RealExplicit ) { - if ( ElVal->IsVrUnknown() ) + if ( ElVal->IsVrUnknown() ) { + // When not a dictionary entry, we can safely overwrite the vr. ElVal->SetVR(vr); + return; + } + if ( ElVal->GetVR() == vr ) { + // The vr we just read and the dictionary agree. Nothing to do. + return; + } + // The vr present in the file and the dictionary disagree. We assume + // the file writer knew best and use the vr of the file. Since it would + // be unwise to overwrite the vr of a dictionary (since it would + // compromise it's next user), we need to clone the actual DictEntry + // and change the vr for the read one. + gdcmDictEntry* NewTag = new gdcmDictEntry(ElVal->GetGroup(), + ElVal->GetElement(), + vr, + "FIXME", + ElVal->GetName()); + ElVal->SetDictEntry(NewTag); return; } @@ -364,18 +384,58 @@ void gdcmHeader::FixFoundLength(ElValue * ElVal, guint32 FoudLength) { ElVal->SetLength(FoudLength); } -void gdcmHeader::FindLength( ElValue * ElVal) { +guint32 gdcmHeader::FindLengthOB(void) { + // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data. + guint16 g; + guint16 n; + long PositionOnEntry = ftell(fp); + bool FoundSequenceDelimiter = false; + guint32 TotalLength = 0; + guint32 ItemLength; + + while ( ! FoundSequenceDelimiter) { + g = ReadInt16(); + n = ReadInt16(); + TotalLength += 4; // We even have to decount the group and element + if ( g != 0xfffe ) { + dbg.Verbose(1, "gdcmHeader::FindLengthOB: ", + "wrong group for an item sequence."); + throw Error::FileReadError(fp, "gdcmHeader::FindLengthOB"); + } + if ( n == 0xe0dd ) + FoundSequenceDelimiter = true; + else if ( n != 0xe000) { + dbg.Verbose(1, "gdcmHeader::FindLengthOB: ", + "wrong element for an item sequence."); + throw Error::FileReadError(fp, "gdcmHeader::FindLengthOB"); + } + ItemLength = ReadInt32(); + TotalLength += ItemLength + 4; // We add 4 bytes since we just read + // the ItemLength with ReadInt32 + SkipBytes(ItemLength); + } + fseek(fp, PositionOnEntry, SEEK_SET); + return TotalLength; +} + +void gdcmHeader::FindLength(ElValue * ElVal) { guint16 element = ElVal->GetElement(); string vr = ElVal->GetVR(); guint16 length16; if ( (filetype == ExplicitVR) && ! ElVal->IsImplicitVr() ) { + if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) { - - // The following two bytes are reserved, so we skip them, - // and we proceed on reading the length on 4 bytes. - fseek(fp, 2L,SEEK_CUR); - FixFoundLength(ElVal, ReadInt32()); + // The following reserved two bytes (see PS 3.5-2001, section + // 7.1.2 Data element structure with explicit vr p27) must be + // skipped before proceeding on reading the length on 4 bytes. + fseek(fp, 2L, SEEK_CUR); + guint32 length32 = ReadInt32(); + if ( (vr == "OB") && (length32 == 0xffffffff) ) { + ElVal->SetLength(FindLengthOB()); + return; + } + FixFoundLength(ElVal, length32); return; } @@ -384,7 +444,7 @@ void gdcmHeader::FindLength( ElValue * ElVal) { // We can tell the current file is encoded in big endian (like // Data/US-RGB-8-epicard) when we find the "Transfer Syntax" tag - // and it's value is the one of the encoding of a bie endian file. + // and it's value is the one of the encoding of a big endian file. // In order to deal with such big endian encoded files, we have // (at least) two strategies: // * when we load the "Transfer Syntax" tag with value of big endian @@ -395,7 +455,7 @@ void gdcmHeader::FindLength( ElValue * ElVal) { // in little endian, and big endian coding only starts at the next // group. The corresponding code can be hard to analyse and adds // many additional unnecessary tests for regular tags. - // * the second strategy consist to wait for trouble, that shall appear + // * the second strategy consist in waiting for trouble, that shall appear // when we find the first group with big endian encoding. This is // easy to detect since the length of a "Group Length" tag (the // ones with zero as element number) has to be of 4 (0x0004). When we @@ -438,12 +498,15 @@ void gdcmHeader::FindLength( ElValue * ElVal) { return; } - // Either implicit VR or an explicit VR that (at least for this - // element) lied a little bit. Length is on 4 bytes. + // Either implicit VR or a non DICOM conformal (see not below) explicit + // VR that ommited the VR of (at least) this element. Farts happen. + // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25 + // on Data elements "Implicit and Explicit VR Data Elements shall + // not coexist in a Data Set and Data Sets nested within it".] + // Length is on 4 bytes. FixFoundLength(ElVal, ReadInt32()); } - /** * \ingroup gdcmHeader * \brief Swaps back the bytes of 4-byte long integer accordingly to @@ -486,9 +549,23 @@ guint16 gdcmHeader::SwapShort(guint16 a) { return (a); } -void gdcmHeader::SkipElementValue(ElValue * ElVal) { +void gdcmHeader::SkipBytes(guint32 NBytes) { //FIXME don't dump the returned value - (void)fseek(fp, (long)ElVal->GetLength(), SEEK_CUR); + (void)fseek(fp, (long)NBytes, SEEK_CUR); +} + +void gdcmHeader::SkipElementValue(ElValue * ElVal) { + SkipBytes(ElVal->GetLength()); +} + +void gdcmHeader::SetMaxSizeLoadElementValue(long NewSize) { + if (NewSize < 0) + return; + if ((guint32)NewSize >= (guint32)0xffffffff) { + MaxSizeLoadElementValue = 0xffffffff; + return; + } + MaxSizeLoadElementValue = NewSize; } /** @@ -526,6 +603,7 @@ void gdcmHeader::LoadElementValue(ElValue * ElVal) { SkipLoad = true; if ( SkipLoad ) { + // FIXME the following skip is not necessary SkipElementValue(ElVal); ElVal->SetLength(0); ElVal->SetValue("gdcm::Skipped"); @@ -537,6 +615,17 @@ void gdcmHeader::LoadElementValue(ElValue * ElVal) { ElVal->SetValue(""); return; } + + // Values bigger than specified are not loaded. + if (length > MaxSizeLoadElementValue) { + ostringstream s; + s << "gdcm::NotLoaded."; + s << " Address:" << (long)ElVal->GetOffset(); + s << " Length:" << ElVal->GetLength(); + //mesg += " Length:" + ElVal->GetLength(); + ElVal->SetValue(s.str()); + return; + } // When an integer is expected, read and convert the following two or // four bytes properly i.e. as an integer as opposed to a string. @@ -564,8 +653,6 @@ void gdcmHeader::LoadElementValue(ElValue * ElVal) { } NewValue[length]= 0; - // FIXME les elements trop long (seuil a fixer a la main) ne devraient - // pas etre charge's !!!! Voir TODO. item_read = fread(NewValue, (size_t)length, (size_t)1, fp); if ( item_read != 1 ) { g_free(NewValue);