X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmParser.cxx;h=ad61419132e4bc03917241f98abd6e0d7defe346;hb=d3e997d981d84fece924c52c8b513bccc6cd371a;hp=1b86aecabd9d9ed3f237431196b3b80db05ac348;hpb=e91954ea004b606c51e8195948fb7e89a9a5b631;p=gdcm.git diff --git a/src/gdcmParser.cxx b/src/gdcmParser.cxx index 1b86aeca..ad614191 100644 --- a/src/gdcmParser.cxx +++ b/src/gdcmParser.cxx @@ -2,6 +2,7 @@ //----------------------------------------------------------------------------- #include "gdcmParser.h" #include "gdcmUtil.h" +#include // For nthos: #ifdef _MSC_VER @@ -16,6 +17,12 @@ # else # include #endif +# include + +#define UI1_2_840_10008_1_2 "1.2.840.10008.1.2" +#define UI1_2_840_10008_1_2_1 "1.2.840.10008.1.2.1" +#define UI1_2_840_10008_1_2_2 "1.2.840.10008.1.2.2" +#define UI1_2_840_10008_1_2_1_99 "1.2.840.10008.1.2.1.99" //----------------------------------------------------------------------------- // Refer to gdcmParser::CheckSwap() @@ -80,10 +87,8 @@ gdcmParser::gdcmParser(bool exception_on_error) */ gdcmParser::~gdcmParser (void) { - dicom_vr = (gdcmVR*)0; - Dicts = (gdcmDictSet*)0; - RefPubDict = (gdcmDict*)0; - RefShaDict = (gdcmDict*)0; + RefPubDict = NULL; + RefShaDict = NULL; } //----------------------------------------------------------------------------- @@ -94,16 +99,11 @@ gdcmParser::~gdcmParser (void) * both from the H Table and the chained list * @return */ -void gdcmParser::PrintPubEntry(std::ostream & os) +void gdcmParser::PrintEntry(std::ostream & os) { std::ostringstream s; -// guint32 lgth; -// char greltag[10]; //group element tag - s << "------------ using listEntries ----------------" << std::endl; - -// char st[20]; for (ListTag::iterator i = listEntries.begin(); i != listEntries.end(); ++i) @@ -136,6 +136,46 @@ void gdcmParser::PrintShaDict(std::ostream & os) //----------------------------------------------------------------------------- // Public +/** + * \ingroup gdcmParser + * \brief Get the public dictionary used + */ +gdcmDict *gdcmParser::GetPubDict(void) +{ + return(RefPubDict); +} + +/** + * \ingroup gdcmParser + * \brief Get the shadow dictionary used + */ +gdcmDict *gdcmParser::GetShaDict(void) +{ + return(RefShaDict); +} + +/** + * \ingroup gdcmParser + * \brief Set the shadow dictionary used + * \param dict dictionary to use in shadow + */ +bool gdcmParser::SetShaDict(gdcmDict *dict) +{ + RefShaDict=dict; + return(!RefShaDict); +} + +/** + * \ingroup gdcmParser + * \brief Set the shadow dictionary used + * \param dictName name of the dictionary to use in shadow + */ +bool gdcmParser::SetShaDict(DictKey dictName) +{ + RefShaDict=gdcmGlobal::GetDicts()->GetDict(dictName); + return(!RefShaDict); +} + /** * \ingroup gdcmParser * \brief This predicate, based on hopefully reasonable heuristics, @@ -147,21 +187,13 @@ void gdcmParser::PrintShaDict(std::ostream & os) */ bool gdcmParser::IsReadable(void) { - std::string res = GetEntryByNumber(0x0028, 0x0005); - if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 ) - { - return false; // Image Dimensions - } + if(filetype==Unknown) + return(false); - if ( !GetHeaderEntryByNumber(0x0028, 0x0100) ) - return false; // "Bits Allocated" - if ( !GetHeaderEntryByNumber(0x0028, 0x0101) ) - return false; // "Bits Stored" - if ( !GetHeaderEntryByNumber(0x0028, 0x0102) ) - return false; // "High Bit" - if ( !GetHeaderEntryByNumber(0x0028, 0x0103) ) - return false; // "Pixel Representation" - return true; + if(listEntries.size()<=0) + return(false); + + return(true); } /** @@ -179,7 +211,7 @@ bool gdcmParser::IsImplicitVRLittleEndianTransferSyntax(void) LoadHeaderEntrySafe(Element); std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2" ) + if ( Transfer == UI1_2_840_10008_1_2 ) return true; return false; } @@ -199,7 +231,7 @@ bool gdcmParser::IsExplicitVRLittleEndianTransferSyntax(void) LoadHeaderEntrySafe(Element); std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.1" ) + if ( Transfer == UI1_2_840_10008_1_2_1 ) return true; return false; } @@ -219,7 +251,7 @@ bool gdcmParser::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) LoadHeaderEntrySafe(Element); std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.1.99" ) + if ( Transfer == UI1_2_840_10008_1_2_1_99 ) return true; return false; } @@ -239,7 +271,7 @@ bool gdcmParser::IsExplicitVRBigEndianTransferSyntax(void) LoadHeaderEntrySafe(Element); std::string Transfer = Element->GetValue(); - if ( Transfer == "1.2.840.10008.1.2.2" ) //1.2.2 ??? A verifier ! + if ( Transfer == UI1_2_840_10008_1_2_2 ) //1.2.2 ??? A verifier ! return true; return false; } @@ -290,7 +322,6 @@ FILE *gdcmParser::OpenFile(bool exception_on_error) dbg.Verbose(0, "gdcmParser::gdcmParser not DICOM/ACR", filename.c_str()); } else { - std::cerr<GetTagByName(tagName); + gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); if( dictEntry == NULL) return GDCM_UNFOUND; @@ -503,7 +517,7 @@ std::string gdcmParser::GetEntryByName(std::string tagName) */ std::string gdcmParser::GetEntryVRByName(std::string tagName) { - gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); + gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); if( dictEntry == NULL) return GDCM_UNFOUND; @@ -562,46 +576,12 @@ std::string gdcmParser::GetEntryVRByNumber(guint16 group, guint16 element) */ bool gdcmParser::SetEntryByName(std::string content,std::string tagName) { - gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); + gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); if( dictEntry == NULL) return false; return(SetEntryByNumber(content,dictEntry->GetGroup(), dictEntry->GetElement())); -/* TagKey key = gdcmDictEntry::TranslateToKey(dictEntry->GetGroup(), - dictEntry->GetElement()); - if ( GetPubEntry().count(key) == 0 ) - return false; - - int l = content.length(); - if(l%2) // Odd length are padded with a space (020H). - { - l++; - content = content + '\0'; - } - - //tagHt[key]->SetValue(content); - gdcmHeaderEntry * a; - IterHT p; - TagHeaderEntryHT::iterator p2; - // DO NOT remove the following lines : they explain how the stuff works - //p= tagHt.equal_range(key); // get a pair of iterators first-last synonym - //p2=p.first; // iterator on the first synonym - //a=p2->second; // H Table target column (2-nd col) - // or, easier : - a = ((GetPubEntry().equal_range(key)).first)->second; - a-> SetValue(content); - std::string vr = a->GetVR(); - - guint32 lgr; - if( (vr == "US") || (vr == "SS") ) - lgr = 2; - else if( (vr == "UL") || (vr == "SL") ) - lgr = 4; - else - lgr = l; - a->SetLength(lgr); - return true;*/ } /** @@ -666,13 +646,13 @@ bool gdcmParser::SetEntryByNumber(std::string content, * the given value. * \warning Use with extreme caution. * @param length new length to substitute with - * @param group group of the ElVal to modify - * @param element element of the ElVal to modify + * @param group group of the entry to modify + * @param element element of the Entry to modify * @return 1 on success, 0 otherwise. */ bool gdcmParser::SetEntryLengthByNumber(guint32 length, - guint16 group, guint16 element) + guint16 group, guint16 element) { TagKey key = gdcmDictEntry::TranslateToKey(group, element); if ( ! tagHT.count(key)) @@ -770,6 +750,52 @@ bool gdcmParser::SetEntryVoidAreaByNumber(void * area,guint16 group, guint16 ele return true; } +/** + * \ingroup gdcmParser + * \brief Update the entries with the shadow dictionary. Only odd entries are + * analized + */ +void gdcmParser::UpdateShaEntries(void) +{ + gdcmDictEntry *entry; + std::string vr; + + for(ListTag::iterator it=listEntries.begin(); + it!=listEntries.end(); + ++it) + { + // Odd group => from public dictionary + if((*it)->GetGroup()%2==0) + continue; + + // Peer group => search the corresponding dict entry + if(RefShaDict) + entry=RefShaDict->GetDictEntryByNumber((*it)->GetGroup(),(*it)->GetElement()); + else + entry=NULL; + + if((*it)->IsImplicitVR()) + vr="Implicit"; + else + vr=(*it)->GetVR(); + + (*it)->SetValue(GetHeaderEntryUnvalue(*it)); + if(entry) + { + // Set the new entry and the new value + (*it)->SetDictEntry(entry); + CheckHeaderEntryVR(*it,vr); + + (*it)->SetValue(GetHeaderEntryValue(*it)); + } + else + { + // Remove precedent value transformation + (*it)->SetDictEntry(NewVirtualDictEntry((*it)->GetGroup(),(*it)->GetElement(),vr)); + } + } +} + /** * \ingroup gdcmParser * \brief Searches within the Header Entries for a Dicom Element of @@ -780,7 +806,7 @@ bool gdcmParser::SetEntryVoidAreaByNumber(void * area,guint16 group, guint16 ele */ gdcmHeaderEntry *gdcmParser::GetHeaderEntryByName(std::string tagName) { - gdcmDictEntry *dictEntry = RefPubDict->GetTagByName(tagName); + gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName); if( dictEntry == NULL) return NULL; @@ -1071,6 +1097,17 @@ guint32 gdcmParser::SwapLong(guint32 a) return(a); } +/** + * \ingroup gdcmParser + * \brief Unswaps back the bytes of 4-byte long integer accordingly to + * processor order. + * @return The properly unswaped 32 bits integer. + */ +guint32 gdcmParser::UnswapLong(guint32 a) +{ + return (SwapLong(a)); +} + /** * \ingroup gdcmParser * \brief Swaps the bytes so they agree with the processor order @@ -1083,8 +1120,35 @@ guint16 gdcmParser::SwapShort(guint16 a) return (a); } +/** + * \ingroup gdcmParser + * \brief Unswaps the bytes so they agree with the processor order + * @return The properly unswaped 16 bits integer. + */ +guint16 gdcmParser::UnswapShort(guint16 a) +{ + return (SwapShort(a)); +} + //----------------------------------------------------------------------------- // Private +/** + * \ingroup gdcmParser + * \brief Parses the header of the file but WITHOUT loading element values. + */ +void gdcmParser::Parse(bool exception_on_error) throw(gdcmFormatError) +{ + gdcmHeaderEntry *newHeaderEntry = (gdcmHeaderEntry *)0; + + rewind(fp); + CheckSwap(); + while ( (newHeaderEntry = ReadNextHeaderEntry()) ) + { + SkipHeaderEntry(newHeaderEntry); + AddHeaderEntry(newHeaderEntry); + } +} + /** * \ingroup gdcmParser * \brief Loads the element values of all the Header Entries pointed in the @@ -1093,12 +1157,12 @@ guint16 gdcmParser::SwapShort(guint16 a) void gdcmParser::LoadHeaderEntries(void) { rewind(fp); - for (ListTag::iterator i = GetPubListEntry().begin(); - i != GetPubListEntry().end(); + for (ListTag::iterator i = GetListEntry().begin(); + i != GetListEntry().end(); ++i) { - LoadHeaderEntry(*i); - } + LoadHeaderEntry(*i); + } rewind(fp); @@ -1141,17 +1205,17 @@ void gdcmParser::LoadHeaderEntries(void) * \brief Loads the element content if it's length is not bigger * than the value specified with * gdcmParser::SetMaxSizeLoadEntry() - * @param ElVal Header Entry (Dicom Element) to be dealt with + * @param Entry Header Entry (Dicom Element) to be dealt with */ -void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry * ElVal) +void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry *Entry) { size_t item_read; - guint16 group = ElVal->GetGroup(); - std::string vr= ElVal->GetVR(); - guint32 length = ElVal->GetLength(); + guint16 group = Entry->GetGroup(); + std::string vr= Entry->GetVR(); + guint32 length = Entry->GetLength(); bool SkipLoad = false; - fseek(fp, (long)ElVal->GetOffset(), SEEK_SET); + fseek(fp, (long)Entry->GetOffset(), SEEK_SET); // the test was commented out to 'go inside' the SeQuences // we don't any longer skip them ! @@ -1168,15 +1232,15 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry * ElVal) if ( SkipLoad ) { - ElVal->SetLength(0); - ElVal->SetValue("gdcm::Skipped"); + Entry->SetLength(0); + Entry->SetValue("gdcm::Skipped"); return; } // When the length is zero things are easy: if ( length == 0 ) { - ElVal->SetValue(""); + Entry->SetValue(""); return; } @@ -1187,10 +1251,10 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry * ElVal) { std::ostringstream s; s << "gdcm::NotLoaded."; - s << " Address:" << (long)ElVal->GetOffset(); - s << " Length:" << ElVal->GetLength(); - s << " x(" << std::hex << ElVal->GetLength() << ")"; - ElVal->SetValue(s.str()); + s << " Address:" << (long)Entry->GetOffset(); + s << " Length:" << Entry->GetLength(); + s << " x(" << std::hex << Entry->GetLength() << ")"; + Entry->SetValue(s.str()); return; } @@ -1201,12 +1265,12 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry * ElVal) // contain a set of integers (not a single one) // Any compacter code suggested (?) - if ( IsHeaderEntryAnInteger(ElVal) ) + if ( IsHeaderEntryAnInteger(Entry) ) { guint32 NewInt; std::ostringstream s; int nbInt; - if (vr == "US" || vr == "SS") + if (vr == "US" || vr == "SS") { nbInt = length / 2; NewInt = ReadInt16(); @@ -1221,7 +1285,7 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry * ElVal) } } - } + } else if (vr == "UL" || vr == "SL") { nbInt = length / 4; @@ -1236,33 +1300,28 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry * ElVal) s << NewInt; } } - } + } #ifdef GDCM_NO_ANSI_STRING_STREAM s << std::ends; // to avoid oddities on Solaris #endif //GDCM_NO_ANSI_STRING_STREAM - ElVal->SetValue(s.str()); + Entry->SetValue(s.str()); return; } // We need an additional byte for storing \0 that is not on disk - char* NewValue = (char*)malloc(length+1); - if( !NewValue) - { - dbg.Verbose(1, "LoadElementValue: Failed to allocate NewValue"); - return; - } - NewValue[length]= 0; - - item_read = fread(NewValue, (size_t)length, (size_t)1, fp); + std::string NewValue(length,0); + item_read = fread(&(NewValue[0]), (size_t)length, (size_t)1, fp); if ( item_read != 1 ) { - free(NewValue); dbg.Verbose(1, "gdcmParser::LoadElementValue","unread element value"); - ElVal->SetValue("gdcm::UnRead"); + Entry->SetValue("gdcm::UnRead"); return; } - ElVal->SetValue(NewValue); - free(NewValue); + + if( (vr == "UI") ) // Because of correspondance with the VR dic + Entry->SetValue(NewValue.c_str()); + else + Entry->SetValue(NewValue); } /** @@ -1274,7 +1333,7 @@ void gdcmParser::LoadHeaderEntry(gdcmHeaderEntry * ElVal) * \ when position to be taken care of * @param newHeaderEntry */ -void gdcmParser::AddHeaderEntry(gdcmHeaderEntry * newHeaderEntry) +void gdcmParser::AddHeaderEntry(gdcmHeaderEntry *newHeaderEntry) { tagHT.insert( PairHT( newHeaderEntry->GetKey(),newHeaderEntry) ); listEntries.push_back(newHeaderEntry); @@ -1284,15 +1343,15 @@ void gdcmParser::AddHeaderEntry(gdcmHeaderEntry * newHeaderEntry) /** * \ingroup gdcmParser * \brief - * @param ElVal : Header Entry whose length of the value shall be loaded. + * @param Entry Header Entry whose length of the value shall be loaded. * @return */ - void gdcmParser::FindHeaderEntryLength (gdcmHeaderEntry * ElVal) + void gdcmParser::FindHeaderEntryLength (gdcmHeaderEntry *Entry) { - guint16 element = ElVal->GetElement(); - guint16 group = ElVal->GetGroup(); - std::string vr = ElVal->GetVR(); + guint16 element = Entry->GetElement(); + guint16 group = Entry->GetGroup(); + std::string vr = Entry->GetVR(); guint16 length16; if( (element == 0x0010) && (group == 0x7fe0) ) { @@ -1301,7 +1360,7 @@ void gdcmParser::AddHeaderEntry(gdcmHeaderEntry * newHeaderEntry) "we reached 7fe0 0010"); } - if ( (filetype == ExplicitVR) && ! ElVal->IsImplicitVr() ) + if ( (filetype == ExplicitVR) && (! Entry->IsImplicitVR()) ) { if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") ) { @@ -1313,10 +1372,10 @@ void gdcmParser::AddHeaderEntry(gdcmHeaderEntry * newHeaderEntry) if ( (vr == "OB") && (length32 == 0xffffffff) ) { - ElVal->SetLength(FindHeaderEntryLengthOB()); + Entry->SetLength(FindHeaderEntryLengthOB()); return; } - FixHeaderEntryFoundLength(ElVal, length32); + FixHeaderEntryFoundLength(Entry, length32); return; } @@ -1362,18 +1421,18 @@ void gdcmParser::AddHeaderEntry(gdcmHeaderEntry * newHeaderEntry) SwitchSwapToBigEndian(); // Restore the unproperly loaded values i.e. the group, the element // and the dictionary entry depending on them. - guint16 CorrectGroup = SwapShort(ElVal->GetGroup()); - guint16 CorrectElem = SwapShort(ElVal->GetElement()); + 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 = Dicts->NewVirtualDictEntry(CorrectGroup, CorrectElem); + NewTag = NewVirtualDictEntry(CorrectGroup, CorrectElem); } // FIXME this can create a memory leaks on the old entry that be // left unreferenced. - ElVal->SetDictEntry(NewTag); + Entry->SetDictEntry(NewTag); } // Heuristic: well some files are really ill-formed. @@ -1386,34 +1445,34 @@ void gdcmParser::AddHeaderEntry(gdcmHeaderEntry * newHeaderEntry) // Unknown Sequence Length } - FixHeaderEntryFoundLength(ElVal, (guint32)length16); + FixHeaderEntryFoundLength(Entry, (guint32)length16); + return; + } + else + { + // Either implicit VR or a non DICOM conformal (see not 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; } - - // Either implicit VR or a non DICOM conformal (see not 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(ElVal, ReadInt32()); - return; } /** * \ingroup gdcmParser * \brief Find the Value Representation of the current Dicom Element. - * @param ElVal + * @param Entry */ -void gdcmParser::FindHeaderEntryVR( gdcmHeaderEntry *ElVal) +void gdcmParser::FindHeaderEntryVR( gdcmHeaderEntry *Entry) { if (filetype != ExplicitVR) return; char VR[3]; - std::string vr; int lgrLue; - char msg[100]; // for sprintf. Sorry long PositionOnEntry = ftell(fp); // Warning: we believe this is explicit VR (Value Representation) because @@ -1423,12 +1482,38 @@ void gdcmParser::FindHeaderEntryVR( gdcmHeaderEntry *ElVal) // 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. - bool RealExplicit = true; lgrLue=fread (&VR, (size_t)2,(size_t)1, fp); VR[2]=0; - vr = std::string(VR); - + if(!CheckHeaderEntryVR(Entry,VR)) + { + fseek(fp, PositionOnEntry, SEEK_SET); + // When this element is known in the dictionary we shall use, e.g. for + // the semantics (see the usage of IsAnInteger), the VR proposed by the + // dictionary entry. Still we have to flag the element as implicit since + // we know now our assumption on expliciteness is not furfilled. + // avoid . + if ( Entry->IsVRUnknown() ) + Entry->SetVR("Implicit"); + Entry->SetImplicitVR(); + } +} + +/** + * \ingroup gdcmParser + * \brief Check the correspondance between the VR of the header entry + * and the taken VR. If they are different, the header entry is + * updated with the new VR. + * @param Entry + * @param VR + * @return false if the VR is incorrect of if the VR isn't referenced + * otherwise, it returns true +*/ +bool gdcmParser::CheckHeaderEntryVR(gdcmHeaderEntry *Entry, VRKey vr) +{ + char msg[100]; // for sprintf + bool RealExplicit = true; + // Assume we are reading a falsely explicit VR file i.e. we reached // a tag where we expect reading a VR but are in fact we read the // first to bytes of the length. Then we will interogate (through find) @@ -1437,68 +1522,165 @@ void gdcmParser::FindHeaderEntryVR( gdcmHeaderEntry *ElVal) // expected VR read happens to be non-ascii characters we consider // we hit falsely explicit VR tag. - if ( (!isalpha(VR[0])) && (!isalpha(VR[1])) ) + if ( (!isalpha(vr[0])) && (!isalpha(vr[1])) ) RealExplicit = false; // CLEANME searching the dicom_vr at each occurence is expensive. // PostPone this test in an optional integrity check at the end // of parsing or only in debug mode. - if ( RealExplicit && !dicom_vr->Count(vr) ) + if ( RealExplicit && !gdcmGlobal::GetVR()->Count(vr) ) RealExplicit= false; - if ( RealExplicit ) + if ( !RealExplicit ) + { + // We thought this was explicit VR, but we end up with an + // implicit VR tag. Let's backtrack. + sprintf(msg,"Falsely explicit vr file (%04x,%04x)\n", + Entry->GetGroup(),Entry->GetElement()); + dbg.Verbose(1, "gdcmParser::FindVR: ",msg); + + return(false); + } + + if ( Entry->IsVRUnknown() ) + { + // When not a dictionary entry, we can safely overwrite the VR. + Entry->SetVR(vr); + } + else if ( Entry->GetVR() != vr ) { - if ( ElVal->IsVRUnknown() ) - { - // When not a dictionary entry, we can safely overwrite the VR. - ElVal->SetVR(vr); - return; - } - if ( ElVal->GetVR() == vr ) - { - // The VR we just read and the dictionary agree. Nothing to do. - return; - } // The VR present in the file and the dictionary disagree. We assume // the file writer knew best and use the VR of the file. Since it would // be unwise to overwrite the VR of a dictionary (since it would // compromise it's next user), we need to clone the actual DictEntry // and change the VR for the read one. - gdcmDictEntry* NewTag = Dicts->NewVirtualDictEntry(ElVal->GetGroup(), - ElVal->GetElement(), - vr, - "FIXME", - ElVal->GetName()); - ElVal->SetDictEntry(NewTag); - return; + gdcmDictEntry* NewEntry = NewVirtualDictEntry( + Entry->GetGroup(),Entry->GetElement(), + vr,"FIXME",Entry->GetName()); + Entry->SetDictEntry(NewEntry); } - - // We thought this was explicit VR, but we end up with an - // implicit VR tag. Let's backtrack. - - sprintf(msg,"Falsely explicit vr file (%04x,%04x)\n", - ElVal->GetGroup(),ElVal->GetElement()); - dbg.Verbose(1, "gdcmParser::FindVR: ",msg); - - fseek(fp, PositionOnEntry, SEEK_SET); - // When this element is known in the dictionary we shall use, e.g. for - // the semantics (see the usage of IsAnInteger), the VR proposed by the - // dictionary entry. Still we have to flag the element as implicit since - // we know now our assumption on expliciteness is not furfilled. - // avoid . - if ( ElVal->IsVRUnknown() ) - ElVal->SetVR("Implicit"); - ElVal->SetImplicitVr(); + return(true); } /** * \ingroup gdcmParser - * \brief Skip a given Header Entry + * \brief Get the transformed value of the header entry. The VR value + * is used to define the transformation to operate on the value * \warning NOT end user intended method ! - * @param entry - * @return + * @param Entry + * @return Transformed entry value + */ +std::string gdcmParser::GetHeaderEntryValue(gdcmHeaderEntry *Entry) +{ + if ( (IsHeaderEntryAnInteger(Entry)) && (Entry->IsImplicitVR()) ) + { + std::string val=Entry->GetValue(); + std::string vr=Entry->GetVR(); + guint32 length = Entry->GetLength(); + std::ostringstream s; + int nbInt; + + if (vr == "US" || vr == "SS") + { + guint16 NewInt16; + + nbInt = length / 2; + for (int i=0; i < nbInt; i++) + { + if(i!=0) + s << '\\'; + NewInt16 = (val[2*i+0]&0xFF)+((val[2*i+1]&0xFF)<<8); + NewInt16 = SwapShort(NewInt16); + s << NewInt16; + } + } + + else if (vr == "UL" || vr == "SL") + { + guint32 NewInt32; + + nbInt = length / 4; + for (int i=0; i < nbInt; i++) + { + if(i!=0) + s << '\\'; + NewInt32= (val[4*i+0]&0xFF)+((val[4*i+1]&0xFF)<<8)+ + ((val[4*i+2]&0xFF)<<16)+((val[4*i+3]&0xFF)<<24); + NewInt32=SwapLong(NewInt32); + s << NewInt32; + } + } + +#ifdef GDCM_NO_ANSI_STRING_STREAM + s << std::ends; // to avoid oddities on Solaris +#endif //GDCM_NO_ANSI_STRING_STREAM + return(s.str()); + } + + return(Entry->GetValue()); +} + +/** + * \ingroup gdcmParser + * \brief Get the reverse transformed value of the header entry. The VR + * value is used to define the reverse transformation to operate on + * the value + * \warning NOT end user intended method ! + * @param Entry + * @return Reverse transformed entry value + */ +std::string gdcmParser::GetHeaderEntryUnvalue(gdcmHeaderEntry *Entry) +{ + if ( (IsHeaderEntryAnInteger(Entry)) && (Entry->IsImplicitVR()) ) + { + std::string vr=Entry->GetVR(); + std::ostringstream s; + std::vector tokens; + + if (vr == "US" || vr == "SS") + { + guint16 NewInt16; + + tokens.erase(tokens.begin(),tokens.end()); // clean any previous value + Tokenize (Entry->GetValue(), tokens, "\\"); + for (unsigned int i=0; i>8)&0xFF); + } + tokens.clear(); + } + if (vr == "UL" || vr == "SL") + { + guint32 NewInt32; + + tokens.erase(tokens.begin(),tokens.end()); // clean any previous value + Tokenize (Entry->GetValue(), tokens, "\\"); + for (unsigned int i=0; i>8)&0xFF) + <<(char)((NewInt32>>16)&0xFF)<<(char)((NewInt32>>24)&0xFF); + } + tokens.clear(); + } + +#ifdef GDCM_NO_ANSI_STRING_STREAM + s << std::ends; // to avoid oddities on Solaris +#endif //GDCM_NO_ANSI_STRING_STREAM + return(s.str()); + } + + return(Entry->GetValue()); +} + +/** + * \ingroup gdcmParser + * \brief Skip a given Header Entry + * \warning NOT end user intended method ! + * @param entry */ -void gdcmParser::SkipHeaderEntry(gdcmHeaderEntry * entry) +void gdcmParser::SkipHeaderEntry(gdcmHeaderEntry *entry) { SkipBytes(entry->GetLength()); } @@ -1509,9 +1691,9 @@ void gdcmParser::SkipHeaderEntry(gdcmHeaderEntry * entry) * the parser went Jabberwocky) one can hope improving things by * applying this heuristic. */ -void gdcmParser::FixHeaderEntryFoundLength(gdcmHeaderEntry * ElVal, guint32 FoundLength) +void gdcmParser::FixHeaderEntryFoundLength(gdcmHeaderEntry *Entry, guint32 FoundLength) { - ElVal->SetReadLength(FoundLength); // will be updated only if a bug is found + Entry->SetReadLength(FoundLength); // will be updated only if a bug is found if ( FoundLength == 0xffffffff) { @@ -1524,26 +1706,26 @@ void gdcmParser::FixHeaderEntryFoundLength(gdcmHeaderEntry * ElVal, guint32 Foun { // The following 'if' will be removed when there is no more // images on Creatis HDs with a 13 length for Manufacturer... - if ( (ElVal->GetGroup() != 0x0008) || - ( (ElVal->GetElement() != 0x0070) && (ElVal->GetElement() != 0x0080) ) ) { + if ( (Entry->GetGroup() != 0x0008) || + ( (Entry->GetElement() != 0x0070) && (Entry->GetElement() != 0x0080) ) ) { // end of remove area FoundLength =10; - ElVal->SetReadLength(10); // a bug is to be fixed + Entry->SetReadLength(10); // a bug is to be fixed } } // to fix some garbage 'Leonardo' Siemens images // May be commented out to avoid overhead - else if ( (ElVal->GetGroup() == 0x0009) && - ( (ElVal->GetElement() == 0x1113) || (ElVal->GetElement() == 0x1114) ) ) + else if ( (Entry->GetGroup() == 0x0009) && + ( (Entry->GetElement() == 0x1113) || (Entry->GetElement() == 0x1114) ) ) { FoundLength =4; - ElVal->SetReadLength(4); // a bug is to be fixed + Entry->SetReadLength(4); // a bug is to be fixed } // end of fix // to try to 'go inside' SeQuences (with length), and not to skip them - else if ( ElVal->GetVR() == "SQ") + else if ( Entry->GetVR() == "SQ") { if (enableSequences) // only if the user does want to ! FoundLength =0; @@ -1558,7 +1740,7 @@ void gdcmParser::FixHeaderEntryFoundLength(gdcmHeaderEntry * ElVal, guint32 Foun // if we set the length to zero IsHeaderEntryAnInteger() breaks... // if we don't, we lost 28800 characters from the Header :-( - else if(ElVal->GetGroup() == 0xfffe) + else if(Entry->GetGroup() == 0xfffe) { // sometimes, length seems to be wrong FoundLength =0; // some more clever checking to be done ! @@ -1567,22 +1749,22 @@ void gdcmParser::FixHeaderEntryFoundLength(gdcmHeaderEntry * ElVal, guint32 Foun // causes troubles :-( } - ElVal->SetUsableLength(FoundLength); + Entry->SetUsableLength(FoundLength); } /** * \ingroup gdcmParser * \brief Apply some heuristics to predict wether the considered * element value contains/represents an integer or not. - * @param ElVal The element value on which to apply the predicate. + * @param Entry The element value on which to apply the predicate. * @return The result of the heuristical predicate. */ -bool gdcmParser::IsHeaderEntryAnInteger(gdcmHeaderEntry * ElVal) +bool gdcmParser::IsHeaderEntryAnInteger(gdcmHeaderEntry *Entry) { - guint16 element = ElVal->GetElement(); - guint16 group = ElVal->GetGroup(); - std::string vr = ElVal->GetVR(); - guint32 length = ElVal->GetLength(); + guint16 element = Entry->GetElement(); + guint16 group = Entry->GetGroup(); + std::string vr = Entry->GetVR(); + guint32 length = Entry->GetLength(); // When we have some semantics on the element we just read, and if we // a priori know we are dealing with an integer, then we shall be @@ -1724,10 +1906,7 @@ void gdcmParser::SkipBytes(guint32 NBytes) */ void gdcmParser::Initialise(void) { - dicom_vr = gdcmGlobal::GetVR(); - dicom_ts = gdcmGlobal::GetTS(); - Dicts = gdcmGlobal::GetDicts(); - RefPubDict = Dicts->GetDefaultPubDict(); + RefPubDict = gdcmGlobal::GetDicts()->GetDefaultPubDict(); RefShaDict = (gdcmDict*)0; } @@ -1975,13 +2154,13 @@ gdcmDictEntry *gdcmParser::GetDictEntryByName(std::string Name) } if (RefPubDict) { - found = RefPubDict->GetTagByName(Name); + found = RefPubDict->GetDictEntryByName(Name); if (found) return found; } if (RefShaDict) { - found = RefShaDict->GetTagByName(Name); + found = RefShaDict->GetDictEntryByName(Name); if (found) return found; } @@ -2008,13 +2187,13 @@ gdcmDictEntry *gdcmParser::GetDictEntryByNumber(guint16 group,guint16 element) } if (RefPubDict) { - found = RefPubDict->GetTagByNumber(group, element); + found = RefPubDict->GetDictEntryByNumber(group, element); if (found) return found; } if (RefShaDict) { - found = RefShaDict->GetTagByNumber(group, element); + found = RefShaDict->GetDictEntryByNumber(group, element); if (found) return found; } @@ -2029,7 +2208,7 @@ gdcmDictEntry *gdcmParser::GetDictEntryByNumber(guint16 group,guint16 element) gdcmHeaderEntry *gdcmParser::ReadNextHeaderEntry(void) { guint16 g,n; - gdcmHeaderEntry *NewElVal; + gdcmHeaderEntry *NewEntry; g = ReadInt16(); n = ReadInt16(); @@ -2039,18 +2218,18 @@ gdcmHeaderEntry *gdcmParser::ReadNextHeaderEntry(void) // has to be considered as finished. return (gdcmHeaderEntry *)0; - NewElVal = NewHeaderEntryByNumber(g, n); - FindHeaderEntryVR(NewElVal); - FindHeaderEntryLength(NewElVal); + NewEntry = NewHeaderEntryByNumber(g, n); + FindHeaderEntryVR(NewEntry); + FindHeaderEntryLength(NewEntry); if (errno == 1) { // Call it quits return NULL; } - NewElVal->SetOffset(ftell(fp)); + NewEntry->SetOffset(ftell(fp)); //if ( (g==0x7fe0) && (n==0x0010) ) - return NewElVal; + return NewEntry; } /** @@ -2064,18 +2243,35 @@ gdcmHeaderEntry *gdcmParser::NewHeaderEntryByName(std::string Name) { gdcmDictEntry *NewTag = GetDictEntryByName(Name); if (!NewTag) - NewTag = Dicts->NewVirtualDictEntry(0xffff, 0xffff, "LO", "Unknown", Name); + NewTag = NewVirtualDictEntry(0xffff, 0xffff, "LO", "Unknown", Name); - gdcmHeaderEntry* NewElVal = new gdcmHeaderEntry(NewTag); - if (!NewElVal) + gdcmHeaderEntry* NewEntry = new gdcmHeaderEntry(NewTag); + if (!NewEntry) { dbg.Verbose(1, "gdcmParser::ObtainHeaderEntryByName", "failed to allocate gdcmHeaderEntry"); return (gdcmHeaderEntry *)0; } - return NewElVal; + return NewEntry; } +/** + * \ingroup gdcmParser + * \brief Request a new virtual dict entry to the dict set + * @param group group of the underlying DictEntry + * @param elem element of the underlying DictEntry + * @param vr VR of the underlying DictEntry + * @param fourth owner group + * @param name english name + */ +gdcmDictEntry *gdcmParser::NewVirtualDictEntry(guint16 group, guint16 element, + std::string vr, + std::string fourth, + std::string name) +{ + return gdcmGlobal::GetDicts()->NewVirtualDictEntry(group,element,vr,fourth,name); +} + /** * \ingroup gdcmParser * \brief Build a new Element Value from all the low level arguments. @@ -2087,18 +2283,18 @@ gdcmHeaderEntry *gdcmParser::NewHeaderEntryByName(std::string Name) gdcmHeaderEntry *gdcmParser::NewHeaderEntryByNumber(guint16 Group, guint16 Elem) { // Find out if the tag we encountered is in the dictionaries: - gdcmDictEntry *NewTag = GetDictEntryByNumber(Group, Elem); - if (!NewTag) - NewTag = Dicts->NewVirtualDictEntry(Group, Elem); + gdcmDictEntry *DictEntry = GetDictEntryByNumber(Group, Elem); + if (!DictEntry) + DictEntry = NewVirtualDictEntry(Group, Elem); - gdcmHeaderEntry* NewElVal = new gdcmHeaderEntry(NewTag); - if (!NewElVal) + gdcmHeaderEntry *NewEntry = new gdcmHeaderEntry(DictEntry); + if (!NewEntry) { dbg.Verbose(1, "gdcmParser::NewHeaderEntryByNumber", "failed to allocate gdcmHeaderEntry"); return NULL; } - return NewElVal; + return NewEntry; } /** @@ -2114,24 +2310,24 @@ gdcmHeaderEntry *gdcmParser::NewHeaderEntryByNumber(guint16 Group, guint16 Elem) gdcmHeaderEntry *gdcmParser::NewManualHeaderEntryToPubDict(std::string NewTagName, std::string VR) { - gdcmHeaderEntry *NewElVal = (gdcmHeaderEntry *)0; + gdcmHeaderEntry *NewEntry = NULL; guint32 StuffGroup = 0xffff; // Group to be stuffed with additional info guint32 FreeElem = 0; - gdcmDictEntry *NewEntry = (gdcmDictEntry *)0; + gdcmDictEntry *DictEntry = NULL; FreeElem = GenerateFreeTagKeyInGroup(StuffGroup); if (FreeElem == UINT32_MAX) { - dbg.Verbose(1, "gdcmHeader::NewManualElValToPubDict", + dbg.Verbose(1, "gdcmHeader::NewManualHeaderEntryToPubDict", "Group 0xffff in Public Dict is full"); return NULL; } - NewEntry = Dicts->NewVirtualDictEntry(StuffGroup, FreeElem, + DictEntry = NewVirtualDictEntry(StuffGroup, FreeElem, VR, "GDCM", NewTagName); - NewElVal = new gdcmHeaderEntry(NewEntry); - AddHeaderEntry(NewElVal); - return NewElVal; + NewEntry = new gdcmHeaderEntry(DictEntry); + AddHeaderEntry(NewEntry); + return NewEntry; } /**