Add thirdparty dir.
This commit is contained in:
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;
|
||||
}
|
||||
Reference in New Issue
Block a user