/* * * Copyright (C) 1994-2021, 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: dcmdata * * Author: Gerd Ehlers, Andreas Barth * * Purpose: Implementation of class DcmByteString * */ #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/ofstd/ofstring.h" #include "dcmtk/ofstd/ofstd.h" #include "dcmtk/dcmdata/dcjson.h" #include "dcmtk/dcmdata/dcbytstr.h" #include "dcmtk/dcmdata/dcvr.h" #include "dcmtk/dcmdata/dcmatch.h" // global flags OFGlobal dcmEnableVRCheckerForStringValues(OFTrue); // global function to get a particular component of a DICOM string OFCondition getStringPart(OFString &result, const char *str, const unsigned long len, const unsigned long pos) { OFCondition l_error = EC_Normal; /* check string parameter */ if (str != NULL) { /* search for beginning of specified string component */ unsigned long i = 0; unsigned long curPos = 0; while ((curPos < pos) && (i++ < len)) { if (*str++ == '\\') curPos++; } /* if found ... */ if (curPos == pos) { /* search for end of specified string component */ const char *p = str; while ((*p != '\\') && (i++ < len)) p++; /* check whether string component is non-empty */ if (p - str > 0) result.assign(str, p - str); else result.clear(); } else { /* specified component index not found in string */ l_error = EC_IllegalParameter; } } else l_error = EC_IllegalParameter; return l_error; } // ******************************** DcmByteString::DcmByteString(const DcmTag &tag) : DcmElement(tag, 0), paddingChar(' '), maxLength(DCM_UndefinedLength), realLength(0), fStringMode(DCM_UnknownString), nonSignificantChars() { } DcmByteString::DcmByteString(const DcmTag &tag, const Uint32 len) : DcmElement(tag, len), paddingChar(' '), maxLength(DCM_UndefinedLength), realLength(len), fStringMode(DCM_UnknownString), nonSignificantChars() { } DcmByteString::DcmByteString(const DcmByteString &old) : DcmElement(old), paddingChar(old.paddingChar), maxLength(old.maxLength), realLength(old.realLength), fStringMode(old.fStringMode), nonSignificantChars(old.nonSignificantChars) { } DcmByteString::~DcmByteString() { } DcmByteString &DcmByteString::operator=(const DcmByteString &obj) { if (this != &obj) { DcmElement::operator=(obj); /* copy member variables */ paddingChar = obj.paddingChar; maxLength = obj.maxLength; realLength = obj.realLength; fStringMode = obj.fStringMode; nonSignificantChars = obj.nonSignificantChars; } return *this; } int DcmByteString::compare(const DcmElement& rhs) const { int result = DcmElement::compare(rhs); if (result != 0) { return result; } /* cast away constness (dcmdata is not const correct...) */ DcmByteString* myThis = NULL; DcmByteString* myRhs = NULL; myThis = OFconst_cast(DcmByteString*, this); myRhs = OFstatic_cast(DcmByteString*, OFconst_cast(DcmElement*, &rhs)); /* compare number of values */ unsigned long rhsNumValues = myRhs->getNumberOfValues(); unsigned long thisNumValues = myThis->getNumberOfValues(); if (thisNumValues < rhsNumValues) { return -1; } else if (thisNumValues > rhsNumValues) { return 1; } /* iterate over all components and test equality */ for (unsigned long count = 0; count < thisNumValues; count++) { OFString val; if (myThis->getOFString(val, count).good()) { OFString rhsVal; if (myRhs->getOFString(rhsVal, count).good()) { result = val.compare(rhsVal); if (result != 0) { return result; } } } } /* all values equal */ return 0; } OFCondition DcmByteString::copyFrom(const DcmObject& rhs) { if (this != &rhs) { if (rhs.ident() != ident()) return EC_IllegalCall; *this = OFstatic_cast(const DcmByteString &, rhs); } return EC_Normal; } // ******************************** DcmEVR DcmByteString::ident() const { /* valid type identifier is set by derived classes */ return EVR_UNKNOWN; } unsigned long DcmByteString::getVM() { char *str = NULL; Uint32 len = 0; /* get stored string value */ getString(str, len); /* and determine the VM */ return DcmElement::determineVM(str, len); } unsigned long DcmByteString::getNumberOfValues() { /* same as value multiplicity unless overwritten in a derived class */ return getVM(); } OFCondition DcmByteString::clear() { /* call inherited method */ errorFlag = DcmElement::clear(); /* set string representation to unknown */ fStringMode = DCM_UnknownString; realLength = 0; return errorFlag; } Uint32 DcmByteString::getRealLength() { /* convert string to internal representation (if required) */ if (fStringMode != DCM_MachineString) { /* strips non-significant trailing spaces (padding) and determines 'realLength' */ makeMachineByteString(); } /* string length of the internal representation */ return realLength; } Uint32 DcmByteString::getLength(const E_TransferSyntax /*xfer*/, const E_EncodingType /*enctype*/) { /* convert string to DICOM representation, i.e. add padding if required */ makeDicomByteString(); /* DICOM value length is always an even number */ return getLengthField(); } // ******************************** void DcmByteString::print(STD_NAMESPACE ostream& out, const size_t flags, const int level, const char * /*pixelFileName*/, size_t * /*pixelCounter*/) { if (valueLoaded()) { /* get string data */ char *stringVal = NULL; Uint32 stringLen = 0; getString(stringVal, stringLen); if ((stringVal != NULL) && (stringLen > 0)) { /* print line start with tag and VR */ printInfoLineStart(out, flags, level); out << '['; OFString outString; /* do not create more output than actually needed */ const size_t outStrLen = (flags & DCMTypes::PF_shortenLongTagValues) ? DCM_OptPrintLineLength : 0 /* all characters */; /* check whether string has to be converted to markup or octal representation */ if (flags & DCMTypes::PF_convertToMarkup) { OFString inString(stringVal, stringLen); OFStandard::convertToMarkupString(inString, outString, OFTrue, OFStandard::MM_XML, OFFalse, outStrLen); } else if (flags & DCMTypes::PF_convertToOctalNumbers) { OFString inString(stringVal, stringLen); OFStandard::convertToOctalString(inString, outString, outStrLen); } else { /* check whether we need the full string or the prefix only */ if ((outStrLen == 0) || (outStrLen > stringLen)) outString.assign(stringVal, stringLen); else outString.assign(stringVal, outStrLen); } size_t printedLength = outString.length() + 2 /* for enclosing brackets */; /* check whether full value text should be printed */ if ((flags & DCMTypes::PF_shortenLongTagValues) && (printedLength > DCM_OptPrintLineLength)) { /* truncate value text and append "..." */ outString.erase(DCM_OptPrintLineLength - 4); out << outString << "..."; printedLength = DCM_OptPrintLineLength; } else out << outString << ']'; /* print line end with length, VM and tag name */ printInfoLineEnd(out, flags, OFstatic_cast(unsigned long, printedLength)); } else printInfoLine(out, flags, level, "(no value available)"); } else printInfoLine(out, flags, level, "(not loaded)"); } // ******************************** OFCondition DcmByteString::write(DcmOutputStream &outStream, const E_TransferSyntax oxfer, const E_EncodingType enctype, DcmWriteCache *wcache) { if (getTransferState() == ERW_notInitialized) errorFlag = EC_IllegalCall; else { /* convert string value to DICOM representation and call inherited method */ if (getTransferState() == ERW_init) makeDicomByteString(); errorFlag = DcmElement::write(outStream, oxfer, enctype, wcache); } return errorFlag; } OFCondition DcmByteString::writeSignatureFormat(DcmOutputStream &outStream, const E_TransferSyntax oxfer, const E_EncodingType enctype, DcmWriteCache *wcache) { if (getTransferState() == ERW_notInitialized) errorFlag = EC_IllegalCall; else { /* convert string value to DICOM representation and call inherited method */ if (getTransferState() == ERW_init) makeDicomByteString(); errorFlag = DcmElement::writeSignatureFormat(outStream, oxfer, enctype, wcache); } return errorFlag; } // ******************************** OFCondition DcmByteString::getOFString(OFString &stringVal, const unsigned long pos, OFBool /*normalize*/) { /* check given string position index */ if (pos >= getVM()) { /* treat an empty string as a special case */ if (pos == 0) { errorFlag = EC_Normal; stringVal.clear(); } else errorFlag = EC_IllegalParameter; } else { /* get string data */ char *str = NULL; Uint32 len = 0; errorFlag = getString(str, len); /* check whether string value is present */ if ((str != NULL) && (len > 0)) { /* extract specified string component */ errorFlag = getStringPart(stringVal, str, len, pos); } else stringVal.clear(); } return errorFlag; } OFCondition DcmByteString::getOFStringArray(OFString &stringVal, OFBool normalize) { /* check whether time-consuming normalization is really needed */ if (normalize) errorFlag = DcmElement::getOFStringArray(stringVal, normalize); else errorFlag = getStringValue(stringVal); return errorFlag; } OFCondition DcmByteString::getStringValue(OFString &stringVal) { char *str = NULL; Uint32 len = 0; errorFlag = getString(str, len); /* check whether string value is present */ if ((str != NULL) && (len > 0)) stringVal.assign(str, len); else stringVal.clear(); return errorFlag; } OFCondition DcmByteString::getString(char *&stringVal) { errorFlag = EC_Normal; /* get string data */ stringVal = OFstatic_cast(char *, getValue()); /* convert to internal string representation (without padding) if required */ if ((stringVal != NULL) && (fStringMode != DCM_MachineString)) makeMachineByteString(); return errorFlag; } OFCondition DcmByteString::getString(char *&stringVal, Uint32 &stringLen) { /* get string data */ errorFlag = getString(stringVal); /* return the real length of the value */ stringLen = realLength; return errorFlag; } // ******************************** OFCondition DcmByteString::putString(const char *stringVal) { /* determine length of the string value */ const size_t stringLen = (stringVal != NULL) ? strlen(stringVal) : 0; /* call the real function */ return putString(stringVal, OFstatic_cast(Uint32, stringLen)); } OFCondition DcmByteString::putString(const char *stringVal, const Uint32 stringLen) { errorFlag = EC_Normal; /* check for an empty string parameter */ if ((stringVal != NULL) && (stringLen > 0)) putValue(stringVal, stringLen); else putValue(NULL, 0); /* make sure that extra padding is removed from the string */ fStringMode = DCM_UnknownString; makeMachineByteString(stringLen); return errorFlag; } OFCondition DcmByteString::putOFStringAtPos(const OFString& stringVal, const unsigned long pos) { OFCondition result; // Get old value OFString str; result = getOFStringArray( str ); if (result.good()) { size_t currentVM = getNumberOfValues(); // Trivial case: No values are set and new value should go to first position if ( (currentVM == 0) && (pos == 0)) return putOFStringArray(stringVal); // 1st case: Insert at the end // If we insert at a position that does not yet exist, append missing number of components by // adding the corresponding number of backspace chars, append new float value and return. size_t futureVM = pos + 1; if (futureVM > currentVM) { str = str.append(currentVM == 0 ? futureVM - currentVM - 1 : futureVM - currentVM, '\\'); str = str.append(stringVal); return putOFStringArray(str); } // 2nd case: New value should be at position 0 size_t rightPos = 0; if (pos == 0) { // First value is empty: Insert new value if (str[0] == '\\') { str = str.insert(0, stringVal); } // First value is set: Replace old value with new value else { rightPos = str.find_first_of('\\', 0); str = str.replace(0, rightPos, stringVal); } return putOFStringArray(str); } // 3rd case: New value should be inserted somewhere in the middle size_t leftPos = 0; size_t vmPos = 0; // First, find the correct position, and then insert / replace new value do { // Step from value to value by looking for delimiters. // Special handling first search (start looking at position 0 instead of 1) if (vmPos == 0) leftPos = str.find('\\', 0); else leftPos = str.find('\\', leftPos + 1 ); // leftPos = str.find('\\', leftPos == 0 ? 0 : leftPos +1); if (leftPos != OFString_npos) { vmPos++; } } while ( (leftPos != OFString_npos) && (vmPos != pos) ); rightPos = str.find_first_of('\\', leftPos+1); if (rightPos == OFString_npos) rightPos = str.length(); // If we do not have an old value of size 1 or we have an empty value if (rightPos - leftPos == 1) { // Empty value if (str.at(leftPos) == '\\') str = str.insert(rightPos, stringVal); // Old value (length 1) else str = str.replace(leftPos, 1, stringVal); } // Otherwise replace existing old value (length > 1) else { str = str.replace(leftPos+1, rightPos - leftPos, stringVal); } // Finally re-insert all values include new value result = putOFStringArray( str ); } return result; } // ******************************** OFCondition DcmByteString::makeDicomByteString() { /* get string data */ char *value = NULL; errorFlag = getString(value); if (value != NULL) { /* check for odd length */ if (realLength & 1) { /* if so add a padding character */ setLengthField(realLength + 1); value[realLength] = paddingChar; } else if (realLength < getLengthField()) setLengthField(realLength); /* terminate string (removes additional trailing padding characters) */ value[getLengthField()] = '\0'; } /* current string representation is now the DICOM one */ fStringMode = DCM_DicomString; return errorFlag; } OFCondition DcmByteString::makeMachineByteString(const Uint32 length) { errorFlag = EC_Normal; /* get string data */ char *value = OFstatic_cast(char *, getValue()); if (value != NULL) { /* check whether string representation is not the internal one */ if (fStringMode != DCM_MachineString) { /* determine initial string length */ realLength = (length == 0) ? getLengthField() : length; /* remove all trailing spaces if automatic input data correction is enabled */ if (dcmEnableAutomaticInputDataCorrection.get()) { /* ** This code removes extra padding characters at the end of a ByteString. ** Trailing padding can cause problems when comparing strings. This kind ** of padding is non-significant for all string-based value representations. */ if (realLength > 0) { size_t i = OFstatic_cast(size_t, realLength); while ((i > 0) && (value[i - 1] == paddingChar)) value[--i] = '\0'; realLength = OFstatic_cast(Uint32, i); } } } } else realLength = 0; /* current string representation is now the internal one */ fStringMode = DCM_MachineString; return errorFlag; } // ******************************** Uint8 *DcmByteString::newValueField() { Uint8 *value = NULL; Uint32 lengthField = getLengthField(); /* check for odd length (in case of a protocol error) */ if (lengthField & 1) { if (lengthField == DCM_UndefinedLength) { /* Print an error message when private attribute states to have an odd length * equal to the maximum length, because we are not able then to make this value even (+1) * which would an overflow on some systems as well as being illegal in DICOM */ DCMDATA_WARN("DcmByteString: Element " << getTagName() << " " << getTag() << " has odd maximum length (" << DCM_UndefinedLength << ") and therefore is not loaded"); errorFlag = EC_CorruptedData; return NULL; } /* allocate space for extra padding character (required for the DICOM representation of the string) */ #ifdef HAVE_STD__NOTHROW // we want to use a non-throwing new here if available. // If the allocation fails, we report an EC_MemoryExhausted error // back to the caller. value = new (std::nothrow) Uint8[lengthField + 2]; #else /* make sure that the pointer is set to NULL in case of error */ try { value = new Uint8[lengthField + 2]; } catch (STD_NAMESPACE bad_alloc const &) { value = NULL; } #endif /* terminate string after real length */ if (value != NULL) value[lengthField] = 0; /* enforce old (pre DCMTK 3.5.2) behaviour? */ if (!dcmAcceptOddAttributeLength.get()) { /* make length even */ lengthField++; setLengthField(lengthField); } } else { /* length is even, but we need an extra byte for the terminating 0 byte */ #ifdef HAVE_STD__NOTHROW // we want to use a non-throwing new here if available. // If the allocation fails, we report an EC_MemoryExhausted error // back to the caller. value = new (std::nothrow) Uint8[lengthField + 1]; #else /* make sure that the pointer is set to NULL in case of error */ try { value = new Uint8[lengthField + 1]; } catch (STD_NAMESPACE bad_alloc const &) { value = NULL; } #endif } /* make sure that the string is properly terminated by a 0 byte */ if (value != NULL) value[lengthField] = 0; else errorFlag = EC_MemoryExhausted; return value; } // ******************************** void DcmByteString::postLoadValue() { /* initially, after loading an attribute the string mode is unknown */ fStringMode = DCM_UnknownString; /* correct value length if automatic input data correction is enabled */ if (dcmEnableAutomaticInputDataCorrection.get()) { /* check for odd length */ if (getLengthField() & 1) { // newValueField always allocates an even number of bytes and sets // the pad byte to zero, so we can safely increase Length here. setLengthField(getLengthField() + 1); } } } // ******************************** OFCondition DcmByteString::verify(const OFBool autocorrect) { char *str = NULL; Uint32 len = 0; /* get string data */ errorFlag = getString(str, len); /* check for non-empty string */ if ((str != NULL) && (len > 0)) { /* check whether there is anything to verify at all */ if (maxLength != DCM_UndefinedLength) { const unsigned long vm = getVM(); /* TODO: is it really a good idea to create a copy of the string? */ OFString value(str, len); size_t posStart = 0; unsigned long vmNum = 0; /* check all string components */ while (posStart != OFString_npos) { ++vmNum; /* search for next component separator */ size_t posEnd = (vm > 1) ? value.find('\\', posStart) : OFString_npos; const size_t fieldLen = (posEnd == OFString_npos) ? value.length() - posStart : posEnd - posStart; /* check size limit for each string component */ if (fieldLen > maxLength) { DCMDATA_DEBUG("DcmByteString::verify() Maximum length violated in element " << getTagName() << " " << getTag() << " value " << vmNum << ": " << fieldLen << " bytes found but only " << maxLength << " bytes allowed"); errorFlag = EC_MaximumLengthViolated; if (autocorrect) { const size_t excess = fieldLen - maxLength; DCMDATA_DEBUG("DcmByteString::verify() Removing " << excess << " bytes from the end of value " << vmNum); /* erase excessive part of the string component */ value.erase(posStart + maxLength, excess); /* correct the position end marker */ posEnd -= excess; } } posStart = (posEnd == OFString_npos) ? posEnd : posEnd + 1; } /* replace current string value if auto correction is enabled */ if (autocorrect && errorFlag.bad()) { putOFStringArray(value); /* the above method also sets 'errorFlag', so we need to assign the error code again */ errorFlag = EC_MaximumLengthViolated; } } } /* report a debug message if an error occurred */ if (errorFlag.bad()) { DCMDATA_WARN("DcmByteString: One or more illegal values in element " << getTagName() << " " << getTag() << " with VM=" << getVM()); } return errorFlag; } OFBool DcmByteString::containsExtendedCharacters(const OFBool checkAllStrings) { OFBool result = OFFalse; /* only check if parameter is true since derived VRs are not affected by the attribute SpecificCharacterSet (0008,0005) */ if (checkAllStrings) { char *str = NULL; Uint32 len = 0; /* determine length in order to support possibly embedded NULL bytes */ if (getString(str, len).good()) result = containsExtendedCharacters(str, len); } return result; } OFBool DcmByteString::isAffectedBySpecificCharacterSet() const { return OFFalse; } // ******************************** OFBool DcmByteString::isEmpty(const OFBool normalize) { OFBool result = OFFalse; if (normalize && !nonSignificantChars.empty()) { OFString value; DcmByteString::getStringValue(value); /* check whether string value consists of non-significant characters only */ result = (value.find_first_not_of(nonSignificantChars) == OFString_npos); } else result = DcmObject::isEmpty(normalize); return result; } // ******************************** // global function for normalizing a DICOM string void normalizeString(OFString &string, const OFBool multiPart, const OFBool leading, const OFBool trailing, const char paddingChar) { /* check for non-empty string */ if (!string.empty()) { size_t partindex = 0; size_t offset = 0; size_t len = string.length(); while (partindex < len) { // remove leading spaces in every part of the string if (leading) { offset = 0; while ((partindex + offset < len) && (string[partindex + offset] == paddingChar)) offset++; if (offset > 0) string.erase(partindex, offset); } len = string.length(); // compute begin to the next separator index! if (multiPart) { partindex = string.find('\\', partindex); if (partindex == OFString_npos) partindex = len; } else partindex = len; // remove trailing spaces in every part of the string if (trailing && partindex) { offset = partindex - 1; while ((offset > 0) && (string[offset] == paddingChar)) offset--; if (offset != partindex - 1) { if (string[offset] == ' ') { string.erase(offset, partindex - offset); partindex = offset; } else { string.erase(offset + 1, partindex - offset - 1); partindex = offset + 1; } } } len = string.length(); if (partindex != len) ++partindex; } } } // ******************************** OFBool DcmByteString::containsExtendedCharacters(const char *stringVal, const size_t stringLen) { if (stringVal != NULL) { for (size_t i = stringLen; i != 0; --i) { /* check for 8 bit characters */ if (OFstatic_cast(unsigned char, *stringVal++) > 127) return OFTrue; } } return OFFalse; } // ******************************** OFCondition DcmByteString::checkStringValue(const OFString &value, const OFString &vm, const OFString &vr, const int vrID, const size_t maxLen, const OFString &charset) { OFCondition result = EC_Normal; const size_t valLen = value.length(); if (valLen > 0) { /* do we need to search for value components at all? */ if (vm.empty()) { /* check value length (if a maximum is specified) */ if ((maxLen > 0) && (value.length() > maxLen)) result = EC_MaximumLengthViolated; else if (dcmEnableVRCheckerForStringValues.get()) { /* check for non-ASCII characters (if default character set used) */ if (charset.empty() || (charset == "ISO_IR 6")) { if (containsExtendedCharacters(value.c_str(), value.length())) result = EC_InvalidCharacter; } if (result.good()) { /* currently, the VR checker only supports ASCII and Latin-1 */ if (charset.empty() || (charset == "ISO_IR 6") || (charset == "ISO_IR 100")) { /* check value representation (VR) */ if (DcmElement::scanValue(value, vr) != vrID) result = EC_ValueRepresentationViolated; } } } } else { size_t posStart = 0; unsigned long vmNum = 0; /* iterate over all value components */ while (posStart != OFString_npos) { ++vmNum; /* search for next component separator */ const size_t posEnd = value.find('\\', posStart); const size_t length = (posEnd == OFString_npos) ? valLen - posStart : posEnd - posStart; /* check length of current value component */ if ((maxLen > 0) && (length > maxLen)) { result = EC_MaximumLengthViolated; break; } else if (dcmEnableVRCheckerForStringValues.get()) { /* check for non-ASCII characters (if default character set used) */ if (charset.empty() || (charset == "ISO_IR 6")) { if (containsExtendedCharacters(value.c_str() + posStart, length)) { result = EC_InvalidCharacter; break; } } /* currently, the VR checker only supports ASCII and Latin-1 */ if (charset.empty() || (charset == "ISO_IR 6") || (charset == "ISO_IR 100")) { /* check value representation (VR) */ if (DcmElement::scanValue(value, vr, posStart, length) != vrID) { result = EC_ValueRepresentationViolated; break; } } } posStart = (posEnd == OFString_npos) ? posEnd : posEnd + 1; } if (result.good()) { /* check value multiplicity (VM) */ result = DcmElement::checkVM(vmNum, vm); } } } return result; } // ******************************** OFCondition DcmByteString::writeJson(STD_NAMESPACE ostream &out, DcmJsonFormat &format) { /* always write JSON Opener */ DcmElement::writeJsonOpener(out, format); /* write element value (if non-empty) */ if (!isEmpty()) { OFString value; OFCondition status = getOFString(value, 0L); if (status.bad()) return status; format.printValuePrefix(out); DcmJsonFormat::printValueString(out, value); const unsigned long vm = getVM(); for (unsigned long valNo = 1; valNo < vm; ++valNo) { status = getOFString(value, valNo); if (status.bad()) return status; format.printNextArrayElementPrefix(out); DcmJsonFormat::printValueString(out, value); } format.printValueSuffix(out); } /* write JSON Closer */ DcmElement::writeJsonCloser(out, format); /* always report success */ return EC_Normal; } OFBool DcmByteString::matches(const DcmElement& candidate, const OFBool enableWildCardMatching) const { if (ident() == candidate.ident()) { // some const casts to call the getter functions, I do not modify the values, I promise! DcmByteString& key = OFconst_cast(DcmByteString&,*this); DcmElement& can = OFconst_cast(DcmElement&,candidate); OFString a, b; for (unsigned long ui = 0; ui < key.getVM(); ++ui) for (unsigned long uj = 0; uj < can.getVM(); ++uj) if( key.getOFString( a, ui, OFTrue ).good() && can.getOFString( b, uj, OFTrue ).good() && matches( a, b, enableWildCardMatching ) ) return OFTrue; return key.getVM() == 0; } return OFFalse; } OFBool DcmByteString::matches(const OFString& key, const OFString& candidate, const OFBool enableWildCardMatching) const { OFstatic_cast(void,enableWildCardMatching); // Universal Matching || Single Value Matching return key.empty() || key == candidate; }