From abb31eef516af593c448f2742b7e8de8735921e0 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Tue, 24 Aug 2021 13:08:19 +0200 Subject: [PATCH] Provide a new API for DcmItem to delete a private attribute Extend DcmItem with findAndDeletePrivateElement to allow user to delete a private tag directly (reservation number is computed internally). --- dcmdata/include/dcmtk/dcmdata/dcitem.h | 13 +++++++++ dcmdata/libsrc/dcitem.cc | 40 ++++++++++++++++++++++++++ dcmdata/tests/tests.cc | 1 + dcmdata/tests/titem.cc | 24 ++++++++++++++++ 4 files changed, 78 insertions(+) diff --git a/dcmdata/include/dcmtk/dcmdata/dcitem.h b/dcmdata/include/dcmtk/dcmdata/dcitem.h index fff90d86b..2e8719685 100644 --- a/dcmdata/include/dcmtk/dcmdata/dcitem.h +++ b/dcmdata/include/dcmtk/dcmdata/dcitem.h @@ -1043,6 +1043,19 @@ class DCMTK_DCMDATA_EXPORT DcmItem const OFBool allOccurrences = OFFalse, const OFBool searchIntoSub = OFFalse); + /** find private element, remove it from the dataset and free the associated memory. + * Applicable to all DICOM value representations (VR). + * @param tag DICOM tag specifying the private attribute to be searched for + * @param allOccurrences flag indicating whether to delete all occurrences of the + * attribute tag or the first one only (implies 'searchIntoSub' to be true) + * @param searchIntoSub flag indicating whether to search into sequences or not + * @return EC_Normal upon success, an error code otherwise. + */ + OFCondition findAndDeletePrivateElement(const DcmTag &tag, + const OFBool allOccurrences = OFFalse, + const OFBool searchIntoSub = OFFalse); + + /** looks up the given sequence in the current dataset and deletes the given item. * Applicable to the following VRs: SQ, (pixelSQ). * @param seqTagKey DICOM tag specifying the sequence attribute to be searched for diff --git a/dcmdata/libsrc/dcitem.cc b/dcmdata/libsrc/dcitem.cc index 13de2ed60..e526bcd7c 100644 --- a/dcmdata/libsrc/dcitem.cc +++ b/dcmdata/libsrc/dcitem.cc @@ -3202,6 +3202,46 @@ OFCondition DcmItem::findAndDeleteElement(const DcmTagKey &tagKey, return status; } +OFCondition DcmItem::findAndDeletePrivateElement(const DcmTag &privTag, + const OFBool allOccurrences, + const OFBool searchIntoSub) +{ + OFCondition status = EC_TagNotFound; + DcmStack stack; + DcmObject *object = NULL; + OFBool intoSub = OFTrue; + /* make sure private tag */ + if( !privTag.isPrivate() || privTag.getPrivateCreator() == NULL || privTag.getElement() >= 0x1000) + return status; + DcmTagKey curTag; + /* iterate over all elements */ + while (nextObject(stack, intoSub).good()) + { + /* get element */ + object = stack.top(); + curTag = object->getTag(); + if (curTag.getGroup() == privTag.getGroup() && (curTag.getElement() > 0 && curTag.getElement() <= 0xff)) { + DcmElement *elem; + elem = OFstatic_cast(DcmElement *, stack.top()); + OFString value; + if (elem->getOFStringArray(value).good()) { + if (value.compare(privTag.getPrivateCreator()) == 0) { + const Uint16 actualElement = OFstatic_cast( + Uint16, (curTag.getElement() << 8) | privTag.getElement()); + const DcmTagKey tagKey(curTag.getGroup(), actualElement); + status = findAndDeleteElement(tagKey, allOccurrences, searchIntoSub); + /* delete only the first element? */ + if (!allOccurrences) + break; + } + } + } + intoSub = searchIntoSub || allOccurrences; + } + return status; +} + + OFCondition DcmItem::findAndDeleteSequenceItem(const DcmTagKey &seqTagKey, const signed long itemNum) diff --git a/dcmdata/tests/tests.cc b/dcmdata/tests/tests.cc index 08fb38a44..585bc431d 100644 --- a/dcmdata/tests/tests.cc +++ b/dcmdata/tests/tests.cc @@ -95,6 +95,7 @@ OFTEST_REGISTER(dcmdata_sequenceInsert); OFTEST_REGISTER(dcmdata_pixelSequenceInsert); OFTEST_REGISTER(dcmdata_findAndGetSequenceItem); OFTEST_REGISTER(dcmdata_findAndGetUint16Array); +OFTEST_REGISTER(dcmdata_findAndDeletePrivateElement); OFTEST_REGISTER(dcmdata_parser_missingDelimitationItems); OFTEST_REGISTER(dcmdata_parser_missingSequenceDelimitationItem_1); OFTEST_REGISTER(dcmdata_parser_missingSequenceDelimitationItem_2); diff --git a/dcmdata/tests/titem.cc b/dcmdata/tests/titem.cc index ecc65fed9..cf28d63de 100644 --- a/dcmdata/tests/titem.cc +++ b/dcmdata/tests/titem.cc @@ -26,6 +26,7 @@ #include "dcmtk/dcmdata/dcitem.h" #include "dcmtk/dcmdata/dcvrat.h" #include "dcmtk/dcmdata/dcvrus.h" +#include "dcmtk/dcmdata/dcvrlo.h" #include "dcmtk/dcmdata/dcdeftag.h" @@ -48,3 +49,26 @@ OFTEST(dcmdata_findAndGetUint16Array) OFCHECK(item.findAndGetUint16Array(DCM_FrameIncrementPointer, uintVals, &numUints).good()); OFCHECK_EQUAL(numUints, 2); } + +OFTEST(dcmdata_findAndDeletePrivateElement) +{ + DcmItem item; + const DcmTag privTag(0x0009,0x0042,"PRIVATE CREATOR"); + /* create data elements with values */ + const Uint16 reservationElem = 0x0070; + /* reservation */ + const DcmTagKey reservationTag(privTag.getGroup(), reservationElem); + DcmLongString loValue( reservationTag ); + loValue.putString(privTag.getPrivateCreator()); + item.insert(new DcmLongString(loValue)); + + /* actual private element */ + const DcmTagKey privTagKey( privTag.getGroup(), (reservationElem << 8) | privTag.getElement()); + DcmUnsignedShort usValue(privTagKey); + usValue.putString("1"); + item.insert(new DcmUnsignedShort(usValue)); + OFCHECK(item.tagExists (privTagKey)); + /* remove it */ + item.findAndDeletePrivateElement(privTag); + OFCHECK(!item.tagExists (privTagKey)); +}