/* * * 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 DcmDataset * */ #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/ofstd/ofstack.h" #include "dcmtk/ofstd/ofstd.h" #include "dcmtk/dcmdata/dcjson.h" #include "dcmtk/dcmdata/dcdatset.h" #include "dcmtk/dcmdata/dcxfer.h" #include "dcmtk/dcmdata/dcvrus.h" #include "dcmtk/dcmdata/dcpixel.h" #include "dcmtk/dcmdata/dcdeftag.h" #include "dcmtk/dcmdata/dcistrma.h" /* for class DcmInputStream */ #include "dcmtk/dcmdata/dcistrmf.h" /* for class DcmInputFileStream */ #include "dcmtk/dcmdata/dcistrms.h" /* for class DcmStdinStream */ #include "dcmtk/dcmdata/dcostrma.h" /* for class DcmOutputStream */ #include "dcmtk/dcmdata/dcostrmf.h" /* for class DcmOutputFileStream */ #include "dcmtk/dcmdata/dcostrms.h" /* for class DcmStdoutStream */ #include "dcmtk/dcmdata/dcwcache.h" /* for class DcmWriteCache */ // ******************************** DcmDataset::DcmDataset() : DcmItem(DCM_ItemTag, DCM_UndefinedLength), OriginalXfer(EXS_Unknown), // the default transfer syntax is explicit VR with local endianness CurrentXfer((gLocalByteOrder == EBO_BigEndian) ? EXS_BigEndianExplicit : EXS_LittleEndianExplicit) { } DcmDataset& DcmDataset::operator=(const DcmDataset& obj) { if (this != &obj) { // copy parent's member variables DcmItem::operator=(obj); // copy DcmDataset's member variables OriginalXfer = obj.OriginalXfer; CurrentXfer = obj.CurrentXfer; } return *this; } DcmDataset::DcmDataset(const DcmDataset &old) : DcmItem(old), OriginalXfer(old.OriginalXfer), CurrentXfer(old.CurrentXfer) { } OFCondition DcmDataset::copyFrom(const DcmObject& rhs) { if (this != &rhs) { if (rhs.ident() != ident()) return EC_IllegalCall; *this = OFstatic_cast(const DcmDataset &, rhs); } return EC_Normal; } DcmDataset::~DcmDataset() { } // ******************************** OFCondition DcmDataset::clear() { OFCondition result = DcmItem::clear(); // TODO: should we also reset OriginalXfer and CurrentXfer? setLengthField(DCM_UndefinedLength); return result; } DcmEVR DcmDataset::ident() const { return EVR_dataset; } E_TransferSyntax DcmDataset::getOriginalXfer() const { return OriginalXfer; } E_TransferSyntax DcmDataset::getCurrentXfer() const { return CurrentXfer; } void DcmDataset::updateOriginalXfer() { DcmStack resultStack; /* Check for pixel data element on main dataset level only. */ /* Icon images and other nested pixel data elements are not checked. */ if (search(DCM_PixelData, resultStack, ESM_fromHere, OFFalse).good()) { if (resultStack.top()->ident() == EVR_PixelData) { /* determine the transfer syntax of the original and current representation */ E_TransferSyntax repType = EXS_Unknown; const DcmRepresentationParameter *repParam = NULL; DcmPixelData *pixelData = OFstatic_cast(DcmPixelData *, resultStack.top()); pixelData->getOriginalRepresentationKey(OriginalXfer, repParam); pixelData->getCurrentRepresentationKey(repType, repParam); /* check whether we also need to change the current transfer syntax */ if (repType == EXS_LittleEndianExplicit /* default */) { /* only change the value if not already uncompressed */ if ((CurrentXfer != EXS_LittleEndianImplicit) && (CurrentXfer != EXS_LittleEndianExplicit) && (CurrentXfer != EXS_BigEndianExplicit)) { CurrentXfer = repType; } } else if (repType != EXS_Unknown) { CurrentXfer = repType; } } else { /* something is fishy with the pixel data element (wrong class) */ DCMDATA_WARN("DcmDataset: Wrong class for pixel data element, cannot update original transfer syntax"); } } /* if no pixel data was found, update only in case of unknown representation */ else { if (OriginalXfer == EXS_Unknown) { /* this is also the default in DcmPixelData::getOriginalRepresentationKey() */ OriginalXfer = EXS_LittleEndianExplicit; } if (CurrentXfer == EXS_Unknown) { /* this is also the default in DcmPixelData::getCurrentRepresentationKey() */ CurrentXfer = EXS_LittleEndianExplicit; } } } void DcmDataset::removeInvalidGroups(const OFBool cmdSet) { DcmStack stack; DcmObject *object = NULL; /* check for data or command set */ if (cmdSet) { /* iterate over all elements */ while (nextObject(stack, OFTrue).good()) { object = stack.top(); /* in command sets, only group 0x0000 is allowed */ if (object->getGTag() != 0x0000) { DCMDATA_DEBUG("DcmDataset::removeInvalidGroups() removing element " << object->getTag() << " from command set"); stack.pop(); /* remove element from command set and free memory */ delete OFstatic_cast(DcmItem *, stack.top())->remove(object); } } } else { /* iterate over all elements */ while (nextObject(stack, OFTrue).good()) { object = stack.top(); /* in data sets, group 0x0000 to 0x0003, 0x0005, 0x0007 and 0xFFFF are not allowed */ if ((object->getGTag() == 0x0000) || (object->getGTag() == 0x0002) || !object->getTag().hasValidGroup()) { DCMDATA_DEBUG("DcmDataset::removeInvalidGroups() removing element " << object->getTag() << " from data set"); stack.pop(); /* remove element from data set and free memory */ delete OFstatic_cast(DcmItem *, stack.top())->remove(object); } /* in sequence items, also group 0x0006 is not allowed */ else if ((stack.card() > 2) && (object->getGTag() == 0x0006)) { DCMDATA_DEBUG("DcmDataset::removeInvalidGroups() removing element " << object->getTag() << " from sequence item"); stack.pop(); /* remove element from data set and free memory */ delete OFstatic_cast(DcmItem *, stack.top())->remove(object); } } } } // ******************************** Uint32 DcmDataset::calcElementLength(const E_TransferSyntax xfer, const E_EncodingType enctype) { return DcmItem::getLength(xfer, enctype); } // ******************************** OFBool DcmDataset::canWriteXfer(const E_TransferSyntax newXfer, const E_TransferSyntax oldXfer) { if (newXfer == EXS_Unknown) return OFFalse; /* Check stream compression for this transfer syntax */ DcmXfer xf(newXfer); if (xf.getStreamCompression() == ESC_unsupported) return OFFalse; return DcmItem::canWriteXfer(newXfer, (OriginalXfer == EXS_Unknown) ? oldXfer : OriginalXfer); } // ******************************** void DcmDataset::print(STD_NAMESPACE ostream &out, const size_t flags, const int level, const char *pixelFileName, size_t *pixelCounter) { out << OFendl; if (flags & DCMTypes::PF_useANSIEscapeCodes) out << DCMDATA_ANSI_ESCAPE_CODE_COMMENT; printNestingLevel(out, flags, level); out << "# Dicom-Data-Set" << OFendl; if (flags & DCMTypes::PF_useANSIEscapeCodes) out << DCMDATA_ANSI_ESCAPE_CODE_COMMENT; printNestingLevel(out, flags, level); out << "# Used TransferSyntax: " << DcmXfer(CurrentXfer).getXferName(); if (flags & DCMTypes::PF_useANSIEscapeCodes) out << DCMDATA_ANSI_ESCAPE_CODE_RESET; out << OFendl; if (!elementList->empty()) { DcmObject *dO; elementList->seek(ELP_first); do { dO = elementList->get(); dO->print(out, flags, level + 1, pixelFileName, pixelCounter); } while (elementList->seek(ELP_next)); } } // ******************************** OFCondition DcmDataset::writeXML(STD_NAMESPACE ostream &out, const size_t flags) { OFCondition l_error = EC_Normal; /* the Native DICOM Model as defined for Application Hosting needs special handling */ if (flags & DCMTypes::XF_useNativeModel) { /* write XML start tag */ out << "" << OFendl; } else { /* DCMTK-specific output format (default) */ OFString xmlString; DcmXfer xfer(CurrentXfer); /* write XML start tag */ out << "" << OFendl; } /* write dataset content */ if (!elementList->empty()) { /* write content of all children */ DcmObject *dO; elementList->seek(ELP_first); do { dO = elementList->get(); l_error = dO->writeXML(out, flags & ~DCMTypes::XF_useXMLNamespace); } while (l_error.good() && elementList->seek(ELP_next)); } if (l_error.good()) { /* write XML end tag (depending on output format) */ if (flags & DCMTypes::XF_useNativeModel) { out << "" << OFendl; } else { out << "" << OFendl; } } return l_error; } // ******************************** OFCondition DcmDataset::writeJson(STD_NAMESPACE ostream &out, DcmJsonFormat &format) { return writeJsonExt(out, format, OFFalse, OFFalse); // omit braces } // ******************************** OFCondition DcmDataset::read(DcmInputStream &inStream, const E_TransferSyntax xfer, const E_GrpLenEncoding glenc, const Uint32 maxReadLength) { return DcmDataset::readUntilTag(inStream, xfer, glenc, maxReadLength, DCM_UndefinedTagKey); } OFCondition DcmDataset::readUntilTag(DcmInputStream &inStream, const E_TransferSyntax xfer, const E_GrpLenEncoding glenc, const Uint32 maxReadLength, const DcmTagKey &stopParsingAtElement) { /* check if the stream variable reported an error */ errorFlag = inStream.status(); /* if the stream did not report an error but the stream */ /* is empty, set the error flag correspondingly */ if (errorFlag.good() && inStream.eos()) errorFlag = EC_EndOfStream; /* else if the stream did not report an error but the transfer */ /* state does not equal ERW_ready, go ahead and do something */ else if (errorFlag.good() && getTransferState() != ERW_ready) { /* if the transfer state is ERW_init, go ahead and check the transfer syntax which was passed */ if (getTransferState() == ERW_init) { if (dcmAutoDetectDatasetXfer.get()) { DCMDATA_DEBUG("DcmDataset::read() automatic detection of transfer syntax is enabled"); /* To support incorrectly encoded datasets detect the transfer syntax from the stream. */ /* This is possible for given unknown and plain big or little endian transfer syntaxes. */ switch (xfer) { case EXS_Unknown: case EXS_LittleEndianImplicit: case EXS_LittleEndianExplicit: case EXS_BigEndianExplicit: case EXS_BigEndianImplicit: DCMDATA_DEBUG("DcmDataset::read() trying to detect transfer syntax of uncompressed data set"); OriginalXfer = checkTransferSyntax(inStream); if ((xfer != EXS_Unknown) && (OriginalXfer != xfer)) DCMDATA_WARN("DcmDataset: Wrong transfer syntax specified, detecting from data set"); break; default: DCMDATA_DEBUG("DcmDataset::read() data set seems to be compressed, so transfer syntax is not detected"); OriginalXfer = xfer; break; } } else /* default behavior */ { /* If the transfer syntax which was passed equals EXS_Unknown we want to */ /* determine the transfer syntax from the information in the stream itself. */ /* If the transfer syntax is given, we want to use it. */ if (xfer == EXS_Unknown) { DCMDATA_DEBUG("DcmDataset::read() trying to detect transfer syntax of data set (because it is unknown)"); OriginalXfer = checkTransferSyntax(inStream); } else OriginalXfer = xfer; } /* dump information on debug level */ DCMDATA_DEBUG("DcmDataset::read() TransferSyntax=\"" << DcmXfer(OriginalXfer).getXferName() << "\""); CurrentXfer = OriginalXfer; /* check stream compression for this transfer syntax */ DcmXfer xf(OriginalXfer); E_StreamCompression sc = xf.getStreamCompression(); switch (sc) { case ESC_none: // nothing to do break; case ESC_unsupported: // stream compressed transfer syntax that we cannot create; bail out. if (errorFlag.good()) errorFlag = EC_UnsupportedEncoding; break; default: // supported stream compressed transfer syntax, install filter errorFlag = inStream.installCompressionFilter(sc); break; } } /* pass processing the task to class DcmItem */ if (errorFlag.good()) errorFlag = DcmItem::readUntilTag(inStream, OriginalXfer, glenc, maxReadLength, stopParsingAtElement); } /* if the error flag shows ok or that the end of the stream was encountered, */ /* we have read information for this particular data set or command; in this */ /* case, we need to do something for the current dataset object */ if (errorFlag.good() || errorFlag == EC_EndOfStream) { /* perform some final checks on dataset level */ errorFlag = doPostReadChecks(); if (errorFlag.good()) { /* set the error flag to ok */ errorFlag = EC_Normal; /* take care of group length (according to what is specified */ /* in glenc) and padding elements (don't change anything) */ computeGroupLengthAndPadding(glenc, EPD_noChange, OriginalXfer); /* and set the transfer state to ERW_ready to indicate that the data set is complete */ setTransferState(ERW_ready); } } /* dump information if required */ DCMDATA_TRACE("DcmDataset::read() returns error = " << errorFlag.text()); /* return result flag */ return errorFlag; } // ******************************** OFCondition DcmDataset::write( DcmOutputStream &outStream, const E_TransferSyntax oxfer, const E_EncodingType enctype /* = EET_UndefinedLength */, DcmWriteCache *wcache) { return write(outStream, oxfer, enctype, wcache, EGL_recalcGL); } OFCondition DcmDataset::write(DcmOutputStream &outStream, const E_TransferSyntax oxfer, const E_EncodingType enctype, DcmWriteCache *wcache, const E_GrpLenEncoding glenc, const E_PaddingEncoding padenc, const Uint32 padlen, const Uint32 subPadlen, Uint32 instanceLength) { /* if the transfer state of this is not initialized, this is an illegal call */ if (getTransferState() == ERW_notInitialized) errorFlag = EC_IllegalCall; else { /* check if the stream reported an error so far; if not, we can go ahead and write some data to it */ errorFlag = outStream.status(); if (errorFlag.good() && getTransferState() != ERW_ready) { /* Determine the transfer syntax which shall be used. Either we use the one which was passed, */ /* or (if it's an unknown transfer syntax) we use the one which is contained in OriginalXfer. */ E_TransferSyntax newXfer = oxfer; if (newXfer == EXS_Unknown) newXfer = OriginalXfer; /* if this function was called for the first time for the dataset object, the transferState is still */ /* set to ERW_init. In this case, we need to take care of group length and padding elements according */ /* to the strategies which are specified in glenc and padenc. Additionally, we need to set the element */ /* list pointer of this data set to the fist element and we need to set the transfer state to ERW_inWork */ /* so that this scenario will only be executed once for this data set object. */ if (getTransferState() == ERW_init) { /* Check stream compression for this transfer syntax */ DcmXfer xf(newXfer); E_StreamCompression sc = xf.getStreamCompression(); switch (sc) { case ESC_none: // nothing to do break; case ESC_unsupported: // stream compressed transfer syntax that we cannot create; bail out. if (errorFlag.good()) errorFlag = EC_UnsupportedEncoding; break; default: // supported stream compressed transfer syntax, install filter errorFlag = outStream.installCompressionFilter(sc); break; } /* take care of group length and padding elements, according to what is specified in glenc and padenc */ computeGroupLengthAndPadding(glenc, padenc, newXfer, enctype, padlen, subPadlen, instanceLength); elementList->seek(ELP_first); setTransferState(ERW_inWork); } /* if the transfer state is set to ERW_inWork, we need to write the information which */ /* is included in this data set's element list into the buffer which was passed. */ if (getTransferState() == ERW_inWork) { // Remember that elementList->get() can be NULL if buffer was full after // writing the last item but before writing the sequence delimitation. if (!elementList->empty() && (elementList->get() != NULL)) { /* as long as everything is ok, go through all elements of this data */ /* set and write the corresponding information to the buffer */ DcmObject *dO; do { dO = elementList->get(); errorFlag = dO->write(outStream, newXfer, enctype, wcache); } while (errorFlag.good() && elementList->seek(ELP_next)); } /* if all the information in this has been written to the */ /* buffer set this data set's transfer state to ERW_ready */ if (errorFlag.good()) { setTransferState(ERW_ready); CurrentXfer = newXfer; } } } } /* return the corresponding result value */ return errorFlag; } // ******************************** OFCondition DcmDataset::writeSignatureFormat(DcmOutputStream &outStream, const E_TransferSyntax oxfer, const E_EncodingType enctype, DcmWriteCache *wcache) { if (getTransferState() == ERW_notInitialized) errorFlag = EC_IllegalCall; else { E_TransferSyntax newXfer = oxfer; if (newXfer == EXS_Unknown) newXfer = OriginalXfer; errorFlag = outStream.status(); if (errorFlag.good() && getTransferState() != ERW_ready) { if (getTransferState() == ERW_init) { computeGroupLengthAndPadding(EGL_recalcGL, EPD_noChange, newXfer, enctype, 0, 0, 0); elementList->seek(ELP_first); setTransferState(ERW_inWork); } if (getTransferState() == ERW_inWork) { // elementList->get() can be NULL if buffer was full after // writing the last item but before writing the sequence delimitation. if (!elementList->empty() && (elementList->get() != NULL)) { DcmObject *dO; do { dO = elementList->get(); errorFlag = dO->writeSignatureFormat(outStream, newXfer, enctype, wcache); } while (errorFlag.good() && elementList->seek(ELP_next)); } if (errorFlag.good()) { setTransferState(ERW_ready); CurrentXfer = newXfer; } } } } return errorFlag; } // ******************************** OFCondition DcmDataset::loadFile(const OFFilename &fileName, const E_TransferSyntax readXfer, const E_GrpLenEncoding groupLength, const Uint32 maxReadLength) { return DcmDataset::loadFileUntilTag(fileName, readXfer, groupLength, maxReadLength, DCM_UndefinedTagKey); } OFCondition DcmDataset::loadFileUntilTag(const OFFilename &fileName, const E_TransferSyntax readXfer, const E_GrpLenEncoding groupLength, const Uint32 maxReadLength, const DcmTagKey &stopParsingAtElement) { OFCondition l_error = EC_InvalidFilename; /* check parameters first */ if (!fileName.isEmpty()) { if (fileName.isStandardStream()) { /* use stdin stream */ DcmStdinStream inStream; /* clear this object */ l_error = clear(); if (l_error.good()) { /* initialize transfer */ transferInit(); do { /* fill the buffer from stdin */ inStream.fillBuffer(); /* and read the buffer content into the DICOM dataset */ l_error = readUntilTag(inStream, readXfer, groupLength, maxReadLength, stopParsingAtElement); } while (l_error == EC_StreamNotifyClient); /* repeat until we're at the end of the stream, or an error occurs */ /* end transfer */ transferEnd(); } } else { /* open file for input */ DcmInputFileStream fileStream(fileName); /* check stream status */ l_error = fileStream.status(); if (l_error.good()) { /* clear this object */ l_error = clear(); if (l_error.good()) { /* read data from file */ transferInit(); l_error = readUntilTag(fileStream, readXfer, groupLength, maxReadLength, stopParsingAtElement); transferEnd(); } } } } return l_error; } OFCondition DcmDataset::saveFile(const OFFilename &fileName, const E_TransferSyntax writeXfer, const E_EncodingType encodingType, const E_GrpLenEncoding groupLength, const E_PaddingEncoding padEncoding, const Uint32 padLength, const Uint32 subPadLength) { OFCondition l_error = EC_InvalidFilename; /* check parameters first */ if (!fileName.isEmpty()) { DcmWriteCache wcache; DcmOutputStream *fileStream; if (fileName.isStandardStream()) { /* use stdout stream */ fileStream = new DcmStdoutStream(fileName); } else { /* open file for output */ fileStream = new DcmOutputFileStream(fileName); } /* check stream status */ l_error = fileStream->status(); if (l_error.good()) { /* write data to file */ transferInit(); l_error = write(*fileStream, writeXfer, encodingType, &wcache, groupLength, padEncoding, padLength, subPadLength); transferEnd(); } delete fileStream; } return l_error; } // ******************************** OFCondition DcmDataset::chooseRepresentation(const E_TransferSyntax repType, const DcmRepresentationParameter *repParam) { OFCondition l_error = EC_Normal; OFBool pixelDataEncountered = OFFalse; OFStack pixelStack; DcmXfer torep(repType); DcmXfer fromrep(CurrentXfer); DcmStack resultStack; resultStack.push(this); // check if we are attempting to compress but the image contains // floating point or double floating point pixel data, which our codecs don't support. if ((tagExists(DCM_FloatPixelData, OFTrue) || tagExists(DCM_DoubleFloatPixelData, OFTrue)) && (fromrep.isEncapsulated() || torep.isEncapsulated())) { DCMDATA_ERROR("DcmDataset: Unable to compress/decompress floating point pixel data, cannot change representation"); l_error = EC_CannotChangeRepresentation; return l_error; } // check if we are attempting to convert a dataset containing // a pixel data URL. In that case we only continue if the target // transfer syntax also uses a pixel data URL. if (tagExists(DCM_PixelDataProviderURL, OFTrue)) { if (! torep.isReferenced()) { DCMDATA_ERROR("DcmDataset: Unable to compress image containing a pixel data provider URL, cannot change representation"); l_error = EC_CannotChangeRepresentation; return l_error; } } // Now search for all PixelData elements in this dataset while (search(DCM_PixelData, resultStack, ESM_afterStackTop, OFTrue).good() && l_error.good()) { pixelDataEncountered = OFTrue; if (resultStack.top()->ident() == EVR_PixelData) { DcmPixelData *pixelData = OFstatic_cast(DcmPixelData *, resultStack.top()); if (!pixelData->canChooseRepresentation(repType, repParam)) l_error = EC_CannotChangeRepresentation; pixelStack.push(resultStack); } else { /* something is fishy with the pixel data element (wrong class) */ DCMDATA_ERROR("DcmDataset: Wrong class for pixel data element, cannot change representation"); l_error = EC_CannotChangeRepresentation; } } // If there are no pixel data elements in the dataset, issue a warning if (! pixelDataEncountered) { if (torep.isEncapsulated() && ! fromrep.isEncapsulated()) { DCMDATA_WARN("DcmDataset: No pixel data present, nothing to compress"); } if (! torep.isEncapsulated() && fromrep.isEncapsulated()) { DCMDATA_WARN("DcmDataset: No pixel data present, nothing to decompress"); } } // then call the method doing the real work for all pixel data elements found while (l_error.good() && (pixelStack.size() > 0)) { l_error = OFstatic_cast(DcmPixelData *, pixelStack.top().top())-> chooseRepresentation(repType, repParam, pixelStack.top()); #ifdef PIXELSTACK_MEMORY_LEAK_WORKAROUND // on certain platforms there seems to be a memory leak // at this point since for some reason pixelStack.pop does // not completely destruct the DcmStack object taken from the stack. // The following work-around should solve this issue. pixelStack.top().clear(); #endif pixelStack.pop(); } // store current transfer syntax (if conversion was successful) if (l_error.good()) CurrentXfer = repType; return l_error; } OFBool DcmDataset::hasRepresentation(const E_TransferSyntax repType, const DcmRepresentationParameter *repParam) { OFBool result = OFTrue; DcmStack resultStack; while(search(DCM_PixelData, resultStack, ESM_afterStackTop, OFTrue).good() && result) { if (resultStack.top()->ident() == EVR_PixelData) { DcmPixelData *pixelData = OFstatic_cast(DcmPixelData *, resultStack.top()); result = pixelData->hasRepresentation(repType, repParam); } else result = OFFalse; } return result; } void DcmDataset::removeAllButCurrentRepresentations() { DcmStack resultStack; while(search(DCM_PixelData, resultStack, ESM_afterStackTop, OFTrue).good()) { if (resultStack.top()->ident() == EVR_PixelData) { DcmPixelData *pixelData = OFstatic_cast(DcmPixelData *, resultStack.top()); pixelData->removeAllButCurrentRepresentations(); } } } void DcmDataset::removeAllButOriginalRepresentations() { DcmStack resultStack; while(search(DCM_PixelData, resultStack, ESM_afterStackTop, OFTrue).good()) { if (resultStack.top()->ident() == EVR_PixelData) { DcmPixelData *pixelData = OFstatic_cast(DcmPixelData *, resultStack.top()); pixelData->removeAllButOriginalRepresentations(); } } } // ******************************** OFCondition DcmDataset::doPostReadChecks() { DcmElement* pixData = NULL; DcmXfer xf(OriginalXfer); OFCondition result = EC_Normal; if (findAndGetElement(DCM_PixelData, pixData).good()) { Uint32 valueLength = pixData->getLengthField(); if (xf.isEncapsulated()) { if (valueLength != DCM_UndefinedLength) { if (dcmUseExplLengthPixDataForEncTS.get() == OFFalse /* default case */) { /* length of top level dataset's Pixel Data is explicitly */ /* defined but we have a transfer syntax requiring */ /* encapsulated pixel data (always encoded with undefined */ /* length). Print and return an error. */ DCMDATA_ERROR("Found explicit length Pixel Data in top level " << "dataset with transfer syntax " << xf.getXferName() << ": Only undefined length permitted"); result = EC_PixelDataExplLengthIllegal; } else { /* Only print warning if requested by related OFGlobal, */ /* and behave like as we have the same case as for an */ /* icon image, which is always uncompressed (see above). */ DCMDATA_WARN("Found explicit length Pixel Data in top level " << "dataset with transfer syntax " << xf.getXferName() << ": Only undefined length permitted (ignored on explicit request)"); } } } } return result; }