Add thirdparty dir.
This commit is contained in:
1
thirdparty/CMakeLists.txt
vendored
Normal file
1
thirdparty/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
add_subdirectory(dcm_network)
|
||||
33
thirdparty/dcm_network/CMakeLists.txt
vendored
Normal file
33
thirdparty/dcm_network/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
set(PROJECT_NAME CACHE STRING "project" )
|
||||
|
||||
project(dcm_network)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
|
||||
|
||||
if(MSVC)
|
||||
#add_definitions(-D_DCM_NET_EXPORTS)
|
||||
add_compile_definitions(_DCM_NET_EXPORTS)
|
||||
endif()
|
||||
|
||||
find_package(DCMTK REQUIRED)
|
||||
include_directories(${DCMTK_INCLUDE_DIRS})
|
||||
|
||||
|
||||
include_directories(./internal)
|
||||
add_library(
|
||||
dcm_network SHARED
|
||||
./dcm_verify.cpp
|
||||
./dcm_verify.h
|
||||
./dcm_find.cpp
|
||||
./dcm_find.h
|
||||
./dcm_store.cpp
|
||||
./dcm_store.h
|
||||
./dcm_move.cpp
|
||||
./dcm_move.h
|
||||
)
|
||||
target_link_libraries(dcm_network ${DCMTK_LIBRARIES})
|
||||
|
||||
|
||||
451
thirdparty/dcm_network/dcm_find.cpp
vendored
Normal file
451
thirdparty/dcm_network/dcm_find.cpp
vendored
Normal file
@@ -0,0 +1,451 @@
|
||||
#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;
|
||||
}
|
||||
87
thirdparty/dcm_network/dcm_find.h
vendored
Normal file
87
thirdparty/dcm_network/dcm_find.h
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
#ifndef _DCM_FIND_H_
|
||||
#define _DCM_FIND_H_
|
||||
|
||||
#include "internal/dcm_global.h"
|
||||
#include "internal/dcm_type.h"
|
||||
#include "internal/dcmtk_headers.h"
|
||||
#include <list>
|
||||
|
||||
|
||||
// this class is awkward, since even it make you a little happy to do with DCMTK, but you still need to
|
||||
// deal with DCMTK type.
|
||||
// For a whole wrapper, really a big project.
|
||||
|
||||
// Inherit this class for custom callback handler
|
||||
class _DCM_EXPORT dcm_cfind_callback : public DcmFindSCUCallback
|
||||
{
|
||||
public:
|
||||
dcm_cfind_callback();
|
||||
dcm_cfind_callback(DcmFindSCUExtractMode extractResponse, int cancelAfterNResponse, const char *outputDirectory = NULL);
|
||||
virtual ~dcm_cfind_callback() {};
|
||||
virtual void callback(T_DIMSE_C_FindRQ *request, int &responseCount, T_DIMSE_C_FindRSP *rsp, DcmDataset *responseIdentifiers);
|
||||
|
||||
std::string get_outputdir();
|
||||
// verify whether the dir exists and writable
|
||||
bool verify();
|
||||
|
||||
private:
|
||||
DcmFindSCUExtractMode extractResponse_;
|
||||
int cancelAfterNReponses_;
|
||||
std::string outputDirectory_;
|
||||
};
|
||||
|
||||
//only support find filter passed in, not files.
|
||||
class _DCM_EXPORT dcm_cfind
|
||||
{
|
||||
public:
|
||||
//dcm_cfind();
|
||||
dcm_cfind(const char *peerIp, unsigned long peerPort, const char *peerTitle, const char *ourTile);
|
||||
~dcm_cfind();
|
||||
|
||||
void set_asce_timeout(int timeout);
|
||||
void set_dimse_timeout(int timeout);
|
||||
void set_max_received_pdu_lenght(unsigned long length);
|
||||
void set_find_callback(dcm_cfind_callback *callback);
|
||||
|
||||
// the query condition will contains as much as information, handle it in your custom callback
|
||||
int find_by_patient_id(std::string patient_id);
|
||||
int find_by_patient_id_and_date(std::string patient_id, std::string startdate, std::string enddate);
|
||||
int find_by_patient_name(std::string patient_name);
|
||||
int find_by_patient_name_and_date(std::string patient_name, std::string startdate, std::string enddate);
|
||||
int find_by_accession_no(std::string accession_no);
|
||||
int find_by_accession_no_and_date(std::string accession_no, std::string startdate, std::string enddate);
|
||||
int find_by_study_uid(std::string study_uid);
|
||||
int find_by_series_uid(std::string study_uid);
|
||||
int find_by_series_uid(std::string study_uid, std::string series_uid);
|
||||
|
||||
// worklist related
|
||||
int find_by_timeinterval(std::string startDate, std::string endDate);
|
||||
|
||||
private:
|
||||
OFCondition docfind();
|
||||
void initQueryInfo();
|
||||
|
||||
private:
|
||||
std::list<std::string> fileNameList;
|
||||
bool abortAssociation;
|
||||
const char * abstractSyntax;
|
||||
int acse_timeout;
|
||||
T_DIMSE_BlockingMode blockMode;
|
||||
//signed long cancelAfterNResponse;
|
||||
int dimse_timeout;
|
||||
//DcmFindSCUExtractMode extractResponse;
|
||||
//std::string extractXMLFileName;
|
||||
//std::string outputDirectory;
|
||||
unsigned long maxReceivePDULength;
|
||||
E_TransferSyntax networkTransferSyntax;
|
||||
const char * ourTitle_;
|
||||
const char * peerIp_;
|
||||
const char * peerTitle_;
|
||||
unsigned long peerPort_;
|
||||
unsigned long repeatCount;
|
||||
std::list<std::string> overrideKeys;
|
||||
|
||||
dcm_cfind_callback *cfind_callback;
|
||||
};
|
||||
|
||||
#endif // _DCM_FIND_H_
|
||||
1102
thirdparty/dcm_network/dcm_move.cpp
vendored
Normal file
1102
thirdparty/dcm_network/dcm_move.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
174
thirdparty/dcm_network/dcm_move.h
vendored
Normal file
174
thirdparty/dcm_network/dcm_move.h
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
#ifndef _DCM_MOVE_H_
|
||||
#define _DCM_MOVE_H_
|
||||
|
||||
#include "internal/dcm_global.h"
|
||||
#include "internal/dcm_type.h"
|
||||
#include "internal/dcmtk_headers.h"
|
||||
|
||||
// C-Move is a little annoying, since C-Move scu is also a C-Store scp:
|
||||
// once upon the C-Move request is sent, C-Move scp will send data to
|
||||
// CMove scu through C-Store in which C_Move scp will act as a C-Store scu
|
||||
// and C-Move scu will act as a C-Store scp.
|
||||
// So, you need to provide two callback subclass to implement custom operation
|
||||
// related the progrss, status and all the like.
|
||||
// the subOpCallback is implemented internally, do not worry
|
||||
|
||||
class _DCM_EXPORT dcm_cmove_callback
|
||||
{
|
||||
public:
|
||||
dcm_cmove_callback();
|
||||
virtual ~dcm_cmove_callback();
|
||||
virtual void callback(T_DIMSE_C_MoveRQ *request, int responseCount, T_DIMSE_C_MoveRSP *response) = 0;
|
||||
|
||||
virtual void setAssoc(T_ASC_Association * assoc);
|
||||
virtual void setPresetnationContextID(const T_ASC_PresentationContextID& presId);
|
||||
virtual void setCancelAfterNReponse(int n = -1);
|
||||
|
||||
protected:
|
||||
T_ASC_Association * assoc_;
|
||||
T_ASC_PresentationContextID presId_;
|
||||
int cancelAfterNResponse_;
|
||||
|
||||
private:
|
||||
////dcm_cmove_callback(const dcm_cmove_callback& other);
|
||||
////dcm_cmove_callback& operator=(const dcm_cmove_callback& other);
|
||||
};
|
||||
|
||||
class _DCM_EXPORT dcm_cmove_callback_default : public dcm_cmove_callback
|
||||
{
|
||||
public:
|
||||
dcm_cmove_callback_default();
|
||||
virtual ~dcm_cmove_callback_default();
|
||||
virtual void callback(T_DIMSE_C_MoveRQ *request, int responseCount, T_DIMSE_C_MoveRSP *response);
|
||||
};
|
||||
|
||||
|
||||
// callback funciton in dcmtk is not flexible if you want access to assoc and more underlayer stuff in callback implementation
|
||||
// so I will put as much as infos in this class, or you can inherit for more info to access
|
||||
// now the infos conatins:
|
||||
// char * imageFileName;
|
||||
// DcmFileFormat *dcmff;
|
||||
// T_ASC_Association *assoc;
|
||||
class _DCM_EXPORT dcm_cmove_storescp_callback
|
||||
{
|
||||
public:
|
||||
dcm_cmove_storescp_callback();
|
||||
virtual ~dcm_cmove_storescp_callback();
|
||||
virtual void callback(T_DIMSE_StoreProgress *progress, T_DIMSE_C_StoreRQ *request, char *imageFileName, DcmDataset **imageDataSet, T_DIMSE_C_StoreRSP *response, DcmDataset **statusDetail) = 0;
|
||||
virtual void setImageFileName(char * imageFileName);
|
||||
virtual void setDcmFileFormat(DcmFileFormat * dcmff);
|
||||
virtual void setAssoc(T_ASC_Association * assoc);
|
||||
|
||||
protected:
|
||||
char * imageFile_;
|
||||
DcmFileFormat * dcmff_;
|
||||
T_ASC_Association * assoc_;
|
||||
|
||||
private:
|
||||
////dcm_cmove_storescp_callback(const dcm_cmove_storescp_callback& other);
|
||||
////dcm_cmove_storescp_callback& operator=(const dcm_cmove_storescp_callback& other);
|
||||
};
|
||||
|
||||
// a default implemetation of dcm_cmove_storescp_callback
|
||||
// which save files in a specified directory, as a different
|
||||
// way to handle image, such as store in database, implement it yourself
|
||||
class _DCM_EXPORT dcm_cmove_storescp_callback_default : public dcm_cmove_storescp_callback
|
||||
{
|
||||
public:
|
||||
dcm_cmove_storescp_callback_default(std::string outputDirectory);
|
||||
virtual ~dcm_cmove_storescp_callback_default();
|
||||
virtual void callback(T_DIMSE_StoreProgress *progress, T_DIMSE_C_StoreRQ *request, char *imageFileName, DcmDataset **imageDataSet, T_DIMSE_C_StoreRSP *response, DcmDataset **statusDetail);
|
||||
|
||||
private:
|
||||
bool abortDuringStore_;
|
||||
bool abortAfterStore_;
|
||||
unsigned long sleepDuring_;
|
||||
bool bitPreserving_;
|
||||
bool ignore_;
|
||||
std::string outputDirectory_;
|
||||
E_TransferSyntax writeTransferSyntax_;
|
||||
E_EncodingType sequenceType_;
|
||||
E_GrpLenEncoding groupLength_;
|
||||
E_PaddingEncoding paddingType_;
|
||||
unsigned long filepad_;
|
||||
unsigned long itempad_;
|
||||
bool useMetaheader_;
|
||||
bool correctUIDPadding_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
QMPatientRoot = 0,
|
||||
QMStudyRoot = 1,
|
||||
QMPatientStudyOnly = 2
|
||||
} QueryModel;
|
||||
|
||||
class _DCM_EXPORT dcm_cmove
|
||||
{
|
||||
public:
|
||||
dcm_cmove(const char *peerIp, unsigned long peerPort, const char *peerTitle, unsigned long ourPort, const char *ourTile);
|
||||
~dcm_cmove();
|
||||
|
||||
void set_sleep_after(unsigned long);
|
||||
void set_sleep_during(unsigned long);
|
||||
void set_dimse_timeout(int timeout);
|
||||
void set_acse_timeout(int timeout);
|
||||
void set_cmove_callback(dcm_cmove_callback * callback);
|
||||
void set_cmove_scp_callback(dcm_cmove_storescp_callback * callback);
|
||||
|
||||
int move_by_patient_id(std::string patient_id);
|
||||
int move_by_study_uid(std::string study_uid);
|
||||
int move_by_series_uid(std::string study_uid, std::string series_uid);
|
||||
int move_by_image_uid(std::string study_uid, std::string series_uid, std::string image_uid);
|
||||
|
||||
OFCondition acceptSubAssoc(T_ASC_Network *aNet, T_ASC_Association **assoc);
|
||||
OFCondition subOpSCP(T_ASC_Association **subAssoc);
|
||||
|
||||
private:
|
||||
void addOverrideKey(const char *s);
|
||||
OFCondition addPresentationContext(T_ASC_Parameters * params, T_ASC_PresentationContextID pid, const char * abstractSyntax);
|
||||
void substituteOverrideKeys(DcmDataset *dset);
|
||||
|
||||
OFCondition echoSCP(T_ASC_Association *assoc, T_DIMSE_Message * msg, T_ASC_PresentationContextID presID);
|
||||
OFCondition storeSCP(T_ASC_Association *assoc, T_DIMSE_Message * msg, T_ASC_PresentationContextID presID);
|
||||
|
||||
OFCondition moveSCU(T_ASC_Association * assoc, const char * fname);
|
||||
OFCondition cmove(T_ASC_Association *assoc, const char *fname);
|
||||
|
||||
int docmove();
|
||||
|
||||
private:
|
||||
const char * peerIp_;
|
||||
unsigned long peerPort_;
|
||||
const char * peerTitle_;
|
||||
unsigned long ourPort_;
|
||||
char * ourTitle_;
|
||||
|
||||
dcm_cmove_callback * cmove_callback;
|
||||
dcm_cmove_storescp_callback * storescp_callback;
|
||||
|
||||
private:
|
||||
unsigned long sleepAfter;
|
||||
unsigned long sleepDuring;
|
||||
unsigned long maxPDU;
|
||||
bool useMetaheader;
|
||||
bool acceptAllXfer;
|
||||
E_TransferSyntax in_networkTransferSyntax;
|
||||
E_TransferSyntax out_networkTransferSyntax;
|
||||
bool bitPreserving;
|
||||
bool ignore;
|
||||
unsigned long repeatCount;
|
||||
bool abortAssociation;
|
||||
QueryModel queryModel;
|
||||
T_DIMSE_BlockingMode blockMode;
|
||||
int dimse_timeout;
|
||||
int acse_timeout;
|
||||
bool ignorePendingDatasets;
|
||||
|
||||
T_ASC_Network * net;
|
||||
DcmDataset * overrideKeys;
|
||||
};
|
||||
|
||||
#endif // !_DCM_MOVE_H_
|
||||
|
||||
820
thirdparty/dcm_network/dcm_store.cpp
vendored
Normal file
820
thirdparty/dcm_network/dcm_store.cpp
vendored
Normal file
@@ -0,0 +1,820 @@
|
||||
#include "dcm_store.h"
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
// dcm_cstore_callback
|
||||
|
||||
dcm_cstore_callback::dcm_cstore_callback()
|
||||
{
|
||||
}
|
||||
|
||||
dcm_cstore_callback::~dcm_cstore_callback()
|
||||
{
|
||||
}
|
||||
|
||||
////dcm_cstore_callback::dcm_cstore_callback(const dcm_cstore_callback& other)
|
||||
////{
|
||||
////}
|
||||
////
|
||||
////dcm_cstore_callback& dcm_cstore_callback::operator=(const dcm_cstore_callback& other)
|
||||
////{
|
||||
////}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
// static function
|
||||
|
||||
static void progressCallback(void *callbackData, T_DIMSE_StoreProgress *progress, T_DIMSE_C_StoreRQ *request)
|
||||
{
|
||||
dcm_cstore_callback *callback = reinterpret_cast<dcm_cstore_callback *>(callbackData);
|
||||
if (callback)
|
||||
callback->callback(progress, request);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
// dcm-cstore
|
||||
|
||||
dcm_cstore::dcm_cstore(const char *peerIp, unsigned long peerPort, const char *peerTitle, const char *ourTitle)
|
||||
: abortAssociation(false)
|
||||
, maxReceivedPDULength(ASC_DEFAULTMAXPDU)
|
||||
, maxSendPDULength(ASC_DEFAULTMAXPDU)
|
||||
, networkTransferSyntax(EXS_Unknown)
|
||||
, readMode(ERM_autoDetect)
|
||||
, scanDir(true)
|
||||
, recurse(true)
|
||||
, scanPattern("")
|
||||
, haltOnUnsuccessfulStore(true)
|
||||
, unsuccessfulStoreEncountered(false)
|
||||
, lastStatusCode(STATUS_Success)
|
||||
, proposeOnlyRequiredPresentationContexts(false)
|
||||
, combineProposedTransferSyntaxes(false)
|
||||
, repeatCount(1)
|
||||
, inventPatientCount(25)
|
||||
, inventStudyCount(50)
|
||||
, inventSeriesCount(100)
|
||||
, inventSOPInstanceInformation(false)
|
||||
, correctUIDPadding(false)
|
||||
, patientNamePrefix("OFFIS^TEST_PN_")
|
||||
, patientIDPrefix("PID_")
|
||||
, studyIDPrefix("SID_")
|
||||
, accessionNumberPrefix("")
|
||||
, configFile(NULL)
|
||||
, profileName(NULL)
|
||||
, blockMode(DIMSE_BLOCKING)
|
||||
, dimse_tiemout(0)
|
||||
, acse_tiemout(30)
|
||||
, socket_tiemout(60)
|
||||
, identMode(ASC_USER_IDENTITY_NONE)
|
||||
, user("")
|
||||
, password("")
|
||||
, identFile_("")
|
||||
, identResponse(false)
|
||||
, cstore_callback(nullptr)
|
||||
, patientCounter(0)
|
||||
, studyCounter(0)
|
||||
, seriesCounter(0)
|
||||
, imageCounter(0)
|
||||
{
|
||||
peerIp_ = peerIp;
|
||||
peerPort_ = peerPort;
|
||||
peerTitle_ = peerTitle;
|
||||
ourTitle_ = ourTitle;
|
||||
}
|
||||
|
||||
dcm_cstore::~dcm_cstore()
|
||||
{
|
||||
}
|
||||
|
||||
void dcm_cstore::set_dimse_tiemout(int timeout)
|
||||
{
|
||||
dimse_tiemout = timeout;
|
||||
}
|
||||
|
||||
void dcm_cstore::set_acse_tiemout(int timeout)
|
||||
{
|
||||
acse_tiemout = timeout;
|
||||
}
|
||||
|
||||
void dcm_cstore::set_ma_received_pdu_length(unsigned long length)
|
||||
{
|
||||
maxReceivedPDULength = length;
|
||||
}
|
||||
|
||||
void dcm_cstore::set_max_send_pdu_length(unsigned long length)
|
||||
{
|
||||
maxSendPDULength = length;
|
||||
}
|
||||
|
||||
void dcm_cstore::set_store_callback(dcm_cstore_callback *callback)
|
||||
{
|
||||
cstore_callback = callback;
|
||||
}
|
||||
|
||||
int dcm_cstore::secondsSince1970()
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
return static_cast<int>(t);
|
||||
}
|
||||
|
||||
std::string dcm_cstore::intToString(int i)
|
||||
{
|
||||
char numbuf[32];
|
||||
sprintf(numbuf, "%d", i);
|
||||
return numbuf;
|
||||
}
|
||||
|
||||
std::string dcm_cstore::makeUID(std::string basePrefix, int counter)
|
||||
{
|
||||
std::string prefix = basePrefix + "." + intToString(counter);
|
||||
char uidbuf[65];
|
||||
std::string uid = dcmGenerateUniqueIdentifier(uidbuf, prefix.c_str());
|
||||
return uid;
|
||||
}
|
||||
|
||||
bool dcm_cstore::updateStringAttributeValue(DcmItem *dataset, const DcmTagKey &key, std::string &value)
|
||||
{
|
||||
DcmStack stack;
|
||||
DcmTag tag(key);
|
||||
|
||||
OFCondition cond = EC_Normal;
|
||||
cond = dataset->search(key, stack, ESM_fromHere, false);
|
||||
if (cond != EC_Normal)
|
||||
{
|
||||
// log >> "updateStringAttributeValue : cannot find
|
||||
return false;
|
||||
}
|
||||
|
||||
DcmElement *elem = static_cast<DcmElement *>(stack.top());
|
||||
DcmVR vr(elem->ident());
|
||||
if (elem->getLength() > vr.getMaxValueLength())
|
||||
{
|
||||
// log >> undateStringAttributeValue : INTERNAL ERROR
|
||||
return false;
|
||||
}
|
||||
|
||||
cond = elem->putOFStringArray(value);
|
||||
if (cond != EC_Normal)
|
||||
{
|
||||
// log >> updateStringAttributeValue : cannot put string in attribute
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcm_cstore::replaceSOPInstanceInformation(DcmDataset *dataset)
|
||||
{
|
||||
std::string seriesInstanceUID;
|
||||
std::string seriesNumber;
|
||||
std::string studyInstanceUID;
|
||||
std::string studyID;
|
||||
std::string accessionNumber;
|
||||
std::string patientID;
|
||||
std::string patientName;
|
||||
|
||||
if (seriesInstanceUID.empty())
|
||||
seriesInstanceUID = makeUID(SITE_SERIES_UID_ROOT, static_cast<int>(seriesCounter));
|
||||
if (seriesNumber.empty())
|
||||
seriesNumber = intToString(static_cast<int>(seriesCounter));
|
||||
if (studyInstanceUID.empty())
|
||||
studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, static_cast<int>(studyCounter));
|
||||
if (studyID.empty())
|
||||
studyID = studyIDPrefix + intToString(static_cast<int>(secondsSince1970())) + intToString(static_cast<int>(studyCounter));
|
||||
if (accessionNumber.empty())
|
||||
accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(studyCounter));
|
||||
if (patientID.empty())
|
||||
patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(patientCounter));
|
||||
if (patientName.empty())
|
||||
patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(patientCounter));
|
||||
|
||||
if (imageCounter >= inventSeriesCount)
|
||||
{
|
||||
imageCounter = 0;
|
||||
seriesCounter++;
|
||||
seriesInstanceUID = makeUID(SITE_SERIES_UID_ROOT, static_cast<int>(seriesCounter));
|
||||
seriesNumber = intToString(static_cast<int>(seriesCounter));
|
||||
}
|
||||
if (seriesCounter >= inventStudyCount)
|
||||
{
|
||||
seriesCounter = 0;
|
||||
studyCounter++;
|
||||
studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, static_cast<int>(studyCounter));
|
||||
studyID = studyIDPrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(studyCounter));
|
||||
accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(studyCounter));
|
||||
}
|
||||
if (studyCounter >= inventPatientCount)
|
||||
{
|
||||
studyCounter = 0;
|
||||
patientCounter++;
|
||||
patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(patientCounter));
|
||||
patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(patientCounter));
|
||||
}
|
||||
|
||||
std::string sopInstanceUID = makeUID(SITE_INSTANCE_UID_ROOT, static_cast<int>(imageCounter));
|
||||
std::string imageNumber = intToString(static_cast<int>(imageCounter));
|
||||
|
||||
updateStringAttributeValue(dataset, DCM_PatientName, patientName);
|
||||
updateStringAttributeValue(dataset, DCM_PatientID, patientID);
|
||||
updateStringAttributeValue(dataset, DCM_StudyInstanceUID, studyInstanceUID);
|
||||
updateStringAttributeValue(dataset, DCM_StudyID, studyID);
|
||||
updateStringAttributeValue(dataset, DCM_SeriesInstanceUID, seriesInstanceUID);
|
||||
updateStringAttributeValue(dataset, DCM_SeriesNumber, seriesNumber);
|
||||
updateStringAttributeValue(dataset, DCM_SOPInstanceUID, sopInstanceUID);
|
||||
updateStringAttributeValue(dataset, DCM_InstanceNumber, imageNumber);
|
||||
|
||||
imageCounter++;
|
||||
}
|
||||
|
||||
OFCondition dcm_cstore::addStoragePresentationContexts(T_ASC_Parameters *params, std::list<std::string> &sopClasses)
|
||||
{
|
||||
std::string preferredTransferSyntax;
|
||||
if (networkTransferSyntax == EXS_Unknown)
|
||||
{
|
||||
if (gLocalByteOrder == E_ByteOrder::EBO_LittleEndian)
|
||||
{
|
||||
preferredTransferSyntax = UID_LittleEndianExplicitTransferSyntax;
|
||||
}
|
||||
else
|
||||
{
|
||||
preferredTransferSyntax = UID_BigEndianExplicitTransferSyntax;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DcmXfer xfer(networkTransferSyntax);
|
||||
preferredTransferSyntax = xfer.getXferID();
|
||||
}
|
||||
|
||||
std::list<std::string>::iterator s_cur;
|
||||
std::list<std::string>::iterator s_end;
|
||||
|
||||
std::list<std::string> fallbackSyntaxes;
|
||||
if ((networkTransferSyntax != EXS_LittleEndianImplicit) &&
|
||||
(networkTransferSyntax != EXS_MPEG2MainProfileAtMainLevel) &&
|
||||
(networkTransferSyntax != EXS_MPEG2MainProfileAtHighLevel) &&
|
||||
(networkTransferSyntax != EXS_MPEG4HighProfileLevel4_1) &&
|
||||
(networkTransferSyntax != EXS_MPEG4BDcompatibleHighProfileLevel4_1) &&
|
||||
(networkTransferSyntax != EXS_MPEG4HighProfileLevel4_2_For2DVideo) &&
|
||||
(networkTransferSyntax != EXS_MPEG4HighProfileLevel4_2_For3DVideo) &&
|
||||
(networkTransferSyntax != EXS_MPEG4StereoHighProfileLevel4_2) &&
|
||||
(networkTransferSyntax != EXS_HEVCMainProfileLevel5_1) &&
|
||||
(networkTransferSyntax != EXS_HEVCMain10ProfileLevel5_1))
|
||||
{
|
||||
fallbackSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax);
|
||||
fallbackSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax);
|
||||
fallbackSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax);
|
||||
|
||||
fallbackSyntaxes.remove(preferredTransferSyntax);
|
||||
}
|
||||
|
||||
std::list<std::string> combinedSyntaxes;
|
||||
s_cur = fallbackSyntaxes.begin();
|
||||
s_end = fallbackSyntaxes.end();
|
||||
combinedSyntaxes.push_back(preferredTransferSyntax);
|
||||
while (s_cur != s_end)
|
||||
{
|
||||
if (!isaListMember(combinedSyntaxes, *s_cur))
|
||||
{
|
||||
combinedSyntaxes.push_back(*s_cur);
|
||||
}
|
||||
++s_cur;
|
||||
}
|
||||
|
||||
if (!proposeOnlyRequiredPresentationContexts)
|
||||
{
|
||||
for (int i = 0; i < numberOfDcmShortSCUStorageSOPClassUIDs; i++)
|
||||
{
|
||||
sopClasses.push_back(dcmShortSCUStorageSOPClassUIDs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<std::string> sops;
|
||||
s_cur = sopClasses.begin();
|
||||
s_end = sopClasses.end();
|
||||
while (s_cur != s_end)
|
||||
{
|
||||
if (!isaListMember(sops, *s_cur))
|
||||
{
|
||||
sops.push_back(*s_cur);
|
||||
}
|
||||
++s_cur;
|
||||
}
|
||||
|
||||
OFCondition cond = EC_Normal;
|
||||
int pid = 1;
|
||||
s_cur = sops.begin();
|
||||
s_end = sops.end();
|
||||
while (s_cur != s_end && cond.good())
|
||||
{
|
||||
if (pid > 255)
|
||||
{
|
||||
// log >> Too many presentation contexts
|
||||
return ASC_BADPRESENTATIONCONTEXTID;
|
||||
}
|
||||
|
||||
if (combineProposedTransferSyntaxes)
|
||||
{
|
||||
addPresentationContext(params, pid, *s_cur, combinedSyntaxes);
|
||||
pid += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
cond = addPresentationContext(params, pid, *s_cur, preferredTransferSyntax);
|
||||
pid += 2;
|
||||
|
||||
if (fallbackSyntaxes.size() > 0)
|
||||
{
|
||||
if (pid > 255)
|
||||
{
|
||||
// log >> Too many presentation contexes
|
||||
return ASC_BADPRESENTATIONCONTEXTID;
|
||||
}
|
||||
|
||||
cond = addPresentationContext(params, pid, *s_cur, fallbackSyntaxes);
|
||||
pid += 2;
|
||||
}
|
||||
}
|
||||
++s_cur;
|
||||
}
|
||||
|
||||
return cond;
|
||||
}
|
||||
|
||||
bool dcm_cstore::findSOPClassAndInstanceInFile(const char *fname, char *sopClass, size_t sopClassSize, char *sopInstance, size_t sopInstanceSize)
|
||||
{
|
||||
DcmFileFormat ff;
|
||||
if (!ff.loadFile(fname, EXS_Unknown, EGL_noChange, DCM_MaxReadLength, readMode).good())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool found = DU_findSOPClassAndInstanceInDataSet(ff.getMetaInfo(), sopClass, sopClassSize, sopInstance, sopInstanceSize, correctUIDPadding);
|
||||
if (!found)
|
||||
found = DU_findSOPClassAndInstanceInDataSet(ff.getDataset(), sopClass, sopClassSize, sopInstance, sopInstanceSize, correctUIDPadding);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
OFCondition dcm_cstore::configureUserIdentityRequest(T_ASC_Parameters *params)
|
||||
{
|
||||
OFCondition cond = EC_Normal;
|
||||
switch (identMode)
|
||||
{
|
||||
case ASC_USER_IDENTITY_USER:
|
||||
{
|
||||
cond = ASC_setIdentRQUserOnly(params, user, identResponse);
|
||||
break;
|
||||
}
|
||||
case ASC_USER_IDENTITY_USER_PASSWORD:
|
||||
{
|
||||
cond = ASC_setIdentRQUserPassword(params, user, password, identResponse);
|
||||
break;
|
||||
}
|
||||
case ASC_USER_IDENTITY_KERBEROS:
|
||||
case ASC_USER_IDENTITY_SAML:
|
||||
case ASC_USER_IDENTITY_JWT:
|
||||
{
|
||||
OFFile identFile;
|
||||
if (!identFile.fopen(identFile_.c_str(), "rb"))
|
||||
{
|
||||
// log >> Unable to open Kerberbose, SAML or JWT file
|
||||
return EC_IllegalCall;
|
||||
}
|
||||
|
||||
offile_off_t result = identFile.fseek(0, SEEK_END);
|
||||
if (result != 0)
|
||||
return EC_IllegalParameter;
|
||||
offile_off_t filesize = identFile.ftell();
|
||||
if (filesize > 65535)
|
||||
{
|
||||
// log >> "Kerberos, SAML or JWT file is larger than 65535 bytes, bytes after that position are ignored
|
||||
filesize = 65535;
|
||||
}
|
||||
|
||||
char *buf = new char[static_cast<unsigned int>(filesize)];
|
||||
size_t bytesRead = identFile.fread(buf, 1, static_cast<size_t>(filesize));
|
||||
identFile.fclose();
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
// log >> Unable to read Kerberos, SAML or JWT info file
|
||||
delete[] buf;
|
||||
return EC_IllegalCall;
|
||||
}
|
||||
|
||||
if (identMode == ASC_USER_IDENTITY_KERBEROS)
|
||||
cond = ASC_setIdentRQKerberos(params, buf, static_cast<Uint16>(bytesRead), identResponse);
|
||||
else if (identMode == ASC_USER_IDENTITY_SAML)
|
||||
cond = ASC_setIdentRQSaml(params, buf, static_cast<Uint16>(bytesRead), identResponse);
|
||||
else
|
||||
cond = ASC_setIdentRQJwt(params, buf, static_cast<Uint16>(bytesRead), identResponse);
|
||||
delete[] buf;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
cond = EC_IllegalCall;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cond.bad())
|
||||
{
|
||||
// log >> Failed
|
||||
}
|
||||
|
||||
return cond;
|
||||
}
|
||||
|
||||
OFCondition dcm_cstore::checkUserIdentityResponse(T_ASC_Parameters *params)
|
||||
{
|
||||
if (params == NULL)
|
||||
return ASC_NULLKEY;
|
||||
if (identMode == ASC_USER_IDENTITY_NONE || !identResponse)
|
||||
return EC_Normal;
|
||||
if (identMode == ASC_USER_IDENTITY_USER || identMode == ASC_USER_IDENTITY_USER_PASSWORD)
|
||||
{
|
||||
UserIdentityNegotiationSubItemAC *rsp = params->DULparams.ackUserIdentNeg;
|
||||
if (rsp == NULL)
|
||||
{
|
||||
// log >> User Identity Negotitation failed: Positive response requested but none received
|
||||
return ASC_USERIDENTIFICATIONFAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return EC_Normal;
|
||||
}
|
||||
|
||||
bool dcm_cstore::isaListMember(std::list<std::string> &lst, std::string &s)
|
||||
{
|
||||
std::list<std::string>::iterator cur = lst.begin();
|
||||
std::list<std::string>::iterator end = lst.end();
|
||||
|
||||
bool found = false;
|
||||
while (cur != end && !found)
|
||||
{
|
||||
found = (s == *cur);
|
||||
++cur;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
OFCondition dcm_cstore::addPresentationContext(T_ASC_Parameters *params, int presentationContextId, const std::string &abstractSyntax, const std::string &transferSyntax, T_ASC_SC_ROLE proposedRole)
|
||||
{
|
||||
const char *c_p = transferSyntax.c_str();
|
||||
OFCondition cond = ASC_addPresentationContext(params, presentationContextId, abstractSyntax.c_str(), &c_p, 1, proposedRole);
|
||||
return cond;
|
||||
}
|
||||
|
||||
OFCondition dcm_cstore::addPresentationContext(T_ASC_Parameters *params, int presentationContextId, const std::string &abstracySyntax, const std::list<std::string> &transferSyntaxList, T_ASC_SC_ROLE proposedRole)
|
||||
{
|
||||
const char **transferSyntaxes = new const char*[transferSyntaxList.size()];
|
||||
int transferSyntaxCount = 0;
|
||||
|
||||
std::list<std::string>::const_iterator s_cur = transferSyntaxList.begin();
|
||||
std::list<std::string>::const_iterator s_end = transferSyntaxList.end();
|
||||
while (s_cur != s_end)
|
||||
{
|
||||
transferSyntaxes[transferSyntaxCount++] = (*s_cur).c_str();
|
||||
++s_cur;
|
||||
}
|
||||
|
||||
OFCondition cond = ASC_addPresentationContext(params, presentationContextId, abstracySyntax.c_str(), transferSyntaxes, transferSyntaxCount, proposedRole);
|
||||
delete[] transferSyntaxes;
|
||||
return cond;
|
||||
}
|
||||
|
||||
OFCondition dcm_cstore::storeSCU(T_ASC_Association *assoc, const char *fname)
|
||||
{
|
||||
DIC_US msgId = assoc->nextMsgID++;
|
||||
T_ASC_PresentationContextID presID;
|
||||
T_DIMSE_C_StoreRQ req;
|
||||
T_DIMSE_C_StoreRSP rsp;
|
||||
DIC_UI sopClass;
|
||||
DIC_UI sopInstance;
|
||||
DcmDataset *statusDetail = NULL;
|
||||
unsuccessfulStoreEncountered = true;
|
||||
|
||||
DcmFileFormat dcmff;
|
||||
OFCondition cond = dcmff.loadFile(fname, EXS_Unknown, EGL_noChange, DCM_MaxReadLength, readMode);
|
||||
if (cond.bad())
|
||||
{
|
||||
// log >> Bad DICOM file
|
||||
return cond;
|
||||
}
|
||||
|
||||
if (inventSOPInstanceInformation)
|
||||
{
|
||||
replaceSOPInstanceInformation(dcmff.getDataset());
|
||||
}
|
||||
|
||||
if (!DU_findSOPClassAndInstanceInDataSet(dcmff.getDataset(), sopClass, sizeof(sopClass), sopInstance, sizeof(sopInstance), correctUIDPadding))
|
||||
{
|
||||
// log >> No SOP Class or Instance UID in file
|
||||
return DIMSE_BADDATA;
|
||||
}
|
||||
|
||||
DcmXfer filexfer(dcmff.getDataset()->getOriginalXfer());
|
||||
if (filexfer.isNotEncapsulated() && networkTransferSyntax == EXS_DeflatedLittleEndianExplicit)
|
||||
{
|
||||
filexfer = EXS_DeflatedLittleEndianExplicit;
|
||||
}
|
||||
|
||||
if (filexfer.getXfer() != EXS_Unknown)
|
||||
{
|
||||
presID = ASC_findAcceptedPresentationContextID(assoc, sopClass, filexfer.getXferID());
|
||||
}
|
||||
else
|
||||
{
|
||||
presID = ASC_findAcceptedPresentationContextID(assoc, sopClass);
|
||||
}
|
||||
if (presID == 0)
|
||||
{
|
||||
const char *modalityName = dcmSOPClassUIDToModality(sopClass);
|
||||
if (!modalityName)
|
||||
modalityName = dcmFindNameOfUID(sopClass);
|
||||
if (!modalityName)
|
||||
modalityName = "unknown SOP class";
|
||||
// log >> No presentation context for :
|
||||
return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
|
||||
}
|
||||
|
||||
T_ASC_PresentationContext pc;
|
||||
ASC_findAcceptedPresentationContext(assoc->params, presID, &pc);
|
||||
DcmXfer netTransfer(pc.acceptedTransferSyntax);
|
||||
|
||||
bzero(reinterpret_cast<char *>(&req), sizeof(req));
|
||||
req.MessageID = msgId;
|
||||
OFStandard::strlcpy(req.AffectedSOPClassUID, sopClass, sizeof(req.AffectedSOPClassUID));
|
||||
OFStandard::strlcpy(req.AffectedSOPInstanceUID, sopInstance, sizeof(req.AffectedSOPInstanceUID));
|
||||
req.DataSetType = DIMSE_DATASET_PRESENT;
|
||||
req.Priority = DIMSE_PRIORITY_MEDIUM;
|
||||
cond = DIMSE_storeUser(assoc, presID, &req, NULL, dcmff.getDataset(), progressCallback, cstore_callback, blockMode, dimse_tiemout, &rsp, &statusDetail, NULL, static_cast<long>(OFStandard::getFileSize(fname)));
|
||||
if (cond == EC_Normal && (rsp.DimseStatus == STATUS_Success || DICOM_WARNING_STATUS(rsp.DimseStatus)))
|
||||
{
|
||||
unsuccessfulStoreEncountered = false;
|
||||
}
|
||||
lastStatusCode = rsp.DimseStatus;
|
||||
if (cond == EC_Normal)
|
||||
{
|
||||
// log >> Recevied Store Response
|
||||
}
|
||||
else
|
||||
{
|
||||
// log >> Store Failed, file
|
||||
}
|
||||
|
||||
return cond;
|
||||
}
|
||||
|
||||
OFCondition dcm_cstore::cstore(T_ASC_Association *assoc, const std::string &fname)
|
||||
{
|
||||
OFCondition cond = EC_Normal;
|
||||
int n = static_cast<int>(repeatCount);
|
||||
while (cond.good() && n-- && !(haltOnUnsuccessfulStore && unsuccessfulStoreEncountered))
|
||||
{
|
||||
cond = storeSCU(assoc, fname.c_str());
|
||||
}
|
||||
|
||||
if (!haltOnUnsuccessfulStore)
|
||||
{
|
||||
cond = EC_Normal;
|
||||
}
|
||||
|
||||
return cond;
|
||||
}
|
||||
|
||||
int dcm_cstore::docstore(std::string dir)
|
||||
{
|
||||
std::list<std::string> fileNameList;
|
||||
std::list<std::string> sopClassUIDList;
|
||||
std::list<std::string> sopInstanceUIDList;
|
||||
|
||||
T_ASC_Network * net;
|
||||
T_ASC_Parameters * params;
|
||||
DIC_NODENAME peerHost;
|
||||
T_ASC_Association * assoc;
|
||||
DcmAssociationConfiguration asccfg;
|
||||
|
||||
OFStandard::initializeNetwork();
|
||||
if (!dcmDataDict.isDictionaryLoaded())
|
||||
{
|
||||
// log >> "no data dictionary loaded, check environment variable
|
||||
}
|
||||
|
||||
std::list<std::string> inputFiles;
|
||||
OFStandard::searchDirectoryRecursively(dir.c_str(), inputFiles, scanPattern, "", recurse);
|
||||
if (inputFiles.empty())
|
||||
{
|
||||
return e_no_input_file;
|
||||
}
|
||||
|
||||
DcmFileFormat dfile;
|
||||
char sopClassUID[128];
|
||||
char sopInstanceUID[128];
|
||||
bool ignoreName;
|
||||
const char * currentFileName = NULL;
|
||||
std::list<std::string>::iterator if_iter = inputFiles.begin();
|
||||
std::list<std::string>::iterator if_last = inputFiles.end();
|
||||
while (if_iter != if_last)
|
||||
{
|
||||
ignoreName = false;
|
||||
currentFileName = (*if_iter).c_str();
|
||||
if (OFStandard::fileExists(currentFileName))
|
||||
{
|
||||
if (proposeOnlyRequiredPresentationContexts)
|
||||
{
|
||||
if (!findSOPClassAndInstanceInFile(currentFileName, sopClassUID, sizeof(sopClassUID), sopInstanceUID, sizeof(sopInstanceUID)))
|
||||
{
|
||||
ignoreName = true;
|
||||
if (haltOnUnsuccessfulStore)
|
||||
{
|
||||
// missing SOP class (or instance) in file
|
||||
return e_no_presentation_context;
|
||||
}
|
||||
}
|
||||
else if (!dcmIsaStorageSOPClassUID(sopClassUID, ESSC_All))
|
||||
{
|
||||
ignoreName = true;
|
||||
if (haltOnUnsuccessfulStore)
|
||||
{
|
||||
// unknown storage SOP class in file
|
||||
return e_unknown_storage_sopclass;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sopClassUIDList.push_back(sopClassUID);
|
||||
sopInstanceUIDList.push_back(sopInstanceUID);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoreName)
|
||||
{
|
||||
fileNameList.push_back(currentFileName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (haltOnUnsuccessfulStore)
|
||||
{
|
||||
// cannot access file
|
||||
return e_cannot_access_file;
|
||||
}
|
||||
}
|
||||
++if_iter;
|
||||
}
|
||||
|
||||
OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, acse_tiemout, &net);
|
||||
if (cond.bad())
|
||||
{
|
||||
// log >> ASC_initializeNetwork Failed
|
||||
return cond.code();
|
||||
}
|
||||
|
||||
cond = ASC_createAssociationParameters(¶ms, maxReceivedPDULength);
|
||||
if (cond.bad())
|
||||
{
|
||||
// log >> ASC_createAssociationParameters Failed
|
||||
return cond.code();
|
||||
}
|
||||
|
||||
ASC_setAPTitles(params, ourTitle_, peerTitle_, NULL);
|
||||
|
||||
sprintf(peerHost, "%s:%d", peerIp_, static_cast<int>(peerPort_));
|
||||
ASC_setPresentationAddresses(params, OFStandard::getHostName().c_str(), peerHost);
|
||||
|
||||
if (identMode != ASC_USER_IDENTITY_NONE)
|
||||
{
|
||||
cond = configureUserIdentityRequest(params);
|
||||
if (cond.bad())
|
||||
return cond.code();
|
||||
}
|
||||
|
||||
if (profileName)
|
||||
{
|
||||
std::string sprofile;
|
||||
const unsigned char * c = reinterpret_cast<const unsigned char *>(profileName);
|
||||
while (*c)
|
||||
{
|
||||
if (!isspace(*c))
|
||||
sprofile += static_cast<char>(toupper(*c));
|
||||
++c;
|
||||
}
|
||||
cond = asccfg.setAssociationParameters(sprofile.c_str(), *params);
|
||||
}
|
||||
else
|
||||
{
|
||||
cond = addStoragePresentationContexts(params, sopClassUIDList);
|
||||
}
|
||||
|
||||
if (cond.bad())
|
||||
{
|
||||
// log >> addStoragePresentationContexts List Failed
|
||||
return cond.code();
|
||||
}
|
||||
|
||||
cond = ASC_requestAssociation(net, params, &assoc);
|
||||
if (cond.bad())
|
||||
{
|
||||
if (cond == DUL_ASSOCIATIONREJECTED)
|
||||
{
|
||||
// Association Rejected
|
||||
return cond.code();
|
||||
}
|
||||
else
|
||||
{
|
||||
// C-Store Association Request Failed
|
||||
return cond.code();
|
||||
}
|
||||
}
|
||||
|
||||
if (ASC_countAcceptedPresentationContexts(params) == 0)
|
||||
{
|
||||
// No Acceptable Presentation Contexts
|
||||
return e_no_acceptable_presentation_context;
|
||||
}
|
||||
|
||||
cond = checkUserIdentityResponse(params);
|
||||
if (cond.bad())
|
||||
{
|
||||
// checkUserIdentityResponse Failed
|
||||
return cond.code();
|
||||
}
|
||||
|
||||
// Association Accepted
|
||||
cond = EC_Normal;
|
||||
std::list<std::string>::iterator iter = fileNameList.begin();
|
||||
std::list<std::string>::iterator enditer = fileNameList.end();
|
||||
while (iter != enditer && cond.good())
|
||||
{
|
||||
cond = cstore(assoc, *iter);
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (cond == EC_Normal)
|
||||
{
|
||||
if (abortAssociation)
|
||||
{
|
||||
// Aborting Association
|
||||
cond = ASC_abortAssociation(assoc);
|
||||
if (cond.bad())
|
||||
{
|
||||
// Association Abort Failed
|
||||
return cond.code();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Releasing Association
|
||||
cond = ASC_releaseAssociation(assoc);
|
||||
if (cond.bad())
|
||||
{
|
||||
// Association Release Failed
|
||||
return cond.code();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cond == DUL_PEERREQUESTEDRELEASE)
|
||||
{
|
||||
// Protocol Error: Peer request release
|
||||
cond = ASC_abortAssociation(assoc);
|
||||
if (cond.bad())
|
||||
{
|
||||
// Association Abort Failed
|
||||
return cond.code();
|
||||
}
|
||||
}
|
||||
else if (cond == DUL_PEERABORTEDASSOCIATION)
|
||||
{
|
||||
// Peer Aborted Association
|
||||
}
|
||||
else
|
||||
{
|
||||
// Store SCU Failed
|
||||
cond = ASC_abortAssociation(assoc);
|
||||
if (cond.bad())
|
||||
{
|
||||
// Association Abort Failed
|
||||
return cond.code();
|
||||
}
|
||||
}
|
||||
|
||||
cond = ASC_destroyAssociation(&assoc);
|
||||
if (cond.bad())
|
||||
{
|
||||
// ASC_destroyAssociation Failed
|
||||
return cond.code();
|
||||
}
|
||||
|
||||
cond = ASC_dropNetwork(&net);
|
||||
if (cond.bad())
|
||||
{
|
||||
// ASC_dropNetwork Failed
|
||||
return cond.code();
|
||||
}
|
||||
|
||||
OFStandard::shutdownNetwork();
|
||||
return e_ok;
|
||||
}
|
||||
111
thirdparty/dcm_network/dcm_store.h
vendored
Normal file
111
thirdparty/dcm_network/dcm_store.h
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
#ifndef _DCM_STORE_H_
|
||||
#define _DCM_STORE_H_
|
||||
|
||||
#include "internal/dcm_global.h"
|
||||
#include "internal/dcm_type.h"
|
||||
#include "internal/dcmtk_headers.h"
|
||||
|
||||
// Inherit this abstract class for custom callback handler
|
||||
class _DCM_EXPORT dcm_cstore_callback
|
||||
{
|
||||
public:
|
||||
dcm_cstore_callback();
|
||||
virtual ~dcm_cstore_callback();
|
||||
virtual void callback(T_DIMSE_StoreProgress * progress, T_DIMSE_C_StoreRQ * req) = 0;
|
||||
|
||||
private:
|
||||
////dcm_cstore_callback(const dcm_cstore_callback& other);
|
||||
////dcm_cstore_callback& operator=(const dcm_cstore_callback& other);
|
||||
};
|
||||
|
||||
class _DCM_EXPORT dcm_cstore
|
||||
{
|
||||
public:
|
||||
dcm_cstore(const char *peerIp, unsigned long peerPort, const char *peerTitle, const char *ourTitle);
|
||||
~dcm_cstore();
|
||||
|
||||
void set_dimse_tiemout(int timeout);
|
||||
void set_acse_tiemout(int timeout);
|
||||
void set_ma_received_pdu_length(unsigned long length);
|
||||
void set_max_send_pdu_length(unsigned long length);
|
||||
void set_store_callback(dcm_cstore_callback *callback);
|
||||
|
||||
// a directory of the files need to transfer
|
||||
int docstore(std::string dir);
|
||||
|
||||
private:
|
||||
int secondsSince1970();
|
||||
std::string intToString(int i);
|
||||
std::string makeUID(std::string basePrefix, int counter);
|
||||
bool updateStringAttributeValue(DcmItem *dataset, const DcmTagKey &key, std::string &value);
|
||||
void replaceSOPInstanceInformation(DcmDataset *dataset);
|
||||
OFCondition addStoragePresentationContexts(T_ASC_Parameters *params, std::list<std::string> &sopClasses);
|
||||
bool findSOPClassAndInstanceInFile(const char *fname, char *sopClass, size_t sopClassSize, char *sopInstance, size_t sopInstanceSize);
|
||||
OFCondition configureUserIdentityRequest(T_ASC_Parameters *params);
|
||||
OFCondition checkUserIdentityResponse(T_ASC_Parameters *params);
|
||||
bool isaListMember(std::list<std::string> &lst, std::string &s);
|
||||
OFCondition addPresentationContext(T_ASC_Parameters *params, int presentationContextId, const std::string &abstractSyntax, const std::string &transferSyntax, T_ASC_SC_ROLE proposedRole = ASC_SC_ROLE_DEFAULT);
|
||||
OFCondition addPresentationContext(T_ASC_Parameters *params, int presentationContextId, const std::string &abstracySyntax, const std::list<std::string> &transferSyntaxList, T_ASC_SC_ROLE proposedRole = ASC_SC_ROLE_DEFAULT);
|
||||
|
||||
OFCondition storeSCU(T_ASC_Association *assoc, const char *fname);
|
||||
OFCondition cstore(T_ASC_Association *assoc, const std::string &fname);
|
||||
|
||||
private:
|
||||
const char * peerIp_;
|
||||
unsigned long peerPort_;
|
||||
const char * peerTitle_;
|
||||
const char * ourTitle_;
|
||||
|
||||
dcm_cstore_callback * cstore_callback;
|
||||
|
||||
unsigned long patientCounter;
|
||||
unsigned long studyCounter;
|
||||
unsigned long seriesCounter;
|
||||
unsigned long imageCounter;
|
||||
|
||||
private:
|
||||
bool abortAssociation;
|
||||
unsigned long maxReceivedPDULength;
|
||||
unsigned long maxSendPDULength;
|
||||
E_TransferSyntax networkTransferSyntax;
|
||||
E_FileReadMode readMode;
|
||||
bool scanDir;
|
||||
bool recurse; // depends on scanDir
|
||||
const char * scanPattern;
|
||||
|
||||
bool haltOnUnsuccessfulStore;
|
||||
bool unsuccessfulStoreEncountered;
|
||||
int lastStatusCode;
|
||||
|
||||
bool proposeOnlyRequiredPresentationContexts;
|
||||
bool combineProposedTransferSyntaxes;
|
||||
|
||||
unsigned long repeatCount;
|
||||
unsigned long inventPatientCount;
|
||||
unsigned long inventStudyCount;
|
||||
unsigned long inventSeriesCount;
|
||||
// set true will cause invent new SOP instance information for the current data set
|
||||
// donot used
|
||||
bool inventSOPInstanceInformation;
|
||||
bool correctUIDPadding;
|
||||
std::string patientNamePrefix;
|
||||
std::string patientIDPrefix;
|
||||
std::string studyIDPrefix;
|
||||
std::string accessionNumberPrefix;
|
||||
const char * configFile;
|
||||
const char * profileName;
|
||||
T_DIMSE_BlockingMode blockMode;
|
||||
int dimse_tiemout;
|
||||
int acse_tiemout;
|
||||
unsigned long socket_tiemout;
|
||||
|
||||
// identify user may be not used
|
||||
T_ASC_UserIdentityNegotiationMode identMode;
|
||||
std::string user;
|
||||
std::string password;
|
||||
std::string identFile_;
|
||||
bool identResponse;
|
||||
};
|
||||
|
||||
#endif // !_DCM_STORE_H_
|
||||
|
||||
195
thirdparty/dcm_network/dcm_verify.cpp
vendored
Normal file
195
thirdparty/dcm_network/dcm_verify.cpp
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
#include "dcm_verify.h"
|
||||
|
||||
/* DICOM standard transfer syntaxes */
|
||||
static const char* transferSyntaxes[] = {
|
||||
UID_LittleEndianImplicitTransferSyntax, /* default xfer syntax first */
|
||||
UID_LittleEndianExplicitTransferSyntax,
|
||||
UID_BigEndianExplicitTransferSyntax,
|
||||
UID_JPEGProcess1TransferSyntax,
|
||||
UID_JPEGProcess2_4TransferSyntax,
|
||||
UID_JPEGProcess3_5TransferSyntax,
|
||||
UID_JPEGProcess6_8TransferSyntax,
|
||||
UID_JPEGProcess7_9TransferSyntax,
|
||||
UID_JPEGProcess10_12TransferSyntax,
|
||||
UID_JPEGProcess11_13TransferSyntax,
|
||||
UID_JPEGProcess14TransferSyntax,
|
||||
UID_JPEGProcess15TransferSyntax,
|
||||
UID_JPEGProcess16_18TransferSyntax,
|
||||
UID_JPEGProcess17_19TransferSyntax,
|
||||
UID_JPEGProcess20_22TransferSyntax,
|
||||
UID_JPEGProcess21_23TransferSyntax,
|
||||
UID_JPEGProcess24_26TransferSyntax,
|
||||
UID_JPEGProcess25_27TransferSyntax,
|
||||
UID_JPEGProcess28TransferSyntax,
|
||||
UID_JPEGProcess29TransferSyntax,
|
||||
UID_JPEGProcess14SV1TransferSyntax,
|
||||
UID_RLELosslessTransferSyntax,
|
||||
UID_DeflatedExplicitVRLittleEndianTransferSyntax,
|
||||
UID_JPEGLSLosslessTransferSyntax,
|
||||
UID_JPEGLSLossyTransferSyntax,
|
||||
UID_JPEG2000LosslessOnlyTransferSyntax,
|
||||
UID_JPEG2000TransferSyntax,
|
||||
UID_JPEG2000Part2MulticomponentImageCompressionLosslessOnlyTransferSyntax,
|
||||
UID_JPEG2000Part2MulticomponentImageCompressionTransferSyntax,
|
||||
UID_MPEG2MainProfileAtMainLevelTransferSyntax,
|
||||
UID_MPEG2MainProfileAtHighLevelTransferSyntax,
|
||||
UID_MPEG4HighProfileLevel4_1TransferSyntax,
|
||||
UID_MPEG4BDcompatibleHighProfileLevel4_1TransferSyntax,
|
||||
UID_MPEG4HighProfileLevel4_2_For2DVideoTransferSyntax,
|
||||
UID_MPEG4HighProfileLevel4_2_For3DVideoTransferSyntax,
|
||||
UID_MPEG4StereoHighProfileLevel4_2TransferSyntax,
|
||||
UID_HEVCMainProfileLevel5_1TransferSyntax,
|
||||
UID_HEVCMain10ProfileLevel5_1TransferSyntax
|
||||
};
|
||||
|
||||
dcm_cecho::dcm_cecho(const char *peerIp, unsigned long peerPort, const char *peerTitle, const char *ourTitle)
|
||||
: maxReceivedPDULength(ASC_DEFAULTMAXPDU)
|
||||
, repeatCount(1)
|
||||
, abortAssociation(false)
|
||||
, numXferSyntaxes(1)
|
||||
, numPresentationCtx(1)
|
||||
, aces_timeout(30)
|
||||
, socket_tiemout(60)
|
||||
, blockMode(DIMSE_BLOCKING)
|
||||
, dimse_timeout(0)
|
||||
|
||||
{
|
||||
maxXferSyntaxes = static_cast<unsigned long>(DIM_OF(transferSyntaxes));
|
||||
peerIp_ = peerIp;
|
||||
peerPort_ = peerPort;
|
||||
peerTitle_ = peerTitle;
|
||||
ourTitle_ = ourTitle;
|
||||
}
|
||||
|
||||
dcm_cecho::~dcm_cecho()
|
||||
{
|
||||
}
|
||||
|
||||
void dcm_cecho::set_asce_timeout(int timeout)
|
||||
{
|
||||
aces_timeout = timeout;
|
||||
}
|
||||
|
||||
void dcm_cecho::set_dimse_timeout(int timeout)
|
||||
{
|
||||
dimse_timeout = timeout;
|
||||
}
|
||||
|
||||
void dcm_cecho::set_max_received_pdu_length(unsigned long length)
|
||||
{
|
||||
maxReceivedPDULength = length;
|
||||
}
|
||||
|
||||
int dcm_cecho::docecho()
|
||||
{
|
||||
T_ASC_Network *cecho_net;
|
||||
T_ASC_Parameters *cecho_params;
|
||||
DIC_NODENAME cecho_peerHost;
|
||||
T_ASC_Association *cecho_assoc;
|
||||
|
||||
OFStandard::initializeNetwork();
|
||||
if (!dcmDataDict.isDictionaryLoaded())
|
||||
return e_no_dictionary_loaded;
|
||||
|
||||
OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, aces_timeout, &cecho_net);
|
||||
if (cond.bad())
|
||||
return cond.code(); // global error code should be a super set of condition error code
|
||||
|
||||
cond = ASC_createAssociationParameters(&cecho_params, maxReceivedPDULength);
|
||||
if (cond.bad())
|
||||
return cond.code();
|
||||
|
||||
ASC_setAPTitles(cecho_params, ourTitle_, peerTitle_, NULL);
|
||||
sprintf(cecho_peerHost, "%s:%d", peerIp_, static_cast<int>(peerPort_));
|
||||
ASC_setPresentationAddresses(cecho_params, OFStandard::getHostName().c_str(), cecho_peerHost);
|
||||
|
||||
int presentationContextID = 1;
|
||||
for (unsigned long ii = 0; ii < numPresentationCtx; ii++)
|
||||
{
|
||||
cond = ASC_addPresentationContext(cecho_params, presentationContextID, UID_VerificationSOPClass, transferSyntaxes, static_cast<int>(numXferSyntaxes));
|
||||
presentationContextID += 2;
|
||||
if (cond.bad())
|
||||
return cond.code();
|
||||
}
|
||||
|
||||
cond = ASC_requestAssociation(cecho_net, cecho_params, &cecho_assoc);
|
||||
if (cond.bad())
|
||||
{
|
||||
if (cond == DUL_ASSOCIATIONREJECTED)
|
||||
return e_association_rejected;
|
||||
else
|
||||
return cond.code();
|
||||
}
|
||||
|
||||
if (ASC_countAcceptedPresentationContexts(cecho_params) == 0)
|
||||
return e_no_acceptable_presentation_context;
|
||||
|
||||
cond = cecho(cecho_assoc, repeatCount, blockMode, dimse_timeout);
|
||||
if (cond == EC_Normal)
|
||||
{
|
||||
if (abortAssociation)
|
||||
{
|
||||
cond = ASC_abortAssociation(cecho_assoc);
|
||||
if (cond.bad())
|
||||
return cond.code();
|
||||
}
|
||||
else
|
||||
{
|
||||
cond = ASC_releaseAssociation(cecho_assoc);
|
||||
if (cond.bad())
|
||||
return cond.code();
|
||||
}
|
||||
}
|
||||
else if (cond == DUL_PEERREQUESTEDRELEASE)
|
||||
{
|
||||
cond = ASC_abortAssociation(cecho_assoc);
|
||||
if (cond.bad())
|
||||
return cond.code();
|
||||
}
|
||||
else if (cond == DUL_PEERABORTEDASSOCIATION)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
cond = ASC_abortAssociation(cecho_assoc);
|
||||
if (cond.bad())
|
||||
return cond.code();
|
||||
}
|
||||
|
||||
cond = ASC_destroyAssociation(&cecho_assoc);
|
||||
if (cond.bad())
|
||||
return cond.code();
|
||||
|
||||
cond = ASC_dropNetwork(&cecho_net);
|
||||
if (cond.bad())
|
||||
return cond.code();
|
||||
|
||||
OFStandard::shutdownNetwork();
|
||||
return e_ok;
|
||||
}
|
||||
|
||||
OFCondition dcm_cecho::echoSCU(T_ASC_Association * assoc, T_DIMSE_BlockingMode block_mode, int dimse_timeout)
|
||||
{
|
||||
DIC_US msgId = assoc->nextMsgID++;
|
||||
DIC_US status;
|
||||
DcmDataset *statusDetail = NULL;
|
||||
|
||||
// log >> "Sending Echo Request
|
||||
OFCondition cond = DIMSE_echoUser(assoc, msgId, block_mode, dimse_timeout, &status, &statusDetail);
|
||||
if (statusDetail != NULL)
|
||||
delete statusDetail;
|
||||
|
||||
return cond;
|
||||
}
|
||||
|
||||
OFCondition dcm_cecho::cecho(T_ASC_Association * assoc, unsigned long num_repeat, T_DIMSE_BlockingMode block_mode, int dimse_tiemout)
|
||||
{
|
||||
OFCondition cond = EC_Normal;
|
||||
unsigned long n = num_repeat;
|
||||
|
||||
while (cond.good() && n--)
|
||||
cond = echoSCU(assoc, block_mode, dimse_tiemout);
|
||||
|
||||
return cond;
|
||||
}
|
||||
|
||||
41
thirdparty/dcm_network/dcm_verify.h
vendored
Normal file
41
thirdparty/dcm_network/dcm_verify.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef _DCM_VERIFY_H_
|
||||
#define _DCM_VERIFY_H_
|
||||
|
||||
#include "internal/dcm_global.h"
|
||||
#include "internal/dcm_type.h"
|
||||
#include "internal/dcmtk_headers.h"
|
||||
|
||||
class _DCM_EXPORT dcm_cecho
|
||||
{
|
||||
public:
|
||||
dcm_cecho(const char *peerIp, unsigned long peerPort, const char *peerTitle, const char *ourTitle);
|
||||
~dcm_cecho();
|
||||
|
||||
void set_asce_timeout(int timeout);
|
||||
void set_dimse_timeout(int timeout);
|
||||
void set_max_received_pdu_length(unsigned long length);
|
||||
|
||||
int docecho();
|
||||
|
||||
private:
|
||||
OFCondition echoSCU(T_ASC_Association * assoc, T_DIMSE_BlockingMode block_mode, int dimse_timeout);
|
||||
OFCondition cecho(T_ASC_Association * assoc, unsigned long num_repeat, T_DIMSE_BlockingMode block_mode, int dimse_tiemout);
|
||||
|
||||
private:
|
||||
const char * peerIp_;
|
||||
unsigned long peerPort_;
|
||||
const char * peerTitle_;
|
||||
const char * ourTitle_;
|
||||
unsigned long maxReceivedPDULength;
|
||||
unsigned long repeatCount;
|
||||
bool abortAssociation;
|
||||
unsigned long numXferSyntaxes;
|
||||
unsigned long numPresentationCtx;
|
||||
unsigned long maxXferSyntaxes;
|
||||
int aces_timeout;
|
||||
int socket_tiemout;
|
||||
T_DIMSE_BlockingMode blockMode;
|
||||
int dimse_timeout;
|
||||
};
|
||||
|
||||
#endif // _DCM_VERIFY_H_
|
||||
33
thirdparty/dcm_network/internal/dcm_global.h
vendored
Normal file
33
thirdparty/dcm_network/internal/dcm_global.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef _DCM_GLOBAL_H_
|
||||
#define _DCM_GLOBAL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define _DCM_BEGIN_EXTERN_C extern "C" {
|
||||
#define _DCM_END_EXTERN_C }
|
||||
#else
|
||||
#define _DCM_BEGIN_EXTERN_C
|
||||
#define _DCM_END_EXTERN_C
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( disable : 4251)
|
||||
#pragma warning( disable : 4099)
|
||||
#pragma warning( disable : 4521)
|
||||
#pragma warning( disable : 4522)
|
||||
#if _MSC_VER >= 1400
|
||||
#pragma warning( disable : 4996)
|
||||
#pragma warning( disable : 4351)
|
||||
#endif /* _MSC_VER >= 1400 */
|
||||
#endif // _MSC_VER
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
|
||||
#ifdef _DCM_NET_EXPORTS
|
||||
#define _DCM_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define _DCM_EXPORT __declspec(dllimport)
|
||||
#endif // _DCM_NET_EXPORTS
|
||||
#else
|
||||
#define _DCM_EXPORT
|
||||
#endif // defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
|
||||
|
||||
#endif // !_DCM_GLOBAL_H_
|
||||
23
thirdparty/dcm_network/internal/dcm_type.h
vendored
Normal file
23
thirdparty/dcm_network/internal/dcm_type.h
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef _DCM_TYPE_H_
|
||||
#define _DCM_TYPE_H_
|
||||
|
||||
const int e_ok = 0;
|
||||
const int e_no_input_file = -9004;
|
||||
const int e_no_sopclass_in_file = -9005;
|
||||
const int e_unknown_storage_sopclass = -9006;
|
||||
const int e_cannot_access_file = -9007;
|
||||
const int e_no_acceptable_presentation_context = -9008;
|
||||
const int e_association_rejected = -9009;
|
||||
const int e_no_dictionary_loaded = -9010;
|
||||
const int e_cannot_initialize_network = -9011;
|
||||
const int e_cannot_set_uid = -9012;
|
||||
const int e_cannot_create_association_parameters = -9013;
|
||||
const int e_cannot_negotiate_association = -9014;
|
||||
const int e_no_presentation_context = -9015;
|
||||
const int e_cannot_abort_association = -9016;
|
||||
const int e_cannot_release_association = -9017;
|
||||
const int e_cannot_destroy_association = -9018;
|
||||
const int e_cannot_drop_network = -9019;
|
||||
|
||||
|
||||
#endif // !DCM_TYPE_H_
|
||||
11
thirdparty/dcm_network/internal/dcmtk_headers.h
vendored
Normal file
11
thirdparty/dcm_network/internal/dcmtk_headers.h
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "dcmtk/dcmnet/dfindscu.h"
|
||||
#include "dcmtk/dcmnet/diutil.h"
|
||||
#include "dcmtk/dcmnet/dcasccfg.h"
|
||||
#include "dcmtk/dcmdata/dcdict.h"
|
||||
#include "dcmtk/dcmdata/dcdicent.h"
|
||||
#include "dcmtk/dcmdata/dcfilefo.h"
|
||||
#include "dcmtk/dcmdata/dcmetinf.h"
|
||||
#include "dcmtk/dcmdata/dcdeftag.h"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user