/* * * Copyright (C) 2015-2019, Open Connections GmbH * All rights reserved. See COPYRIGHT file for details. * * This software and supporting documentation are maintained by * * OFFIS e.V. * R&D Division Health * Escherweg 2 * D-26121 Oldenburg, Germany * * * Module: dcmiod * * Author: Michael Onken * * Purpose: Class for managing the Common Instance Reference Module * */ #include "dcmtk/dcmiod/modcommoninstanceref.h" #include "dcmtk/config/osconfig.h" #include "dcmtk/dcmiod/iodutil.h" // for static helpers const OFString IODCommonInstanceReferenceModule::m_ComponentName = "CommonInstanceReferenceModule"; const OFString IODCommonInstanceReferenceModule::StudiesOtherInstancesItem::m_ComponentName = "StudiesContainingOtherReferencedInstancesSequence"; IODCommonInstanceReferenceModule::IODCommonInstanceReferenceModule(OFshared_ptr item, OFshared_ptr rules) : IODModule(item, rules) , m_ReferenceSeriesItems() , m_StudiesContainingOtherReferencedInstancesSequence() { resetRules(); } IODCommonInstanceReferenceModule::IODCommonInstanceReferenceModule() : IODModule() , m_ReferenceSeriesItems() , m_StudiesContainingOtherReferencedInstancesSequence() { resetRules(); } IODCommonInstanceReferenceModule::~IODCommonInstanceReferenceModule() { freeMemory(); } OFString IODCommonInstanceReferenceModule::getName() const { return m_ComponentName; } OFVector& IODCommonInstanceReferenceModule::getReferencedSeriesItems() { return m_ReferenceSeriesItems; } OFVector& IODCommonInstanceReferenceModule::getStudiesContainingOtherReferences() { return m_StudiesContainingOtherReferencedInstancesSequence; } void IODCommonInstanceReferenceModule::clearData() { freeMemory(); } OFCondition IODCommonInstanceReferenceModule::read(DcmItem& source, const OFBool clearOldData) { if (clearOldData) clearData(); DcmIODUtil::readSubSequence( source, DCM_ReferencedSeriesSequence, m_ReferenceSeriesItems, m_Rules->getByTag(DCM_ReferencedSeriesSequence)); DcmIODUtil::readSubSequence(source, DCM_StudiesContainingOtherReferencedInstancesSequence, m_StudiesContainingOtherReferencedInstancesSequence, m_Rules->getByTag(DCM_StudiesContainingOtherReferencedInstancesSequence)); return EC_Normal; } OFCondition IODCommonInstanceReferenceModule::write(DcmItem& destination) { OFCondition result = EC_Normal; DcmIODUtil::writeSubSequence >( result, DCM_ReferencedSeriesSequence, m_ReferenceSeriesItems, *m_Item, m_Rules->getByTag(DCM_ReferencedSeriesSequence)); DcmIODUtil::writeSubSequence >( result, DCM_StudiesContainingOtherReferencedInstancesSequence, m_StudiesContainingOtherReferencedInstancesSequence, *m_Item, m_Rules->getByTag(DCM_StudiesContainingOtherReferencedInstancesSequence)); if (result.good()) result = IODModule::write(destination); return result; } size_t IODCommonInstanceReferenceModule::addReferences(const IODReferences& references, const OFString& studyInstanceUID, const OFBool clearOldData) { if (clearOldData) { clearData(); } OFString ourStudy = studyInstanceUID; if (ourStudy.empty()) { m_Item->findAndGetOFString(DCM_StudyInstanceUID, ourStudy); if (ourStudy.empty()) { DCMIOD_ERROR("Could not add references: No Study Instance UID specified for \"this\" object"); return 0; } } const OFVector refs = references.get(); OFVector::const_iterator ref = refs.begin(); size_t count = 0; while (ref != refs.end()) { OFCondition result; // If reference belongs into "this" study, add it to Referenced Series Sequence OFString refStudy = (*ref)->m_StudyInstanceUID; if (refStudy == ourStudy) { result = addSeriesReference(m_ReferenceSeriesItems, **ref); } else { // Reference lies outside of "this" study, put it into Studies Containing // Other Referenced Instances Sequence OFVector::iterator it = m_StudiesContainingOtherReferencedInstancesSequence.begin(); while (it != m_StudiesContainingOtherReferencedInstancesSequence.end()) { OFString studyEntry; (*it)->getStudyInstanceUID(studyEntry); if (studyEntry == refStudy) { result = addSeriesReference( (*it)->getReferencedSeriesAndInstanceReferences().getReferencedSeriesItems(), **ref); break; } else { it++; } } // We did not find an entry for this study, add new one if (it == m_StudiesContainingOtherReferencedInstancesSequence.end()) { StudiesOtherInstancesItem* newItem = new StudiesOtherInstancesItem(); if (newItem) { result = newItem->setStudyInstanceUID(refStudy); if (result.good()) { result = addSeriesReference( newItem->getReferencedSeriesAndInstanceReferences().getReferencedSeriesItems(), **ref); } if (result.good()) { m_StudiesContainingOtherReferencedInstancesSequence.push_back(newItem); } else { delete newItem; } } else { DCMIOD_ERROR("Memory exhausted while adding references to Common Instance Reference Module"); return count; } } } if (result.good()) { count++; } ref++; } return count; } void IODCommonInstanceReferenceModule::resetRules() { // Parameters for Rule are tag, VM, type (1,1C,2,2C,3), module name and logical IOD level m_Rules->addRule(new IODRule(DCM_ReferencedSeriesSequence, "1-n", "1C", getName(), DcmIODTypes::IE_INSTANCE), OFTrue); m_Rules->addRule( new IODRule( DCM_StudiesContainingOtherReferencedInstancesSequence, "1-n", "1C", getName(), DcmIODTypes::IE_INSTANCE), OFTrue); } OFCondition IODCommonInstanceReferenceModule::addSeriesReference( OFVector& container, const IODReference& ref) { OFCondition result; OFVector::iterator series = container.begin(); while (series != container.end()) { OFString s; (*series)->getSeriesInstanceUID(s); if (s == ref.m_SeriesInstanceUID) { // There is already an entry for this series result = (*series)->addReference(ref.m_SOPClassUID, ref.m_SOPInstanceUID); if (result.good()) { return EC_Normal; } else { DCMIOD_ERROR("Could not add reference to Common Instance Reference Module: " << ref.toString()); return IOD_EC_InvalidElementValue; } } series++; } // If we do not have such a series Referenced Series Sequence, add it if (series == container.end()) { IODSeriesAndInstanceReferenceMacro::ReferencedSeriesItem* newseries = new IODSeriesAndInstanceReferenceMacro::ReferencedSeriesItem(); if (!newseries) { return EC_MemoryExhausted; } result = newseries->setSeriesInstanceUID(ref.m_SeriesInstanceUID); if (result.good()) result = newseries->addReference(ref.m_SOPClassUID, ref.m_SOPInstanceUID); if (result.good()) { container.push_back(newseries); } else { DCMIOD_ERROR("Could not add reference to Common Instance Reference Module: " << ref.toString()); } } return result; } // -- IODCommonInstanceReferenceModule::StudiesOtherInstancesItem -- IODCommonInstanceReferenceModule::StudiesOtherInstancesItem::StudiesOtherInstancesItem(OFshared_ptr item, OFshared_ptr rules, IODComponent* parent) : IODComponent(item, rules, parent) , m_ReferencedSeriesAndInstance() { // reset element rules resetRules(); } IODCommonInstanceReferenceModule::StudiesOtherInstancesItem::StudiesOtherInstancesItem(IODComponent* parent) : IODComponent(parent) , m_ReferencedSeriesAndInstance() { // reset element rules resetRules(); } IODCommonInstanceReferenceModule::StudiesOtherInstancesItem::~StudiesOtherInstancesItem() { clearData(); } OFString IODCommonInstanceReferenceModule::StudiesOtherInstancesItem::getName() const { return m_ComponentName; } void IODCommonInstanceReferenceModule::StudiesOtherInstancesItem::clearData() { m_ReferencedSeriesAndInstance.clearData(); IODComponent::clearData(); } OFCondition IODCommonInstanceReferenceModule::StudiesOtherInstancesItem::read(DcmItem& source, const OFBool clearOldData) { if (clearOldData) clearData(); IODComponent::read(source, clearOldData); m_ReferencedSeriesAndInstance.read(source, clearOldData); return EC_Normal; } OFCondition IODCommonInstanceReferenceModule::StudiesOtherInstancesItem::write(DcmItem& destination) { OFCondition result = EC_Normal; result = IODComponent::write(destination); if (result.good()) result = m_ReferencedSeriesAndInstance.write(destination); return result; } void IODCommonInstanceReferenceModule::StudiesOtherInstancesItem::resetRules() { // Parameters for Rule are tag, VM, type (1,1C,2,2C,3), module name and logical IOD level m_Rules->addRule(new IODRule(DCM_StudyInstanceUID, "1", "1", getName(), DcmIODTypes::IE_INSTANCE), OFTrue); } IODSeriesAndInstanceReferenceMacro& IODCommonInstanceReferenceModule::StudiesOtherInstancesItem::getReferencedSeriesAndInstanceReferences() { return m_ReferencedSeriesAndInstance; } OFCondition IODCommonInstanceReferenceModule::StudiesOtherInstancesItem::getStudyInstanceUID(OFString& value, const long signed int pos) const { return DcmIODUtil::getStringValueFromItem(DCM_StudyInstanceUID, *m_Item, value, pos); } OFCondition IODCommonInstanceReferenceModule::StudiesOtherInstancesItem::setStudyInstanceUID(const OFString& value, const OFBool checkValue) { OFCondition result = (checkValue) ? DcmUniqueIdentifier::checkStringValue(value, "1") : EC_Normal; if (result.good()) result = m_Item->putAndInsertOFStringArray(DCM_StudyInstanceUID, value); return result; } void IODCommonInstanceReferenceModule::freeMemory() { DcmIODUtil::freeContainer(m_StudiesContainingOtherReferencedInstancesSequence); DcmIODUtil::freeContainer(m_ReferenceSeriesItems); }