X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmElementSet.cxx;h=378ecebd68d8a6add4af0da117b0862c74ee891e;hb=cb593916f564c344b33051ff890ba4a06b77375a;hp=33325c3fda8ba30b71857eac771eaf988534e90b;hpb=0b36f4932e894a1dde4a80e614755816b4b29218;p=gdcm.git diff --git a/src/gdcmElementSet.cxx b/src/gdcmElementSet.cxx index 33325c3f..378ecebd 100644 --- a/src/gdcmElementSet.cxx +++ b/src/gdcmElementSet.cxx @@ -1,37 +1,172 @@ -// gdcmElementSet.cxx -//----------------------------------------------------------------------------- -// -#include "gdcmElementSet.h" -#include "gdcmTS.h" +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmElementSet.cxx,v $ + Language: C++ + Date: $Date: 2005/10/26 06:07:26 $ + Version: $Revision: 1.68 $ + + 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 +{ //----------------------------------------------------------------------------- // 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() +{ + ClearEntry(); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Writes the Header Entries (Dicom Elements) + * from the H Table + * @param fp ofstream to write to + * @param filetype filetype + */ +void ElementSet::WriteContent(std::ofstream *fp, FileType filetype) +{ + for (TagDocEntryHT::const_iterator i = TagHT.begin(); + i != TagHT.end(); + ++i) + { + // FIXME : find a trick to know if current object is a + // gdcm::File or a gdcm::Document + //if ( dynamic_cast< File* > ( this ) ) { // ignore illegal groups } + + // Skip 'Group Length' element, since it may be wrong. + // except for Group 0002 + if ( (i->second)->GetElement() == 0x0000 + && (i->second)->GetElement() != 0x0002 ) + continue; + + i->second->WriteContent(fp, filetype); + } +} + +/** + * \brief add a new Dicom Element pointer to the H Table + * @param newEntry entry to add + */ +bool ElementSet::AddEntry(DocEntry *newEntry) { -/* for(tous les DocEntry) + const TagKey &key = newEntry->GetKey(); + + if ( TagHT.count(key) == 1 ) { - delete *cc; + 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(); +} + +/** + * \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; +} + +/** + * \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 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 + */ +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; +} //----------------------------------------------------------------------------- // Protected @@ -39,114 +174,38 @@ gdcmElementSet::~gdcmElementSet() //----------------------------------------------------------------------------- // Private +//----------------------------------------------------------------------------- +// Print /** - * \brief Find the value Length of the passed Header Entry - * @param Entry Header Entry whose length of the value shall be loaded. - */ - 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()) ) + * \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 ) { - if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) - { - // 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; - } + pixelElement->SetFlag( DataEntry::FLAG_PIXELDATA ); + } - // 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) ) - { - 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); - } - - // Heuristic: well some files are really ill-formed. - if ( length16 == 0xffff) + for( TagDocEntryHT::const_iterator i = TagHT.begin(); i != TagHT.end(); ++i) + { + DocEntry *entry = i->second; + + entry->SetPrintLevel(PrintLevel); + entry->Print(os); + + if ( dynamic_cast(entry) ) { - length16 = 0; - //dbg.Verbose(0, "gdcmDocument::FindLength", - // "Erroneous element length fixed."); - // Actually, length= 0xffff means that we deal with - // Unknown Sequence Length + // Avoid the newline for a sequence: + continue; } - FixHeaderEntryFoundLength(Entry, (guint32)length16); - return; - } - else - { - // 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; + os << std::endl; } } + +//----------------------------------------------------------------------------- +} // end namespace gdcm