451 lines
12 KiB
C++
451 lines
12 KiB
C++
#include "dcm_find.h"
|
|
|
|
//--------------------------------------------------------------------------
|
|
// dcm_cfind_callback
|
|
|
|
dcm_cfind_callback::dcm_cfind_callback()
|
|
: DcmFindSCUCallback()
|
|
, extractResponse_(FEM_xmlFile)
|
|
, cancelAfterNReponses_(-1)
|
|
, outputDirectory_(".")
|
|
{
|
|
}
|
|
|
|
dcm_cfind_callback::dcm_cfind_callback(DcmFindSCUExtractMode extractResponse, int cancelAfterNResponse, const char *outputDirectory)
|
|
: DcmFindSCUCallback()
|
|
, extractResponse_(extractResponse)
|
|
, cancelAfterNReponses_(cancelAfterNResponse)
|
|
, outputDirectory_(outputDirectory)
|
|
{
|
|
}
|
|
|
|
|
|
void dcm_cfind_callback::callback(T_DIMSE_C_FindRQ *request, int &responseCount, T_DIMSE_C_FindRSP *rsp, DcmDataset *responseIdentifiers)
|
|
{
|
|
std::string outputFileName;
|
|
char rspIdsFileName[32];
|
|
|
|
if (extractResponse_ == FEM_dicomFile)
|
|
{
|
|
sprintf(rspIdsFileName, "rsp%04d.dcm", responseCount);
|
|
OFStandard::combineDirAndFilename(outputFileName, outputDirectory_, rspIdsFileName, true);
|
|
DcmFindSCU::writeToFile(outputFileName.c_str(), responseIdentifiers);
|
|
}
|
|
else if (extractResponse_ == FEM_xmlFile)
|
|
{
|
|
sprintf(rspIdsFileName, "rsp%04d.xml", responseCount);
|
|
OFStandard::combineDirAndFilename(outputFileName, outputDirectory_, rspIdsFileName, true);
|
|
DcmFindSCU::writeToXMLFile(outputFileName.c_str(), responseIdentifiers);
|
|
}
|
|
else if (extractResponse_ == FEM_singleXMLFile)
|
|
{
|
|
}
|
|
}
|
|
|
|
std::string dcm_cfind_callback::get_outputdir()
|
|
{
|
|
return outputDirectory_;
|
|
}
|
|
|
|
bool dcm_cfind_callback::verify()
|
|
{
|
|
if (extractResponse_ == DcmFindSCUExtractMode::FEM_none)
|
|
return true;
|
|
|
|
if (!OFStandard::dirExists(outputDirectory_))
|
|
{
|
|
// log >> output directory does not exist
|
|
return false;
|
|
}
|
|
else if (!OFStandard::isWriteable(outputDirectory_))
|
|
{
|
|
// log >> output directory is not writtable
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// dcm-cfind
|
|
|
|
////dcm_cfind::dcm_cfind()
|
|
//// : abortAssociation(false)
|
|
//// , abstractSyntax(UID_FINDPatientRootQueryRetrieveInformationModel)
|
|
//// , acse_timeout(30)
|
|
//// , blockMode(DIMSE_BLOCKING)
|
|
//// , dimse_timeout(0)
|
|
//// , maxReceivePDULength(ASC_DEFAULTMAXPDU)
|
|
//// , networkTransferSyntax(EXS_Unknown)
|
|
//// , repeatCount(1)
|
|
//// , cfind_callback(nullptr)
|
|
////
|
|
////{
|
|
//// peerIp_ = "127.0.0.1";
|
|
//// peerPort_ = 104;
|
|
//// peerTitle_ = "";
|
|
//// ourTitle_ = "";
|
|
////}
|
|
|
|
dcm_cfind::dcm_cfind(const char *peerIp, unsigned long peerPort, const char *peerTitle, const char *ourTile)
|
|
: abortAssociation(false)
|
|
, abstractSyntax(UID_FINDPatientRootQueryRetrieveInformationModel)
|
|
, acse_timeout(30)
|
|
, blockMode(DIMSE_BLOCKING)
|
|
, dimse_timeout(0)
|
|
, maxReceivePDULength(ASC_DEFAULTMAXPDU)
|
|
, networkTransferSyntax(EXS_Unknown)
|
|
, repeatCount(1)
|
|
, cfind_callback(nullptr)
|
|
{
|
|
peerIp_ = peerIp;
|
|
peerPort_ = peerPort;
|
|
peerTitle_ = peerTitle;
|
|
ourTitle_ = ourTile;
|
|
}
|
|
|
|
dcm_cfind::~dcm_cfind()
|
|
{
|
|
}
|
|
|
|
void dcm_cfind::set_asce_timeout(int timeout)
|
|
{
|
|
acse_timeout = timeout;
|
|
}
|
|
|
|
void dcm_cfind::set_dimse_timeout(int timeout)
|
|
{
|
|
dimse_timeout = timeout;
|
|
}
|
|
|
|
void dcm_cfind::set_max_received_pdu_lenght(unsigned long length)
|
|
{
|
|
maxReceivePDULength = length;
|
|
}
|
|
|
|
void dcm_cfind::set_find_callback(dcm_cfind_callback *callback)
|
|
{
|
|
cfind_callback = callback;
|
|
}
|
|
|
|
void dcm_cfind::initQueryInfo()
|
|
{
|
|
overrideKeys.clear();
|
|
overrideKeys.push_back("0008,0020="); // StudyDate
|
|
overrideKeys.push_back("0008,0050="); // AccessionNumber
|
|
overrideKeys.push_back("0010,0010="); // PatientName
|
|
overrideKeys.push_back("0010,0020="); // PatientID
|
|
overrideKeys.push_back("0010,0030="); // PatientBirthDate
|
|
overrideKeys.push_back("0010,0040="); // PatientSex
|
|
overrideKeys.push_back("0010,1010="); // PatientAge
|
|
overrideKeys.push_back("0020,000D="); // StudyInstanceUID
|
|
overrideKeys.push_back("0020,0010="); // StudyID
|
|
overrideKeys.push_back("0032,1032="); // RequestingPhysician
|
|
overrideKeys.push_back("0020,000E="); // SeriesInstanceUID
|
|
overrideKeys.push_back("0008,0060="); // Modality
|
|
overrideKeys.push_back("0020,0011="); // SeriesNumber
|
|
}
|
|
|
|
// for the purpose to get all the information we need, store a template DICOM file to contains all the information we need
|
|
// AND to return a int code to upper user, need to define globle erro code
|
|
int dcm_cfind::find_by_patient_id(std::string patient_id)
|
|
{
|
|
//abstractSyntax = UID_FINDPatientRootQueryRetrieveInformationModel;
|
|
abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel;
|
|
|
|
initQueryInfo();
|
|
|
|
std::string query_level = "0008,0052=";
|
|
//query_level += "PATIENT";
|
|
query_level += "STUDY";
|
|
overrideKeys.push_back(query_level);
|
|
|
|
std::string patient_id_ = "0010,0020=";
|
|
patient_id_ += patient_id;
|
|
overrideKeys.push_back(patient_id_);
|
|
|
|
int ret = 0;
|
|
OFCondition cond = docfind();
|
|
cond == EC_Normal ? ret = 0 : ret = cond.code();
|
|
return ret;
|
|
}
|
|
|
|
int dcm_cfind::find_by_patient_id_and_date(std::string patient_id, std::string startdate, std::string enddate)
|
|
{
|
|
//abstractSyntax = UID_FINDPatientRootQueryRetrieveInformationModel;
|
|
abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel;
|
|
|
|
initQueryInfo();
|
|
|
|
std::string query_level = "0008,0052=";
|
|
//query_level += "PATIENT";
|
|
query_level += "STUDY";
|
|
overrideKeys.push_back(query_level);
|
|
|
|
std::string patient_id_ = "0010,0020=";
|
|
patient_id_ += patient_id;
|
|
overrideKeys.push_back(patient_id_);
|
|
|
|
std::string study_date_ = "0008,0020=";
|
|
if (!startdate.empty())
|
|
{
|
|
study_date_ += startdate;
|
|
study_date_ += "-";
|
|
}
|
|
if (!enddate.empty())
|
|
study_date_ += enddate;
|
|
overrideKeys.push_back(study_date_.c_str());
|
|
|
|
int ret = 0;
|
|
OFCondition cond = docfind();
|
|
cond == EC_Normal ? ret = 0 : ret = cond.code();
|
|
return ret;
|
|
}
|
|
|
|
int dcm_cfind::find_by_patient_name(std::string patient_name)
|
|
{
|
|
//abstractSyntax = UID_FINDPatientRootQueryRetrieveInformationModel;
|
|
abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel;
|
|
|
|
initQueryInfo();
|
|
|
|
std::string query_level = "0008,0052=";
|
|
//query_level += "PATIENT";
|
|
query_level += "STUDY";
|
|
overrideKeys.push_back(query_level);
|
|
|
|
std::string patient_name_ = "0010,0010=";
|
|
patient_name_ += patient_name;
|
|
overrideKeys.push_back(patient_name_);
|
|
|
|
int ret = 0;
|
|
OFCondition cond = docfind();
|
|
cond == EC_Normal ? ret = 0 : ret = cond.code();
|
|
return ret;
|
|
}
|
|
|
|
int dcm_cfind::find_by_patient_name_and_date(std::string patient_name, std::string startdate, std::string enddate)
|
|
{
|
|
//abstractSyntax = UID_FINDPatientRootQueryRetrieveInformationModel;
|
|
abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel;
|
|
|
|
initQueryInfo();
|
|
|
|
std::string query_level = "0008,0052=";
|
|
//query_level += "PATIENT";
|
|
query_level += "STUDY";
|
|
overrideKeys.push_back(query_level);
|
|
|
|
std::string patient_name_ = "0010,0010=";
|
|
patient_name_ += patient_name;
|
|
overrideKeys.push_back(patient_name_);
|
|
|
|
std::string study_date_ = "0008,0020=";
|
|
if (!startdate.empty())
|
|
{
|
|
study_date_ += startdate;
|
|
study_date_ += "-";
|
|
}
|
|
if (!enddate.empty())
|
|
study_date_ += enddate;
|
|
overrideKeys.push_back(study_date_.c_str());
|
|
|
|
int ret = 0;
|
|
OFCondition cond = docfind();
|
|
cond == EC_Normal ? ret = 0 : ret = cond.code();
|
|
return ret;
|
|
}
|
|
|
|
int dcm_cfind::find_by_accession_no(std::string accession_no)
|
|
{
|
|
//abstractSyntax = UID_FINDPatientRootQueryRetrieveInformationModel;
|
|
abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel;
|
|
|
|
initQueryInfo();
|
|
|
|
std::string query_level = "0008,0052=";
|
|
//query_level += "PATIENT";
|
|
query_level += "STUDY";
|
|
overrideKeys.push_back(query_level);
|
|
|
|
std::string accession_number = "0008,0050=";
|
|
accession_number += accession_no;
|
|
overrideKeys.push_back(accession_number);
|
|
|
|
int ret = 0;
|
|
OFCondition cond = docfind();
|
|
cond == EC_Normal ? ret = 0 : ret = cond.code();
|
|
return ret;
|
|
}
|
|
|
|
int dcm_cfind::find_by_accession_no_and_date(std::string accession_no, std::string startdate, std::string enddate)
|
|
{
|
|
//abstractSyntax = UID_FINDPatientRootQueryRetrieveInformationModel;
|
|
abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel;
|
|
|
|
initQueryInfo();
|
|
|
|
std::string query_level = "0008,0052=";
|
|
//query_level += "PATIENT";
|
|
query_level += "STUDY";
|
|
overrideKeys.push_back(query_level);
|
|
|
|
std::string accession_number = "0008,0050=";
|
|
accession_number += accession_no;
|
|
overrideKeys.push_back(accession_number);
|
|
|
|
std::string study_date_ = "0008,0020=";
|
|
if (!startdate.empty())
|
|
{
|
|
study_date_ += startdate;
|
|
study_date_ += "-";
|
|
}
|
|
if (!enddate.empty())
|
|
study_date_ += enddate;
|
|
overrideKeys.push_back(study_date_.c_str());
|
|
|
|
int ret = 0;
|
|
OFCondition cond = docfind();
|
|
cond == EC_Normal ? ret = 0 : ret = cond.code();
|
|
return ret;
|
|
}
|
|
|
|
int dcm_cfind::find_by_study_uid(std::string study_uid)
|
|
{
|
|
abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel;
|
|
|
|
initQueryInfo();
|
|
|
|
std::string query_level = "0008,0052=";
|
|
//query_level += "STUDY";
|
|
query_level += "SERIES";
|
|
overrideKeys.push_back(query_level);
|
|
|
|
std::string study_instance_uid_ = "0020,000D=";
|
|
study_instance_uid_ += study_uid;
|
|
overrideKeys.push_back(study_instance_uid_);
|
|
|
|
int ret = 0;
|
|
OFCondition cond = docfind();
|
|
cond == EC_Normal ? ret = 0 : ret = cond.code();
|
|
return ret;
|
|
}
|
|
|
|
int dcm_cfind::find_by_series_uid(std::string study_uid)
|
|
{
|
|
abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel;
|
|
|
|
initQueryInfo();
|
|
|
|
std::string query_level = "0008,0052=";
|
|
query_level += "SERIES";
|
|
overrideKeys.push_back(query_level);
|
|
|
|
std::string study_instance_uid_ = "0020,000D=";
|
|
study_instance_uid_ += study_uid;
|
|
overrideKeys.push_back(study_instance_uid_);
|
|
|
|
int ret = 0;
|
|
OFCondition cond = docfind();
|
|
cond == EC_Normal ? ret = 0 : ret = cond.code();
|
|
return ret;
|
|
}
|
|
|
|
int dcm_cfind::find_by_series_uid(std::string study_uid, std::string series_uid)
|
|
{
|
|
abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel;
|
|
|
|
initQueryInfo();
|
|
|
|
std::string query_level = "0008,0052=";
|
|
query_level += "STUDY";
|
|
overrideKeys.push_back(query_level);
|
|
|
|
std::string study_instance_uid_ = "0020,000D=";
|
|
study_instance_uid_ += study_uid;
|
|
overrideKeys.push_back(study_instance_uid_);
|
|
|
|
std::string series_instance_uid_ = "0020,000E=";
|
|
series_instance_uid_ += series_uid;
|
|
overrideKeys.push_back(series_instance_uid_);
|
|
|
|
int ret = 0;
|
|
OFCondition cond = docfind();
|
|
cond == EC_Normal ? ret = 0 : ret = cond.code();
|
|
return ret;
|
|
}
|
|
|
|
int dcm_cfind::find_by_timeinterval(std::string startDate, std::string endDate)
|
|
{
|
|
abstractSyntax = UID_FINDModalityWorklistInformationModel;
|
|
|
|
// Since worklist is used to get infos which
|
|
// will be used by upper user to construct user/study info,
|
|
// So we set all the infos except the filter to empty,
|
|
// and then pass them to C-Find SCP who will fill these
|
|
// value in response
|
|
initQueryInfo();
|
|
|
|
std::string scheduleStartDate = "(0040,0100)[0].(0040,0002)=";
|
|
if (!startDate.empty())
|
|
{
|
|
scheduleStartDate += startDate;
|
|
scheduleStartDate += "-";
|
|
}
|
|
|
|
if (!endDate.empty())
|
|
{
|
|
//std::string scheduleEndDate = "(0040,0100)[0].(0040,0002)=";
|
|
//scheduleEndDate += endDate;
|
|
//overrideKeys.push_back(scheduleEndDate.c_str());
|
|
scheduleStartDate += endDate;
|
|
}
|
|
overrideKeys.push_back(scheduleStartDate.c_str());
|
|
|
|
int ret = 0;
|
|
OFCondition cond = docfind();
|
|
cond == EC_Normal ? ret = 0 : ret = cond.code();
|
|
return ret;
|
|
}
|
|
|
|
// METHOD performQuery method from DCMTK sucks
|
|
OFCondition dcm_cfind::docfind()
|
|
{
|
|
OFStandard::initializeNetwork();
|
|
if (cfind_callback == nullptr)
|
|
{
|
|
// log >> No callback is provided
|
|
cfind_callback = new dcm_cfind_callback(DcmFindSCUExtractMode::FEM_xmlFile, -1, ".");
|
|
|
|
// Donnot need to verify, since the query operation should not care about property of callback
|
|
}
|
|
|
|
DcmFindSCU findscu;
|
|
OFCondition cond = findscu.initializeNetwork(acse_timeout);
|
|
if (cond.bad())
|
|
{
|
|
// log >> failed to connect scp;
|
|
return cond;
|
|
}
|
|
|
|
cond = findscu.performQuery(peerIp_, peerPort_, ourTitle_, peerTitle_, abstractSyntax,
|
|
networkTransferSyntax, blockMode, dimse_timeout, maxReceivePDULength, false, abortAssociation,
|
|
repeatCount, DcmFindSCUExtractMode::FEM_none, -1, &overrideKeys, cfind_callback, &fileNameList,
|
|
"", "");
|
|
if (cond.bad())
|
|
{
|
|
// log >> query failed
|
|
return cond;
|
|
}
|
|
|
|
cond = findscu.dropNetwork();
|
|
if (cond.bad())
|
|
{
|
|
// log >> drop network failed
|
|
return cond;
|
|
}
|
|
|
|
OFStandard::shutdownNetwork();
|
|
return cond;
|
|
} |