X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmElementSet.cxx;h=c476b0a5395284b2c8000dc1c789fb129fa93b20;hb=0bcc188c6d5185375f809253e8b9b97c856d2eac;hp=33325c3fda8ba30b71857eac771eaf988534e90b;hpb=0b36f4932e894a1dde4a80e614755816b4b29218;p=gdcm.git diff --git a/src/gdcmElementSet.cxx b/src/gdcmElementSet.cxx index 33325c3f..c476b0a5 100644 --- a/src/gdcmElementSet.cxx +++ b/src/gdcmElementSet.cxx @@ -1,152 +1,306 @@ -// gdcmElementSet.cxx -//----------------------------------------------------------------------------- -// -#include "gdcmElementSet.h" -#include "gdcmTS.h" +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmElementSet.cxx,v $ + Language: C++ + Date: $Date: 2007/08/29 15:30:49 $ + Version: $Revision: 1.78 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "gdcmElementSet.h" +#include "gdcmDebug.h" +#include "gdcmSeqEntry.h" +#include "gdcmDataEntry.h" +namespace GDCM_NAME_SPACE +{ //----------------------------------------------------------------------------- // Constructor / Destructor /** - * \ingroup gdcmElementSet - * \brief Constructor from a given gdcmElementSet + * \brief Constructor for a given ElementSet */ -gdcmDocEntrySet::gdcmDocEntrySet() { - +ElementSet::ElementSet() + : DocEntrySet() +{ } /** - * \ingroup gdcmElementSet * \brief Canonical destructor. */ -gdcmElementSet::~gdcmElementSet() +ElementSet::~ElementSet() { -/* for(tous les DocEntry) + ClearEntry(); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Writes the Header Entries (Dicom Elements) + * from the H Table + * @param fp ofstream to write to + * @param filetype ExplicitVR/ImplicitVR/ACR/ACR_LIBIDO/JPEG/JPEG2000/... + */ +void ElementSet::WriteContent(std::ofstream *fp, FileType filetype, bool dummy, bool dummy2) +{ + bool insideMetaElements = false; + bool yetOutsideMetaElements = false; + int countSQ =0; + + for (TagDocEntryHT::const_iterator i = TagHT.begin(); + i != TagHT.end(); + ++i) { - delete *cc; + int group = (i->second)->GetGroup(); + + if (yetOutsideMetaElements==false && group == 0x0002) + insideMetaElements = true; + + if (insideMetaElements == true && group != 0x0002) + { + yetOutsideMetaElements = true; + insideMetaElements = false; + } + + // depending on the gdcm::Document type + // (gdcm::File; gdcm::DicomDir, (more to come ?) + // some groups *cannot* be present. + // We hereby protect gdcm for writting stupid things + // if they were found in the original document. + if ( !MayIWrite( group ) ) + continue; + + // Skip 'Group Length' element, since it may be wrong. + // except for Group 0x0002 + // ( keep it as well for Group 0x0008 of ACR Files, + // since some ACR readers *need* it ) + + if ( (i->second)->GetElement() != 0x0000 + || + ( (i->second)->GetGroup() == 0x0002 + ||( (filetype == ACR || filetype == ACR_LIBIDO ) && (i->second)->GetGroup() == 0x0008 ) ) + ) + { + // There are DocEntries, written recursively + // false : we are outside any Sequence + i->second->WriteContent(fp, filetype, insideMetaElements, false ); + } + } +} + +/** + * \brief add a new Dicom Element pointer to the H Table + * @param newEntry entry to add + */ +bool ElementSet::AddEntry(DocEntry *newEntry) +{ + const TagKey &key = newEntry->GetKey(); + + if ( TagHT.count(key) == 1 ) + { + gdcmWarningMacro( "Key already present: " << key ); + return false; + } + else + { + TagHT.insert(TagDocEntryHT::value_type(newEntry->GetKey(), newEntry)); + newEntry->Register(); + return true; } - */ } +/** + * \brief Clear the hash table from given entry AND delete the entry. + * @param entryToRemove Entry to remove AND delete. + */ +bool ElementSet::RemoveEntry( DocEntry *entryToRemove) +{ + const TagKey &key = entryToRemove->GetKey(); + if ( TagHT.count(key) == 1 ) + { + TagHT.erase(key); + entryToRemove->Unregister(); + return true; + } -//----------------------------------------------------------------------------- -// Public + gdcmWarningMacro( "Key not present : " << key); + return false ; +} +/** + * \brief delete all entries in the ElementSet + */ +void ElementSet::ClearEntry() +{ + for(TagDocEntryHT::iterator cc = TagHT.begin();cc != TagHT.end(); ++cc) + { + if ( cc->second ) + { + cc->second->Unregister(); + } + } + TagHT.clear(); +} -//----------------------------------------------------------------------------- -// Protected +/** + * \brief Get the first entry while visiting *the* 'zero level' DocEntrySet + * (DocEntries out of any Sequence) + * \return The first DocEntry if found, otherwhise NULL + */ +DocEntry *ElementSet::GetFirstEntry() +{ + ItTagHT = TagHT.begin(); + if (ItTagHT != TagHT.end()) + return ItTagHT->second; + return NULL; +} -//----------------------------------------------------------------------------- -// Private +/** + * \brief Get the next entry while visiting *the* 'zero level' DocEntrySet + * (DocEntries out of any Sequence) + * \note : meaningfull only if GetFirstEntry already called + * \return The next DocEntry if found, otherwhise NULL + */ +DocEntry *ElementSet::GetNextEntry() +{ + gdcmAssertMacro (ItTagHT != TagHT.end()); + + ++ItTagHT; + if (ItTagHT != TagHT.end()) + return ItTagHT->second; + return NULL; +} /** - * \brief Find the value Length of the passed Header Entry - * @param Entry Header Entry whose length of the value shall be loaded. + * \brief retrieves a Dicom Element using (group, element) + * @param group Group number of the searched Dicom Element + * @param elem Element number of the searched Dicom Element + * @return */ - void gdcmElementSet::FindDocEntryLength (gdcmDocEntry *Entry) { - guint16 element = Entry->GetElement(); - //guint16 group = Entry->GetGroup(); //FIXME - std::string vr = Entry->GetVR(); - guint16 length16; - - - if ( (filetype == ExplicitVR) && (! Entry->IsImplicitVR()) ) +DocEntry *ElementSet::GetDocEntry(uint16_t group, uint16_t elem) +{ + TagKey key = DictEntry::TranslateToKey(group, elem); + TagDocEntryHT::iterator it = TagHT.find(key); + + if ( it!=TagHT.end() ) + return it->second; + return NULL; +} + +/** + * \brief Copies all the attributes from an other DocEntrySet + * @param set entry to copy from + * @remarks The contained DocEntries a not copied, only referenced + */ +void ElementSet::Copy(DocEntrySet *set) +{ + // Remove all previous entries + ClearEntry(); + + DocEntrySet::Copy(set); + + ElementSet *eltSet = dynamic_cast(set); + if( eltSet ) { - if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) + TagHT = eltSet->TagHT; + for(ItTagHT = TagHT.begin();ItTagHT != TagHT.end();++ItTagHT) { - // 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) ) - { - Entry->SetLength(FindHeaderEntryLengthOB()); - return; - } - FixHeaderEntryFoundLength(Entry, length32); - return; + (ItTagHT->second)->Register(); } + } +} - // Length is encoded on 2 bytes. - length16 = ReadInt16(); - - // 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 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 - // encoding, we raise the proper flags. Then we wait for the end - // of the META group (0x0002) among which is "Transfer Syntax", - // before switching the swap code to big endian. We have to postpone - // the switching of the swap code since the META group is fully encoded - // 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 consists 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 - // encounter 1024 (0x0400) chances are the encoding changed and we - // found a group with big endian encoding. - // We shall use this second strategy. In order to make sure that we - // can interpret the presence of an apparently big endian encoded - // length of a "Group Length" without committing a big mistake, we - // add an additional check: we look in the already parsed elements - // for the presence of a "Transfer Syntax" whose value has to be "big - // endian encoding". When this is the case, chances are we have got our - // hands on a big endian encoded file: we switch the swap code to - // big endian and proceed... - if ( (element == 0x0000) && (length16 == 0x0400) ) +/** + * \brief Checks whether *all* the DataEntries of the group have all + * the same type for VR (ImplicitVR or ExplicitVR) + * @param group group number to be checked + * @return 1:ImplicitVR 2:ExplicitVR -1:NotCoherent + */ +int ElementSet::IsVRCoherent( uint16_t group ) +{ + uint16_t currentGroup; + int codeVR = -1; + int currentCodeVR; + for(TagDocEntryHT::iterator cc = TagHT.begin();cc != TagHT.end(); ++cc) + { + currentGroup = cc->second->GetGroup(); + + if ( currentGroup < group ) + continue; + if ( currentGroup > group ) + break; + // currentGroup == group + if (codeVR == -1) { - if ( ! IsExplicitVRBigEndianTransferSyntax() ) - { - dbg.Verbose(0, "gdcmDocument::FindLength", "not explicit VR"); - errno = 1; - return; - } - length16 = 4; - SwitchSwapToBigEndian(); - // Restore the unproperly loaded values i.e. the group, the element - // and the dictionary entry depending on them. - guint16 CorrectGroup = SwapShort(Entry->GetGroup()); - guint16 CorrectElem = SwapShort(Entry->GetElement()); - gdcmDictEntry * NewTag = GetDictEntryByNumber(CorrectGroup, - CorrectElem); - if (!NewTag) - { - // This correct tag is not in the dictionary. Create a new one. - NewTag = NewVirtualDictEntry(CorrectGroup, CorrectElem); - } - // FIXME this can create a memory leaks on the old entry that be - // left unreferenced. - Entry->SetDictEntry(NewTag); + if (cc->second->IsImplicitVR() ) + codeVR = 1; + else + codeVR = 2; + continue; } - - // Heuristic: well some files are really ill-formed. - if ( length16 == 0xffff) + else { - length16 = 0; - //dbg.Verbose(0, "gdcmDocument::FindLength", - // "Erroneous element length fixed."); - // Actually, length= 0xffff means that we deal with - // Unknown Sequence Length + if (cc->second->IsImplicitVR() ) + currentCodeVR = 1; //Implicit + else + currentCodeVR = 2; // Explicit + + if ( currentCodeVR == codeVR ) + continue; + else + return -1; // -1 : not coherent } - FixHeaderEntryFoundLength(Entry, (guint32)length16); - return; + } + return codeVR; +} + + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Prints the Header Entries (Dicom Elements) from the H Table + * @param os ostream to write to + * @param indent Indentation string to be prepended during printing + */ +void ElementSet::Print(std::ostream &os, std::string const & ) +{ + // Let's change the 'warning value' for Pixel Data, + // to avoid human reader to be confused by 'gdcm::NotLoaded'. + DataEntry *pixelElement = GetDataEntry(0x7fe0,0x0010); + if ( pixelElement != 0 ) + { + pixelElement->SetFlag( DataEntry::FLAG_PIXELDATA ); } - else + + for( TagDocEntryHT::const_iterator i = TagHT.begin(); i != TagHT.end(); ++i) { - // Either implicit VR or a non DICOM conformal (see note 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. - - FixHeaderEntryFoundLength(Entry, ReadInt32()); - return; + DocEntry *entry = i->second; + + entry->SetPrintLevel(PrintLevel); + entry->Print(os); + + if ( dynamic_cast(entry) ) + { + // Avoid the newline for a sequence: + continue; + } + os << std::endl; } } + +//----------------------------------------------------------------------------- +} // end namespace gdcm