/* * * Copyright (C) 2018-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: Pedro ArizpeGomez * * Purpose: Implementation of Document encapsulation * */ //make sure OS specific configuration is included first #include "dcmtk/config/osconfig.h" #include "dcmtk/dcmdata/dcencdoc.h" #include "dcmtk/ofstd/ofconapp.h" #include "dcmtk/ofstd/ofxml.h" #include "dcmtk/ofstd/oftypes.h" #include "dcmtk/dcmdata/dcpath.h" #include "dcmtk/dcmdata/dccodec.h" #include "dcmtk/dcmdata/dcdeftag.h" #include "dcmtk/dcmdata/dcuid.h" #include "dcmtk/dcmdata/dcvrpobw.h" #include "dcmtk/dcmdata/dcvrui.h" #include "dcmtk/dcmdata/dcvrda.h" #include "dcmtk/dcmdata/dcvrtm.h" #define SHORTCOL 3 #define LONGCOL 21 // exit codes for this command line tool // (common codes are defined in "ofexit.h" included from "ofconapp.h") // general errors #define EXITCODE_MEMORY_EXHAUSTED 4 DcmEncapsulatedDocument::DcmEncapsulatedDocument() : opt_patientBirthdate(), opt_patientID(), opt_patientName(), opt_patientSex(), opt_conceptCM(), opt_conceptCSD(), opt_conceptCV(), opt_documentTitle(), opt_seriesFile(), opt_seriesUID(), opt_studyUID(), opt_oenctype(EET_ExplicitLength), opt_writeMode(EWM_fileformat), opt_oglenc(EGL_withoutGL), opt_opadenc(EPD_withoutPadding), opt_oxfer(EXS_LittleEndianExplicit), opt_filepad(0), opt_itempad(0), opt_readSeriesInfo(OFFalse), opt_annotation(OFTrue), opt_increment(OFFalse), opt_instance(1), opt_overrideKeys(), cda_mediaTypes(), hl7_InstanceIdentifier(), opt_override(OFFalse), // Frame of Reference Module (STL) opt_frameOfReferenceUID(), opt_positionReferenceIndicator(), // Frame of Reference Module (STL) opt_manufacturer(), opt_manufacturerModelName(), opt_deviceSerialNumber(), opt_softwareVersions(), // Enhanced General Equipment Module (STL) opt_measurementUnitsCM(), opt_measurementUnitsCSD(), opt_measurementUnitsCV(), //encapsulation file type ftype() { } OFBool DcmEncapsulatedDocument::XMLsearchAttribute( XMLNode currnode, OFList *results, OFString attr) { OFBool found = OFFalse; #ifndef _XMLWIDECHAR if (currnode.nChildNode() == 0) { //"currnode has no children (leaf)"; if (currnode.isAttributeSet(attr.c_str())) { //attribute found on leaf results->push_back(OFSTRING_GUARD(currnode.getAttribute(attr.c_str()))); found = OFTrue; } } else { //"currnode has children (branch)"; if (currnode.isAttributeSet(attr.c_str())) { //attribute found on branch results->push_back(OFSTRING_GUARD(currnode.getAttribute(attr.c_str()))); found = OFTrue; } for (int i = 0; i < currnode.nChildNode(); i++) { //search all children recursively OFBool childfound = XMLsearchAttribute(currnode.getChildNode(i), results, attr); found |= childfound; } } #endif return found; } OFString DcmEncapsulatedDocument::XMLgetAllAttributeValues( XMLNode fileNode, OFString attr) { OFString attributeValues; #ifndef _XMLWIDECHAR OFList attributeValueslist; if (XMLsearchAttribute(fileNode, &attributeValueslist, attr)) { //If the Attribute is mediaType, initialize with text/xml to exclude //the primary MIME Type of the encapsulated document if (attr == "mediaType") attributeValues.append("text/xml"); while (!attributeValueslist.empty()) { if (attributeValues.find(attributeValueslist.front()) == OFString_npos) { if (!attributeValues.empty()) attributeValues.append("\\"); attributeValues.append(attributeValueslist.front()); } attributeValueslist.pop_front(); } //remove the primary MIME Type of the //encapsulated document if (attr == "mediaType") { if (attributeValues.size() > 9) attributeValues.erase(0, 9); else attributeValues = ""; } } #endif return attributeValues; } OFString DcmEncapsulatedDocument::XMLgetAttribute( XMLNode fileNode, DcmTagKey attr) { OFString result = ""; #ifndef _XMLWIDECHAR if (attr == DCM_DocumentTitle) { if (fileNode.getChildNode("title").getText() != NULL) { result = OFString(OFSTRING_GUARD(fileNode.getChildNode("title").getText())); } } if (attr == DCM_HL7InstanceIdentifier) { result = OFString(OFSTRING_GUARD(fileNode.getChildNode("id").getAttribute("root"))) + "^" + OFString(OFSTRING_GUARD(fileNode.getChildNode("id").getAttribute("extension"))); } /*PatientNameExtension could reflect the type of name (PHON, IDE, ABC) if (attr == DCM_PatientNameExtension) { result = OFString(OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name").getAttribute("use"))); }*/ if (attr == DCM_PatientName) { result = OFString( OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name/family").getText())) + "^" + OFString(OFSTRING_GUARD( fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name").getChildNode( "given", 0).getText())) + "^" + OFString(OFSTRING_GUARD( fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name").getChildNode( "given", 1).getText())) + "^" + OFString( OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name/prefix").getText())) + "^" + OFString( OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/patient/name/suffix").getText())); } if (attr == DCM_PatientSex) { result = OFString(OFSTRING_GUARD(fileNode.getChildNodeByPath( "recordTarget/patientRole/patient/administrativeGenderCode").getAttribute("code"))); } if (attr == DCM_PatientBirthDate) { result = OFString(OFSTRING_GUARD( fileNode.getChildNodeByPath("recordTarget/patientRole/patient/birthTime").getAttribute( "value"))); } //Table A.8-1. Basic Code Attributes Mapping to HL7 V3 Code Data Types (CV, CS, CE and CD) if (attr == DCM_PatientID) { result = OFString( OFSTRING_GUARD(fileNode.getChildNodeByPath("recordTarget/patientRole/id").getAttribute("extension"))); } if (attr == DCM_CodeValue)//Code Value { result = OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("code"))); } if (attr == DCM_CodingSchemeUID)//Coding Scheme UID (PS3.16) { result = OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("codeSystem"))); } if (attr == DCM_CodingSchemeDesignator)//Coding Scheme Designator (0008,0102) { OFString CSDtemp = OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("codeSystemName"))); // Abbreviate most common CSNs if (CSDtemp == OFString("LOINC")) { result = OFString("LN"); } else { if (CSDtemp == OFString("DICOM")) { result = OFString("DC"); } else { if (CSDtemp == OFString("SNOMED")) { result = OFString("SRT"); } else { result = CSDtemp; } } } } if (attr == DCM_CodingSchemeVersion)//Coding Scheme Version (0008,0103) { result = OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("codeSystemVersion"))); } if (attr == DCM_CodeMeaning)//Code Meaning (0008,0104) { result = OFString(OFSTRING_GUARD(fileNode.getChildNode("code").getAttribute("displayName"))); } #endif return result; } int DcmEncapsulatedDocument::getCDAData( const char *filename, OFLogger &appLogger) { #ifdef _XMLWIDECHAR #ifdef _MSC_VER #pragma message("DCMTK compiled with 'wide char XML parser'. cda2dcm will be unable to read and encapsulate CDA documents.") #else #warning "DCMTK compiled with 'wide char XML parser'. cda2dcm will be unable to read and encapsulate CDA documents." #endif OFLOG_ERROR(appLogger, "DCMTK compiled with \"wide char XML parser\". Cannot parse CDA data because of incompatible API."); return 99; #else if (ftype != "cda") { OFLOG_WARN(appLogger, "Filetype mismatch or filetype not set. Current ftype is " << ftype); } XMLResults err; XMLNode fileNode = XMLNode::parseFile(filename, "ClinicalDocument", &err); OFLOG_TRACE(appLogger, "checking if the XML file is correctly formatted"); if (0 != err.error) { OFLOG_ERROR(appLogger, fileNode.getError(err.error)); return EXITCODE_INVALID_INPUT_FILE; } else { OFLOG_TRACE(appLogger, "XML file is correctly formatted"); } OFLOG_TRACE(appLogger, "Getting all media types from CDA file"); cda_mediaTypes = XMLgetAllAttributeValues(fileNode, "mediaType"); OFLOG_TRACE(appLogger, "Following mediaTypes were found: " << cda_mediaTypes); OFLOG_TRACE(appLogger, "Getting HL7 Instance Identifier from CDA file"); hl7_InstanceIdentifier = XMLgetAttribute(fileNode, DCM_HL7InstanceIdentifier); OFLOG_TRACE(appLogger, "Reading and comparing patient information between CDA File and options"); OFString pID = XMLgetAttribute(fileNode, DCM_PatientID); if ((pID != "") && (opt_patientID != pID)) { if (opt_patientID != "") { //if no-override option is inactive, return an error if (!opt_override) { OFLOG_ERROR(appLogger, "Patient ID mismatch:" << OFendl << "Found in the CDA file : " << pID << OFendl << "Entered (or found in DCM file): " << opt_patientID << OFendl << "If you wish to override, run again with +ov"); return EXITCODE_COMMANDLINE_SYNTAX_ERROR; } else { OFLOG_WARN(appLogger, "Patient ID mismatch:" << OFendl << "Found in the CDA file : " << pID << OFendl << "Provided (in DCM file): " << opt_patientID); } } else { opt_patientID = pID; } } OFString pBirthDate = XMLgetAttribute(fileNode, DCM_PatientBirthDate); if ((pBirthDate != "") && (opt_patientBirthdate != pBirthDate)) { if (opt_patientBirthdate != "") { if (!opt_override) { OFLOG_ERROR(appLogger, "Patient Birth Date mismatch:" << OFendl << "Found in the CDA file : " << pBirthDate << OFendl << "Provided (in DCM file): " << opt_patientBirthdate << OFendl << "If you wish to override, run again with +ov"); return EXITCODE_COMMANDLINE_SYNTAX_ERROR; } else { OFLOG_WARN(appLogger, "Patient Birth Date mismatch:" << OFendl << "Found in the CDA file : " << pBirthDate << OFendl << "Provided (in DCM file): " << opt_patientBirthdate); } } else opt_patientBirthdate = pBirthDate; } OFString pSex = XMLgetAttribute(fileNode, DCM_PatientSex); if ((pSex != "") && (opt_patientSex != pSex)) { if (opt_patientSex != "") { if (!opt_override) { OFLOG_ERROR(appLogger, "Patient Sex mismatch:" << OFendl << "Found in the CDA file : " << pSex << OFendl << "Provided (in DCM file): " << opt_patientSex << OFendl << "If you wish to override, run again with +ov"); return EXITCODE_COMMANDLINE_SYNTAX_ERROR; } else { OFLOG_WARN(appLogger, "Patient Sex mismatch:" << OFendl << "Found in the CDA file : " << pSex << OFendl << "Provided (in DCM file): " << opt_patientSex); } } else opt_patientSex = pSex; } OFString pName = XMLgetAttribute(fileNode, DCM_PatientName); if ((pName != "^^^^") && (opt_patientName != pName)) { if (opt_patientName != "") { if (!opt_override) { OFLOG_ERROR(appLogger, "Patient Name mismatch:" << OFendl << "Found in the CDA file : " << pName << OFendl << "Provided (in DCM file): " << opt_patientName << OFendl << "If you wish to override, run again with +ov"); return EXITCODE_COMMANDLINE_SYNTAX_ERROR; } else { OFLOG_WARN(appLogger, "Patient Name mismatch:" << OFendl << "Found in the CDA file : " << pName << OFendl << "Provided (in DCM file): " << opt_patientName); } } else opt_patientName = pName; } //get document title from CDA OFString dTitle = XMLgetAttribute(fileNode, DCM_DocumentTitle); if (opt_documentTitle == "") { if (opt_conceptCSD != "") opt_documentTitle = opt_conceptCSD; if (opt_conceptCV != "") opt_documentTitle = opt_conceptCV; if (opt_conceptCM != "") opt_documentTitle = opt_conceptCM; } if ((dTitle != "") && (opt_documentTitle != dTitle)) { if (opt_documentTitle != "") { if (!opt_override) { OFLOG_ERROR(appLogger, "Document Title mismatch:" << OFendl << "Found in the CDA file : " << dTitle << OFendl << "Provided (in DCM file): " << opt_documentTitle << OFendl << "If you wish to override, run again with +ov"); return EXITCODE_COMMANDLINE_SYNTAX_ERROR; } else { OFLOG_WARN(appLogger, "Document Title mismatch:" << OFendl << "Found in the CDA file : " << dTitle << OFendl << "Provided (in DCM file): " << opt_documentTitle); } } else opt_documentTitle = dTitle; } //get Concept information from CDA OFString cCSD = XMLgetAttribute(fileNode, DCM_CodingSchemeDesignator); if ((cCSD != "") && (opt_conceptCSD != cCSD)) { if (opt_conceptCSD != "") { if (!opt_override) { OFLOG_ERROR(appLogger, "concept CSD mismatch:" << OFendl << "Found in the CDA file : " << cCSD << OFendl << "Provided (in DCM file): " << opt_conceptCSD << OFendl << "If you wish to override, run again with +ov"); return EXITCODE_COMMANDLINE_SYNTAX_ERROR; } else { OFLOG_WARN(appLogger, "concept CSD mismatch:" << OFendl << "Found in the CDA file : " << cCSD << OFendl << "Provided (in DCM file): " << opt_conceptCSD); } } else opt_conceptCSD = cCSD; } OFString cCV = XMLgetAttribute(fileNode, DCM_CodeValue); if ((cCV != "") && (opt_conceptCV != cCV)) { if (opt_conceptCV != "") { if (!opt_override) { OFLOG_ERROR(appLogger, "concept CV mismatch:" << OFendl << "Found in the CDA file : " << cCV << OFendl << "Provided (in DCM file): " << opt_conceptCV << OFendl << "If you wish to override, run again with +ov"); return EXITCODE_COMMANDLINE_SYNTAX_ERROR; } else { OFLOG_WARN(appLogger, "concept CV mismatch:" << OFendl << "Found in the CDA file : " << cCV << OFendl << "Provided (in DCM file): " << opt_conceptCV); } } else opt_conceptCV = cCV; } OFString cCM = XMLgetAttribute(fileNode, DCM_CodeMeaning); if ((cCM != "") && (opt_conceptCM != cCM)) { if (opt_conceptCM != "") { if (!opt_override) { OFLOG_ERROR(appLogger, "concept CM mismatch:" << OFendl << "Found in the CDA file : " << cCM << OFendl << "Provided (in DCM file): " << opt_conceptCM << OFendl << "If you wish to override, run again with +ov"); return EXITCODE_COMMANDLINE_SYNTAX_ERROR; } else { OFLOG_WARN(appLogger, "concept CM mismatch:" << OFendl << "Found in the CDA file : " << cCM << OFendl << "Provided (in DCM file): " << opt_conceptCM); } } else opt_conceptCM = cCM; } return EXITCODE_NO_ERROR; #endif } void DcmEncapsulatedDocument::addCDACommandlineOptions(OFCommandLine &cmd) { ftype = "cda"; cmd.setOptionColumns(LONGCOL, SHORTCOL); cmd.setParamColumn(LONGCOL + SHORTCOL + 4); cmd.addParam("cdafile-in", "CDA input filename to be converted"); cmd.addParam("dcmfile-out", "DICOM output filename"); addGeneralOptions(cmd); addDocumentOptions(cmd); cmd.addSubGroup("override CDA data:"); cmd.addOption("--no-override", "-ov", "CDA patient and document data must match study,\nseries or manually entered information (default)"); cmd.addOption("--override", "+ov", "CDA's data will be overwritten by study, series\nor manually entered information"); addOutputOptions(cmd); } void DcmEncapsulatedDocument::addPDFCommandlineOptions(OFCommandLine &cmd) { ftype = "pdf"; cmd.setOptionColumns(LONGCOL, SHORTCOL); cmd.setParamColumn(LONGCOL + SHORTCOL + 4); cmd.addParam("pdffile-in", "PDF input filename to be converted"); cmd.addParam("dcmfile-out", "DICOM output filename"); addGeneralOptions(cmd); addDocumentOptions(cmd); addOutputOptions(cmd); } void DcmEncapsulatedDocument::addSTLCommandlineOptions(OFCommandLine &cmd) { ftype = "stl"; cmd.setOptionColumns(LONGCOL, SHORTCOL); cmd.setParamColumn(LONGCOL + SHORTCOL + 4); cmd.addParam("stlfile-in", "STL input filename to be converted"); cmd.addParam("dcmfile-out", "DICOM output filename"); addGeneralOptions(cmd); addDocumentOptions(cmd); cmd.addSubGroup("enhanced general equipment:"); cmd.addOption("--manufacturer", "+mn", 1, "[n]ame: string", "manufacturer's name"); cmd.addOption("--manufacturer-model", "+mm", 1, "[n]ame: string", "manufacturer's model name"); cmd.addOption("--device-serial", "+ds", 1, "[n]umber: string", "device serial number"); cmd.addOption("--software-versions", "+sv", 1, "[v]ersions: string", "software versions"); cmd.addSubGroup("3d model measurement units:"); cmd.addOption("--measurement-units", "+mu", 3, "[CSD] [CV] [CM]: string (default: UCUM, um, um)", "measurement units defined by coding scheme\ndesignator CSD, code value CV, code meaning CM"); addOutputOptions(cmd); } void DcmEncapsulatedDocument::addGeneralOptions(OFCommandLine &cmd) { cmd.addGroup("general options:", LONGCOL, SHORTCOL + 2); cmd.addOption("--help", "-h", "print this help text and exit", OFCommandLine::AF_Exclusive); cmd.addOption("--version", "print version information and exit", OFCommandLine::AF_Exclusive); OFLog::addOptions(cmd); } void DcmEncapsulatedDocument::addDocumentOptions(OFCommandLine &cmd) { cmd.addGroup("DICOM document options:"); cmd.addSubGroup("document title:"); cmd.addOption("--title", "+t", 1, "[t]itle: string (default: empty)", "document title"); cmd.addOption("--concept-name", "+cn", 3, "[CSD] [CV] [CM]: string (default: empty)", "coded representation of document title defined\nby coding scheme designator CSD,\n" "code value CV and code meaning CM"); cmd.addSubGroup("patient data:"); cmd.addOption("--patient-name", "+pn", 1, "[n]ame: string", "patient's name in DICOM PN syntax"); cmd.addOption("--patient-id", "+pi", 1, "[i]d: string", "patient identifier"); cmd.addOption("--patient-birthdate", "+pb", 1, "[d]ate: string (YYYYMMDD)", "patient's birth date"); cmd.addOption("--patient-sex", "+ps", 1, "[s]ex: string (M, F or O)", "patient's sex"); cmd.addSubGroup("study and series:"); cmd.addOption("--generate", "+sg", "generate new study and\nseries UIDs (default)"); cmd.addOption("--study-from", "+st", 1, "[f]ilename: string", "read patient/study data from DICOM file"); cmd.addOption("--series-from", "+se", 1, "[f]ilename: string", "read patient/study/series data from DICOM file"); cmd.addSubGroup("instance number:"); cmd.addOption("--instance-one", "+i1", "use instance number 1\n(default, not with +se)"); cmd.addOption("--instance-inc", "+ii", "increment instance number (only with +se)"); cmd.addOption("--instance-set", "+is", 1, "[i]nstance number: integer", "use instance number i"); cmd.addSubGroup("burned-in annotation:"); cmd.addOption("--annotation-yes", "+an", "document contains patient identifying data\n(default)"); cmd.addOption("--annotation-no", "-an", "document does not contain patient identif. data"); } void DcmEncapsulatedDocument::addOutputOptions(OFCommandLine &cmd) { cmd.addGroup("processing options:"); cmd.addSubGroup("other processing options:"); cmd.addOption("--key", "-k", 1, "[k]ey: gggg,eeee=\"str\", path or dict. name=\"str\"", "add further attribute"); cmd.addGroup("output options:"); cmd.addSubGroup("output transfer syntax:"); cmd.addOption("--write-xfer-little", "+te", "write with explicit VR little endian (default)"); cmd.addOption("--write-xfer-big", "+tb", "write with explicit VR big endian TS"); cmd.addOption("--write-xfer-implicit", "+ti", "write with implicit VR little endian TS"); cmd.addSubGroup("group length encoding:"); cmd.addOption("--group-length-recalc", "+g=", "recalculate group lengths if present (default)"); cmd.addOption("--group-length-create", "+g", "always write with group length elements"); cmd.addOption("--group-length-remove", "-g", "always write without group length elements"); cmd.addSubGroup("length encoding in sequences and items:"); cmd.addOption("--length-explicit", "+e", "write with explicit lengths (default)"); cmd.addOption("--length-undefined", "-e", "write with undefined lengths"); cmd.addSubGroup("data set trailing padding (not with --write-dataset):"); cmd.addOption("--padding-retain", "-p=", "do not change padding (default)"); cmd.addOption("--padding-off", "-p", "no padding (implicit if --write-dataset)"); cmd.addOption("--padding-create", "+p", 2, "[f]ile-pad [i]tem-pad: integer", "align file on multiple of f bytes\nand items on multiple of i bytes"); } void DcmEncapsulatedDocument::parseArguments( OFConsoleApplication &app, OFCommandLine &cmd) { //command line parameters and options cmd.getParam(1, opt_ifname); cmd.getParam(2, opt_ofname); OFLog::configureFromCommandLine(cmd, app); dcmEnableGenerationOfNewVRs(); // Override keys are applied at the very end of the conversion "pipeline" OFList overrideKeys; cmd.beginOptionBlock(); if (cmd.findOption("--generate")) { opt_seriesFile = ""; opt_readSeriesInfo = OFFalse; } if (cmd.findOption("--series-from")) { app.checkValue(cmd.getValue(opt_seriesFile)); opt_readSeriesInfo = OFTrue; } if (cmd.findOption("--study-from")) { app.checkValue(cmd.getValue(opt_seriesFile)); opt_readSeriesInfo = OFFalse; } cmd.endOptionBlock(); if (cmd.findOption("--title")) { app.checkValue(cmd.getValue(opt_documentTitle)); } if (cmd.findOption("--concept-name")) { app.checkValue(cmd.getValue(opt_conceptCSD)); app.checkValue(cmd.getValue(opt_conceptCV)); app.checkValue(cmd.getValue(opt_conceptCM)); } if (cmd.findOption("--patient-name")) { app.checkValue(cmd.getValue(opt_patientName)); app.checkConflict("--patient-name", "--study-from or --series-from", opt_seriesFile != ""); } if (cmd.findOption("--patient-id")) { app.checkValue(cmd.getValue(opt_patientID)); app.checkConflict("--patient-id", "--study-from or --series-from", opt_seriesFile != ""); } if (cmd.findOption("--patient-birthdate")) { app.checkValue(cmd.getValue(opt_patientBirthdate)); app.checkConflict("--patient-birthdate", "--study-from or --series-from", opt_seriesFile != ""); } if (cmd.findOption("--patient-sex")) { app.checkValue(cmd.getValue(opt_patientSex)); app.checkConflict("--patient-sex", "--study-from or --series-from", opt_seriesFile != ""); } cmd.beginOptionBlock(); if (cmd.findOption("--annotation-yes")) { opt_annotation = OFTrue; } if (cmd.findOption("--annotation-no")) { opt_annotation = OFFalse; } cmd.endOptionBlock(); if (ftype == "cda") { cmd.beginOptionBlock(); if (cmd.findOption("--override")) { opt_override = OFTrue; } if (cmd.findOption("--no-override")) { opt_override = OFFalse; } cmd.endOptionBlock(); } if (ftype == "stl") { if (cmd.findOption("--measurement-units")) { app.checkValue(cmd.getValue(opt_measurementUnitsCSD)); app.checkValue(cmd.getValue(opt_measurementUnitsCV)); app.checkValue(cmd.getValue(opt_measurementUnitsCM)); } if (cmd.findOption("--manufacturer")) app.checkValue(cmd.getValue(opt_manufacturer)); if (cmd.findOption("--manufacturer-model")) app.checkValue(cmd.getValue(opt_manufacturerModelName)); if (cmd.findOption("--device-serial")) app.checkValue(cmd.getValue(opt_deviceSerialNumber)); if (cmd.findOption("--software-versions")) app.checkValue(cmd.getValue(opt_softwareVersions)); } cmd.beginOptionBlock(); if (cmd.findOption("--write-xfer-little")) opt_oxfer = EXS_LittleEndianExplicit; if (cmd.findOption("--write-xfer-big")) opt_oxfer = EXS_BigEndianExplicit; if (cmd.findOption("--write-xfer-implicit")) opt_oxfer = EXS_LittleEndianImplicit; cmd.endOptionBlock(); cmd.beginOptionBlock(); if (cmd.findOption("--group-length-recalc")) opt_oglenc = EGL_recalcGL; if (cmd.findOption("--group-length-create")) opt_oglenc = EGL_withGL; if (cmd.findOption("--group-length-remove")) opt_oglenc = EGL_withoutGL; cmd.endOptionBlock(); cmd.beginOptionBlock(); if (cmd.findOption("--length-explicit")) opt_oenctype = EET_ExplicitLength; if (cmd.findOption("--length-undefined")) opt_oenctype = EET_UndefinedLength; cmd.endOptionBlock(); cmd.beginOptionBlock(); if (cmd.findOption("--padding-retain")) { app.checkConflict("--padding-retain", "--write-dataset", opt_writeMode == EWM_dataset); opt_opadenc = EPD_noChange; } if (cmd.findOption("--padding-off")) opt_opadenc = EPD_withoutPadding; if (cmd.findOption("--padding-create")) { app.checkConflict("--padding-create", "--write-dataset", opt_writeMode == EWM_dataset); app.checkValue(cmd.getValueAndCheckMin(opt_filepad, 0)); app.checkValue(cmd.getValueAndCheckMin(opt_itempad, 0)); opt_opadenc = EPD_withPadding; } cmd.endOptionBlock(); // create override attribute dataset (copied from findscu code) if (cmd.findOption("--key", 0, OFCommandLine::FOM_FirstFromLeft)) { const char *ovKey = NULL; do { app.checkValue(cmd.getValue(ovKey)); overrideKeys.push_back(ovKey); } while (cmd.findOption("--key", 0, OFCommandLine::FOM_NextFromLeft)); } DcmEncapsulatedDocument::setOverrideKeys(overrideKeys); // initialize default for --series-from if (opt_seriesFile != "" && opt_readSeriesInfo) opt_increment = OFTrue; cmd.beginOptionBlock(); if (cmd.findOption("--instance-one")) { app.checkConflict("--instance-one", "--series-from", (opt_seriesFile != "") && opt_readSeriesInfo); opt_increment = OFFalse; opt_instance = 1; } if (cmd.findOption("--instance-inc")) { app.checkDependence("--instance-inc", "--series-from", (opt_seriesFile != "") && opt_readSeriesInfo); opt_increment = OFTrue; } if (cmd.findOption("--instance-set")) { opt_increment = OFFalse; app.checkValue(cmd.getValueAndCheckMin(opt_instance, 1)); } cmd.endOptionBlock(); } OFCondition DcmEncapsulatedDocument::createIdentifiers(OFLogger &appLogger) { char buf[100]; OFCondition cond = EC_Normal; Sint32 incrementedInstance = 0; if (opt_seriesFile != "") { DcmFileFormat dfile; cond = dfile.loadFile(opt_seriesFile, EXS_Unknown, EGL_noChange); if (cond.bad()) { OFLOG_WARN(appLogger, cond.text() << ": reading file: " << opt_seriesFile); } else { const char *c = NULL; DcmDataset *dset = dfile.getDataset(); if (dset) { OFLOG_TRACE(appLogger, "reading patient attributes"); c = NULL; if (dset->findAndGetString(DCM_PatientName, c).good() && c) { opt_patientName = c; } c = NULL; if (dset->findAndGetString(DCM_PatientID, c).good() && c) { opt_patientID = c; } c = NULL; if (dset->findAndGetString(DCM_PatientBirthDate, c).good() && c) { opt_patientBirthdate = c; } c = NULL; if (dset->findAndGetString(DCM_PatientSex, c).good() && c) { opt_patientSex = c; } OFLOG_TRACE(appLogger, "reading study attributes"); c = NULL; if (dset->findAndGetString(DCM_StudyInstanceUID, c).good() && c) { opt_studyUID = c; } OFLOG_TRACE(appLogger, "reading series attributes"); if (opt_readSeriesInfo) { c = NULL; if (dset->findAndGetString(DCM_SeriesInstanceUID, c).good() && c) { opt_seriesUID = c; } if (dset->findAndGetSint32(DCM_InstanceNumber, incrementedInstance).good()) { ++incrementedInstance; } else { incrementedInstance = 0; } if (opt_increment) opt_instance = incrementedInstance; } if (ftype == "stl") { OFLOG_TRACE(appLogger, "reading STL specific information"); c = NULL; OFLOG_TRACE(appLogger, "reading Frame of Reference Info"); if (dset->findAndGetString(DCM_FrameOfReferenceUID, c).good() && c) { opt_frameOfReferenceUID = c; } c = NULL; if (dset->findAndGetString(DCM_PositionReferenceIndicator, c).good() && c) { opt_positionReferenceIndicator = c; } OFLOG_TRACE(appLogger, "reading Enhanced Equipment info"); c = NULL; if (dset->findAndGetString(DCM_Manufacturer, c).good() && c) { opt_manufacturer = c; } c = NULL; if (dset->findAndGetString(DCM_ManufacturerModelName, c).good() && c) { opt_manufacturerModelName = c; } c = NULL; if (dset->findAndGetString(DCM_DeviceSerialNumber, c).good() && c) { opt_deviceSerialNumber = c; } c = NULL; if (dset->findAndGetString(DCM_SoftwareVersions, c).good() && c) { opt_softwareVersions = c; } OFLOG_TRACE(appLogger, "reading manufacturing 3d model info"); { OFLOG_TRACE(appLogger, "manufacturing 3d model info read successfully"); } } } } } if (opt_studyUID.empty()) { dcmGenerateUniqueIdentifier(buf, SITE_STUDY_UID_ROOT); opt_studyUID = buf; } if (opt_seriesUID.empty()) { dcmGenerateUniqueIdentifier(buf, SITE_SERIES_UID_ROOT); opt_seriesUID = buf; } return cond; } int DcmEncapsulatedDocument::insertEncapsulatedDocument( DcmItem *dataset, OFLogger &appLogger) { char buf[100]; size_t fileSize = 0; size_t buflen = 100; struct stat fileStat; if (0 == stat(opt_ifname.c_str(), &fileStat)) { fileSize = OFstatic_cast(size_t, fileStat.st_size); } else { OFLOG_ERROR(appLogger, "file " << opt_ifname << " not found"); return EXITCODE_NO_INPUT_FILES; } if (fileSize == 0) { OFLOG_ERROR(appLogger, "file " << opt_ifname << " is empty"); return EXITCODE_INVALID_INPUT_FILE; } FILE *encapfile = fopen(opt_ifname.c_str(), "rb"); if (encapfile == NULL) { OFLOG_ERROR(appLogger, "unable to read file " << opt_ifname); return EXITCODE_CANNOT_READ_INPUT_FILE; } if (fileSize < buflen) { buflen = fileSize; } if (buflen != fread(buf, 1, buflen, encapfile)) { OFLOG_ERROR(appLogger, "read error in file " << opt_ifname); fclose(encapfile); return EXITCODE_INVALID_INPUT_FILE; } if (ftype == "pdf") { // check magic word for PDF file if (0 != strncmp("%PDF-", buf, 5)) { OFLOG_ERROR(appLogger, "file " << opt_ifname << " is not a PDF file"); fclose(encapfile); return EXITCODE_INVALID_INPUT_FILE; } // check PDF version number char *version = buf + 5; OFBool found = OFFalse; for (int i = 0; i < 5; ++i) { if (version[i] == 10 || version[i] == 13) { version[i] = 0; // insert end of string found = OFTrue; break; } } if (!found) { OFLOG_ERROR(appLogger, "file " << opt_ifname << ": unable to decode PDF version number"); fclose(encapfile); return EXITCODE_INVALID_INPUT_FILE; } OFLOG_INFO(appLogger, "file " << opt_ifname << ": PDF " << version << ", " << (fileSize + 1023) / 1024 << "kB"); } else { if (ftype == "cda") { //xml validation occurs when getting data OFLOG_INFO(appLogger, "file " << opt_ifname << ": HL7 CDA file (XML Format)" << ", " << (fileSize + 1023) / 1024 << "kB"); } else { if (ftype == "stl") { // Each facet contains: // - Normals: 3 floats (4 bytes) // - Vertices: 3x floats (4 byte each, 12 bytes total) // - AttributeCount: 1 short (2 bytes) // Total: 50 bytes per facet const size_t facetSize32 = 3 * sizeof(Float32) + 3 * 3 * sizeof(Float32) + sizeof(Uint16); const size_t facetSize64 = 3 * sizeof(Float64) + 3 * 3 * sizeof(Float64) + sizeof(Uint16); // STL validation for ASCII CODE if (fileSize < 15) { // "solid " and "endsolid " markers for an ASCII file OFLOG_ERROR(appLogger, "The STL file is not long enough" << " (" << fileSize << "kB)"); fclose(encapfile); return EXITCODE_INVALID_INPUT_FILE; } // Binary files should never start with "solid ", // but just in case, check for ASCII, // and if not valid then check for binary... // Look for text "solid " in first 6 bytes, // indicating the possibility that this is an // ASCII STL format. if (0 == strncmp("solid ", buf, 6)) { OFLOG_ERROR(appLogger, "File " << opt_ifname << " starts with 'solid '. " << "It is a valid STL file but it is in ASCII Code" << "and DICOM only accepts binary STL"); return EXITCODE_INVALID_INPUT_FILE; } //////STL validation for Binary Format else { OFLOG_DEBUG(appLogger, "Magic word 'solid ' not found. " << "Validating STL file " << "in Binary format"); // 80-byte header + 4-byte "number of triangles" for a binary file if (fileSize < 84) { OFLOG_ERROR(appLogger, "The binary STL file is not long enough" << " (" << fileSize << "kB)"); fclose(encapfile); return EXITCODE_INVALID_INPUT_FILE; } // Header is from bytes 0-79 // The number of Triangles starts at byte offset 80 and is a uint32 (4 Bytes) char ntriangleschar[5]; for (int j = 0; j < 4; j++) ntriangleschar[j] = buf[80 + j]; ntriangleschar[4] = 0; Uint32 *nTriangles = OFreinterpret_cast(Uint32*, ntriangleschar); // Verify that file size equals the sum of // header + nTriangles value + all triangles OFLOG_DEBUG(appLogger, "verifying if the file size is consistent"); if (fileSize == (84 + *OFconst_cast(Uint32*, nTriangles) * facetSize32) || fileSize == (84 + *OFconst_cast(Uint32*, nTriangles) * facetSize64)) { OFLOG_DEBUG(appLogger, "File " << opt_ifname << " passed binary STL validation." << OFendl << "Assuming valid STL file " << "in binary format" ); OFLOG_TRACE(appLogger, "The binary STL file is:" << OFendl << fileSize << " kB " << " as expected." << OFendl << (84 + *OFconst_cast(Uint32 * , nTriangles) * facetSize32) << " kB for x86" << OFendl << (84 + *OFconst_cast(Uint32 * , nTriangles) * facetSize64) << " kB for x64" << OFendl << "(84 + triangles number * facet size)" << OFendl << " number of Triangles " << *OFconst_cast(Uint32 * , nTriangles) << OFendl << " nTriangles (Uint32): " << nTriangles << OFendl << " facetSize32: " << facetSize32 << OFendl << " facetSize64: " << facetSize64 << OFendl ); } else { OFLOG_ERROR(appLogger, "The binary STL file is not consistent." << OFendl << (84 + *OFconst_cast(Uint32 * , nTriangles) * facetSize32) << " kB for x86 and " << (84 + *OFconst_cast(Uint32 * , nTriangles) * facetSize64) << " kB for x64 " << OFendl << "(84 + triangles number * facet size)" << OFendl << " number of Triangles " << *OFconst_cast(Uint32 * , nTriangles) << OFendl << " nTriangles (Uint32): " << nTriangles << OFendl << " facetSize32: " << facetSize32 << OFendl << " facetSize64: " << facetSize64 << OFendl ); fclose(encapfile); return EXITCODE_INVALID_INPUT_FILE; } } } else { OFLOG_WARN(appLogger, "Filetype not supported or filetype not set. Current ftype is " << ftype << OFendl << "The name of the passed logger is: " << appLogger.getName()); } } } if (0 != fseek(encapfile, 0, SEEK_SET)) { OFLOG_ERROR(appLogger, "file " << opt_ifname << ": seek error"); fclose(encapfile); return EXITCODE_CANNOT_READ_INPUT_FILE; } OFCondition result = EC_Normal; DcmPolymorphOBOW *elem = new DcmPolymorphOBOW(DCM_EncapsulatedDocument); if (elem) { size_t numBytes = fileSize; // according to CP 1851 result = dataset->putAndInsertUint32(DCM_EncapsulatedDocumentLength, OFstatic_cast(Uint32, numBytes)); if (numBytes & 1) ++numBytes; Uint8 *bytes = NULL; if (result.good()) { result = elem->createUint8Array(OFstatic_cast(Uint32, numBytes), bytes); } else { return EXITCODE_CANNOT_WRITE_OUTPUT_FILE; } if (result.good()) { // blank pad byte bytes[numBytes - 1] = 0; // read file content if (fileSize != fread(bytes, 1, fileSize, encapfile)) { OFLOG_ERROR(appLogger, "read error in file " << opt_ifname); return EXITCODE_CANNOT_READ_INPUT_FILE; } } else { return EXITCODE_MEMORY_EXHAUSTED; } } else { fclose(encapfile); return EXITCODE_MEMORY_EXHAUSTED; } // if successful, insert element into dataset if (result.good()) { result = dataset->insert(elem); } else { delete elem; OFLOG_ERROR(appLogger, "Unsuccessful, did not insert element."); return EXITCODE_CANNOT_WRITE_OUTPUT_FILE; } // close file fclose(encapfile); if (result.good()) { return EXITCODE_NO_ERROR; } else { return EXITCODE_CANNOT_WRITE_OUTPUT_FILE; } } OFCondition DcmEncapsulatedDocument::createHeader( DcmItem *dataset, OFLogger &logger) { OFCondition result = EC_Normal; char buf[80]; // insert empty type 2 attributes if (result.good()) result = dataset->insertEmptyElement(DCM_StudyDate); if (result.good()) result = dataset->insertEmptyElement(DCM_StudyTime); if (result.good()) result = dataset->insertEmptyElement(DCM_AccessionNumber); if (result.good()) result = dataset->insertEmptyElement(DCM_Manufacturer); if (result.good()) result = dataset->insertEmptyElement(DCM_ReferringPhysicianName); if (result.good()) result = dataset->insertEmptyElement(DCM_StudyID); if (result.good()) result = dataset->insertEmptyElement(DCM_ContentDate); if (result.good()) result = dataset->insertEmptyElement(DCM_ContentTime); if (result.good()) result = dataset->insertEmptyElement(DCM_AcquisitionDateTime); if (result.good()) { if (opt_conceptCSD != "" && opt_conceptCV != "" && opt_conceptCM != "") { result = DcmCodec::insertCodeSequence(dataset, DCM_ConceptNameCodeSequence, opt_conceptCSD.c_str(), opt_conceptCV.c_str(), opt_conceptCM.c_str()); } else { result = dataset->insertEmptyElement(DCM_ConceptNameCodeSequence); } } // insert const value attributes if (result.good()) { result = dataset->putAndInsertString(DCM_SpecificCharacterSet, "ISO_IR 100"); } //insert encapsulated file storage UID (CDA/PDF/STL) if (result.good()) { if (ftype == "pdf") { OFLOG_TRACE(logger, "Inserting SOPClassUID to dataset"); result = dataset->putAndInsertString(DCM_SOPClassUID, UID_EncapsulatedPDFStorage); } if (ftype == "cda") { OFLOG_TRACE(logger, "Inserting SOPClassUID to dataset"); result = dataset->putAndInsertString(DCM_SOPClassUID, UID_EncapsulatedCDAStorage); } if (ftype == "stl") {//STL Specific modules OFLOG_TRACE(logger, "Validating Frame of Reference UID value"); if (opt_frameOfReferenceUID.empty()) { OFLOG_DEBUG(logger, "Frame of Reference UID " << DCM_FrameOfReferenceUID << " value was empty, generating a new one." ); dcmGenerateUniqueIdentifier(buf, SITE_SERIES_UID_ROOT); opt_frameOfReferenceUID = buf; } else { if (DcmUniqueIdentifier::checkStringValue(opt_frameOfReferenceUID, "1").bad()) { OFLOG_DEBUG(logger, "Frame of Reference UID " << DCM_FrameOfReferenceUID << " value was faulty, generating a new one." ); dcmGenerateUniqueIdentifier(buf, SITE_SERIES_UID_ROOT); opt_frameOfReferenceUID = buf; } } if (result.good()) { OFLOG_TRACE(logger, "Inserting Frame of Reference info to dataset"); result = dataset->putAndInsertOFStringArray(DCM_FrameOfReferenceUID, opt_frameOfReferenceUID); } if (result.good()) result = dataset->putAndInsertOFStringArray(DCM_PositionReferenceIndicator, opt_positionReferenceIndicator); OFLOG_TRACE(logger, "Validating and inserting Enhanced General Equipment fields"); if (result.good()) { if (opt_manufacturer.empty()) { opt_manufacturer = "DCMTK_MANUFACTURING"; OFLOG_WARN(logger, "No Manufacturer " << DCM_Manufacturer << " provided nor found in series. This attribute is " << "required for Enhanced General Equipment module. " << opt_manufacturer << " will be inserted as dummy value." ); } result = dataset->putAndInsertOFStringArray(DCM_Manufacturer, opt_manufacturer); } if (result.good()) { if (opt_manufacturerModelName.empty()) { opt_manufacturerModelName = "DCMTK_3DMODEL_3"; OFLOG_WARN(logger, "No Manufacturer Model Name " << DCM_ManufacturerModelName << " provided nor found in series. This attribute is " << "required for Enhanced General Equipment module. " << opt_manufacturerModelName << " will be inserted as dummy value." ); } result = dataset->putAndInsertOFStringArray(DCM_ManufacturerModelName, opt_manufacturerModelName); } if (result.good()) { if (opt_deviceSerialNumber.empty()) { opt_deviceSerialNumber = "DCMTK01234567890"; OFLOG_WARN(logger, "No Device Serial Number " << DCM_DeviceSerialNumber << " provided nor found in series. This attribute is " << "required for Enhanced General Equipment module. " << opt_deviceSerialNumber << " will be inserted as dummy value." ); } result = dataset->putAndInsertOFStringArray(DCM_DeviceSerialNumber, opt_deviceSerialNumber); } if (result.good()) { if (opt_softwareVersions.empty()) { opt_softwareVersions = OFFIS_DCMTK_VERSION; OFLOG_WARN(logger, "No Software Versions " << DCM_SoftwareVersions << " provided nor found in series. This attribute is " << "required for Enhanced General Equipment module. " << opt_softwareVersions << " will be inserted as dummy value." ); } result = dataset->putAndInsertOFStringArray(DCM_SoftwareVersions, opt_softwareVersions); } if (result.good()) { if (opt_measurementUnitsCSD != "" && opt_measurementUnitsCV != "" && opt_measurementUnitsCM != "") { result = DcmCodec::insertCodeSequence(dataset, DCM_MeasurementUnitsCodeSequence, opt_measurementUnitsCSD.c_str(), opt_measurementUnitsCV.c_str(), opt_measurementUnitsCM.c_str()); } else { OFLOG_DEBUG(logger, "Measurement Units Code Sequence " << DCM_FrameOfReferenceUID << "had one or more empty values, generating default values." ); result = DcmCodec::insertCodeSequence(dataset, DCM_MeasurementUnitsCodeSequence, "UCUM", "um", "um"); } } if (result.good()) { OFLOG_TRACE(logger, "Inserting SOPClassUID to dataset"); result = dataset->putAndInsertString(DCM_SOPClassUID, UID_EncapsulatedSTLStorage); } } } if (result.good()) { if (ftype == "stl") { result = dataset->putAndInsertString(DCM_Modality, "M3D"); } else { // we are now using "DOC" for the modality, which seems to be more appropriate than "OT" (see CP-749) result = dataset->putAndInsertString(DCM_Modality, "DOC"); } } if (result.good()) { if (ftype != "stl") { OFLOG_TRACE(logger, "Inserting default Conversion type: Workstation (WSD) to dataset"); result = dataset->putAndInsertString(DCM_ConversionType, "WSD"); } else { OFLOG_TRACE(logger, "STL has no Conversion Type"); result = EC_Normal; } } if (result.good()) { // according to C.24.2.1 on part 3, (0042,0012) is text/XML for CDA. if (ftype == "cda") result = dataset->putAndInsertString(DCM_MIMETypeOfEncapsulatedDocument, "text/XML"); // according to A.45.1.4.1 on part 3, MIME Type is application/pdf for PDF. if (ftype == "pdf") result = dataset->putAndInsertString(DCM_MIMETypeOfEncapsulatedDocument, "application/pdf"); // according to A.85.1.4.2 on part 3, MIME Type is model/stl. if (ftype == "stl") result = dataset->putAndInsertString(DCM_MIMETypeOfEncapsulatedDocument, "model/stl"); } // there is no way we could determine a meaningful series number, so we just use a constant. if (result.good()) result = dataset->putAndInsertString(DCM_SeriesNumber, "1"); // insert variable value attributes if (result.good()) result = dataset->putAndInsertString(DCM_DocumentTitle, opt_documentTitle.c_str()); if (result.good()) result = dataset->putAndInsertString(DCM_PatientName, opt_patientName.c_str()); if (result.good()) result = dataset->putAndInsertString(DCM_PatientID, opt_patientID.c_str()); if (result.good()) result = dataset->putAndInsertString(DCM_PatientBirthDate, opt_patientBirthdate.c_str()); if (result.good()) result = dataset->putAndInsertString(DCM_PatientSex, opt_patientSex.c_str()); if (result.good()) result = dataset->putAndInsertString(DCM_BurnedInAnnotation, opt_annotation ? "YES" : "NO"); if (strlen(cda_mediaTypes.c_str()) > 0) { if (result.good()) result = dataset->putAndInsertString(DCM_ListOfMIMETypes, cda_mediaTypes.c_str()); } if (hl7_InstanceIdentifier.size() > 0) { if (result.good()) result = dataset->putAndInsertString(DCM_HL7InstanceIdentifier, hl7_InstanceIdentifier.c_str()); } sprintf(buf, "%ld", OFstatic_cast(long, opt_instance)); if (result.good()) result = dataset->putAndInsertString(DCM_InstanceNumber, buf); dcmGenerateUniqueIdentifier(buf, SITE_INSTANCE_UID_ROOT); if (result.good()) result = dataset->putAndInsertString(DCM_StudyInstanceUID, opt_studyUID.c_str()); if (result.good()) result = dataset->putAndInsertString(DCM_SeriesInstanceUID, opt_seriesUID.c_str()); if (result.good()) result = dataset->putAndInsertString(DCM_SOPInstanceUID, buf); // set instance creation date and time OFString s; if (result.good()) result = DcmDate::getCurrentDate(s); if (result.good()) result = dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, s); if (result.good()) result = DcmTime::getCurrentTime(s); if (result.good()) result = dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, s); return result; } OFCondition DcmEncapsulatedDocument::applyOverrideKeys(DcmDataset *outputDset) { // replace specific keys by those in overrideKeys, copied from findscu OFListConstIterator(OFString) path = opt_overrideKeys.begin(); OFListConstIterator(OFString) endOfList = opt_overrideKeys.end(); OFCondition cond; DcmPathProcessor proc; while (path != endOfList) { cond = proc.applyPathWithValue(outputDset, *path); if (cond.bad()) { OFString err; err += "Bad override key/path: "; err += *path; err += ": "; err += cond.text(); return makeOFCondition(OFM_dcmdata, 18, OF_error, err.c_str()); } path++; } return cond; } void DcmEncapsulatedDocument::setOverrideKeys(const OFList &ovkeys) { OFListConstIterator(OFString) it = ovkeys.begin(); OFListConstIterator(OFString) end = ovkeys.end(); while (it != end) { opt_overrideKeys.push_back(*it); it++; } } OFCondition DcmEncapsulatedDocument::saveFile(DcmFileFormat fileformat) { return fileformat.saveFile(opt_ofname, opt_oxfer, opt_oenctype, opt_oglenc, opt_opadenc, OFstatic_cast(Uint32, opt_filepad), OFstatic_cast(Uint32, opt_itempad)); } OFString DcmEncapsulatedDocument::getInputFileName() { return opt_ifname; } void DcmEncapsulatedDocument::setInputFileName(OFString fName) { opt_ifname = fName; } OFString DcmEncapsulatedDocument::getOutputFileName() { return opt_ofname; } void DcmEncapsulatedDocument::setOutputFileName(OFString fName) { opt_ofname = fName; } OFString DcmEncapsulatedDocument::getFileType() { return ftype; } void DcmEncapsulatedDocument::setFileType(OFString fType) { ftype = fType; } E_TransferSyntax DcmEncapsulatedDocument::getTransferSyntax() { return opt_oxfer; } DcmEncapsulatedDocument::~DcmEncapsulatedDocument() { }