X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmDocument.cxx;h=11d558e3344917dd92f07a156cd11d79244467ff;hb=fec6b180f2002f8fbeb80edeee57511c0b33a0d0;hp=70e868c1236a99d51c53ce6f8be0518858f2d71c;hpb=957dcd905e535fcfe37185ca5ea08a801e3078d3;p=gdcm.git diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index 70e868c1..11d558e3 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/06/23 09:20:23 $ - Version: $Revision: 1.250 $ + Date: $Date: 2005/07/05 18:44:21 $ + Version: $Revision: 1.255 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -31,6 +31,8 @@ #include #include #include +#include // for isdigit +#include // for atoi namespace gdcm { @@ -77,7 +79,7 @@ Document::Document( std::string const &fileName ) SwapCode = 1234; Filetype = ExplicitVR; Group0002Parsed = false; - LoadMode = 0x00000000; // Load everything + LoadMode = 0x00000000; // Load everything, later // Load will set it to true if sucessfull IsDocumentAlreadyLoaded = false; @@ -106,7 +108,7 @@ bool Document::Load( std::string const &fileName ) { // We should clean out anything that already exists. // Check IsDocumentAlreadyLoaded to be sure. - if( IsDocumentAlreadyLoaded ) + if ( IsDocumentAlreadyLoaded ) { gdcmWarningMacro( "A file was already parsed inside this " << "gdcm::Document (previous name was: " @@ -151,7 +153,9 @@ bool Document::Load( std::string const &fileName ) lgt -= beg; // remaining length to parse - ParseDES( this, beg, lgt, false); // Loading is done during parsing + // Recursive call. + // Loading is done during parsing + ParseDES( this, beg, lgt, false); // delim_mode is first defaulted to false if ( IsEmpty() ) { @@ -167,7 +171,7 @@ bool Document::Load( std::string const &fileName ) // Load 'non string' values std::string PhotometricInterpretation = GetEntryValue(0x0028,0x0004); - if( PhotometricInterpretation == "PALETTE COLOR " ) + if ( PhotometricInterpretation == "PALETTE COLOR " ) { // FIXME // Probabely this line should be outside the 'if' @@ -184,7 +188,7 @@ bool Document::Load( std::string const &fileName ) /// altered on PURPOSE but now contains a WRONG value. /// In order to fix things and restore the dictionary to its /// correct value, one needs to decided of the semantics by deciding - /// whether the following tags are either: + /// whether the following tags are either : /// - multivaluated US, and hence loaded as ValEntry, but afterwards /// also used as BinEntry, which requires the proper conversion, /// - OW, and hence loaded as BinEntry, but afterwards also used @@ -224,7 +228,7 @@ bool Document::Load( std::string const &fileName ) // ---------------------------- // Specific code to allow gdcm to read ACR-LibIDO formated images // Note: ACR-LibIDO is an extension of the ACR standard that was - // used at CREATIS. For the time being (say a couple years) + // used at CREATIS. For the time being (say a couple of years) // we keep this kludge to allow CREATIS users // reading their old images. // @@ -293,7 +297,7 @@ bool Document::SetShaDict(DictKey const &dictName) */ bool Document::IsReadable() { - if( Filetype == Unknown) + if ( Filetype == Unknown ) { gdcmWarningMacro( "Wrong filetype"); return false; @@ -476,14 +480,14 @@ std::ifstream *Document::OpenFile() return 0; } - if(Fp) + if ( Fp ) { gdcmWarningMacro( "File already open: " << Filename.c_str()); CloseFile(); } Fp = new std::ifstream(Filename.c_str(), std::ios::in | std::ios::binary); - if( ! *Fp ) + if ( ! *Fp ) { // Don't user gdcmErrorMacro : // a spurious message will appear when you use, for instance @@ -499,14 +503,14 @@ std::ifstream *Document::OpenFile() uint16_t zero = 0; Fp->read((char*)&zero, (size_t)2); - if( Fp->eof() ) + if ( Fp->eof() ) { CloseFile(); return 0; } //-- ACR or DICOM with no Preamble; may start with a Shadow Group -- - if( + if ( zero == 0x0001 || zero == 0x0100 || zero == 0x0002 || zero == 0x0200 || zero == 0x0003 || zero == 0x0300 || zero == 0x0004 || zero == 0x0400 || zero == 0x0005 || zero == 0x0500 || zero == 0x0006 || zero == 0x0600 || @@ -522,12 +526,12 @@ std::ifstream *Document::OpenFile() Fp->seekg(126L, std::ios::cur); char dicm[4] = {' ',' ',' ',' '}; Fp->read(dicm, (size_t)4); - if( Fp->eof() ) + if ( Fp->eof() ) { CloseFile(); return 0; } - if( memcmp(dicm, "DICM", 4) == 0 ) + if ( memcmp(dicm, "DICM", 4) == 0 ) { HasDCMPreamble = true; return Fp; @@ -546,7 +550,7 @@ std::ifstream *Document::OpenFile() */ bool Document::CloseFile() { - if( Fp ) + if ( Fp ) { Fp->close(); delete Fp; @@ -610,7 +614,7 @@ void Document::LoadEntryBinArea(uint16_t group, uint16_t elem) return; BinEntry *binElement = dynamic_cast(docElement); - if( !binElement ) + if ( !binElement ) return; LoadEntryBinArea(binElement); @@ -623,11 +627,11 @@ void Document::LoadEntryBinArea(uint16_t group, uint16_t elem) */ void Document::LoadEntryBinArea(BinEntry *elem) { - if(elem->GetBinArea()) + if (elem->GetBinArea() ) return; bool openFile = !Fp; - if(openFile) + if ( openFile ) OpenFile(); size_t o =(size_t)elem->GetOffset(); @@ -635,14 +639,14 @@ void Document::LoadEntryBinArea(BinEntry *elem) size_t l = elem->GetLength(); uint8_t *a = new uint8_t[l]; - if( !a ) + if ( !a ) { gdcmWarningMacro( "Cannot allocate BinEntry content"); return; } Fp->read((char*)a, l); - if( Fp->fail() || Fp->eof()) + if ( Fp->fail() || Fp->eof() ) { delete[] a; return; @@ -650,7 +654,7 @@ void Document::LoadEntryBinArea(BinEntry *elem) elem->SetBinArea(a); - if(openFile) + if ( openFile ) CloseFile(); } @@ -662,7 +666,7 @@ void Document::LoadEntryBinArea(BinEntry *elem) */ void Document::LoadDocEntrySafe(DocEntry *entry) { - if(Fp) + if ( Fp ) { long PositionOnEntry = Fp->tellg(); LoadDocEntry(entry); @@ -682,11 +686,11 @@ bool Document::operator<(Document &document) // Patient Name std::string s1 = GetEntryValue(0x0010,0x0010); std::string s2 = document.GetEntryValue(0x0010,0x0010); - if(s1 < s2) + if (s1 < s2) { return true; } - else if( s1 > s2 ) + else if ( s1 > s2 ) { return false; } @@ -712,7 +716,7 @@ bool Document::operator<(Document &document) { return true; } - else if( s1 > s2 ) + else if ( s1 > s2 ) { return false; } @@ -725,7 +729,7 @@ bool Document::operator<(Document &document) { return true; } - else if( s1 > s2 ) + else if ( s1 > s2 ) { return false; } @@ -751,7 +755,7 @@ uint16_t Document::ReadInt16() { throw FormatError( "Document::ReadInt16()", " file error." ); } - if( Fp->eof() ) + if ( Fp->eof() ) { throw FormatError( "Document::ReadInt16()", "EOF." ); } @@ -773,7 +777,7 @@ uint32_t Document::ReadInt32() { throw FormatError( "Document::ReadInt32()", " file error." ); } - if( Fp->eof() ) + if ( Fp->eof() ) { throw FormatError( "Document::ReadInt32()", "EOF." ); } @@ -810,15 +814,15 @@ int Document::ComputeGroup0002Length( FileType filetype ) { gr = entry->GetGroup(); - if( gr == 0x0002 ) + if ( gr == 0x0002 ) { found0002 = true; - if( entry->GetElement() != 0x0000 ) + if ( entry->GetElement() != 0x0000 ) { vr = entry->GetVR(); - if( filetype == ExplicitVR ) + if ( filetype == ExplicitVR ) { if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") || (vr == "UT") ) { @@ -852,7 +856,7 @@ void Document::Initialize() /** * \brief Parses a DocEntrySet (Zero-level DocEntries or SQ Item DocEntries) - * @param set DocEntrySet we are going to parse ('zero level' or a SQItem) + * @param set DocEntrySet we are going to parse ('zero level' or a SQItem) * @param offset start of parsing * @param l_max length to parse * @param delim_mode : whether we are in 'delimitor mode' (l=0xffffff) or not @@ -866,6 +870,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, SeqEntry *newSeqEntry; VRKey vr; bool used; + bool delim_mode_intern; while (true) { @@ -918,10 +923,11 @@ void Document::ParseDES(DocEntrySet *set, long offset, } LoadDocEntry( newBinEntry ); - if( !set->AddEntry( newBinEntry ) ) + if ( !set->AddEntry( newBinEntry ) ) { //Expect big troubles if here //delete newBinEntry; + gdcmWarningMacro("in ParseDES : shouldn't get here !"); used=false; } } @@ -968,7 +974,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, } } - if( !set->AddEntry( newValEntry ) ) + if ( !set->AddEntry( newValEntry ) ) { // If here expect big troubles // delete newValEntry; //otherwise mem leak @@ -977,13 +983,13 @@ void Document::ParseDES(DocEntrySet *set, long offset, if (delimitor) { - if(!used) + if ( !used ) delete newDocEntry; break; } - if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max) + if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max ) { - if(!used) + if ( !used ) delete newDocEntry; break; } @@ -994,29 +1000,41 @@ void Document::ParseDES(DocEntrySet *set, long offset, } else { - // VR = "SQ" + /////////////////////// SeqEntry : VR = "SQ" + unsigned long l = newDocEntry->GetReadLength(); - if ( l != 0 ) // don't mess the delim_mode for zero-length sequence + if ( l != 0 ) // don't mess the delim_mode for 'zero-length sequence' { if ( l == 0xffffffff ) { - delim_mode = true; + delim_mode_intern = true; } else { - delim_mode = false; + delim_mode_intern = false; } } - - if ( (LoadMode & NO_SEQ) && ! delim_mode ) // User asked to skip SQ + + if ( (LoadMode & NO_SHADOWSEQ) && ! delim_mode_intern ) + { + // User asked to skip SeQuences *only* if they belong to Shadow Group + if ( newDocEntry->GetGroup()%2 != 0 ) + { + Fp->seekg( l, std::ios::cur); + used = false; + continue; + } + } + if ( (LoadMode & NO_SEQ) && ! delim_mode_intern ) { + // User asked to skip *any* SeQuence Fp->seekg( l, std::ios::cur); used = false; continue; - } + } // no other way to create it ... - newSeqEntry->SetDelimitorMode( delim_mode ); + newSeqEntry->SetDelimitorMode( delim_mode_intern ); // At the top of the hierarchy, stands a Document. When "set" // is a Document, then we are building the first depth level. @@ -1041,22 +1059,22 @@ void Document::ParseDES(DocEntrySet *set, long offset, { // Don't try to parse zero-length sequences ParseSQ( newSeqEntry, newDocEntry->GetOffset(), - l, delim_mode); + l, delim_mode_intern); } - if( !set->AddEntry( newSeqEntry ) ) + if ( !set->AddEntry( newSeqEntry ) ) { used = false; } - + if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max) { - if( !used ) + if ( !used ) delete newDocEntry; break; } } - if( !used ) + if ( !used ) delete newDocEntry; } } @@ -1080,9 +1098,10 @@ void Document::ParseSQ( SeqEntry *seqEntry, if ( !newDocEntry ) { // FIXME Should warn user + gdcmWarningMacro("in ParseSQ : should never get here!"); break; } - if( delim_mode ) + if ( delim_mode ) { if ( newDocEntry->IsSequenceDelimitor() ) { @@ -1119,7 +1138,9 @@ void Document::ParseSQ( SeqEntry *seqEntry, delete newDocEntry; Fp->seekg(offsetStartCurrentSQItem, std::ios::beg); // fill up the current SQItem, starting at the beginning of fff0,e000 + ParseDES(itemSQ, offsetStartCurrentSQItem, l+8, dlm_mod); + offsetStartCurrentSQItem = Fp->tellg(); // end try ----------------- @@ -1149,7 +1170,7 @@ void Document::LoadDocEntry(DocEntry *entry) // (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 ) + if ( group == 0xfffe ) { // NO more value field for SQ ! return; @@ -1163,7 +1184,7 @@ void Document::LoadDocEntry(DocEntry *entry) } // The elements whose length is bigger than the specified upper bound - // are not loaded. Instead we leave a short notice of the offset of + // are not loaded. Instead we leave a short notice on the offset of // the element content and it's length. std::ostringstream s; @@ -1263,7 +1284,7 @@ void Document::LoadDocEntry(DocEntry *entry) str[length] = '\0'; //this is only useful when length is odd // Special DicomString call to properly handle \0 and even length std::string newValue; - if( length % 2 ) + if ( length % 2 ) { newValue = Util::DicomString(str, length+1); gdcmWarningMacro("Warning: bad length: " << length << @@ -1291,7 +1312,7 @@ void Document::LoadDocEntry(DocEntry *entry) return; } - if( vr == "UI" ) + if ( vr == "UI" ) { // Because of correspondance with the VR dic valEntry->SetValue(newValue); @@ -1471,7 +1492,7 @@ std::string Document::FindDocEntryVR() Fp->read (vr, (size_t)2); vr[2] = 0; - if( !CheckDocEntryVR(vr) ) + if ( !CheckDocEntryVR(vr) ) { Fp->seekg(positionOnEntry, std::ios::beg); return GDCM_UNKNOWN; @@ -1519,14 +1540,14 @@ std::string Document::GetDocEntryValue(DocEntry *entry) // Elements with Value Multiplicity > 1 // contain a set of short integers (not a single one) - if( vr == "US" || vr == "SS" ) + if ( vr == "US" || vr == "SS" ) { uint16_t newInt16; nbInt = length / 2; for (int i=0; i < nbInt; i++) { - if( i != 0 ) + if ( i != 0 ) { s << '\\'; } @@ -1542,14 +1563,14 @@ std::string Document::GetDocEntryValue(DocEntry *entry) // as usual for standard multivaluated filels // Elements with Value Multiplicity > 1 // contain a set of integers (not a single one) - else if( vr == "UL" || vr == "SL" ) + else if ( vr == "UL" || vr == "SL" ) { uint32_t newInt32; nbInt = length / 4; for (int i=0; i < nbInt; i++) { - if( i != 0) + if ( i != 0) { s << '\\'; } @@ -1706,12 +1727,12 @@ void Document::FixDocEntryFoundLength(DocEntry *entry, //////// We encountered a 'delimiter' element i.e. a tag of the form // "fffe|xxxx" which is just a marker. Delimiters length should not be // taken into account. - else if( gr == 0xfffe ) + else if ( gr == 0xfffe ) { // According to the norm, fffe|0000 shouldn't exist. BUT the Philips // image gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm happens to // causes extra troubles... - if( entry->GetElement() != 0x0000 ) + if ( entry->GetElement() != 0x0000 ) { foundLength = 0; } @@ -1774,12 +1795,7 @@ bool Document::IsDocEntryAnInteger(DocEntry *entry) * true when we hope ours assuptions are OK */ bool Document::CheckSwap() -{ - // The only guaranted way of finding the swap code is to find a - // group tag since we know it's length has to be of four bytes i.e. - // 0x00000004. Finding the swap code in then straigthforward. Trouble - // occurs when we can't find such group... - +{ uint32_t s32; uint16_t s16; @@ -1794,7 +1810,7 @@ bool Document::CheckSwap() Fp->read(deb, 256); char *entCur = deb + 128; - if( memcmp(entCur, "DICM", (size_t)4) == 0 ) + if ( memcmp(entCur, "DICM", (size_t)4) == 0 ) { gdcmWarningMacro( "Looks like DICOM Version3 (preamble + DCM)" ); @@ -1818,11 +1834,11 @@ bool Document::CheckSwap() // even if elem 0002,0010 (Transfer Syntax) tells us the file is // *Implicit* VR (see former 'gdcmData/icone.dcm') - if( memcmp(entCur, "UL", (size_t)2) == 0 || - memcmp(entCur, "OB", (size_t)2) == 0 || - memcmp(entCur, "UI", (size_t)2) == 0 || - memcmp(entCur, "CS", (size_t)2) == 0 ) // CS, to remove later - // when Write DCM *adds* + if ( memcmp(entCur, "UL", (size_t)2) == 0 || + memcmp(entCur, "OB", (size_t)2) == 0 || + memcmp(entCur, "UI", (size_t)2) == 0 || + memcmp(entCur, "CS", (size_t)2) == 0 ) // CS, to remove later + // when Write DCM *adds* // FIXME // Use Document::dicom_vr to test all the possibilities // instead of just checking for UL, OB and UI !? group 0000 @@ -1884,12 +1900,12 @@ bool Document::CheckSwap() if ( SwapCode != 0 ) { - if( memcmp(entCur, "UL", (size_t)2) == 0 || - memcmp(entCur, "OB", (size_t)2) == 0 || - memcmp(entCur, "UI", (size_t)2) == 0 || - memcmp(entCur, "SH", (size_t)2) == 0 || - memcmp(entCur, "AE", (size_t)2) == 0 || - memcmp(entCur, "OB", (size_t)2) == 0 ) + if ( memcmp(entCur, "UL", (size_t)2) == 0 || + memcmp(entCur, "OB", (size_t)2) == 0 || + memcmp(entCur, "UI", (size_t)2) == 0 || + memcmp(entCur, "SH", (size_t)2) == 0 || + memcmp(entCur, "AE", (size_t)2) == 0 || + memcmp(entCur, "OB", (size_t)2) == 0 ) { Filetype = ExplicitVR; gdcmWarningMacro( "Group 0002 : Explicit Value Representation"); @@ -2020,11 +2036,11 @@ void Document::SetMaxSizeLoadEntry(long newSize) } /** - * \brief Read the next tag but WITHOUT loading it's value + * \brief Read the next tag WITHOUT loading it's value * (read the 'Group Number', the 'Element Number', * gets the Dict Entry * gets the VR, gets the length, gets the offset value) - * @return On succes the newly created DocEntry, NULL on failure. + * @return On succes : the newly created DocEntry, NULL on failure. */ DocEntry *Document::ReadNextDocEntry() { @@ -2053,37 +2069,38 @@ DocEntry *Document::ReadNextDocEntry() std::string vr = FindDocEntryVR(); std::string realVR = vr; - if( vr == GDCM_UNKNOWN) + if ( vr == GDCM_UNKNOWN ) { if ( elem == 0x0000 ) // Group Length realVR = "UL"; // must be UL else { DictEntry *dictEntry = GetDictEntry(group,elem); - if( dictEntry ) + if ( dictEntry ) realVR = dictEntry->GetVR(); } } DocEntry *newEntry; - if( Global::GetVR()->IsVROfSequence(realVR) ) + if ( Global::GetVR()->IsVROfSequence(realVR) ) newEntry = NewSeqEntry(group, elem); - else if( Global::GetVR()->IsVROfStringRepresentable(realVR) ) + else if ( Global::GetVR()->IsVROfStringRepresentable(realVR) ) newEntry = NewValEntry(group, elem,vr); else newEntry = NewBinEntry(group, elem,vr); - if( vr == GDCM_UNKNOWN ) + if ( vr == GDCM_UNKNOWN ) { - if( Filetype == ExplicitVR ) + if ( Filetype == ExplicitVR ) { // We thought this was explicit VR, but we end up with an // implicit VR tag. Let's backtrack. if ( newEntry->GetGroup() != 0xfffe ) { std::string msg; - msg = Util::Format("Entry (%04x,%04x) should be Explicit VR\n", - newEntry->GetGroup(), newEntry->GetElement()); + int offset = Fp->tellg(); + msg = Util::Format("Entry (%04x,%04x) at 0x(%x) should be Explicit VR\n", + newEntry->GetGroup(), newEntry->GetElement(), offset ); gdcmWarningMacro( msg.c_str() ); } } @@ -2108,8 +2125,8 @@ DocEntry *Document::ReadNextDocEntry() /** * \brief Handle broken private tag from Philips NTSCAN - * where the endianess is being switch to BigEndian for no - * apparent reason + * where the endianess is being switched to BigEndian + * for no apparent reason * @return no return */ void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem)