Files
DCMV/thirdparty/dcm_network/dcm_move.cpp

1103 lines
30 KiB
C++
Raw Normal View History

2022-07-08 10:04:23 +08:00
#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<dcm_cmove_callback *>(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<dcm_cmove_storescp_callback *>(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<dcm_cmove *>(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<unsigned int>(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<Uint32>(filepad_), static_cast<Uint32>(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<unsigned long>(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<void *>(storescp_callback),
blockMode, dimse_timeout);
}
else
{
cond = DIMSE_storeProvider(assoc, presID, req, NULL, useMetaheader,
&dset, storeSCPCallback, reinterpret_cast<void *>(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<unsigned int>(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<void *>(cmove_callback),
blockMode, dimse_timeout, net, subOpCallback, reinterpret_cast<void *>(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<int>(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<int>(ourPort_), acse_timeout, &net);
if (cond.bad())
{
return e_cannot_initialize_network;
}
if (OFStandard::dropPrivileges().bad())
{
return e_cannot_set_uid;
}
cond = ASC_createAssociationParameters(&params, maxPDU);
if (cond.bad())
{
return e_cannot_create_association_parameters;
}
ASC_setAPTitles(params, ourTitle_, peerTitle_, NULL);
sprintf(peerHost, "%s:%d", peerIp_, static_cast<int>(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;
}