//=====================================================================
// SendDICOM.cpp : Defines the entry point for the DLL application.
//
// Created by HGB 2011 Nanjing ChunRen L.T.D
//=====================================================================
#include "stdafx.h"
#include "SendDICOM.h"
#include "osconfig.h" /* make sure OS specific configuration is included first */
#define INCLUDE_CSTDLIB
#define INCLUDE_CSTDIO
#define INCLUDE_CSTRING
#define INCLUDE_CERRNO
#define INCLUDE_CSTDARG
#define INCLUDE_CCTYPE
#include "ofstdinc.h"
BEGIN_EXTERN_C
#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
END_EXTERN_C
#ifdef HAVE_GUSI_H
#include <GUSI.h>
#endif
#include "ofstring.h"
#include "dimse.h"
#include "diutil.h"
#include "dcdatset.h"
#include "dcmetinf.h"
#include "dcfilefo.h"
#include "dcdebug.h"
#include "dcuid.h"
#include "dcdict.h"
#include "dcdeftag.h"
#include "cmdlnarg.h"
#include "ofconapp.h"
#include "dcuid.h" /* for dcmtk version name */
#include "dicom.h" /* for DICOM_APPLICATION_REQUESTOR */
#include "dcostrmz.h" /* for dcmZlibCompressionLevel */
#include "dcasccfg.h" /* for class DcmAssociationConfiguration */
#include "dcasccff.h" /* for class DcmAssociationConfigurationFile */
#ifdef ON_THE_FLY_COMPRESSION
#include "djdecode.h" /* for dcmjpeg decoders */
#include "djencode.h" /* for dcmjpeg encoders */
#include "dcrledrg.h" /* for DcmRLEDecoderRegistration */
#include "dcrleerg.h" /* for DcmRLEEncoderRegistration */
#endif
#ifdef WITH_OPENSSL
#include "tlstrans.h"
#include "tlslayer.h"
#endif
#include "WINSOCK.H"
#ifdef WITH_ZLIB
#include <zlib.h> /* for zlibVersion() */
#endif
static E_TransferSyntax opt_networkTransferSyntax = EXS_Unknown;
static OFBool opt_proposeOnlyRequiredPresentationContexts = OFFalse;
static OFBool opt_combineProposedTransferSyntaxes = OFFalse;
static OFCmdUnsignedInt opt_repeatCount = 1;
static OFBool opt_haltOnUnsuccessfulStore = OFTrue;
static OFCmdUnsignedInt opt_inventPatientCount = 25;
static OFCmdUnsignedInt opt_inventStudyCount = 50;
static OFCmdUnsignedInt opt_inventSeriesCount = 100;
static OFBool opt_inventSOPInstanceInformation = OFFalse;
static OFBool opt_correctUIDPadding = OFFalse;
static OFBool unsuccessfulStoreEncountered = OFFalse;
static OFBool opt_verbose = OFFalse;
static OFBool opt_showPresentationContexts = OFFalse;
static OFBool opt_debug = OFFalse;
static OFBool opt_abortAssociation = OFFalse;
static OFCmdUnsignedInt opt_maxReceivePDULength = ASC_DEFAULTMAXPDU;
static OFCmdUnsignedInt opt_maxSendPDULength = 0;
T_DIMSE_BlockingMode opt_blockMode = DIMSE_BLOCKING;
int opt_dimse_timeout = 0;
int opt_acse_timeout = 30;
static int lastStatusCode = STATUS_Success;
static OFString studyIDPrefix("SID_"); // StudyID is SH (maximum 16 chars)
static OFString accessionNumberPrefix; // AccessionNumber is SH (maximum 16 chars)
static OFString patientIDPrefix("PID_"); // PatientID is LO (maximum 64 chars)
static OFString patientNamePrefix("OFFIS^TEST_PN_"); // PatientName is PN (maximum 16 chars)
static OFCondition
addStoragePresentationContexts(T_ASC_Parameters *params, OFList<OFString>& sopClasses);
static OFCondition
cstore(T_ASC_Association * assoc, const OFString& fname);
static OFBool
isaListMember(OFList<OFString>& lst, OFString& s);
static OFCondition
addPresentationContext(T_ASC_Parameters *params,
int presentationContextId, const OFString& abstractSyntax,
const OFList<OFString>& transferSyntaxList,
T_ASC_SC_ROLE proposedRole = ASC_SC_ROLE_DEFAULT);
static OFCondition
addPresentationContext(T_ASC_Parameters *params,
int presentationContextId, const OFString& abstractSyntax,
const OFString& transferSyntax,
T_ASC_SC_ROLE proposedRole = ASC_SC_ROLE_DEFAULT);
static OFCondition
storeSCU(T_ASC_Association * assoc, const char *fname);
static void
replaceSOPInstanceInformation(DcmDataset* dataset);
static void
progressCallback(void * /*callbackData*/,
T_DIMSE_StoreProgress *progress,
T_DIMSE_C_StoreRQ * /*req*/);
static OFString
makeUID(OFString basePrefix, int counter);
static int
secondsSince1970();
static OFString
intToString(int i);
static OFBool
updateStringAttributeValue(DcmItem* dataset, const DcmTagKey& key, OFString& value);
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
int IncInt(int params)
{
return params+1;
}
//int IniNet
/*==========================================================*/
//Created by hgb 20061229
//result value:
//0: success
//-1: not foud file
//-2:
//-3:
//-4:
//-5:
/*==========================================================*/
int __stdcall SendDCM(LPSTR ourTitle, LPSTR peerTitle,
LPSTR scpIP, LPSTR scpPort, LPSTR FileName)
{
char sopClassUID[128];
char sopInstanceUID[128];
OFList<OFString> fileNameList;
OFList<OFString> sopClassUIDList;
OFList<OFString> sopInstanceUIDList;
T_ASC_Network *net;
T_ASC_Parameters *params;
DIC_NODENAME localHost;
DIC_NODENAME peerHost;
T_ASC_Association *assoc;
//TCHAR tcsModulePath[_MAX_PATH];
//::GetModuleFileName(NULL, tcsModulePath, _MAX_PATH);
//CString strCurDir = tcsModulePath;
//strCurDir = strCurDir.Left(strCurDir.ReverseFind(TEXT('\\'))+1);
//char currentFilename[strCurDir.GetLength()+1];
//strcpy(currentFilename, strCurDir.GetBuffer());
//char *currentFilename = strCurDir;
#ifdef HAVE_GUSI_H
GUSISetup(GUSIwithSIOUXSockets);
GUSISetup(GUSIwithInternetSockets);
#endif
#ifdef HAVE_WINSOCK_H
WSAData winSockData;
/* we need at least version 1.1 */
WORD winSockVersionNeeded = MAKEWORD( 1, 1 );
WSAStartup(winSockVersionNeeded, &winSockData);
#endif
/*
CFileFind find;
if(find.FindFile(FileName))
{
return -1; // not found the file
}
*/
if (access(FileName, R_OK)!=0)
return -2; // did't access file
if (!DU_findSOPClassAndInstanceInFile(FileName, sopClassUID, sopInstanceUID))
return -101;
if (!dcmIsaStorageSOPClassUID(sopClassUID))
return -102;
else
{
//fileNameList.push_back(FileName);
sopClassUIDList.push_back(sopClassUID);
sopInstanceUIDList.push_back(sopInstanceUID);
OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, 30, &net);
if (cond.bad())
return -103;
cond = ASC_createAssociationParameters(¶ms, ASC_DEFAULTMAXPDU);
if (cond.bad())
return -104;
ASC_setAPTitles(params, ourTitle, peerTitle, NULL);
gethostname(localHost, sizeof(localHost) - 1);
sprintf(peerHost, "%s:%s", scpIP, scpPort);
ASC_setPresentationAddresses(params, localHost, peerHost);
cond = addStoragePresentationContexts(params, sopClassUIDList);
if (cond.bad())
{
return -105;
}
cond = ASC_requestAssociation(net, params, &assoc);
if (cond.bad())
{
if (cond == DUL_ASSOCIATIONREJECTED) {
return -106;
} else { //Association Request Failed
return -107;
}
}
//发送文件
cond = EC_Normal;
//OFListIterator(OFString) iter = fileNameList.begin();
//OFListIterator(OFString) enditer = fileNameList.end();
//cond = cstore(assoc, *iter); //OFString
cond = cstore(assoc, OFString(FileName));
if (cond != EC_Normal)
{
//ASC_releaseAssociation(assoc);
//ASC_destroyAssociation(&assoc);
//DimseCondition::dump(cond);
//#ifdef HAVE_WINSOCK_H
//WSACleanup();
//#endif
return -108;//send faid;
}
cond = ASC_releaseAssociation(assoc);
if (cond.bad())
return -109;
cond = ASC_destroyAssociation(&assoc);
if (cond.bad())
return -120;
}
#ifdef HAVE_WINSOCK_H
WSACleanup();
#endif
return 0;
}
static OFCondition
addStoragePresentationContexts(T_ASC_Parameters *params, OFList<OFString>& sopClasses)
{
/*
* Each SOP Class will be proposed in two presentation contexts (unless
* the opt_combineProposedTransferSyntaxes global variable is true).
* The command line specified a preferred transfer syntax to use.
* This prefered transfer syntax will be proposed in one
* presentation context and a set of alternative (fallback) transfer
* syntaxes will be proposed in a different presentation context.
*
* Generally, we prefer to use Explicitly encoded transfer syntaxes
* and if running on a Little Endian machine we prefer
* LittleEndianExplicitTransferSyntax to BigEndianTransferSyntax.
* Some SCP implementations will just select the first transfer
* syntax they support (this is not part of the standard) so
* organise the proposed transfer syntaxes to take advantage
* of such behaviour.
*/
// Which transfer syntax was preferred on the command line
OFString preferredTransferSyntax;
if (opt_networkTransferSyntax == EXS_Unknown) {
/* gLocalByteOrder is defined in dcxfer.h */
if (gLocalByteOrder == EBO_LittleEndian) {
/* we are on a little endian machine */
preferredTransferSyntax = UID_LittleEndianExplicitTransferSyntax;
} else {
/* we are on a big endian machine */
preferredTransferSyntax = UID_BigEndianExplicitTransferSyntax;
}
} else {
DcmXfer xfer(opt_networkTransferSyntax);
preferredTransferSyntax = xfer.getXferID();
}
OFListIterator(OFString) s_cur;
OFListIterator(OFString) s_end;
OFList<OFString> fallbackSyntaxes;
fallbackSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax);
fallbackSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax);
fallbackSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax);
// Remove the preferred syntax from the fallback list
fallbackSyntaxes.remove(preferredTransferSyntax);
// If little endian implicit is preferred then we don't need any fallback syntaxes
// because it is the default transfer syntax and all applications must support it.
if (opt_networkTransferSyntax == EXS_LittleEndianImplicit) {
fallbackSyntaxes.clear();
}
// created a list of transfer syntaxes combined from the preferred and fallback syntaxes
OFList<OFString> 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 (!opt_proposeOnlyRequiredPresentationContexts) {
// add the (short list of) known storage sop classes to the list
// the array of Storage SOP Class UIDs comes from dcuid.h
for (int i=0; i<numberOfDcmShortSCUStorageSOPClassUIDs; i++) {
sopClasses.push_back(dcmShortSCUStorageSOPClassUIDs[i]);
}
}
// thin out the sop classes to remove any duplicates.
OFList<OFString> 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;
}
// add a presentations context for each sop class / transfer syntax pair
OFCondition cond = EC_Normal;
int pid = 1; // presentation context id
s_cur = sops.begin();
s_end = sops.end();
while (s_cur != s_end && cond.good()) {
if (pid > 255) {
///errmsg("Too many presentation contexts");
return ASC_BADPRESENTATIONCONTEXTID;
}
if (opt_combineProposedTransferSyntaxes) {
cond = addPresentationContext(params, pid, *s_cur, combinedSyntaxes);
pid += 2; /* only odd presentation context id's */
} else {
// sop class with preferred transfer syntax
cond = addPresentationContext(params, pid, *s_cur, preferredTransferSyntax);
pid += 2; /* only odd presentation context id's */
if (fallbackSyntaxes.size() > 0) {
if (pid > 255) {
//errmsg("Too many presentation contexts");
return ASC_BADPRESENTATIONCONTEXTID;
}
// sop class with fallback transfer syntax
cond = addPresentationContext(params, pid, *s_cur, fallbackSyntaxes);
pid += 2; /* only odd presentation context id's */
}
}
++s_cur;
}
return cond;
}
static OFCondition
cstore(T_ASC_Association * assoc, const OFString& fname)
/*
* This function will process the given file as often as is specified by opt_repeatCount.
* "Process" in this case means "read file, send C-STORE-RQ, receive C-STORE-RSP".
*
* Parameters:
* assoc - [in] The association (network connection to another DICOM application).
* fname - [in] Name of the file which shall be processed.
*/
{
OFCondition cond = EC_Normal;
/* opt_repeatCount specifies how many times a certain file shall be processed */
int n = (int)opt_repeatCount;
/* as long as no error occured and the counter does not equal 0 */
while ((cond.good()) && n-- && !(opt_haltOnUnsuccessfulStore && unsuccessfulStoreEncountered))
{
/* process file (read file, send C-STORE-RQ, receive C-STORE-RSP) */
cond = storeSCU(assoc, fname.c_str());
}
// we don't want to return an error code if --no-halt was specified.
if (! opt_haltOnUnsuccessfulStore)
{
cond = EC_Normal;
}
/* return result value */
return cond;
}
static OFBool
isaListMember(OFList<OFString>& lst, OFString& s)
{
OFListIterator(OFString) cur = lst.begin();
OFListIterator(OFString) end = lst.end();
OFBool found = OFFalse;
while (cur != end && !found) {
found = (s == *cur);
++cur;
}
return found;
}
static OFCondition
addPresentationContext(T_ASC_Parameters *params,
int presentationContextId, const OFString& abstractSyntax,
const OFString& 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;
}
static OFCondition
addPresentationContext(T_ASC_Parameters *params,
int presentationContextId, const OFString& abstractSyntax,
const OFList<OFString>& transferSyntaxList,
T_ASC_SC_ROLE proposedRole)
{
// create an array of supported/possible transfer syntaxes
const char** transferSyntaxes = new const char*[transferSyntaxList.size()];
int transferSyntaxCount = 0;
OFListConstIterator(OFString) s_cur = transferSyntaxList.begin();
OFListConstIterator(OFString) s_end = transferSyntaxList.end();
while (s_cur != s_end) {
transferSyntaxes[transferSyntaxCount++] = (*s_cur).c_str();
++s_cur;
}
OFCondition cond = ASC_addPresentationContext(params, presentationContextId,
abstractSyntax.c_str(), transferSyntaxes, transferSyntaxCount, proposedRole);
delete[] transferSyntaxes;
return cond;
}
static OFCondition
storeSCU(T_ASC_Association * assoc, const char *fname)
/*
* This function will read all the information from the given file,
* figure out a corresponding presentation context which will be used
* to transmit the information over the network to the SCP, and it
* will finally initiate the transmission of all data to the SCP.
*
* Parameters:
* assoc - [in] The association (network connection to another DICOM application).
* fname - [in] Name of the file which shall be processed.
*/
{
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 = OFTrue; // assumption
if (opt_verbose) {
printf("--------------------------\n");
printf("Sending file: %s\n", fname);
}
/* read information from file. After the call to DcmFileFormat::loadFile(...) the information */
/* which is encapsulated in the file will be available through the DcmFileFormat object. */
/* In detail, it will be available through calls to DcmFileFormat::getMetaInfo() (for */
/* meta header information) and DcmFileFormat::getDataset() (for data set information). */
DcmFileFormat dcmff;
OFCondition cond = dcmff.loadFile(fname);
/* figure out if an error occured while the file was read*/
if (cond.bad()) {
//errmsg("Bad DICOM file: %s: %s", fname, cond.text());
return cond;
}
/* if required, invent new SOP instance information for the current data set (user option) */
if (opt_inventSOPInstanceInformation) {
replaceSOPInstanceInformation(dcmff.getDataset());
}
/* figure out which SOP class and SOP instance is encapsulated in the file */
if (!DU_findSOPClassAndInstanceInDataSet(dcmff.getDataset(),
sopClass, sopInstance, opt_correctUIDPadding)) {
//errmsg("No SOP Class & Instance UIDs in file: %s", fname);
return DIMSE_BADDATA;
}
/* figure out which of the accepted presentation contexts should be used */
DcmXfer filexfer(dcmff.getDataset()->getOriginalXfer());//??????? added by HGB
/* special case: if the file uses an unencapsulated transfer syntax (uncompressed
* or deflated explicit VR) and we prefer deflated explicit VR, then try
* to find a presentation context for deflated explicit VR first.
*/
if (filexfer.isNotEncapsulated() &&
opt_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";
// errmsg("No presentation context for: (%s) %s", modalityName, sopClass);
return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
}
/* if required, dump general information concerning transfer syntaxes */
if (opt_verbose) {
DcmXfer fileTransfer(dcmff.getDataset()->getOriginalXfer());
T_ASC_PresentationContext pc;
ASC_findAcceptedPresentationContext(assoc->params, presId, &pc);
DcmXfer netTransfer(pc.acceptedTransferSyntax);
printf("Transfer: %s -> %s\n",
dcmFindNameOfUID(fileTransfer.getXferID()), dcmFindNameOfUID(netTransfer.getXferID()));
}
/* prepare the transmission of data */
bzero((char*)&req, sizeof(req));
req.MessageID = msgId;
strcpy(req.AffectedSOPClassUID, sopClass);
strcpy(req.AffectedSOPInstanceUID, sopInstance);
req.DataSetType = DIMSE_DATASET_PRESENT;
req.Priority = DIMSE_PRIORITY_LOW;
/* if required, dump some more general information */
if (opt_verbose) {
printf("Store SCU RQ: MsgID %d, (%s)\n", msgId, dcmSOPClassUIDToModality(sopClass));
}
/* finally conduct transmission of data */
cond = DIMSE_storeUser(assoc, presId, &req,
NULL, dcmff.getDataset(), progressCallback, NULL,
opt_blockMode, opt_dimse_timeout,
&rsp, &statusDetail, NULL, DU_fileSize(fname));
/*
* If store command completed normally, with a status
* of success or some warning then the image was accepted.
*/
if (cond == EC_Normal && (rsp.DimseStatus == STATUS_Success || DICOM_WARNING_STATUS(rsp.DimseStatus))) {
unsuccessfulStoreEncountered = OFFalse;
}
/* remember the response's status for later transmissions of data */
lastStatusCode = rsp.DimseStatus;
/* dump some more general information */
if (cond == EC_Normal)
{
if (opt_verbose) {
DIMSE_printCStoreRSP(stdout, &rsp);
}
}
else
{
//errmsg("Store Failed, file: %s:", fname);
DimseCondition::dump(cond);
}
/* dump status detail information if there is some */
if (statusDetail != NULL) {
printf(" Status Detail:\n");
statusDetail->print(COUT);
delete statusDetail;
}
/* return */
return cond;
}
static void
replaceSOPInstanceInformation(DcmDataset* dataset)
{
static OFCmdUnsignedInt patientCounter = 0;
static OFCmdUnsignedInt studyCounter = 0;
static OFCmdUnsignedInt seriesCounter = 0;
static OFCmdUnsignedInt imageCounter = 0;
static OFString seriesInstanceUID;
static OFString seriesNumber;
static OFString studyInstanceUID;
static OFString studyID;
static OFString accessionNumber;
static OFString patientID;
static OFString patientName;
if (seriesInstanceUID.length() == 0) seriesInstanceUID=makeUID(SITE_SERIES_UID_ROOT, (int)seriesCounter);
if (seriesNumber.length() == 0) seriesNumber = intToString((int)seriesCounter);
if (studyInstanceUID.length() == 0) studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, (int)studyCounter);
if (studyID.length() == 0) studyID = studyIDPrefix + intToString((int)secondsSince1970()) + intToString((int)studyCounter);
if (accessionNumber.length() == 0) accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString((int)studyCounter);
if (patientID.length() == 0) patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);
if (patientName.length() == 0) patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);
if (imageCounter >= opt_inventSeriesCount) {
imageCounter = 0;
seriesCounter++;
seriesInstanceUID = makeUID(SITE_SERIES_UID_ROOT, (int)seriesCounter);
seriesNumber = intToString((int)seriesCounter);
}
if (seriesCounter >= opt_inventStudyCount) {
seriesCounter = 0;
studyCounter++;
studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, (int)studyCounter);
studyID = studyIDPrefix + intToString(secondsSince1970()) + intToString((int)studyCounter);
accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString((int)studyCounter);
}
if (studyCounter >= opt_inventPatientCount) {
// we create as many patients as necessary */
studyCounter = 0;
patientCounter++;
patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);
patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);
}
OFString sopInstanceUID = makeUID(SITE_INSTANCE_UID_ROOT, (int)imageCounter);
OFString imageNumber = intToString((int)imageCounter);
if (opt_verbose) {
COUT << "Inventing Identifying Information (" <<
"pa" << patientCounter << ", st" << studyCounter <<
", se" << seriesCounter << ", im" << imageCounter << "): " << endl;
COUT << " PatientName=" << patientName << endl;
COUT << " PatientID=" << patientID << endl;
COUT << " StudyInstanceUID=" << studyInstanceUID << endl;
COUT << " StudyID=" << studyID << endl;
COUT << " SeriesInstanceUID=" << seriesInstanceUID << endl;
COUT << " SeriesNumber=" << seriesNumber << endl;
COUT << " SOPInstanceUID=" << sopInstanceUID << endl;
COUT << " ImageNumber=" << imageNumber << endl;
}
updateStringAttributeValue(dataset, DCM_PatientsName, 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++;
}
static void
progressCallback(void * /*callbackData*/,
T_DIMSE_StoreProgress *progress,
T_DIMSE_C_StoreRQ * /*req*/)
{
if (opt_verbose) {
switch (progress->state) {
case DIMSE_StoreBegin:
printf("XMIT:"); break;
case DIMSE_StoreEnd:
printf("\n"); break;
default:
putchar('.'); break;
}
fflush(stdout);
}
}
static OFString
makeUID(OFString basePrefix, int counter)
{
OFString prefix = basePrefix + "." + intToString(counter);
char uidbuf[65];
OFString uid = dcmGenerateUniqueIdentifier(uidbuf, prefix.c_str());
return uid;
}
static int
secondsSince1970()
{
time_t t = time(NULL);
return (int)t;
}
static OFString
intToString(int i)
{
char numbuf[32];
sprintf(numbuf, "%d", i);
return numbuf;
}
static OFBool
updateStringAttributeValue(DcmItem* dataset, const DcmTagKey& key, OFString& value)
{
DcmStack stack;
DcmTag tag(key);
OFCondition cond = EC_Normal;
cond = dataset->search(key, stack, ESM_fromHere, OFFalse);
if (cond != EC_Normal) {
CERR << "error: updateStringAttributeValue: cannot find: " << tag.getTagName()
<< " " << key << ": "
<< cond.text() << endl;
return OFFalse;
}
DcmElement* elem = (DcmElement*) stack.top();
DcmVR vr(elem->ident());
if (elem->getLength() > vr.getMaxValueLength()) {
CERR << "error: updateStringAttributeValue: INTERNAL ERROR: " << tag.getTagName()
<< " " << key << ": value too large (max "
<< vr.getMaxValueLength() << ") for " << vr.getVRName() << " value: " << value << endl;
return OFFalse;
}
cond = elem->putOFStringArray(value);
if (cond != EC_Normal) {
CERR << "error: updateStringAttributeValue: cannot put string in attribute: " << tag.getTagName()
<< " " << key << ": "
<< cond.text() << endl;
return OFFalse;
}
return OFTrue;
}
---------------------