#include "dcm_move.h" //------------------------------------------------------------------------------------------------------ // static function static void moveCallback(void *callbackData, T_DIMSE_C_MoveRQ *request, int responseCount, T_DIMSE_C_MoveRSP *response) { dcm_cmove_callback * callback = reinterpret_cast(callbackData); if (callback) { callback->callback(request, responseCount, response); } } //----------------------------------------------------------------------------------------------------- // c-move callback dcm_cmove_callback::dcm_cmove_callback() { } dcm_cmove_callback::~dcm_cmove_callback() { } void dcm_cmove_callback::setAssoc(T_ASC_Association * assoc) { assoc = assoc; } void dcm_cmove_callback::setPresetnationContextID(const T_ASC_PresentationContextID& presId) { presId_ = presId; } void dcm_cmove_callback::setCancelAfterNReponse(int n) { cancelAfterNResponse_ = n; } ////dcm_cmove_callback::dcm_cmove_callback(const dcm_cmove_callback& other) ////{ ////} //// ////dcm_cmove_callback& dcm_cmove_callback::operator=(const dcm_cmove_callback& other) ////{ ////} // default implementation dcm_cmove_callback_default::dcm_cmove_callback_default() { } dcm_cmove_callback_default::~dcm_cmove_callback_default() { } void dcm_cmove_callback_default::callback(T_DIMSE_C_MoveRQ *request, int responseCount, T_DIMSE_C_MoveRSP *response) { OFCondition cond = EC_Normal; if (cancelAfterNResponse_ == responseCount) { cond = DIMSE_sendCancelRequest(assoc_, presId_, request->MessageID); if (cond != EC_Normal) { // log << Cancel Request Failed } } } //------------------------------------------------------------------------------------------------------ // static function static void storeSCPCallback(void *callbackData, T_DIMSE_StoreProgress *progress, T_DIMSE_C_StoreRQ *req, char *imageFileName, DcmDataset **imageDataSet, T_DIMSE_C_StoreRSP *rsp, DcmDataset **statusDetail) { dcm_cmove_storescp_callback *callback = reinterpret_cast(callbackData); if (callback) { callback->callback(progress, req, imageFileName, imageDataSet, rsp, statusDetail); } } static void subOpCallback(void *callbackData, T_ASC_Network *aNet, T_ASC_Association **subAssoc) { dcm_cmove *cbdata = reinterpret_cast(callbackData); if (cbdata == NULL) { return; } if (aNet == NULL) { return; } if (*subAssoc == NULL) { cbdata->acceptSubAssoc(aNet, subAssoc); } else { cbdata->subOpSCP(subAssoc); } } //------------------------------------------------------------------------------------------------------ // c-store scp callback dcm_cmove_storescp_callback::dcm_cmove_storescp_callback() { } dcm_cmove_storescp_callback::~dcm_cmove_storescp_callback() { } void dcm_cmove_storescp_callback::setImageFileName(char * imageFileName) { imageFile_ = imageFileName; } void dcm_cmove_storescp_callback::setDcmFileFormat(DcmFileFormat * dcmff) { dcmff_ = dcmff; } void dcm_cmove_storescp_callback::setAssoc(T_ASC_Association * assoc) { assoc_ = assoc; } ////dcm_cmove_storescp_callback::dcm_cmove_storescp_callback(const dcm_cmove_storescp_callback& other) ////{ ////} //// ////dcm_cmove_storescp_callback& dcm_cmove_storescp_callback::operator=(const dcm_cmove_storescp_callback& other) ////{ ////} // default implementation dcm_cmove_storescp_callback_default::dcm_cmove_storescp_callback_default(std::string outputDirectory) : dcm_cmove_storescp_callback() , abortDuringStore_(false) , abortAfterStore_(false) , sleepDuring_(0) , bitPreserving_(false) , ignore_(false) , writeTransferSyntax_(EXS_Unknown) , sequenceType_(EET_ExplicitLength) , groupLength_(EGL_recalcGL) , paddingType_(EPD_withoutPadding) , filepad_(0) , itempad_(0) , useMetaheader_(true) { outputDirectory_ = outputDirectory.c_str(); } dcm_cmove_storescp_callback_default::~dcm_cmove_storescp_callback_default() { } void dcm_cmove_storescp_callback_default::callback(T_DIMSE_StoreProgress *progress, T_DIMSE_C_StoreRQ *request, char *imageFileName, DcmDataset **imageDataSet, T_DIMSE_C_StoreRSP *response, DcmDataset **statusDetail) { DIC_UI sopClass; DIC_UI sopInstance; if ((abortDuringStore_ && progress->state != DIMSE_StoreBegin) || (abortAfterStore_ && progress->state == DIMSE_StoreEnd)) { // log >> ABORT initiated ASC_abortAssociation(assoc_); response->DimseStatus = STATUS_STORE_Refused_OutOfResources; return; } if (sleepDuring_ > 0) { OFStandard::sleep(static_cast(sleepDuring_)); } switch (progress->state) { case DIMSE_StoreBegin: // log << "Recv: " break; case DIMSE_StoreEnd: // log << "End" break; default: // log << "." break; } if (progress->state == DIMSE_StoreEnd) { *statusDetail = NULL; if ((imageDataSet != NULL) && (*imageDataSet != NULL) && !bitPreserving_ && !ignore_) { std::string ofname; OFStandard::combineDirAndFilename(ofname, outputDirectory_, imageFile_, true); if (OFStandard::fileExists(ofname)) { //log << "DICOM file already exists, overwriting: } E_TransferSyntax xfer = writeTransferSyntax_; if (xfer == EXS_Unknown) { xfer = (*imageDataSet)->getOriginalXfer(); } OFCondition cond = dcmff_->saveFile(ofname.c_str(), xfer, sequenceType_, groupLength_, paddingType_, static_cast(filepad_), static_cast(itempad_), useMetaheader_ ? EWM_fileformat : EWM_dataset); if (cond.bad()) { // log << cannot write DICOM file response->DimseStatus = STATUS_STORE_Refused_OutOfResources; OFStandard::deleteFile(ofname); } if ((response->DimseStatus == STATUS_Success) && (!ignore_)) { if (!DU_findSOPClassAndInstanceInDataSet(*imageDataSet, sopClass, sizeof(sopClass), sopClass, sizeof(sopInstance), correctUIDPadding_)) { // log << bad DICOM file response->DimseStatus = STATUS_STORE_Error_CannotUnderstand; } else if (strcmp(sopClass, request->AffectedSOPClassUID) != 0) { response->DimseStatus = STATUS_STORE_Error_DataSetDoesNotMatchSOPClass; } else if (strcmp(sopInstance, request->AffectedSOPInstanceUID) != 0) { response->DimseStatus = STATUS_STORE_Error_DataSetDoesNotMatchSOPClass; } } } } } //-------------------------------------------------------------------------------------------------------- // dcm-cmove typedef struct { const char * findSyntax; const char * moveSyntax; } QuerySyntax; static QuerySyntax querySyntax[3] = { { UID_FINDPatientRootQueryRetrieveInformationModel, UID_MOVEPatientRootQueryRetrieveInformationModel }, { UID_FINDStudyRootQueryRetrieveInformationModel, UID_MOVEStudyRootQueryRetrieveInformationModel }, { UID_RETIRED_FINDPatientStudyOnlyQueryRetrieveInformationModel, UID_RETIRED_MOVEPatientStudyOnlyQueryRetrieveInformationModel } }; dcm_cmove::dcm_cmove(const char *peerIp, unsigned long peerPort, const char *peerTitle, unsigned long ourPort, const char *ourTile) : cmove_callback(NULL) , storescp_callback(NULL) , sleepAfter(0) , sleepDuring(0) , maxPDU(ASC_DEFAULTMAXPDU) , useMetaheader(true) , acceptAllXfer(true) , in_networkTransferSyntax(EXS_Unknown) , out_networkTransferSyntax(EXS_Unknown) , bitPreserving(false) , ignore(false) , repeatCount(1) , abortAssociation(false) , queryModel(QMPatientRoot) , blockMode(DIMSE_BLOCKING) , dimse_timeout(0) , acse_timeout(30) , ignorePendingDatasets(true) , net(NULL) , overrideKeys(NULL) { peerIp_ = peerIp; peerPort_ = peerPort; peerTitle_ = peerTitle; ourPort_ = ourPort; ourTitle_ = new char[1024]; sprintf(ourTitle_, "%s", ourTile); } dcm_cmove::~dcm_cmove() { if (ourTitle_ != NULL) { delete[] ourTitle_; } } void dcm_cmove::set_sleep_after(unsigned long after) { sleepAfter = after; } void dcm_cmove::set_sleep_during(unsigned long during) { sleepDuring = during; } void dcm_cmove::set_dimse_timeout(int timeout) { dimse_timeout = timeout; } void dcm_cmove::set_acse_timeout(int timeout) { acse_timeout = timeout; } void dcm_cmove::set_cmove_callback(dcm_cmove_callback * callback) { cmove_callback = callback; } void dcm_cmove::set_cmove_scp_callback(dcm_cmove_storescp_callback * callback) { storescp_callback = callback; } int dcm_cmove::move_by_patient_id(std::string patient_id) { queryModel = QMPatientRoot; addOverrideKey("0008,0052=PATIENT"); std::string patient_id_ = "0010,0020="; patient_id_ += patient_id; addOverrideKey(patient_id_.c_str()); return docmove(); } int dcm_cmove::move_by_study_uid(std::string study_uid) { queryModel = QMStudyRoot; addOverrideKey("0008,0052=STUDY"); std::string studyinstance_uid_ = "0020,000D="; studyinstance_uid_ += study_uid; addOverrideKey(studyinstance_uid_.c_str()); return docmove(); } int dcm_cmove::move_by_series_uid(std::string study_uid, std::string series_uid) { queryModel = QMStudyRoot; addOverrideKey("0008,0052=SERIES"); std::string studyinstance_uid_ = "0020,000D="; studyinstance_uid_ += study_uid; addOverrideKey(studyinstance_uid_.c_str()); std::string seriesinstance_uid_ = "0020,000E="; seriesinstance_uid_ += series_uid; addOverrideKey(seriesinstance_uid_.c_str()); return docmove(); } int dcm_cmove::move_by_image_uid(std::string study_uid, std::string series_uid, std::string image_uid) { queryModel = QMStudyRoot; addOverrideKey("0008,0052=IMAGE"); std::string studyinstance_uid_ = "0020,000D="; studyinstance_uid_ += study_uid; addOverrideKey(studyinstance_uid_.c_str()); std::string seriesinstance_uid_ = "0020,000E="; seriesinstance_uid_ += series_uid; addOverrideKey(seriesinstance_uid_.c_str()); std::string image_uid_ = "0008,0018="; image_uid_ += image_uid; addOverrideKey(image_uid_.c_str()); return docmove(); } void dcm_cmove::addOverrideKey(const char *s) { unsigned int g = 0xffff; unsigned int e = 0xffff; int n = 0; std::string dicName, valStr; n = sscanf(s, "%x,%x=", &g, &e); std::string toParse = s; size_t eqPos = toParse.find('='); if (n < 2) { if (eqPos != std::string::npos) { dicName = toParse.substr(0, eqPos).c_str(); valStr = toParse.substr(eqPos + 1, toParse.length()); } else { dicName = s; } DcmTagKey key(0xffff, 0xffff); const DcmDataDictionary& globalDataDict = dcmDataDict.rdlock(); const DcmDictEntry * dicent = globalDataDict.findEntry(dicName.c_str()); dcmDataDict.rdunlock(); if (dicent != NULL) { key = dicent->getKey(); g = key.getGroup(); e = key.getElement(); } else { // log << bad key format or dictionary name not found in dictionary } } else { if (eqPos != std::string::npos) { valStr = toParse.substr(eqPos + 1, toParse.length()); } } DcmTag tag(g, e); if (tag.error() != EC_Normal) { // log << unknown tag } DcmElement *elem = DcmItem::newDicomElement(tag); if (elem == NULL) { // log << cannot create element for tag } if (!valStr.empty()) { if (elem->putString(valStr.c_str()).bad()) { // log << cannot put tag value } } if (overrideKeys == NULL) { overrideKeys = new DcmDataset; } if (overrideKeys->insert(elem, true).bad()) { // log << cannot insert tag } } OFCondition dcm_cmove::addPresentationContext(T_ASC_Parameters * params, T_ASC_PresentationContextID pid, const char * abstractSyntax) { const char *transferSyntax[] = {NULL, NULL, NULL, NULL}; int numTransferSyntaxes = 0; switch (out_networkTransferSyntax) { case EXS_LittleEndianImplicit: transferSyntax[0] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 1; break; case EXS_LittleEndianExplicit: transferSyntax[0] = UID_LittleEndianExplicitTransferSyntax; transferSyntax[1] = UID_BigEndianExplicitTransferSyntax; transferSyntax[2] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 3; break; case EXS_BigEndianExplicit: transferSyntax[0] = UID_BigEndianExplicitTransferSyntax; transferSyntax[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntax[2] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 3; break; default: if (gLocalByteOrder == EBO_LittleEndian) { transferSyntax[0] = UID_LittleEndianExplicitTransferSyntax; transferSyntax[1] = UID_BigEndianExplicitTransferSyntax; } else { transferSyntax[0] = UID_BigEndianExplicitTransferSyntax; transferSyntax[1] = UID_LittleEndianExplicitTransferSyntax; } transferSyntax[2] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 3; break; } return ASC_addPresentationContext(params, pid, abstractSyntax, transferSyntax, numTransferSyntaxes); } void dcm_cmove::substituteOverrideKeys(DcmDataset *dset) { if (overrideKeys == NULL) return; DcmDataset keys(*overrideKeys); unsigned long elemCount = keys.card(); for (unsigned long i = 0; i < elemCount; i++) { DcmElement *elem = keys.remove(static_cast(0)); dset->insert(elem, true); } } OFCondition dcm_cmove::acceptSubAssoc(T_ASC_Network *aNet, T_ASC_Association **assoc) { const char *knownAbstractSyntaxes[] = { UID_VerificationSOPClass }; const char* transferSyntaxes[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //10 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //20 NULL //+1 }; int numTransferSyntaxes; OFCondition cond = ASC_receiveAssociation(aNet, assoc, maxPDU); if (cond.good()) { switch (in_networkTransferSyntax) { case EXS_LittleEndianImplicit: transferSyntaxes[0] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 1; break; case EXS_LittleEndianExplicit: transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 3; break; case EXS_BigEndianExplicit: transferSyntaxes[0] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 3; break; case EXS_JPEGProcess14SV1: transferSyntaxes[0] = UID_JPEGProcess14SV1TransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_JPEGProcess1: transferSyntaxes[0] = UID_JPEGProcess1TransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_JPEGProcess2_4: transferSyntaxes[0] = UID_JPEGProcess2_4TransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_JPEG2000LosslessOnly: transferSyntaxes[0] = UID_JPEG2000LosslessOnlyTransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_JPEG2000: transferSyntaxes[0] = UID_JPEG2000TransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_JPEGLSLossless: transferSyntaxes[0] = UID_JPEGLSLosslessTransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_JPEGLSLossy: transferSyntaxes[0] = UID_JPEGLSLossyTransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_MPEG2MainProfileAtMainLevel: transferSyntaxes[0] = UID_MPEG2MainProfileAtMainLevelTransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes; break; case EXS_MPEG2MainProfileAtHighLevel: transferSyntaxes[0] = UID_MPEG2MainProfileAtHighLevelTransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_MPEG4HighProfileLevel4_1: transferSyntaxes[0] = UID_MPEG4HighProfileLevel4_1TransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_MPEG4BDcompatibleHighProfileLevel4_1: transferSyntaxes[0] = UID_MPEG4BDcompatibleHighProfileLevel4_1TransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_MPEG4HighProfileLevel4_2_For2DVideo: transferSyntaxes[0] = UID_MPEG4HighProfileLevel4_2_For2DVideoTransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_MPEG4HighProfileLevel4_2_For3DVideo: transferSyntaxes[0] = UID_MPEG4HighProfileLevel4_2_For3DVideoTransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_MPEG4StereoHighProfileLevel4_2: transferSyntaxes[0] = UID_MPEG4StereoHighProfileLevel4_2TransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_HEVCMainProfileLevel5_1: transferSyntaxes[0] = UID_HEVCMainProfileLevel5_1TransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_HEVCMain10ProfileLevel5_1: transferSyntaxes[0] = UID_HEVCMain10ProfileLevel5_1TransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; case EXS_RLELossless: transferSyntaxes[0] = UID_RLELosslessTransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 4; break; default: if (acceptAllXfer) { transferSyntaxes[0] = UID_JPEG2000TransferSyntax; transferSyntaxes[1] = UID_JPEG2000LosslessOnlyTransferSyntax; transferSyntaxes[2] = UID_JPEGProcess2_4TransferSyntax; transferSyntaxes[3] = UID_JPEGProcess1TransferSyntax; transferSyntaxes[4] = UID_JPEGProcess14SV1TransferSyntax; transferSyntaxes[5] = UID_JPEGLSLossyTransferSyntax; transferSyntaxes[6] = UID_JPEGLSLosslessTransferSyntax; transferSyntaxes[7] = UID_RLELosslessTransferSyntax; transferSyntaxes[8] = UID_MPEG2MainProfileAtMainLevelTransferSyntax; transferSyntaxes[9] = UID_MPEG2MainProfileAtHighLevelTransferSyntax; transferSyntaxes[10] = UID_MPEG4HighProfileLevel4_1TransferSyntax; transferSyntaxes[11] = UID_MPEG4BDcompatibleHighProfileLevel4_1TransferSyntax; transferSyntaxes[12] = UID_MPEG4HighProfileLevel4_2_For2DVideoTransferSyntax; transferSyntaxes[13] = UID_MPEG4HighProfileLevel4_2_For3DVideoTransferSyntax; transferSyntaxes[14] = UID_MPEG4StereoHighProfileLevel4_2TransferSyntax; transferSyntaxes[15] = UID_HEVCMainProfileLevel5_1TransferSyntax; transferSyntaxes[16] = UID_HEVCMain10ProfileLevel5_1TransferSyntax; transferSyntaxes[17] = UID_DeflatedExplicitVRLittleEndianTransferSyntax; if (gLocalByteOrder == EBO_LittleEndian) { transferSyntaxes[18] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[19] = UID_BigEndianExplicitTransferSyntax; } else { transferSyntaxes[18] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[19] = UID_LittleEndianExplicitTransferSyntax; } transferSyntaxes[20] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 21; } else { if (gLocalByteOrder == EBO_LittleEndian) { transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax; } else { transferSyntaxes[0] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax; } transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 3; } break; } cond = ASC_acceptContextsWithPreferredTransferSyntaxes((*assoc)->params, knownAbstractSyntaxes, DIM_OF(knownAbstractSyntaxes), transferSyntaxes, numTransferSyntaxes); if (cond.good()) { cond = ASC_acceptContextsWithPreferredTransferSyntaxes((*assoc)->params, dcmAllStorageSOPClassUIDs, numberOfDcmAllStorageSOPClassUIDs, transferSyntaxes, numTransferSyntaxes); } } if (cond.good()) { cond = ASC_acknowledgeAssociation(*assoc); } if (cond.good()) { // log << Sub-Association Acknowledged Success if (ASC_countAcceptedPresentationContexts((*assoc)->params) == 0) { // log << but no valid presentation contexes; } } else { // log << Sub-Association Acknowleged Failed ASC_dropAssociation(*assoc); ASC_destroyAssociation(assoc); } return cond; } OFCondition dcm_cmove::echoSCP(T_ASC_Association *assoc, T_DIMSE_Message * msg, T_ASC_PresentationContextID presID) { T_DIMSE_C_EchoRQ *req = &msg->msg.CEchoRQ; OFCondition cond = DIMSE_sendEchoResponse(assoc, presID, req, STATUS_Success, NULL); if (cond.bad()) { // log << Echo SCP Failed } return cond; } OFCondition dcm_cmove::storeSCP(T_ASC_Association *assoc, T_DIMSE_Message * msg, T_ASC_PresentationContextID presID) { OFCondition cond = EC_Normal; T_DIMSE_C_StoreRQ *req; char imageFileName[2048]; req = &msg->msg.CStoreRQ; if (ignore) { #ifdef _WIN32 tmpnam(imageFileName); #else OFStandard::strlcpy(imageFileName, NULL_DEVICE_NAME, 2048); #endif // _WIN32 } else { sprintf(imageFileName, "%s.%s", dcmSOPClassUIDToModality(req->AffectedSOPClassUID), req->AffectedSOPInstanceUID); } if (storescp_callback == NULL) storescp_callback = new dcm_cmove_storescp_callback_default("."); //will not be called actually storescp_callback->setAssoc(assoc); DcmFileFormat dcmff; // ? storescp_callback->setDcmFileFormat(&dcmff); storescp_callback->setImageFileName(imageFileName); if (assoc && assoc->params) { const char *aet = assoc->params->DULparams.callingAPTitle; if (aet) { dcmff.getMetaInfo()->putAndInsertString(DCM_SourceApplicationEntityTitle, aet); } } DcmDataset *dset = dcmff.getDataset(); if (bitPreserving) { cond = DIMSE_storeProvider(assoc, presID, req, imageFileName, useMetaheader, NULL, storeSCPCallback, reinterpret_cast(storescp_callback), blockMode, dimse_timeout); } else { cond = DIMSE_storeProvider(assoc, presID, req, NULL, useMetaheader, &dset, storeSCPCallback, reinterpret_cast(storescp_callback), blockMode, dimse_timeout); } if (cond.bad()) { if (!ignore) { if (strcmp(imageFileName, NULL_DEVICE_NAME) != 0) { OFStandard::deleteFile(imageFileName); } } #ifdef _WIN32 else if (ignore) { if (strcmp(imageFileName, NULL_DEVICE_NAME) != 0) { OFStandard::deleteFile(imageFileName); } } #endif // _WIN32 } if (sleepAfter > 0) { OFStandard::sleep(static_cast(sleepDuring)); } return cond; } OFCondition dcm_cmove::subOpSCP(T_ASC_Association **subAssoc) { T_DIMSE_Message msg; T_ASC_PresentationContextID presID; if (!ASC_dataWaiting(*subAssoc, 0)) return DIMSE_NODATAAVAILABLE; OFCondition cond = DIMSE_receiveCommand(*subAssoc, blockMode, dimse_timeout, &presID, &msg, NULL); if (cond == EC_Normal) { switch (msg.CommandField) { case DIMSE_C_ECHO_RQ: cond = echoSCP(*subAssoc, &msg, presID); break; case DIMSE_C_STORE_RQ: cond = storeSCP(*subAssoc, &msg, presID); break; default: cond = DIMSE_BADCOMMANDTYPE; break; } } if (cond == DUL_PEERREQUESTEDRELEASE) { cond = ASC_acknowledgeRelease(*subAssoc); ASC_dropSCPAssociation(*subAssoc); ASC_destroyAssociation(subAssoc); return cond; } else if (cond == DUL_PEERABORTEDASSOCIATION) { } else if (cond != EC_Normal) { cond = ASC_abortAssociation(*subAssoc); } if (cond != EC_Normal) { ASC_dropAssociation(*subAssoc); ASC_destroyAssociation(subAssoc); } return cond; } OFCondition dcm_cmove::moveSCU(T_ASC_Association * assoc, const char * fname) { T_ASC_PresentationContextID presID; T_DIMSE_C_MoveRQ req; T_DIMSE_C_MoveRSP rsp; DIC_US msgId = assoc->nextMsgID; DcmDataset *rspIds = NULL; const char *sopClass; DcmDataset *statusDetail = NULL; DcmFileFormat dcmff; if (fname != NULL) { if (dcmff.loadFile(fname).bad()) { // log << bad DICOM file return DIMSE_BADDATA; } } substituteOverrideKeys(dcmff.getDataset()); sopClass = querySyntax[queryModel].moveSyntax; presID = ASC_findAcceptedPresentationContextID(assoc, sopClass); if (presID == 0) { return DIMSE_NOVALIDPRESENTATIONCONTEXTID; } if (cmove_callback == NULL) cmove_callback = new dcm_cmove_callback_default(); cmove_callback->setAssoc(assoc); cmove_callback->setPresetnationContextID(presID); req.MessageID = msgId; OFStandard::strlcpy(req.AffectedSOPClassUID, sopClass, sizeof(req.AffectedSOPClassUID)); req.Priority = DIMSE_PRIORITY_MEDIUM; req.DataSetType = DIMSE_DATASET_PRESENT; if (ourTitle_ == NULL) { ourTitle_ = new char[1024]; ASC_getAPTitles(assoc->params, req.MoveDestination, sizeof(req.MoveDestination), ourTitle_, 1023, NULL, 0); } else { OFStandard::strlcpy(req.MoveDestination, ourTitle_, sizeof(req.MoveDestination)); } OFCondition cond = DIMSE_moveUser(assoc, presID, &req, dcmff.getDataset(), moveCallback, reinterpret_cast(cmove_callback), blockMode, dimse_timeout, net, subOpCallback, reinterpret_cast(this), &rsp, &statusDetail, &rspIds, ignorePendingDatasets); if (cond == EC_Normal) { if ((rsp.DimseStatus == STATUS_Success) || (rsp.DimseStatus == STATUS_MOVE_Cancel_SubOperationsTerminatedDueToCancelIndication)) { } else if (rsp.DimseStatus == STATUS_MOVE_Warning_SubOperationsCompleteOneOrMoreFailures) { // log << response with warning } else { // log << respone with error } } else { // log << Move Request Failed } if (statusDetail != NULL) delete statusDetail; if (rspIds != NULL) delete rspIds; return cond; } OFCondition dcm_cmove::cmove(T_ASC_Association *assoc, const char *fname) { OFCondition cond = EC_Normal; int n = static_cast(repeatCount); while (cond.good() && n--) { cond = moveSCU(assoc, fname); } return cond; } int dcm_cmove::docmove() { T_ASC_Parameters *params = NULL; DIC_NODENAME peerHost; T_ASC_Association *assoc = NULL; OFStandard::initializeNetwork(); if (!dcmDataDict.isDictionaryLoaded()) return e_no_dictionary_loaded; T_ASC_NetworkRole role = (ourPort_ > 0) ? NET_ACCEPTORREQUESTOR : NET_REQUESTOR; OFCondition cond = ASC_initializeNetwork(role, static_cast(ourPort_), acse_timeout, &net); if (cond.bad()) { return e_cannot_initialize_network; } if (OFStandard::dropPrivileges().bad()) { return e_cannot_set_uid; } cond = ASC_createAssociationParameters(¶ms, maxPDU); if (cond.bad()) { return e_cannot_create_association_parameters; } ASC_setAPTitles(params, ourTitle_, peerTitle_, NULL); sprintf(peerHost, "%s:%d", peerIp_, static_cast(peerPort_)); ASC_setPresentationAddresses(params, OFStandard::getHostName().c_str(), peerHost); cond = addPresentationContext(params, 1, querySyntax[queryModel].findSyntax); cond = addPresentationContext(params, 3, querySyntax[queryModel].moveSyntax); if (cond.bad()) { return e_cannot_create_association_parameters; } cond = ASC_requestAssociation(net, params, &assoc); if (cond.bad()) { if (cond == DUL_ASSOCIATIONREJECTED) { return e_association_rejected; } else { return e_cannot_negotiate_association; } } if (ASC_countAcceptedPresentationContexts(params) == 0) { return e_no_acceptable_presentation_context; } cond = EC_Normal; cond = cmove(assoc, NULL); if (cond == EC_Normal) { if (abortAssociation) { cond = ASC_abortAssociation(assoc); if (cond.bad()) { return e_cannot_abort_association; } } else { cond = ASC_releaseAssociation(assoc); if (cond.bad()) { return e_cannot_release_association; } } } else if (cond == DUL_PEERREQUESTEDRELEASE) { cond = ASC_abortAssociation(assoc); if (cond.bad()) { return e_cannot_abort_association; } } else if (cond == DUL_PEERABORTEDASSOCIATION) { } else { cond = ASC_abortAssociation(assoc); if (cond.bad()) { return e_cannot_abort_association; } } cond = ASC_destroyAssociation(&assoc); if (cond.bad()) { return e_cannot_destroy_association; } cond = ASC_dropNetwork(&net); if (cond.bad()) { return e_cannot_drop_network; } OFStandard::shutdownNetwork(); return e_ok; }