Add thirdparty dir.

This commit is contained in:
Krad
2022-07-08 10:04:23 +08:00
parent 36f854dadc
commit 3e9f4a7b75
14 changed files with 3082 additions and 1 deletions

1
thirdparty/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1 @@
add_subdirectory(dcm_network)

33
thirdparty/dcm_network/CMakeLists.txt vendored Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

174
thirdparty/dcm_network/dcm_move.h vendored Normal file
View 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
View 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(&params, 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
View 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
View 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
View 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_

View 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_

View 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_

View 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"