X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmDocument.cxx;h=3625d94b0fba7bc41292ac0ac3ad06b1446dab1d;hb=3842530aeeb5ab67f9d7b0f1754108fd176ee51a;hp=693d425e6ecf27530982d04c4e9ef331138f98fa;hpb=a61fbd6eb8daabbe9a6df9ebc91300875dc1c560;p=gdcm.git diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index 693d425e..3625d94b 100644 --- a/src/gdcmDocument.cxx +++ b/src/gdcmDocument.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.cxx,v $ Language: C++ - Date: $Date: 2005/10/18 10:43:31 $ - Version: $Revision: 1.291 $ + Date: $Date: 2005/10/26 15:49:56 $ + Version: $Revision: 1.311 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -127,7 +127,7 @@ bool Document::DoTheLoadingDocumentJob( ) Group0002Parsed = false; - gdcmWarningMacro( "Starting parsing of file: " << Filename.c_str()); + gdcmDebugMacro( "Starting parsing of file: " << Filename.c_str()); Fp->seekg(0, std::ios::end); long lgt = Fp->tellg(); // total length of the file @@ -277,7 +277,7 @@ bool Document::DoTheLoadingDocumentJob( ) */ void Document::AddForceLoadElement (uint16_t group, uint16_t elem) { - Element el; + DicomElement el; el.Group = group; el.Elem = elem; UserForceLoadList.push_back(el); @@ -386,7 +386,8 @@ FileType Document::GetFileType() * \brief Accessor to the Transfer Syntax (when present) of the * current document (it internally handles reading the * value from disk when only parsing occured). - * @return The encountered Transfer Syntax of the current document. + * @return The encountered Transfer Syntax of the current document, if DICOM. + * GDCM_UNKNOWN for ACR-NEMA files (or broken headers ...) */ std::string Document::GetTransferSyntax() { @@ -500,6 +501,42 @@ uint32_t Document::SwapLong(uint32_t a) return a; } +/** + * \brief Swaps back the bytes of 8-byte long 'double' accordingly to + * processor order. + * @return The properly swaped 64 bits double. + */ +double Document::SwapDouble(double a) +{ + switch (SwapCode) + { + // There were no 'double' at ACR-NEMA time. + // We just have to deal with 'straight Little Endian' and + // 'straight Big Endian' + case 1234 : + break; + case 4321 : + char *beg = (char *)&a; + char *end = beg + 7; + char t; + for (unsigned int i = 0; i<7; i++) + { + t = *beg; + *beg = *end; + *end = t; + beg++, + end--; + } + break; + + default : + gdcmErrorMacro( "Unset swap code:" << SwapCode ); + a = 0.; + } + return a; +} + + // // -----------------File I/O --------------- /** @@ -604,7 +641,8 @@ void Document::WriteContent(std::ofstream *fp, FileType filetype) { // Skip if user wants to write an ACR-NEMA file - if ( filetype == ImplicitVR || filetype == ExplicitVR ) + if ( filetype == ImplicitVR || filetype == ExplicitVR || + filetype == JPEG ) { // writing Dicom File Preamble char filePreamble[128]; @@ -659,7 +697,7 @@ void Document::LoadEntryBinArea(uint16_t group, uint16_t elem) /** * \brief Loads (from disk) the element content * when a string is not suitable - * @param elem Entry whose binArea is going to be loaded + * @param entry Entry whose binArea is going to be loaded */ void Document::LoadEntryBinArea(DataEntry *entry) { @@ -683,7 +721,7 @@ void Document::LoadEntryBinArea(DataEntry *entry) return; } - // Read the datas + // Read the data Fp->read((char*)data, l); if ( Fp->fail() || Fp->eof() ) { @@ -694,7 +732,8 @@ void Document::LoadEntryBinArea(DataEntry *entry) // Swap the data content if necessary uint32_t i; - unsigned short vrLgth = Global::GetVR()->GetAtomicElementLength(entry->GetVR()); + unsigned short vrLgth = + Global::GetVR()->GetAtomicElementLength(entry->GetVR()); if( entry->GetVR() == "OW" ) vrLgth = 1; @@ -716,10 +755,9 @@ void Document::LoadEntryBinArea(DataEntry *entry) } case 8: { - gdcmWarningMacro("Can't swap 64 bits datas"); -/* uint64_t *data64 = (uint64_t *)data; + double *data64 = (double *)data; for(i=0;iGetGroup(), - // newDocEntry->GetElement(), - // newDocEntry->GetVR().c_str() ); + if( Debug::GetDebugFlag() ) + std::cerr<GetKey()<<" "<GetVR()<GetVR(); + + // Useless checking, now ! + /* if ( Filetype == ExplicitVR && !Global::GetVR()->IsVROfBinaryRepresentable(vr) ) { ////// No DataEntry: should mean UNKOWN VR gdcmWarningMacro( std::hex << newDocEntry->GetGroup() << "|" << newDocEntry->GetElement() - << " : No DataEntry." - "Probably unknown VR."); + << " : unknown VR." + " Probably 'Implicit VR' entry within " + "an explicit VR 'document'."); } + */ if ( !set->AddEntry( newDataEntry ) ) { @@ -1017,6 +1060,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, } else { + newDataEntry->Delete(); // Load only if we can add (not a duplicate key) LoadDocEntry( newDataEntry ); } @@ -1049,7 +1093,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, (!delim_mode && ((long)(Fp->tellg())-offset) >= l_max) ) { if ( !used ) - delete newDocEntry; + newDocEntry->Delete(); break; } @@ -1079,8 +1123,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, if ( newDocEntry->GetGroup()%2 != 0 ) { Fp->seekg( l, std::ios::cur); - RemoveEntry( newDocEntry ); // Remove and delete - //used = false; // never used + newDocEntry->Delete(); // Delete, not in the set continue; } } @@ -1088,8 +1131,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, { // User asked to skip *any* SeQuence Fp->seekg( l, std::ios::cur); - //used = false; // never used - RemoveEntry( newDocEntry ); // Remove and delete + newDocEntry->Delete(); // Delete, not in the set continue; } // delay the dynamic cast as late as possible @@ -1102,11 +1144,9 @@ void Document::ParseDES(DocEntrySet *set, long offset, // is a Document, then we are building the first depth level. // Hence the SeqEntry we are building simply has a depth // level of one: -// SQItem *parentSQItem = dynamic_cast< SQItem* > ( set ); if ( set == this ) // ( dynamic_cast< Document* > ( set ) ) { newSeqEntry->SetDepthLevel( 1 ); - // newSeqEntry->SetKey( newSeqEntry->GetKey() ); } // But when "set" is already a SQItem, we are building a nested // sequence, and hence the depth level of the new SeqEntry @@ -1116,9 +1156,6 @@ void Document::ParseDES(DocEntrySet *set, long offset, else if (SQItem *parentSQItem = dynamic_cast< SQItem* > ( set ) ) { newSeqEntry->SetDepthLevel( parentSQItem->GetDepthLevel() + 1 ); - - // newSeqEntry->SetKey( parentSQItem->GetBaseTagKey() - // + newSeqEntry->GetKey() ); } if ( l != 0 ) @@ -1143,22 +1180,26 @@ void Document::ParseDES(DocEntrySet *set, long offset, << newSeqEntry->GetOffset() << " )" ); used = false; } + else + { + newDocEntry->Delete(); + } if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max) { if ( !used ) - delete newDocEntry; - break; + newDocEntry->Delete(); + break; } } // end SeqEntry : VR = "SQ" if ( !used ) { - delete newDocEntry; + newDocEntry->Delete(); } first = false; } // end While - gdcmWarningMacro( "Exit from ParseDES, delim-mode " << delim_mode ); + gdcmDebugMacro( "Exit from ParseDES, delim-mode " << delim_mode ); } /** @@ -1188,16 +1229,17 @@ void Document::ParseSQ( SeqEntry *seqEntry, if ( newDocEntry->IsSequenceDelimitor() ) { seqEntry->SetDelimitationItem( newDocEntry ); + newDocEntry->Delete(); break; } } if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max) { - delete newDocEntry; + newDocEntry->Delete(); break; } // create the current SQItem - SQItem *itemSQ = new SQItem( seqEntry->GetDepthLevel() ); + SQItem *itemSQ = SQItem::New( seqEntry->GetDepthLevel() ); unsigned int l = newDocEntry->GetReadLength(); if ( l == 0xffffffff ) @@ -1211,7 +1253,6 @@ void Document::ParseSQ( SeqEntry *seqEntry, // Let's try :------------ // remove fff0,e000, created out of the SQItem - delete newDocEntry; Fp->seekg(offsetStartCurrentSQItem, std::ios::beg); // fill up the current SQItem, starting at the beginning of fff0,e000 @@ -1221,6 +1262,8 @@ void Document::ParseSQ( SeqEntry *seqEntry, // end try ----------------- seqEntry->AddSQItem( itemSQ, SQItemNumber ); + itemSQ->Delete(); + newDocEntry->Delete(); SQItemNumber++; if ( !delim_mode && ((long)(Fp->tellg())-offset ) >= l_max ) { @@ -1239,7 +1282,7 @@ DocEntry *Document::Backtrack(DocEntry *docEntry) { // delete the Item Starter, built erroneously out of any Sequence // it's not yet in the HTable/chained list - delete docEntry; + docEntry->Delete(); // Get all info we can from PreviousDocEntry uint16_t group = PreviousDocEntry->GetGroup(); @@ -1273,7 +1316,8 @@ DocEntry *Document::Backtrack(DocEntry *docEntry) void Document::LoadDocEntry(DocEntry *entry, bool forceLoad) { uint16_t group = entry->GetGroup(); - std::string vr = entry->GetVR(); + uint16_t elem = entry->GetElement(); + const VRKey &vr = entry->GetVR(); uint32_t length = entry->GetLength(); Fp->seekg((long)entry->GetOffset(), std::ios::beg); @@ -1282,7 +1326,11 @@ void Document::LoadDocEntry(DocEntry *entry, bool forceLoad) // (fffe e000) tells us an Element is beginning // (fffe e00d) tells us an Element just ended // (fffe e0dd) tells us the current SeQuence just ended - if ( group == 0xfffe || vr == "SQ" ) + // + // (fffe 0000) is an 'impossible' tag value, + // found in MR-PHILIPS-16-Multi-Seq.dcm + + if ( (group == 0xfffe && elem != 0x0000 ) || vr == "SQ" ) { // NO more value field for SQ ! return; @@ -1331,7 +1379,7 @@ void Document::LoadDocEntry(DocEntry *entry, bool forceLoad) void Document::FindDocEntryLength( DocEntry *entry ) throw ( FormatError ) { - std::string vr = entry->GetVR(); + const VRKey &vr = entry->GetVR(); uint16_t length16; if ( Filetype == ExplicitVR && !entry->IsImplicitVR() ) @@ -1472,10 +1520,10 @@ uint32_t Document::FindDocEntryLengthOBOrOW() * \brief Find the Value Representation of the current Dicom Element. * @return Value Representation of the current Entry */ -std::string Document::FindDocEntryVR() +VRKey Document::FindDocEntryVR() { if ( Filetype != ExplicitVR ) - return GDCM_UNKNOWN; + return GDCM_VRUNKNOWN; long positionOnEntry = Fp->tellg(); // Warning: we believe this is explicit VR (Value Representation) because @@ -1486,14 +1534,16 @@ std::string Document::FindDocEntryVR() // is in explicit VR and try to fix things if it happens not to be // the case. - char vr[3]; - Fp->read (vr, (size_t)2); - vr[2] = 0; + VRKey vr; + Fp->read(&(vr[0]),(size_t)2); + //gdcmDebugMacro( "--> VR: " << vr ) if ( !CheckDocEntryVR(vr) ) { + gdcmWarningMacro( "Unknown VR '" << vr << "' at offset :" + << positionOnEntry ); Fp->seekg(positionOnEntry, std::ios::beg); - return GDCM_UNKNOWN; + return GDCM_VRUNKNOWN; } return vr; } @@ -1506,12 +1556,9 @@ std::string Document::FindDocEntryVR() * @return false if the VR is incorrect or if the VR isn't referenced * otherwise, it returns true */ -bool Document::CheckDocEntryVR(VRKey vr) +bool Document::CheckDocEntryVR(const VRKey &vr) { - if ( !Global::GetVR()->IsValidVR(vr) ) - return false; - - return true; + return Global::GetVR()->IsValidVR(vr); } /** @@ -1552,7 +1599,7 @@ void Document::SkipToNextDocEntry(DocEntry *currentDocEntry) void Document::FixDocEntryFoundLength(DocEntry *entry, uint32_t foundLength) { - entry->SetReadLength( foundLength ); // will be updated only if a bug is found + entry->SetReadLength( foundLength );// will be updated only if a bug is found if ( foundLength == 0xffffffff) { foundLength = 0; @@ -1563,7 +1610,7 @@ void Document::FixDocEntryFoundLength(DocEntry *entry, if ( foundLength % 2) { - gdcmWarningMacro( "Warning : Tag with uneven length " << foundLength + gdcmWarningMacro( "Warning : Tag with uneven length " << foundLength << " in x(" << std::hex << gr << "," << elem <<")"); } @@ -1590,7 +1637,7 @@ void Document::FixDocEntryFoundLength(DocEntry *entry, else if ( gr == 0x0009 && ( elem == 0x1113 || elem == 0x1114 ) ) { foundLength = 4; - entry->SetReadLength(4); // a bug is to be fixed !? + entry->SetReadLength(4); // a bug is to be fixed ! } else if ( entry->GetVR() == "SQ" ) @@ -1610,7 +1657,11 @@ void Document::FixDocEntryFoundLength(DocEntry *entry, { foundLength = 0; } - } + else + { + foundLength=12; // to skip the mess that follows this bugged Tag ! + } + } entry->SetLength(foundLength); } @@ -1624,7 +1675,7 @@ bool Document::IsDocEntryAnInteger(DocEntry *entry) { uint16_t elem = entry->GetElement(); uint16_t group = entry->GetGroup(); - const std::string &vr = entry->GetVR(); + const VRKey &vr = entry->GetVR(); uint32_t length = entry->GetLength(); // When we have some semantics on the element we just read, and if we @@ -1638,9 +1689,9 @@ bool Document::IsDocEntryAnInteger(DocEntry *entry) } else { - // Allthough this should never happen, still some images have a + // Although this should never happen, still some images have a // corrupted group length [e.g. have a glance at offset x(8336) of - // gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm]. + // gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm. // Since for dicom compliant and well behaved headers, the present // test is useless (and might even look a bit paranoid), when we // encounter such an ill-formed image, we simply display a warning @@ -1686,7 +1737,7 @@ bool Document::CheckSwap() char *entCur = deb + 128; if ( memcmp(entCur, "DICM", (size_t)4) == 0 ) { - gdcmWarningMacro( "Looks like DICOM Version3 (preamble + DCM)" ); + gdcmDebugMacro( "Looks like DICOM Version3 (preamble + DCM)" ); // Group 0002 should always be VR, and the first element 0000 // Let's be carefull (so many wrong headers ...) @@ -1718,24 +1769,24 @@ bool Document::CheckSwap() // instead of just checking for UL, OB and UI !? group 0000 { Filetype = ExplicitVR; - gdcmWarningMacro( "Group 0002 : Explicit Value Representation"); + gdcmDebugMacro( "Group 0002 : Explicit Value Representation"); } else { Filetype = ImplicitVR; - gdcmWarningMacro( "Group 0002 :Not an explicit Value Representation;" + gdcmErrorMacro( "Group 0002 :Not an explicit Value Representation;" << "Looks like a bugged Header!"); } if ( net2host ) { SwapCode = 4321; - gdcmWarningMacro( "HostByteOrder != NetworkByteOrder"); + gdcmDebugMacro( "HostByteOrder != NetworkByteOrder"); } else { SwapCode = 1234; - gdcmWarningMacro( "HostByteOrder = NetworkByteOrder"); + gdcmDebugMacro( "HostByteOrder = NetworkByteOrder"); } // Position the file position indicator at first tag @@ -1782,7 +1833,7 @@ bool Document::CheckSwap() memcmp(entCur, "OB", (size_t)2) == 0 ) { Filetype = ExplicitVR; - gdcmWarningMacro( "Group 0002 : Explicit Value Representation"); + gdcmDebugMacro( "Group 0002 : Explicit Value Representation"); return true; } } @@ -1828,7 +1879,7 @@ bool Document::CheckSwap() // Only 0 or 4321 will be possible // (no oportunity to check for the formerly well known // ACR-NEMA 'Bad Big Endian' or 'Bad Little Endian' - // if unsuccessfull (i.e. neither 0x0002 nor 0x0200 etc -3, 4, ..., 8-) + // if unsuccessfull (i.e. neither 0x0002 nor 0x0200 etc-3, 4, ..., 8-) // the file IS NOT ACR-NEMA nor DICOM V3 // Find a trick to tell it the caller... @@ -1859,7 +1910,7 @@ bool Document::CheckSwap() Filetype = ACR; return true; default : - gdcmWarningMacro("ACR/NEMA unfound swap info (Really hopeless !)"); + gdcmWarningMacro("ACR/NEMA unfound swap info (Hopeless !)"); Filetype = Unknown; return false; } @@ -1871,8 +1922,8 @@ bool Document::CheckSwap() */ void Document::SwitchByteSwapCode() { - gdcmWarningMacro( "Switching Byte Swap code from "<< SwapCode - << " at :" <tellg() ); + gdcmDebugMacro( "Switching Byte Swap code from "<< SwapCode + << " at: 0x" << std::hex << Fp->tellg() ); if ( SwapCode == 1234 ) { SwapCode = 4321; @@ -1889,6 +1940,7 @@ void Document::SwitchByteSwapCode() { SwapCode = 3412; } + gdcmDebugMacro( " Into: "<< SwapCode ); } /** @@ -1940,10 +1992,11 @@ DocEntry *Document::ReadNextDocEntry() if ( HasDCMPreamble ) HandleOutOfGroup0002(group, elem); - std::string vr = FindDocEntryVR(); - std::string realVR = vr; + VRKey vr = FindDocEntryVR(); + + VRKey realVR = vr; - if ( vr == GDCM_UNKNOWN ) + if ( vr == GDCM_VRUNKNOWN ) { if ( elem == 0x0000 ) // Group Length { @@ -1961,9 +2014,11 @@ DocEntry *Document::ReadNextDocEntry() if ( dictEntry ) { realVR = dictEntry->GetVR(); + dictEntry->Unregister(); } } } + // gdcmDebugMacro( "Found VR: " << vr << " / Real VR: " << realVR ); DocEntry *newEntry; if ( Global::GetVR()->IsVROfSequence(realVR) ) @@ -1974,7 +2029,7 @@ DocEntry *Document::ReadNextDocEntry() static_cast(newEntry)->SetState(DataEntry::STATE_NOTLOADED); } - if ( vr == GDCM_UNKNOWN ) + if ( vr == GDCM_VRUNKNOWN ) { if ( Filetype == ExplicitVR ) { @@ -1984,8 +2039,9 @@ DocEntry *Document::ReadNextDocEntry() { std::string msg; int offset = Fp->tellg(); - msg = Util::Format("Entry (%04x,%04x) at 0x(%x) should be Explicit VR\n", - newEntry->GetGroup(), newEntry->GetElement(), offset ); + msg = Util::Format( + "Entry (%04x,%04x) at x(%x) should be Explicit VR\n", + newEntry->GetGroup(), newEntry->GetElement(), offset ); gdcmWarningMacro( msg.c_str() ); } } @@ -1999,7 +2055,7 @@ DocEntry *Document::ReadNextDocEntry() catch ( FormatError ) { // Call it quits - delete newEntry; + newEntry->Delete(); return 0; } @@ -2016,7 +2072,8 @@ DocEntry *Document::ReadNextDocEntry() */ void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem) { - // Endian reversion. Some files contain groups of tags with reversed endianess. + // Endian reversion. + // Some files contain groups of tags with reversed endianess. static int reversedEndian = 0; // try to fix endian switching in the middle of headers if ((group == 0xfeff) && (elem == 0x00e0)) @@ -2041,7 +2098,7 @@ void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem) // Do what you want, it breaks ! //reversedEndian--; //SwitchByteSwapCode(); - gdcmWarningMacro( "Should never get here! reversed Sequence Terminator!" ); + gdcmWarningMacro( "Should never get here! reversed Sequence Terminator!" ); // fix the tag group = 0xfffe; elem = 0xe0dd; @@ -2059,7 +2116,8 @@ void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem) */ void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem) { - // Endian reversion. Some files contain groups of tags with reversed endianess. + // Endian reversion. + // Some files contain groups of tags with reversed endianess. if ( !Group0002Parsed && group != 0x0002) { Group0002Parsed = true; @@ -2073,9 +2131,11 @@ void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem) return; } - // Group 0002 is always 'Explicit ...' even when Transfer Syntax says 'Implicit ..." + // Group 0002 is always 'Explicit ...' + // even when Transfer Syntax says 'Implicit ..." - if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian ) + if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == + TS::ImplicitVRLittleEndian ) { Filetype = ImplicitVR; } @@ -2083,9 +2143,12 @@ void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem) // FIXME Strangely, this works with //'Implicit VR BigEndian Transfer Syntax (GE Private) // - // --> Probabely normal, since we considered we never have to trust manufacturers. - // (we find very often 'Implicit VR' tag, even when Transfer Syntax tells us it's Explicit ... - if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian ) + // --> Probabely normal, since we considered we never have + // to trust manufacturers. + // (we find very often 'Implicit VR' tag, + // even when Transfer Syntax tells us it's Explicit ... + if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == + TS::ExplicitVRBigEndian ) { gdcmWarningMacro("Transfer Syntax Name = [" << GetTransferSyntaxName() << "]" );