PageRenderTime 69ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/dcmtk-3.6.0/dcmnet/apps/movescu.cc

#
C++ | 1890 lines | 1260 code | 145 blank | 485 comment | 266 complexity | e7834f6b13bfd59ee25e5f22882b1c31 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0
  1. /*
  2. *
  3. * Copyright (C) 1994-2010, OFFIS e.V.
  4. * All rights reserved. See COPYRIGHT file for details.
  5. *
  6. * This software and supporting documentation were developed by
  7. *
  8. * OFFIS e.V.
  9. * R&D Division Health
  10. * Escherweg 2
  11. * D-26121 Oldenburg, Germany
  12. *
  13. *
  14. * Module: dcmnet
  15. *
  16. * Author: Andrew Hewett
  17. *
  18. * Purpose: Query/Retrieve Service Class User (C-MOVE operation)
  19. *
  20. * Last Update: $Author: uli $
  21. * Update Date: $Date: 2010-11-17 13:01:21 $
  22. * CVS/RCS Revision: $Revision: 1.88 $
  23. * Status: $State: Exp $
  24. *
  25. * CVS/RCS Log at end of file
  26. *
  27. */
  28. #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
  29. #define INCLUDE_CSTDLIB
  30. #define INCLUDE_CSTDIO
  31. #define INCLUDE_CSTRING
  32. #define INCLUDE_CSTDARG
  33. #define INCLUDE_CERRNO
  34. #include "dcmtk/ofstd/ofstdinc.h"
  35. #ifdef HAVE_GUSI_H
  36. #include <GUSI.h>
  37. #endif
  38. #include "dcmtk/ofstd/ofstd.h"
  39. #include "dcmtk/ofstd/ofconapp.h"
  40. #include "dcmtk/dcmnet/dicom.h"
  41. #include "dcmtk/dcmnet/dimse.h"
  42. #include "dcmtk/dcmnet/diutil.h"
  43. #include "dcmtk/dcmdata/dcfilefo.h"
  44. #include "dcmtk/dcmdata/dcuid.h"
  45. #include "dcmtk/dcmdata/dcdict.h"
  46. #include "dcmtk/dcmdata/cmdlnarg.h"
  47. #include "dcmtk/dcmdata/dcdeftag.h"
  48. #include "dcmtk/dcmdata/dcmetinf.h"
  49. #include "dcmtk/dcmdata/dcuid.h" /* for dcmtk version name */
  50. #include "dcmtk/dcmdata/dcdicent.h"
  51. #include "dcmtk/dcmdata/dcostrmz.h" /* for dcmZlibCompressionLevel */
  52. #ifdef WITH_ZLIB
  53. #include <zlib.h> /* for zlibVersion() */
  54. #endif
  55. #define OFFIS_CONSOLE_APPLICATION "movescu"
  56. static OFLogger movescuLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION);
  57. static char rcsid[] = "$dcmtk: " OFFIS_CONSOLE_APPLICATION " v"
  58. OFFIS_DCMTK_VERSION " " OFFIS_DCMTK_RELEASEDATE " $";
  59. /* default application titles */
  60. #define APPLICATIONTITLE "MOVESCU"
  61. #define PEERAPPLICATIONTITLE "ANY-SCP"
  62. typedef enum {
  63. QMPatientRoot = 0,
  64. QMStudyRoot = 1,
  65. QMPatientStudyOnly = 2
  66. } QueryModel;
  67. typedef struct {
  68. const char *findSyntax;
  69. const char *moveSyntax;
  70. } QuerySyntax;
  71. typedef struct {
  72. T_ASC_Association *assoc;
  73. T_ASC_PresentationContextID presId;
  74. } MyCallbackInfo;
  75. OFCmdUnsignedInt opt_sleepAfter = 0;
  76. OFCmdUnsignedInt opt_sleepDuring = 0;
  77. OFCmdUnsignedInt opt_maxPDU = ASC_DEFAULTMAXPDU;
  78. OFBool opt_useMetaheader = OFTrue;
  79. OFBool opt_acceptAllXfers = OFFalse;
  80. E_TransferSyntax opt_networkTransferSyntax = EXS_Unknown;
  81. E_TransferSyntax opt_writeTransferSyntax = EXS_Unknown;
  82. E_GrpLenEncoding opt_groupLength = EGL_recalcGL;
  83. E_EncodingType opt_sequenceType = EET_ExplicitLength;
  84. E_PaddingEncoding opt_paddingType = EPD_withoutPadding;
  85. OFCmdUnsignedInt opt_filepad = 0;
  86. OFCmdUnsignedInt opt_itempad = 0;
  87. OFCmdUnsignedInt opt_compressionLevel = 0;
  88. OFBool opt_bitPreserving = OFFalse;
  89. OFBool opt_ignore = OFFalse;
  90. OFBool opt_abortDuringStore = OFFalse;
  91. OFBool opt_abortAfterStore = OFFalse;
  92. OFBool opt_correctUIDPadding = OFFalse;
  93. OFCmdUnsignedInt opt_repeatCount = 1;
  94. OFCmdUnsignedInt opt_retrievePort = 0;
  95. E_TransferSyntax opt_in_networkTransferSyntax = EXS_Unknown;
  96. E_TransferSyntax opt_out_networkTransferSyntax = EXS_Unknown;
  97. OFBool opt_abortAssociation = OFFalse;
  98. const char * opt_moveDestination = NULL;
  99. OFCmdSignedInt opt_cancelAfterNResponses = -1;
  100. QueryModel opt_queryModel = QMPatientRoot;
  101. T_DIMSE_BlockingMode opt_blockMode = DIMSE_BLOCKING;
  102. int opt_dimse_timeout = 0;
  103. int opt_acse_timeout = 30;
  104. OFBool opt_ignorePendingDatasets = OFTrue;
  105. OFString opt_outputDirectory = ".";
  106. static T_ASC_Network *net = NULL; /* the global DICOM network */
  107. static DcmDataset *overrideKeys = NULL;
  108. static QuerySyntax querySyntax[3] = {
  109. { UID_FINDPatientRootQueryRetrieveInformationModel,
  110. UID_MOVEPatientRootQueryRetrieveInformationModel },
  111. { UID_FINDStudyRootQueryRetrieveInformationModel,
  112. UID_MOVEStudyRootQueryRetrieveInformationModel },
  113. { UID_RETIRED_FINDPatientStudyOnlyQueryRetrieveInformationModel,
  114. UID_RETIRED_MOVEPatientStudyOnlyQueryRetrieveInformationModel }
  115. };
  116. static void
  117. addOverrideKey(OFConsoleApplication& app, const char* s)
  118. {
  119. unsigned int g = 0xffff;
  120. unsigned int e = 0xffff;
  121. int n = 0;
  122. OFString dicName, valStr;
  123. OFString msg;
  124. char msg2[200];
  125. // try to parse group and element number
  126. n = sscanf(s, "%x,%x=", &g, &e);
  127. OFString toParse = s;
  128. size_t eqPos = toParse.find('=');
  129. if (n < 2) // if at least no tag could be parsed
  130. {
  131. // if value is given, extract it (and extrect dictname)
  132. if (eqPos != OFString_npos)
  133. {
  134. dicName = toParse.substr(0,eqPos).c_str();
  135. valStr = toParse.substr(eqPos+1,toParse.length());
  136. }
  137. else // no value given, just dictionary name
  138. dicName = s; // only dictionary name given (without value)
  139. // try to lookup in dictionary
  140. DcmTagKey key(0xffff,0xffff);
  141. const DcmDataDictionary& globalDataDict = dcmDataDict.rdlock();
  142. const DcmDictEntry *dicent = globalDataDict.findEntry(dicName.c_str());
  143. dcmDataDict.unlock();
  144. if (dicent!=NULL) {
  145. // found dictionary name, copy group and element number
  146. key = dicent->getKey();
  147. g = key.getGroup();
  148. e = key.getElement();
  149. }
  150. else {
  151. // not found in dictionary
  152. msg = "bad key format or dictionary name not found in dictionary: ";
  153. msg += dicName;
  154. app.printError(msg.c_str());
  155. }
  156. } // tag could be parsed, copy value if it exists
  157. else
  158. {
  159. if (eqPos != OFString_npos)
  160. valStr = toParse.substr(eqPos+1,toParse.length());
  161. }
  162. DcmTag tag(g,e);
  163. if (tag.error() != EC_Normal) {
  164. sprintf(msg2, "unknown tag: (%04x,%04x)", g, e);
  165. app.printError(msg2);
  166. }
  167. DcmElement *elem = newDicomElement(tag);
  168. if (elem == NULL) {
  169. sprintf(msg2, "cannot create element for tag: (%04x,%04x)", g, e);
  170. app.printError(msg2);
  171. }
  172. if (valStr.length() > 0) {
  173. if (elem->putString(valStr.c_str()).bad())
  174. {
  175. sprintf(msg2, "cannot put tag value: (%04x,%04x)=\"", g, e);
  176. msg = msg2;
  177. msg += valStr;
  178. msg += "\"";
  179. app.printError(msg.c_str());
  180. }
  181. }
  182. if (overrideKeys == NULL) overrideKeys = new DcmDataset;
  183. if (overrideKeys->insert(elem, OFTrue).bad()) {
  184. sprintf(msg2, "cannot insert tag: (%04x,%04x)", g, e);
  185. app.printError(msg2);
  186. }
  187. }
  188. static OFCondition cmove(T_ASC_Association *assoc, const char *fname);
  189. static OFCondition
  190. addPresentationContext(T_ASC_Parameters *params,
  191. T_ASC_PresentationContextID pid,
  192. const char* abstractSyntax);
  193. #define SHORTCOL 4
  194. #define LONGCOL 21
  195. int
  196. main(int argc, char *argv[])
  197. {
  198. T_ASC_Parameters *params = NULL;
  199. const char *opt_peer;
  200. OFCmdUnsignedInt opt_port = 104;
  201. DIC_NODENAME localHost;
  202. DIC_NODENAME peerHost;
  203. T_ASC_Association *assoc = NULL;
  204. const char *opt_peerTitle = PEERAPPLICATIONTITLE;
  205. const char *opt_ourTitle = APPLICATIONTITLE;
  206. OFList<OFString> fileNameList;
  207. #ifdef HAVE_GUSI_H
  208. /* needed for Macintosh */
  209. GUSISetup(GUSIwithSIOUXSockets);
  210. GUSISetup(GUSIwithInternetSockets);
  211. #endif
  212. #ifdef HAVE_WINSOCK_H
  213. WSAData winSockData;
  214. /* we need at least version 1.1 */
  215. WORD winSockVersionNeeded = MAKEWORD( 1, 1 );
  216. WSAStartup(winSockVersionNeeded, &winSockData);
  217. #endif
  218. char tempstr[20];
  219. OFString temp_str;
  220. OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION , "DICOM retrieve (C-MOVE) SCU", rcsid);
  221. OFCommandLine cmd;
  222. cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
  223. cmd.addParam("peer", "hostname of DICOM peer");
  224. cmd.addParam("port", "tcp/ip port number of peer");
  225. cmd.addParam("dcmfile-in", "DICOM query file(s)", OFCmdParam::PM_MultiOptional);
  226. cmd.setOptionColumns(LONGCOL, SHORTCOL);
  227. cmd.addGroup("general options:", LONGCOL, SHORTCOL + 2);
  228. cmd.addOption("--help", "-h", "print this help text and exit", OFCommandLine::AF_Exclusive);
  229. cmd.addOption("--version", "print version information and exit", OFCommandLine::AF_Exclusive);
  230. OFLog::addOptions(cmd);
  231. cmd.addGroup("network options:");
  232. cmd.addSubGroup("override matching keys:");
  233. cmd.addOption("--key", "-k", 1, "[k]ey: gggg,eeee=\"str\" or dict. name=\"str\"",
  234. "override matching key");
  235. cmd.addSubGroup("query information model:");
  236. cmd.addOption("--patient", "-P", "use patient root information model (default)");
  237. cmd.addOption("--study", "-S", "use study root information model");
  238. cmd.addOption("--psonly", "-O", "use patient/study only information model");
  239. cmd.addSubGroup("application entity titles:");
  240. OFString opt1 = "set my calling AE title (default: ";
  241. opt1 += APPLICATIONTITLE;
  242. opt1 += ")";
  243. cmd.addOption("--aetitle", "-aet", 1, "[a]etitle: string", opt1.c_str());
  244. OFString opt2 = "set called AE title of peer (default: ";
  245. opt2 += PEERAPPLICATIONTITLE;
  246. opt2 += ")";
  247. cmd.addOption("--call", "-aec", 1, "[a]etitle: string", opt2.c_str());
  248. OFString opt5 = "set move destinat. AE title (default: ";
  249. opt5 += APPLICATIONTITLE;
  250. opt5 += ")";
  251. cmd.addOption("--move", "-aem", 1, "[a]etitle: string", opt5.c_str());
  252. cmd.addSubGroup("preferred network transfer syntaxes (incoming associations):");
  253. cmd.addOption("--prefer-uncompr", "+x=", "prefer explicit VR local byte order (default)");
  254. cmd.addOption("--prefer-little", "+xe", "prefer explicit VR little endian TS");
  255. cmd.addOption("--prefer-big", "+xb", "prefer explicit VR big endian TS");
  256. cmd.addOption("--prefer-lossless", "+xs", "prefer default JPEG lossless TS");
  257. cmd.addOption("--prefer-jpeg8", "+xy", "prefer default JPEG lossy TS for 8 bit data");
  258. cmd.addOption("--prefer-jpeg12", "+xx", "prefer default JPEG lossy TS for 12 bit data");
  259. cmd.addOption("--prefer-j2k-lossless", "+xv", "prefer JPEG 2000 lossless TS");
  260. cmd.addOption("--prefer-j2k-lossy", "+xw", "prefer JPEG 2000 lossy TS");
  261. cmd.addOption("--prefer-jls-lossless", "+xt", "prefer JPEG-LS lossless TS");
  262. cmd.addOption("--prefer-jls-lossy", "+xu", "prefer JPEG-LS lossy TS");
  263. cmd.addOption("--prefer-mpeg2", "+xm", "prefer MPEG2 Main Profile @ Main Level TS");
  264. cmd.addOption("--prefer-mpeg2-high", "+xh", "prefer MPEG2 Main Profile @ High Level TS");
  265. cmd.addOption("--prefer-rle", "+xr", "prefer RLE lossless TS");
  266. #ifdef WITH_ZLIB
  267. cmd.addOption("--prefer-deflated", "+xd", "prefer deflated expl. VR little endian TS");
  268. #endif
  269. cmd.addOption("--implicit", "+xi", "accept implicit VR little endian TS only");
  270. cmd.addOption("--accept-all", "+xa", "accept all supported transfer syntaxes");
  271. cmd.addSubGroup("proposed transmission transfer syntaxes (outgoing associations):");
  272. cmd.addOption("--propose-uncompr", "-x=", "propose all uncompressed TS, explicit VR\nwith local byte ordering first (default)");
  273. cmd.addOption("--propose-little", "-xe", "propose all uncompressed TS, explicit VR\nlittle endian first");
  274. cmd.addOption("--propose-big", "-xb", "propose all uncompressed TS, explicit VR\nbig endian first");
  275. cmd.addOption("--propose-implicit", "-xi", "propose implicit VR little endian TS only");
  276. #ifdef WITH_TCPWRAPPER
  277. cmd.addSubGroup("network host access control (tcp wrapper):");
  278. cmd.addOption("--access-full", "-ac", "accept connections from any host (default)");
  279. cmd.addOption("--access-control", "+ac", "enforce host access control rules");
  280. #endif
  281. cmd.addSubGroup("port for incoming network associations:");
  282. cmd.addOption("--no-port", "no port for incoming associations (default)");
  283. cmd.addOption("--port", "+P", 1, "[n]umber: integer",
  284. "port number for incoming associations");
  285. cmd.addSubGroup("handling of illegal datasets following 'pending' move responses:");
  286. cmd.addOption("--pending-ignore", "-pi", "assume no dataset present (default)");
  287. cmd.addOption("--pending-read", "-pr", "read and ignore dataset");
  288. cmd.addSubGroup("other network options:");
  289. cmd.addOption("--timeout", "-to", 1, "[s]econds: integer (default: unlimited)", "timeout for connection requests");
  290. cmd.addOption("--acse-timeout", "-ta", 1, "[s]econds: integer (default: 30)", "timeout for ACSE messages");
  291. cmd.addOption("--dimse-timeout", "-td", 1, "[s]econds: integer (default: unlimited)", "timeout for DIMSE messages");
  292. OFString opt3 = "set max receive pdu to n bytes (default: ";
  293. sprintf(tempstr, "%ld", OFstatic_cast(long, ASC_DEFAULTMAXPDU));
  294. opt3 += tempstr;
  295. opt3 += ")";
  296. OFString opt4 = "[n]umber of bytes: integer (";
  297. sprintf(tempstr, "%ld", OFstatic_cast(long, ASC_MINIMUMPDUSIZE));
  298. opt4 += tempstr;
  299. opt4 += "..";
  300. sprintf(tempstr, "%ld", OFstatic_cast(long, ASC_MAXIMUMPDUSIZE));
  301. opt4 += tempstr;
  302. opt4 += ")";
  303. cmd.addOption("--max-pdu", "-pdu", 1, opt4.c_str(), opt3.c_str());
  304. cmd.addOption("--disable-host-lookup", "-dhl", "disable hostname lookup");
  305. cmd.addOption("--repeat", 1, "[n]umber: integer", "repeat n times");
  306. cmd.addOption("--abort", "abort association instead of releasing it");
  307. cmd.addOption("--ignore", "ignore store data, receive but do not store");
  308. cmd.addOption("--cancel", 1, "[n]umber: integer",
  309. "cancel after n responses (default: never)");
  310. cmd.addOption("--uid-padding", "-up", "silently correct space-padded UIDs");
  311. cmd.addGroup("output options:");
  312. cmd.addSubGroup("general:");
  313. cmd.addOption("--output-directory", "-od", 1, "[d]irectory: string (default: \".\")", "write received objects to existing directory d");
  314. cmd.addSubGroup("bit preserving mode:");
  315. cmd.addOption("--normal", "-B", "allow implicit format conversions (default)");
  316. cmd.addOption("--bit-preserving", "+B", "write data exactly as read");
  317. cmd.addSubGroup("output file format:");
  318. cmd.addOption("--write-file", "+F", "write file format (default)");
  319. cmd.addOption("--write-dataset", "-F", "write data set without file meta information");
  320. cmd.addSubGroup("output transfer syntax (not with --bit-preserving or compressed transmission):");
  321. cmd.addOption("--write-xfer-same", "+t=", "write with same TS as input (default)");
  322. cmd.addOption("--write-xfer-little", "+te", "write with explicit VR little endian TS");
  323. cmd.addOption("--write-xfer-big", "+tb", "write with explicit VR big endian TS");
  324. cmd.addOption("--write-xfer-implicit", "+ti", "write with implicit VR little endian TS");
  325. #ifdef WITH_ZLIB
  326. cmd.addOption("--write-xfer-deflated", "+td", "write with deflated expl. VR little endian TS");
  327. #endif
  328. cmd.addSubGroup("post-1993 value representations (not with --bit-preserving):");
  329. cmd.addOption("--enable-new-vr", "+u", "enable support for new VRs (UN/UT) (default)");
  330. cmd.addOption("--disable-new-vr", "-u", "disable support for new VRs, convert to OB");
  331. cmd.addSubGroup("group length encoding (not with --bit-preserving):");
  332. cmd.addOption("--group-length-recalc", "+g=", "recalculate group lengths if present (default)");
  333. cmd.addOption("--group-length-create", "+g", "always write with group length elements");
  334. cmd.addOption("--group-length-remove", "-g", "always write without group length elements");
  335. cmd.addSubGroup("length encoding in sequences and items (not with --bit-preserving):");
  336. cmd.addOption("--length-explicit", "+e", "write with explicit lengths (default)");
  337. cmd.addOption("--length-undefined", "-e", "write with undefined lengths");
  338. cmd.addSubGroup("data set trailing padding (not with --write-dataset or --bit-preserving):");
  339. cmd.addOption("--padding-off", "-p", "no padding (default)");
  340. cmd.addOption("--padding-create", "+p", 2, "[f]ile-pad [i]tem-pad: integer",
  341. "align file on multiple of f bytes\nand items on multiple of i bytes");
  342. #ifdef WITH_ZLIB
  343. cmd.addSubGroup("deflate compression level (only with --write-xfer-deflated/same):");
  344. cmd.addOption("--compression-level", "+cl", 1, "[l]evel: integer (default: 6)",
  345. "0=uncompressed, 1=fastest, 9=best compression");
  346. #endif
  347. /* evaluate command line */
  348. prepareCmdLineArgs(argc, argv, OFFIS_CONSOLE_APPLICATION);
  349. if (app.parseCommandLine(cmd, argc, argv, OFCommandLine::PF_ExpandWildcards))
  350. {
  351. /* check exclusive options first */
  352. if (cmd.hasExclusiveOption())
  353. {
  354. if (cmd.findOption("--version"))
  355. {
  356. app.printHeader(OFTrue /*print host identifier*/);
  357. COUT << OFendl << "External libraries used:";
  358. #if !defined(WITH_ZLIB) && !defined(WITH_TCPWRAPPER)
  359. COUT << " none" << OFendl;
  360. #else
  361. COUT << OFendl;
  362. #endif
  363. #ifdef WITH_ZLIB
  364. COUT << "- ZLIB, Version " << zlibVersion() << OFendl;
  365. #endif
  366. #ifdef WITH_TCPWRAPPER
  367. COUT << "- LIBWRAP" << OFendl;
  368. #endif
  369. return 0;
  370. }
  371. }
  372. /* command line parameters */
  373. cmd.getParam(1, opt_peer);
  374. app.checkParam(cmd.getParamAndCheckMinMax(2, opt_port, 1, 65535));
  375. OFLog::configureFromCommandLine(cmd, app);
  376. if (cmd.findOption("--key", 0, OFCommandLine::FOM_First))
  377. {
  378. const char *ovKey = NULL;
  379. do {
  380. app.checkValue(cmd.getValue(ovKey));
  381. addOverrideKey(app, ovKey);
  382. } while (cmd.findOption("--key", 0, OFCommandLine::FOM_Next));
  383. }
  384. cmd.beginOptionBlock();
  385. if (cmd.findOption("--patient")) opt_queryModel = QMPatientRoot;
  386. if (cmd.findOption("--study")) opt_queryModel = QMStudyRoot;
  387. if (cmd.findOption("--psonly")) opt_queryModel = QMPatientStudyOnly;
  388. cmd.endOptionBlock();
  389. if (cmd.findOption("--aetitle")) app.checkValue(cmd.getValue(opt_ourTitle));
  390. if (cmd.findOption("--call")) app.checkValue(cmd.getValue(opt_peerTitle));
  391. if (cmd.findOption("--move")) app.checkValue(cmd.getValue(opt_moveDestination));
  392. cmd.beginOptionBlock();
  393. if (cmd.findOption("--prefer-uncompr"))
  394. {
  395. opt_acceptAllXfers = OFFalse;
  396. opt_in_networkTransferSyntax = EXS_Unknown;
  397. }
  398. if (cmd.findOption("--prefer-little")) opt_in_networkTransferSyntax = EXS_LittleEndianExplicit;
  399. if (cmd.findOption("--prefer-big")) opt_in_networkTransferSyntax = EXS_BigEndianExplicit;
  400. if (cmd.findOption("--prefer-lossless")) opt_in_networkTransferSyntax = EXS_JPEGProcess14SV1TransferSyntax;
  401. if (cmd.findOption("--prefer-jpeg8")) opt_in_networkTransferSyntax = EXS_JPEGProcess1TransferSyntax;
  402. if (cmd.findOption("--prefer-jpeg12")) opt_in_networkTransferSyntax = EXS_JPEGProcess2_4TransferSyntax;
  403. if (cmd.findOption("--prefer-j2k-lossless")) opt_in_networkTransferSyntax = EXS_JPEG2000LosslessOnly;
  404. if (cmd.findOption("--prefer-j2k-lossy")) opt_in_networkTransferSyntax = EXS_JPEG2000;
  405. if (cmd.findOption("--prefer-jls-lossless")) opt_networkTransferSyntax = EXS_JPEGLSLossless;
  406. if (cmd.findOption("--prefer-jls-lossy")) opt_networkTransferSyntax = EXS_JPEGLSLossy;
  407. if (cmd.findOption("--prefer-mpeg2")) opt_networkTransferSyntax = EXS_MPEG2MainProfileAtMainLevel;
  408. if (cmd.findOption("--prefer-mpeg2-high")) opt_networkTransferSyntax = EXS_MPEG2MainProfileAtHighLevel;
  409. if (cmd.findOption("--prefer-rle")) opt_in_networkTransferSyntax = EXS_RLELossless;
  410. #ifdef WITH_ZLIB
  411. if (cmd.findOption("--prefer-deflated")) opt_networkTransferSyntax = EXS_DeflatedLittleEndianExplicit;
  412. #endif
  413. if (cmd.findOption("--implicit")) opt_in_networkTransferSyntax = EXS_LittleEndianImplicit;
  414. if (cmd.findOption("--accept-all"))
  415. {
  416. opt_acceptAllXfers = OFTrue;
  417. opt_networkTransferSyntax = EXS_Unknown;
  418. }
  419. cmd.endOptionBlock();
  420. if (opt_in_networkTransferSyntax != EXS_Unknown) opt_acceptAllXfers = OFFalse;
  421. cmd.beginOptionBlock();
  422. if (cmd.findOption("--propose-uncompr")) opt_out_networkTransferSyntax = EXS_Unknown;
  423. if (cmd.findOption("--propose-little")) opt_out_networkTransferSyntax = EXS_LittleEndianExplicit;
  424. if (cmd.findOption("--propose-big")) opt_out_networkTransferSyntax = EXS_BigEndianExplicit;
  425. if (cmd.findOption("--propose-implicit")) opt_out_networkTransferSyntax = EXS_LittleEndianImplicit;
  426. cmd.endOptionBlock();
  427. #ifdef WITH_TCPWRAPPER
  428. cmd.beginOptionBlock();
  429. if (cmd.findOption("--access-full")) dcmTCPWrapperDaemonName.set(NULL);
  430. if (cmd.findOption("--access-control")) dcmTCPWrapperDaemonName.set(OFFIS_CONSOLE_APPLICATION);
  431. cmd.endOptionBlock();
  432. #endif
  433. if (cmd.findOption("--timeout"))
  434. {
  435. OFCmdSignedInt opt_timeout = 0;
  436. app.checkValue(cmd.getValueAndCheckMin(opt_timeout, 1));
  437. dcmConnectionTimeout.set(OFstatic_cast(Sint32, opt_timeout));
  438. }
  439. if (cmd.findOption("--acse-timeout"))
  440. {
  441. OFCmdSignedInt opt_timeout = 0;
  442. app.checkValue(cmd.getValueAndCheckMin(opt_timeout, 1));
  443. opt_acse_timeout = OFstatic_cast(int, opt_timeout);
  444. }
  445. if (cmd.findOption("--dimse-timeout"))
  446. {
  447. OFCmdSignedInt opt_timeout = 0;
  448. app.checkValue(cmd.getValueAndCheckMin(opt_timeout, 1));
  449. opt_dimse_timeout = OFstatic_cast(int, opt_timeout);
  450. opt_blockMode = DIMSE_NONBLOCKING;
  451. }
  452. cmd.beginOptionBlock();
  453. if (cmd.findOption("--port")) app.checkValue(cmd.getValueAndCheckMinMax(opt_retrievePort, 1, 65535));
  454. if (cmd.findOption("--no-port")) { /* do nothing */ }
  455. cmd.endOptionBlock();
  456. cmd.beginOptionBlock();
  457. if (cmd.findOption("--pending-ignore")) opt_ignorePendingDatasets = OFTrue;
  458. if (cmd.findOption("--pending-read")) opt_ignorePendingDatasets = OFFalse;
  459. cmd.endOptionBlock();
  460. if (cmd.findOption("--max-pdu")) app.checkValue(cmd.getValueAndCheckMinMax(opt_maxPDU, ASC_MINIMUMPDUSIZE, ASC_MAXIMUMPDUSIZE));
  461. if (cmd.findOption("--disable-host-lookup")) dcmDisableGethostbyaddr.set(OFTrue);
  462. if (cmd.findOption("--repeat")) app.checkValue(cmd.getValueAndCheckMin(opt_repeatCount, 1));
  463. if (cmd.findOption("--abort")) opt_abortAssociation = OFTrue;
  464. if (cmd.findOption("--ignore")) opt_ignore = OFTrue;
  465. if (cmd.findOption("--cancel")) app.checkValue(cmd.getValueAndCheckMin(opt_cancelAfterNResponses, 0));
  466. if (cmd.findOption("--uid-padding")) opt_correctUIDPadding = OFTrue;
  467. if (cmd.findOption("--output-directory")) app.checkValue(cmd.getValue(opt_outputDirectory));
  468. cmd.beginOptionBlock();
  469. if (cmd.findOption("--normal")) opt_bitPreserving = OFFalse;
  470. if (cmd.findOption("--bit-preserving")) opt_bitPreserving = OFTrue;
  471. cmd.endOptionBlock();
  472. cmd.beginOptionBlock();
  473. if (cmd.findOption("--write-file")) opt_useMetaheader = OFTrue;
  474. if (cmd.findOption("--write-dataset")) opt_useMetaheader = OFFalse;
  475. cmd.endOptionBlock();
  476. cmd.beginOptionBlock();
  477. if (cmd.findOption("--write-xfer-same")) opt_writeTransferSyntax = EXS_Unknown;
  478. if (cmd.findOption("--write-xfer-little"))
  479. {
  480. app.checkConflict("--write-xfer-little", "--accept-all", opt_acceptAllXfers);
  481. app.checkConflict("--write-xfer-little", "--bit-preserving", opt_bitPreserving);
  482. app.checkConflict("--write-xfer-little", "--prefer-lossless", opt_networkTransferSyntax==EXS_JPEGProcess14SV1TransferSyntax);
  483. app.checkConflict("--write-xfer-little", "--prefer-jpeg8", opt_networkTransferSyntax==EXS_JPEGProcess1TransferSyntax);
  484. app.checkConflict("--write-xfer-little", "--prefer-jpeg12", opt_networkTransferSyntax==EXS_JPEGProcess2_4TransferSyntax);
  485. app.checkConflict("--write-xfer-little", "--prefer-j2k-lossless", opt_networkTransferSyntax==EXS_JPEG2000LosslessOnly);
  486. app.checkConflict("--write-xfer-little", "--prefer-j2k-lossy", opt_networkTransferSyntax==EXS_JPEG2000);
  487. app.checkConflict("--write-xfer-little", "--prefer-jls-lossless", opt_networkTransferSyntax == EXS_JPEGLSLossless);
  488. app.checkConflict("--write-xfer-little", "--prefer-jls-lossy", opt_networkTransferSyntax == EXS_JPEGLSLossy);
  489. app.checkConflict("--write-xfer-little", "--prefer-mpeg2", opt_networkTransferSyntax == EXS_MPEG2MainProfileAtMainLevel);
  490. app.checkConflict("--write-xfer-little", "--prefer-mpeg2-high", opt_networkTransferSyntax == EXS_MPEG2MainProfileAtHighLevel);
  491. app.checkConflict("--write-xfer-little", "--prefer-rle", opt_networkTransferSyntax==EXS_RLELossless);
  492. // we don't have to check a conflict for --prefer-deflated because we can always convert that to uncompressed.
  493. opt_writeTransferSyntax = EXS_LittleEndianExplicit;
  494. }
  495. if (cmd.findOption("--write-xfer-big"))
  496. {
  497. app.checkConflict("--write-xfer-big", "--accept-all", opt_acceptAllXfers);
  498. app.checkConflict("--write-xfer-big", "--bit-preserving", opt_bitPreserving);
  499. app.checkConflict("--write-xfer-big", "--prefer-lossless", opt_networkTransferSyntax==EXS_JPEGProcess14SV1TransferSyntax);
  500. app.checkConflict("--write-xfer-big", "--prefer-jpeg8", opt_networkTransferSyntax==EXS_JPEGProcess1TransferSyntax);
  501. app.checkConflict("--write-xfer-big", "--prefer-jpeg12", opt_networkTransferSyntax==EXS_JPEGProcess2_4TransferSyntax);
  502. app.checkConflict("--write-xfer-big", "--prefer-j2k-lossy", opt_networkTransferSyntax==EXS_JPEG2000);
  503. app.checkConflict("--write-xfer-big", "--prefer-j2k-lossless", opt_networkTransferSyntax==EXS_JPEG2000LosslessOnly);
  504. app.checkConflict("--write-xfer-big", "--prefer-jls-lossless", opt_networkTransferSyntax == EXS_JPEGLSLossless);
  505. app.checkConflict("--write-xfer-big", "--prefer-jls-lossy", opt_networkTransferSyntax == EXS_JPEGLSLossy);
  506. app.checkConflict("--write-xfer-big", "--prefer-mpeg2", opt_networkTransferSyntax == EXS_MPEG2MainProfileAtMainLevel);
  507. app.checkConflict("--write-xfer-big", "--prefer-mpeg2-high", opt_networkTransferSyntax == EXS_MPEG2MainProfileAtHighLevel);
  508. app.checkConflict("--write-xfer-big", "--prefer-rle", opt_networkTransferSyntax==EXS_RLELossless);
  509. // we don't have to check a conflict for --prefer-deflated because we can always convert that to uncompressed.
  510. opt_writeTransferSyntax = EXS_BigEndianExplicit;
  511. }
  512. if (cmd.findOption("--write-xfer-implicit"))
  513. {
  514. app.checkConflict("--write-xfer-implicit", "--accept-all", opt_acceptAllXfers);
  515. app.checkConflict("--write-xfer-implicit", "--bit-preserving", opt_bitPreserving);
  516. app.checkConflict("--write-xfer-implicit", "--prefer-lossless", opt_networkTransferSyntax==EXS_JPEGProcess14SV1TransferSyntax);
  517. app.checkConflict("--write-xfer-implicit", "--prefer-jpeg8", opt_networkTransferSyntax==EXS_JPEGProcess1TransferSyntax);
  518. app.checkConflict("--write-xfer-implicit", "--prefer-jpeg12", opt_networkTransferSyntax==EXS_JPEGProcess2_4TransferSyntax);
  519. app.checkConflict("--write-xfer-implicit", "--prefer-j2k-lossy", opt_networkTransferSyntax==EXS_JPEG2000);
  520. app.checkConflict("--write-xfer-implicit", "--prefer-j2k-lossless", opt_networkTransferSyntax==EXS_JPEG2000LosslessOnly);
  521. app.checkConflict("--write-xfer-implicit", "--prefer-jls-lossless", opt_networkTransferSyntax == EXS_JPEGLSLossless);
  522. app.checkConflict("--write-xfer-implicit", "--prefer-jls-lossy", opt_networkTransferSyntax == EXS_JPEGLSLossy);
  523. app.checkConflict("--write-xfer-implicit", "--prefer-mpeg2", opt_networkTransferSyntax == EXS_MPEG2MainProfileAtMainLevel);
  524. app.checkConflict("--write-xfer-implicit", "--prefer-mpeg2-high", opt_networkTransferSyntax == EXS_MPEG2MainProfileAtHighLevel);
  525. app.checkConflict("--write-xfer-implicit", "--prefer-rle", opt_networkTransferSyntax==EXS_RLELossless);
  526. // we don't have to check a conflict for --prefer-deflated because we can always convert that to uncompressed.
  527. opt_writeTransferSyntax = EXS_LittleEndianImplicit;
  528. }
  529. #ifdef WITH_ZLIB
  530. if (cmd.findOption("--write-xfer-deflated"))
  531. {
  532. app.checkConflict("--write-xfer-deflated", "--accept-all", opt_acceptAllXfers);
  533. app.checkConflict("--write-xfer-deflated", "--bit-preserving", opt_bitPreserving);
  534. app.checkConflict("--write-xfer-deflated", "--prefer-lossless", opt_networkTransferSyntax == EXS_JPEGProcess14SV1TransferSyntax);
  535. app.checkConflict("--write-xfer-deflated", "--prefer-jpeg8", opt_networkTransferSyntax == EXS_JPEGProcess1TransferSyntax);
  536. app.checkConflict("--write-xfer-deflated", "--prefer-jpeg12", opt_networkTransferSyntax == EXS_JPEGProcess2_4TransferSyntax);
  537. app.checkConflict("--write-xfer-deflated", "--prefer-j2k-lossless", opt_networkTransferSyntax == EXS_JPEG2000LosslessOnly);
  538. app.checkConflict("--write-xfer-deflated", "--prefer-j2k-lossy", opt_networkTransferSyntax == EXS_JPEG2000);
  539. app.checkConflict("--write-xfer-deflated", "--prefer-jls-lossless", opt_networkTransferSyntax == EXS_JPEGLSLossless);
  540. app.checkConflict("--write-xfer-deflated", "--prefer-jls-lossy", opt_networkTransferSyntax == EXS_JPEGLSLossy);
  541. app.checkConflict("--write-xfer-deflated", "--prefer-mpeg2", opt_networkTransferSyntax == EXS_MPEG2MainProfileAtMainLevel);
  542. app.checkConflict("--write-xfer-deflated", "--prefer-mpeg2-high", opt_networkTransferSyntax == EXS_MPEG2MainProfileAtHighLevel);
  543. app.checkConflict("--write-xfer-deflated", "--prefer-rle", opt_networkTransferSyntax == EXS_RLELossless);
  544. opt_writeTransferSyntax = EXS_DeflatedLittleEndianExplicit;
  545. }
  546. #endif
  547. cmd.endOptionBlock();
  548. cmd.beginOptionBlock();
  549. if (cmd.findOption("--enable-new-vr"))
  550. {
  551. app.checkConflict("--enable-new-vr", "--bit-preserving", opt_bitPreserving);
  552. dcmEnableUnknownVRGeneration.set(OFTrue);
  553. dcmEnableUnlimitedTextVRGeneration.set(OFTrue);
  554. }
  555. if (cmd.findOption("--disable-new-vr"))
  556. {
  557. app.checkConflict("--disable-new-vr", "--bit-preserving", opt_bitPreserving);
  558. dcmEnableUnknownVRGeneration.set(OFFalse);
  559. dcmEnableUnlimitedTextVRGeneration.set(OFFalse);
  560. }
  561. cmd.endOptionBlock();
  562. cmd.beginOptionBlock();
  563. if (cmd.findOption("--group-length-recalc"))
  564. {
  565. app.checkConflict("--group-length-recalc", "--bit-preserving", opt_bitPreserving);
  566. opt_groupLength = EGL_recalcGL;
  567. }
  568. if (cmd.findOption("--group-length-create"))
  569. {
  570. app.checkConflict("--group-length-create", "--bit-preserving", opt_bitPreserving);
  571. opt_groupLength = EGL_withGL;
  572. }
  573. if (cmd.findOption("--group-length-remove"))
  574. {
  575. app.checkConflict("--group-length-remove", "--bit-preserving", opt_bitPreserving);
  576. opt_groupLength = EGL_withoutGL;
  577. }
  578. cmd.endOptionBlock();
  579. cmd.beginOptionBlock();
  580. if (cmd.findOption("--length-explicit"))
  581. {
  582. app.checkConflict("--length-explicit", "--bit-preserving", opt_bitPreserving);
  583. opt_sequenceType = EET_ExplicitLength;
  584. }
  585. if (cmd.findOption("--length-undefined"))
  586. {
  587. app.checkConflict("--length-undefined", "--bit-preserving", opt_bitPreserving);
  588. opt_sequenceType = EET_UndefinedLength;
  589. }
  590. cmd.endOptionBlock();
  591. cmd.beginOptionBlock();
  592. if (cmd.findOption("--padding-off")) opt_paddingType = EPD_withoutPadding;
  593. if (cmd.findOption("--padding-create"))
  594. {
  595. app.checkConflict("--padding-create", "--write-dataset", !opt_useMetaheader);
  596. app.checkConflict("--padding-create", "--bit-preserving", opt_bitPreserving);
  597. app.checkValue(cmd.getValueAndCheckMin(opt_filepad, 0));
  598. app.checkValue(cmd.getValueAndCheckMin(opt_itempad, 0));
  599. opt_paddingType = EPD_withPadding;
  600. }
  601. cmd.endOptionBlock();
  602. #ifdef WITH_ZLIB
  603. if (cmd.findOption("--compression-level"))
  604. {
  605. app.checkDependence("--compression-level", "--write-xfer-deflated or --write-xfer-same",
  606. (opt_writeTransferSyntax == EXS_DeflatedLittleEndianExplicit) || (opt_writeTransferSyntax == EXS_Unknown));
  607. app.checkValue(cmd.getValueAndCheckMinMax(opt_compressionLevel, 0, 9));
  608. dcmZlibCompressionLevel.set(OFstatic_cast(int, opt_compressionLevel));
  609. }
  610. #endif
  611. /* finally parse filenames */
  612. int paramCount = cmd.getParamCount();
  613. const char *currentFilename = NULL;
  614. OFString errormsg;
  615. for (int i=3; i <= paramCount; i++)
  616. {
  617. cmd.getParam(i, currentFilename);
  618. if (access(currentFilename, R_OK) < 0)
  619. {
  620. errormsg = "cannot access file: ";
  621. errormsg += currentFilename;
  622. app.printError(errormsg.c_str());
  623. }
  624. fileNameList.push_back(currentFilename);
  625. }
  626. if ((fileNameList.empty()) && (overrideKeys == NULL))
  627. {
  628. app.printError("either query file or override keys (or both) must be specified");
  629. }
  630. }
  631. /* print resource identifier */
  632. OFLOG_DEBUG(movescuLogger, rcsid << OFendl);
  633. /* make sure data dictionary is loaded */
  634. if (!dcmDataDict.isDictionaryLoaded())
  635. {
  636. OFLOG_WARN(movescuLogger, "no data dictionary loaded, check environment variable: "
  637. << DCM_DICT_ENVIRONMENT_VARIABLE);
  638. }
  639. /* make sure output directory exists and is writeable */
  640. if (opt_retrievePort > 0)
  641. {
  642. if (!OFStandard::dirExists(opt_outputDirectory))
  643. {
  644. OFLOG_FATAL(movescuLogger, "specified output directory does not exist");
  645. return 1;
  646. }
  647. else if (!OFStandard::isWriteable(opt_outputDirectory))
  648. {
  649. OFLOG_FATAL(movescuLogger, "specified output directory is not writeable");
  650. return 1;
  651. }
  652. }
  653. #ifdef HAVE_GETEUID
  654. /* if retrieve port is privileged we must be as well */
  655. if ((opt_retrievePort > 0) && (opt_retrievePort < 1024)) {
  656. if (geteuid() != 0)
  657. {
  658. OFLOG_FATAL(movescuLogger, "cannot listen on port " << opt_retrievePort << ", insufficient privileges");
  659. return 1;
  660. }
  661. }
  662. #endif
  663. /* network for move request and responses */
  664. T_ASC_NetworkRole role = (opt_retrievePort > 0) ? NET_ACCEPTORREQUESTOR : NET_REQUESTOR;
  665. OFCondition cond = ASC_initializeNetwork(role, OFstatic_cast(int, opt_retrievePort), opt_acse_timeout, &net);
  666. if (cond.bad())
  667. {
  668. OFLOG_FATAL(movescuLogger, "cannot create network: " << DimseCondition::dump(temp_str, cond));
  669. return 1;
  670. }
  671. #ifdef HAVE_GETUID
  672. /* return to normal uid so that we can't do too much damage in case
  673. * things go very wrong. Only does someting if the program is setuid
  674. * root, and run by another user. Running as root user may be
  675. * potentially disasterous if this program screws up badly.
  676. */
  677. setuid(getuid());
  678. #endif
  679. /* set up main association */
  680. cond = ASC_createAssociationParameters(&params, opt_maxPDU);
  681. if (cond.bad()) {
  682. OFLOG_FATAL(movescuLogger, DimseCondition::dump(temp_str, cond));
  683. exit(1);
  684. }
  685. ASC_setAPTitles(params, opt_ourTitle, opt_peerTitle, NULL);
  686. gethostname(localHost, sizeof(localHost) - 1);
  687. sprintf(peerHost, "%s:%d", opt_peer, OFstatic_cast(int, opt_port));
  688. ASC_setPresentationAddresses(params, localHost, peerHost);
  689. /*
  690. * We also add a presentation context for the corresponding
  691. * find sop class.
  692. */
  693. cond = addPresentationContext(params, 1,
  694. querySyntax[opt_queryModel].findSyntax);
  695. cond = addPresentationContext(params, 3,
  696. querySyntax[opt_queryModel].moveSyntax);
  697. if (cond.bad()) {
  698. OFLOG_FATAL(movescuLogger, DimseCondition::dump(temp_str, cond));
  699. exit(1);
  700. }
  701. OFLOG_DEBUG(movescuLogger, "Request Parameters:" << OFendl << ASC_dumpParameters(temp_str, params, ASC_ASSOC_RQ));
  702. /* create association */
  703. OFLOG_INFO(movescuLogger, "Requesting Association");
  704. cond = ASC_requestAssociation(net, params, &assoc);
  705. if (cond.bad()) {
  706. if (cond == DUL_ASSOCIATIONREJECTED) {
  707. T_ASC_RejectParameters rej;
  708. ASC_getRejectParameters(params, &rej);
  709. OFLOG_FATAL(movescuLogger, "Association Rejected:");
  710. OFLOG_FATAL(movescuLogger, ASC_printRejectParameters(temp_str, &rej));
  711. exit(1);
  712. } else {
  713. OFLOG_FATAL(movescuLogger, "Association Request Failed:");
  714. OFLOG_FATAL(movescuLogger, DimseCondition::dump(temp_str, cond));
  715. exit(1);
  716. }
  717. }
  718. /* what has been accepted/refused ? */
  719. OFLOG_DEBUG(movescuLogger, "Association Parameters Negotiated:" << OFendl << ASC_dumpParameters(temp_str, params, ASC_ASSOC_AC));
  720. if (ASC_countAcceptedPresentationContexts(params) == 0) {
  721. OFLOG_FATAL(movescuLogger, "No Acceptable Presentation Contexts");
  722. exit(1);
  723. }
  724. OFLOG_INFO(movescuLogger, "Association Accepted (Max Send PDV: " << assoc->sendPDVLength << ")");
  725. /* do the real work */
  726. cond = EC_Normal;
  727. if (fileNameList.empty())
  728. {
  729. /* no files provided on command line */
  730. cond = cmove(assoc, NULL);
  731. } else {
  732. OFListIterator(OFString) iter = fileNameList.begin();
  733. OFListIterator(OFString) enditer = fileNameList.end();
  734. while ((iter != enditer) && cond.good())
  735. {
  736. cond = cmove(assoc, (*iter).c_str());
  737. ++iter;
  738. }
  739. }
  740. /* tear down association */
  741. if (cond == EC_Normal)
  742. {
  743. if (opt_abortAssociation) {
  744. OFLOG_INFO(movescuLogger, "Aborting Association");
  745. cond = ASC_abortAssociation(assoc);
  746. if (cond.bad()) {
  747. OFLOG_FATAL(movescuLogger, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
  748. exit(1);
  749. }
  750. } else {
  751. /* release association */
  752. OFLOG_INFO(movescuLogger, "Releasing Association");
  753. cond = ASC_releaseAssociation(assoc);
  754. if (cond.bad())
  755. {
  756. OFLOG_FATAL(movescuLogger, "Association Release Failed:");
  757. OFLOG_FATAL(movescuLogger, DimseCondition::dump(temp_str, cond));
  758. exit(1);
  759. }
  760. }
  761. }
  762. else if (cond == DUL_PEERREQUESTEDRELEASE)
  763. {
  764. OFLOG_ERROR(movescuLogger, "Protocol Error: Peer requested release (Aborting)");
  765. OFLOG_INFO(movescuLogger, "Aborting Association");
  766. cond = ASC_abortAssociation(assoc);
  767. if (cond.bad()) {
  768. OFLOG_FATAL(movescuLogger, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
  769. exit(1);
  770. }
  771. }
  772. else if (cond == DUL_PEERABORTEDASSOCIATION)
  773. {
  774. OFLOG_INFO(movescuLogger, "Peer Aborted Association");
  775. }
  776. else
  777. {
  778. OFLOG_ERROR(movescuLogger, "Move SCU Failed: " << DimseCondition::dump(temp_str, cond));
  779. OFLOG_INFO(movescuLogger, "Aborting Association");
  780. cond = ASC_abortAssociation(assoc);
  781. if (cond.bad()) {
  782. OFLOG_FATAL(movescuLogger, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
  783. exit(1);
  784. }
  785. }
  786. cond = ASC_destroyAssociation(&assoc);
  787. if (cond.bad()) {
  788. OFLOG_FATAL(movescuLogger, DimseCondition::dump(temp_str, cond));
  789. exit(1);
  790. }
  791. cond = ASC_dropNetwork(&net);
  792. if (cond.bad()) {
  793. OFLOG_FATAL(movescuLogger, DimseCondition::dump(temp_str, cond));
  794. exit(1);
  795. }
  796. #ifdef HAVE_WINSOCK_H
  797. WSACleanup();
  798. #endif
  799. return 0;
  800. }
  801. static OFCondition
  802. addPresentationContext(T_ASC_Parameters *params,
  803. T_ASC_PresentationContextID pid,
  804. const char* abstractSyntax)
  805. {
  806. /*
  807. ** We prefer to use Explicitly encoded transfer syntaxes.
  808. ** If we are running on a Little Endian machine we prefer
  809. ** LittleEndianExplicitTransferSyntax to BigEndianTransferSyntax.
  810. ** Some SCP implementations will just select the first transfer
  811. ** syntax they support (this is not part of the standard) so
  812. ** organise the proposed transfer syntaxes to take advantage
  813. ** of such behaviour.
  814. **
  815. ** The presentation contexts proposed here are only used for
  816. ** C-FIND and C-MOVE, so there is no need to support compressed
  817. ** transmission.
  818. */
  819. const char* transferSyntaxes[] = { NULL, NULL, NULL };
  820. int numTransferSyntaxes = 0;
  821. switch (opt_out_networkTransferSyntax) {
  822. case EXS_LittleEndianImplicit:
  823. /* we only support Little Endian Implicit */
  824. transferSyntaxes[0] = UID_LittleEndianImplicitTransferSyntax;
  825. numTransferSyntaxes = 1;
  826. break;
  827. case EXS_LittleEndianExplicit:
  828. /* we prefer Little Endian Explicit */
  829. transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax;
  830. transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax;
  831. transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
  832. numTransferSyntaxes = 3;
  833. break;
  834. case EXS_BigEndianExplicit:
  835. /* we prefer Big Endian Explicit */
  836. transferSyntaxes[0] = UID_BigEndianExplicitTransferSyntax;
  837. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  838. transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
  839. numTransferSyntaxes = 3;
  840. break;
  841. default:
  842. /* We prefer explicit transfer syntaxes.
  843. * If we are running on a Little Endian machine we prefer
  844. * LittleEndianExplicitTransferSyntax to BigEndianTransferSyntax.
  845. */
  846. if (gLocalByteOrder == EBO_LittleEndian) /* defined in dcxfer.h */
  847. {
  848. transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax;
  849. transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax;
  850. } else {
  851. transferSyntaxes[0] = UID_BigEndianExplicitTransferSyntax;
  852. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  853. }
  854. transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
  855. numTransferSyntaxes = 3;
  856. break;
  857. }
  858. return ASC_addPresentationContext(
  859. params, pid, abstractSyntax,
  860. transferSyntaxes, numTransferSyntaxes);
  861. }
  862. static OFCondition
  863. acceptSubAssoc(T_ASC_Network * aNet, T_ASC_Association ** assoc)
  864. {
  865. const char* knownAbstractSyntaxes[] = {
  866. UID_VerificationSOPClass
  867. };
  868. const char* transferSyntaxes[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  869. int numTransferSyntaxes;
  870. OFCondition cond = ASC_receiveAssociation(aNet, assoc, opt_maxPDU);
  871. if (cond.good())
  872. {
  873. switch (opt_in_networkTransferSyntax)
  874. {
  875. case EXS_LittleEndianImplicit:
  876. /* we only support Little Endian Implicit */
  877. transferSyntaxes[0] = UID_LittleEndianImplicitTransferSyntax;
  878. numTransferSyntaxes = 1;
  879. break;
  880. case EXS_LittleEndianExplicit:
  881. /* we prefer Little Endian Explicit */
  882. transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax;
  883. transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax;
  884. transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
  885. numTransferSyntaxes = 3;
  886. break;
  887. case EXS_BigEndianExplicit:
  888. /* we prefer Big Endian Explicit */
  889. transferSyntaxes[0] = UID_BigEndianExplicitTransferSyntax;
  890. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  891. transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
  892. numTransferSyntaxes = 3;
  893. break;
  894. case EXS_JPEGProcess14SV1TransferSyntax:
  895. /* we prefer JPEGLossless:Hierarchical-1stOrderPrediction (default lossless) */
  896. transferSyntaxes[0] = UID_JPEGProcess14SV1TransferSyntax;
  897. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  898. transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
  899. transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
  900. numTransferSyntaxes = 4;
  901. break;
  902. case EXS_JPEGProcess1TransferSyntax:
  903. /* we prefer JPEGBaseline (default lossy for 8 bit images) */
  904. transferSyntaxes[0] = UID_JPEGProcess1TransferSyntax;
  905. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  906. transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
  907. transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
  908. numTransferSyntaxes = 4;
  909. break;
  910. case EXS_JPEGProcess2_4TransferSyntax:
  911. /* we prefer JPEGExtended (default lossy for 12 bit images) */
  912. transferSyntaxes[0] = UID_JPEGProcess2_4TransferSyntax;
  913. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  914. transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
  915. transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
  916. numTransferSyntaxes = 4;
  917. break;
  918. case EXS_JPEG2000LosslessOnly:
  919. /* we prefer JPEG2000 Lossless */
  920. transferSyntaxes[0] = UID_JPEG2000LosslessOnlyTransferSyntax;
  921. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  922. transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
  923. transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
  924. numTransferSyntaxes = 4;
  925. break;
  926. case EXS_JPEG2000:
  927. /* we prefer JPEG2000 Lossy */
  928. transferSyntaxes[0] = UID_JPEG2000TransferSyntax;
  929. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  930. transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
  931. transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
  932. numTransferSyntaxes = 4;
  933. break;
  934. case EXS_JPEGLSLossless:
  935. /* we prefer JPEG-LS Lossless */
  936. transferSyntaxes[0] = UID_JPEGLSLosslessTransferSyntax;
  937. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  938. transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
  939. transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
  940. numTransferSyntaxes = 4;
  941. break;
  942. case EXS_JPEGLSLossy:
  943. /* we prefer JPEG-LS Lossy */
  944. transferSyntaxes[0] = UID_JPEGLSLossyTransferSyntax;
  945. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  946. transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
  947. transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
  948. numTransferSyntaxes = 4;
  949. break;
  950. case EXS_MPEG2MainProfileAtMainLevel:
  951. /* we prefer MPEG2 MP@ML */
  952. transferSyntaxes[0] = UID_MPEG2MainProfileAtMainLevelTransferSyntax;
  953. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  954. transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
  955. transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
  956. numTransferSyntaxes = 4;
  957. break;
  958. case EXS_MPEG2MainProfileAtHighLevel:
  959. /* we prefer MPEG2 MP@HL */
  960. transferSyntaxes[0] = UID_MPEG2MainProfileAtHighLevelTransferSyntax;
  961. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  962. transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
  963. transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
  964. numTransferSyntaxes = 4;
  965. break;
  966. case EXS_RLELossless:
  967. /* we prefer RLE Lossless */
  968. transferSyntaxes[0] = UID_RLELosslessTransferSyntax;
  969. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  970. transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
  971. transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
  972. numTransferSyntaxes = 4;
  973. break;
  974. #ifdef WITH_ZLIB
  975. case EXS_DeflatedLittleEndianExplicit:
  976. /* we prefer Deflated Explicit VR Little Endian */
  977. transferSyntaxes[0] = UID_DeflatedExplicitVRLittleEndianTransferSyntax;
  978. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  979. transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
  980. transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
  981. numTransferSyntaxes = 4;
  982. break;
  983. #endif
  984. default:
  985. if (opt_acceptAllXfers)
  986. {
  987. /* we accept all supported transfer syntaxes
  988. * (similar to "AnyTransferSyntax" in "storescp.cfg")
  989. */
  990. transferSyntaxes[0] = UID_JPEG2000TransferSyntax;
  991. transferSyntaxes[1] = UID_JPEG2000LosslessOnlyTransferSyntax;
  992. transferSyntaxes[2] = UID_JPEGProcess2_4TransferSyntax;
  993. transferSyntaxes[3] = UID_JPEGProcess1TransferSyntax;
  994. transferSyntaxes[4] = UID_JPEGProcess14SV1TransferSyntax;
  995. transferSyntaxes[5] = UID_JPEGLSLossyTransferSyntax;
  996. transferSyntaxes[6] = UID_JPEGLSLosslessTransferSyntax;
  997. transferSyntaxes[7] = UID_RLELosslessTransferSyntax;
  998. transferSyntaxes[8] = UID_MPEG2MainProfileAtMainLevelTransferSyntax;
  999. transferSyntaxes[9] = UID_MPEG2MainProfileAtHighLevelTransferSyntax;
  1000. transferSyntaxes[10] = UID_DeflatedExplicitVRLittleEndianTransferSyntax;
  1001. if (gLocalByteOrder == EBO_LittleEndian)
  1002. {
  1003. transferSyntaxes[11] = UID_LittleEndianExplicitTransferSyntax;
  1004. transferSyntaxes[12] = UID_BigEndianExplicitTransferSyntax;
  1005. } else {
  1006. transferSyntaxes[11] = UID_BigEndianExplicitTransferSyntax;
  1007. transferSyntaxes[12] = UID_LittleEndianExplicitTransferSyntax;
  1008. }
  1009. transferSyntaxes[13] = UID_LittleEndianImplicitTransferSyntax;
  1010. numTransferSyntaxes = 14;
  1011. } else {
  1012. /* We prefer explicit transfer syntaxes.
  1013. * If we are running on a Little Endian machine we prefer
  1014. * LittleEndianExplicitTransferSyntax to BigEndianTransferSyntax.
  1015. */
  1016. if (gLocalByteOrder == EBO_LittleEndian) /* defined in dcxfer.h */
  1017. {
  1018. transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax;
  1019. transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax;
  1020. } else {
  1021. transferSyntaxes[0] = UID_BigEndianExplicitTransferSyntax;
  1022. transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
  1023. }
  1024. transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
  1025. numTransferSyntaxes = 3;
  1026. }
  1027. break;
  1028. }
  1029. /* accept the Verification SOP Class if presented */
  1030. cond = ASC_acceptContextsWithPreferredTransferSyntaxes(
  1031. (*assoc)->params,
  1032. knownAbstractSyntaxes, DIM_OF(knownAbstractSyntaxes),
  1033. transferSyntaxes, numTransferSyntaxes);
  1034. if (cond.good())
  1035. {
  1036. /* the array of Storage SOP Class UIDs comes from dcuid.h */
  1037. cond = ASC_acceptContextsWithPreferredTransferSyntaxes(
  1038. (*assoc)->params,
  1039. dcmAllStorageSOPClassUIDs, numberOfAllDcmStorageSOPClassUIDs,
  1040. transferSyntaxes, numTransferSyntaxes);
  1041. }
  1042. }
  1043. if (cond.good()) cond = ASC_acknowledgeAssociation(*assoc);
  1044. if (cond.bad()) {
  1045. ASC_dropAssociation(*assoc);
  1046. ASC_destroyAssociation(assoc);
  1047. }
  1048. return cond;
  1049. }
  1050. static OFCondition echoSCP(
  1051. T_ASC_Association * assoc,
  1052. T_DIMSE_Message * msg,
  1053. T_ASC_PresentationContextID presID)
  1054. {
  1055. OFString temp_str;
  1056. OFLOG_INFO(movescuLogger, "Received Echo Request");
  1057. OFLOG_DEBUG(movescuLogger, DIMSE_dumpMessage(temp_str, msg->msg.CEchoRQ, DIMSE_INCOMING));
  1058. /* the echo succeeded !! */
  1059. OFCondition cond = DIMSE_sendEchoResponse(assoc, presID, &msg->msg.CEchoRQ, STATUS_Success, NULL);
  1060. if (cond.bad())
  1061. {
  1062. OFLOG_ERROR(movescuLogger, "Echo SCP Failed: " << DimseCondition::dump(temp_str, cond));
  1063. }
  1064. return cond;
  1065. }
  1066. struct StoreCallbackData
  1067. {
  1068. char* imageFileName;
  1069. DcmFileFormat* dcmff;
  1070. T_ASC_Association* assoc;
  1071. };
  1072. static void
  1073. storeSCPCallback(
  1074. /* in */
  1075. void *callbackData,
  1076. T_DIMSE_StoreProgress *progress, /* progress state */
  1077. T_DIMSE_C_StoreRQ *req, /* original store request */
  1078. char *imageFileName, DcmDataset **imageDataSet, /* being received into */
  1079. /* out */
  1080. T_DIMSE_C_StoreRSP *rsp, /* final store response */
  1081. DcmDataset **statusDetail)
  1082. {
  1083. DIC_UI sopClass;
  1084. DIC_UI sopInstance;
  1085. if ((opt_abortDuringStore && progress->state != DIMSE_StoreBegin) ||
  1086. (opt_abortAfterStore && progress->state == DIMSE_StoreEnd)) {
  1087. OFLOG_INFO(movescuLogger, "ABORT initiated (due to command line options)");
  1088. ASC_abortAssociation(OFstatic_cast(StoreCallbackData*, callbackData)->assoc);
  1089. rsp->DimseStatus = STATUS_STORE_Refused_OutOfResources;
  1090. return;
  1091. }
  1092. if (opt_sleepDuring > 0)
  1093. {
  1094. OFStandard::sleep(OFstatic_cast(unsigned int, opt_sleepDuring));
  1095. }
  1096. // dump some information if required (depending on the progress state)
  1097. // We can't use oflog for the pdu output, but we use a special logger for
  1098. // generating this output. If it is set to level "INFO" we generate the
  1099. // output, if it's set to "DEBUG" then we'll assume that there is debug output
  1100. // generated for each PDU elsewhere.
  1101. OFLogger progressLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION ".progress");
  1102. if (progressLogger.getChainedLogLevel() == OFLogger::INFO_LOG_LEVEL)
  1103. {
  1104. switch (progress->state)
  1105. {
  1106. case DIMSE_StoreBegin:
  1107. COUT << "RECV: ";
  1108. break;
  1109. case DIMSE_StoreEnd:
  1110. COUT << OFendl;
  1111. break;
  1112. default:
  1113. COUT << '.';
  1114. break;
  1115. }
  1116. COUT.flush();
  1117. }
  1118. if (progress->state == DIMSE_StoreEnd)
  1119. {
  1120. *statusDetail = NULL; /* no status detail */
  1121. /* could save the image somewhere else, put it in database, etc */
  1122. /*
  1123. * An appropriate status code is already set in the resp structure, it need not be success.
  1124. * For example, if the caller has already detected an out of resources problem then the
  1125. * status will reflect this. The callback function is still called to allow cleanup.
  1126. */
  1127. // rsp->DimseStatus = STATUS_Success;
  1128. if ((imageDataSet != NULL) && (*imageDataSet != NULL) && !opt_bitPreserving && !opt_ignore)
  1129. {
  1130. StoreCallbackData *cbdata = OFstatic_cast(StoreCallbackData*, callbackData);
  1131. /* create full path name for the output file */
  1132. OFString ofname;
  1133. OFStandard::combineDirAndFilename(ofname, opt_outputDirectory, cbdata->imageFileName, OFTrue /* allowEmptyDirName */);
  1134. E_TransferSyntax xfer = opt_writeTransferSyntax;
  1135. if (xfer == EXS_Unknown) xfer = (*imageDataSet)->getOriginalXfer();
  1136. OFCondition cond = cbdata->dcmff->saveFile(ofname.c_str(), xfer, opt_sequenceType, opt_groupLength,
  1137. opt_paddingType, OFstatic_cast(Uint32, opt_filepad), OFstatic_cast(Uint32, opt_itempad),
  1138. (opt_useMetaheader) ? EWM_fileformat : EWM_dataset);
  1139. if (cond.bad())
  1140. {
  1141. OFLOG_ERROR(movescuLogger, "cannot write DICOM file: " << ofname);
  1142. rsp->DimseStatus = STATUS_STORE_Refused_OutOfResources;
  1143. }
  1144. /* should really check the image to make sure it is consistent,
  1145. * that its sopClass and sopInstance correspond with those in
  1146. * the request.
  1147. */
  1148. if ((rsp->DimseStatus == STATUS_Success) && !opt_ignore)
  1149. {
  1150. /* which SOP class and SOP instance ? */
  1151. if (!DU_findSOPClassAndInstanceInDataSet(*imageDataSet, sopClass, sopInstance, opt_correctUIDPadding))
  1152. {
  1153. OFLOG_FATAL(movescuLogger, "bad DICOM file: " << imageFileName);
  1154. rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand;
  1155. }
  1156. else if (strcmp(sopClass, req->AffectedSOPClassUID) != 0)
  1157. {
  1158. rsp->DimseStatus = STATUS_STORE_Error_DataSetDoesNotMatchSOPClass;
  1159. }
  1160. else if (strcmp(sopInstance, req->AffectedSOPInstanceUID) != 0)
  1161. {
  1162. rsp->DimseStatus = STATUS_STORE_Error_DataSetDoesNotMatchSOPClass;
  1163. }
  1164. }
  1165. }
  1166. }
  1167. }
  1168. static OFCondition storeSCP(
  1169. T_ASC_Association *assoc,
  1170. T_DIMSE_Message *msg,
  1171. T_ASC_PresentationContextID presID)
  1172. {
  1173. OFCondition cond = EC_Normal;
  1174. T_DIMSE_C_StoreRQ *req;
  1175. char imageFileName[2048];
  1176. req = &msg->msg.CStoreRQ;
  1177. if (opt_ignore)
  1178. {
  1179. #ifdef _WIN32
  1180. tmpnam(imageFileName);
  1181. #else
  1182. strcpy(imageFileName, NULL_DEVICE_NAME);
  1183. #endif
  1184. } else {
  1185. sprintf(imageFileName, "%s.%s",
  1186. dcmSOPClassUIDToModality(req->AffectedSOPClassUID),
  1187. req->AffectedSOPInstanceUID);
  1188. }
  1189. OFString temp_str;
  1190. OFLOG_INFO(movescuLogger, "Received Store Request: MsgID " << req->MessageID << ", ("
  1191. << dcmSOPClassUIDToModality(req->AffectedSOPClassUID, "OT") << ")");
  1192. OFLOG_DEBUG(movescuLogger, DIMSE_dumpMessage(temp_str, *req, DIMSE_INCOMING, NULL, presID));
  1193. StoreCallbackData callbackData;
  1194. callbackData.assoc = assoc;
  1195. callbackData.imageFileName = imageFileName;
  1196. DcmFileFormat dcmff;
  1197. callbackData.dcmff = &dcmff;
  1198. // store SourceApplicationEntityTitle in metaheader
  1199. if (assoc && assoc->params)
  1200. {
  1201. const char *aet = assoc->params->DULparams.callingAPTitle;
  1202. if (aet) dcmff.getMetaInfo()->putAndInsertString(DCM_SourceApplicationEntityTitle, aet);
  1203. }
  1204. DcmDataset *dset = dcmff.getDataset();
  1205. if (opt_bitPreserving)
  1206. {
  1207. cond = DIMSE_storeProvider(assoc, presID, req, imageFileName, opt_useMetaheader,
  1208. NULL, storeSCPCallback, OFreinterpret_cast(void*, &callbackData), opt_blockMode, opt_dimse_timeout);
  1209. } else {
  1210. cond = DIMSE_storeProvider(assoc, presID, req, NULL, opt_useMetaheader,
  1211. &dset, storeSCPCallback, OFreinterpret_cast(void*, &callbackData), opt_blockMode, opt_dimse_timeout);
  1212. }
  1213. if (cond.bad())
  1214. {
  1215. OFLOG_ERROR(movescuLogger, "Store SCP Failed: " << DimseCondition::dump(temp_str, cond));
  1216. /* remove file */
  1217. if (!opt_ignore)
  1218. {
  1219. if (strcmp(imageFileName, NULL_DEVICE_NAME) != 0) unlink(imageFileName);
  1220. }
  1221. #ifdef _WIN32
  1222. } else if (opt_ignore) {
  1223. if (strcmp(imageFileName, NULL_DEVICE_NAME) != 0) unlink(imageFileName); // delete the temporary file
  1224. #endif
  1225. }
  1226. if (opt_sleepAfter > 0)
  1227. {
  1228. OFStandard::sleep(OFstatic_cast(unsigned int, opt_sleepDuring));
  1229. }
  1230. return cond;
  1231. }
  1232. static OFCondition
  1233. subOpSCP(T_ASC_Association **subAssoc)
  1234. {
  1235. T_DIMSE_Message msg;
  1236. T_ASC_PresentationContextID presID;
  1237. if (!ASC_dataWaiting(*subAssoc, 0)) /* just in case */
  1238. return DIMSE_NODATAAVAILABLE;
  1239. OFCondition cond = DIMSE_receiveCommand(*subAssoc, opt_blockMode, opt_dimse_timeout, &presID,
  1240. &msg, NULL);
  1241. if (cond == EC_Normal) {
  1242. switch (msg.CommandField)
  1243. {
  1244. case DIMSE_C_STORE_RQ:
  1245. cond = storeSCP(*subAssoc, &msg, presID);
  1246. break;
  1247. case DIMSE_C_ECHO_RQ:
  1248. cond = echoSCP(*subAssoc, &msg, presID);
  1249. break;
  1250. default:
  1251. cond = DIMSE_BADCOMMANDTYPE;
  1252. OFLOG_ERROR(movescuLogger, "cannot handle command: 0x"
  1253. << STD_NAMESPACE hex << OFstatic_cast(unsigned, msg.CommandField));
  1254. break;
  1255. }
  1256. }
  1257. /* clean up on association termination */
  1258. if (cond == DUL_PEERREQUESTEDRELEASE)
  1259. {
  1260. cond = ASC_acknowledgeRelease(*subAssoc);
  1261. ASC_dropSCPAssociation(*subAssoc);
  1262. ASC_destroyAssociation(subAssoc);
  1263. return cond;
  1264. }
  1265. else if (cond == DUL_PEERABORTEDASSOCIATION)
  1266. {
  1267. }
  1268. else if (cond != EC_Normal)
  1269. {
  1270. OFString temp_str;
  1271. OFLOG_ERROR(movescuLogger, "DIMSE failure (aborting sub-association): " << DimseCondition::dump(temp_str, cond));
  1272. /* some kind of error so abort the association */
  1273. cond = ASC_abortAssociation(*subAssoc);
  1274. }
  1275. if (cond != EC_Normal)
  1276. {
  1277. ASC_dropAssociation(*subAssoc);
  1278. ASC_destroyAssociation(subAssoc);
  1279. }
  1280. return cond;
  1281. }
  1282. static void
  1283. subOpCallback(void * /*subOpCallbackData*/ ,
  1284. T_ASC_Network *aNet, T_ASC_Association **subAssoc)
  1285. {
  1286. if (aNet == NULL) return; /* help no net ! */
  1287. if (*subAssoc == NULL) {
  1288. /* negotiate association */
  1289. acceptSubAssoc(aNet, subAssoc);
  1290. } else {
  1291. /* be a service class provider */
  1292. subOpSCP(subAssoc);
  1293. }
  1294. }
  1295. static void
  1296. moveCallback(void *callbackData, T_DIMSE_C_MoveRQ *request,
  1297. int responseCount, T_DIMSE_C_MoveRSP *response)
  1298. {
  1299. OFCondition cond = EC_Normal;
  1300. MyCallbackInfo *myCallbackData;
  1301. myCallbackData = OFstatic_cast(MyCallbackInfo*, callbackData);
  1302. OFString temp_str;
  1303. OFLOG_INFO(movescuLogger, "Move Response " << responseCount << ":" << OFendl << DIMSE_dumpMessage(temp_str, *response, DIMSE_INCOMING));
  1304. /* should we send a cancel back ?? */
  1305. if (opt_cancelAfterNResponses == responseCount) {
  1306. OFLOG_INFO(movescuLogger, "Sending Cancel Request: MsgID " << request->MessageID
  1307. << ", PresID " << myCallbackData->presId);
  1308. cond = DIMSE_sendCancelRequest(myCallbackData->assoc,
  1309. myCallbackData->presId, request->MessageID);
  1310. if (cond != EC_Normal) {
  1311. OFLOG_ERROR(movescuLogger, "Cancel Request Failed: " << DimseCondition::dump(temp_str, cond));
  1312. }
  1313. }
  1314. }
  1315. static void
  1316. substituteOverrideKeys(DcmDataset *dset)
  1317. {
  1318. if (overrideKeys == NULL) {
  1319. return; /* nothing to do */
  1320. }
  1321. /* copy the override keys */
  1322. DcmDataset keys(*overrideKeys);
  1323. /* put the override keys into dset replacing existing tags */
  1324. unsigned long elemCount = keys.card();
  1325. for (unsigned long i = 0; i < elemCount; i++) {
  1326. DcmElement *elem = keys.remove(OFstatic_cast(unsigned long, 0));
  1327. dset->insert(elem, OFTrue);
  1328. }
  1329. }
  1330. static OFCondition
  1331. moveSCU(T_ASC_Association * assoc, const char *fname)
  1332. {
  1333. T_ASC_PresentationContextID presId;
  1334. T_DIMSE_C_MoveRQ req;
  1335. T_DIMSE_C_MoveRSP rsp;
  1336. DIC_US msgId = assoc->nextMsgID++;
  1337. DcmDataset *rspIds = NULL;
  1338. const char *sopClass;
  1339. DcmDataset *statusDetail = NULL;
  1340. MyCallbackInfo callbackData;
  1341. DcmFileFormat dcmff;
  1342. if (fname != NULL) {
  1343. if (dcmff.loadFile(fname).bad()) {
  1344. OFLOG_ERROR(movescuLogger, "bad DICOM file: " << fname << ": " << dcmff.error().text());
  1345. return DIMSE_BADDATA;
  1346. }
  1347. }
  1348. /* replace specific keys by those in overrideKeys */
  1349. substituteOverrideKeys(dcmff.getDataset());
  1350. sopClass = querySyntax[opt_queryModel].moveSyntax;
  1351. /* which presentation context should be used */
  1352. presId = ASC_findAcceptedPresentationContextID(assoc, sopClass);
  1353. if (presId == 0) return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
  1354. if (movescuLogger.isEnabledFor(OFLogger::INFO_LOG_LEVEL)) {
  1355. OFLOG_INFO(movescuLogger, "Sending Move Request: MsgID " << msgId);
  1356. OFLOG_INFO(movescuLogger, "Request:" << OFendl << DcmObject::PrintHelper(*dcmff.getDataset()));
  1357. }
  1358. callbackData.assoc = assoc;
  1359. callbackData.presId = presId;
  1360. req.MessageID = msgId;
  1361. strcpy(req.AffectedSOPClassUID, sopClass);
  1362. req.Priority = DIMSE_PRIORITY_MEDIUM;
  1363. req.DataSetType = DIMSE_DATASET_PRESENT;
  1364. if (opt_moveDestination == NULL) {
  1365. /* set the destination to be me */
  1366. ASC_getAPTitles(assoc->params, req.MoveDestination,
  1367. NULL, NULL);
  1368. } else {
  1369. strcpy(req.MoveDestination, opt_moveDestination);
  1370. }
  1371. OFCondition cond = DIMSE_moveUser(assoc, presId, &req, dcmff.getDataset(),
  1372. moveCallback, &callbackData, opt_blockMode, opt_dimse_timeout, net, subOpCallback,
  1373. NULL, &rsp, &statusDetail, &rspIds, opt_ignorePendingDatasets);
  1374. if (cond == EC_Normal) {
  1375. OFString temp_str;
  1376. OFLOG_INFO(movescuLogger, DIMSE_dumpMessage(temp_str, rsp, DIMSE_INCOMING));
  1377. if (rspIds != NULL) {
  1378. OFLOG_INFO(movescuLogger, "Response Identifiers:" << OFendl << DcmObject::PrintHelper(*rspIds));
  1379. }
  1380. } else {
  1381. OFString temp_str;
  1382. OFLOG_ERROR(movescuLogger, "Move Request Failed: " << DimseCondition::dump(temp_str, cond));
  1383. }
  1384. if (statusDetail != NULL) {
  1385. OFLOG_WARN(movescuLogger, "Status Detail:" << OFendl << DcmObject::PrintHelper(*statusDetail));
  1386. delete statusDetail;
  1387. }
  1388. if (rspIds != NULL) delete rspIds;
  1389. return cond;
  1390. }
  1391. static OFCondition
  1392. cmove(T_ASC_Association * assoc, const char *fname)
  1393. {
  1394. OFCondition cond = EC_Normal;
  1395. int n = OFstatic_cast(int, opt_repeatCount);
  1396. while (cond.good() && n--)
  1397. cond = moveSCU(assoc, fname);
  1398. return cond;
  1399. }
  1400. /*
  1401. ** CVS Log
  1402. **
  1403. ** $Log: movescu.cc,v $
  1404. ** Revision 1.88 2010-11-17 13:01:21 uli
  1405. ** Removed some uses of "%s" with sscanf().
  1406. **
  1407. ** Revision 1.87 2010-11-01 10:42:44 uli
  1408. ** Fixed some compiler warnings reported by gcc with additional flags.
  1409. **
  1410. ** Revision 1.86 2010-10-14 13:13:42 joergr
  1411. ** Updated copyright header. Added reference to COPYRIGHT file.
  1412. **
  1413. ** Revision 1.85 2010-09-24 13:30:30 joergr
  1414. ** Compared names of SOP Class UIDs with 2009 edition of the DICOM standard. The
  1415. ** resulting name changes are mainly caused by the fact that the corresponding
  1416. ** SOP Class is now retired.
  1417. **
  1418. ** Revision 1.84 2010-09-02 12:12:48 joergr
  1419. ** Added support for "MPEG2 Main Profile @ High Level" transfer syntax.
  1420. **
  1421. ** Revision 1.83 2010-05-18 16:10:25 joergr
  1422. ** Replaced '\n' by OFendl in log messages.
  1423. **
  1424. ** Revision 1.82 2010-03-23 15:20:13 joergr
  1425. ** Use printError() method for command line parsing errors only. After the
  1426. ** resource identifier has been printed to the log stream use "oflog" instead.
  1427. **
  1428. ** Revision 1.81 2010-02-19 14:13:45 joergr
  1429. ** Fixed wrong log output (error message when status is "normal").
  1430. **
  1431. ** Revision 1.80 2009-12-02 16:13:23 joergr
  1432. ** Make sure that dcmSOPClassUIDToModality() never returns NULL when passed to
  1433. ** the log stream in order to avoid an application crash.
  1434. **
  1435. ** Revision 1.79 2009-12-01 10:16:06 joergr
  1436. ** Sightly modified log messages.
  1437. **
  1438. ** Revision 1.78 2009-11-18 11:53:58 uli
  1439. ** Switched to logging mechanism provided by the "new" oflog module.
  1440. **
  1441. ** Revision 1.77 2009-11-12 10:13:01 joergr
  1442. ** Fixed issue with --accept-all command line option which caused the other
  1443. ** --prefer-xxx options to be ignored under certain conditions.
  1444. **
  1445. ** Revision 1.76 2009-08-21 09:47:34 joergr
  1446. ** Added parameter 'writeMode' to save/write methods which allows for specifying
  1447. ** whether to write a dataset or fileformat as well as whether to update the
  1448. ** file meta information or to create a new file meta information header.
  1449. **
  1450. ** Revision 1.75 2009-08-04 10:08:42 joergr
  1451. ** Added output of Presentation Context ID of the C-STORE message in debug mode.
  1452. **
  1453. ** Revision 1.74 2009-07-13 09:44:18 onken
  1454. ** Removed misleading comment about dcmnet DIMSE return code and changed
  1455. ** corresponding OFCondition check from EC_Normal to .good().
  1456. **
  1457. ** Revision 1.73 2009-04-24 12:26:05 joergr
  1458. ** Fixed minor inconsistencies regarding layout/formatting in syntax usage.
  1459. **
  1460. ** Revision 1.72 2009-04-21 14:09:22 joergr
  1461. ** Fixed minor inconsistencies in manpage / syntax usage.
  1462. **
  1463. ** Revision 1.71 2009-03-06 14:52:43 joergr
  1464. ** Made error/warning messages and verbose output more consistent with storescp.
  1465. ** Changed output from stderr to CERR and from stdout to COUT.
  1466. **
  1467. ** Revision 1.70 2009-02-06 15:34:48 joergr
  1468. ** Added support for JPEG-LS and MPEG2 transfer syntaxes.
  1469. ** Fixed minor inconsistencies with regard to transfer syntaxes.
  1470. ** Added support for writing files with deflated transfer syntax.
  1471. ** Added new option that allows for accepting all supported transfer syntaxes.
  1472. **
  1473. ** Revision 1.69 2008-11-20 12:13:22 joergr
  1474. ** Added new command line option --output-directory to specify the directory
  1475. ** where received objects are stored.
  1476. **
  1477. ** Revision 1.68 2008-09-25 16:00:58 joergr
  1478. ** Added support for printing the expanded command line arguments.
  1479. ** Always output the resource identifier of the command line tool in debug mode.
  1480. **
  1481. ** Revision 1.67 2007/10/25 10:08:22 joergr
  1482. ** Removed short option -P for --no-port since this string is already used for
  1483. ** the patient root information model (--patient).
  1484. **
  1485. ** Revision 1.66 2007/10/19 11:52:09 onken
  1486. ** *** empty log message ***
  1487. **
  1488. ** Revision 1.65 2007/10/18 16:15:07 onken
  1489. ** - Fixed bug in addOverrideKey() that caused problems when parsing a value in a
  1490. ** tag-value combination if the value contained whitespace characters.
  1491. **
  1492. ** Revision 1.64 2007/02/19 14:51:27 meichel
  1493. ** Removed calls to DcmObject::error()
  1494. **
  1495. ** Revision 1.63 2006/08/15 16:04:28 meichel
  1496. ** Updated the code in module dcmnet to correctly compile when
  1497. ** all standard C++ classes remain in namespace std.
  1498. **
  1499. ** Revision 1.62 2006/07/27 14:22:28 joergr
  1500. ** Changed parameter "exclusive" of method addOption() from type OFBool into an
  1501. ** integer parameter "flags". Prepended prefix "PF_" to parseLine() flags.
  1502. ** Option "--help" is no longer an exclusive option by default.
  1503. ** Made naming conventions for command line parameters more consistent, e.g.
  1504. ** used "dcmfile-in", "dcmfile-out" and "bitmap-out".
  1505. ** Added optional library "LIBWRAP" to output of option "--version".
  1506. **
  1507. ** Revision 1.61 2006/06/23 10:24:41 meichel
  1508. ** All Store SCPs in DCMTK now store the source application entity title in the
  1509. ** metaheader, both in normal and in bit-preserving mode.
  1510. **
  1511. ** Revision 1.60 2006/01/17 15:38:50 onken
  1512. ** Fixed "--key" option, which was broken when using the optional assignment ("=")
  1513. ** operation inside the option value
  1514. **
  1515. ** Revision 1.59 2005/12/08 15:44:20 meichel
  1516. ** Changed include path schema for all DCMTK header files
  1517. **
  1518. ** Revision 1.58 2005/11/22 16:44:35 meichel
  1519. ** Added option to movescu that allows graceful handling of Move SCPs
  1520. ** that send illegal datasets following pending C-MOVE-RSP messages.
  1521. **
  1522. ** Revision 1.57 2005/11/17 13:45:16 meichel
  1523. ** Added command line options for DIMSE and ACSE timeouts
  1524. **
  1525. ** Revision 1.56 2005/11/16 14:58:07 meichel
  1526. ** Set association timeout in ASC_initializeNetwork to 30 seconds. This improves
  1527. ** the responsiveness of the tools if the peer blocks during assoc negotiation.
  1528. **
  1529. ** Revision 1.55 2005/11/14 09:06:50 onken
  1530. ** Added data dictionary name support for "--key" option
  1531. **
  1532. ** Revision 1.54 2005/11/11 16:09:01 onken
  1533. ** Added options for JPEG2000 support (lossy and lossless)
  1534. **
  1535. ** Revision 1.53 2005/11/03 17:27:10 meichel
  1536. ** The movescu tool does not open any listen port by default anymore.
  1537. **
  1538. ** Revision 1.52 2005/10/25 08:55:43 meichel
  1539. ** Updated list of UIDs and added support for new transfer syntaxes
  1540. ** and storage SOP classes.
  1541. **
  1542. ** Revision 1.51 2004/04/06 18:11:24 joergr
  1543. ** Added missing suffix "TransferSyntax" to some transfer syntax constants.
  1544. **
  1545. ** Revision 1.50 2003/09/04 10:08:32 joergr
  1546. ** Fixed wrong use of OFBool/bool variable.
  1547. **
  1548. ** Revision 1.49 2003/06/10 14:00:34 meichel
  1549. ** Added support for TCP wrappers based host access control
  1550. **
  1551. ** Revision 1.48 2003/06/06 09:44:40 meichel
  1552. ** Added static sleep function in class OFStandard. This replaces the various
  1553. ** calls to sleep(), Sleep() and usleep() throughout the toolkit.
  1554. **
  1555. ** Revision 1.47 2002/11/29 09:15:50 meichel
  1556. ** Introduced new command line option --timeout for controlling the
  1557. ** connection request timeout.
  1558. **
  1559. ** Revision 1.46 2002/11/27 13:04:30 meichel
  1560. ** Adapted module dcmnet to use of new header file ofstdinc.h
  1561. **
  1562. ** Revision 1.45 2002/11/26 08:43:21 meichel
  1563. ** Replaced all includes for "zlib.h" with <zlib.h>
  1564. ** to avoid inclusion of zlib.h in the makefile dependencies.
  1565. **
  1566. ** Revision 1.44 2002/11/25 18:00:18 meichel
  1567. ** Converted compile time option to leniently handle space padded UIDs
  1568. ** in the Storage Service Class into command line / config file option.
  1569. **
  1570. ** Revision 1.43 2002/09/23 17:53:46 joergr
  1571. ** Added new command line option "--version" which prints the name and version
  1572. ** number of external libraries used (incl. preparation for future support of
  1573. ** 'config.guess' host identifiers).
  1574. **
  1575. ** Revision 1.42 2002/08/21 10:18:27 meichel
  1576. ** Adapted code to new loadFile and saveFile methods, thus removing direct
  1577. ** use of the DICOM stream classes.
  1578. **
  1579. ** Revision 1.41 2002/08/20 12:21:21 meichel
  1580. ** Adapted code to new loadFile and saveFile methods, thus removing direct
  1581. ** use of the DICOM stream classes.
  1582. **
  1583. ** Revision 1.40 2002/04/11 12:45:50 joergr
  1584. ** Adapted layout of command line help.
  1585. **
  1586. ** Revision 1.39 2001/11/09 15:56:24 joergr
  1587. ** Renamed some of the getValue/getParam methods to avoid ambiguities reported
  1588. ** by certain compilers.
  1589. **
  1590. ** Revision 1.38 2001/10/12 10:18:21 meichel
  1591. ** Replaced the CONDITION types, constants and functions in the dcmnet module
  1592. ** by an OFCondition based implementation which eliminates the global condition
  1593. ** stack. This is a major change, caveat emptor!
  1594. **
  1595. ** Revision 1.37 2001/09/26 12:28:55 meichel
  1596. ** Implemented changes in dcmnet required by the adaptation of dcmdata
  1597. ** to class OFCondition. Removed some unused code.
  1598. **
  1599. ** Revision 1.36 2001/06/01 15:50:02 meichel
  1600. ** Updated copyright header
  1601. **
  1602. ** Revision 1.35 2001/06/01 11:01:56 meichel
  1603. ** Implemented global flag and command line option to disable reverse
  1604. ** DNS hostname lookup using gethostbyaddr when accepting associations.
  1605. **
  1606. ** Revision 1.34 2000/11/10 18:07:42 meichel
  1607. ** Mixed up strcmp and strcpy - oops.
  1608. **
  1609. ** Revision 1.33 2000/11/10 16:25:03 meichel
  1610. ** Fixed problem with DIMSE routines which attempted to delete /dev/null
  1611. ** under certain circumstances, which could lead to disastrous results if
  1612. ** tools were run with root permissions (what they shouldn't).
  1613. **
  1614. ** Revision 1.32 2000/06/07 13:56:17 meichel
  1615. ** Output stream now passed as mandatory parameter to ASC_dumpParameters.
  1616. **
  1617. ** Revision 1.31 2000/04/14 16:29:26 meichel
  1618. ** Removed default value from output stream passed to print() method.
  1619. ** Required for use in multi-thread environments.
  1620. **
  1621. ** Revision 1.30 2000/03/08 16:43:16 meichel
  1622. ** Updated copyright header.
  1623. **
  1624. ** Revision 1.29 2000/02/29 11:49:49 meichel
  1625. ** Removed support for VS value representation. This was proposed in CP 101
  1626. ** but never became part of the standard.
  1627. **
  1628. ** Revision 1.28 2000/02/23 15:12:20 meichel
  1629. ** Corrected macro for Borland C++ Builder 4 workaround.
  1630. **
  1631. ** Revision 1.27 2000/02/03 11:50:08 meichel
  1632. ** Moved UID related functions from dcmnet (diutil.h) to dcmdata (dcuid.h)
  1633. ** where they belong. Renamed access functions to dcmSOPClassUIDToModality
  1634. ** and dcmGuessModalityBytes.
  1635. **
  1636. ** Revision 1.26 2000/02/02 15:17:28 meichel
  1637. ** Replaced some #if statements by more robust #ifdef
  1638. **
  1639. ** Revision 1.25 2000/02/01 10:24:02 meichel
  1640. ** Avoiding to include <stdlib.h> as extern "C" on Borland C++ Builder 4,
  1641. ** workaround for bug in compiler header files.
  1642. **
  1643. ** Revision 1.24 1999/04/30 16:40:22 meichel
  1644. ** Minor code purifications to keep Sun CC 2.0.1 quiet
  1645. **
  1646. ** Revision 1.23 1999/04/29 12:01:02 meichel
  1647. ** Adapted movescu to new command line option scheme.
  1648. ** Added support for transmission of compressed images.
  1649. **
  1650. ** Revision 1.22 1999/03/29 11:19:54 meichel
  1651. ** Cleaned up dcmnet code for char* to const char* assignments.
  1652. **
  1653. ** Revision 1.21 1998/08/10 08:53:35 meichel
  1654. ** renamed member variable in DIMSE structures from "Status" to
  1655. ** "DimseStatus". This is required if dcmnet is used together with
  1656. ** <X11/Xlib.h> where Status is #define'd as int.
  1657. **
  1658. ** Revision 1.20 1998/02/06 15:07:28 meichel
  1659. ** Removed many minor problems (name clashes, unreached code)
  1660. ** reported by Sun CC4 with "+w" or Sun CC2.
  1661. **
  1662. ** Revision 1.19 1998/01/14 14:35:54 hewett
  1663. ** Modified existing -u command line option to also disable generation
  1664. ** of UT and VS (previously just disabled generation of UN).
  1665. **
  1666. ** Revision 1.18 1997/08/05 07:36:20 andreas
  1667. ** - Corrected error in DUL finite state machine
  1668. ** SCPs shall close sockets after the SCU have closed the socket in
  1669. ** a normal association release. Therfore, an ARTIM timer is described
  1670. ** in DICOM part 8 that is not implemented correctly in the
  1671. ** DUL. Since the whole DUL finite state machine is affected, we
  1672. ** decided to solve the proble outside the fsm. Now it is necessary to call the
  1673. ** ASC_DropSCPAssociation() after the calling ASC_acknowledgeRelease().
  1674. ** - Change needed version number of WINSOCK to 1.1
  1675. ** to support WINDOWS 95
  1676. **
  1677. ** Revision 1.17 1997/07/21 08:37:03 andreas
  1678. ** - Replace all boolean types (BOOLEAN, CTNBOOLEAN, DICOM_BOOL, BOOL)
  1679. ** with one unique boolean type OFBool.
  1680. **
  1681. ** Revision 1.16 1997/06/26 12:53:08 andreas
  1682. ** - Include tests for changing of user IDs and the using of fork
  1683. ** in code since Windows NT/95 do not support this
  1684. ** - Corrected error interchanged parameters in a call
  1685. **
  1686. ** Revision 1.15 1997/05/30 07:33:22 meichel
  1687. ** Added space characters around comments and simplified
  1688. ** some inlining code (needed for SunCC 2.0.1).
  1689. **
  1690. ** Revision 1.14 1997/05/29 15:52:57 meichel
  1691. ** Added constant for dcmtk release date in dcuid.h.
  1692. ** All dcmtk applications now contain a version string
  1693. ** which is displayed with the command line options ("usage" message)
  1694. ** and which can be queried in the binary with the "ident" command.
  1695. **
  1696. ** Revision 1.13 1997/05/23 10:44:19 meichel
  1697. ** Major rewrite of storescp application. See CHANGES for details.
  1698. ** Changes to interfaces of some DIMSE functions.
  1699. **
  1700. ** Revision 1.12 1997/05/22 13:29:59 hewett
  1701. ** Modified the test for presence of a data dictionary to use the
  1702. ** method DcmDataDictionary::isDictionaryLoaded().
  1703. **
  1704. ** Revision 1.11 1997/05/16 08:31:33 andreas
  1705. ** - Revised handling of GroupLength elements and support of
  1706. ** DataSetTrailingPadding elements. The enumeratio E_GrpLenEncoding
  1707. ** got additional enumeration values (for a description see dctypes.h).
  1708. ** addGroupLength and removeGroupLength methods are replaced by
  1709. ** computeGroupLengthAndPadding. To support Padding, the parameters of
  1710. ** element and sequence write functions changed.
  1711. **
  1712. ** Revision 1.10 1997/04/18 08:40:14 andreas
  1713. ** - The put/get-methods for all VRs did not conform to the C++-Standard
  1714. ** draft. Some Compilers (e.g. SUN-C++ Compiler, Metroworks
  1715. ** CodeWarrier, etc.) create many warnings concerning the hiding of
  1716. ** overloaded get methods in all derived classes of DcmElement.
  1717. ** So the interface of all value representation classes in the
  1718. ** library are changed rapidly, e.g.
  1719. ** OFCondition get(Uint16 & value, const unsigned long pos);
  1720. ** becomes
  1721. ** OFCondition getUint16(Uint16 & value, const unsigned long pos);
  1722. ** All (retired) "returntype get(...)" methods are deleted.
  1723. ** For more information see dcmdata/include/dcelem.h
  1724. **
  1725. ** Revision 1.9 1997/03/27 16:11:26 hewett
  1726. ** Added command line switches allowing generation of UN to
  1727. ** be disabled (it is enabled by default).
  1728. **
  1729. ** Revision 1.8 1997/01/08 12:19:34 hewett
  1730. ** The Storage SCP code now will accept any presentation context for
  1731. ** a Storage SOP Class based on the table of Storage SOP Classes
  1732. ** exported in dcuid.h
  1733. **
  1734. ** Revision 1.7 1997/01/08 10:46:45 hewett
  1735. ** Changes default AE title to MOVESCU and cleaned up option summary.
  1736. **
  1737. ** Revision 1.6 1996/12/16 15:14:00 hewett
  1738. ** Added bugfix for WINSOCK support. The required WINSOCK version
  1739. ** number was being incorrectly set to version 0.1. The fixed
  1740. ** WINSOCK initialisation now uses the MAKEWORD macro to correctly
  1741. ** set the required version number. This bugfix was contributed
  1742. ** by Dr. Yongjian Bao of Innomed GmbH, Germany.
  1743. **
  1744. **
  1745. */