X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmDocument.cxx;h=1a3f177c3525696ae6a6126d146b0625c3f84943;hb=e46fd685cb5a48ed7604c523cba93359003f5984;hp=15680d25ca17513ffd993479745ef1f7e7ef9972;hpb=bd1e1aea88a95e4d14cd59088a7e5280703402ea;p=gdcm.git diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index 15680d25..1a3f177c 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/19 12:01:50 $ - Version: $Revision: 1.298 $ + Date: $Date: 2005/11/21 16:28:06 $ + Version: $Revision: 1.331 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -76,7 +76,6 @@ Document::~Document () //----------------------------------------------------------------------------- // Public - /** * \brief Loader. use SetLoadMode(), SetFileName() before ! * @return false if file cannot be open or no swap info was found, @@ -90,18 +89,17 @@ bool Document::Load( ) return false; } return DoTheLoadingDocumentJob( ); -} -/** - * \brief Loader. (DEPRECATED : not to break the API) - * @param fileName 'Document' (File or DicomDir) to be open for parsing - * @return false if file cannot be open or no swap info was found, - * or no tag was found. - */ +} + +/* +//#ifndef GDCM_LEGACY_REMOVE bool Document::Load( std::string const &fileName ) { Filename = fileName; return DoTheLoadingDocumentJob( ); } +//#endif +*/ /** * \brief Performs the Loading Job (internal use only) @@ -119,8 +117,6 @@ bool Document::DoTheLoadingDocumentJob( ) if ( !OpenFile() ) { // warning already performed in OpenFile() - //gdcmWarningMacro( "Unable to open as an ACR/DICOM file: " - // << Filename.c_str() ); Filetype = Unknown; return false; } @@ -154,7 +150,7 @@ bool Document::DoTheLoadingDocumentJob( ) if ( IsEmpty() ) { - gdcmWarningMacro( "No tag in internal hash table for: " + gdcmErrorMacro( "No tag in internal hash table for: " << Filename.c_str()); CloseFile(); return false; @@ -174,20 +170,33 @@ bool Document::DoTheLoadingDocumentJob( ) LoadEntryBinArea(0x0028,0x1200); // gray LUT /// FIXME + /// --> FIXME : The difference between BinEntry and DataEntry + /// --> no longer exists, but the alteration of Dicom Dictionary remains. + /// --> Old comment restored on purpose. + /// --> New one (replacing both BinEntry and ValEntry by DataEntry) + /// --> had absolutely no meaning. + /// --> The whole comment will be removed when the stuff is cleaned ! + /// --> /// 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 /// lines state that the corresponding tag contents are in fact - /// the ones of a DataEntry. + /// the ones of a BinEntry. /// In order to fix things "Quick and Dirty" the dictionary was /// 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 + /// correct value, one needs to decide of the semantics by deciding /// whether the following tags are either : - /// - multivaluated US, and hence loaded as DataEntry, but afterwards - /// also used as DataEntry, which requires the proper conversion, - /// - OW, and hence loaded as DataEntry, but afterwards also used - /// as DataEntry, which requires the proper conversion. + /// - 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 + /// as ValEntry, which requires the proper conversion. + + // --> OB (byte aray) or OW (short int aray) + // The actual VR has to be deduced from other entries. + // Our way of loading them may fail in some cases : + // We must or not SwapByte depending on other field values. + LoadEntryBinArea(0x0028,0x1201); // R LUT LoadEntryBinArea(0x0028,0x1202); // G LUT LoadEntryBinArea(0x0028,0x1203); // B LUT @@ -212,6 +221,8 @@ bool Document::DoTheLoadingDocumentJob( ) { if ( dataEntry->GetLength() != 0 ) { + // FIXME : CTX dependent means : contexted dependant. + // see upper comment. LoadEntryBinArea(dataEntry); //LUT Data (CTX dependent) } } @@ -225,7 +236,7 @@ bool Document::DoTheLoadingDocumentJob( ) it != UserForceLoadList.end(); ++it) { - gdcmWarningMacro( "Force Load " << std::hex + gdcmDebugMacro( "Force Load " << std::hex << (*it).Group << "|" <<(*it).Elem ); d = GetDocEntry( (*it).Group, (*it).Elem); @@ -325,11 +336,11 @@ bool Document::SetShaDict(DictKey const &dictName) * @return false when we're 150 % sure it's NOT a Dicom/Acr file, * true otherwise. */ -bool Document::IsReadable() +bool Document::IsParsable() { if ( Filetype == Unknown ) { - gdcmWarningMacro( "Wrong filetype"); + gdcmWarningMacro( "Wrong filetype for " << GetFileName()); return false; } @@ -341,6 +352,17 @@ bool Document::IsReadable() return true; } +/** + * \brief This predicate tells us whether or not the current Document + * was properly parsed and contains at least *one* Dicom Element + * (and nothing more, sorry). + * @return false when we're 150 % sure it's NOT a Dicom/Acr file, + * true otherwise. + */ +bool Document::IsReadable() +{ + return IsParsable(); +} /** * \brief Predicate for dicom version 3 file. @@ -386,7 +408,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() { @@ -408,6 +431,7 @@ std::string Document::GetTransferSyntax() if ( transfer.length() == 0 ) { // for brain damaged headers + gdcmWarningMacro( "Transfer Syntax has length = 0."); return GDCM_UNKNOWN; } while ( !isdigit((unsigned char)transfer[transfer.length()-1]) ) @@ -416,6 +440,7 @@ std::string Document::GetTransferSyntax() if ( transfer.length() == 0 ) { // for brain damaged headers + gdcmWarningMacro( "Transfer Syntax contains no valid character."); return GDCM_UNKNOWN; } } @@ -441,7 +466,7 @@ std::string Document::GetTransferSyntaxName() } if ( transferSyntax == GDCM_UNFOUND ) { - gdcmWarningMacro( "Unfound Transfer Syntax (0002,0010)"); + gdcmDebugMacro( "Unfound Transfer Syntax (0002,0010)"); return "Uncompressed ACR-NEMA"; } @@ -494,12 +519,48 @@ uint32_t Document::SwapLong(uint32_t a) a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) ); break; default : - gdcmErrorMacro( "Unset swap code:" << SwapCode ); + gdcmErrorMacro( "Unexpected swap code:" << SwapCode ); a = 0; } 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( "Unexpected swap code:" << SwapCode ); + a = 0.; + } + return a; +} + // // -----------------File I/O --------------- /** @@ -517,7 +578,7 @@ std::ifstream *Document::OpenFile() if ( Fp ) { - gdcmWarningMacro( "File already open: " << Filename.c_str()); + gdcmDebugMacro( "File already open: " << Filename.c_str()); CloseFile(); } @@ -528,6 +589,10 @@ std::ifstream *Document::OpenFile() // a spurious message will appear when you use, for instance // gdcm::FileHelper *fh = new gdcm::FileHelper( outputFileName ); // to create outputFileName. + + // FIXME : if the upper comment is still usefull + // --> the constructor is not so good ... + gdcmWarningMacro( "Cannot open file: " << Filename.c_str()); delete Fp; Fp = 0; @@ -544,7 +609,10 @@ std::ifstream *Document::OpenFile() return 0; } - //-- ACR or DICOM with no Preamble; may start with a Shadow Group -- + //-- Broken ACR or DICOM with no Preamble; may start with a Shadow Group -- + + // FIXME : We cannot be sure the preable is only zeroes.. + // (see ACUSON-24-YBR_FULL-RLE.dcm ) if ( zero == 0x0001 || zero == 0x0100 || zero == 0x0002 || zero == 0x0200 || zero == 0x0003 || zero == 0x0300 || zero == 0x0004 || zero == 0x0400 || @@ -552,7 +620,8 @@ std::ifstream *Document::OpenFile() zero == 0x0007 || zero == 0x0700 || zero == 0x0008 || zero == 0x0800 ) { std::string msg = Util::Format( - "ACR/DICOM starting at the beginning of the file:(%04x)\n", zero); + "ACR/DICOM starting by 0x(%04x) at the beginning of the file\n", zero); + // FIXME : is it a Warning message, or a Debug message? gdcmWarningMacro( msg.c_str() ); return Fp; } @@ -574,7 +643,9 @@ std::ifstream *Document::OpenFile() // -- Neither ACR/No Preamble Dicom nor DICOMV3 file CloseFile(); - gdcmWarningMacro( "Neither ACR/No Preamble Dicom nor DICOMV3 file: " + // Don't user Warning nor Error, not to polute the output + // while directory recursive parsing ... + gdcmDebugMacro( "Neither ACR/No Preamble Dicom nor DICOMV3 file: " << Filename.c_str()); return 0; } @@ -605,7 +676,7 @@ void Document::WriteContent(std::ofstream *fp, FileType filetype) // Skip if user wants to write an ACR-NEMA file if ( filetype == ImplicitVR || filetype == ExplicitVR || - filetype == JPEG ) + filetype == JPEG ) { // writing Dicom File Preamble char filePreamble[128]; @@ -624,6 +695,10 @@ void Document::WriteContent(std::ofstream *fp, FileType filetype) * UpdateGroupLength(false,filetype); * if ( filetype == ACR) * UpdateGroupLength(true,ACR); + * + * --> Computing group length for groups with embeded Sequences + * --> was too much tricky / we were [in a hurry / too lazy] + * --> We don't write the element 0x0000 (group length) */ ElementSet::WriteContent(fp, filetype); // This one is recursive @@ -643,15 +718,15 @@ void Document::LoadEntryBinArea(uint16_t group, uint16_t elem) DocEntry *docEntry = GetDocEntry(group, elem); if ( !docEntry ) { - gdcmWarningMacro(std::hex << group << "|" << elem - << "doesn't exist" ); + gdcmDebugMacro(std::hex << group << "|" << elem + << " doesn't exist" ); return; } DataEntry *dataEntry = dynamic_cast(docEntry); if ( !dataEntry ) { gdcmWarningMacro(std::hex << group << "|" << elem - << "is NOT a DataEntry"); + << " is NOT a DataEntry"); return; } LoadEntryBinArea(dataEntry); @@ -660,7 +735,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) { @@ -684,7 +759,7 @@ void Document::LoadEntryBinArea(DataEntry *entry) return; } - // Read the datas + // Read the data Fp->read((char*)data, l); if ( Fp->fail() || Fp->eof() ) { @@ -697,11 +772,17 @@ void Document::LoadEntryBinArea(DataEntry *entry) uint32_t i; unsigned short vrLgth = Global::GetVR()->GetAtomicElementLength(entry->GetVR()); - if( entry->GetVR() == "OW" ) - vrLgth = 1; + +// FIXME : trouble expected if we read an ... OW Entry (LUT, etc ..) +// if( entry->GetVR() == "OW" ) +// vrLgth = 1; switch(vrLgth) { + case 1: + { + break; + } case 2: { uint16_t *data16 = (uint16_t *)data; @@ -718,10 +799,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;iGetVR(); - // FIXME : group 0x0002 is *always* Explicit VR! - - //if ( filetype == ExplicitVR ) - //{ //if ( (vr == "OB")||(vr == "OW")||(vr == "UT")||(vr == "SQ")) // (no SQ, OW, UT in group 0x0002;) if ( vr == "OB" ) { - // explicit VR AND OB, OW, SQ, UT : 4 more bytes + // explicit VR AND (OB, OW, SQ, UT) : 4 more bytes groupLength += 4; } - //} + groupLength += 2 + 2 + 4 + entry->GetLength(); } } @@ -922,7 +997,6 @@ int Document::ComputeGroup0002Length( ) // Private /** * \brief Loads all the needed Dictionaries - * \warning NOT end user intended method ! */ void Document::Initialize() { @@ -949,7 +1023,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, // (Entry will then be deleted) bool delim_mode_intern = delim_mode; bool first = true; - gdcmWarningMacro( "Enter in ParseDES, delim-mode " << delim_mode + gdcmDebugMacro( "Enter in ParseDES, delim-mode " << delim_mode << " at offset " << std::hex << offset ); while (true) { @@ -960,19 +1034,10 @@ void Document::ParseDES(DocEntrySet *set, long offset, newDocEntry = ReadNextDocEntry( ); - // FIXME : - // Private tag, in IMplicit VR are defaulted as a DataEntry, - // Very often they are only composed of Printable characters, - // and could be defaulted as a DataEntry. - // It's too late to do the Job - // (we should check the value, but we know it after LoadDocEntry ...) - - // Uncoment this printf line to be able to 'follow' the DocEntries + // Uncoment this cerr line to be able to 'follow' the DocEntries // when something *very* strange happens - - //printf( "%04x|%04x %s\n",newDocEntry->GetGroup(), - // newDocEntry->GetElement(), - // newDocEntry->GetVR().c_str() ); + if( Debug::GetDebugFlag() ) + std::cerr<GetKey()<<" "<GetVR()<IsItemStarter() ) - { - newDocEntry = Backtrack(newDocEntry); + { + // Debug message within the method ! + newDocEntry = Backtrack(newDocEntry); } else { @@ -998,20 +1064,12 @@ void Document::ParseDES(DocEntrySet *set, long offset, if ( newDataEntry ) { //////////////////////////// DataEntry + vr = newDocEntry->GetVR(); - 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."); - } if ( !set->AddEntry( newDataEntry ) ) { - gdcmWarningMacro( "in ParseDES : cannot add a DataEntry " + gdcmDebugMacro( "in ParseDES : cannot add a DataEntry " << newDataEntry->GetKey() << " (at offset : " << newDataEntry->GetOffset() << " )" ); @@ -1019,6 +1077,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, } else { + newDataEntry->Delete(); // Load only if we can add (not a duplicate key) LoadDocEntry( newDataEntry ); } @@ -1051,7 +1110,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, (!delim_mode && ((long)(Fp->tellg())-offset) >= l_max) ) { if ( !used ) - delete newDocEntry; + newDocEntry->Delete(); break; } @@ -1081,8 +1140,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; } } @@ -1090,8 +1148,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 @@ -1104,11 +1161,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 @@ -1118,15 +1173,12 @@ 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 ) { // Don't try to parse zero-length sequences - gdcmWarningMacro( "Entry in ParseSQ, delim " << delim_mode_intern + gdcmDebugMacro( "Entry in ParseSQ, delim " << delim_mode_intern << " at offset " << std::hex << newDocEntry->GetOffset() ); @@ -1134,7 +1186,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, newDocEntry->GetOffset(), l, delim_mode_intern); - gdcmWarningMacro( "Exit from ParseSQ, delim " << delim_mode_intern); + gdcmDebugMacro( "Exit from ParseSQ, delim " << delim_mode_intern); } if ( !set->AddEntry( newSeqEntry ) ) @@ -1145,18 +1197,22 @@ 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 @@ -1181,7 +1237,6 @@ void Document::ParseSQ( SeqEntry *seqEntry, if ( !newDocEntry ) { - // FIXME Should warn user gdcmWarningMacro("in ParseSQ : should never get here!"); break; } @@ -1190,16 +1245,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,18 +1267,17 @@ void Document::ParseSQ( SeqEntry *seqEntry, dlm_mod = false; } - // 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 ParseDES(itemSQ, offsetStartCurrentSQItem, l+8, dlm_mod); offsetStartCurrentSQItem = Fp->tellg(); - // end try ----------------- seqEntry->AddSQItem( itemSQ, SQItemNumber ); + itemSQ->Delete(); + newDocEntry->Delete(); SQItemNumber++; if ( !delim_mode && ((long)(Fp->tellg())-offset ) >= l_max ) { @@ -1241,7 +1296,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(); @@ -1249,7 +1304,7 @@ DocEntry *Document::Backtrack(DocEntry *docEntry) uint32_t lgt = PreviousDocEntry->GetLength(); long offset = PreviousDocEntry->GetOffset(); - gdcmWarningMacro( "Backtrack :" << std::hex << group + gdcmDebugMacro( "Backtrack :" << std::hex << group << "|" << elem << " at offset " << offset ); RemoveEntry( PreviousDocEntry ); @@ -1309,8 +1364,7 @@ void Document::LoadDocEntry(DocEntry *entry, bool forceLoad) } // The elements whose length is bigger than the specified upper bound - // are not loaded. Instead we leave a short notice on the offset of - // the element content and it's length. + // are not loaded. std::ostringstream s; @@ -1409,7 +1463,8 @@ void Document::FindDocEntryLength( DocEntry *entry ) // Length is on 4 bytes. // Well ... group 0002 is always coded in 'Explicit VR Litle Endian' - // even if Transfer Syntax is 'Implicit VR ...' + // even if Transfer Syntax is 'Implicit VR ...' + // --> Except for 'Implicit VR Big Endian Transfer Syntax GE Private' FixDocEntryFoundLength( entry, ReadInt32() ); return; @@ -1418,7 +1473,6 @@ void Document::FindDocEntryLength( DocEntry *entry ) /** * \brief Find the Length till the next sequence delimiter - * \warning NOT end user intended method ! * @return */ uint32_t Document::FindDocEntryLengthOBOrOW() @@ -1486,20 +1540,24 @@ VRKey Document::FindDocEntryVR() long positionOnEntry = Fp->tellg(); // Warning: we believe this is explicit VR (Value Representation) because - // we used a heuristic that found "UL" in the first tag. Alas this - // doesn't guarantee that all the tags will be in explicit VR. In some - // cases (see e-film filtered files) one finds implicit VR tags mixed - // within an explicit VR file. Hence we make sure the present tag - // is in explicit VR and try to fix things if it happens not to be - // the case. + // we used a heuristic that found "UL" in the first tag and/or + // 'Transfer Syntax' told us it is. + // Alas this doesn't guarantee that all the tags will be in explicit VR. + // In some cases one finds implicit VR tags mixed within an explicit VR file. + // Hence we make sure the present tag is in explicit VR and try to fix things + // if it happens not to be the case. VRKey vr; Fp->read(&(vr[0]),(size_t)2); - gdcmDebugMacro( "--> VR: " << vr ) if ( !CheckDocEntryVR(vr) ) { - gdcmWarningMacro( "Unknown VR '" << vr << "'" ) + // Don't warn user with useless messages + // Often, delimiters (0xfffe), are not explicit VR ... + if ( CurrentGroup != 0xfffe ) + gdcmWarningMacro( "Unknown VR " << std::hex << "0x(" + << (unsigned int)vr[0] << "|" << (unsigned int)vr[1] + << ") at offset :" << positionOnEntry ); Fp->seekg(positionOnEntry, std::ios::beg); return GDCM_VRUNKNOWN; } @@ -1521,7 +1579,6 @@ bool Document::CheckDocEntryVR(const VRKey &vr) /** * \brief Skip a given Header Entry - * \warning NOT end user intended method ! * @param entry entry to skip */ void Document::SkipDocEntry(DocEntry *entry) @@ -1531,7 +1588,6 @@ void Document::SkipDocEntry(DocEntry *entry) /** * \brief Skips to the beginning of the next Header Entry - * \warning NOT end user intended method ! * @param currentDocEntry entry to skip */ void Document::SkipToNextDocEntry(DocEntry *currentDocEntry) @@ -1633,7 +1689,7 @@ bool Document::IsDocEntryAnInteger(DocEntry *entry) { uint16_t elem = entry->GetElement(); uint16_t group = entry->GetGroup(); - const VRKey &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 @@ -1647,9 +1703,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 @@ -1732,19 +1788,19 @@ bool Document::CheckSwap() else { Filetype = ImplicitVR; - gdcmErrorMacro( "Group 0002 :Not an explicit Value Representation;" + gdcmWarningMacro( "Group 0002 :Not an explicit Value Representation;" << "Looks like a bugged Header!"); } if ( net2host ) { SwapCode = 4321; - gdcmDebugMacro( "HostByteOrder != NetworkByteOrder"); + gdcmDebugMacro( "HostByteOrder != NetworkByteOrder, SwapCode = 4321"); } else { SwapCode = 1234; - gdcmDebugMacro( "HostByteOrder = NetworkByteOrder"); + gdcmDebugMacro( "HostByteOrder = NetworkByteOrder, SwapCode = 1234"); } // Position the file position indicator at first tag @@ -1880,8 +1936,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; @@ -1898,6 +1954,7 @@ void Document::SwitchByteSwapCode() { SwapCode = 3412; } + gdcmDebugMacro( " Into: "<< SwapCode ); } /** @@ -1927,13 +1984,10 @@ void Document::SetMaxSizeLoadEntry(long newSize) */ DocEntry *Document::ReadNextDocEntry() { - uint16_t group; - uint16_t elem; - try { - group = ReadInt16(); - elem = ReadInt16(); + CurrentGroup = ReadInt16(); + CurrentElem = ReadInt16(); } catch ( FormatError ) { @@ -1943,11 +1997,11 @@ DocEntry *Document::ReadNextDocEntry() } // Sometimes file contains groups of tags with reversed endianess. - HandleBrokenEndian(group, elem); + HandleBrokenEndian(CurrentGroup, CurrentElem); // In 'true DICOM' files Group 0002 is always little endian if ( HasDCMPreamble ) - HandleOutOfGroup0002(group, elem); + HandleOutOfGroup0002(CurrentGroup, CurrentElem); VRKey vr = FindDocEntryVR(); @@ -1955,11 +2009,12 @@ DocEntry *Document::ReadNextDocEntry() if ( vr == GDCM_VRUNKNOWN ) { - if ( elem == 0x0000 ) // Group Length + if ( CurrentElem == 0x0000 ) // Group Length { realVR = "UL"; // must be UL } - else if (group%2 == 1 && (elem >= 0x0010 && elem <=0x00ff )) + else if (CurrentGroup%2 == 1 && + (CurrentElem >= 0x0010 && CurrentElem <=0x00ff )) { // DICOM PS 3-5 7.8.1 a) states that those // (gggg-0010->00FF where gggg is odd) attributes have to be LO @@ -1967,21 +2022,22 @@ DocEntry *Document::ReadNextDocEntry() } else { - DictEntry *dictEntry = GetDictEntry(group,elem); + DictEntry *dictEntry = GetDictEntry(CurrentGroup,CurrentElem); if ( dictEntry ) { realVR = dictEntry->GetVR(); + dictEntry->Unregister(); } } } - gdcmDebugMacro( "Found VR: " << vr << " / Real VR: " << realVR ); + // gdcmDebugMacro( "Found VR: " << vr << " / Real VR: " << realVR ); DocEntry *newEntry; if ( Global::GetVR()->IsVROfSequence(realVR) ) - newEntry = NewSeqEntry(group, elem); + newEntry = NewSeqEntry(CurrentGroup, CurrentElem); else { - newEntry = NewDataEntry(group, elem, realVR); + newEntry = NewDataEntry(CurrentGroup, CurrentElem, realVR); static_cast(newEntry)->SetState(DataEntry::STATE_NOTLOADED); } @@ -2011,7 +2067,7 @@ DocEntry *Document::ReadNextDocEntry() catch ( FormatError ) { // Call it quits - delete newEntry; + newEntry->Delete(); return 0; } @@ -2035,6 +2091,7 @@ void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem) if ((group == 0xfeff) && (elem == 0x00e0)) { // start endian swap mark for group found + gdcmDebugMacro( "Start endian swap mark found." ); reversedEndian++; SwitchByteSwapCode(); // fix the tag @@ -2044,6 +2101,7 @@ void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem) else if (group == 0xfffe && elem == 0xe00d && reversedEndian) { // end of reversed endian group + gdcmDebugMacro( "End of reversed endian." ); reversedEndian--; SwitchByteSwapCode(); } @@ -2061,7 +2119,7 @@ void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem) } else if (group == 0xfffe && elem == 0xe0dd) { - gdcmWarningMacro( "Straight Sequence Terminator." ); + gdcmDebugMacro( "Straight Sequence Terminator." ); } } @@ -2078,12 +2136,18 @@ void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem) { Group0002Parsed = true; // we just came out of group 0002 - // if Transfer syntax is Big Endian we have to change CheckSwap + // if Transfer Syntax is Big Endian we have to change CheckSwap std::string ts = GetTransferSyntax(); + if ( ts == GDCM_UNKNOWN ) + { + gdcmDebugMacro("True DICOM File, with NO Transfer Syntax (?!) " ); + return; + } if ( !Global::GetTS()->IsTransferSyntax(ts) ) { - gdcmWarningMacro("True DICOM File, with NO Tansfer Syntax: " << ts ); + gdcmWarningMacro("True DICOM File, with illegal Transfer Syntax: [" + << ts << "]"); return; } @@ -2092,9 +2156,9 @@ void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem) if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian ) - { - Filetype = ImplicitVR; - } + { + Filetype = ImplicitVR; + } // FIXME Strangely, this works with //'Implicit VR BigEndian Transfer Syntax (GE Private) @@ -2106,7 +2170,7 @@ void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem) if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian ) { - gdcmWarningMacro("Transfer Syntax Name = [" + gdcmDebugMacro("Transfer Syntax Name = [" << GetTransferSyntaxName() << "]" ); SwitchByteSwapCode(); group = SwapShort(group);