/*
*
* Copyright (C) 2002-2016, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
*
* OFFIS e.V.
* R&D Division Health
* Escherweg 2
* D-26121 Oldenburg, Germany
*
*
* Module: dcmsr
*
* Author: Joerg Riesmeier
*
* Purpose:
* classes: DSRSOPInstanceReferenceList
* - InstanceStruct, SeriesStruct, StudyStruct
*
*/
#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
#include "dcmtk/dcmsr/dsrsoprf.h"
#include "dcmtk/dcmsr/dsrxmld.h"
#include "dcmtk/dcmdata/dcdeftag.h"
#include "dcmtk/dcmdata/dcuid.h"
#include "dcmtk/dcmdata/dcvrae.h"
#include "dcmtk/dcmdata/dcvrcs.h"
#include "dcmtk/dcmdata/dcvrsh.h"
#include "dcmtk/dcmdata/dcvrui.h"
// --- DSRSOPInstanceReferenceList::InstanceStruct ---
DSRSOPInstanceReferenceList::InstanceStruct::InstanceStruct(const OFString &sopClassUID,
const OFString &instanceUID)
: SOPClassUID(sopClassUID),
InstanceUID(instanceUID),
PurposeOfReference()
{
}
void DSRSOPInstanceReferenceList::InstanceStruct::clear()
{
PurposeOfReference.clear();
}
// --- DSRSOPInstanceReferenceList::SeriesStruct ---
DSRSOPInstanceReferenceList::SeriesStruct::SeriesStruct(const OFString &seriesUID)
: SeriesUID(seriesUID),
RetrieveAETitle(),
RetrieveLocationUID(),
StorageMediaFileSetID(),
StorageMediaFileSetUID(),
InstanceList(),
Iterator()
{
/* initialize list cursor */
Iterator = InstanceList.end();
}
DSRSOPInstanceReferenceList::SeriesStruct::~SeriesStruct()
{
Iterator = InstanceList.begin();
const OFListIterator(InstanceStruct *) last = InstanceList.end();
/* delete all items and free memory */
while (Iterator != last)
{
delete (*Iterator);
Iterator = InstanceList.erase(Iterator);
}
}
size_t DSRSOPInstanceReferenceList::SeriesStruct::getNumberOfInstances() const
{
return InstanceList.size();
}
OFCondition DSRSOPInstanceReferenceList::SeriesStruct::read(DcmItem &dataset,
const size_t flags)
{
/* first, read optional attributes on series level */
getAndCheckStringValueFromDataset(dataset, DCM_RetrieveAETitle, RetrieveAETitle, "1-n", "3", "ReferencedSeriesSequence");
getAndCheckStringValueFromDataset(dataset, DCM_RetrieveLocationUID, RetrieveLocationUID, "1", "3", "ReferencedSeriesSequence");
getAndCheckStringValueFromDataset(dataset, DCM_StorageMediaFileSetID, StorageMediaFileSetID, "1", "3", "ReferencedSeriesSequence");
getAndCheckStringValueFromDataset(dataset, DCM_StorageMediaFileSetUID, StorageMediaFileSetUID, "1", "3", "ReferencedSeriesSequence");
/* then, check whether sequence is present and non-empty */
DcmSequenceOfItems *sequence = NULL;
OFCondition result = dataset.findAndGetSequence(DCM_ReferencedSOPSequence, sequence);
checkElementValue(sequence, DCM_ReferencedSOPSequence, "1-n", "1", result);
if (result.good())
{
/* iterate over all sequence items */
DcmObject *object = NULL;
while ((object = sequence->nextInContainer(object)) != NULL)
{
DcmItem *item = OFstatic_cast(DcmItem *, object);
/* get the SOP class and SOP instance UID */
OFString sopClassUID, instanceUID;
if (getAndCheckStringValueFromDataset(*item, DCM_ReferencedSOPClassUID, sopClassUID, "1", "1", "ReferencedSOPSequence").good() &&
getAndCheckStringValueFromDataset(*item, DCM_ReferencedSOPInstanceUID, instanceUID, "1", "1", "ReferencedSOPSequence").good())
{
/* check whether instance item already exists */
InstanceStruct *instance = gotoInstance(instanceUID);
if (instance == NULL)
{
/* if not, create new instance list item */
instance = new InstanceStruct(sopClassUID, instanceUID);
if (instance != NULL)
{
/* add add it to the list of instances */
InstanceList.push_back(instance);
/* set cursor to new position */
Iterator = --InstanceList.end();
/* read additional information */
instance->PurposeOfReference.readSequence(*item, DCM_PurposeOfReferenceCodeSequence, "3", flags);
} else {
result = EC_MemoryExhausted;
break;
}
} else {
/* report a warning message and ignore this entry */
DCMSR_WARN("SOP Instance \"" << instanceUID << "\" already exists in reference list ... ignoring");
}
}
}
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::SeriesStruct::write(DcmItem &dataset) const
{
OFCondition result = EC_Normal;
/* store the series level attributes */
dataset.putAndInsertOFStringArray(DCM_SeriesInstanceUID, SeriesUID);
/* write optional attributes if non-empty */
if (!RetrieveAETitle.empty())
dataset.putAndInsertOFStringArray(DCM_RetrieveAETitle, RetrieveAETitle);
if (!RetrieveLocationUID.empty())
dataset.putAndInsertOFStringArray(DCM_RetrieveLocationUID, RetrieveLocationUID);
if (!StorageMediaFileSetID.empty())
dataset.putAndInsertOFStringArray(DCM_StorageMediaFileSetID, StorageMediaFileSetID);
if (!StorageMediaFileSetUID.empty())
dataset.putAndInsertOFStringArray(DCM_StorageMediaFileSetUID, StorageMediaFileSetUID);
/* iterate over all list items */
OFListConstIterator(InstanceStruct *) iter = InstanceList.begin();
const OFListConstIterator(InstanceStruct *) last = InstanceList.end();
while ((iter != last) && result.good())
{
InstanceStruct *instance = *iter;
/* check whether list item really exists */
if (instance != NULL)
{
DcmItem *item = NULL;
/* create a new item (and a sequence if required) */
result = dataset.findOrCreateSequenceItem(DCM_ReferencedSOPSequence, item, -2 /*append new*/);
if (result.good())
{
/* store the instance level attributes */
item->putAndInsertOFStringArray(DCM_ReferencedSOPClassUID, instance->SOPClassUID);
item->putAndInsertOFStringArray(DCM_ReferencedSOPInstanceUID, instance->InstanceUID);
if (!instance->PurposeOfReference.isEmpty()) // optional
instance->PurposeOfReference.writeSequence(*item, DCM_PurposeOfReferenceCodeSequence);
}
}
iter++;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::SeriesStruct::readXML(const DSRXMLDocument &doc,
DSRXMLCursor cursor,
const size_t flags)
{
OFCondition result = SR_EC_InvalidDocument;
if (cursor.valid())
{
/* first, read optional elements on series level */
doc.getStringFromNodeContent(doc.getNamedNode(cursor, "aetitle", OFFalse /*required*/), RetrieveAETitle);
doc.getStringFromAttribute(doc.getNamedNode(cursor, "location", OFFalse /*required*/), RetrieveLocationUID, "uid",
OFFalse /*encoding*/, OFFalse /*required*/);
const DSRXMLCursor childCursor = doc.getNamedNode(cursor, "fileset", OFFalse /*required*/);
if (childCursor.valid())
{
doc.getStringFromAttribute(childCursor, StorageMediaFileSetUID, "uid", OFFalse /*encoding*/, OFFalse /*required*/);
doc.getStringFromNodeContent(childCursor, StorageMediaFileSetID);
}
/* then proceed with instance level elements */
OFString sopClassUID, instanceUID;
do {
/* iterate over all "value" elements */
cursor = doc.getNamedNode(cursor, "value");
if (cursor.valid())
{
DSRXMLCursor instanceCursor = cursor.getChild();
if (!doc.getStringFromAttribute(doc.getNamedNode(instanceCursor, "sopclass"), sopClassUID, "uid").empty() &&
!doc.getStringFromAttribute(doc.getNamedNode(instanceCursor, "instance"), instanceUID, "uid").empty())
{
/* check whether instance item already exists,
because the internal structure is organized in a strictly hierarchical manner */
InstanceStruct *instance = gotoInstance(instanceUID);
if (instance == NULL)
{
/* if not, create a new instance list item */
instance = new InstanceStruct(sopClassUID, instanceUID);
if (instance != NULL)
{
/* and add it to the list of instances */
InstanceList.push_back(instance);
/* set cursor to new position */
Iterator = --InstanceList.end();
/* iterate over further child nodes */
while (instanceCursor.valid())
{
/* check for known element tags */
if (doc.matchNode(instanceCursor, "purpose"))
instance->PurposeOfReference.readXML(doc, instanceCursor, flags);
/* proceed with next node */
instanceCursor.gotoNext();
}
result = EC_Normal;
} else {
result = EC_MemoryExhausted;
break;
}
} else {
/* report a warning message and ignore this entry */
DCMSR_WARN("SOP Instance \"" << instanceUID << "\" already exists in reference list ... ignoring");
}
}
/* proceed with next node */
cursor.gotoNext();
}
} while (cursor.valid());
/* report a warning message if no "value" element found */
if (result.bad())
DCMSR_WARN("Series \"" << SeriesUID << "\" empty in reference list ... ignoring");
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::SeriesStruct::writeXML(STD_NAMESPACE ostream &stream,
const size_t flags) const
{
/* write the series level attributes */
stream << "" << OFendl;
writeStringValueToXML(stream, RetrieveAETitle, "aetitle", (flags & XF_writeEmptyTags) > 0);
if ((flags & XF_writeEmptyTags) || !RetrieveLocationUID.empty())
{
stream << "" << OFendl;
}
if ((flags & XF_writeEmptyTags) || !StorageMediaFileSetUID.empty() || !StorageMediaFileSetID.empty())
{
stream << "" << StorageMediaFileSetID << "" << OFendl;
}
/* iterate over all list items */
OFListConstIterator(InstanceStruct *) iter = InstanceList.begin();
const OFListConstIterator(InstanceStruct *) last = InstanceList.end();
while (iter != last)
{
InstanceStruct *instance = *iter;
/* check whether list item really exists */
if (instance != NULL)
{
/* write instance level */
stream << "" << OFendl;
stream << "SOPClassUID << "\">";
/* retrieve name of SOP class (if known) */
stream << dcmFindNameOfUID(instance->SOPClassUID.c_str(), "" /* empty value as default */);
stream << "" << OFendl;
stream << "InstanceUID << "\"/>" << OFendl;
/* purpose of reference (optional) */
if (instance->PurposeOfReference.isValid())
{
if (flags & DSRTypes::XF_codeComponentsAsAttribute)
stream << "" is closed in next writeXML() call
else
stream << "" << OFendl;
instance->PurposeOfReference.writeXML(stream, flags);
stream << "" << OFendl;
}
stream << "" << OFendl;
}
iter++;
}
stream << "" << OFendl;
return EC_Normal;
}
DSRSOPInstanceReferenceList::InstanceStruct *DSRSOPInstanceReferenceList::SeriesStruct::gotoInstance(const OFString &instanceUID)
{
InstanceStruct *instance = NULL;
/* first, check whether the current instance is the one we're searching for */
if ((Iterator != InstanceList.end()) && (*Iterator != NULL) && ((*Iterator)->InstanceUID == instanceUID))
instance = *Iterator;
else
{
/* start with the first list item */
Iterator = InstanceList.begin();
const OFListIterator(InstanceStruct *) last = InstanceList.end();
/* search for given SOP instance UID */
while ((Iterator != last) && ((*Iterator == NULL) || ((*Iterator)->InstanceUID != instanceUID)))
Iterator++;
/* item found */
if (Iterator != last)
instance = *Iterator;
}
return instance;
}
OFCondition DSRSOPInstanceReferenceList::SeriesStruct::gotoFirstItem()
{
OFCondition result = EC_IllegalCall;
/* check for empty instance list */
if (!InstanceList.empty())
{
/* set cursor to first list item */
Iterator = InstanceList.begin();
/* check whether list item is valid */
if (*Iterator != NULL)
result = EC_Normal;
else
result = EC_CorruptedData;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::SeriesStruct::gotoNextItem()
{
OFCondition result = EC_IllegalCall;
/* goto next list item */
if (++Iterator != InstanceList.end())
{
/* check whether list item is valid */
if (*Iterator != NULL)
result = EC_Normal;
else
result = EC_CorruptedData;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::SeriesStruct::addItem(const OFString &sopClassUID,
const OFString &instanceUID)
{
OFCondition result = EC_Normal;
/* check whether series already exists */
InstanceStruct *instance = gotoInstance(instanceUID);
if (instance == NULL)
{
/* if not, create new instance item and add it to the list */
instance = new InstanceStruct(sopClassUID, instanceUID);
if (instance != NULL)
{
InstanceList.push_back(instance);
/* set cursor to new position */
Iterator = --InstanceList.end();
} else
result = EC_MemoryExhausted;
} else {
/* check whether given SOP class is the same as stored */
if (instance->SOPClassUID != sopClassUID)
result = SR_EC_DifferentSOPClassesForAnInstance;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::SeriesStruct::removeItem()
{
OFCondition result = EC_IllegalCall;
/* check whether list is empty or iterator is invalid */
if (!InstanceList.empty() && (Iterator != InstanceList.end()))
{
/* free memory */
delete (*Iterator);
/* remove item from list */
Iterator = InstanceList.erase(Iterator);
result = EC_Normal;
}
return result;
}
// --- DSRSOPInstanceReferenceList::StudyStruct ---
DSRSOPInstanceReferenceList::StudyStruct::StudyStruct(const OFString &studyUID)
: StudyUID(studyUID),
SeriesList(),
Iterator()
{
/* initialize list cursor */
Iterator = SeriesList.end();
}
DSRSOPInstanceReferenceList::StudyStruct::~StudyStruct()
{
Iterator = SeriesList.begin();
const OFListIterator(SeriesStruct *) last = SeriesList.end();
/* delete all items and free memory */
while (Iterator != last)
{
delete (*Iterator);
Iterator = SeriesList.erase(Iterator);
}
}
size_t DSRSOPInstanceReferenceList::StudyStruct::getNumberOfInstances() const
{
size_t result = 0;
OFListConstIterator(SeriesStruct *) iter = SeriesList.begin();
const OFListConstIterator(SeriesStruct *) last = SeriesList.end();
/* for all series in the list */
while (iter != last)
{
/* sum up the number of instances */
if (*iter != NULL)
result += (*iter)->getNumberOfInstances();
++iter;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::StudyStruct::read(DcmItem &dataset,
const size_t flags)
{
/* first, check whether sequence is present and non-empty */
DcmSequenceOfItems *sequence = NULL;
OFCondition result = dataset.findAndGetSequence(DCM_ReferencedSeriesSequence, sequence);
checkElementValue(sequence, DCM_ReferencedSeriesSequence, "1-n", "1", result);
if (result.good())
{
/* iterate over all sequence items */
DcmObject *object = NULL;
while ((object = sequence->nextInContainer(object)) != NULL)
{
DcmItem *item = OFstatic_cast(DcmItem *, object);
/* get the series instance UID */
OFString seriesUID;
if (getAndCheckStringValueFromDataset(*item, DCM_SeriesInstanceUID, seriesUID, "1", "1", "ReferencedSeriesSequence").good())
{
/* check whether series item already exists,
because the internal structure is organized in a strictly hierarchical manner */
SeriesStruct *series = gotoSeries(seriesUID);
if (series == NULL)
{
/* if not, create a new series list item */
series = new SeriesStruct(seriesUID);
if (series != NULL)
{
/* and add it to the list of studies */
SeriesList.push_back(series);
} else {
result = EC_MemoryExhausted;
break;
}
}
if (series != NULL)
{
/* set cursor to new position */
Iterator = --SeriesList.end();
/* read further attributes on series level and the instance level */
result = series->read(*item, flags);
}
}
}
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::StudyStruct::write(DcmItem &dataset) const
{
OFCondition result = EC_Normal;
/* store the study level attributes */
dataset.putAndInsertOFStringArray(DCM_StudyInstanceUID, StudyUID);
/* iterate over all list items */
OFListConstIterator(SeriesStruct *) iter = SeriesList.begin();
const OFListConstIterator(SeriesStruct *) last = SeriesList.end();
while ((iter != last) && result.good())
{
SeriesStruct *series = *iter;
/* check whether list item really exists */
if (series != NULL)
{
DcmItem *item = NULL;
/* create a new item (and a sequence if required) */
result = dataset.findOrCreateSequenceItem(DCM_ReferencedSeriesSequence, item, -2 /*append new*/);
/* write series and instance level */
if (result.good())
result = series->write(*item);
}
iter++;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::StudyStruct::readXML(const DSRXMLDocument &doc,
DSRXMLCursor cursor,
const size_t flags)
{
OFCondition result = SR_EC_InvalidDocument;
if (cursor.valid())
{
OFString seriesUID;
while (cursor.valid())
{
/* check for known element tags */
if (doc.checkNode(cursor, "series").good())
{
if (!doc.getStringFromAttribute(cursor, seriesUID, "uid").empty())
{
/* check whether series item already exists,
because the internal structure is organized in a strictly hierarchical manner */
SeriesStruct *series = gotoSeries(seriesUID);
if (series == NULL)
{
/* if not, create a new series list item */
series = new SeriesStruct(seriesUID);
if (series != NULL)
{
/* and add it to the list of series */
SeriesList.push_back(series);
} else {
result = EC_MemoryExhausted;
break;
}
}
if (series != NULL)
{
/* set cursor to new position */
Iterator = --SeriesList.end();
/* read further attributes on series level and the instance level */
result = series->readXML(doc, cursor.getChild(), flags);
}
}
}
/* proceed with next node */
cursor.gotoNext();
}
/* report a warning message if no "value" element found */
if (result.bad())
DCMSR_WARN("Study \"" << StudyUID << "\" empty in reference list ... ignoring");
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::StudyStruct::writeXML(STD_NAMESPACE ostream &stream,
const size_t flags) const
{
OFCondition result = EC_Normal;
/* write the study level attributes */
stream << "" << OFendl;
/* iterate over all list items */
OFListConstIterator(SeriesStruct *) iter = SeriesList.begin();
const OFListConstIterator(SeriesStruct *) last = SeriesList.end();
while ((iter != last) && result.good())
{
SeriesStruct *series = *iter;
/* check whether list item really exists */
if (series != NULL)
{
/* write series and instance level */
result = series->writeXML(stream, flags);
}
iter++;
}
stream << "" << OFendl;
return result;
}
DSRSOPInstanceReferenceList::SeriesStruct *DSRSOPInstanceReferenceList::StudyStruct::gotoSeries(const OFString &seriesUID)
{
SeriesStruct *series = NULL;
/* first, check whether the current series is the one we're searching for */
if ((Iterator != SeriesList.end()) && (*Iterator != NULL) && ((*Iterator)->SeriesUID == seriesUID))
series = *Iterator;
else
{
/* start with the first list item */
Iterator = SeriesList.begin();
const OFListIterator(SeriesStruct *) last = SeriesList.end();
/* search for given series UID */
while ((Iterator != last) && ((*Iterator == NULL) || ((*Iterator)->SeriesUID != seriesUID)))
Iterator++;
/* item found */
if (Iterator != last)
series = *Iterator;
}
return series;
}
DSRSOPInstanceReferenceList::InstanceStruct *DSRSOPInstanceReferenceList::StudyStruct::gotoInstance(const OFString &instanceUID)
{
InstanceStruct *instance = NULL;
/* start with the first list item */
Iterator = SeriesList.begin();
const OFListIterator(SeriesStruct *) last = SeriesList.end();
/* search for given series UID */
while ((Iterator != last) && (instance == NULL))
{
SeriesStruct *series = *Iterator;
/* continue search on instance level */
if (series != NULL)
instance = series->gotoInstance(instanceUID);
/* if found exit loop, else goto next */
if (instance == NULL)
Iterator++;
}
return instance;
}
OFCondition DSRSOPInstanceReferenceList::StudyStruct::gotoFirstItem()
{
OFCondition result = EC_IllegalCall;
/* check for empty series list */
if (!SeriesList.empty())
{
/* set cursor to first list item */
Iterator = SeriesList.begin();
/* check whether list item is valid */
if (*Iterator != NULL)
{
/* do the same for instance level */
result = (*Iterator)->gotoFirstItem();
} else
result = EC_CorruptedData;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::StudyStruct::gotoNextItem()
{
OFCondition result = EC_IllegalCall;
/* goto next list item */
if (Iterator != SeriesList.end())
{
/* check whether current list item is valid */
if (*Iterator != NULL)
{
/* try to go to the next instance item */
result = (*Iterator)->gotoNextItem();
/* if this fails ... */
if (result.bad())
{
/* goto to the first instance of the next series item */
if (++Iterator != SeriesList.end())
{
if (*Iterator != NULL)
result = (*Iterator)->gotoFirstItem();
}
}
} else
result = EC_CorruptedData;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::StudyStruct::addItem(const OFString &seriesUID,
const OFString &sopClassUID,
const OFString &instanceUID)
{
OFCondition result = EC_Normal;
/* check whether series already exists */
SeriesStruct *series = gotoSeries(seriesUID);
if (series == NULL)
{
/* if not create new series item and add it to the list */
series = new SeriesStruct(seriesUID);
if (series != NULL)
{
SeriesList.push_back(series);
/* set cursor to new position */
Iterator = --SeriesList.end();
} else
result = EC_MemoryExhausted;
}
/* do the same for the instance level */
if (series != NULL)
result = series->addItem(sopClassUID, instanceUID);
return result;
}
OFCondition DSRSOPInstanceReferenceList::StudyStruct::removeItem()
{
OFCondition result = EC_IllegalCall;
/* check whether list is empty or iterator is invalid */
if (!SeriesList.empty() && (Iterator != SeriesList.end()))
{
SeriesStruct *series = *Iterator;
if (series != NULL)
{
result = series->removeItem();
/* check whether lower level list has become empty */
if (result.good() && series->InstanceList.empty())
{
/* free memory */
delete series;
/* if so, remove series from list and set iterator to the next item */
Iterator = SeriesList.erase(Iterator);
}
}
}
return result;
}
void DSRSOPInstanceReferenceList::StudyStruct::removeIncompleteItems()
{
Iterator = SeriesList.begin();
const OFListIterator(SeriesStruct *) last = SeriesList.end();
/* for all series in the list */
while (Iterator != last)
{
SeriesStruct *series = *Iterator;
if (series != NULL)
{
/* check whether list of series is empty */
if (series->InstanceList.empty())
{
/* free memory */
delete series;
/* if so, remove series from list and set iterator to the next item */
Iterator = SeriesList.erase(Iterator);
} else
++Iterator;
} else
++Iterator;
}
}
// --- DSRSOPInstanceReferenceList ---
DSRSOPInstanceReferenceList::DSRSOPInstanceReferenceList(const DcmTagKey &sequence)
: SequenceTag(sequence),
StudyList(),
Iterator(),
SpecificCharacterSet()
{
/* initialize list cursor */
Iterator = StudyList.end();
}
DSRSOPInstanceReferenceList::~DSRSOPInstanceReferenceList()
{
/* clear reference list and delete allocated memory */
clear();
}
void DSRSOPInstanceReferenceList::clear()
{
Iterator = StudyList.begin();
const OFListIterator(StudyStruct *) last = StudyList.end();
/* delete all items and free memory */
while (Iterator != last)
{
delete (*Iterator);
Iterator = StudyList.erase(Iterator);
}
/* make sure that the list is empty */
StudyList.clear();
Iterator = StudyList.end();
/* also clear other members */
SpecificCharacterSet.clear();
}
OFBool DSRSOPInstanceReferenceList::isEmpty() const
{
return StudyList.empty();
}
size_t DSRSOPInstanceReferenceList::getNumberOfInstances() const
{
size_t result = 0;
OFListConstIterator(StudyStruct *) iter = StudyList.begin();
const OFListConstIterator(StudyStruct *) last = StudyList.end();
/* for all studies in the list */
while (iter != last)
{
/* sum up the number of instances */
if (*iter != NULL)
result += (*iter)->getNumberOfInstances();
++iter;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::read(DcmItem &dataset,
const size_t flags)
{
/* first, check whether sequence is present and non-empty */
DcmSequenceOfItems *sequence = NULL;
OFCondition result = dataset.findAndGetSequence(SequenceTag, sequence);
checkElementValue(sequence, SequenceTag, "1-n", "1C", result);
if (result.good())
{
OFString sequenceName = DcmTag(SequenceTag).getTagName();
/* iterate over all sequence items */
DcmObject *object = NULL;
while ((object = sequence->nextInContainer(object)) != NULL)
{
DcmItem *item = OFstatic_cast(DcmItem *, object);
/* get the study instance UID */
OFString studyUID;
if (getAndCheckStringValueFromDataset(*item, DCM_StudyInstanceUID, studyUID, "1", "1", sequenceName.c_str()).good())
{
/* check whether study item already exists,
because the internal structure is organized in a strictly hierarchical manner */
StudyStruct *study = gotoStudy(studyUID);
if (study == NULL)
{
/* if not, create a new study list item */
study = new StudyStruct(studyUID);
if (study != NULL)
{
/* and add it to the list of studies */
StudyList.push_back(study);
} else {
result = EC_MemoryExhausted;
break;
}
}
if (study != NULL)
{
/* set cursor to new position */
Iterator = --StudyList.end();
/* read attributes on series and instance level */
result = study->read(*item, flags);
}
}
}
/* remove empty/incomplete items from the list structure */
removeIncompleteItems();
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::write(DcmItem &dataset) const
{
OFCondition result = EC_Normal;
/* iterate over all list items */
OFListConstIterator(StudyStruct *) iter = StudyList.begin();
const OFListConstIterator(StudyStruct *) last = StudyList.end();
while ((iter != last) && result.good())
{
StudyStruct *study = *iter;
/* check whether list item really exists */
if (study != NULL)
{
DcmItem *item = NULL;
/* create a new item (and a sequence if required) */
result = dataset.findOrCreateSequenceItem(SequenceTag, item, -2 /*append new*/);
/* write study, series and instance level */
if (result.good())
result = study->write(*item);
}
iter++;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::readXML(const DSRXMLDocument &doc,
DSRXMLCursor cursor,
const size_t flags)
{
/* default: no error, e.g. for empty list of references */
OFCondition result = EC_Normal;
if (cursor.valid())
{
OFString studyUID;
while (cursor.valid())
{
/* check for known element tags */
if (doc.checkNode(cursor, "study").good())
{
if (!doc.getStringFromAttribute(cursor, studyUID, "uid").empty())
{
/* check whether study item already exists,
because the internal structure is organized in a strictly hierarchical manner */
StudyStruct *study = gotoStudy(studyUID);
if (study == NULL)
{
/* if not, create a new study list item */
study = new StudyStruct(studyUID);
if (study != NULL)
{
/* and add it to the list of studies */
StudyList.push_back(study);
} else {
result = EC_MemoryExhausted;
break;
}
}
if (study != NULL)
{
/* set cursor to new position */
Iterator = --StudyList.end();
/* read attributes on series and instance level */
result = study->readXML(doc, cursor.getChild(), flags);
}
}
}
/* proceed with next node */
cursor.gotoNext();
}
/* remove empty/incomplete items from the list structure */
removeIncompleteItems();
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::writeXML(STD_NAMESPACE ostream &stream,
const size_t flags) const
{
OFCondition result = EC_Normal;
/* iterate over all list items */
OFListConstIterator(StudyStruct *) iter = StudyList.begin();
const OFListConstIterator(StudyStruct *) last = StudyList.end();
while ((iter != last) && result.good())
{
StudyStruct *study = *iter;
/* check whether list item really exists */
if (study != NULL)
{
/* write study, series and instance level */
result = study->writeXML(stream, flags);
}
iter++;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::setSpecificCharacterSet(const OFString &value,
const OFBool check)
{
OFCondition result = (check) ? DcmCodeString::checkStringValue(value, "1-n") : EC_Normal;
if (result.good())
SpecificCharacterSet = value;
return result;
}
DSRSOPInstanceReferenceList::StudyStruct *DSRSOPInstanceReferenceList::gotoStudy(const OFString &studyUID)
{
StudyStruct *study = NULL;
/* first, check whether the current study is the one we're searching for */
if ((Iterator != StudyList.end()) && (*Iterator != NULL) && ((*Iterator)->StudyUID == studyUID))
study = *Iterator;
else
{
/* start with the first list item */
Iterator = StudyList.begin();
const OFListIterator(StudyStruct *) last = StudyList.end();
/* search for given study UID */
while ((Iterator != last) && ((*Iterator == NULL) || ((*Iterator)->StudyUID != studyUID)))
Iterator++;
/* item found */
if (Iterator != last)
study = *Iterator;
}
return study;
}
OFCondition DSRSOPInstanceReferenceList::addItem(const OFString &studyUID,
const OFString &seriesUID,
const OFString &sopClassUID,
const OFString &instanceUID,
const OFBool check)
{
OFCondition result = EC_Normal;
/* check parameters first */
if (check)
{
/* check whether the passed values are valid */
result = checkSOPInstance(studyUID, seriesUID, sopClassUID, instanceUID);
} else {
/* make sure that the mandatory values are non-empty */
if (studyUID.empty() || seriesUID.empty() || sopClassUID.empty() || instanceUID.empty())
result = EC_IllegalParameter;
}
if (result.good())
{
StudyStruct *study = gotoStudy(studyUID);
/* check whether study already exists */
if (study == NULL)
{
/* if not create new study item and add it to the list */
study = new StudyStruct(studyUID);
if (study != NULL)
{
StudyList.push_back(study);
/* set cursor to new position */
Iterator = --StudyList.end();
} else
result = EC_MemoryExhausted;
}
/* do the same for the series and instance level */
if (study != NULL)
result = study->addItem(seriesUID, sopClassUID, instanceUID);
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::addItem(DcmItem &dataset,
const OFBool check)
{
OFString studyUID, seriesUID, sopClassUID, instanceUID;
/* retrieve element values from dataset */
getStringValueFromDataset(dataset, DCM_StudyInstanceUID, studyUID);
getStringValueFromDataset(dataset, DCM_SeriesInstanceUID, seriesUID);
getStringValueFromDataset(dataset, DCM_SOPClassUID, sopClassUID);
getStringValueFromDataset(dataset, DCM_SOPInstanceUID, instanceUID);
/* add new item to the list of references (if valid) */
return addItem(studyUID, seriesUID, sopClassUID, instanceUID, check);
}
OFCondition DSRSOPInstanceReferenceList::removeItem()
{
OFCondition result = EC_IllegalCall;
/* check whether list is empty or iterator is invalid */
if (!StudyList.empty() && (Iterator != StudyList.end()))
{
StudyStruct *study = *Iterator;
if (study != NULL)
{
result = study->removeItem();
/* check whether lower level list has become empty */
if (result.good() && study->SeriesList.empty())
{
/* free memory */
delete study;
/* if so, remove study from list and set iterator to the next item */
Iterator = StudyList.erase(Iterator);
}
}
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::removeItem(const OFString &sopClassUID,
const OFString &instanceUID)
{
/* goto specified item ... */
OFCondition result = gotoItem(sopClassUID, instanceUID);
/* ... and remove it */
if (result.good())
result = removeItem();
return result;
}
OFCondition DSRSOPInstanceReferenceList::removeItem(const OFString &studyUID,
const OFString &seriesUID,
const OFString &instanceUID)
{
/* goto specified item ... */
OFCondition result = gotoItem(studyUID, seriesUID, instanceUID);
/* ... and remove it */
if (result.good())
result = removeItem();
return result;
}
void DSRSOPInstanceReferenceList::removeIncompleteItems()
{
Iterator = StudyList.begin();
const OFListIterator(StudyStruct *) last = StudyList.end();
/* for all studies in the list */
while (Iterator != last)
{
StudyStruct *study = *Iterator;
if (study != NULL)
{
/* remove empty/incomplete items on series/instance level */
study->removeIncompleteItems();
/* check whether list of series is empty */
if (study->SeriesList.empty())
{
/* free memory */
delete study;
/* if so, remove study from list and set iterator to the next item */
Iterator = StudyList.erase(Iterator);
} else
++Iterator;
} else
++Iterator;
}
}
OFCondition DSRSOPInstanceReferenceList::gotoItem(const OFString &sopClassUID,
const OFString &instanceUID)
{
OFCondition result = EC_IllegalParameter;
/* check parameters first */
if (!sopClassUID.empty() && !instanceUID.empty())
{
OFBool sopClassMatch = OFFalse;
result = SR_EC_SOPInstanceNotFound;
/* start with first study */
Iterator = StudyList.begin();
const OFListIterator(StudyStruct *) last = StudyList.end();
/* iterate over all studies */
while ((Iterator != last) && result.bad())
{
StudyStruct *study = *Iterator;
/* continue search on series level */
if (study != NULL)
{
InstanceStruct *instance = study->gotoInstance(instanceUID);
/* if instance found, exit loop */
if (instance != NULL)
{
/* finally, check whether SOP class matches */
sopClassMatch = (instance->SOPClassUID == sopClassUID);
result = EC_Normal;
} else
Iterator ++;
} else
Iterator++;
}
/* report an error in case of SOP class mismatch */
if (result.good() && !sopClassMatch)
result = SR_EC_DifferentSOPClassesForAnInstance;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::gotoItem(const OFString &studyUID,
const OFString &seriesUID,
const OFString &instanceUID)
{
OFCondition result = EC_IllegalParameter;
/* check parameters first */
if (!studyUID.empty() && !seriesUID.empty() && !instanceUID.empty())
{
result = SR_EC_SOPInstanceNotFound;
/* search for given study */
StudyStruct *study = gotoStudy(studyUID);
if (study != NULL)
{
/* do the same for the series ... */
SeriesStruct *series = study->gotoSeries(seriesUID);
if (series != NULL)
{
/* ... and instance level */
if (series->gotoInstance(instanceUID) != NULL)
result = EC_Normal;
}
}
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::gotoFirstItem()
{
OFCondition result = EC_IllegalCall;
/* check for empty study list */
if (!StudyList.empty())
{
/* set cursor to first list item */
Iterator = StudyList.begin();
if (*Iterator != NULL)
{
/* do the same for series and instance level */
result = (*Iterator)->gotoFirstItem();
}
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::gotoNextItem()
{
OFCondition result = EC_IllegalCall;
/* goto next list item */
if (Iterator != StudyList.end())
{
/* check whether current list item is valid */
if (*Iterator != NULL)
{
/* try to go to the next instance item */
result = (*Iterator)->gotoNextItem();
/* if this fails ... */
if (result.bad())
{
/* goto to the first series/instance of the next stidy item */
if (++Iterator != StudyList.end())
{
if (*Iterator != NULL)
result = (*Iterator)->gotoFirstItem();
}
}
} else
result = EC_CorruptedData;
}
return result;
}
DSRSOPInstanceReferenceList::StudyStruct *DSRSOPInstanceReferenceList::getCurrentStudy() const
{
StudyStruct *study = NULL;
/* check whether current study is valid */
OFListConstIterator(StudyStruct *) it = Iterator;
if (it != StudyList.end())
study = *Iterator;
return study;
}
DSRSOPInstanceReferenceList::SeriesStruct *DSRSOPInstanceReferenceList::getCurrentSeries() const
{
SeriesStruct *series = NULL;
StudyStruct *study = getCurrentStudy();
/* check whether current series is valid */
if ((study != NULL) && (study->Iterator != study->SeriesList.end()))
series = *(study->Iterator);
return series;
}
DSRSOPInstanceReferenceList::InstanceStruct *DSRSOPInstanceReferenceList::getCurrentInstance() const
{
InstanceStruct *instance = NULL;
SeriesStruct *series = getCurrentSeries();
/* check whether current instance is valid */
if ((series != NULL) && (series->Iterator != series->InstanceList.end()))
instance = *(series->Iterator);
return instance;
}
const OFString &DSRSOPInstanceReferenceList::getStudyInstanceUID(OFString &stringValue) const
{
/* check whether current study is valid */
StudyStruct *study = getCurrentStudy();
/* get study instance UID or clear string if invalid */
if (study != NULL)
stringValue = study->StudyUID;
else
stringValue.clear();
return stringValue;
}
const OFString &DSRSOPInstanceReferenceList::getSeriesInstanceUID(OFString &stringValue) const
{
/* check whether current series is valid */
SeriesStruct *series = getCurrentSeries();
/* get series instance UID or clear string if invalid */
if (series != NULL)
stringValue = series->SeriesUID;
else
stringValue.clear();
return stringValue;
}
const OFString &DSRSOPInstanceReferenceList::getSOPInstanceUID(OFString &stringValue) const
{
/* check whether current instance is valid */
InstanceStruct *instance = getCurrentInstance();
/* get SOP instance UID or clear string if invalid */
if (instance != NULL)
stringValue = instance->InstanceUID;
else
stringValue.clear();
return stringValue;
}
const OFString &DSRSOPInstanceReferenceList::getSOPClassUID(OFString &stringValue) const
{
/* check whether current instance is valid */
InstanceStruct *instance = getCurrentInstance();
/* get SOP class UID or clear string if invalid */
if (instance != NULL)
stringValue = instance->SOPClassUID;
else
stringValue.clear();
return stringValue;
}
const OFString &DSRSOPInstanceReferenceList::getSOPClassName(OFString &stringValue,
const OFString &defaultName) const
{
OFString sopClassUID;
/* retrieve SOP class UID of current entry */
if (!getSOPClassUID(sopClassUID).empty())
{
/* lookup name associated with the SOP class UID */
stringValue = dcmFindNameOfUID(sopClassUID.c_str(), defaultName.c_str());
} else
stringValue.clear();
return stringValue;
}
const OFString &DSRSOPInstanceReferenceList::getRetrieveAETitle(OFString &stringValue) const
{
/* check whether current series is valid */
SeriesStruct *series = getCurrentSeries();
/* get retrieve application entity title or clear string if invalid */
if (series != NULL)
stringValue = series->RetrieveAETitle;
else
stringValue.clear();
return stringValue;
}
const OFString &DSRSOPInstanceReferenceList::getRetrieveLocationUID(OFString &stringValue) const
{
/* check whether current series is valid */
SeriesStruct *series = getCurrentSeries();
/* get retrieve location UID or clear string if invalid */
if (series != NULL)
stringValue = series->RetrieveLocationUID;
else
stringValue.clear();
return stringValue;
}
const OFString &DSRSOPInstanceReferenceList::getStorageMediaFileSetID(OFString &stringValue) const
{
/* check whether current series is valid */
SeriesStruct *series = getCurrentSeries();
/* get storage media file set ID or clear string if invalid */
if (series != NULL)
stringValue = series->StorageMediaFileSetID;
else
stringValue.clear();
return stringValue;
}
const OFString &DSRSOPInstanceReferenceList::getStorageMediaFileSetUID(OFString &stringValue) const
{
/* check whether current series is valid */
SeriesStruct *series = getCurrentSeries();
/* get storage media file set UID or clear string if invalid */
if (series != NULL)
stringValue = series->StorageMediaFileSetUID;
else
stringValue.clear();
return stringValue;
}
OFCondition DSRSOPInstanceReferenceList::getPurposeOfReference(DSRCodedEntryValue &codeValue) const
{
OFCondition result = EC_IllegalCall;
/* check whether current instance is valid */
InstanceStruct *instance = getCurrentInstance();
if (instance != NULL)
{
codeValue = instance->PurposeOfReference;
result = EC_Normal;
} else
codeValue.clear();
return result;
}
OFCondition DSRSOPInstanceReferenceList::setRetrieveAETitle(const OFString &value,
const OFBool check)
{
OFCondition result = EC_IllegalCall;
/* check whether current series is valid */
SeriesStruct *series = getCurrentSeries();
if (series != NULL)
{
/* set the value (if valid) */
result = (check) ? DcmApplicationEntity::checkStringValue(value, "1-n") : EC_Normal;
if (result.good())
series->RetrieveAETitle = value;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::setRetrieveLocationUID(const OFString &value,
const OFBool check)
{
OFCondition result = EC_IllegalCall;
/* check whether current series is valid */
SeriesStruct *series = getCurrentSeries();
if (series != NULL)
{
/* set the value (if valid) */
result = (check) ? DcmUniqueIdentifier::checkStringValue(value, "1") : EC_Normal;
if (result.good())
series->RetrieveLocationUID = value;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::setStorageMediaFileSetID(const OFString &value,
const OFBool check)
{
OFCondition result = EC_IllegalCall;
/* check whether current series is valid */
SeriesStruct *series = getCurrentSeries();
if (series != NULL)
{
/* set the value (if valid) */
result = (check) ? DcmShortString::checkStringValue(value, "1", SpecificCharacterSet) : EC_Normal;
if (result.good())
series->StorageMediaFileSetID = value;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::setStorageMediaFileSetUID(const OFString &value,
const OFBool check)
{
OFCondition result = EC_IllegalCall;
/* check whether current series is valid */
SeriesStruct *series = getCurrentSeries();
if (series != NULL)
{
/* set the value (if valid) */
result = (check) ? DcmUniqueIdentifier::checkStringValue(value, "1") : EC_Normal;
if (result.good())
series->StorageMediaFileSetUID = value;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::setPurposeOfReference(const DSRCodedEntryValue &codeValue,
const OFBool check)
{
OFCondition result = EC_IllegalCall;
/* check whether current instance is valid */
InstanceStruct *instance = getCurrentInstance();
if (instance != NULL)
{
if (check)
{
/* check whether the passed value is valid */
result = checkPurposeOfReference(codeValue);
} else {
/* make sure that the mandatory values are non-empty */
result = codeValue.isEmpty() ? SR_EC_InvalidValue : EC_Normal;
}
if (result.good())
instance->PurposeOfReference = codeValue;
}
return result;
}
OFCondition DSRSOPInstanceReferenceList::checkSOPInstance(const OFString &studyUID,
const OFString &seriesUID,
const OFString &sopClassUID,
const OFString &instanceUID) const
{
OFCondition result = EC_Normal;
/* the four UID values should never be empty */
if (studyUID.empty() || seriesUID.empty() || sopClassUID.empty() || instanceUID.empty())
result = SR_EC_InvalidValue;
/* check for conformance with VR and VM */
if (result.good())
result = DcmUniqueIdentifier::checkStringValue(studyUID, "1");
if (result.good())
result = DcmUniqueIdentifier::checkStringValue(seriesUID, "1");
if (result.good())
result = DcmUniqueIdentifier::checkStringValue(sopClassUID, "1");
if (result.good())
result = DcmUniqueIdentifier::checkStringValue(instanceUID, "1");
return result;
}
OFCondition DSRSOPInstanceReferenceList::checkPurposeOfReference(const DSRCodedEntryValue &purposeOfReference) const
{
/* purpose of reference can be empty */
return purposeOfReference.isEmpty() ? EC_Normal
: purposeOfReference.checkCurrentValue();
}