使用dctmtk实现DICOM文件的发送(StoreSCU)

  1 //=====================================================================

  2 // SendDICOM.cpp : Defines the entry point for the DLL application.

  3 //

  4 //   Created by HGB 2011  Nanjing ChunRen L.T.D 

  5 //=====================================================================

  6 

  7 

  8 #include "stdafx.h"

  9 #include "SendDICOM.h"

 10 #include "osconfig.h" /* make sure OS specific configuration is included first */

 11 

 12 #define INCLUDE_CSTDLIB

 13 #define INCLUDE_CSTDIO

 14 #define INCLUDE_CSTRING

 15 #define INCLUDE_CERRNO

 16 #define INCLUDE_CSTDARG

 17 #define INCLUDE_CCTYPE

 18 #include "ofstdinc.h"

 19 

 20 BEGIN_EXTERN_C

 21 #ifdef HAVE_SYS_FILE_H

 22 #include <sys/file.h>

 23 #endif

 24 END_EXTERN_C

 25 

 26 #ifdef HAVE_GUSI_H

 27 #include <GUSI.h>

 28 #endif

 29 

 30 #include "ofstring.h"

 31 #include "dimse.h"

 32 #include "diutil.h"

 33 #include "dcdatset.h"

 34 #include "dcmetinf.h"

 35 #include "dcfilefo.h"

 36 #include "dcdebug.h"

 37 #include "dcuid.h"

 38 #include "dcdict.h"

 39 #include "dcdeftag.h"

 40 #include "cmdlnarg.h"

 41 #include "ofconapp.h"

 42 #include "dcuid.h"     /* for dcmtk version name */

 43 #include "dicom.h"     /* for DICOM_APPLICATION_REQUESTOR */

 44 #include "dcostrmz.h"  /* for dcmZlibCompressionLevel */

 45 #include "dcasccfg.h"  /* for class DcmAssociationConfiguration */

 46 #include "dcasccff.h"  /* for class DcmAssociationConfigurationFile */

 47 

 48 #ifdef ON_THE_FLY_COMPRESSION

 49 #include "djdecode.h"  /* for dcmjpeg decoders */

 50 #include "djencode.h"  /* for dcmjpeg encoders */

 51 #include "dcrledrg.h"  /* for DcmRLEDecoderRegistration */

 52 #include "dcrleerg.h"  /* for DcmRLEEncoderRegistration */

 53 #endif

 54 

 55 #ifdef WITH_OPENSSL

 56 #include "tlstrans.h"

 57 #include "tlslayer.h"

 58 #endif

 59 

 60 #include "WINSOCK.H"

 61 

 62 #ifdef WITH_ZLIB

 63 #include <zlib.h>          /* for zlibVersion() */

 64 #endif

 65 

 66 static E_TransferSyntax opt_networkTransferSyntax = EXS_Unknown;

 67 static OFBool opt_proposeOnlyRequiredPresentationContexts = OFFalse;

 68 static OFBool opt_combineProposedTransferSyntaxes = OFFalse;

 69 static OFCmdUnsignedInt opt_repeatCount = 1;

 70 static OFBool opt_haltOnUnsuccessfulStore = OFTrue;

 71 static OFCmdUnsignedInt opt_inventPatientCount = 25;

 72 static OFCmdUnsignedInt opt_inventStudyCount = 50;

 73 static OFCmdUnsignedInt opt_inventSeriesCount = 100;

 74 static OFBool opt_inventSOPInstanceInformation = OFFalse;

 75 static OFBool opt_correctUIDPadding = OFFalse;

 76 static OFBool unsuccessfulStoreEncountered = OFFalse;

 77 static OFBool opt_verbose = OFFalse;

 78 static OFBool opt_showPresentationContexts = OFFalse;

 79 static OFBool opt_debug = OFFalse;

 80 static OFBool opt_abortAssociation = OFFalse;

 81 static OFCmdUnsignedInt opt_maxReceivePDULength = ASC_DEFAULTMAXPDU;

 82 static OFCmdUnsignedInt opt_maxSendPDULength = 0;

 83 T_DIMSE_BlockingMode opt_blockMode = DIMSE_BLOCKING;

 84 int opt_dimse_timeout = 0;

 85 int opt_acse_timeout = 30;

 86 static int lastStatusCode = STATUS_Success;

 87 static OFString studyIDPrefix("SID_");   // StudyID is SH (maximum 16 chars)

 88 static OFString accessionNumberPrefix;  // AccessionNumber is SH (maximum 16 chars)

 89 static OFString patientIDPrefix("PID_"); // PatientID is LO (maximum 64 chars)

 90 static OFString patientNamePrefix("OFFIS^TEST_PN_");   // PatientName is PN (maximum 16 chars)

 91 

 92 static OFCondition

 93 addStoragePresentationContexts(T_ASC_Parameters *params, OFList<OFString>& sopClasses);

 94 static OFCondition

 95 cstore(T_ASC_Association * assoc, const OFString& fname);

 96 static OFBool

 97 isaListMember(OFList<OFString>& lst, OFString& s);

 98 

 99 static OFCondition

100 addPresentationContext(T_ASC_Parameters *params,

101     int presentationContextId, const OFString& abstractSyntax,

102     const OFList<OFString>& transferSyntaxList,

103     T_ASC_SC_ROLE proposedRole = ASC_SC_ROLE_DEFAULT);

104 static OFCondition

105 addPresentationContext(T_ASC_Parameters *params,

106     int presentationContextId, const OFString& abstractSyntax,

107     const OFString& transferSyntax,

108     T_ASC_SC_ROLE proposedRole = ASC_SC_ROLE_DEFAULT);

109 static OFCondition

110 storeSCU(T_ASC_Association * assoc, const char *fname);

111 static void

112 replaceSOPInstanceInformation(DcmDataset* dataset);

113 static void

114 progressCallback(void * /*callbackData*/,

115     T_DIMSE_StoreProgress *progress,

116     T_DIMSE_C_StoreRQ * /*req*/);

117 static OFString

118 makeUID(OFString basePrefix, int counter);

119 static int

120 secondsSince1970();

121 static OFString

122 intToString(int i);

123 static OFBool

124 updateStringAttributeValue(DcmItem* dataset, const DcmTagKey& key, OFString& value);

125 

126 BOOL APIENTRY DllMain( HANDLE hModule, 

127                        DWORD  ul_reason_for_call, 

128                        LPVOID lpReserved

129                      )

130 {

131     return TRUE;

132 }

133 

134 int IncInt(int params)

135 {

136     return params+1;

137 }

138 

139 //int IniNet

140 

141 /*==========================================================*/

142 //Created by hgb 20061229

143 //result value:

144 //0: success

145 //-1: not foud file

146 //-2:

147 //-3:

148 //-4:

149 //-5:

150 /*==========================================================*/

151 int __stdcall SendDCM(LPSTR ourTitle, LPSTR peerTitle, 

152                    LPSTR scpIP, LPSTR scpPort, LPSTR FileName)

153 {

154     char sopClassUID[128];

155     char sopInstanceUID[128];

156     OFList<OFString> fileNameList;

157     OFList<OFString> sopClassUIDList;

158     OFList<OFString> sopInstanceUIDList;

159     T_ASC_Network *net;

160     T_ASC_Parameters *params;

161     DIC_NODENAME localHost;

162     DIC_NODENAME peerHost;

163     T_ASC_Association *assoc;

164 

165     //TCHAR tcsModulePath[_MAX_PATH];

166     //::GetModuleFileName(NULL, tcsModulePath, _MAX_PATH);

167 

168     //CString strCurDir = tcsModulePath;

169     //strCurDir = strCurDir.Left(strCurDir.ReverseFind(TEXT('\\'))+1);

170     //char currentFilename[strCurDir.GetLength()+1];

171     //strcpy(currentFilename, strCurDir.GetBuffer());

172     //char *currentFilename = strCurDir;

173     

174 

175 #ifdef HAVE_GUSI_H

176     GUSISetup(GUSIwithSIOUXSockets);

177     GUSISetup(GUSIwithInternetSockets);

178 #endif

179 

180 #ifdef HAVE_WINSOCK_H

181     WSAData winSockData;

182     /* we need at least version 1.1 */

183     WORD winSockVersionNeeded = MAKEWORD( 1, 1 );

184     WSAStartup(winSockVersionNeeded, &winSockData);

185 #endif

186 

187     /*

188     CFileFind find;

189     if(find.FindFile(FileName))

190     {

191         return -1; // not found the file  

192     }

193     */

194 

195 

196     if (access(FileName, R_OK)!=0)

197         return -2; // did't access file

198     if (!DU_findSOPClassAndInstanceInFile(FileName, sopClassUID, sopInstanceUID))

199         return -101;

200     if (!dcmIsaStorageSOPClassUID(sopClassUID))

201         return -102;

202     else

203     {

204         //fileNameList.push_back(FileName);

205         sopClassUIDList.push_back(sopClassUID);

206         sopInstanceUIDList.push_back(sopInstanceUID);

207 

208         OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, 30, &net);

209         if (cond.bad())

210             return -103;

211 

212         cond = ASC_createAssociationParameters(&params, ASC_DEFAULTMAXPDU);

213         if (cond.bad())

214             return -104;

215 

216         ASC_setAPTitles(params, ourTitle, peerTitle, NULL);

217         gethostname(localHost, sizeof(localHost) - 1);

218         sprintf(peerHost, "%s:%s", scpIP, scpPort);////////

219         ASC_setPresentationAddresses(params, localHost, peerHost);

220 

221         cond = addStoragePresentationContexts(params, sopClassUIDList);

222         if (cond.bad())

223         {

224             return -105;

225         }

226 

227         cond = ASC_requestAssociation(net, params, &assoc);

228         if (cond.bad())

229         {

230             if (cond == DUL_ASSOCIATIONREJECTED) {

231                 return -106;

232             } else {  //Association Request Failed

233                 return -107;

234             }

235         }

236 

237         //发送文件

238         cond = EC_Normal;

239         //OFListIterator(OFString) iter = fileNameList.begin();

240         //OFListIterator(OFString) enditer = fileNameList.end();////

241         //cond = cstore(assoc, *iter);  //OFString

242         cond = cstore(assoc, OFString(FileName));

243         if (cond != EC_Normal)

244         {

245             //ASC_releaseAssociation(assoc);

246             //ASC_destroyAssociation(&assoc);

247             //DimseCondition::dump(cond);

248             //#ifdef HAVE_WINSOCK_H

249                 //WSACleanup();

250             //#endif

251             return -108;//send faid;

252         }

253 

254         cond = ASC_releaseAssociation(assoc);

255         if (cond.bad()) 

256             return -109;

257 

258         cond = ASC_destroyAssociation(&assoc);

259         if (cond.bad()) 

260             return -120;

261 

262     }

263 

264 #ifdef HAVE_WINSOCK_H

265     WSACleanup();

266 #endif

267     return 0;

268 

269 }

270 

271 

272 static OFCondition

273 addStoragePresentationContexts(T_ASC_Parameters *params, OFList<OFString>& sopClasses)

274 {

275     /*

276      * Each SOP Class will be proposed in two presentation contexts (unless

277      * the opt_combineProposedTransferSyntaxes global variable is true).

278      * The command line specified a preferred transfer syntax to use.

279      * This prefered transfer syntax will be proposed in one

280      * presentation context and a set of alternative (fallback) transfer

281      * syntaxes will be proposed in a different presentation context.

282      *

283      * Generally, we prefer to use Explicitly encoded transfer syntaxes

284      * and if running on a Little Endian machine we prefer

285      * LittleEndianExplicitTransferSyntax to BigEndianTransferSyntax.

286      * Some SCP implementations will just select the first transfer

287      * syntax they support (this is not part of the standard) so

288      * organise the proposed transfer syntaxes to take advantage

289      * of such behaviour.

290      */

291 

292     // Which transfer syntax was preferred on the command line

293     OFString preferredTransferSyntax;

294     if (opt_networkTransferSyntax == EXS_Unknown) {

295         /* gLocalByteOrder is defined in dcxfer.h */

296         if (gLocalByteOrder == EBO_LittleEndian) {

297             /* we are on a little endian machine */

298             preferredTransferSyntax = UID_LittleEndianExplicitTransferSyntax;

299         } else {

300             /* we are on a big endian machine */

301             preferredTransferSyntax = UID_BigEndianExplicitTransferSyntax;

302         }

303     } else {

304         DcmXfer xfer(opt_networkTransferSyntax);

305         preferredTransferSyntax = xfer.getXferID();

306     }

307 

308     OFListIterator(OFString) s_cur;

309     OFListIterator(OFString) s_end;

310 

311 

312     OFList<OFString> fallbackSyntaxes;

313     fallbackSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax);

314     fallbackSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax);

315     fallbackSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax);

316     // Remove the preferred syntax from the fallback list

317     fallbackSyntaxes.remove(preferredTransferSyntax);

318     // If little endian implicit is preferred then we don't need any fallback syntaxes

319     // because it is the default transfer syntax and all applications must support it.

320     if (opt_networkTransferSyntax == EXS_LittleEndianImplicit) {

321         fallbackSyntaxes.clear();

322     }

323 

324     // created a list of transfer syntaxes combined from the preferred and fallback syntaxes

325     OFList<OFString> combinedSyntaxes;

326     s_cur = fallbackSyntaxes.begin();

327     s_end = fallbackSyntaxes.end();

328     combinedSyntaxes.push_back(preferredTransferSyntax);

329     while (s_cur != s_end)

330     {

331         if (!isaListMember(combinedSyntaxes, *s_cur)) combinedSyntaxes.push_back(*s_cur);

332         ++s_cur;

333     }

334 

335     if (!opt_proposeOnlyRequiredPresentationContexts) {

336         // add the (short list of) known storage sop classes to the list

337         // the array of Storage SOP Class UIDs comes from dcuid.h

338         for (int i=0; i<numberOfDcmShortSCUStorageSOPClassUIDs; i++) {

339             sopClasses.push_back(dcmShortSCUStorageSOPClassUIDs[i]);

340         }

341     }

342 

343     // thin out the sop classes to remove any duplicates.

344     OFList<OFString> sops;

345     s_cur = sopClasses.begin();

346     s_end = sopClasses.end();

347     while (s_cur != s_end) {

348         if (!isaListMember(sops, *s_cur)) {

349             sops.push_back(*s_cur);

350         }

351         ++s_cur;

352     }

353 

354     // add a presentations context for each sop class / transfer syntax pair

355     OFCondition cond = EC_Normal;

356     int pid = 1; // presentation context id

357     s_cur = sops.begin();

358     s_end = sops.end();

359     while (s_cur != s_end && cond.good()) {

360 

361         if (pid > 255) {

362             ///errmsg("Too many presentation contexts");

363             return ASC_BADPRESENTATIONCONTEXTID;

364         }

365 

366         if (opt_combineProposedTransferSyntaxes) {

367             cond = addPresentationContext(params, pid, *s_cur, combinedSyntaxes);

368             pid += 2;   /* only odd presentation context id's */

369         } else {

370 

371             // sop class with preferred transfer syntax

372             cond = addPresentationContext(params, pid, *s_cur, preferredTransferSyntax);

373             pid += 2;   /* only odd presentation context id's */

374 

375             if (fallbackSyntaxes.size() > 0) {

376                 if (pid > 255) {

377                     //errmsg("Too many presentation contexts");

378                     return ASC_BADPRESENTATIONCONTEXTID;

379                 }

380 

381                 // sop class with fallback transfer syntax

382                 cond = addPresentationContext(params, pid, *s_cur, fallbackSyntaxes);

383                 pid += 2;       /* only odd presentation context id's */

384             }

385         }

386         ++s_cur;

387     }

388 

389     return cond;

390 }

391 

392 static OFCondition

393 cstore(T_ASC_Association * assoc, const OFString& fname)

394     /*

395      * This function will process the given file as often as is specified by opt_repeatCount.

396      * "Process" in this case means "read file, send C-STORE-RQ, receive C-STORE-RSP".

397      *

398      * Parameters:

399      *   assoc - [in] The association (network connection to another DICOM application).

400      *   fname - [in] Name of the file which shall be processed.

401      */

402 {

403     OFCondition cond = EC_Normal;

404 

405     /* opt_repeatCount specifies how many times a certain file shall be processed */

406     int n = (int)opt_repeatCount;

407 

408     /* as long as no error occured and the counter does not equal 0 */

409     while ((cond.good()) && n-- && !(opt_haltOnUnsuccessfulStore && unsuccessfulStoreEncountered))

410     {

411         /* process file (read file, send C-STORE-RQ, receive C-STORE-RSP) */

412         cond = storeSCU(assoc, fname.c_str());

413     }

414 

415     // we don't want to return an error code if --no-halt was specified.

416     if (! opt_haltOnUnsuccessfulStore)

417     {

418         cond = EC_Normal;

419     }

420 

421     /* return result value */

422     return cond;

423 }

424 

425 static OFBool

426 isaListMember(OFList<OFString>& lst, OFString& s)

427 {

428     OFListIterator(OFString) cur = lst.begin();

429     OFListIterator(OFString) end = lst.end();

430 

431     OFBool found = OFFalse;

432 

433     while (cur != end && !found) {

434 

435         found = (s == *cur);

436 

437         ++cur;

438     }

439 

440     return found;

441 }

442 

443 static OFCondition

444 addPresentationContext(T_ASC_Parameters *params,

445     int presentationContextId, const OFString& abstractSyntax,

446     const OFString& transferSyntax,

447     T_ASC_SC_ROLE proposedRole)

448 {

449     const char* c_p = transferSyntax.c_str();

450     OFCondition cond = ASC_addPresentationContext(params, presentationContextId,

451         abstractSyntax.c_str(), &c_p, 1, proposedRole);

452     return cond;

453 }

454 

455 static OFCondition

456 addPresentationContext(T_ASC_Parameters *params,

457     int presentationContextId, const OFString& abstractSyntax,

458     const OFList<OFString>& transferSyntaxList,

459     T_ASC_SC_ROLE proposedRole)

460 {

461     // create an array of supported/possible transfer syntaxes

462     const char** transferSyntaxes = new const char*[transferSyntaxList.size()];

463     int transferSyntaxCount = 0;

464     OFListConstIterator(OFString) s_cur = transferSyntaxList.begin();

465     OFListConstIterator(OFString) s_end = transferSyntaxList.end();

466     while (s_cur != s_end) {

467         transferSyntaxes[transferSyntaxCount++] = (*s_cur).c_str();

468         ++s_cur;

469     }

470 

471     OFCondition cond = ASC_addPresentationContext(params, presentationContextId,

472         abstractSyntax.c_str(), transferSyntaxes, transferSyntaxCount, proposedRole);

473 

474     delete[] transferSyntaxes;

475     return cond;

476 }

477 

478 static OFCondition

479 storeSCU(T_ASC_Association * assoc, const char *fname)

480     /*

481      * This function will read all the information from the given file,

482      * figure out a corresponding presentation context which will be used

483      * to transmit the information over the network to the SCP, and it

484      * will finally initiate the transmission of all data to the SCP.

485      *

486      * Parameters:

487      *   assoc - [in] The association (network connection to another DICOM application).

488      *   fname - [in] Name of the file which shall be processed.

489      */

490 {

491     DIC_US msgId = assoc->nextMsgID++;

492     T_ASC_PresentationContextID presId;

493     T_DIMSE_C_StoreRQ req;

494     T_DIMSE_C_StoreRSP rsp;

495     DIC_UI sopClass;

496     DIC_UI sopInstance;

497     DcmDataset *statusDetail = NULL;

498 

499     unsuccessfulStoreEncountered = OFTrue; // assumption

500 

501     if (opt_verbose) {

502         printf("--------------------------\n");

503         printf("Sending file: %s\n", fname);

504     }

505 

506     /* read information from file. After the call to DcmFileFormat::loadFile(...) the information */

507     /* which is encapsulated in the file will be available through the DcmFileFormat object. */

508     /* In detail, it will be available through calls to DcmFileFormat::getMetaInfo() (for */

509     /* meta header information) and DcmFileFormat::getDataset() (for data set information). */

510     DcmFileFormat dcmff;

511     OFCondition cond = dcmff.loadFile(fname);

512 

513     /* figure out if an error occured while the file was read*/

514     if (cond.bad()) {

515         //errmsg("Bad DICOM file: %s: %s", fname, cond.text());

516         return cond;

517     }

518 

519     /* if required, invent new SOP instance information for the current data set (user option) */

520     if (opt_inventSOPInstanceInformation) {

521         replaceSOPInstanceInformation(dcmff.getDataset());

522     }

523 

524     /* figure out which SOP class and SOP instance is encapsulated in the file */

525     if (!DU_findSOPClassAndInstanceInDataSet(dcmff.getDataset(),

526         sopClass, sopInstance, opt_correctUIDPadding)) {

527         //errmsg("No SOP Class & Instance UIDs in file: %s", fname);

528         return DIMSE_BADDATA;

529     }

530 

531     /* figure out which of the accepted presentation contexts should be used */

532     DcmXfer filexfer(dcmff.getDataset()->getOriginalXfer());//??????? added by HGB

533 

534     /* special case: if the file uses an unencapsulated transfer syntax (uncompressed

535      * or deflated explicit VR) and we prefer deflated explicit VR, then try

536      * to find a presentation context for deflated explicit VR first.

537      */

538     if (filexfer.isNotEncapsulated() &&

539         opt_networkTransferSyntax == EXS_DeflatedLittleEndianExplicit)

540     {

541         filexfer = EXS_DeflatedLittleEndianExplicit;

542     }

543 

544     if (filexfer.getXfer() != EXS_Unknown) presId = ASC_findAcceptedPresentationContextID(assoc, sopClass, filexfer.getXferID());

545     else presId = ASC_findAcceptedPresentationContextID(assoc, sopClass);

546     if (presId == 0) {

547         const char *modalityName = dcmSOPClassUIDToModality(sopClass);

548         if (!modalityName) modalityName = dcmFindNameOfUID(sopClass);

549         if (!modalityName) modalityName = "unknown SOP class";

550        // errmsg("No presentation context for: (%s) %s", modalityName, sopClass);

551         return DIMSE_NOVALIDPRESENTATIONCONTEXTID;

552     }

553 

554     /* if required, dump general information concerning transfer syntaxes */

555     if (opt_verbose) {

556         DcmXfer fileTransfer(dcmff.getDataset()->getOriginalXfer());

557         T_ASC_PresentationContext pc;

558         ASC_findAcceptedPresentationContext(assoc->params, presId, &pc);

559         DcmXfer netTransfer(pc.acceptedTransferSyntax);

560         printf("Transfer: %s -> %s\n",

561             dcmFindNameOfUID(fileTransfer.getXferID()), dcmFindNameOfUID(netTransfer.getXferID()));

562     }

563 

564     /* prepare the transmission of data */

565     bzero((char*)&req, sizeof(req));

566     req.MessageID = msgId;

567     strcpy(req.AffectedSOPClassUID, sopClass);

568     strcpy(req.AffectedSOPInstanceUID, sopInstance);

569     req.DataSetType = DIMSE_DATASET_PRESENT;

570     req.Priority = DIMSE_PRIORITY_LOW;

571 

572     /* if required, dump some more general information */

573     if (opt_verbose) {

574         printf("Store SCU RQ: MsgID %d, (%s)\n", msgId, dcmSOPClassUIDToModality(sopClass));

575     }

576 

577     /* finally conduct transmission of data */

578     cond = DIMSE_storeUser(assoc, presId, &req,

579         NULL, dcmff.getDataset(), progressCallback, NULL,

580         opt_blockMode, opt_dimse_timeout,

581         &rsp, &statusDetail, NULL, DU_fileSize(fname));

582 

583     /*

584      * If store command completed normally, with a status

585      * of success or some warning then the image was accepted.

586      */

587     if (cond == EC_Normal && (rsp.DimseStatus == STATUS_Success || DICOM_WARNING_STATUS(rsp.DimseStatus))) {

588         unsuccessfulStoreEncountered = OFFalse;

589     }

590 

591     /* remember the response's status for later transmissions of data */

592     lastStatusCode = rsp.DimseStatus;

593 

594     /* dump some more general information */

595     if (cond == EC_Normal)

596     {

597         if (opt_verbose) {

598             DIMSE_printCStoreRSP(stdout, &rsp);

599         }

600     }

601     else

602     {

603         //errmsg("Store Failed, file: %s:", fname);

604         DimseCondition::dump(cond);

605     }

606 

607     /* dump status detail information if there is some */

608     if (statusDetail != NULL) {

609         printf("  Status Detail:\n");

610         statusDetail->print(COUT);

611         delete statusDetail;

612     }

613     /* return */

614     return cond;

615 }

616 

617 static void

618 replaceSOPInstanceInformation(DcmDataset* dataset)

619 {

620     static OFCmdUnsignedInt patientCounter = 0;

621     static OFCmdUnsignedInt studyCounter = 0;

622     static OFCmdUnsignedInt seriesCounter = 0;

623     static OFCmdUnsignedInt imageCounter = 0;

624     static OFString seriesInstanceUID;

625     static OFString seriesNumber;

626     static OFString studyInstanceUID;

627     static OFString studyID;

628     static OFString accessionNumber;

629     static OFString patientID;

630     static OFString patientName;

631 

632     if (seriesInstanceUID.length() == 0) seriesInstanceUID=makeUID(SITE_SERIES_UID_ROOT, (int)seriesCounter);

633     if (seriesNumber.length() == 0) seriesNumber = intToString((int)seriesCounter);

634     if (studyInstanceUID.length() == 0) studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, (int)studyCounter);

635     if (studyID.length() == 0) studyID = studyIDPrefix + intToString((int)secondsSince1970()) + intToString((int)studyCounter);

636     if (accessionNumber.length() == 0) accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString((int)studyCounter);

637     if (patientID.length() == 0) patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);

638     if (patientName.length() == 0) patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);

639 

640     if (imageCounter >= opt_inventSeriesCount) {

641         imageCounter = 0;

642         seriesCounter++;

643         seriesInstanceUID = makeUID(SITE_SERIES_UID_ROOT, (int)seriesCounter);

644         seriesNumber = intToString((int)seriesCounter);

645     }

646     if (seriesCounter >= opt_inventStudyCount) {

647         seriesCounter = 0;

648         studyCounter++;

649         studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, (int)studyCounter);

650         studyID = studyIDPrefix + intToString(secondsSince1970()) + intToString((int)studyCounter);

651         accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString((int)studyCounter);

652     }

653     if (studyCounter >= opt_inventPatientCount) {

654         // we create as many patients as necessary */

655         studyCounter = 0;

656         patientCounter++;

657         patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);

658         patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString((int)patientCounter);

659     }

660 

661     OFString sopInstanceUID = makeUID(SITE_INSTANCE_UID_ROOT, (int)imageCounter);

662     OFString imageNumber = intToString((int)imageCounter);

663 

664     if (opt_verbose) {

665         COUT << "Inventing Identifying Information (" <<

666             "pa" << patientCounter << ", st" << studyCounter <<

667             ", se" << seriesCounter << ", im" << imageCounter << "): " << endl;

668         COUT << "  PatientName=" << patientName << endl;

669         COUT << "  PatientID=" << patientID << endl;

670         COUT << "  StudyInstanceUID=" << studyInstanceUID << endl;

671         COUT << "  StudyID=" << studyID << endl;

672         COUT << "  SeriesInstanceUID=" << seriesInstanceUID << endl;

673         COUT << "  SeriesNumber=" << seriesNumber << endl;

674         COUT << "  SOPInstanceUID=" << sopInstanceUID << endl;

675         COUT << "  ImageNumber=" << imageNumber << endl;

676     }

677 

678     updateStringAttributeValue(dataset, DCM_PatientsName, patientName);

679     updateStringAttributeValue(dataset, DCM_PatientID, patientID);

680     updateStringAttributeValue(dataset, DCM_StudyInstanceUID, studyInstanceUID);

681     updateStringAttributeValue(dataset, DCM_StudyID, studyID);

682     updateStringAttributeValue(dataset, DCM_SeriesInstanceUID, seriesInstanceUID);

683     updateStringAttributeValue(dataset, DCM_SeriesNumber, seriesNumber);

684     updateStringAttributeValue(dataset, DCM_SOPInstanceUID, sopInstanceUID);

685     updateStringAttributeValue(dataset, DCM_InstanceNumber, imageNumber);

686 

687     imageCounter++;

688 }

689 

690 static void

691 progressCallback(void * /*callbackData*/,

692     T_DIMSE_StoreProgress *progress,

693     T_DIMSE_C_StoreRQ * /*req*/)

694 {

695     if (opt_verbose) {

696         switch (progress->state) {

697         case DIMSE_StoreBegin:

698             printf("XMIT:"); break;

699         case DIMSE_StoreEnd:

700             printf("\n"); break;

701         default:

702             putchar('.'); break;

703         }

704         fflush(stdout);

705     }

706 }

707 

708 static OFString

709 makeUID(OFString basePrefix, int counter)

710 {

711     OFString prefix = basePrefix + "." + intToString(counter);

712     char uidbuf[65];

713     OFString uid = dcmGenerateUniqueIdentifier(uidbuf, prefix.c_str());

714     return uid;

715 }

716 

717 static int

718 secondsSince1970()

719 {

720     time_t t = time(NULL);

721     return (int)t;

722 }

723 

724 static OFString

725 intToString(int i)

726 {

727     char numbuf[32];

728     sprintf(numbuf, "%d", i);

729     return numbuf;

730 }

731 

732 static OFBool

733 updateStringAttributeValue(DcmItem* dataset, const DcmTagKey& key, OFString& value)

734 {

735     DcmStack stack;

736     DcmTag tag(key);

737 

738     OFCondition cond = EC_Normal;

739     cond = dataset->search(key, stack, ESM_fromHere, OFFalse);

740     if (cond != EC_Normal) {

741         CERR << "error: updateStringAttributeValue: cannot find: " << tag.getTagName()

742              << " " << key << ": "

743              << cond.text() << endl;

744         return OFFalse;

745     }

746 

747     DcmElement* elem = (DcmElement*) stack.top();

748 

749     DcmVR vr(elem->ident());

750     if (elem->getLength() > vr.getMaxValueLength()) {

751         CERR << "error: updateStringAttributeValue: INTERNAL ERROR: " << tag.getTagName()

752              << " " << key << ": value too large (max "

753             << vr.getMaxValueLength() << ") for " << vr.getVRName() << " value: " << value << endl;

754         return OFFalse;

755     }

756 

757     cond = elem->putOFStringArray(value);

758     if (cond != EC_Normal) {

759         CERR << "error: updateStringAttributeValue: cannot put string in attribute: " << tag.getTagName()

760              << " " << key << ": "

761              << cond.text() << endl;

762         return OFFalse;

763     }

764 

765     return OFTrue;

766 }

 

你可能感兴趣的:(store)