X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmDocument.cxx;h=8027220eb8cff68d6983418b6139f96fdc7ddf15;hb=cb4f20df180632c04cfd29497b0038874b24678c;hp=e39d799bbed0e1f6d7c34a93599f7b9e6e32b959;hpb=d22baa64f4ee5306566910262d2b0e82997922a2;p=gdcm.git diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index e39d799b..8027220e 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/20 15:58:53 $ - Version: $Revision: 1.248 $ + Date: $Date: 2005/07/06 09:25:12 $ + Version: $Revision: 1.258 $ 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; @@ -104,16 +106,15 @@ Document::~Document () */ 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: " << Filename.c_str() << ". New name is :" << fileName ); - // todo : clean out the 'Document' - // Should we call ClearEntry() on the parent object ?!? + // clean out the Entries, if already parsed + // (probabely a mistake from the user) + ClearEntry(); } Filename = fileName; @@ -151,7 +152,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,10 +170,14 @@ 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 " ) { - LoadEntryBinArea(0x0028,0x1200); // gray LUT - /// FIXME FIXME FIXME + // FIXME + // Probabely this line should be outside the 'if' + // Try to find an image sample holding a 'gray LUT' + LoadEntryBinArea(0x0028,0x1200); // gray LUT + + /// FIXME /// The tags refered by the three following lines used to be CORRECTLY /// defined as having an US Value Representation in the public /// dictionary. BUT the semantics implied by the three following @@ -180,7 +187,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 @@ -202,7 +209,7 @@ bool Document::Load( std::string const &fileName ) if ( modLutSeq !=0 ) { SQItem *sqi= modLutSeq->GetFirstSQItem(); - if ( !sqi ) + if ( sqi != 0 ) { BinEntry *b = sqi->GetBinEntry(0x0028,0x3006); if ( b != 0 ) @@ -220,7 +227,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. // @@ -289,7 +296,7 @@ bool Document::SetShaDict(DictKey const &dictName) */ bool Document::IsReadable() { - if( Filetype == Unknown) + if ( Filetype == Unknown ) { gdcmWarningMacro( "Wrong filetype"); return false; @@ -472,14 +479,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 @@ -495,14 +502,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 || @@ -518,12 +525,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; @@ -542,7 +549,7 @@ std::ifstream *Document::OpenFile() */ bool Document::CloseFile() { - if( Fp ) + if ( Fp ) { Fp->close(); delete Fp; @@ -606,7 +613,7 @@ void Document::LoadEntryBinArea(uint16_t group, uint16_t elem) return; BinEntry *binElement = dynamic_cast(docElement); - if( !binElement ) + if ( !binElement ) return; LoadEntryBinArea(binElement); @@ -619,11 +626,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(); @@ -631,14 +638,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; @@ -646,7 +653,7 @@ void Document::LoadEntryBinArea(BinEntry *elem) elem->SetBinArea(a); - if(openFile) + if ( openFile ) CloseFile(); } @@ -658,7 +665,7 @@ void Document::LoadEntryBinArea(BinEntry *elem) */ void Document::LoadDocEntrySafe(DocEntry *entry) { - if(Fp) + if ( Fp ) { long PositionOnEntry = Fp->tellg(); LoadDocEntry(entry); @@ -678,11 +685,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; } @@ -708,7 +715,7 @@ bool Document::operator<(Document &document) { return true; } - else if( s1 > s2 ) + else if ( s1 > s2 ) { return false; } @@ -721,7 +728,7 @@ bool Document::operator<(Document &document) { return true; } - else if( s1 > s2 ) + else if ( s1 > s2 ) { return false; } @@ -747,7 +754,7 @@ uint16_t Document::ReadInt16() { throw FormatError( "Document::ReadInt16()", " file error." ); } - if( Fp->eof() ) + if ( Fp->eof() ) { throw FormatError( "Document::ReadInt16()", "EOF." ); } @@ -769,7 +776,7 @@ uint32_t Document::ReadInt32() { throw FormatError( "Document::ReadInt32()", " file error." ); } - if( Fp->eof() ) + if ( Fp->eof() ) { throw FormatError( "Document::ReadInt32()", "EOF." ); } @@ -806,15 +813,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") ) { @@ -848,9 +855,9 @@ 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 l_max length to parse (meaningless when we are in 'delimitor mode') * @param delim_mode : whether we are in 'delimitor mode' (l=0xffffff) or not */ void Document::ParseDES(DocEntrySet *set, long offset, @@ -862,6 +869,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, SeqEntry *newSeqEntry; VRKey vr; bool used; + bool delim_mode_intern = delim_mode; while (true) { @@ -870,7 +878,6 @@ void Document::ParseDES(DocEntrySet *set, long offset, break; } - used = true; newDocEntry = ReadNextDocEntry( ); if ( !newDocEntry ) @@ -878,15 +885,15 @@ void Document::ParseDES(DocEntrySet *set, long offset, break; } - vr = newDocEntry->GetVR(); + used = true; newValEntry = dynamic_cast(newDocEntry); newBinEntry = dynamic_cast(newDocEntry); - newSeqEntry = dynamic_cast(newDocEntry); if ( newValEntry || newBinEntry ) { if ( newBinEntry ) { + vr = newDocEntry->GetVR(); if ( Filetype == ExplicitVR && !Global::GetVR()->IsVROfBinaryRepresentable(vr) ) { @@ -914,11 +921,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; - used=false; + gdcmWarningMacro( "in ParseDES : cannot add a BinEntry " + << newBinEntry->GetKey() ); + used=false; } } else @@ -964,22 +971,22 @@ 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 + gdcmWarningMacro( "in ParseDES : cannot add a ValEntry " + << newValEntry->GetKey() ); used=false; } 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; } @@ -990,29 +997,43 @@ 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; - } + } + // delay the dynamic cast as late as possible + newSeqEntry = dynamic_cast(newDocEntry); - // no other way to create it ... - newSeqEntry->SetDelimitorMode( delim_mode ); + // no other way to create the Delimitor ... + 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. @@ -1037,22 +1058,24 @@ 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 ) ) { + gdcmWarningMacro( "in ParseDES : cannot add a SeqEntry " + << newSeqEntry->GetKey() ); used = false; } - + if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max) { - if( !used ) + if ( !used ) delete newDocEntry; break; } } - if( !used ) + if ( !used ) delete newDocEntry; } } @@ -1076,9 +1099,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() ) { @@ -1115,7 +1139,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 ----------------- @@ -1145,7 +1171,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; @@ -1159,7 +1185,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; @@ -1259,7 +1285,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 << @@ -1287,7 +1313,7 @@ void Document::LoadDocEntry(DocEntry *entry) return; } - if( vr == "UI" ) + if ( vr == "UI" ) { // Because of correspondance with the VR dic valEntry->SetValue(newValue); @@ -1467,7 +1493,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; @@ -1515,14 +1541,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 << '\\'; } @@ -1538,14 +1564,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 << '\\'; } @@ -1702,12 +1728,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; } @@ -1770,12 +1796,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; @@ -1790,7 +1811,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)" ); @@ -1814,11 +1835,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 @@ -1880,12 +1901,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"); @@ -1977,7 +1998,8 @@ bool Document::CheckSwap() */ void Document::SwitchByteSwapCode() { - gdcmWarningMacro( "Switching Byte Swap code from "<< SwapCode); + gdcmWarningMacro( "Switching Byte Swap code from "<< SwapCode + << " at :" <tellg() ); if ( SwapCode == 1234 ) { SwapCode = 4321; @@ -2015,11 +2037,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() { @@ -2048,37 +2070,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() ); } } @@ -2103,8 +2126,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)