/* * * Copyright (C) 2000-2019, 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: DSRBasicCodedEntry, DSRCodedEntryValue * */ #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/dcmsr/dsrtypes.h" #include "dcmtk/dcmsr/dsrcodvl.h" #include "dcmtk/dcmsr/dsrxmld.h" #include "dcmtk/dcmdata/dcdeftag.h" #include "dcmtk/dcmdata/dcvrcs.h" #include "dcmtk/dcmdata/dcvrdt.h" #include "dcmtk/dcmdata/dcvrlo.h" #include "dcmtk/dcmdata/dcvrsh.h" #include "dcmtk/dcmdata/dcvruc.h" #include "dcmtk/dcmdata/dcvrui.h" #include "dcmtk/dcmdata/dcvrur.h" // implementation of class DSRBasicCodedEntry DSRBasicCodedEntry::DSRBasicCodedEntry(const OFString &codeValue, const OFString &codingSchemeDesignator, const OFString &codeMeaning, const DSRTypes::E_CodeValueType codeValueType) : CodeValueType(codeValueType), CodeValue(codeValue), CodingSchemeDesignator(codingSchemeDesignator), CodingSchemeVersion(), CodeMeaning(codeMeaning) { } DSRBasicCodedEntry::DSRBasicCodedEntry(const OFString &codeValue, const OFString &codingSchemeDesignator, const OFString &codingSchemeVersion, const OFString &codeMeaning, const DSRTypes::E_CodeValueType codeValueType) : CodeValueType(codeValueType), CodeValue(codeValue), CodingSchemeDesignator(codingSchemeDesignator), CodingSchemeVersion(codingSchemeVersion), CodeMeaning(codeMeaning) { } // implementation of class DSRCodedEntryValue DSRCodedEntryValue::DSRCodedEntryValue() : CodeValueType(DSRTypes::CVT_auto), CodeValue(), CodingSchemeDesignator(), CodingSchemeVersion(), CodeMeaning(), ContextIdentifier(), ContextUID(), MappingResource(), ContextGroupVersion(), ContextGroupLocalVersion(), ContextGroupExtensionCreatorUID() { } DSRCodedEntryValue::DSRCodedEntryValue(const DSRBasicCodedEntry &basicCodedEntry, const OFBool check) : CodeValueType(DSRTypes::CVT_auto), CodeValue(), CodingSchemeDesignator(), CodingSchemeVersion(), CodeMeaning(), ContextIdentifier(), ContextUID(), MappingResource(), ContextGroupVersion(), ContextGroupLocalVersion(), ContextGroupExtensionCreatorUID() { /* check code (if not disabled) */ setCode(basicCodedEntry, check); } DSRCodedEntryValue::DSRCodedEntryValue(const OFString &codeValue, const OFString &codingSchemeDesignator, const OFString &codeMeaning, const DSRTypes::E_CodeValueType codeValueType, const OFExplicitBool check) : CodeValueType(DSRTypes::CVT_auto), CodeValue(), CodingSchemeDesignator(), CodingSchemeVersion(), CodeMeaning(), ContextIdentifier(), ContextUID(), MappingResource(), ContextGroupVersion(), ContextGroupLocalVersion(), ContextGroupExtensionCreatorUID() { /* check code (if not disabled) */ setCode(codeValue, codingSchemeDesignator, codeMeaning, codeValueType, check); } DSRCodedEntryValue::DSRCodedEntryValue(const OFString &codeValue, const OFString &codingSchemeDesignator, const OFString &codingSchemeVersion, const OFString &codeMeaning, const DSRTypes::E_CodeValueType codeValueType, const OFBool check) : CodeValueType(DSRTypes::CVT_auto), CodeValue(), CodingSchemeDesignator(), CodingSchemeVersion(), CodeMeaning(), ContextIdentifier(), ContextUID(), MappingResource(), ContextGroupVersion(), ContextGroupLocalVersion(), ContextGroupExtensionCreatorUID() { /* check code (if not disabled) */ setCode(codeValue, codingSchemeDesignator, codingSchemeVersion, codeMeaning, codeValueType, check); } DSRCodedEntryValue::DSRCodedEntryValue(const DSRCodedEntryValue &codedEntryValue) : CodeValueType(codedEntryValue.CodeValueType), CodeValue(codedEntryValue.CodeValue), CodingSchemeDesignator(codedEntryValue.CodingSchemeDesignator), CodingSchemeVersion(codedEntryValue.CodingSchemeVersion), CodeMeaning(codedEntryValue.CodeMeaning), ContextIdentifier(codedEntryValue.ContextIdentifier), ContextUID(codedEntryValue.ContextUID), MappingResource(codedEntryValue.MappingResource), ContextGroupVersion(codedEntryValue.ContextGroupVersion), ContextGroupLocalVersion(codedEntryValue.ContextGroupLocalVersion), ContextGroupExtensionCreatorUID(codedEntryValue.ContextGroupExtensionCreatorUID) { /* do not check since this would be unexpected to the user */ } DSRCodedEntryValue::~DSRCodedEntryValue() { } DSRCodedEntryValue &DSRCodedEntryValue::operator=(const DSRCodedEntryValue &codedEntryValue) { /* do not check since this would be unexpected to the user */ CodeValueType = codedEntryValue.CodeValueType; CodeValue = codedEntryValue.CodeValue; CodingSchemeDesignator = codedEntryValue.CodingSchemeDesignator; CodingSchemeVersion = codedEntryValue.CodingSchemeVersion; CodeMeaning = codedEntryValue.CodeMeaning; ContextIdentifier = codedEntryValue.ContextIdentifier; ContextUID = codedEntryValue.ContextUID; MappingResource = codedEntryValue.MappingResource; ContextGroupVersion = codedEntryValue.ContextGroupVersion; ContextGroupLocalVersion = codedEntryValue.ContextGroupLocalVersion; ContextGroupExtensionCreatorUID = codedEntryValue.ContextGroupExtensionCreatorUID; return *this; } OFBool DSRCodedEntryValue::operator==(const DSRCodedEntryValue &codedEntryValue) const { /* Code Meaning is not used for comparing the two codes, also the "Enhanced Encoding Mode" is not taken into account */ return (CodeValue == codedEntryValue.CodeValue) && (CodingSchemeDesignator == codedEntryValue.CodingSchemeDesignator) && (CodingSchemeVersion == codedEntryValue.CodingSchemeVersion); } OFBool DSRCodedEntryValue::operator!=(const DSRCodedEntryValue &codedEntryValue) const { /* Code Meaning is not used for comparing the two codes, also the "Enhanced Encoding Mode" is not taken into account */ return (CodeValue != codedEntryValue.CodeValue) || (CodingSchemeDesignator != codedEntryValue.CodingSchemeDesignator) || (CodingSchemeVersion != codedEntryValue.CodingSchemeVersion); } OFBool DSRCodedEntryValue::operator==(const DSRBasicCodedEntry &basicCodedEntry) const { /* Code Meaning is not used for comparing the two codes */ return (CodeValue == basicCodedEntry.CodeValue) && (CodingSchemeDesignator == basicCodedEntry.CodingSchemeDesignator) && (CodingSchemeVersion == basicCodedEntry.CodingSchemeVersion); } OFBool DSRCodedEntryValue::operator!=(const DSRBasicCodedEntry &basicCodedEntry) const { /* Code Meaning is not used for comparing the two codes */ return (CodeValue != basicCodedEntry.CodeValue) || (CodingSchemeDesignator != basicCodedEntry.CodingSchemeDesignator) || (CodingSchemeVersion != basicCodedEntry.CodingSchemeVersion); } void DSRCodedEntryValue::clear() { CodeValueType = DSRTypes::CVT_auto; CodeValue.clear(); CodingSchemeDesignator.clear(); CodingSchemeVersion.clear(); CodeMeaning.clear(); ContextIdentifier.clear(); ContextUID.clear(); MappingResource.clear(); ContextGroupVersion.clear(); ContextGroupLocalVersion.clear(); ContextGroupExtensionCreatorUID.clear(); } OFBool DSRCodedEntryValue::isValid() const { return checkCurrentValue().good(); } OFBool DSRCodedEntryValue::isEmpty() const { return CodeValue.empty() && CodingSchemeDesignator.empty() && CodingSchemeVersion.empty() && CodeMeaning.empty(); } OFBool DSRCodedEntryValue::isComplete() const { return !CodeValue.empty() && (!CodingSchemeDesignator.empty() || (CodeValueType == DSRTypes::CVT_URN)) && !CodeMeaning.empty(); } void DSRCodedEntryValue::print(STD_NAMESPACE ostream &stream, const OFBool printCodeValue, const size_t flags) const { if ((flags & DSRTypes::PF_printInvalidCodes) || isValid()) { OFString printString; stream << "("; if (printCodeValue) { stream << DSRTypes::convertToPrintString(CodeValue, printString) << ","; stream << DSRTypes::convertToPrintString(CodingSchemeDesignator, printString); if (!CodingSchemeVersion.empty()) stream << "[" << DSRTypes::convertToPrintString(CodingSchemeVersion, printString) << "]"; } else stream << ","; stream << ",\"" << DSRTypes::convertToPrintString(CodeMeaning, printString) << "\")"; if ((flags & DSRTypes::PF_indicateEnhancedEncodingMode) && usesEnhancedEncodingMode()) stream << "*"; } else if ((flags & DSRTypes::PF_printEmptyCodes) && isEmpty()) stream << "empty code"; else stream << "invalid code"; } OFCondition DSRCodedEntryValue::readItem(DcmItem &dataset, const char *moduleName, const size_t flags) { const OFBool acceptViolation = (flags & DSRTypes::RF_acceptInvalidContentItemValue) > 0; /* read "Basic Coded Entry Attributes" */ OFCondition result = DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_LongCodeValue, CodeValue, "1", "1C", moduleName, acceptViolation); /* tbc: should we distinguish "tag not found" from other errors? */ if (result.bad()) /* different types of code value */ { result = DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_URNCodeValue, CodeValue, "1", "1C", moduleName, acceptViolation); if (result.bad()) { result = DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_CodeValue, CodeValue, "1", "1", moduleName, acceptViolation); CodeValueType = DSRTypes::CVT_Short; } else CodeValueType = DSRTypes::CVT_URN; } else CodeValueType = DSRTypes::CVT_Long; if (result.good()) { if (CodeValueType == DSRTypes::CVT_URN) /* conditional or mandatory */ result = DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_CodingSchemeDesignator, CodingSchemeDesignator, "1", "1C", moduleName, acceptViolation); else result = DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_CodingSchemeDesignator, CodingSchemeDesignator, "1", "1", moduleName, acceptViolation); } if (result.good()) /* conditional (type 1C) */ DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_CodingSchemeVersion, CodingSchemeVersion, "1", "1C", moduleName); if (result.good()) result = DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_CodeMeaning, CodeMeaning, "1", "1", moduleName, acceptViolation); /* read "Enhanced Encoding Mode" */ if (result.good()) /* optional or conditional */ { DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_ContextIdentifier, ContextIdentifier, "1", "3", moduleName); if (!ContextIdentifier.empty()) { OFString extensionFlag; /* check for a common error: Context Group Identifier includes "CID" prefix */ if ((ContextIdentifier.find_first_not_of("0123456789") != OFString_npos) || (ContextIdentifier.at(0) == '0')) { DCMSR_DEBUG("Reading invalid Context Identifier (" << ContextIdentifier << ")"); DCMSR_WARN("Context Identifier shall be a string of digits without leading zeros"); } DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_MappingResource, MappingResource, "1", "1" /* was 1C */, moduleName); DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_ContextGroupVersion, ContextGroupVersion, "1", "1" /* was 1C */, moduleName); DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_ContextGroupExtensionFlag, extensionFlag, "1", "3", moduleName); if (extensionFlag == "Y") { DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_ContextGroupLocalVersion, ContextGroupLocalVersion, "1", "1" /* was 1C */, moduleName); DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_ContextGroupExtensionCreatorUID, ContextGroupExtensionCreatorUID, "1", "1" /* was 1C */, moduleName); } else { /* ignore Context Group Local Version and/or Context Group Extension Creator UID */ } } DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_ContextUID, ContextUID, "1", "3", moduleName); } /* tbd: might add check for correct code */ return result; } OFCondition DSRCodedEntryValue::writeItem(DcmItem &dataset) const { /* write "Basic Coded Entry Attributes" */ OFCondition result = EC_Normal; if (CodeValueType == DSRTypes::CVT_Long) /* different types of code value */ result = DSRTypes::putStringValueToDataset(dataset, DCM_LongCodeValue, CodeValue); else if (CodeValueType == DSRTypes::CVT_URN) result = DSRTypes::putStringValueToDataset(dataset, DCM_URNCodeValue, CodeValue); else /* short or auto */ result = DSRTypes::putStringValueToDataset(dataset, DCM_CodeValue, CodeValue); if (result.good()) result = DSRTypes::putStringValueToDataset(dataset, DCM_CodingSchemeDesignator, CodingSchemeDesignator); if (result.good()) /* conditional (type 1C) */ result = DSRTypes::putStringValueToDataset(dataset, DCM_CodingSchemeVersion, CodingSchemeVersion, OFFalse /*allowEmpty*/); if (result.good()) result = DSRTypes::putStringValueToDataset(dataset, DCM_CodeMeaning, CodeMeaning); /* write "Enhanced Encoding Mode" */ if (result.good()) /* optional or conditional */ { if (!ContextIdentifier.empty()) { DSRTypes::putStringValueToDataset(dataset, DCM_ContextIdentifier, ContextIdentifier); DSRTypes::putStringValueToDataset(dataset, DCM_ContextUID, ContextUID, OFFalse /*allowEmpty*/); DSRTypes::putStringValueToDataset(dataset, DCM_MappingResource, MappingResource, OFFalse /*allowEmpty*/); DSRTypes::putStringValueToDataset(dataset, DCM_ContextGroupVersion, ContextGroupVersion, OFFalse /*allowEmpty*/); if (!ContextGroupLocalVersion.empty() && !ContextGroupExtensionCreatorUID.empty()) { DSRTypes::putStringValueToDataset(dataset, DCM_ContextGroupExtensionFlag, "Y"); DSRTypes::putStringValueToDataset(dataset, DCM_ContextGroupLocalVersion, ContextGroupLocalVersion); DSRTypes::putStringValueToDataset(dataset, DCM_ContextGroupExtensionCreatorUID, ContextGroupExtensionCreatorUID); } } DSRTypes::putStringValueToDataset(dataset, DCM_ContextUID, ContextUID, OFFalse /*allowEmpty*/); } return result; } OFCondition DSRCodedEntryValue::readSequence(DcmItem &dataset, const DcmTagKey &tagKey, const OFString &type, const size_t flags, const OFString &vm) { /* read CodeSequence */ DcmSequenceOfItems *dseq = NULL; OFCondition result = dataset.findAndGetSequence(tagKey, dseq); DSRTypes::checkElementValue(dseq, tagKey, vm, type, result); if (result.good()) { DcmItem *ditem = dseq->getItem(0); if (ditem != NULL) { /* read Code */ result = readItem(*ditem, DcmTag(tagKey).getTagName(), flags); } else result = SR_EC_InvalidDocumentTree; } return result; } OFCondition DSRCodedEntryValue::readSequenceItem(DcmItem &item, const DcmTagKey &tagKey, const size_t flags) { /* call the real function, which is "protected" */ return readItem(item, DcmTag(tagKey).getTagName(), flags); } OFCondition DSRCodedEntryValue::writeSequence(DcmItem &dataset, const DcmTagKey &tagKey) const { OFCondition result = EC_MemoryExhausted; /* write CodeSequence */ DcmSequenceOfItems *dseq = new DcmSequenceOfItems(tagKey); if (dseq != NULL) { /* check for empty value */ if (isEmpty()) result = EC_Normal; else { DcmItem *ditem = new DcmItem(); if (ditem != NULL) { /* write Code */ if (isValid()) result = writeItem(*ditem); if (result.good()) dseq->insert(ditem); else delete ditem; } else result = EC_MemoryExhausted; } if (result.good()) result= dataset.insert(dseq, OFTrue /*replaceOld*/); if (result.bad()) delete dseq; } return result; } OFCondition DSRCodedEntryValue::writeSequenceItem(DcmItem &item, const DcmTagKey & /*tagKey*/) const { /* call the real function, which is "protected" */ return writeItem(item); } OFCondition DSRCodedEntryValue::readXML(const DSRXMLDocument &doc, DSRXMLCursor cursor, const size_t /*flags*/) { OFCondition result = SR_EC_CorruptedXMLStructure; if (cursor.valid()) { /* check whether code is stored as XML attributes */ if (doc.hasAttribute(cursor, "codValue")) { doc.getStringFromAttribute(cursor, CodeValue, "codValue", OFTrue /*encoding*/); doc.getStringFromAttribute(cursor, CodingSchemeDesignator, "codScheme", OFTrue /*encoding*/); doc.getStringFromAttribute(cursor, CodingSchemeVersion, "codVersion", OFTrue /*encoding*/, OFFalse /*required*/); doc.getStringFromNodeContent(cursor, CodeMeaning, NULL /*name*/, OFTrue /*encoding*/); } else { /* goto first child node */ cursor.gotoChild(); /* iterate over all content items */ while (cursor.valid()) { /* check for known element tags */ if (doc.matchNode(cursor, "scheme")) { doc.getStringFromNodeContent(doc.getNamedChildNode(cursor, "designator"), CodingSchemeDesignator, NULL /*name*/, OFTrue /*encoding*/, OFFalse /*clearString*/); doc.getStringFromNodeContent(doc.getNamedChildNode(cursor, "version", OFFalse /*required*/), CodingSchemeVersion, NULL /*name*/, OFTrue /*encoding*/, OFFalse /*clearString*/); } else { doc.getStringFromNodeContent(cursor, CodeValue, "value", OFTrue /*encoding*/, OFFalse /*clearString*/); doc.getStringFromNodeContent(cursor, CodeMeaning, "meaning", OFTrue /*encoding*/, OFFalse /*clearString*/); } /* proceed with next node */ cursor.gotoNext(); } } CodeValueType = determineCodeValueType(CodeValue); /* check whether code is valid */ result = isValid() ? EC_Normal : SR_EC_InvalidValue; } return result; } OFCondition DSRCodedEntryValue::writeXML(STD_NAMESPACE ostream &stream, const size_t flags) const { OFString tmpString; if (flags & DSRTypes::XF_codeComponentsAsAttribute) { stream << " codValue=\"" << DSRTypes::convertToXMLString(CodeValue, tmpString) << "\""; stream << " codScheme=\"" << DSRTypes::convertToXMLString(CodingSchemeDesignator, tmpString) << "\""; if (!CodingSchemeVersion.empty() || (flags & DSRTypes::XF_writeEmptyTags)) stream << " codVersion=\"" << DSRTypes::convertToXMLString(CodingSchemeVersion, tmpString) << "\""; stream << ">"; // close open bracket from calling routine stream << DSRTypes::convertToXMLString(CodeMeaning, tmpString); } else { DSRTypes::writeStringValueToXML(stream, CodeValue, "value", (flags & DSRTypes::XF_writeEmptyTags) > 0); stream << "" << OFendl; DSRTypes::writeStringValueToXML(stream, CodingSchemeDesignator, "designator", (flags & DSRTypes::XF_writeEmptyTags) > 0); DSRTypes::writeStringValueToXML(stream, CodingSchemeVersion, "version", (flags & DSRTypes::XF_writeEmptyTags) > 0); stream << "" << OFendl; DSRTypes::writeStringValueToXML(stream, CodeMeaning, "meaning", (flags & DSRTypes::XF_writeEmptyTags) > 0); } return EC_Normal; } OFCondition DSRCodedEntryValue::renderHTML(STD_NAMESPACE ostream &stream, const size_t flags, const OFBool fullCode, const OFBool valueFirst) const { OFString htmlString; if (flags & DSRTypes::HF_useCodeDetailsTooltip) { /* render code details as a tooltip */ stream << ""; /* render value */ if (valueFirst) stream << DSRTypes::convertToHTMLString(CodeValue, htmlString, flags); else stream << DSRTypes::convertToHTMLString(CodeMeaning, htmlString, flags); stream << ""; } else { /* render code in a conventional manner */ if (valueFirst) stream << DSRTypes::convertToHTMLString(CodeValue, htmlString, flags); else stream << DSRTypes::convertToHTMLString(CodeMeaning, htmlString, flags); if (fullCode) { stream << " ("; if (!valueFirst) stream << DSRTypes::convertToHTMLString(CodeValue, htmlString, flags) << ", "; stream << DSRTypes::convertToHTMLString(CodingSchemeDesignator, htmlString, flags); if (!CodingSchemeVersion.empty()) stream << " [" << DSRTypes::convertToHTMLString(CodingSchemeVersion, htmlString, flags) << "]"; if (valueFirst) stream << ", "" << DSRTypes::convertToHTMLString(CodeMeaning, htmlString, flags) << """; stream << ")"; } } return EC_Normal; } OFCondition DSRCodedEntryValue::getValue(DSRCodedEntryValue &codedEntryValue) const { codedEntryValue = *this; return EC_Normal; } OFCondition DSRCodedEntryValue::setValue(const DSRCodedEntryValue &codedEntryValue, const OFBool check) { /* first set "Basic Coded Entry Attributes" */ OFCondition result = setCode(codedEntryValue.CodeValue, codedEntryValue.CodingSchemeDesignator, codedEntryValue.CodingSchemeVersion, codedEntryValue.CodeMeaning, codedEntryValue.CodeValueType, check); /* then handle "Enhanced Encoding Mode" (if present) */ if (result.good()) { if (!codedEntryValue.ContextIdentifier.empty()) { /* specify details for a non-private context group */ result = setEnhancedEncodingMode(codedEntryValue.ContextIdentifier, codedEntryValue.MappingResource, codedEntryValue.ContextGroupVersion, codedEntryValue.ContextUID, codedEntryValue.ContextGroupLocalVersion, codedEntryValue.ContextGroupExtensionCreatorUID, check); } else if (!codedEntryValue.ContextUID.empty()) { /* specify details for a private context group */ result = setEnhancedEncodingMode(codedEntryValue.ContextUID, check); } } return result; } OFCondition DSRCodedEntryValue::setCode(const DSRBasicCodedEntry &basicCodedEntry, const OFBool check) { /* set "Basic Coded Entry Attributes" */ return setCode(basicCodedEntry.CodeValue, basicCodedEntry.CodingSchemeDesignator, basicCodedEntry.CodingSchemeVersion, basicCodedEntry.CodeMeaning, basicCodedEntry.CodeValueType, check); } OFCondition DSRCodedEntryValue::setCode(const OFString &codeValue, const OFString &codingSchemeDesignator, const OFString &codeMeaning, const DSRTypes::E_CodeValueType codeValueType, const OFExplicitBool check) { /* call the real function */ return setCode(codeValue, codingSchemeDesignator, "" /*codingSchemeVersion*/, codeMeaning, codeValueType, check); } OFCondition DSRCodedEntryValue::setCode(const OFString &codeValue, const OFString &codingSchemeDesignator, const OFString &codingSchemeVersion, const OFString &codeMeaning, const DSRTypes::E_CodeValueType codeValueType, const OFBool check) { OFCondition result = EC_Normal; const DSRTypes::E_CodeValueType actualCodeValueType = (codeValueType == DSRTypes::CVT_auto) ? determineCodeValueType(codeValue) : codeValueType; if (check) { /* check whether the passed values are valid */ result = checkCode(codeValue, codingSchemeDesignator, codingSchemeVersion, codeMeaning, actualCodeValueType); } else { /* make sure that the mandatory values are non-empty */ if (codeValue.empty() || (codingSchemeDesignator.empty() && (actualCodeValueType != DSRTypes::CVT_URN)) || codeMeaning.empty()) result = EC_IllegalParameter; } if (result.good()) { /* copy "Basic Coded Entry Attributes" */ CodeValueType = actualCodeValueType; CodeValue = codeValue; CodingSchemeDesignator = codingSchemeDesignator; CodingSchemeVersion = codingSchemeVersion; CodeMeaning = codeMeaning; /* clear attributes from "Enhanced Encoding Mode" */ removeEnhancedEncodingMode(); } return result; } OFBool DSRCodedEntryValue::usesEnhancedEncodingMode() const { /* this is currently a very simple check */ return !ContextIdentifier.empty() || !ContextUID.empty(); } void DSRCodedEntryValue::removeEnhancedEncodingMode() { ContextIdentifier.clear(); ContextUID.clear(); MappingResource.clear(); ContextGroupVersion.clear(); ContextGroupLocalVersion.clear(); ContextGroupExtensionCreatorUID.clear(); } OFCondition DSRCodedEntryValue::setEnhancedEncodingMode(const OFString &contextUID, const OFBool check) { OFCondition result = EC_Normal; /* first, make sure that the mandatory value is non-empty */ if (contextUID.empty()) result = EC_IllegalParameter; else if (check) { /* check whether the passed value is valid */ result = DcmUniqueIdentifier::checkStringValue(contextUID, "1"); } if (result.good()) { ContextUID = contextUID; /* clear all other attributes */ ContextIdentifier.clear(); MappingResource.clear(); ContextGroupVersion.clear(); ContextGroupLocalVersion.clear(); ContextGroupExtensionCreatorUID.clear(); } return result; } OFCondition DSRCodedEntryValue::setEnhancedEncodingMode(const OFString &contextIdentifier, const OFString &mappingResource, const OFString &contextGroupVersion, const OFString &contextUID, const OFString &localVersion, const OFString &extensionCreatorUID, const OFBool check) { OFCondition result = EC_Normal; /* first, make sure that the mandatory values are non-empty */ if (contextIdentifier.empty() || mappingResource.empty() || contextGroupVersion.empty()) result = EC_IllegalParameter; /* both values need to be empty or non-empty */ else if (localVersion.empty() != extensionCreatorUID.empty()) result = SR_EC_InvalidValue; else if (check) { /* check whether the passed values are valid */ result = DcmCodeString::checkStringValue(contextIdentifier, "1"); if (result.good()) result = DcmCodeString::checkStringValue(mappingResource, "1"); if (result.good()) result = DcmDateTime::checkStringValue(contextGroupVersion, "1"); if (result.good()) result = DcmUniqueIdentifier::checkStringValue(contextUID, "1"); if (result.good()) result = DcmDateTime::checkStringValue(localVersion, "1"); if (result.good()) result = DcmUniqueIdentifier::checkStringValue(extensionCreatorUID, "1"); } if (result.good()) { ContextIdentifier = contextIdentifier; MappingResource = mappingResource; ContextGroupVersion = contextGroupVersion; ContextUID = contextUID; ContextGroupLocalVersion = localVersion; ContextGroupExtensionCreatorUID = extensionCreatorUID; } return result; } OFCondition DSRCodedEntryValue::checkCurrentValue() const { /* call the real function */ return checkCode(CodeValue, CodingSchemeDesignator, CodingSchemeVersion, CodeMeaning, CodeValueType); } // static functions OFCondition DSRCodedEntryValue::checkCode(const OFString &codeValue, const OFString &codingSchemeDesignator, const OFString &codingSchemeVersion, const OFString &codeMeaning, const DSRTypes::E_CodeValueType codeValueType) { OFCondition result = EC_Normal; /* first, make sure that the mandatory values are non-empty and the type is valid */ if (codeValueType == DSRTypes::CVT_URN) { /* CP-1913: Coding Scheme Version shall not be present if Coding Scheme Designator is absent */ if (codeValue.empty() || (codingSchemeDesignator.empty() && !codingSchemeVersion.empty()) || codeMeaning.empty()) result = SR_EC_InvalidValue; } else if (codeValueType == DSRTypes::CVT_auto) { DCMSR_DEBUG("INTERNAL ERROR: DSRCodedEntryValue::checkCode() called with DSRTypes::CVT_auto"); result = EC_IllegalCall; } else { /* short or long code value */ if (codeValue.empty() || codingSchemeDesignator.empty() || codeMeaning.empty()) result = SR_EC_InvalidValue; } /* then, check whether the passed values are valid with regards to VR and VM. * tbd: unfortunately, we do not know the character set, so "UNKNOWN" is used. */ if (result.good()) { if (codeValueType == DSRTypes::CVT_Long) result = DcmUnlimitedCharacters::checkStringValue(codeValue, "1", "UNKNOWN"); else if (codeValueType == DSRTypes::CVT_URN) result = DcmUniversalResourceIdentifierOrLocator::checkStringValue(codeValue); else /* short or auto */ result = DcmShortString::checkStringValue(codeValue, "1", "UNKNOWN"); } if (result.good()) result = DcmShortString::checkStringValue(codingSchemeDesignator, "1", "UNKNOWN"); if (result.good()) result = DcmShortString::checkStringValue(codingSchemeVersion, "1", "UNKNOWN"); if (result.good()) result = DcmLongString::checkStringValue(codeMeaning, "1", "UNKNOWN"); /* tbd: also need to check correctness of the code (requires code dictionary) */ return result; } DSRTypes::E_CodeValueType DSRCodedEntryValue::determineCodeValueType(const OFString &codeValue) { DSRTypes::E_CodeValueType codeValueType = DSRTypes::CVT_auto; /* first, check for URN or URL scheme (not perfect but should do in most cases) */ if ((codeValue.compare(0, 4, "urn:") == 0) || (codeValue.find("://") != OFString_npos)) codeValueType = DSRTypes::CVT_URN; /* then, check maximum value length (tbd: should be characters not bytes!) */ else if (codeValue.length() > 16) codeValueType = DSRTypes::CVT_Long; else codeValueType = DSRTypes::CVT_Short; return codeValueType; } // output operators STD_NAMESPACE ostream &operator<<(STD_NAMESPACE ostream &stream, const DSRCodedEntryValue& codedEntryValue) { codedEntryValue.print(stream, OFTrue /*printCodeValue*/, DSRTypes::PF_printEmptyCodes /*flags*/); return stream; }