1 /*
2 *
3 * Copyright (C) 1998-2020, 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: dcmpstat
15 *
16 * Author: Joerg Riesmeier, Marco Eichelberg
17 *
18 * Purpose: DVPresentationState
19 *
20 */
21
22
23 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
24
25 #include "dcmtk/dcmpstat/dviface.h"
26
27 #include "dcmtk/dcmpstat/dvpsdef.h" /* for constants */
28 #include "dcmtk/ofstd/ofstring.h" /* for class OFString */
29 #include "dcmtk/ofstd/ofbmanip.h" /* for OFBitmanipTemplate */
30 #include "dcmtk/ofstd/ofdatime.h" /* for OFDateTime */
31 #include "dcmtk/ofstd/oflist.h" /* for class OFList */
32 #include "dcmtk/ofstd/ofstream.h"
33 #include "dcmtk/ofstd/ofcast.h"
34
35 #include "dcmtk/dcmimgle/digsdfn.h" /* for DiGSDFunction */
36 #include "dcmtk/dcmimgle/diciefn.h" /* for DiCIELABFunction */
37 #include "dcmtk/dcmnet/diutil.h" /* for DU_getStringDOElement */
38 #include "dcmtk/dcmpstat/dvpssp.h" /* for class DVPSStoredPrint */
39 #include "dcmtk/dcmpstat/dvpshlp.h" /* for class DVPSHelper */
40 #include "dcmtk/dcmimgle/dcmimage.h" /* for class DicomImage */
41 #include "dcmtk/dcmpstat/dvsighdl.h" /* for class DVSignatureHandler */
42 #include "dcmtk/dcmsign/dcsignat.h" /* for class DcmSignature */
43 #include "dcmtk/dcmsr/dsrdoc.h" /* for class DSRDocument */
44 #include "dcmtk/dcmsr/dsrcodvl.h" /* for class DSRCodedEntryValue */
45 #include "dcmtk/oflog/fileap.h" /* for dcmtk::log4cplus::FileAppender */
46
47 #include "dcmtk/dcmpstat/dvpsib.h" /* for DVPSImageBoxContent, needed by MSVC5 with STL */
48 #include "dcmtk/dcmpstat/dvpsab.h" /* for DVPSAnnotationContent, needed by MSVC5 with STL */
49 #include "dcmtk/dcmpstat/dvpsov.h" /* for DVPSOverlay, needed by MSVC5 with STL */
50 #include "dcmtk/dcmpstat/dvpsgl.h" /* for DVPSGraphicLayer, needed by MSVC5 with STL */
51 #include "dcmtk/dcmpstat/dvpsal.h" /* for DVPSOverlayCurveActivationLayer, needed by MSVC5 with STL */
52 #include "dcmtk/dcmpstat/dvpsga.h" /* for DVPSGraphicAnnotation, needed by MSVC5 with STL */
53 #include "dcmtk/dcmpstat/dvpscu.h" /* for DVPSCurve, needed by MSVC5 with STL */
54 #include "dcmtk/dcmpstat/dvpsvl.h" /* for DVPSVOILUT, needed by MSVC5 with STL */
55 #include "dcmtk/dcmpstat/dvpsvw.h" /* for DVPSVOIWindow, needed by MSVC5 with STL */
56 #include "dcmtk/dcmpstat/dvpsda.h" /* for DVPSDisplayedArea, needed by MSVC5 with STL */
57 #include "dcmtk/dcmpstat/dvpssv.h" /* for DVPSSoftcopyVOI, needed by MSVC5 with STL */
58 #include "dcmtk/dcmpstat/dvpsrs.h" /* for DVPSReferencedSeries, needed by MSVC5 with STL */
59 #include "dcmtk/dcmpstat/dvpstx.h" /* for DVPSTextObject, needed by MSVC5 with STL */
60 #include "dcmtk/dcmpstat/dvpsgr.h" /* for DVPSGraphicObject, needed by MSVC5 with STL */
61 #include "dcmtk/dcmpstat/dvpsri.h" /* for DVPSReferencedImage, needed by MSVC5 with STL */
62 #include "dcmtk/dcmqrdb/dcmqrdbi.h" /* for DB_UpperMaxBytesPerStudy */
63 #include "dcmtk/dcmqrdb/dcmqrdbs.h" /* for DcmQueryRetrieveDatabaseStatus */
64
65 #define INCLUDE_CSTDIO
66 #define INCLUDE_CCTYPE
67 #define INCLUDE_CMATH
68 #define INCLUDE_UNISTD
69 #include "dcmtk/ofstd/ofstdinc.h"
70
71 BEGIN_EXTERN_C
72 #ifdef HAVE_SYS_TYPES_H
73 #include <sys/types.h> /* for fork */
74 #endif
75 #ifdef HAVE_SYS_WAIT_H
76 #include <sys/wait.h> /* for waitpid */
77 #endif
78 #ifdef HAVE_SYS_TIME_H
79 #include <sys/time.h> /* for wait3 */
80 #endif
81 #ifdef HAVE_SYS_RESOURCE_H
82 #include <sys/resource.h> /* for wait3 */
83 #endif
84 #ifdef HAVE_SYS_STAT_H
85 #include <sys/stat.h> /* for stat, fstat */
86 #endif
87 #ifdef HAVE_SYS_UTIME_H
88 #include <sys/utime.h> /* for utime */
89 #endif
90 #ifdef HAVE_UTIME_H
91 #include <utime.h> /* for utime */
92 #endif
93 END_EXTERN_C
94
95 #ifdef HAVE_WINDOWS_H
96 #include <winbase.h> /* for CreateProcess */
97 #endif
98
99 #ifdef WITH_OPENSSL
100 #include "dcmtk/dcmtls/tlstrans.h"
101 #include "dcmtk/dcmtls/tlslayer.h"
102
103 BEGIN_EXTERN_C
104 #include <openssl/evp.h>
105 #include <openssl/x509.h>
106 #include <openssl/pem.h>
107 #include <openssl/err.h>
108 #include <openssl/ssl.h>
109 END_EXTERN_C
110 #endif
111
112
DVInterface(const char * config_file,OFBool useLog)113 DVInterface::DVInterface(const char *config_file, OFBool useLog)
114 : DVConfiguration(config_file)
115 , pPrint(NULL)
116 , pState(NULL)
117 , pReport(NULL)
118 , pSignatureHandler(NULL)
119 , pStoredPState(NULL)
120 , pDicomImage(NULL)
121 , pDicomPState(NULL)
122 , pHardcopyImage(NULL)
123 , printJobIdentifier()
124 , printJobCounter(0)
125 , configPath()
126 , databaseIndexFile()
127 , referenceTime(0)
128 , pHandle(NULL)
129 , lockingMode(OFFalse)
130 , idxCache()
131 , idxRec()
132 , idxRecPos(-1)
133 , imageInDatabase(OFFalse)
134 , minimumPrintBitmapWidth(0)
135 , minimumPrintBitmapHeight(0)
136 , maximumPrintBitmapWidth(0)
137 , maximumPrintBitmapHeight(0)
138 , maximumPrintPreviewWidth(0)
139 , maximumPrintPreviewHeight(0)
140 , maximumPreviewImageWidth(0)
141 , maximumPreviewImageHeight(0)
142 , currentPrinter()
143 , displayCurrentLUTID()
144 , printCurrentLUTID()
145 , printerMediumType()
146 , printerFilmDestination()
147 , printerFilmSessionLabel()
148 , printerNumberOfCopies(0)
149 , printerPriority()
150 , printerOwnerID()
151 , activateAnnotation(OFFalse)
152 , prependDateTime(OFTrue)
153 , prependPrinterName(OFTrue)
154 , prependLighting(OFTrue)
155 , annotationText()
156 {
157 #ifdef WITH_OPENSSL
158 DcmSignature::initializeLibrary(); // initializes OpenSSL for dcmsign and dcmtls
159 #endif
160
161 clearIndexRecord(idxRec, idxRecPos);
162 if (config_file) configPath = config_file;
163
164 /* initialize display transform (only on low-cost systems) */
165 for (int i = DVPSD_first; i < DVPSD_max;i++)
166 displayFunction[i] = NULL;
167 if (!getGUIConfigEntryBool(L2_HIGHRESOLUTIONGRAPHICS, OFFalse))
168 {
169 const char *displayFunctionFile = getMonitorCharacteristicsFile();
170 if (displayFunctionFile && (strlen(displayFunctionFile) > 0))
171 {
172 DiDisplayFunction *df = new DiGSDFunction(displayFunctionFile);
173 if (df && (df->isValid()))
174 {
175 displayFunction[DVPSD_GSDF] = df;
176 df = new DiCIELABFunction(displayFunctionFile);
177 if (df && (df->isValid()))
178 displayFunction[DVPSD_CIELAB] = df;
179 }
180 else
181 {
182 if (df) delete df;
183 DCMPSTAT_WARN("Unable to load monitor characterics file '" << displayFunctionFile << "', ignoring");
184 }
185 }
186 }
187
188 minimumPrintBitmapWidth = getMinPrintResolutionX();
189 minimumPrintBitmapHeight = getMinPrintResolutionY();
190 maximumPrintBitmapWidth = getMaxPrintResolutionX();
191 maximumPrintBitmapHeight = getMaxPrintResolutionY();
192 maximumPreviewImageWidth = getMaxPreviewResolutionX();
193 maximumPreviewImageHeight = getMaxPreviewResolutionY();
194
195 pPrint = new DVPSStoredPrint(getDefaultPrintIllumination(), getDefaultPrintReflection(), getNetworkAETitle());
196 pState = new DVPresentationState(OFstatic_cast(DiDisplayFunction **, displayFunction),
197 minimumPrintBitmapWidth, minimumPrintBitmapHeight, maximumPrintBitmapWidth, maximumPrintBitmapHeight,
198 maximumPreviewImageWidth, maximumPreviewImageHeight);
199 pReport = new DSRDocument();
200 pSignatureHandler = new DVSignatureHandler(*this);
201
202 referenceTime = OFstatic_cast(unsigned long, time(NULL));
203 /* initialize printJobIdentifier with a string comprising the current time */
204 char buf[20];
205 sprintf(buf, "%lu", referenceTime);
206 printJobIdentifier = buf;
207 /* initialize reference time with "yesterday" */
208 if (referenceTime >= 86400) referenceTime -= 86400; // subtract one day
209 setCurrentPrinter(getTargetID(0, DVPSE_printAny));
210
211 if (useLog)
212 {
213 const char *filename = getLogFile();
214 if (filename != NULL)
215 {
216 const char *directory = getLogFolder();
217 OFString filepath;
218 if (directory != NULL)
219 {
220 filepath = directory;
221 filepath += PATH_SEPARATOR;
222 filepath += filename;
223 } else
224 filepath = filename;
225
226 // This will badly interact with oflog config files :(
227 const char *pattern = "%D, Level %p, Module DCMPSTAT%n%m%n";
228 OFunique_ptr<dcmtk::log4cplus::Layout> layout(new dcmtk::log4cplus::PatternLayout(pattern));
229 dcmtk::log4cplus::SharedAppenderPtr logfile(new dcmtk::log4cplus::FileAppender(filepath, STD_NAMESPACE ios::app));
230 // We can't use OFLog::getLogger() here because that doesn't let us
231 // configure the object
232 dcmtk::log4cplus::Logger log = dcmtk::log4cplus::Logger::getInstance("dcmtk.dcmpstat.logfile");
233
234 logfile->setLayout(OFmove(layout));
235 log.addAppender(logfile);
236 log.setLogLevel(getLogLevel());
237
238 // All log messages to the logger "dcmtk.dcmpstat" are now written
239 // to the log file <filepath>
240 }
241 }
242
243 DCMPSTAT_LOGFILE("---------------------------\n--- Application started ---\n---------------------------");
244 }
245
246
~DVInterface()247 DVInterface::~DVInterface()
248 {
249 DCMPSTAT_INFO("Application terminated");
250 delete pPrint;
251 delete pState;
252 delete pReport;
253 delete pSignatureHandler;
254 delete pStoredPState;
255 delete pDicomImage;
256 delete pDicomPState;
257 delete pHardcopyImage;
258 for (int i = DVPSD_first; i < DVPSD_max; i++)
259 delete displayFunction[i];
260 if (pHandle) releaseDatabase();
261 // refresh database index file access time
262 if (!databaseIndexFile.empty())
263 // cast to char* required for gcc 2.5.8 on NeXTSTEP
264 utime(OFconst_cast(char *, databaseIndexFile.c_str()), NULL);
265 }
266
267
loadImage(const char * studyUID,const char * seriesUID,const char * instanceUID,OFBool changeStatus)268 OFCondition DVInterface::loadImage(const char *studyUID,
269 const char *seriesUID,
270 const char *instanceUID,
271 OFBool changeStatus)
272 {
273 OFCondition status = EC_IllegalCall;
274 if (studyUID && seriesUID && instanceUID)
275 {
276 if (lockDatabase() == EC_Normal)
277 {
278 const char *filename = getFilename(studyUID, seriesUID, instanceUID);
279 if (filename)
280 {
281 if ((status = loadImage(filename)) == EC_Normal)
282 {
283 imageInDatabase = OFTrue;
284 if (changeStatus)
285 instanceReviewed(studyUID, seriesUID, instanceUID);
286 }
287 } else
288 DCMPSTAT_LOGFILE("Load image from database failed: UIDs not in index file");
289 } else
290 DCMPSTAT_LOGFILE("Load image from database failed: could not lock index file");
291 } else
292 DCMPSTAT_LOGFILE("Load image from database failed: invalid UIDs");
293 return status;
294 }
295
296
loadImage(const char * imgName)297 OFCondition DVInterface::loadImage(const char *imgName)
298 {
299 OFCondition status = EC_IllegalCall;
300 DcmFileFormat *image = NULL;
301 DVPresentationState *newState = new DVPresentationState(OFstatic_cast(DiDisplayFunction **, displayFunction),
302 minimumPrintBitmapWidth, minimumPrintBitmapHeight, maximumPrintBitmapWidth, maximumPrintBitmapHeight,
303 maximumPreviewImageWidth, maximumPreviewImageHeight);
304 if (newState==NULL)
305 {
306 DCMPSTAT_LOGFILE("Load image from file failed: memory exhausted");
307 return EC_MemoryExhausted;
308 }
309
310 if ((status = DVPSHelper::loadFileFormat(imgName, image)) == EC_Normal)
311 {
312 if (image)
313 {
314 DcmDataset *dataset = image->getDataset();
315 if (dataset)
316 {
317 if (EC_Normal == (status = newState->createFromImage(*dataset)))
318 status = newState->attachImage(image, OFFalse);
319 if (EC_Normal == status)
320 {
321 exchangeImageAndPState(newState, image);
322 imageInDatabase = OFFalse;
323 }
324 } else status = EC_CorruptedData;
325 } else status = EC_IllegalCall;
326 if (status != EC_Normal)
327 DCMPSTAT_LOGFILE("Load image from file failed: invalid data structures");
328 } else
329 DCMPSTAT_LOGFILE("Load image from file failed: could not read fileformat");
330 if (status != EC_Normal)
331 {
332 delete newState;
333 delete image;
334 }
335 return status;
336 }
337
338
loadReferencedImage(size_t idx,OFBool changeStatus)339 OFCondition DVInterface::loadReferencedImage(size_t idx, OFBool changeStatus)
340 {
341 OFCondition status = EC_IllegalCall;
342 if ((pState != NULL) && (idx < pState->numberOfImageReferences()))
343 {
344 OFString ofstudyUID, ofseriesUID, ofsopclassUID, ofinstanceUID, offrames, aetitle, mediaID, mediaUID;
345 if ((status = pState->getImageReference(idx, ofstudyUID, ofseriesUID, ofsopclassUID, ofinstanceUID,
346 offrames, aetitle, mediaID, mediaUID)) == EC_Normal)
347 {
348 if (lockDatabase() == EC_Normal)
349 {
350 const char *filename = getFilename(ofstudyUID.c_str(), ofseriesUID.c_str(), ofinstanceUID.c_str());
351 if (filename != NULL)
352 {
353 DcmFileFormat *image = NULL;
354 if ((status = DVPSHelper::loadFileFormat(filename, image)) == EC_Normal)
355 {
356 status = EC_IllegalCall;
357 if (image != NULL)
358 {
359 DcmDataset *dataset = image->getDataset();
360 if (dataset != NULL)
361 {
362 if ((status = pState->attachImage(image, OFFalse)) == EC_Normal)
363 {
364 exchangeImageAndPState(pState, image); // do not exchange pState
365 imageInDatabase = OFTrue;
366 if (changeStatus)
367 instanceReviewed(ofstudyUID.c_str(), ofseriesUID.c_str(), ofinstanceUID.c_str());
368 }
369 }
370 }
371 if (status != EC_Normal)
372 DCMPSTAT_LOGFILE("Load referenced image from file failed: invalid data structures");
373 } else {
374 status = EC_CorruptedData;
375 DCMPSTAT_LOGFILE("Load referenced image from file failed: could not read fileformat");
376 }
377 if (status != EC_Normal)
378 delete image;
379 } else {
380 status = EC_IllegalCall;
381 DCMPSTAT_LOGFILE("Load referenced image from database failed: UIDs not in index file");
382 }
383 } else
384 DCMPSTAT_LOGFILE("Load referenced image from database failed: could not lock index file");
385 } else
386 DCMPSTAT_LOGFILE("Load referenced image from database failed: internal error");
387 } else
388 DCMPSTAT_LOGFILE("Load referenced image from database failed: internal error");
389 return status;
390 }
391
392
loadPState(const char * studyUID,const char * seriesUID,const char * instanceUID,OFBool changeStatus)393 OFCondition DVInterface::loadPState(const char *studyUID,
394 const char *seriesUID,
395 const char *instanceUID,
396 OFBool changeStatus)
397 {
398 // determine the filename of the presentation state
399 OFCondition status = lockDatabase();
400 if (status != EC_Normal)
401 {
402 DCMPSTAT_LOGFILE("Load presentation state from database failed: could not lock index file");
403 return status;
404 }
405 const char *filename = getFilename(studyUID, seriesUID, instanceUID);
406 if (filename==NULL)
407 {
408 DCMPSTAT_LOGFILE("Load presentation state from database failed: UIDs not in index file");
409 return EC_IllegalCall;
410 }
411
412 // load the presentation state
413 DcmFileFormat *pstate = NULL;
414 DVPresentationState *newState = new DVPresentationState(OFstatic_cast(DiDisplayFunction **, displayFunction),
415 minimumPrintBitmapWidth, minimumPrintBitmapHeight, maximumPrintBitmapWidth, maximumPrintBitmapHeight,
416 maximumPreviewImageWidth, maximumPreviewImageHeight);
417 if (newState==NULL)
418 {
419 DCMPSTAT_LOGFILE("Load presentation state from database failed: memory exhausted");
420 return EC_MemoryExhausted;
421 }
422
423 if ((EC_Normal == (status = DVPSHelper::loadFileFormat(filename, pstate)))&&(pstate))
424 {
425 DcmDataset *dataset = pstate->getDataset();
426 if (dataset) status = newState->read(*dataset); else status = EC_CorruptedData;
427 }
428 if (status == EC_Normal)
429 {
430 // access the first image reference in the presentation state
431 OFString ofstudyUID, ofseriesUID, ofsopclassUID, ofinstanceUID, offrames, aetitle, mediaID, mediaUID;
432 status = newState->getImageReference(0, ofstudyUID, ofseriesUID, ofsopclassUID, ofinstanceUID,
433 offrames, aetitle, mediaID, mediaUID);
434
435 // we could do something fancy with the retrieve AE title and the storage media ID here,
436 // but we just assume that the referenced image is in our local database.
437 if (EC_Normal == status)
438 {
439 // determine the filename of the referenced image
440 const char *imagefilename = NULL;
441 imagefilename = getFilename(ofstudyUID.c_str(), ofseriesUID.c_str(), ofinstanceUID.c_str());
442
443 // load the image file and attach it
444 if (imagefilename)
445 {
446 DcmFileFormat *fimage = NULL;
447 if ((EC_Normal == (status = DVPSHelper::loadFileFormat(imagefilename, fimage)))&&(fimage))
448 {
449 DcmDataset *dataset = pstate->getDataset();
450 if (dataset)
451 {
452 status = newState->attachImage(fimage, OFFalse);
453 if (EC_Normal == status)
454 {
455 exchangeImageAndPState(newState, fimage, pstate);
456 imageInDatabase = OFTrue;
457 if (changeStatus)
458 {
459 // mark pstate and (first) image reviewed
460 instanceReviewed(studyUID, seriesUID, instanceUID);
461 instanceReviewed(ofstudyUID.c_str(), ofseriesUID.c_str(), ofinstanceUID.c_str());
462 }
463 }
464 } else status = EC_CorruptedData;
465 }
466 if (status!=EC_Normal)
467 {
468 delete fimage;
469 DCMPSTAT_LOGFILE("Load presentation state from database failed: could not read image data");
470 }
471 } else {
472 status = EC_IllegalCall; // no valid image filename
473 DCMPSTAT_LOGFILE("Load presentation state from database failed: referenced image not in index file");
474 }
475 }
476 } else
477 DCMPSTAT_LOGFILE("Load presentation state from database failed: could not read fileformat");
478 if (status!=EC_Normal)
479 {
480 delete pstate;
481 delete newState;
482 }
483 return status;
484 }
485
486
loadPState(const char * pstName,const char * imgName)487 OFCondition DVInterface::loadPState(const char *pstName,
488 const char *imgName)
489 {
490 OFCondition status = EC_IllegalCall;
491 DcmFileFormat *pstate = NULL;
492 DcmFileFormat *image = pDicomImage; // default: do not replace image if image filename is NULL
493 DVPresentationState *newState = new DVPresentationState(OFstatic_cast(DiDisplayFunction **, displayFunction),
494 minimumPrintBitmapWidth, minimumPrintBitmapHeight, maximumPrintBitmapWidth, maximumPrintBitmapHeight,
495 maximumPreviewImageWidth, maximumPreviewImageHeight);
496 if (newState==NULL)
497 {
498 DCMPSTAT_LOGFILE("Load presentation state from file failed: memory exhausted");
499 return EC_MemoryExhausted;
500 }
501
502 if ((status = DVPSHelper::loadFileFormat(pstName, pstate)) == EC_Normal)
503 {
504 if ((imgName == NULL) || ((status = DVPSHelper::loadFileFormat(imgName, image)) == EC_Normal))
505 {
506 if ((pstate)&&(image))
507 {
508 DcmDataset *dataset = pstate->getDataset();
509 if (dataset)
510 {
511 if (EC_Normal == (status = newState->read(*dataset)))
512 status = newState->attachImage(image, OFFalse);
513 if (EC_Normal == status)
514 {
515 exchangeImageAndPState(newState, image, pstate);
516 imageInDatabase = OFFalse;
517 }
518 } else status = EC_CorruptedData;
519 } else status = EC_IllegalCall;
520 if (status != EC_Normal)
521 DCMPSTAT_LOGFILE("Load presentation state from file failed: invalid data structures");
522 } else
523 DCMPSTAT_LOGFILE("Load presentation state from file failed: could not load image");
524 } else
525 DCMPSTAT_LOGFILE("Load presentation state from file failed: could not read fileformat");
526 if (status != EC_Normal)
527 {
528 delete newState;
529 if (image != pDicomImage)
530 delete image;
531 delete pstate;
532 }
533 return status;
534 }
535
536
loadStructuredReport(const char * studyUID,const char * seriesUID,const char * instanceUID,OFBool changeStatus)537 OFCondition DVInterface::loadStructuredReport(const char *studyUID,
538 const char *seriesUID,
539 const char *instanceUID,
540 OFBool changeStatus)
541 {
542 OFCondition status = EC_IllegalCall;
543 if (studyUID && seriesUID && instanceUID)
544 {
545 if (lockDatabase() == EC_Normal)
546 {
547 const char *filename = getFilename(studyUID, seriesUID, instanceUID);
548 if (filename)
549 {
550 if ((status = loadStructuredReport(filename)) == EC_Normal)
551 {
552 if (changeStatus)
553 instanceReviewed(studyUID, seriesUID, instanceUID);
554 }
555 } else
556 DCMPSTAT_LOGFILE("Load structured report from database failed: UIDs not in index file");
557 } else
558 DCMPSTAT_LOGFILE("Load structured report from database failed: could not lock index file");
559 } else
560 DCMPSTAT_LOGFILE("Load structured report from database failed: invalid UIDs");
561 return status;
562 }
563
564
loadStructuredReport(const char * filename)565 OFCondition DVInterface::loadStructuredReport(const char *filename)
566 {
567 OFCondition status = EC_IllegalCall;
568 DcmFileFormat *fileformat = NULL;
569 DSRDocument *newReport = new DSRDocument();
570 if (newReport == NULL)
571 {
572 DCMPSTAT_LOGFILE("Load structured report from file failed: memory exhausted");
573 return EC_MemoryExhausted;
574 }
575
576 if ((status = DVPSHelper::loadFileFormat(filename, fileformat)) == EC_Normal)
577 {
578 if (fileformat)
579 {
580 DcmDataset *dataset = fileformat->getDataset();
581 if (dataset)
582 {
583 if ((status = newReport->read(*dataset, DSRTypes::RF_readDigitalSignatures)) == EC_Normal)
584 {
585 delete pReport;
586 pReport = newReport;
587 if (pSignatureHandler)
588 {
589 pSignatureHandler->updateDigitalSignatureInformation(*dataset, DVPSS_structuredReport, OFTrue);
590 /* check whether loaded report is 'finalized' (certain attributes are digitally signed) */
591 DcmAttributeTag tagList(DcmTag(0, 0) /* irrelevant value */);
592 tagList.putTagVal(DCM_SOPInstanceUID, 0);
593 tagList.putTagVal(DCM_VerifyingObserverSequence, 1);
594 tagList.putTagVal(DCM_InstanceCreationDate, 2);
595 tagList.putTagVal(DCM_InstanceCreationTime, 3);
596 tagList.putTagVal(DCM_InstanceCreatorUID, 4);
597 if (pSignatureHandler->attributesSigned(*dataset, tagList))
598 pReport->finalizeDocument();
599 }
600 }
601 } else
602 status = EC_CorruptedData;
603 } else
604 status = EC_IllegalCall;
605 if (status != EC_Normal)
606 DCMPSTAT_LOGFILE("Load structured report from file failed: invalid data structures");
607 } else
608 DCMPSTAT_LOGFILE("Load structured report from file failed: could not read fileformat");
609 if (status != EC_Normal)
610 delete newReport;
611 delete fileformat;
612 return status;
613 }
614
615
loadSRTemplate(const char * reportID)616 OFCondition DVInterface::loadSRTemplate(const char *reportID)
617 {
618 OFCondition result = EC_IllegalCall;
619 if (reportID)
620 {
621 const char *srfile = getReportFilename(reportID);
622 if (srfile)
623 {
624 OFString filename = getReportFolder(); // never NULL.
625 filename += PATH_SEPARATOR;
626 filename += srfile;
627 result = loadStructuredReport(filename.c_str());
628 if (result == EC_Normal)
629 {
630 if (pReport != NULL)
631 {
632 /* date/time is filled automatically if empty */
633 pReport->setContentDate("");
634 pReport->setContentTime("");
635 /* generate new study/series/instance UID and fill date/time */
636 pReport->createNewStudy();
637 }
638 } else
639 DCMPSTAT_LOGFILE("Load structured reporting 'template' from file failed");
640 }
641 }
642 return result;
643 }
644
645
savePState(OFBool replaceSOPInstanceUID)646 OFCondition DVInterface::savePState(OFBool replaceSOPInstanceUID)
647 {
648 // release database lock since we are using the DB module directly
649 releaseDatabase();
650
651 if (pState==NULL) return EC_IllegalCall;
652 const char *instanceUID = NULL;
653 if (replaceSOPInstanceUID) instanceUID=pState->createInstanceUID(); else instanceUID=pState->getInstanceUID();
654 if (instanceUID==NULL) return EC_IllegalCall;
655
656 DcmQueryRetrieveDatabaseStatus dbStatus(STATUS_Success);
657 OFCondition result=EC_Normal;
658 char imageFileName[MAXPATHLEN+1];
659
660 DcmQueryRetrieveIndexDatabaseHandle dbhandle(getDatabaseFolder(), PSTAT_MAXSTUDYCOUNT, PSTAT_STUDYSIZE, result);
661 if (result.bad())
662 {
663 DCMPSTAT_LOGFILE("Save presentation state to database failed: could not lock index file");
664 return EC_IllegalCall;
665 }
666
667 if (dbhandle.makeNewStoreFileName(UID_GrayscaleSoftcopyPresentationStateStorage, instanceUID, imageFileName, sizeof(imageFileName)).good())
668 {
669 // now store presentation state as filename
670 result = savePState(imageFileName, OFFalse);
671 if (EC_Normal==result)
672 {
673 if (dbhandle.storeRequest(UID_GrayscaleSoftcopyPresentationStateStorage,
674 instanceUID, imageFileName, &dbStatus).bad())
675 {
676 result = EC_IllegalCall;
677 DCMPSTAT_LOGFILE("Save presentation state to database failed: could not register in index file");
678 DCMPSTAT_WARN("Unable to register presentation state '" << imageFileName << "' in database");
679 }
680 }
681 }
682 if (pDicomImage != NULL)
683 {
684 DcmDataset *dset = pDicomImage->getDataset();
685 if (dset != NULL)
686 {
687 DIC_UI sopClass;
688 DIC_UI instanceUID2;
689 DIC_UI seriesUID;
690 DIC_UI studyUID;
691 if (DU_getStringDOElement(dset, DCM_SOPClassUID, sopClass, sizeof(sopClass)) &&
692 DU_getStringDOElement(dset, DCM_SOPInstanceUID, instanceUID2, sizeof(instanceUID2)) &&
693 DU_getStringDOElement(dset, DCM_SeriesInstanceUID, seriesUID, sizeof(seriesUID)) &&
694 DU_getStringDOElement(dset, DCM_StudyInstanceUID, studyUID, sizeof(studyUID)) &&
695 ((!imageInDatabase) || (getSeriesStruct(studyUID, seriesUID, instanceUID2) == NULL)))
696 {
697 releaseDatabase(); /* avoid deadlocks */
698 if (dbhandle.makeNewStoreFileName(sopClass, instanceUID2, imageFileName, sizeof(imageFileName)).good())
699 {
700 // now store presentation state as filename
701 result = saveCurrentImage(imageFileName);
702 if (EC_Normal==result)
703 {
704 if (dbhandle.storeRequest(sopClass, instanceUID2, imageFileName, &dbStatus).bad())
705 {
706 result = EC_IllegalCall;
707 DCMPSTAT_LOGFILE("Save presentation state to database failed: could not register image in index file");
708 DCMPSTAT_WARN("Unable to register image '" << imageFileName << "' in database");
709 } else {
710 imageInDatabase = OFTrue;
711 }
712 }
713 }
714 }
715 }
716 }
717 return result;
718 }
719
720
savePState(const char * filename,OFBool replaceSOPInstanceUID,OFBool explicitVR)721 OFCondition DVInterface::savePState(const char *filename, OFBool replaceSOPInstanceUID, OFBool explicitVR)
722 {
723 if (pState==NULL) return EC_IllegalCall;
724 if (filename==NULL) return EC_IllegalCall;
725
726 OFCondition status = EC_IllegalCall;
727 DcmFileFormat *fileformat = new DcmFileFormat();
728 DcmDataset *dataset = NULL;
729 if (fileformat) dataset=fileformat->getDataset();
730
731 if (dataset)
732 {
733 if ((status = pState->write(*dataset, replaceSOPInstanceUID)) == EC_Normal)
734 {
735 status = DVPSHelper::saveFileFormat(filename, fileformat, explicitVR);
736
737 // replace the stored data for resetPresentationState()
738 delete pDicomPState;
739 pDicomPState = fileformat;
740 fileformat = NULL; // make sure we don't delete fileformat later
741 if (pSignatureHandler)
742 {
743 pSignatureHandler->updateDigitalSignatureInformation(*pDicomPState->getDataset(), DVPSS_presentationState, OFFalse);
744 }
745 }
746 if (status != EC_Normal)
747 DCMPSTAT_LOGFILE("Save presentation state to file failed: could not write fileformat");
748 } else {
749 DCMPSTAT_LOGFILE("Save presentation state to file failed: memory exhausted");
750 status = EC_MemoryExhausted;
751 }
752
753 delete fileformat;
754 return status;
755 }
756
757
saveCurrentImage(const char * filename,OFBool explicitVR)758 OFCondition DVInterface::saveCurrentImage(const char *filename, OFBool explicitVR)
759 {
760 if (filename==NULL) return EC_IllegalCall;
761 if (pDicomImage==NULL) return EC_IllegalCall;
762 OFCondition result = DVPSHelper::saveFileFormat(filename, pDicomImage, explicitVR);
763 if (result != EC_Normal)
764 DCMPSTAT_LOGFILE("Save image to file failed: could not write fileformat");
765 return result;
766 }
767
768
saveStructuredReport()769 OFCondition DVInterface::saveStructuredReport()
770 {
771 // release database lock since we are using the DB module directly
772 releaseDatabase();
773
774 if (pReport == NULL)
775 return EC_IllegalCall;
776 OFString sopClassUID;
777 if (pReport->getSOPClassUID(sopClassUID).bad() || sopClassUID.empty())
778 return EC_IllegalCall;
779 OFString instanceUID;
780 if (pReport->getSOPInstanceUID(instanceUID).bad() || instanceUID.empty())
781 return EC_IllegalCall;
782
783 DcmQueryRetrieveDatabaseStatus dbStatus(STATUS_Success);
784 char filename[MAXPATHLEN + 1];
785 OFCondition result = EC_Normal;
786
787 DcmQueryRetrieveIndexDatabaseHandle dbhandle(getDatabaseFolder(), PSTAT_MAXSTUDYCOUNT, PSTAT_STUDYSIZE, result);
788 if (result.bad())
789 {
790 DCMPSTAT_LOGFILE("Save structured report to database failed: could not lock index file");
791 return EC_IllegalCall;
792 }
793
794 if (dbhandle.makeNewStoreFileName(sopClassUID.c_str(), instanceUID.c_str(), filename, sizeof(filename)).good())
795 {
796 // now store presentation state as filename
797 result = saveStructuredReport(filename);
798 if (EC_Normal == result)
799 {
800 if (dbhandle.storeRequest(sopClassUID.c_str(), instanceUID.c_str(), filename, &dbStatus).bad())
801 {
802 result = EC_IllegalCall;
803 DCMPSTAT_LOGFILE("Save structured report to database failed: could not register in index file");
804 DCMPSTAT_WARN("Unable to register structured report '" << filename << "' in database");
805 }
806 }
807 }
808 return result;
809 }
810
811
saveStructuredReport(const char * filename,OFBool explicitVR)812 OFCondition DVInterface::saveStructuredReport(const char *filename, OFBool explicitVR)
813 {
814 if (pReport==NULL) return EC_IllegalCall;
815 if (filename==NULL) return EC_IllegalCall;
816
817 OFCondition status = EC_IllegalCall;
818 DcmFileFormat *fileformat = new DcmFileFormat();
819 DcmDataset *dataset = NULL;
820 if (fileformat) dataset=fileformat->getDataset();
821
822 if (dataset)
823 {
824 /* always add information about private OFFIS DCMTK Coding Scheme */
825 pReport->getCodingSchemeIdentification().addPrivateDcmtkCodingScheme();
826 if ((status = pReport->write(*dataset)) == EC_Normal)
827 {
828 status = DVPSHelper::saveFileFormat(filename, fileformat, explicitVR);
829 if (pSignatureHandler)
830 {
831 pSignatureHandler->updateDigitalSignatureInformation(*dataset, DVPSS_structuredReport, OFFalse);
832 }
833 }
834 if (status != EC_Normal)
835 DCMPSTAT_LOGFILE("Save structured report to file failed: could not write fileformat");
836 } else {
837 DCMPSTAT_LOGFILE("Save structured report to file failed: memory exhausted");
838 status = EC_MemoryExhausted;
839 }
840
841 delete fileformat;
842 return status;
843 }
844
845
addImageReferenceToPState(const char * studyUID,const char * seriesUID,const char * instanceUID)846 OFCondition DVInterface::addImageReferenceToPState(const char *studyUID, const char *seriesUID, const char *instanceUID)
847 {
848 OFCondition status = EC_IllegalCall;
849 if (pState && studyUID && seriesUID && instanceUID)
850 {
851 OFString study = pState->getStudyUID();
852 if (study == studyUID)
853 {
854 if (lockDatabase() == EC_Normal)
855 {
856 const char *filename = getFilename(studyUID, seriesUID, instanceUID);
857 if (filename)
858 {
859 DcmFileFormat *image = NULL;
860 if ((status = DVPSHelper::loadFileFormat(filename, image)) == EC_Normal)
861 {
862 status = EC_CorruptedData;
863 if (image)
864 {
865 DcmDataset *dataset = image->getDataset();
866 if (dataset)
867 status = pState->addImageReference(*dataset);
868 }
869 if (status != EC_Normal)
870 DCMPSTAT_LOGFILE("Add image reference to presentation state failed: invalid data structures");
871 } else
872 DCMPSTAT_LOGFILE("Add image reference to presentation state failed: could not read fileformat");
873 delete image;
874 } else
875 DCMPSTAT_LOGFILE("Add image reference to presentation state failed: UIDs not in index file");
876 } else
877 DCMPSTAT_LOGFILE("Add image reference to presentation state failed: could not lock index file");
878 } else
879 DCMPSTAT_LOGFILE("Add image reference to presentation state failed: not the same study UID");
880 } else
881 DCMPSTAT_LOGFILE("Add image reference to presentation state failed: invalid UIDs");
882 return status;
883 }
884
885
getNumberOfImageReferences()886 size_t DVInterface::getNumberOfImageReferences()
887 {
888 if (pState != NULL)
889 return pState->numberOfImageReferences();
890 return 0;
891 }
892
893
exchangeImageAndPState(DVPresentationState * newState,DcmFileFormat * image,DcmFileFormat * state)894 OFCondition DVInterface::exchangeImageAndPState(DVPresentationState *newState, DcmFileFormat *image, DcmFileFormat *state)
895 {
896 if (newState==NULL) return EC_IllegalCall;
897 if (image==NULL) return EC_IllegalCall;
898 if (pState != newState)
899 {
900 delete pState;
901 delete pStoredPState;
902 delete pDicomPState;
903 pState = newState;
904 pStoredPState = NULL;
905 pDicomPState = state;
906 if (pSignatureHandler)
907 {
908 if (pDicomPState) pSignatureHandler->updateDigitalSignatureInformation(*pDicomPState->getDataset(), DVPSS_presentationState, OFTrue);
909 else pSignatureHandler->disableDigitalSignatureInformation(DVPSS_presentationState);
910 }
911 }
912 if (pDicomImage != image)
913 {
914 delete pDicomImage; // delete only if different
915 pDicomImage = image;
916 if (pSignatureHandler)
917 {
918 pSignatureHandler->updateDigitalSignatureInformation(*pDicomImage->getDataset(), DVPSS_image, OFTrue);
919 }
920 }
921 return EC_Normal;
922 }
923
924
resetPresentationState()925 OFCondition DVInterface::resetPresentationState()
926 {
927 DVPresentationState *newState = new DVPresentationState(displayFunction,
928 minimumPrintBitmapWidth, minimumPrintBitmapHeight, maximumPrintBitmapWidth, maximumPrintBitmapHeight,
929 maximumPreviewImageWidth, maximumPreviewImageHeight);
930 if (newState==NULL) return EC_MemoryExhausted;
931
932 OFCondition status = EC_Normal;
933 if ((pDicomImage)&&(pDicomPState))
934 {
935 // both image and presentation state are present
936 DcmDataset *dataset = pDicomPState->getDataset();
937 if (dataset)
938 {
939 if (EC_Normal == (status = newState->read(*dataset))) status = newState->attachImage(pDicomImage, OFFalse);
940 if (EC_Normal == status)
941 {
942 if (pState) delete pState;
943 if (pStoredPState) delete pStoredPState;
944 pState = newState;
945 pStoredPState = NULL; // return to original pstate
946 }
947 } else status = EC_IllegalCall;
948 }
949 else if (pDicomImage)
950 {
951 // only image is present
952 DcmDataset *dataset = pDicomImage->getDataset();
953 if (dataset)
954 {
955 if (EC_Normal == (status = newState->createFromImage(*dataset))) status = newState->attachImage(pDicomImage, OFFalse);
956 if (EC_Normal == status)
957 {
958 if (pState) delete pState;
959 if (pStoredPState) delete pStoredPState;
960 pState = newState;
961 pStoredPState = NULL;
962 }
963 } else status = EC_IllegalCall;
964 }
965 if (EC_Normal != status) delete newState;
966 return status;
967 }
968
969
saveCurrentPStateForReset()970 OFCondition DVInterface::saveCurrentPStateForReset()
971 {
972 OFCondition status = EC_IllegalCall;
973 if (pState != NULL)
974 {
975 DcmFileFormat *fileformat = new DcmFileFormat();
976 if (fileformat != NULL)
977 {
978 DcmDataset *dataset = fileformat->getDataset();
979 if (dataset)
980 {
981 status = pState->write(*dataset, OFFalse); // write current state to 'reset' dataset
982 if (status == EC_Normal)
983 {
984 delete pDicomPState;
985 pDicomPState = fileformat;
986 fileformat = NULL; // avoid deletion of pDicomPState a few lines later
987 }
988 } else status = EC_MemoryExhausted;
989 } else status = EC_MemoryExhausted;
990 delete fileformat;
991 }
992 return status;
993 }
994
995
getNumberOfPStates()996 Uint32 DVInterface::getNumberOfPStates()
997 {
998 if (createPStateCache())
999 {
1000 DVInstanceCache::ItemStruct *instance = getInstanceStruct();
1001 if ((instance != NULL) && ((instance->Type == DVPSI_image) || (instance->Type == DVPSI_hardcopyGrayscale)))
1002 return OFstatic_cast(Uint32, instance->List.size());
1003 }
1004 return 0;
1005 }
1006
1007
selectPState(Uint32 idx,OFBool changeStatus)1008 OFCondition DVInterface::selectPState(Uint32 idx, OFBool changeStatus)
1009 {
1010 if (createPStateCache())
1011 {
1012 DVInstanceCache::ItemStruct *instance = getInstanceStruct();
1013 if ((instance != NULL) && ((instance->Type == DVPSI_image) || (instance->Type == DVPSI_hardcopyGrayscale)))
1014 {
1015 OFListIterator(DVInstanceCache::ItemStruct *) iter = instance->List.begin();
1016 OFListIterator(DVInstanceCache::ItemStruct *) last = instance->List.end();
1017 while (iter != last)
1018 {
1019 if (idx == 0)
1020 {
1021 DVInstanceCache::ItemStruct *pstate = (*iter);
1022 if (pstate != NULL)
1023 {
1024 OFCondition status = EC_IllegalCall;
1025 if (pDicomImage == NULL)
1026 status = loadPState(pstate->Filename.c_str(), instance->Filename.c_str());
1027 else
1028 status = loadPState(pstate->Filename.c_str());
1029 if ((status == EC_Normal) && changeStatus)
1030 instanceReviewed(pstate->Pos);
1031 return status;
1032 }
1033 }
1034 idx--;
1035 ++iter;
1036 }
1037 }
1038 }
1039 return EC_IllegalCall;
1040 }
1041
1042
getPStateDescription(Uint32 idx)1043 const char *DVInterface::getPStateDescription(Uint32 idx)
1044 {
1045 if (createPStateCache())
1046 {
1047 DVInstanceCache::ItemStruct *instance = getInstanceStruct();
1048 if ((instance != NULL) && ((instance->Type == DVPSI_image) || (instance->Type == DVPSI_hardcopyGrayscale)))
1049 {
1050 OFListIterator(DVInstanceCache::ItemStruct *) iter = instance->List.begin();
1051 OFListIterator(DVInstanceCache::ItemStruct *) last = instance->List.end();
1052 while (iter != last)
1053 {
1054 if (idx == 0)
1055 {
1056 DVInstanceCache::ItemStruct *pstate = (*iter);
1057 if (pstate != NULL)
1058 return pstate->Description.c_str();
1059 }
1060 idx--;
1061 ++iter;
1062 }
1063 }
1064 }
1065 return NULL;
1066 }
1067
1068
getPStateLabel(Uint32 idx)1069 const char *DVInterface::getPStateLabel(Uint32 idx)
1070 {
1071 if (createPStateCache())
1072 {
1073 DVInstanceCache::ItemStruct *instance = getInstanceStruct();
1074 if ((instance != NULL) && ((instance->Type == DVPSI_image) || (instance->Type == DVPSI_hardcopyGrayscale)))
1075 {
1076 OFListIterator(DVInstanceCache::ItemStruct *) iter = instance->List.begin();
1077 OFListIterator(DVInstanceCache::ItemStruct *) last = instance->List.end();
1078 while (iter != last)
1079 {
1080 if (idx == 0)
1081 {
1082 DVInstanceCache::ItemStruct *pstate = (*iter);
1083 if (pstate != NULL)
1084 return pstate->Label.c_str();
1085 }
1086 idx--;
1087 ++iter;
1088 }
1089 }
1090 }
1091 return NULL;
1092 }
1093
1094
disablePState()1095 OFCondition DVInterface::disablePState()
1096 {
1097 OFCondition status = EC_IllegalCall;
1098 if ((pState != NULL) && (pStoredPState == NULL))
1099 {
1100 if (pDicomImage != NULL)
1101 {
1102 DcmDataset *dataset = pDicomImage->getDataset();
1103 if (dataset != NULL)
1104 {
1105 DVPresentationState *newState = new DVPresentationState(displayFunction,
1106 minimumPrintBitmapWidth, minimumPrintBitmapHeight, maximumPrintBitmapWidth, maximumPrintBitmapHeight,
1107 maximumPreviewImageWidth, maximumPreviewImageHeight);
1108 if (newState != NULL)
1109 {
1110 if ((status = newState->createFromImage(*dataset)) == EC_Normal)
1111 {
1112 if ((status = newState->attachImage(pDicomImage, OFFalse)) == EC_Normal)
1113 {
1114 pStoredPState = pState;
1115 pState = newState;
1116 return EC_Normal;
1117 }
1118 }
1119 delete newState;
1120 }
1121 }
1122 }
1123 }
1124 return status;
1125 }
1126
1127
enablePState()1128 OFCondition DVInterface::enablePState()
1129 {
1130 if ((pState != NULL) && (pStoredPState != NULL))
1131 {
1132 delete pState;
1133 pState = pStoredPState;
1134 pStoredPState = NULL;
1135 return EC_Normal;
1136 }
1137 return EC_IllegalCall;
1138 }
1139
1140
getStudyStruct(const char * studyUID,const char * seriesUID)1141 DVStudyCache::ItemStruct *DVInterface::getStudyStruct(const char *studyUID,
1142 const char *seriesUID)
1143 {
1144 if (createIndexCache())
1145 {
1146 if (studyUID)
1147 {
1148 if (idxCache.isElem(studyUID))
1149 {
1150 DVStudyCache::ItemStruct *study = idxCache.getItem();
1151 if ((seriesUID == NULL) || (study->List.isElem(seriesUID)))
1152 return study;
1153 }
1154 } else
1155 return idxCache.getItem(); // current study
1156 }
1157 return NULL;
1158 }
1159
1160
getSeriesStruct(const char * studyUID,const char * seriesUID,const char * instanceUID)1161 DVSeriesCache::ItemStruct *DVInterface::getSeriesStruct(const char *studyUID,
1162 const char *seriesUID,
1163 const char *instanceUID)
1164 {
1165 if ((studyUID && seriesUID) || (!studyUID && !seriesUID))
1166 {
1167 DVStudyCache::ItemStruct *study = getStudyStruct(studyUID, seriesUID);
1168 if (study != NULL)
1169 {
1170 DVSeriesCache::ItemStruct *series = study->List.getItem();
1171 if (series != NULL)
1172 {
1173 if ((instanceUID == NULL) || (series->List.isElem(instanceUID)))
1174 return series;
1175 }
1176 }
1177 }
1178 return NULL;
1179 }
1180
1181
getInstanceStruct(const char * studyUID,const char * seriesUID,const char * instanceUID)1182 DVInstanceCache::ItemStruct *DVInterface::getInstanceStruct(const char *studyUID,
1183 const char *seriesUID,
1184 const char *instanceUID)
1185 {
1186 if ((studyUID && seriesUID && instanceUID) || (!studyUID && !seriesUID && !instanceUID))
1187 {
1188 DVSeriesCache::ItemStruct *series = getSeriesStruct(studyUID, seriesUID, instanceUID);
1189 if (series != NULL)
1190 return series->List.getItem();
1191 }
1192 return NULL;
1193 }
1194
1195
getFilename(const char * studyUID,const char * seriesUID,const char * instanceUID)1196 const char *DVInterface::getFilename(const char *studyUID,
1197 const char *seriesUID,
1198 const char *instanceUID)
1199 {
1200 DVSeriesCache::ItemStruct *series = getSeriesStruct(studyUID, seriesUID, instanceUID);
1201 if (series != NULL)
1202 return series->List.getFilename();
1203 return NULL;
1204 }
1205
1206
lockDatabase()1207 OFCondition DVInterface::lockDatabase()
1208 {
1209 if (pHandle) return EC_Normal; // may be called multiple times
1210
1211 OFCondition result;
1212 pHandle = new DcmQueryRetrieveIndexDatabaseHandle(getDatabaseFolder(), PSTAT_MAXSTUDYCOUNT, PSTAT_STUDYSIZE, result);
1213 if (result.good())
1214 {
1215 lockingMode = OFFalse;
1216 if (pHandle->DB_lock(OFFalse).good())
1217 {
1218 if (databaseIndexFile.empty())
1219 databaseIndexFile = pHandle->getIndexFilename();
1220 return EC_Normal;
1221 }
1222 }
1223 return EC_IllegalCall;
1224 }
1225
1226
lockExclusive()1227 OFCondition DVInterface::lockExclusive()
1228 {
1229 if (pHandle && lockingMode) return EC_Normal;
1230 OFCondition result = EC_Normal;
1231 if (pHandle == NULL) result = lockDatabase();
1232 if (result.good())
1233 {
1234 // we now have a shared lock.
1235 pHandle->DB_unlock();
1236 if (pHandle->DB_lock(OFTrue).good())
1237 lockingMode = OFTrue;
1238 else
1239 result = EC_IllegalCall;
1240 }
1241 return result;
1242 }
1243
1244
unlockExclusive()1245 OFCondition DVInterface::unlockExclusive()
1246 {
1247 if (pHandle && lockingMode)
1248 {
1249 if (pHandle->DB_unlock().good())
1250 {
1251 delete pHandle;
1252 pHandle=NULL;
1253 lockingMode=OFFalse;
1254 clearIndexCache();
1255 return EC_Normal;
1256 }
1257 }
1258 return EC_IllegalCall;
1259 }
1260
1261
releaseDatabase()1262 OFCondition DVInterface::releaseDatabase()
1263 {
1264 if (pHandle == NULL) return EC_Normal;
1265 OFCondition cond = pHandle->DB_unlock();
1266 if (cond.good())
1267 {
1268 delete pHandle;
1269 pHandle = NULL;
1270 clearIndexCache();
1271 }
1272 return cond;
1273 }
1274
1275
resetDatabaseReferenceTime()1276 void DVInterface::resetDatabaseReferenceTime()
1277 {
1278 // set index file modification time to "yesterday" to make sure
1279 // we notice any change even if different processes have minor
1280 // date/time differences (i.e. over NFS)
1281 #ifdef HAVE_DECLARATION_STRUCT_UTIMBUF
1282 struct utimbuf utime_buf;
1283 utime_buf.actime = OFstatic_cast(time_t, referenceTime);
1284 utime_buf.modtime = OFstatic_cast(time_t, referenceTime);
1285 if (0 != utime(databaseIndexFile.c_str(), &utime_buf))
1286 #else
1287 // some old platforms use the prototype int utime(char *file, time_t timep[])
1288 time_t utime_buf[2];
1289 utime_buf[0] = OFstatic_cast(time_t, referenceTime);
1290 utime_buf[1] = OFstatic_cast(time_t, referenceTime);
1291 if (0 != utime(OFconst_cast(char *, databaseIndexFile.c_str()), utime_buf))
1292 #endif
1293 {
1294 DCMPSTAT_WARN("Cannot set database index file modification time");
1295 } else {
1296 struct stat stat_buf;
1297 if (0 == stat(databaseIndexFile.c_str(), &stat_buf))
1298 {
1299 referenceTime = OFstatic_cast(unsigned long, stat_buf.st_mtime);
1300 }
1301 }
1302 }
1303
1304
newInstancesReceived()1305 OFBool DVInterface::newInstancesReceived()
1306 {
1307 if (databaseIndexFile.empty())
1308 {
1309 if (pHandle == NULL)
1310 {
1311 lockDatabase(); // derives databaseIndexFile
1312 releaseDatabase();
1313 }
1314 }
1315
1316 if (!databaseIndexFile.empty())
1317 {
1318 struct stat stat_buf;
1319 if (0== stat(databaseIndexFile.c_str(), &stat_buf))
1320 {
1321 if (OFstatic_cast(unsigned long, stat_buf.st_mtime) == referenceTime) return OFFalse;
1322 }
1323
1324 resetDatabaseReferenceTime();
1325 }
1326 return OFTrue; // default
1327 }
1328
1329
clearIndexCache()1330 void DVInterface::clearIndexCache()
1331 {
1332 idxCache.clear();
1333 clearIndexRecord(idxRec, idxRecPos);
1334 }
1335
1336
createIndexCache()1337 OFBool DVInterface::createIndexCache()
1338 {
1339 if (lockDatabase() == EC_Normal)
1340 {
1341 if (idxCache.empty())
1342 {
1343 int counter = 0;
1344 pHandle->DB_IdxInitLoop(&counter);
1345 IdxRecord record;
1346 while (pHandle->DB_IdxGetNext(&counter, &record).good())
1347 {
1348 if (!idxCache.isElem(record.StudyInstanceUID))
1349 idxCache.addItem(record.StudyInstanceUID);
1350 DVStudyCache::ItemStruct *study = idxCache.getItem();
1351 if (study != NULL)
1352 {
1353 if (!study->List.isElem(record.SeriesInstanceUID))
1354 study->List.addItem(record.SeriesInstanceUID);
1355 DVSeriesCache::ItemStruct *series = study->List.getItem();
1356 if (series != NULL)
1357 {
1358 if (!series->List.isElem(record.SOPInstanceUID))
1359 {
1360 DVPSInstanceType type = DVPSI_image;
1361 if (DSRTypes::sopClassUIDToDocumentType(record.SOPClassUID) != DSRTypes::DT_invalid)
1362 type = DVPSI_structuredReport;
1363 else if (strcmp(record.Modality, "PR") == 0)
1364 type = DVPSI_presentationState;
1365 else if (strcmp(record.Modality, "SR") == 0)
1366 type = DVPSI_structuredReport;
1367 else if (strcmp(record.Modality, "HC") == 0)
1368 type =DVPSI_hardcopyGrayscale;
1369 else if (strcmp(record.Modality, "STORED_PRINT") == 0)
1370 type = DVPSI_storedPrint;
1371 series->List.addItem(record.SOPInstanceUID,
1372 counter,
1373 OFstatic_cast(DVIFhierarchyStatus, record.hstat),
1374 type,
1375 record.ImageSize,
1376 record.filename);
1377 if (series->Type == DVPSI_image)
1378 series->Type = type; // series contains only one type of instances
1379 }
1380 }
1381 }
1382 }
1383 updateStatusCache();
1384 }
1385 return OFTrue;
1386 }
1387 return OFFalse;
1388 }
1389
1390
createPStateCache()1391 OFBool DVInterface::createPStateCache()
1392 {
1393 DVStudyCache::ItemStruct *study = getStudyStruct();
1394 if (study != NULL)
1395 {
1396 DVSeriesCache::ItemStruct *series = study->List.getItem();
1397 if (series != NULL)
1398 {
1399 DVInstanceCache::ItemStruct *instance = series->List.getItem();
1400 if ((instance != NULL) && ((instance->Type == DVPSI_image) || (instance->Type == DVPSI_hardcopyGrayscale)))
1401 {
1402 if (!instance->Checked) // is current instance already checked?
1403 {
1404 if (instance->List.empty())
1405 {
1406 OFString seriesUID = series->UID;
1407 OFString instanceUID = instance->UID;
1408 if (study->List.gotoFirst())
1409 {
1410 do { /* for all series */
1411 if (study->List.getType() == DVPSI_presentationState)
1412 {
1413 series = study->List.getItem();
1414 if (series != NULL)
1415 {
1416 if (series->List.gotoFirst())
1417 {
1418 do { /* for all instances */
1419 if (series->List.getType() == DVPSI_presentationState)
1420 {
1421 DcmFileFormat *pstate = NULL;
1422 if ((DVPSHelper::loadFileFormat(series->List.getFilename(), pstate) == EC_Normal) && pstate)
1423 {
1424 DcmDataset *dataset = pstate->getDataset();
1425 DVPSReferencedSeries_PList plist;
1426 if (dataset && (plist.read(*dataset) == EC_Normal) && plist.isValid())
1427 {
1428 if (plist.findImageReference(seriesUID.c_str(), instanceUID.c_str()))
1429 {
1430 DVInstanceCache::ItemStruct *reference = series->List.getItem();
1431 if (reference != NULL)
1432 {
1433 DcmStack stack;
1434 if (dataset->search(DCM_ContentDescription, stack, ESM_fromHere, OFFalse) == EC_Normal)
1435 {
1436 char *value = NULL;
1437 if ((*OFstatic_cast(DcmLongString *, stack.top())).getString(value) == EC_Normal)
1438 reference->Description = value;
1439 }
1440 stack.clear();
1441 if (dataset->search(DCM_ContentLabel, stack, ESM_fromHere, OFFalse) == EC_Normal)
1442 {
1443 char *value = NULL;
1444 if ((*OFstatic_cast(DcmLongString *, stack.top())).getString(value) == EC_Normal)
1445 reference->Label = value;
1446 }
1447 instance->List.push_back(reference);
1448 }
1449 }
1450 }
1451 }
1452 delete pstate;
1453 }
1454 } while (series->List.gotoNext());
1455 }
1456 series->List.reset(); // set iterator to old position
1457 }
1458 }
1459 } while (study->List.gotoNext());
1460 }
1461 study->List.reset(); // set iterator to old position
1462 }
1463 instance->Checked = OFTrue; // do not check twice
1464 }
1465 return OFTrue;
1466 }
1467 }
1468 }
1469 return OFFalse;
1470 }
1471
1472
clearIndexRecord(IdxRecord & record,int & recpos)1473 void DVInterface::clearIndexRecord(IdxRecord &record,
1474 int &recpos)
1475 {
1476 OFBitmanipTemplate<Uint8>::zeroMem(OFreinterpret_cast(Uint8 *, &record), sizeof(idxRec));
1477 recpos = -1;
1478 }
1479
1480
readIndexRecord(const int pos,IdxRecord & record,int * oldpos)1481 OFBool DVInterface::readIndexRecord(const int pos,
1482 IdxRecord &record,
1483 int *oldpos)
1484 {
1485 if (lockDatabase() == EC_Normal)
1486 {
1487 if ((oldpos != NULL) && (pos == *oldpos)) // record already read
1488 return OFTrue;
1489 if (pHandle->DB_IdxRead(pos, &record).good())
1490 {
1491 if (oldpos != NULL)
1492 *oldpos = pos;
1493 return OFTrue;
1494 }
1495 }
1496 return OFFalse;
1497 }
1498
1499
updateStatusCache()1500 void DVInterface::updateStatusCache()
1501 {
1502 idxCache.updateStatus();
1503 }
1504
1505
getNumberOfStudies()1506 Uint32 DVInterface::getNumberOfStudies()
1507 {
1508 if (createIndexCache())
1509 return idxCache.getCount();
1510 return 0;
1511 }
1512
1513
getNumberOfSeries()1514 Uint32 DVInterface::getNumberOfSeries()
1515 {
1516 DVStudyCache::ItemStruct *study = getStudyStruct();
1517 if (study != NULL)
1518 return study->List.getCount();
1519 return 0;
1520 }
1521
1522
getNumberOfInstances()1523 Uint32 DVInterface::getNumberOfInstances()
1524 {
1525 DVSeriesCache::ItemStruct *series = getSeriesStruct();
1526 if (series != NULL)
1527 return series->List.getCount();
1528 return 0;
1529 }
1530
1531
selectStudy(Uint32 idx)1532 OFCondition DVInterface::selectStudy(Uint32 idx)
1533 {
1534 if (createIndexCache())
1535 {
1536 if (idxCache.gotoItem(idx))
1537 {
1538 DVStudyCache::ItemStruct *study = idxCache.getItem();
1539 if (study->List.gotoItem(0))
1540 {
1541 DVSeriesCache::ItemStruct *series = study->List.getItem();
1542 if (series != NULL)
1543 {
1544 if (series->List.gotoItem(0))
1545 {
1546 if (readIndexRecord(series->List.getPos(), idxRec, &idxRecPos))
1547 return EC_Normal;
1548 }
1549 }
1550 }
1551 }
1552 }
1553 return EC_IllegalCall;
1554 }
1555
1556
selectStudy(const char * studyUID)1557 OFCondition DVInterface::selectStudy(const char *studyUID)
1558 {
1559 if (studyUID)
1560 {
1561 if (createIndexCache())
1562 {
1563 if (idxCache.isElem(studyUID))
1564 {
1565 DVStudyCache::ItemStruct *study = idxCache.getItem();
1566 if (study->List.gotoItem(0))
1567 {
1568 DVSeriesCache::ItemStruct *series = study->List.getItem();
1569 if (series != NULL)
1570 {
1571 if (series->List.gotoItem(0))
1572 {
1573 if (readIndexRecord(series->List.getPos(), idxRec, &idxRecPos))
1574 return EC_Normal;
1575 }
1576 }
1577 }
1578 }
1579 }
1580 }
1581 return EC_IllegalCall;
1582 }
1583
1584
selectSeries(Uint32 idx)1585 OFCondition DVInterface::selectSeries(Uint32 idx)
1586 {
1587 DVStudyCache::ItemStruct *study = getStudyStruct();
1588 if (study != NULL)
1589 {
1590 if (study->List.gotoItem(idx))
1591 {
1592 DVSeriesCache::ItemStruct *series = study->List.getItem();
1593 if (series != NULL)
1594 {
1595 if (series->List.gotoItem(0))
1596 {
1597 if (readIndexRecord(series->List.getPos(), idxRec, &idxRecPos))
1598 return EC_Normal;
1599 }
1600 }
1601 }
1602 }
1603 return EC_IllegalCall;
1604 }
1605
1606
selectSeries(const char * seriesUID)1607 OFCondition DVInterface::selectSeries(const char *seriesUID)
1608 {
1609 if (seriesUID)
1610 {
1611 DVStudyCache::ItemStruct *study = getStudyStruct();
1612 if (study != NULL)
1613 {
1614 if (study->List.isElem(seriesUID))
1615 {
1616 DVSeriesCache::ItemStruct *series = study->List.getItem();
1617 if (series != NULL)
1618 {
1619 if (series->List.gotoItem(0))
1620 {
1621 if (readIndexRecord(series->List.getPos(), idxRec, &idxRecPos))
1622 return EC_Normal;
1623 }
1624 }
1625 }
1626 }
1627 }
1628 return EC_IllegalCall;
1629 }
1630
1631
selectInstance(Uint32 idx)1632 OFCondition DVInterface::selectInstance(Uint32 idx)
1633 {
1634 DVSeriesCache::ItemStruct *series = getSeriesStruct();
1635 if (series != NULL)
1636 {
1637 if (series->List.gotoItem(idx))
1638 {
1639 if (readIndexRecord(series->List.getPos(), idxRec, &idxRecPos))
1640 return EC_Normal;
1641 }
1642 }
1643 return EC_IllegalCall;
1644 }
1645
1646
selectInstance(const char * instanceUID)1647 OFCondition DVInterface::selectInstance(const char *instanceUID)
1648 {
1649 if (instanceUID)
1650 {
1651 DVSeriesCache::ItemStruct *series = getSeriesStruct();
1652 if (series != NULL)
1653 {
1654 if (series->List.isElem(instanceUID))
1655 {
1656 if (readIndexRecord(series->List.getPos(), idxRec, &idxRecPos))
1657 return EC_Normal;
1658 }
1659 }
1660 }
1661 return EC_IllegalCall;
1662 }
1663
1664
selectInstance(const char * instanceUID,const char * sopClassUID)1665 OFCondition DVInterface::selectInstance(const char *instanceUID, const char *sopClassUID)
1666 {
1667 if (instanceUID)
1668 {
1669 if (createIndexCache() && idxCache.gotoFirst())
1670 {
1671 DVStudyCache::ItemStruct *study = NULL;
1672 DVSeriesCache::ItemStruct *series = NULL;
1673 do { /* for all studies */
1674 study = idxCache.getItem();
1675 if ((study != NULL) && study->List.gotoFirst())
1676 {
1677 do { /* for all series */
1678 series = study->List.getItem();
1679 if ((series != NULL) && series->List.isElem(instanceUID))
1680 {
1681 if (readIndexRecord(series->List.getPos(), idxRec, &idxRecPos))
1682 {
1683 if (sopClassUID == NULL)
1684 return EC_Normal;
1685 else if (strcmp(sopClassUID, idxRec.SOPClassUID) == 0)
1686 return EC_Normal;
1687 }
1688 }
1689 } while (study->List.gotoNext());
1690 }
1691 } while (idxCache.gotoNext());
1692 }
1693 }
1694 return EC_IllegalCall;
1695 }
1696
1697
selectInstance(const char * studyUID,const char * seriesUID,const char * instanceUID)1698 OFCondition DVInterface::selectInstance(const char *studyUID, const char *seriesUID, const char *instanceUID)
1699 {
1700 if (studyUID && seriesUID && instanceUID)
1701 {
1702 if (createIndexCache())
1703 {
1704 if (idxCache.isElem(studyUID))
1705 {
1706 DVStudyCache::ItemStruct *study = idxCache.getItem();
1707 if (study->List.isElem(seriesUID))
1708 {
1709 DVSeriesCache::ItemStruct *series = study->List.getItem();
1710 if (series != NULL)
1711 {
1712 if (series->List.isElem(instanceUID))
1713 {
1714 if (readIndexRecord(series->List.getPos(), idxRec, &idxRecPos))
1715 return EC_Normal;
1716 }
1717 }
1718 }
1719 }
1720 }
1721 }
1722 return EC_IllegalCall;
1723 }
1724
1725
getStudyStatus()1726 DVIFhierarchyStatus DVInterface::getStudyStatus()
1727 {
1728 return idxCache.getStatus();
1729 }
1730
1731
getSeriesStatus()1732 DVIFhierarchyStatus DVInterface::getSeriesStatus()
1733 {
1734 DVStudyCache::ItemStruct *study = idxCache.getItem();
1735 if (study != NULL)
1736 return study->List.getStatus();
1737 return DVIF_objectIsNew;
1738 }
1739
1740
getInstanceStatus()1741 DVIFhierarchyStatus DVInterface::getInstanceStatus()
1742 {
1743 DVStudyCache::ItemStruct *study = idxCache.getItem();
1744 if (study != NULL)
1745 {
1746 DVSeriesCache::ItemStruct *series = study->List.getItem();
1747 if (series != NULL)
1748 return series->List.getStatus();
1749 }
1750 return DVIF_objectIsNew;
1751 }
1752
1753
getSeriesType()1754 DVPSInstanceType DVInterface::getSeriesType()
1755 {
1756 DVStudyCache::ItemStruct *study = idxCache.getItem();
1757 if (study != NULL)
1758 return study->List.getType();
1759 return DVPSI_image;
1760 }
1761
1762
getInstanceType()1763 DVPSInstanceType DVInterface::getInstanceType()
1764 {
1765 DVStudyCache::ItemStruct *study = idxCache.getItem();
1766 if (study != NULL)
1767 {
1768 DVSeriesCache::ItemStruct *series = study->List.getItem();
1769 if (series != NULL)
1770 return series->List.getType();
1771 }
1772 return DVPSI_image;
1773 }
1774
1775
getStudyUID()1776 const char *DVInterface::getStudyUID()
1777 {
1778 return idxRec.StudyInstanceUID;
1779 }
1780
1781
getSeriesUID()1782 const char *DVInterface::getSeriesUID()
1783 {
1784 return idxRec.SeriesInstanceUID;
1785 }
1786
1787
getSOPClassUID()1788 const char *DVInterface::getSOPClassUID()
1789 {
1790 return idxRec.SOPClassUID;
1791 }
1792
1793
getInstanceUID()1794 const char *DVInterface::getInstanceUID()
1795 {
1796 return idxRec.SOPInstanceUID;
1797 }
1798
1799
getStudyDescription()1800 const char *DVInterface::getStudyDescription()
1801 {
1802 return idxRec.StudyDescription;
1803 }
1804
1805
getStudyDate()1806 const char *DVInterface::getStudyDate()
1807 {
1808 return idxRec.StudyDate;
1809 }
1810
1811
getStudyTime()1812 const char *DVInterface::getStudyTime()
1813 {
1814 return idxRec.StudyTime;
1815 }
1816
1817
getReferringPhysiciansName()1818 const char *DVInterface::getReferringPhysiciansName()
1819 {
1820 return idxRec.ReferringPhysicianName;
1821 }
1822
1823
getAccessionNumber()1824 const char *DVInterface::getAccessionNumber()
1825 {
1826 return idxRec.AccessionNumber;
1827 }
1828
1829
getNameOfPhysiciansReadingStudy()1830 const char *DVInterface::getNameOfPhysiciansReadingStudy()
1831 {
1832 return idxRec.NameOfPhysiciansReadingStudy;
1833 }
1834
1835
getPatientName()1836 const char *DVInterface::getPatientName()
1837 {
1838 return idxRec.PatientName;
1839 }
1840
1841
getPatientID()1842 const char *DVInterface::getPatientID()
1843 {
1844 return idxRec.PatientID;
1845 }
1846
1847
getPatientBirthDate()1848 const char *DVInterface::getPatientBirthDate()
1849 {
1850 return idxRec.PatientBirthDate;
1851 }
1852
1853
getPatientSex()1854 const char *DVInterface::getPatientSex()
1855 {
1856 return idxRec.PatientSex;
1857 }
1858
1859
getPatientBirthTime()1860 const char *DVInterface::getPatientBirthTime()
1861 {
1862 return idxRec.PatientBirthTime;
1863 }
1864
1865
getOtherPatientNames()1866 const char *DVInterface::getOtherPatientNames()
1867 {
1868 return idxRec.OtherPatientNames;
1869 }
1870
1871
getOtherPatientID()1872 const char *DVInterface::getOtherPatientID()
1873 {
1874 return idxRec.OtherPatientIDs;
1875 }
1876
1877
getEthnicGroup()1878 const char *DVInterface::getEthnicGroup()
1879 {
1880 return idxRec.EthnicGroup;
1881 }
1882
1883
getSeriesDescription()1884 const char *DVInterface::getSeriesDescription()
1885 {
1886 return idxRec.SeriesDescription;
1887 }
1888
1889
getSeriesNumber()1890 const char *DVInterface::getSeriesNumber()
1891 {
1892 return idxRec.SeriesNumber;
1893 }
1894
1895
getSeriesDate()1896 const char *DVInterface::getSeriesDate()
1897 {
1898 return idxRec.SeriesDate;
1899 }
1900
1901
getSeriesTime()1902 const char *DVInterface::getSeriesTime()
1903 {
1904 return idxRec.SeriesTime;
1905 }
1906
1907
getSeriesPerformingPhysiciansName()1908 const char *DVInterface::getSeriesPerformingPhysiciansName()
1909 {
1910 return idxRec.PerformingPhysicianName;
1911 }
1912
1913
getSeriesProtocolName()1914 const char *DVInterface::getSeriesProtocolName()
1915 {
1916 return idxRec.ProtocolName;
1917 }
1918
1919
getSeriesOperatorsName()1920 const char *DVInterface::getSeriesOperatorsName()
1921 {
1922 return idxRec.OperatorsName;
1923 }
1924
1925
getModality()1926 const char *DVInterface::getModality()
1927 {
1928 return idxRec.Modality;
1929 }
1930
1931
getImageNumber()1932 const char *DVInterface::getImageNumber()
1933 {
1934 return idxRec.ImageNumber;
1935 }
1936
1937
getFilename()1938 const char *DVInterface::getFilename()
1939 {
1940 return idxRec.filename;
1941 }
1942
1943
getInstanceDescription()1944 const char *DVInterface::getInstanceDescription()
1945 {
1946 return idxRec.InstanceDescription;
1947 }
1948
1949
getPresentationLabel()1950 const char *DVInterface::getPresentationLabel()
1951 {
1952 return idxRec.PresentationLabel;
1953 }
1954
1955
instanceReviewed(int pos)1956 OFCondition DVInterface::instanceReviewed(int pos)
1957 {
1958 lockDatabase();
1959 OFBool wasNew = newInstancesReceived();
1960 if (pHandle == NULL) return EC_IllegalCall;
1961 pHandle->DB_unlock();
1962 OFCondition result = pHandle->instanceReviewed(pos);
1963 pHandle->DB_lock(OFFalse);
1964 if (!wasNew) resetDatabaseReferenceTime();
1965 releaseDatabase();
1966 return result;
1967 }
1968
1969
instanceReviewed(const char * studyUID,const char * seriesUID,const char * instanceUID)1970 OFCondition DVInterface::instanceReviewed(const char *studyUID,
1971 const char *seriesUID,
1972 const char *instanceUID)
1973 {
1974 OFCondition result = EC_IllegalCall;
1975 DVInstanceCache::ItemStruct *instance = getInstanceStruct(studyUID, seriesUID, instanceUID);
1976 if (instance != NULL)
1977 {
1978 if (instance->Status == DVIF_objectIsNotNew)
1979 result = EC_Normal;
1980 else
1981 result = instanceReviewed(instance->Pos);
1982 }
1983 return result;
1984 }
1985
1986
findStudyIdx(StudyDescRecord * study,const char * uid)1987 int DVInterface::findStudyIdx(StudyDescRecord *study,
1988 const char *uid)
1989 {
1990 if ((study != NULL) && (uid != NULL))
1991 {
1992 int i = 0;
1993 for (i = 0; i < PSTAT_MAXSTUDYCOUNT; i++)
1994 {
1995 if (strcmp(uid, study[i].StudyInstanceUID) == 0)
1996 return i;
1997 }
1998 }
1999 return -1;
2000 }
2001
2002
deleteImageFile(const char * filename)2003 int DVInterface::deleteImageFile(const char *filename)
2004 {
2005 if ((filename != NULL) && (pHandle != NULL))
2006 {
2007 const char *pos;
2008 if (((pos = strrchr(filename, OFstatic_cast(int, PATH_SEPARATOR))) == NULL) || // check whether image file resides in index.dat directory
2009 (strncmp(filename, pHandle->getStorageArea(), pos - filename) == 0))
2010 {
2011 // DB_deleteImageFile((/*const */char *)filename);
2012 if (unlink(filename) == 0)
2013 return 1; // image file has been deleted
2014 }
2015 return 2; // image file has not been deleted
2016 }
2017 return 0; // given filename is invalid
2018 }
2019
2020
deleteStudy(const char * studyUID)2021 OFCondition DVInterface::deleteStudy(const char *studyUID)
2022 {
2023 DVStudyCache::ItemStruct *study = getStudyStruct(studyUID);
2024 if (study != NULL)
2025 {
2026 OFCondition result = EC_IllegalCall;
2027 OFBool wasNew = OFTrue;
2028 if (lockExclusive() == EC_Normal)
2029 {
2030 wasNew = newInstancesReceived();
2031 if (study->List.gotoFirst())
2032 {
2033 StudyDescRecord *study_desc = OFstatic_cast(StudyDescRecord *, malloc(SIZEOF_STUDYDESC));
2034 if (study_desc != NULL)
2035 {
2036 if (pHandle->DB_GetStudyDesc(study_desc).good())
2037 {
2038 int idx = findStudyIdx(study_desc, studyUID);
2039 if (idx >= 0)
2040 {
2041 do /* for all series */
2042 {
2043 DVSeriesCache::ItemStruct *series = study->List.getItem();
2044 if (series != NULL)
2045 {
2046 if (series->List.gotoFirst())
2047 {
2048 do /* for all instances */
2049 {
2050 pHandle->DB_IdxRemove(series->List.getPos());
2051 deleteImageFile(series->List.getFilename());
2052 } while (series->List.gotoNext());
2053 }
2054 }
2055 } while (study->List.gotoNext());
2056 study_desc[idx].NumberofRegistratedImages = 0;
2057 study_desc[idx].StudySize = 0;
2058 pHandle->DB_StudyDescChange(study_desc);
2059 }
2060 }
2061 free(study_desc);
2062 }
2063 }
2064 }
2065 unlockExclusive();
2066 if (!wasNew)
2067 resetDatabaseReferenceTime();
2068 return result;
2069 }
2070 return EC_IllegalCall;
2071 }
2072
2073
deleteSeries(const char * studyUID,const char * seriesUID)2074 OFCondition DVInterface::deleteSeries(const char *studyUID,
2075 const char *seriesUID)
2076 {
2077 DVSeriesCache::ItemStruct *series = getSeriesStruct(studyUID, seriesUID);
2078 if (series != NULL)
2079 {
2080 OFCondition result = EC_IllegalCall;
2081 OFBool wasNew = OFTrue;
2082 if (lockExclusive() == EC_Normal)
2083 {
2084 wasNew = newInstancesReceived();
2085 if (series->List.gotoFirst())
2086 {
2087 StudyDescRecord *study_desc = OFstatic_cast(StudyDescRecord *, malloc(SIZEOF_STUDYDESC));
2088 if (study_desc != NULL)
2089 {
2090 if (pHandle->DB_GetStudyDesc(study_desc).good())
2091 {
2092 int idx = findStudyIdx(study_desc, studyUID);
2093 if (idx >= 0)
2094 {
2095 do /* for all images */
2096 {
2097 pHandle->DB_IdxRemove(series->List.getPos());
2098 if (study_desc[idx].NumberofRegistratedImages > 0)
2099 {
2100 study_desc[idx].NumberofRegistratedImages--;
2101 study_desc[idx].StudySize -= series->List.getImageSize();
2102 }
2103 deleteImageFile(series->List.getFilename());
2104 } while (series->List.gotoNext());
2105 pHandle->DB_StudyDescChange(study_desc);
2106 }
2107 }
2108 free(study_desc);
2109 }
2110 }
2111 }
2112 unlockExclusive();
2113 if (!wasNew)
2114 resetDatabaseReferenceTime();
2115 return result;
2116 }
2117 return EC_IllegalCall;
2118 }
2119
2120
2121
deleteInstance(const char * studyUID,const char * seriesUID,const char * instanceUID)2122 OFCondition DVInterface::deleteInstance(const char *studyUID,
2123 const char *seriesUID,
2124 const char *instanceUID)
2125 {
2126 DVSeriesCache::ItemStruct *series = getSeriesStruct(studyUID, seriesUID, instanceUID);
2127 if (series != NULL)
2128 {
2129 OFCondition result = EC_IllegalCall;
2130 OFBool wasNew = OFTrue;
2131 if (lockExclusive() == EC_Normal)
2132 {
2133 wasNew = newInstancesReceived();
2134 pHandle->DB_IdxRemove(series->List.getPos());
2135 StudyDescRecord *study_desc = OFstatic_cast(StudyDescRecord *, malloc(SIZEOF_STUDYDESC));
2136 if (study_desc != NULL)
2137 {
2138 if (pHandle->DB_GetStudyDesc(study_desc).good())
2139 {
2140 int i = 0;
2141 for (i = 0; i < PSTAT_MAXSTUDYCOUNT; i++)
2142 {
2143 if (strcmp(studyUID, study_desc[i].StudyInstanceUID) != 0)
2144 {
2145 if (study_desc[i].NumberofRegistratedImages > 0)
2146 {
2147 study_desc[i].NumberofRegistratedImages--;
2148 study_desc[i].StudySize -= series->List.getImageSize();
2149 pHandle->DB_StudyDescChange(study_desc);
2150 }
2151 break;
2152 }
2153 }
2154 free(study_desc);
2155 result = EC_Normal;
2156 }
2157 deleteImageFile(series->List.getFilename());
2158 }
2159 }
2160 unlockExclusive();
2161 if (!wasNew)
2162 resetDatabaseReferenceTime();
2163 return result;
2164 }
2165 return EC_IllegalCall;
2166 }
2167
2168
isDisplayTransformPossible(DVPSDisplayTransform transform)2169 OFBool DVInterface::isDisplayTransformPossible(DVPSDisplayTransform transform)
2170 {
2171 if (transform == DVPSD_none)
2172 return OFFalse;
2173 return (displayFunction[transform] != NULL);
2174 }
2175
2176
setAmbientLightValue(double value)2177 OFCondition DVInterface::setAmbientLightValue(double value)
2178 {
2179 OFCondition result = EC_IllegalCall;
2180 for (int i = DVPSD_first; i < DVPSD_max; i++)
2181 {
2182 if ((displayFunction[i] != NULL) && (displayFunction[i]->setAmbientLightValue(value)))
2183 result = EC_Normal; // at least one display function has been valid
2184 }
2185 return result;
2186 }
2187
2188
getAmbientLightValue(double & value)2189 OFCondition DVInterface::getAmbientLightValue(double &value)
2190 {
2191 if (displayFunction[DVPSD_first] != NULL)
2192 {
2193 value = displayFunction[DVPSD_first]->getAmbientLightValue();
2194 return EC_Normal;
2195 }
2196 return EC_IllegalCall;
2197 }
2198
2199
sendIOD(const char * targetID,const char * studyUID,const char * seriesUID,const char * instanceUID)2200 OFCondition DVInterface::sendIOD(const char * targetID,
2201 const char * studyUID,
2202 const char * seriesUID,
2203 const char * instanceUID)
2204 {
2205 if ((targetID==NULL)||(studyUID==NULL)) return EC_IllegalCall;
2206 const char *sender_application = getSenderName();
2207 if (sender_application==NULL) return EC_IllegalCall;
2208 if (configPath.empty()) return EC_IllegalCall;
2209
2210 DVPSHelper::cleanChildren(); // clean up old child processes before creating new ones
2211
2212 #ifdef HAVE_FORK
2213 // Unix version - call fork() and execl()
2214 pid_t pid = fork();
2215 if (pid < 0)
2216 {
2217 // fork failed - return error code
2218 return EC_IllegalCall;
2219 } else if (pid > 0)
2220 {
2221 // we are the parent process
2222 return EC_Normal;
2223 } else {
2224 // we are the child process
2225 if (execl(sender_application, sender_application, configPath.c_str(),
2226 targetID, studyUID, seriesUID, instanceUID, OFreinterpret_cast(char *, 0)) < 0)
2227 {
2228 DCMPSTAT_ERROR("Unable to execute '" << sender_application << "'");
2229 }
2230 // if execl succeeds, this part will not get executed.
2231 // if execl fails, there is not much we can do except bailing out.
2232 abort();
2233 }
2234 #else
2235 // Windows version - call CreateProcess()
2236
2237 // initialize startup info
2238 PROCESS_INFORMATION procinfo;
2239 STARTUPINFOA sinfo;
2240 OFBitmanipTemplate<char>::zeroMem((char *)&sinfo, sizeof(sinfo));
2241 sinfo.cb = sizeof(sinfo);
2242 char commandline[4096];
2243 if (seriesUID && instanceUID) sprintf(commandline, "%s %s %s %s %s %s", sender_application, configPath.c_str(),
2244 targetID, studyUID, seriesUID, instanceUID);
2245 else if (seriesUID) sprintf(commandline, "%s %s %s %s %s", sender_application, configPath.c_str(), targetID,
2246 studyUID, seriesUID);
2247 else sprintf(commandline, "%s %s %s %s", sender_application, configPath.c_str(), targetID, studyUID);
2248 #ifdef DEBUG
2249 if (CreateProcessA(NULL, commandline, NULL, NULL, 0, 0, NULL, NULL, &sinfo, &procinfo))
2250 #else
2251 if (CreateProcessA(NULL, commandline, NULL, NULL, 0, DETACHED_PROCESS, NULL, NULL, &sinfo, &procinfo))
2252 #endif
2253 {
2254 return EC_Normal;
2255 } else {
2256 DCMPSTAT_ERROR("Unable to execute '" << sender_application << "'");
2257 }
2258
2259 #endif
2260 return EC_IllegalCall;
2261 }
2262
2263
startReceiver()2264 OFCondition DVInterface::startReceiver()
2265 {
2266 const char *receiver_application = getReceiverName();
2267 if (receiver_application==NULL) return EC_IllegalCall;
2268 if (configPath.empty()) return EC_IllegalCall;
2269
2270 OFCondition result = EC_Normal;
2271 DCMPSTAT_LOGFILE("Starting network receiver processes ...");
2272
2273 Uint32 numberOfReceivers = getNumberOfTargets(DVPSE_receiver);
2274 for (Uint32 i=0; i < numberOfReceivers; i++)
2275 {
2276 DVPSHelper::cleanChildren(); // clean up old child processes before creating new ones
2277 #ifdef HAVE_FORK
2278 // Unix version - call fork() and execl()
2279 pid_t pid = fork();
2280 if (pid < 0)
2281 {
2282 // fork failed - set error code
2283 result = EC_IllegalCall;
2284 } else if (pid > 0)
2285 {
2286 // we are the parent process, continue loop
2287 } else {
2288 // we are the child process
2289 if (execl(receiver_application, receiver_application, configPath.c_str(), getTargetID(i, DVPSE_receiver), OFreinterpret_cast(char *, 0)) < 0)
2290 {
2291 DCMPSTAT_ERROR("Unable to execute '" << receiver_application << "'");
2292 }
2293 // if execl succeeds, this part will not get executed.
2294 // if execl fails, there is not much we can do except bailing out.
2295 abort();
2296 }
2297 #else
2298 // Windows version - call CreateProcess()
2299 // initialize startup info
2300 PROCESS_INFORMATION procinfo;
2301 STARTUPINFOA sinfo;
2302 OFBitmanipTemplate<char>::zeroMem((char *)&sinfo, sizeof(sinfo));
2303 sinfo.cb = sizeof(sinfo);
2304 char commandline[4096];
2305 sprintf(commandline, "%s %s %s", receiver_application, configPath.c_str(), getTargetID(i, DVPSE_receiver));
2306 #ifdef DEBUG
2307 if (CreateProcessA(NULL, commandline, NULL, NULL, 0, 0, NULL, NULL, &sinfo, &procinfo))
2308 #else
2309 if (CreateProcessA(NULL, commandline, NULL, NULL, 0, DETACHED_PROCESS, NULL, NULL, &sinfo, &procinfo))
2310 #endif
2311 {
2312 // continue loop
2313 } else {
2314 DCMPSTAT_ERROR("Unable to execute '" << receiver_application << "'");
2315 result = EC_IllegalCall;
2316 }
2317 #endif
2318 }
2319 return result;
2320 }
2321
terminateReceiver()2322 OFCondition DVInterface::terminateReceiver()
2323 {
2324 const char *receiver_application = getReceiverName();
2325 if (receiver_application==NULL) return EC_IllegalCall;
2326 if (configPath.empty()) return EC_IllegalCall;
2327
2328 OFCondition result = EC_Normal;
2329 DCMPSTAT_LOGFILE("Terminating network receiver processes ...");
2330
2331 DVPSHelper::cleanChildren(); // clean up old child processes before creating new ones
2332 #ifdef HAVE_FORK
2333 // Unix version - call fork() and execl()
2334 pid_t pid = fork();
2335 if (pid < 0)
2336 {
2337 // fork failed - set error code
2338 result = EC_IllegalCall;
2339 } else if (pid > 0)
2340 {
2341 // we are the parent process, continue loop
2342 } else {
2343 // we are the child process
2344 if (execl(receiver_application, receiver_application, configPath.c_str(), "--terminate", OFreinterpret_cast(char *, 0)) < 0)
2345 {
2346 DCMPSTAT_ERROR("Unable to execute '" << receiver_application << "'");
2347 }
2348 // if execl succeeds, this part will not get executed.
2349 // if execl fails, there is not much we can do except bailing out.
2350 abort();
2351 }
2352 #else
2353 // Windows version - call CreateProcess()
2354 // initialize startup info
2355 PROCESS_INFORMATION procinfo;
2356 STARTUPINFOA sinfo;
2357 OFBitmanipTemplate<char>::zeroMem((char *)&sinfo, sizeof(sinfo));
2358 sinfo.cb = sizeof(sinfo);
2359 char commandline[4096];
2360 sprintf(commandline, "%s %s %s", receiver_application, configPath.c_str(), "--terminate");
2361 #ifdef DEBUG
2362 if (CreateProcessA(NULL, commandline, NULL, NULL, 0, 0, NULL, NULL, &sinfo, &procinfo))
2363 #else
2364 if (CreateProcessA(NULL, commandline, NULL, NULL, 0, DETACHED_PROCESS, NULL, NULL, &sinfo, &procinfo))
2365 #endif
2366 {
2367 // continue loop
2368 } else {
2369 DCMPSTAT_ERROR("Unable to execute '" << receiver_application << "'");
2370 result = EC_IllegalCall;
2371 }
2372 #endif
2373 return result;
2374 }
2375
2376
startQueryRetrieveServer()2377 OFCondition DVInterface::startQueryRetrieveServer()
2378 {
2379 const char *server_application = getQueryRetrieveServerName();
2380 if (server_application==NULL) return EC_IllegalCall;
2381 if (configPath.empty()) return EC_IllegalCall;
2382
2383 OFString config_filename = getQueryRetrieveServerName();
2384 config_filename += ".cfg";
2385 if (getQueryRetrieveAutoCreateConfigFile())
2386 createQueryRetrieveServerConfigFile(config_filename.c_str());
2387
2388 DCMPSTAT_LOGFILE("Starting query/retrieve server process ...");
2389
2390 DVPSHelper::cleanChildren(); // clean up old child processes before creating new ones
2391
2392 Sint32 timeout = getQueryRetrieveTimeout();
2393
2394 #ifdef HAVE_FORK
2395 // Unix version - call fork() and execl()
2396 pid_t pid = fork();
2397 if (pid < 0)
2398 {
2399 // fork failed - return error code
2400 return EC_IllegalCall;
2401 } else if (pid > 0)
2402 {
2403 // we are the parent process
2404 return EC_Normal;
2405 } else {
2406 // we are the child process
2407 if (timeout > 0)
2408 {
2409 char str_timeout[20];
2410 sprintf(str_timeout, "%lu", OFstatic_cast(unsigned long, timeout));
2411 execl(server_application, server_application, "-c", config_filename.c_str(), "--allow-shutdown",
2412 "--timeout", str_timeout, OFreinterpret_cast(char *, 0));
2413 }
2414 else
2415 {
2416 execl(server_application, server_application, "-c", config_filename.c_str(), "--allow-shutdown", OFreinterpret_cast(char *, 0));
2417 }
2418
2419 DCMPSTAT_ERROR("Unable to execute '" << server_application << "'");
2420
2421 // if execl succeeds, this part will not get executed.
2422 // if execl fails, there is not much we can do except bailing out.
2423 abort();
2424 }
2425 #else
2426 // Windows version - call CreateProcess()
2427 // initialize startup info
2428 PROCESS_INFORMATION procinfo;
2429 STARTUPINFOA sinfo;
2430 OFBitmanipTemplate<char>::zeroMem((char *)&sinfo, sizeof(sinfo));
2431 sinfo.cb = sizeof(sinfo);
2432 char commandline[4096];
2433
2434 if (timeout > 0)
2435 {
2436 sprintf(commandline, "%s -c %s --allow-shutdown --timeout %lu",
2437 server_application, config_filename.c_str(), (unsigned long) timeout);
2438 }
2439 else
2440 {
2441 sprintf(commandline, "%s -c %s --allow-shutdown", server_application, config_filename.c_str());
2442 }
2443
2444 #ifdef DEBUG
2445 if (CreateProcessA(NULL, commandline, NULL, NULL, 0, 0, NULL, NULL, &sinfo, &procinfo))
2446 #else
2447 if (CreateProcessA(NULL, commandline, NULL, NULL, 0, DETACHED_PROCESS, NULL, NULL, &sinfo, &procinfo))
2448 #endif
2449 {
2450 return EC_Normal;
2451 } else {
2452 DCMPSTAT_ERROR("Unable to execute '" << server_application << "'");
2453 }
2454 #endif
2455 return EC_IllegalCall;
2456 }
2457
terminateQueryRetrieveServer()2458 OFCondition DVInterface::terminateQueryRetrieveServer()
2459 {
2460 if (getQueryRetrieveServerName()==NULL) return EC_IllegalCall;
2461 if (configPath.empty()) return EC_IllegalCall;
2462
2463 OFStandard::initializeNetwork();
2464
2465 OFCondition result = EC_Normal;
2466 T_ASC_Network *net=NULL;
2467 T_ASC_Parameters *params=NULL;
2468 DIC_NODENAME peerHost;
2469 T_ASC_Association *assoc=NULL;
2470
2471 DCMPSTAT_LOGFILE("Terminating query/retrieve server process ...");
2472
2473 OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, 30, &net);
2474 if (cond.good())
2475 {
2476 cond = ASC_createAssociationParameters(¶ms, DEFAULT_MAXPDU);
2477 if (cond.good())
2478 {
2479 ASC_setAPTitles(params, getNetworkAETitle(), getQueryRetrieveAETitle(), NULL);
2480 sprintf(peerHost, "localhost:%d", OFstatic_cast(int, getQueryRetrievePort()));
2481 ASC_setPresentationAddresses(params, OFStandard::getHostName().c_str(), peerHost);
2482
2483 const char* transferSyntaxes[] = { UID_LittleEndianImplicitTransferSyntax };
2484 cond = ASC_addPresentationContext(params, 1, UID_PrivateShutdownSOPClass, transferSyntaxes, 1);
2485 if (cond.good())
2486 {
2487 cond = ASC_requestAssociation(net, params, &assoc);
2488 if (cond.good()) ASC_abortAssociation(assoc); // tear down association if necessary
2489 ASC_dropAssociation(assoc);
2490 ASC_destroyAssociation(&assoc);
2491 }
2492 } else result = EC_IllegalCall;
2493 ASC_dropNetwork(&net);
2494 } else result = EC_IllegalCall;
2495
2496 OFStandard::shutdownNetwork();
2497
2498 return result;
2499 }
2500
createQueryRetrieveServerConfigFile(const char * filename)2501 OFCondition DVInterface::createQueryRetrieveServerConfigFile(const char *filename)
2502 {
2503 STD_NAMESPACE ofstream output(filename);
2504 if (output)
2505 {
2506 DCMPSTAT_LOGFILE("Creating configuration file for query/retrieve server");
2507 output << "# ATTENTION: This file has been created automatically and will" << OFendl;
2508 output << "# be re-created each time the query/retrieve server" << OFendl;
2509 output << "# is started. To avoid that manual changes to this" << OFendl;
2510 output << "# file are destroyed, the flag AutoCreateConfigFile" << OFendl;
2511 output << "# in the configuration file '" << configPath << "' has to be" << OFendl;
2512 output << "# switched off." << OFendl;
2513 output << OFendl;
2514 output << "NetworkType = \"tcp\"" << OFendl;
2515 output << "NetworkTCPPort = " << getQueryRetrievePort() << OFendl;
2516 output << "MaxPDUSize = " << getQueryRetrieveMaxPDU() << OFendl;
2517 output << "MaxAssociations = " << getQueryRetrieveMaxAssociations() << OFendl;
2518 output << "Display = \"no\"" << OFendl;
2519 output << OFendl;
2520 output << "HostTable BEGIN" << OFendl;
2521 const char *aet = NULL;
2522 const char *name = NULL;
2523 const Uint32 count = getNumberOfTargets();
2524 for (Uint32 i = 0; i < count; i++)
2525 {
2526 const char *id = getTargetID(i);
2527 if (id != NULL)
2528 {
2529 aet = getTargetAETitle(id);
2530 name = getTargetHostname(id);
2531 if ((aet != NULL) && (name != NULL))
2532 output << id << " = (" << aet << ", " << name << ", " << getTargetPort(id) << ")" << OFendl;
2533 }
2534 }
2535 output << "HostTable END" << OFendl;
2536 output << OFendl;
2537 output << "AETable BEGIN" << OFendl;
2538 output << getQueryRetrieveAETitle() << "\t" << getDatabaseFolder() << "\tR\t(";
2539 output << PSTAT_MAXSTUDYCOUNT << ", " << PSTAT_STUDYSIZE / 1024 / 1024 << "mb)\tANY" << OFendl;
2540 output << "AETable END" << OFendl;
2541 return EC_Normal;
2542 }
2543 DCMPSTAT_LOGFILE("Could not create configuration file for query/retrieve server");
2544 return EC_IllegalCall;
2545 }
2546
saveDICOMImage(const char * filename,const void * pixelData,unsigned long width,unsigned long height,double aspectRatio,OFBool explicitVR,const char * instanceUID)2547 OFCondition DVInterface::saveDICOMImage(
2548 const char *filename,
2549 const void *pixelData,
2550 unsigned long width,
2551 unsigned long height,
2552 double aspectRatio,
2553 OFBool explicitVR,
2554 const char *instanceUID)
2555 {
2556 if ((width<1)||(width > 0xFFFF)) return EC_IllegalCall;
2557 if ((height<1)||(height > 0xFFFF)) return EC_IllegalCall;
2558 if (pixelData == NULL) return EC_IllegalCall;
2559 if (filename == NULL) return EC_IllegalCall;
2560 if (aspectRatio == 0.0) return EC_IllegalCall;
2561
2562 Uint16 columns = OFstatic_cast(Uint16, width);
2563 Uint16 rows = OFstatic_cast(Uint16, height);
2564 OFCondition status = EC_Normal;
2565 DcmFileFormat *fileformat = new DcmFileFormat();
2566 DcmDataset *dataset = NULL;
2567 if (fileformat) dataset=fileformat->getDataset();
2568 char newuid[70];
2569
2570 if (dataset)
2571 {
2572 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_PatientName);
2573 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_PatientID);
2574 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_PatientBirthDate);
2575 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_PatientSex);
2576 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_StudyDate);
2577 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_StudyTime);
2578 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_ReferringPhysicianName);
2579 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_StudyID);
2580 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_AccessionNumber);
2581 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_SeriesNumber);
2582 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_InstanceNumber);
2583 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_PatientOrientation);
2584 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_SOPClassUID, UID_SecondaryCaptureImageStorage);
2585 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_Modality, "OT");
2586 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_ConversionType, "WSD");
2587 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_PhotometricInterpretation, "MONOCHROME2");
2588 dcmGenerateUniqueIdentifier(newuid);
2589 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_SOPInstanceUID, (instanceUID ? instanceUID : newuid));
2590 dcmGenerateUniqueIdentifier(newuid, SITE_SERIES_UID_ROOT);
2591 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_SeriesInstanceUID, newuid);
2592 dcmGenerateUniqueIdentifier(newuid, SITE_STUDY_UID_ROOT);
2593 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_StudyInstanceUID, newuid);
2594 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_SamplesPerPixel, 1);
2595 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_Rows, rows);
2596 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_Columns, columns);
2597 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_BitsAllocated, 8);
2598 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_BitsStored, 8);
2599 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_HighBit, 7);
2600 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_PixelRepresentation, 0);
2601 if ((EC_Normal==status)&&(aspectRatio != 1.0))
2602 {
2603 sprintf(newuid, "%ld\\%ld", 1000L, OFstatic_cast(long, aspectRatio*1000.0));
2604 status = DVPSHelper::putStringValue(dataset, DCM_PixelAspectRatio, newuid);
2605 }
2606 DcmPolymorphOBOW *pxData = new DcmPolymorphOBOW(DCM_PixelData);
2607 if (pxData)
2608 {
2609 status = pxData->putUint8Array(OFstatic_cast(Uint8 *, OFconst_cast(void *, pixelData)), OFstatic_cast(unsigned long, width*height));
2610 if (EC_Normal==status) status = dataset->insert(pxData, OFTrue /*replaceOld*/); else delete pxData;
2611 } else status = EC_MemoryExhausted;
2612
2613 if (status != EC_Normal)
2614 DCMPSTAT_LOGFILE("Save image to file failed: invalid data structures");
2615
2616 if (EC_Normal == status)
2617 {
2618 status = DVPSHelper::saveFileFormat(filename, fileformat, explicitVR);
2619 if (status != EC_Normal)
2620 DCMPSTAT_LOGFILE("Save image to file failed: could not write fileformat");
2621 }
2622 } else {
2623 status = EC_MemoryExhausted;
2624 DCMPSTAT_LOGFILE("Save image to file failed: memory exhausted");
2625 }
2626
2627 delete fileformat;
2628 return status;
2629 }
2630
2631
saveDICOMImage(const void * pixelData,unsigned long width,unsigned long height,double aspectRatio)2632 OFCondition DVInterface::saveDICOMImage(
2633 const void *pixelData,
2634 unsigned long width,
2635 unsigned long height,
2636 double aspectRatio)
2637 {
2638 // release database lock since we are using the DB module directly
2639 releaseDatabase();
2640
2641 char uid[100];
2642 dcmGenerateUniqueIdentifier(uid);
2643
2644 DcmQueryRetrieveDatabaseStatus dbStatus(STATUS_Success);
2645 char imageFileName[MAXPATHLEN+1];
2646
2647 OFCondition result = EC_Normal;
2648 DcmQueryRetrieveIndexDatabaseHandle handle(getDatabaseFolder(), PSTAT_MAXSTUDYCOUNT, PSTAT_STUDYSIZE, result);
2649 if (result.bad())
2650 {
2651 DCMPSTAT_LOGFILE("Save image to database failed: could not lock index file");
2652 return result;
2653 }
2654
2655 if (handle.makeNewStoreFileName(UID_SecondaryCaptureImageStorage, uid, imageFileName, sizeof(imageFileName)).good())
2656 {
2657 // now store presentation state as filename
2658 result = saveDICOMImage(imageFileName, pixelData, width, height, aspectRatio, OFTrue, uid);
2659 if (EC_Normal==result)
2660 {
2661 if (handle.storeRequest(UID_SecondaryCaptureImageStorage, uid, imageFileName, &dbStatus).bad())
2662 {
2663 result = EC_IllegalCall;
2664 DCMPSTAT_LOGFILE("Save image to database failed: could not register in index file");
2665 DCMPSTAT_WARN("Unable to register secondary capture image '" << imageFileName << "' in database");
2666 }
2667 }
2668 }
2669 return result;
2670 }
2671
2672
saveHardcopyGrayscaleImage(const char * filename,const void * pixelData,unsigned long width,unsigned long height,double aspectRatio,OFBool explicitVR,const char * instanceUID)2673 OFCondition DVInterface::saveHardcopyGrayscaleImage(
2674 const char *filename,
2675 const void *pixelData,
2676 unsigned long width,
2677 unsigned long height,
2678 double aspectRatio,
2679 OFBool explicitVR,
2680 const char *instanceUID)
2681 {
2682 if (pState == NULL) return EC_IllegalCall;
2683 if (pPrint == NULL) return EC_IllegalCall;
2684
2685 if ((width<1)||(width > 0xFFFF)) return EC_IllegalCall;
2686 if ((height<1)||(height > 0xFFFF)) return EC_IllegalCall;
2687 if (pixelData == NULL) return EC_IllegalCall;
2688 if (filename == NULL) return EC_IllegalCall;
2689 if (aspectRatio == 0.0) return EC_IllegalCall;
2690
2691 Uint16 columns = OFstatic_cast(Uint16, width);
2692 Uint16 rows = OFstatic_cast(Uint16, height);
2693 OFCondition status = EC_Normal;
2694 DcmFileFormat *fileformat = new DcmFileFormat();
2695 DcmDataset *dataset = NULL;
2696 if (fileformat) dataset=fileformat->getDataset();
2697 char newuid[70];
2698 OFString aString;
2699 OFString theInstanceUID;
2700
2701 if (dataset)
2702 {
2703 // write patient module
2704 if (EC_Normal==status) status = pState->writeHardcopyImageAttributes(*dataset);
2705 // write general study and general series module
2706 if (EC_Normal==status) status = pPrint->writeHardcopyImageAttributes(*dataset);
2707
2708 // Hardcopy Equipment Module
2709 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_RETIRED_HardcopyDeviceManufacturer, "OFFIS");
2710 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_RETIRED_HardcopyDeviceSoftwareVersion, OFFIS_DTK_IMPLEMENTATION_VERSION_NAME);
2711
2712 // General Image Module
2713 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_InstanceNumber);
2714 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_PatientOrientation);
2715 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_ImageType, "DERIVED\\SECONDARY");
2716 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_DerivationDescription, "Hardcopy rendered using Presentation State");
2717 // source image sequence is written in pState->writeHardcopyImageAttributes().
2718
2719 // SOP Common Module
2720 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_SOPClassUID, UID_RETIRED_HardcopyGrayscaleImageStorage);
2721 dcmGenerateUniqueIdentifier(newuid);
2722 theInstanceUID = (instanceUID ? instanceUID : newuid);
2723 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_SOPInstanceUID, theInstanceUID.c_str());
2724 DVPSHelper::currentDate(aString);
2725 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_InstanceCreationDate, aString.c_str());
2726 DVPSHelper::currentTime(aString);
2727 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_InstanceCreationTime, aString.c_str());
2728
2729 // Hardcopy Grayscale Image Module
2730 if (EC_Normal==status) status = DVPSHelper::putStringValue(dataset, DCM_PhotometricInterpretation, "MONOCHROME2");
2731 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_SamplesPerPixel, 1);
2732 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_Rows, rows);
2733 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_Columns, columns);
2734 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_BitsAllocated, 16);
2735 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_BitsStored, 12);
2736 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_HighBit, 11);
2737 if (EC_Normal==status) status = DVPSHelper::putUint16Value(dataset, DCM_PixelRepresentation, 0);
2738 if ((EC_Normal==status)&&(aspectRatio != 1.0))
2739 {
2740 sprintf(newuid, "%ld\\%ld", 1000L, OFstatic_cast(long, aspectRatio*1000.0));
2741 status = DVPSHelper::putStringValue(dataset, DCM_PixelAspectRatio, newuid);
2742 }
2743
2744 DcmPolymorphOBOW *pxData = new DcmPolymorphOBOW(DCM_PixelData);
2745 if (pxData)
2746 {
2747 status = pxData->putUint16Array(OFstatic_cast(Uint16 *, OFconst_cast(void *, pixelData)), OFstatic_cast(unsigned long, width*height));
2748 if (EC_Normal==status) status = dataset->insert(pxData, OFTrue /*replaceOld*/); else delete pxData;
2749 } else status = EC_MemoryExhausted;
2750
2751 // add Presentation LUT to hardcopy file if present, making it a Standard Extended SOP Class
2752 if ((EC_Normal==status)&&(pState->getPresentationLUT() == DVPSP_table))
2753 {
2754 status = pState->writePresentationLUTforPrint(*dataset);
2755 }
2756
2757 if (status != EC_Normal)
2758 DCMPSTAT_LOGFILE("Save hardcopy grayscale image to file failed: invalid data structures");
2759
2760 // save image file
2761 if (EC_Normal == status)
2762 {
2763 status = DVPSHelper::saveFileFormat(filename, fileformat, explicitVR);
2764 if (status != EC_Normal)
2765 DCMPSTAT_LOGFILE("Save hardcopy grayscale image to file failed: could not write fileformat");
2766 }
2767 } else {
2768 status = EC_MemoryExhausted;
2769 DCMPSTAT_LOGFILE("Save hardcopy grayscale image to file failed: memory exhausted");
2770 }
2771
2772 if (EC_Normal == status)
2773 {
2774 OFString reqImageTmp;
2775 const char *reqImageSize = NULL;
2776 DVPSPresentationLUT *presLUT = pState->getPresentationLUTData();
2777
2778 if (EC_Normal == pState->getPrintBitmapRequestedImageSize(reqImageTmp)) reqImageSize = reqImageTmp.c_str();
2779 /* we don't pass the patient ID (available as pState->getPatientID()) here because then
2780 * we could end up with multiple images being part of one study and one series, but having
2781 * different patient IDs. This might confuse archives using the patient root query model.
2782 */
2783 status = pPrint->addImageBox(getNetworkAETitle(), theInstanceUID.c_str(), reqImageSize, NULL, presLUT, pState->isMonochrome1Image());
2784 }
2785
2786 delete fileformat;
2787 return status;
2788 }
2789
2790
saveHardcopyGrayscaleImage(const void * pixelData,unsigned long width,unsigned long height,double aspectRatio)2791 OFCondition DVInterface::saveHardcopyGrayscaleImage(
2792 const void *pixelData,
2793 unsigned long width,
2794 unsigned long height,
2795 double aspectRatio)
2796 {
2797 // release database lock since we are using the DB module directly
2798 releaseDatabase();
2799
2800 char uid[100];
2801 dcmGenerateUniqueIdentifier(uid);
2802
2803 DcmQueryRetrieveDatabaseStatus dbStatus(STATUS_Success);
2804 char imageFileName[MAXPATHLEN+1];
2805
2806 OFCondition result=EC_Normal;
2807 DcmQueryRetrieveIndexDatabaseHandle handle(getDatabaseFolder(), PSTAT_MAXSTUDYCOUNT, PSTAT_STUDYSIZE, result);
2808 if (result.bad())
2809 {
2810 DCMPSTAT_LOGFILE("Save hardcopy grayscale image to database failed: could not lock index file");
2811 return result;
2812 }
2813
2814 if (handle.makeNewStoreFileName(UID_RETIRED_HardcopyGrayscaleImageStorage, uid, imageFileName, sizeof(imageFileName)).good())
2815 {
2816 result = saveHardcopyGrayscaleImage(imageFileName, pixelData, width, height, aspectRatio, OFTrue, uid);
2817 if (EC_Normal==result)
2818 {
2819 if (handle.storeRequest(UID_RETIRED_HardcopyGrayscaleImageStorage, uid, imageFileName, &dbStatus).bad())
2820 {
2821 result = EC_IllegalCall;
2822 DCMPSTAT_LOGFILE("Save hardcopy grayscale image to database failed: could not register in index file");
2823 DCMPSTAT_WARN("Unable to register hardcopy grayscale image '" << imageFileName << "' in database");
2824 }
2825 }
2826 }
2827 return result;
2828 }
2829
2830
saveFileFormatToDB(DcmFileFormat & fileformat)2831 OFCondition DVInterface::saveFileFormatToDB(DcmFileFormat &fileformat)
2832 {
2833 // release database lock since we are using the DB module directly
2834 releaseDatabase();
2835
2836 // get SOP class and instance UID from dataset
2837 char *classUID = NULL;
2838 char *instanceUID = NULL;
2839 DcmStack stack;
2840 DcmDataset *dset = fileformat.getDataset();
2841 if (dset)
2842 {
2843 if (EC_Normal == dset->search(DCM_SOPInstanceUID, stack, ESM_fromHere, OFFalse))
2844 {
2845 OFstatic_cast(DcmElement *, stack.top())->getString(instanceUID);
2846 }
2847 stack.clear();
2848 if (EC_Normal == dset->search(DCM_SOPClassUID, stack, ESM_fromHere, OFFalse))
2849 {
2850 OFstatic_cast(DcmElement *, stack.top())->getString(classUID);
2851 }
2852 }
2853 if ((instanceUID==NULL)||(classUID==NULL)) return EC_IllegalCall;
2854
2855 DcmQueryRetrieveDatabaseStatus dbStatus(STATUS_Success);
2856 char imageFileName[MAXPATHLEN+1];
2857
2858 OFCondition result=EC_Normal;
2859 DcmQueryRetrieveIndexDatabaseHandle handle(getDatabaseFolder(), PSTAT_MAXSTUDYCOUNT, PSTAT_STUDYSIZE, result);
2860 if (result.bad())
2861 {
2862 DCMPSTAT_LOGFILE("Save fileformat to database failed: could not lock index file");
2863 return result;
2864 }
2865
2866 if (handle.makeNewStoreFileName(classUID, instanceUID, imageFileName, sizeof(imageFileName)).good())
2867 {
2868 // save image file
2869 result = DVPSHelper::saveFileFormat(imageFileName, &fileformat, OFTrue);
2870 if (EC_Normal==result)
2871 {
2872 if (handle.storeRequest(classUID, instanceUID, imageFileName, &dbStatus).bad())
2873 {
2874 result = EC_IllegalCall;
2875 DCMPSTAT_LOGFILE("Save fileformat to database failed: could not register in index file");
2876 DCMPSTAT_WARN("Unable to register file '" << imageFileName << "' in database");
2877 }
2878 }
2879 }
2880 return result;
2881 }
2882
2883
loadStoredPrint(const char * studyUID,const char * seriesUID,const char * instanceUID,OFBool changeStatus)2884 OFCondition DVInterface::loadStoredPrint(const char *studyUID, const char *seriesUID, const char *instanceUID, OFBool changeStatus)
2885 {
2886 OFCondition status = EC_IllegalCall;
2887 if (studyUID && seriesUID && instanceUID)
2888 {
2889 if (lockDatabase() == EC_Normal)
2890 {
2891 const char *filename = getFilename(studyUID, seriesUID, instanceUID);
2892 if (filename)
2893 {
2894 if ((status = loadStoredPrint(filename)) == EC_Normal)
2895 {
2896 if (changeStatus)
2897 instanceReviewed(studyUID, seriesUID, instanceUID);
2898 }
2899 } else
2900 DCMPSTAT_LOGFILE("Load stored print from database failed: UIDs not in index file");
2901 } else
2902 DCMPSTAT_LOGFILE("Load stored print from database failed: could not lock index file");
2903 } else
2904 DCMPSTAT_LOGFILE("Load stored print from database failed: invalid UIDs");
2905 return status;
2906 }
2907
2908
loadStoredPrint(const char * filename)2909 OFCondition DVInterface::loadStoredPrint(const char *filename)
2910 {
2911 OFCondition status = EC_IllegalCall;
2912 DcmFileFormat *fileformat = NULL;
2913 DVPSStoredPrint *print = new DVPSStoredPrint(getDefaultPrintIllumination(), getDefaultPrintReflection());
2914 if (print==NULL)
2915 {
2916 DCMPSTAT_LOGFILE("Load stored print from file failed: memory exhausted");
2917 return EC_MemoryExhausted;
2918 }
2919
2920 if ((status = DVPSHelper::loadFileFormat(filename, fileformat)) == EC_Normal)
2921 {
2922 if (fileformat)
2923 {
2924 DcmDataset *dataset = fileformat->getDataset();
2925 if (dataset)
2926 {
2927 if (EC_Normal == (status = print->read(*dataset)))
2928 {
2929 delete pPrint;
2930 pPrint = print;
2931 clearFilmSessionSettings();
2932 }
2933 } else status = EC_CorruptedData;
2934 delete fileformat;
2935 } else status = EC_IllegalCall;
2936 if (status != EC_Normal)
2937 DCMPSTAT_LOGFILE("Load stored print from file failed: invalid data structures");
2938 } else
2939 DCMPSTAT_LOGFILE("Load stored print from file failed: could not read fileformat");
2940 if (status != EC_Normal)
2941 {
2942 delete print;
2943 }
2944 return status;
2945 }
2946
2947
saveStoredPrint(const char * filename,OFBool writeRequestedImageSize,OFBool explicitVR,const char * instanceUID)2948 OFCondition DVInterface::saveStoredPrint(
2949 const char *filename,
2950 OFBool writeRequestedImageSize,
2951 OFBool explicitVR,
2952 const char *instanceUID)
2953 {
2954 if (pState == NULL) return EC_IllegalCall;
2955 if (pPrint == NULL) return EC_IllegalCall;
2956 if (filename == NULL) return EC_IllegalCall;
2957
2958 OFCondition status = EC_Normal;
2959 DcmFileFormat *fileformat = new DcmFileFormat();
2960 DcmDataset *dataset = NULL;
2961 if (fileformat)
2962 dataset = fileformat->getDataset();
2963
2964 char newuid[70];
2965 char buf[32];
2966
2967 /* set annotation if active */
2968 if (activateAnnotation)
2969 {
2970 OFString text;
2971 OFString dummy;
2972 if (prependDateTime)
2973 {
2974 OFDateTime::getCurrentDateTime().getISOFormattedDateTime(text, OFFalse /*showSeconds*/);
2975 text += " ";
2976 }
2977 if (prependPrinterName)
2978 {
2979 text += currentPrinter;
2980 text += " ";
2981 }
2982 if (prependLighting)
2983 {
2984 sprintf(buf, "%d/%d ", pPrint->getPrintIllumination(), pPrint->getPrintReflectedAmbientLight());
2985 text += buf;
2986 }
2987 text += annotationText;
2988 if (text.size() >64) text.erase(64); // limit to max annotation length
2989
2990 if (getTargetPrinterSupportsAnnotationBoxSOPClass(currentPrinter.c_str()))
2991 {
2992 const char *displayformat = getTargetPrinterAnnotationDisplayFormatID(currentPrinter.c_str(), dummy);
2993 Uint16 position = getTargetPrinterAnnotationPosition(currentPrinter.c_str());
2994 pPrint->setSingleAnnotation(displayformat, text.c_str(), position);
2995 } else pPrint->deleteAnnotations();
2996 if (getTargetPrinterSessionLabelAnnotation(currentPrinter.c_str()))
2997 {
2998 status = setPrinterFilmSessionLabel(text.c_str());
2999 }
3000 } else {
3001 pPrint->deleteAnnotations();
3002 }
3003
3004 if (dataset)
3005 {
3006 if (instanceUID) status = pPrint->setInstanceUID(instanceUID); else
3007 {
3008 dcmGenerateUniqueIdentifier(newuid);
3009 status = pPrint->setInstanceUID(newuid);
3010 }
3011 if (EC_Normal == status) status = pPrint->write(*dataset, writeRequestedImageSize, OFTrue, OFTrue, OFFalse);
3012
3013 // save file
3014 if (EC_Normal == status) status = DVPSHelper::saveFileFormat(filename, fileformat, explicitVR);
3015
3016 if (status != EC_Normal)
3017 DCMPSTAT_LOGFILE("Save stored print to file failed: could not write fileformat");
3018 } else {
3019 DCMPSTAT_LOGFILE("Save stored print to file failed: memory exhausted");
3020 status = EC_MemoryExhausted;
3021 }
3022
3023 delete fileformat;
3024 return status;
3025 }
3026
saveStoredPrint(OFBool writeRequestedImageSize)3027 OFCondition DVInterface::saveStoredPrint(OFBool writeRequestedImageSize)
3028 {
3029 // release database lock since we are using the DB module directly
3030 releaseDatabase();
3031
3032 char uid[100];
3033 dcmGenerateUniqueIdentifier(uid);
3034
3035 DcmQueryRetrieveDatabaseStatus dbStatus(STATUS_Success);
3036 char imageFileName[MAXPATHLEN+1];
3037 OFCondition result=EC_Normal;
3038 DcmQueryRetrieveIndexDatabaseHandle handle(getDatabaseFolder(), PSTAT_MAXSTUDYCOUNT, PSTAT_STUDYSIZE, result);
3039 if (result.bad())
3040 {
3041 DCMPSTAT_LOGFILE("Save stored print to database failed: could not lock index file");
3042 return result;
3043 }
3044
3045 if (handle.makeNewStoreFileName(UID_RETIRED_StoredPrintStorage, uid, imageFileName, sizeof(imageFileName)).good())
3046 {
3047 // now store stored print object as filename
3048 result = saveStoredPrint(imageFileName, writeRequestedImageSize, OFTrue, uid);
3049 if (EC_Normal==result)
3050 {
3051 if (handle.storeRequest(UID_RETIRED_StoredPrintStorage, uid, imageFileName, &dbStatus).bad())
3052 {
3053 result = EC_IllegalCall;
3054 DCMPSTAT_LOGFILE("Save stored print to database failed: could not register in index file");
3055 DCMPSTAT_WARN("Unable to register stored print object '" << imageFileName << "' in database");
3056 }
3057 }
3058 }
3059 return result;
3060 }
3061
getNumberOfPrintPreviews()3062 size_t DVInterface::getNumberOfPrintPreviews()
3063 {
3064 if (pPrint != NULL)
3065 return pPrint->getNumberOfImages();
3066 return 0;
3067 }
3068
loadPrintPreview(size_t idx,OFBool printLUT,OFBool changeStatus)3069 OFCondition DVInterface::loadPrintPreview(size_t idx, OFBool printLUT, OFBool changeStatus)
3070 {
3071 OFCondition status = EC_IllegalCall;
3072 if ((pPrint != NULL) && (maximumPrintPreviewWidth > 0) && (maximumPrintPreviewHeight > 0))
3073 {
3074 const char *studyUID;
3075 const char *seriesUID;
3076 const char *instanceUID;
3077 if ((status = pPrint->getImageReference(idx, studyUID, seriesUID, instanceUID)) == EC_Normal)
3078 {
3079 status = EC_IllegalCall;
3080 const char *filename = getFilename(studyUID, seriesUID, instanceUID);
3081 if (filename)
3082 {
3083 DicomImage *image = new DicomImage(filename);
3084 if (image != NULL)
3085 {
3086 if (image->getStatus() == EIS_Normal)
3087 {
3088 unsigned long width = maximumPrintPreviewWidth;
3089 unsigned long height = maximumPrintPreviewHeight;
3090 /* consider aspect ratio of the image and the display */
3091 double ratio = image->getWidthHeightRatio();
3092 const double mpWidth = getMonitorPixelWidth();
3093 const double mpHeight = getMonitorPixelHeight();
3094 if ((mpWidth > 0) && (mpHeight > 0))
3095 ratio *= (mpWidth / mpHeight);
3096 if (ratio == 0.0)
3097 ratio = 1.0;
3098 if (OFstatic_cast(double, image->getWidth()) / OFstatic_cast(double, width * ratio) <
3099 OFstatic_cast(double, image->getHeight()) / OFstatic_cast(double, height))
3100 {
3101 width = 0;
3102 } else
3103 height = 0;
3104 image->setWidthHeightRatio(ratio);
3105 pHardcopyImage = image->createScaledImage(width, height, 0 /*interpolate*/, 1 /*aspect ratio*/);
3106 if (pHardcopyImage != NULL)
3107 {
3108 if (pHardcopyImage->getStatus() == EIS_Normal)
3109 {
3110 /* set display function for calibrated output */
3111 if (displayFunction[DVPSD_GSDF] != NULL)
3112 pHardcopyImage->setDisplayFunction(displayFunction[DVPSD_GSDF]);
3113 /* adapt polarity if necessary */
3114 const char *polarity = pPrint->getImagePolarity(idx);
3115 if ((polarity != NULL) && (strcmp(polarity, "REVERSE") == 0))
3116 pHardcopyImage->setPolarity(EPP_Reverse);
3117 /* set (print/display) presentation LUT */
3118 DVPSPresentationLUT *plut = pPrint->getPresentationLUT(); // first check whether there's a global one
3119 if (plut == NULL)
3120 plut = pPrint->getImagePresentationLUT(idx); // ... then check for an image box specific
3121 if (plut != NULL)
3122 {
3123 pHardcopyImage->setHardcopyParameters(pPrint->getMinDensityValue(), pPrint->getMaxDensityValue(),
3124 pPrint->getPrintReflectedAmbientLight(), pPrint->getPrintIllumination());
3125 plut->activate(pHardcopyImage, printLUT);
3126 }
3127 status = EC_Normal;
3128 if (changeStatus)
3129 instanceReviewed(studyUID, seriesUID, instanceUID);
3130 } else
3131 unloadPrintPreview();
3132 } else
3133 DCMPSTAT_LOGFILE("Load hardcopy grayscale image for print preview failed: memory exhausted");
3134 } else
3135 DCMPSTAT_LOGFILE("Load hardcopy grayscale image for print preview failed: could not read image");
3136 delete image;
3137 } else
3138 DCMPSTAT_LOGFILE("Load hardcopy grayscale image for print preview failed: memory exhausted");
3139 } else
3140 DCMPSTAT_LOGFILE("Load hardcopy grayscale image for print preview failed: UIDs not in index file");
3141 }
3142 }
3143 return status;
3144 }
3145
unloadPrintPreview()3146 void DVInterface::unloadPrintPreview()
3147 {
3148 delete pHardcopyImage;
3149 pHardcopyImage = NULL;
3150 }
3151
getPrintPreviewSize()3152 unsigned long DVInterface::getPrintPreviewSize()
3153 {
3154 unsigned long result = 0;
3155 unsigned long width;
3156 unsigned long height;
3157 if (getPrintPreviewWidthHeight(width, height) == EC_Normal)
3158 result = width * height;
3159 return result;
3160 }
3161
setMaxPrintPreviewWidthHeight(unsigned long width,unsigned long height)3162 void DVInterface::setMaxPrintPreviewWidthHeight(unsigned long width, unsigned long height)
3163 {
3164 if ((width != maximumPrintPreviewWidth) || (height != maximumPrintPreviewHeight))
3165 {
3166 unloadPrintPreview();
3167 maximumPrintPreviewWidth = width;
3168 maximumPrintPreviewHeight = height;
3169 }
3170 }
3171
getPrintPreviewWidthHeight(unsigned long & width,unsigned long & height)3172 OFCondition DVInterface::getPrintPreviewWidthHeight(unsigned long &width, unsigned long &height)
3173 {
3174 OFCondition result = EC_IllegalCall;
3175 if (pHardcopyImage != NULL)
3176 {
3177 width = pHardcopyImage->getWidth();
3178 height = pHardcopyImage->getHeight();
3179 if ((width > 0) && (height > 0))
3180 result = EC_Normal;
3181 } else {
3182 width = 0;
3183 height = 0;
3184 }
3185 return result;
3186 }
3187
getPrintPreviewBitmap(void * bitmap,unsigned long size)3188 OFCondition DVInterface::getPrintPreviewBitmap(void *bitmap, unsigned long size)
3189 {
3190 OFCondition status = EC_IllegalCall;
3191 if ((pHardcopyImage != NULL) && (bitmap != NULL) && (size > 0))
3192 {
3193 if (pHardcopyImage->getOutputData(bitmap, size, 8 /*bits*/))
3194 status = EC_Normal;
3195 }
3196 return status;
3197 }
3198
setCurrentPrinter(const char * targetID)3199 OFCondition DVInterface::setCurrentPrinter(const char *targetID)
3200 {
3201 if (targetID == NULL) return EC_IllegalCall;
3202 if (getTargetHostname(targetID) == NULL) return EC_IllegalCall; // Printer seems to be unknown
3203 activateAnnotation = getTargetPrinterSupportsAnnotation(targetID);
3204 if (pPrint != NULL)
3205 {
3206 pPrint->setPrinterName(targetID);
3207 pPrint->setDestination(getTargetAETitle(targetID));
3208 }
3209 currentPrinter = targetID;
3210 return EC_Normal;
3211 }
3212
getCurrentPrinter()3213 const char *DVInterface::getCurrentPrinter()
3214 {
3215 return currentPrinter.c_str();
3216 }
3217
setPrinterMediumType(const char * value)3218 OFCondition DVInterface::setPrinterMediumType(const char *value)
3219 {
3220 if (value) printerMediumType = value; else printerMediumType.clear();
3221 return EC_Normal;
3222 }
3223
getPrinterMediumType()3224 const char *DVInterface::getPrinterMediumType()
3225 {
3226 return printerMediumType.c_str();
3227 }
3228
setPrinterFilmDestination(const char * value)3229 OFCondition DVInterface::setPrinterFilmDestination(const char *value)
3230 {
3231 if (value) printerFilmDestination = value; else printerFilmDestination.clear();
3232 return EC_Normal;
3233 }
3234
getPrinterFilmDestination()3235 const char *DVInterface::getPrinterFilmDestination()
3236 {
3237 return printerFilmDestination.c_str();
3238 }
3239
setPrinterFilmSessionLabel(const char * value)3240 OFCondition DVInterface::setPrinterFilmSessionLabel(const char *value)
3241 {
3242 if (value) printerFilmSessionLabel = value; else printerFilmSessionLabel.clear();
3243 return EC_Normal;
3244 }
3245
getPrinterFilmSessionLabel()3246 const char *DVInterface::getPrinterFilmSessionLabel()
3247 {
3248 return printerFilmSessionLabel.c_str();
3249 }
3250
setPrinterPriority(const char * value)3251 OFCondition DVInterface::setPrinterPriority(const char *value)
3252 {
3253 if (value) printerPriority = value; else printerPriority.clear();
3254 return EC_Normal;
3255 }
3256
getPrinterPriority()3257 const char *DVInterface::getPrinterPriority()
3258 {
3259 return printerPriority.c_str();
3260 }
3261
setPrinterOwnerID(const char * value)3262 OFCondition DVInterface::setPrinterOwnerID(const char *value)
3263 {
3264 if (value) printerOwnerID = value; else printerOwnerID.clear();
3265 return EC_Normal;
3266 }
3267
getPrinterOwnerID()3268 const char *DVInterface::getPrinterOwnerID()
3269 {
3270 return printerOwnerID.c_str();
3271 }
3272
setPrinterNumberOfCopies(unsigned long value)3273 OFCondition DVInterface::setPrinterNumberOfCopies(unsigned long value)
3274 {
3275 printerNumberOfCopies = value;
3276 return EC_Normal;
3277 }
3278
getPrinterNumberOfCopies()3279 unsigned long DVInterface::getPrinterNumberOfCopies()
3280 {
3281 return printerNumberOfCopies;
3282 }
3283
selectDisplayPresentationLUT(const char * lutID)3284 OFCondition DVInterface::selectDisplayPresentationLUT(const char *lutID)
3285 {
3286 OFCondition result = EC_IllegalCall;
3287 if (lutID && pState)
3288 {
3289 const char *lutfile = getLUTFilename(lutID);
3290 if (lutfile)
3291 {
3292 OFString filename = getLUTFolder(); // never NULL.
3293 filename += PATH_SEPARATOR;
3294 filename += lutfile;
3295 DcmFileFormat *fileformat = NULL;
3296 if ((result = DVPSHelper::loadFileFormat(filename.c_str(), fileformat)) == EC_Normal)
3297 {
3298 if (fileformat)
3299 {
3300 DcmDataset *dataset = fileformat->getDataset();
3301 if (dataset)
3302 result = pState->setPresentationLookupTable(*dataset);
3303 else
3304 result = EC_IllegalCall;
3305 if (EC_Normal == result)
3306 displayCurrentLUTID = lutID;
3307 else
3308 displayCurrentLUTID.clear();
3309 } else result = EC_IllegalCall;
3310 if (result != EC_Normal)
3311 DCMPSTAT_LOGFILE("Load display presentation LUT from file: invalid data structures");
3312 } else
3313 DCMPSTAT_LOGFILE("Load display presentation LUT from file: could not read fileformat");
3314 delete fileformat;
3315 } else
3316 DCMPSTAT_LOGFILE("Load display presentation LUT from file: not specified in config file");
3317 }
3318 return result;
3319 }
3320
getDisplayPresentationLUTID()3321 const char *DVInterface::getDisplayPresentationLUTID()
3322 {
3323 return displayCurrentLUTID.c_str();
3324 }
3325
selectPrintPresentationLUT(const char * lutID)3326 OFCondition DVInterface::selectPrintPresentationLUT(const char *lutID)
3327 {
3328 OFCondition result = EC_IllegalCall;
3329 if (lutID && pPrint)
3330 {
3331 const char *lutfile = getLUTFilename(lutID);
3332 if (lutfile)
3333 {
3334 OFString filename = getLUTFolder(); // never NULL.
3335 filename += PATH_SEPARATOR;
3336 filename += lutfile;
3337 DcmFileFormat *fileformat = NULL;
3338 if ((result = DVPSHelper::loadFileFormat(filename.c_str(), fileformat)) == EC_Normal)
3339 {
3340 if (fileformat)
3341 {
3342 DcmDataset *dataset = fileformat->getDataset();
3343 if (dataset)
3344 result = pPrint->setPresentationLookupTable(*dataset);
3345 else
3346 result = EC_IllegalCall;
3347 if (EC_Normal == result)
3348 printCurrentLUTID = lutID;
3349 else
3350 printCurrentLUTID.clear();
3351 } else result = EC_IllegalCall;
3352 if (result != EC_Normal)
3353 DCMPSTAT_LOGFILE("Load print presentation LUT from file: invalid data structures");
3354 } else
3355 DCMPSTAT_LOGFILE("Load print presentation LUT from file: could not read fileformat");
3356 delete fileformat;
3357 } else
3358 DCMPSTAT_LOGFILE("Load print presentation LUT from file: not specified in config file");
3359 }
3360 return result;
3361 }
3362
getPrintPresentationLUTID()3363 const char *DVInterface::getPrintPresentationLUTID()
3364 {
3365 return printCurrentLUTID.c_str();
3366 }
3367
spoolPrintJob(OFBool deletePrintedImages)3368 OFCondition DVInterface::spoolPrintJob(OFBool deletePrintedImages)
3369 {
3370 if (pPrint==NULL) return EC_IllegalCall;
3371 if (currentPrinter.size()==0) return EC_IllegalCall;
3372
3373 OFCondition result = saveStoredPrint(getTargetPrinterSupportsRequestedImageSize(currentPrinter.c_str()));
3374 if (EC_Normal == result)
3375 {
3376 result = spoolStoredPrintFromDB(pPrint->getStudyInstanceUID(), pPrint->getSeriesInstanceUID(), pPrint->getSOPInstanceUID());
3377 }
3378 if ((EC_Normal == result) && deletePrintedImages) result = pPrint->deleteSpooledImages();
3379 return result;
3380 }
3381
startPrintSpooler()3382 OFCondition DVInterface::startPrintSpooler()
3383 {
3384 const char *spooler_application = getSpoolerName();
3385 if (spooler_application==NULL) return EC_IllegalCall;
3386 if (configPath.empty()) return EC_IllegalCall;
3387
3388 const char *printer = NULL;
3389 unsigned long sleepingTime = getSpoolerSleep();
3390 if (sleepingTime==0) sleepingTime=1; // default
3391 char sleepStr[30];
3392 sprintf(sleepStr, "%lu", sleepingTime);
3393 OFBool detailedLog = getDetailedLog();
3394
3395 OFCondition result = EC_Normal;
3396 DCMPSTAT_LOGFILE("Starting print spooler process ...");
3397
3398 DVPSHelper::cleanChildren(); // clean up old child processes before creating new ones
3399
3400 Uint32 numberOfPrinters = getNumberOfTargets(DVPSE_printAny);
3401 if (numberOfPrinters > 0) for (Uint32 i=0; i < numberOfPrinters; i++)
3402 {
3403 printer = getTargetID(i, DVPSE_printAny);
3404
3405 #ifdef HAVE_FORK
3406 // Unix version - call fork() and execl()
3407 pid_t pid = fork();
3408 if (pid < 0) result = EC_IllegalCall; // fork failed - return error code
3409 else if (pid==0)
3410 {
3411 // we are the child process
3412
3413 if (detailedLog)
3414 {
3415 if (execl(spooler_application, spooler_application, "--verbose", "--dump", "--spool", printJobIdentifier.c_str(),
3416 "--printer", printer, "--config", configPath.c_str(), "--sleep", sleepStr, OFreinterpret_cast(char *, 0)) < 0)
3417 {
3418 DCMPSTAT_ERROR("Unable to execute '" << spooler_application << "'");
3419 }
3420 } else {
3421 if (execl(spooler_application, spooler_application, "--spool", printJobIdentifier.c_str(),
3422 "--printer", printer, "--config", configPath.c_str(), "--sleep", sleepStr, OFreinterpret_cast(char *, 0)) < 0)
3423 {
3424 DCMPSTAT_ERROR("Unable to execute '" << spooler_application << "'");
3425 }
3426 }
3427
3428 // if execl succeeds, this part will not get executed.
3429 // if execl fails, there is not much we can do except bailing out.
3430 abort();
3431 }
3432 #else
3433 // Windows version - call CreateProcess()
3434 // initialize startup info
3435 PROCESS_INFORMATION procinfo;
3436 STARTUPINFOA sinfo;
3437 OFBitmanipTemplate<char>::zeroMem((char *)&sinfo, sizeof(sinfo));
3438 sinfo.cb = sizeof(sinfo);
3439 char commandline[4096];
3440 if (detailedLog)
3441 {
3442 sprintf(commandline, "%s --verbose --dump --spool %s --printer %s --config %s --sleep %s", spooler_application,
3443 printJobIdentifier.c_str(), printer, configPath.c_str(), sleepStr);
3444 } else {
3445 sprintf(commandline, "%s --spool %s --printer %s --config %s --sleep %s", spooler_application,
3446 printJobIdentifier.c_str(), printer, configPath.c_str(), sleepStr);
3447 }
3448 #ifdef DEBUG
3449 if (0 == CreateProcessA(NULL, commandline, NULL, NULL, 0, 0, NULL, NULL, &sinfo, &procinfo))
3450 #else
3451 if (0 == CreateProcessA(NULL, commandline, NULL, NULL, 0, DETACHED_PROCESS, NULL, NULL, &sinfo, &procinfo))
3452 #endif
3453 {
3454 DCMPSTAT_ERROR("Unable to execute '" << spooler_application << "'");
3455 result = EC_IllegalCall;
3456 }
3457 #endif
3458 }
3459 return result;
3460 }
3461
createPrintJobFilenames(const char * printer,OFString & tempname,OFString & jobname)3462 OFCondition DVInterface::createPrintJobFilenames(const char *printer, OFString& tempname, OFString& jobname)
3463 {
3464 tempname.clear();
3465 jobname.clear();
3466 if (printer==NULL) return EC_IllegalCall;
3467 char buf[20];
3468
3469 sprintf(buf, "%04lu", printJobCounter++);
3470 jobname = getSpoolFolder();
3471 jobname += PATH_SEPARATOR;
3472 jobname += printJobIdentifier;
3473 jobname += '_';
3474 jobname += printer;
3475 jobname += '_';
3476 jobname += buf;
3477 tempname = jobname;
3478 jobname += PRINTJOB_SUFFIX;
3479 tempname += PRINTJOB_TEMP_SUFFIX;
3480 return EC_Normal;
3481 }
3482
terminatePrintSpooler()3483 OFCondition DVInterface::terminatePrintSpooler()
3484 {
3485 if (getSpoolerName()==NULL) return EC_IllegalCall;
3486 if (configPath.empty()) return EC_IllegalCall;
3487
3488 DVPSHelper::cleanChildren(); // clean up old child processes before creating new ones
3489 OFString spoolFilename;
3490 OFString tempFilename;
3491 const char *prt = NULL;
3492
3493 DCMPSTAT_LOGFILE("Terminating print spooler process ...");
3494
3495 Uint32 numberOfPrinters = getNumberOfTargets(DVPSE_printAny);
3496 if (numberOfPrinters > 0) for (Uint32 i=0; i < numberOfPrinters; i++)
3497 {
3498 prt = getTargetID(i, DVPSE_printAny);
3499 if (EC_Normal != createPrintJobFilenames(prt, tempFilename, spoolFilename)) return EC_IllegalCall;
3500 FILE *outf = fopen(tempFilename.c_str(),"wb");
3501 if (outf)
3502 {
3503 OFString timeString;
3504 OFDateTime::getCurrentDateTime().getISOFormattedDateTime(timeString);
3505 fprintf(outf,"#\n# print job created %s\n", timeString.c_str());
3506 fprintf(outf,"# target printer: [%s]\n#\n", (prt ? prt : "none"));
3507 fprintf(outf,"terminate\n");
3508 fclose(outf);
3509 if (0 != rename(tempFilename.c_str(), spoolFilename.c_str()))
3510 {
3511 DCMPSTAT_ERROR("Unable to activate spooler termination request '" << spoolFilename.c_str() << "'");
3512 return EC_IllegalCall;
3513 }
3514 } else {
3515 DCMPSTAT_ERROR("Unable to create spooler termination request '" << tempFilename.c_str() << "'");
3516 return EC_IllegalCall;
3517 }
3518 }
3519 return EC_Normal;
3520 }
3521
startPrintServer()3522 OFCondition DVInterface::startPrintServer()
3523 {
3524 const char *application = getPrintServerName();
3525 if (application==NULL) return EC_IllegalCall;
3526 if (configPath.empty()) return EC_IllegalCall;
3527
3528 const char *printer = NULL;
3529 OFBool detailedLog = getDetailedLog();
3530
3531 OFCondition result = EC_Normal;
3532 DCMPSTAT_LOGFILE("Starting print server process ...");
3533
3534 DVPSHelper::cleanChildren(); // clean up old child processes before creating new ones
3535
3536 Uint32 numberOfPrinters = getNumberOfTargets(DVPSE_printLocal);
3537 if (numberOfPrinters > 0) for (Uint32 i=0; i < numberOfPrinters; i++)
3538 {
3539 printer = getTargetID(i, DVPSE_printLocal);
3540
3541 #ifdef HAVE_FORK
3542 // Unix version - call fork() and execl()
3543 pid_t pid = fork();
3544 if (pid < 0) result = EC_IllegalCall; // fork failed - return error code
3545 else if (pid==0)
3546 {
3547 // we are the child process
3548
3549 if (detailedLog)
3550 {
3551 if (execl(application, application, "--logfile", "--verbose", "--dump", "--printer", printer, "--config",
3552 configPath.c_str(), OFreinterpret_cast(char *, 0)) < 0)
3553 {
3554 DCMPSTAT_ERROR("Unable to execute '" << application << "'");
3555 }
3556 } else {
3557 if (execl(application, application, "--logfile", "--printer", printer, "--config", configPath.c_str(), OFreinterpret_cast(char *, 0)) < 0)
3558 {
3559 DCMPSTAT_ERROR("Unable to execute '" << application << "'");
3560 }
3561 }
3562
3563 // if execl succeeds, this part will not get executed.
3564 // if execl fails, there is not much we can do except bailing out.
3565 abort();
3566 }
3567 #else
3568 // Windows version - call CreateProcess()
3569 // initialize startup info
3570 PROCESS_INFORMATION procinfo;
3571 STARTUPINFOA sinfo;
3572 OFBitmanipTemplate<char>::zeroMem((char *)&sinfo, sizeof(sinfo));
3573 sinfo.cb = sizeof(sinfo);
3574 char commandline[4096];
3575 if (detailedLog)
3576 {
3577 sprintf(commandline, "%s --logfile --verbose --dump --printer %s --config %s", application, printer, configPath.c_str());
3578 } else {
3579 sprintf(commandline, "%s --logfile --printer %s --config %s", application, printer, configPath.c_str());
3580 }
3581 #ifdef DEBUG
3582 if (0 == CreateProcessA(NULL, commandline, NULL, NULL, 0, 0, NULL, NULL, &sinfo, &procinfo))
3583 #else
3584 if (0 == CreateProcessA(NULL, commandline, NULL, NULL, 0, DETACHED_PROCESS, NULL, NULL, &sinfo, &procinfo))
3585 #endif
3586 {
3587 DCMPSTAT_ERROR("Unable to execute '" << application << "'");
3588 result = EC_IllegalCall;
3589 }
3590 #endif
3591 }
3592 return result; // result of last process only
3593 }
3594
terminatePrintServer()3595 OFCondition DVInterface::terminatePrintServer()
3596 {
3597 if (getPrintServerName()==NULL) return EC_IllegalCall;
3598 if (configPath.empty()) return EC_IllegalCall;
3599
3600 OFStandard::initializeNetwork();
3601
3602 OFCondition result = EC_Normal;
3603 T_ASC_Network *net=NULL;
3604 T_ASC_Parameters *params=NULL;
3605 DIC_NODENAME peerHost;
3606 T_ASC_Association *assoc=NULL;
3607 const char *target = NULL;
3608 OFBool useTLS = OFFalse;
3609
3610 DCMPSTAT_LOGFILE("Terminating print server process ...");
3611
3612 #ifdef WITH_OPENSSL
3613 /* TLS directory */
3614 const char *current = NULL;
3615 const char *tlsFolder = getTLSFolder();
3616 if (tlsFolder==NULL) tlsFolder = ".";
3617
3618 /* key file format */
3619 DcmKeyFileFormat keyFileFormat = DCF_Filetype_PEM;
3620 if (! getTLSPEMFormat()) keyFileFormat = DCF_Filetype_ASN1;
3621 #endif
3622
3623 Uint32 numberOfPrinters = getNumberOfTargets(DVPSE_printLocal);
3624 if (numberOfPrinters > 0) for (Uint32 i=0; i < numberOfPrinters; i++)
3625 {
3626 target = getTargetID(i, DVPSE_printLocal);
3627 useTLS = getTargetUseTLS(target);
3628
3629 OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, 30, &net);
3630 if (cond.good())
3631 {
3632 cond = ASC_createAssociationParameters(¶ms, DEFAULT_MAXPDU);
3633 if (cond.good())
3634 {
3635 if (useTLS)
3636 {
3637 #ifdef WITH_OPENSSL
3638 /* certificate file */
3639 OFString tlsCertificateFile(tlsFolder);
3640 tlsCertificateFile += PATH_SEPARATOR;
3641 current = getTargetCertificate(target);
3642 if (current) tlsCertificateFile += current; else tlsCertificateFile += "sitecert.pem";
3643
3644 /* private key file */
3645 OFString tlsPrivateKeyFile(tlsFolder);
3646 tlsPrivateKeyFile += PATH_SEPARATOR;
3647 current = getTargetPrivateKey(target);
3648 if (current) tlsPrivateKeyFile += current; else tlsPrivateKeyFile += "sitekey.pem";
3649
3650 /* private key password */
3651 const char *tlsPrivateKeyPassword = getTargetPrivateKeyPassword(target);
3652
3653 /* DH parameter file */
3654 OFString tlsDHParametersFile;
3655 current = getTargetDiffieHellmanParameters(target);
3656 if (current)
3657 {
3658 tlsDHParametersFile = tlsFolder;
3659 tlsDHParametersFile += PATH_SEPARATOR;
3660 tlsDHParametersFile += current;
3661 }
3662
3663 /* random seed file */
3664 OFString tlsRandomSeedFile(tlsFolder);
3665 tlsRandomSeedFile += PATH_SEPARATOR;
3666 current = getTargetRandomSeed(target);
3667 if (current) tlsRandomSeedFile += current; else tlsRandomSeedFile += "siteseed.bin";
3668
3669 /* CA certificate directory */
3670 const char *tlsCACertificateFolder = getTLSCACertificateFolder();
3671 if (tlsCACertificateFolder==NULL) tlsCACertificateFolder = ".";
3672
3673
3674 DcmTLSTransportLayer *tLayer = new DcmTLSTransportLayer(NET_REQUESTOR, tlsRandomSeedFile.c_str(), OFTrue);
3675 if (tLayer)
3676 {
3677 if (tlsCACertificateFolder) tLayer->addTrustedCertificateDir(tlsCACertificateFolder, keyFileFormat);
3678 if (tlsDHParametersFile.size() > 0) tLayer->setTempDHParameters(tlsDHParametersFile.c_str());
3679 tLayer->setPrivateKeyPasswd(tlsPrivateKeyPassword); // never prompt on console
3680 tLayer->setPrivateKeyFile(tlsPrivateKeyFile.c_str(), keyFileFormat);
3681 tLayer->setCertificateFile(tlsCertificateFile.c_str(), keyFileFormat);
3682 tLayer->setCertificateVerification(DCV_ignoreCertificate);
3683
3684 // determine TLS profile
3685 OFString profileName;
3686 const char *profileNamePtr = getTargetTLSProfile(target);
3687 if (profileNamePtr) profileName = profileNamePtr;
3688 DcmTLSSecurityProfile tlsProfile = TSP_Profile_BCP195; // default
3689 if (profileName == "BCP195-ND") tlsProfile = TSP_Profile_BCP195_ND;
3690 else if (profileName == "BCP195-EX") tlsProfile = TSP_Profile_BCP195_Extended;
3691 else if (profileName == "BCP195") tlsProfile = TSP_Profile_BCP195;
3692 else if (profileName == "AES") tlsProfile = TSP_Profile_AES;
3693 else if (profileName == "BASIC") tlsProfile = TSP_Profile_Basic;
3694 else if (profileName == "NULL") tlsProfile = TSP_Profile_IHE_ATNA_Unencrypted;
3695
3696 // set TLS profile
3697 (void) tLayer->setTLSProfile(tlsProfile);
3698
3699 // activate cipher suites
3700 (void) tLayer->activateCipherSuites();
3701
3702 ASC_setTransportLayer(net, tLayer, 1);
3703 }
3704 #else
3705 // we cannot shutdown a TLS process since we're compiled without OpenSSL support
3706 cond = EC_IllegalCall;
3707 #endif
3708 }
3709
3710 ASC_setAPTitles(params, getNetworkAETitle(), getTargetAETitle(target), NULL);
3711 sprintf(peerHost, "%s:%d", getTargetHostname(target), OFstatic_cast(int, getTargetPort(target)));
3712 ASC_setPresentationAddresses(params, OFStandard::getHostName().c_str(), peerHost);
3713
3714 if (cond.good()) cond = ASC_setTransportLayerType(params, useTLS);
3715
3716 const char* transferSyntaxes[] = { UID_LittleEndianImplicitTransferSyntax };
3717 if (cond.good()) cond = ASC_addPresentationContext(params, 1, UID_PrivateShutdownSOPClass, transferSyntaxes, 1);
3718 if (cond.good())
3719 {
3720 cond = ASC_requestAssociation(net, params, &assoc);
3721 if (cond.good()) ASC_abortAssociation(assoc); // tear down association if necessary
3722 ASC_dropAssociation(assoc);
3723 ASC_destroyAssociation(&assoc);
3724 }
3725 } else result = EC_IllegalCall;
3726 ASC_dropNetwork(&net);
3727 } else result = EC_IllegalCall;
3728 }
3729
3730 OFStandard::shutdownNetwork();
3731
3732 return result; // result of last process only
3733 }
3734
addToPrintHardcopyFromDB(const char * studyUID,const char * seriesUID,const char * instanceUID)3735 OFCondition DVInterface::addToPrintHardcopyFromDB(const char *studyUID, const char *seriesUID, const char *instanceUID)
3736 {
3737 OFCondition result = EC_IllegalCall;
3738
3739 if (pPrint)
3740 {
3741 if (studyUID && seriesUID && instanceUID)
3742 {
3743 if (EC_Normal == (result = lockDatabase()))
3744 {
3745 DcmUniqueIdentifier sopclassuid(DCM_SOPClassUID);
3746 const char *filename = getFilename(studyUID, seriesUID, instanceUID);
3747 if (filename)
3748 {
3749 DcmFileFormat *ff = NULL;
3750 if ((result = DVPSHelper::loadFileFormat(filename, ff)) == EC_Normal)
3751 {
3752 if (ff)
3753 {
3754 DcmDataset *dataset = ff->getDataset();
3755 if (dataset)
3756 {
3757 DcmStack stack;
3758 DVPSPresentationLUT presentationLUT;
3759 if (EC_Normal != presentationLUT.read(*dataset, OFFalse)) presentationLUT.setType(DVPSP_identity);
3760 result = dataset->search(sopclassuid.getTag(), stack, ESM_fromHere, OFFalse);
3761 if (EC_Normal == result)
3762 {
3763 char *sopclass = NULL;
3764 sopclassuid = *OFstatic_cast(DcmUniqueIdentifier *, stack.top());
3765 if (EC_Normal == sopclassuid.getString(sopclass))
3766 result = pPrint->addImageBox(getNetworkAETitle(), studyUID, seriesUID,
3767 sopclass, instanceUID, NULL, NULL, &presentationLUT, OFFalse);
3768 else
3769 result = EC_IllegalCall;
3770 }
3771 } else result = EC_CorruptedData;
3772 } else result = EC_IllegalCall;
3773 if (result != EC_Normal)
3774 DCMPSTAT_LOGFILE("Load hardcopy grayscale image from file failed: invalid data structures");
3775 } else
3776 DCMPSTAT_LOGFILE("Load hardcopy grayscale image from file failed: could not read fileformat");
3777 if (ff) delete ff;
3778 } else {
3779 result = EC_IllegalCall;
3780 DCMPSTAT_LOGFILE("Load hardcopy grayscale image from database failed: UIDs not in index file");
3781 }
3782 } else
3783 DCMPSTAT_LOGFILE("Load hardcopy grayscale image from database failed: could not lock index file");
3784 } else
3785 DCMPSTAT_LOGFILE("Load hardcopy grayscale image from database failed: invalid UIDs");
3786 }
3787
3788 releaseDatabase();
3789 return result;
3790 }
3791
spoolStoredPrintFromDB(const char * studyUID,const char * seriesUID,const char * instanceUID)3792 OFCondition DVInterface::spoolStoredPrintFromDB(const char *studyUID, const char *seriesUID, const char *instanceUID)
3793 {
3794 if ((studyUID==NULL)||(seriesUID==NULL)||(instanceUID==NULL)||configPath.empty()) return EC_IllegalCall;
3795 OFString spoolFilename;
3796 OFString tempFilename;
3797 const char *prt = getCurrentPrinter();
3798 if (EC_Normal != createPrintJobFilenames(prt, tempFilename, spoolFilename)) return EC_IllegalCall;
3799
3800 FILE *outf = fopen(tempFilename.c_str(),"wb");
3801 if (outf)
3802 {
3803 OFString timeString;
3804 OFDateTime::getCurrentDateTime().getISOFormattedDateTime(timeString);
3805 fprintf(outf, "#\n# print job created %s\n", timeString.c_str());
3806 fprintf(outf, "# target printer: [%s]\n#\n", (prt ? prt : "none"));
3807 fprintf(outf, "study %s\nseries %s\ninstance %s\n", studyUID, seriesUID, instanceUID);
3808 if (printerMediumType.size() >0) fprintf(outf,"mediumtype %s\n", printerMediumType.c_str());
3809 if (printerFilmDestination.size() >0) fprintf(outf,"destination %s\n", printerFilmDestination.c_str());
3810 if (printerFilmSessionLabel.size() >0) fprintf(outf,"label %s\n", printerFilmSessionLabel.c_str());
3811 if (printerPriority.size() >0) fprintf(outf,"priority %s\n", printerPriority.c_str());
3812 if (printerOwnerID.size() >0) fprintf(outf,"owner_id %s\n", printerOwnerID.c_str());
3813 if (printerNumberOfCopies >0) fprintf(outf,"copies %lu\n", printerNumberOfCopies);
3814
3815 fclose(outf);
3816 if (0 != rename(tempFilename.c_str(), spoolFilename.c_str()))
3817 {
3818 DCMPSTAT_ERROR("Unable to activate print job '" << spoolFilename.c_str() << "'");
3819 return EC_IllegalCall;
3820 }
3821 } else {
3822 DCMPSTAT_ERROR("Unable to create print job '" << tempFilename.c_str() << "'");
3823 return EC_IllegalCall;
3824 }
3825 return EC_Normal;
3826 }
3827
printSCUcreateBasicFilmSession(DVPSPrintMessageHandler & printHandler,OFBool plutInSession)3828 OFCondition DVInterface::printSCUcreateBasicFilmSession(DVPSPrintMessageHandler& printHandler, OFBool plutInSession)
3829 {
3830 if (!pPrint) return EC_IllegalCall;
3831 OFCondition result = EC_Normal;
3832 DcmDataset dset;
3833 DcmElement *delem = NULL;
3834 char buf[30];
3835
3836 if ((EC_Normal==result)&&(printerMediumType.size() > 0))
3837 {
3838 delem = new DcmCodeString(DCM_MediumType);
3839 if (delem) result = delem->putString(printerMediumType.c_str()); else result=EC_IllegalCall;
3840 if (EC_Normal==result) result = dset.insert(delem, OFTrue /*replaceOld*/);
3841 }
3842
3843 if ((EC_Normal==result)&&(printerFilmDestination.size() > 0))
3844 {
3845 delem = new DcmCodeString(DCM_FilmDestination);
3846 if (delem) result = delem->putString(printerFilmDestination.c_str()); else result=EC_IllegalCall;
3847 if (EC_Normal==result) result = dset.insert(delem, OFTrue /*replaceOld*/);
3848 }
3849
3850 if ((EC_Normal==result)&&(printerFilmSessionLabel.size() > 0))
3851 {
3852 delem = new DcmLongString(DCM_FilmSessionLabel);
3853 if (delem) result = delem->putString(printerFilmSessionLabel.c_str()); else result=EC_IllegalCall;
3854 if (EC_Normal==result) result = dset.insert(delem, OFTrue /*replaceOld*/);
3855 }
3856
3857 if ((EC_Normal==result)&&(printerPriority.size() > 0))
3858 {
3859 delem = new DcmCodeString(DCM_PrintPriority);
3860 if (delem) result = delem->putString(printerPriority.c_str()); else result=EC_IllegalCall;
3861 if (EC_Normal==result) result = dset.insert(delem, OFTrue /*replaceOld*/);
3862 }
3863
3864 if ((EC_Normal==result)&&(printerOwnerID.size() > 0))
3865 {
3866 delem = new DcmShortString(DCM_OwnerID);
3867 if (delem) result = delem->putString(printerOwnerID.c_str()); else result=EC_IllegalCall;
3868 if (EC_Normal==result) result = dset.insert(delem, OFTrue /*replaceOld*/);
3869 }
3870
3871 if ((EC_Normal==result)&&(printerNumberOfCopies > 0))
3872 {
3873 sprintf(buf, "%lu", printerNumberOfCopies);
3874 delem = new DcmIntegerString(DCM_NumberOfCopies);
3875 if (delem) result = delem->putString(buf); else result=EC_IllegalCall;
3876 if (EC_Normal==result) result = dset.insert(delem, OFTrue /*replaceOld*/);
3877 }
3878
3879 if (EC_Normal==result) result = pPrint->printSCUcreateBasicFilmSession(printHandler, dset, plutInSession);
3880 return result;
3881 }
3882
clearFilmSessionSettings()3883 void DVInterface::clearFilmSessionSettings()
3884 {
3885 printerMediumType.clear();
3886 printerFilmDestination.clear();
3887 printerFilmSessionLabel.clear();
3888 printerPriority.clear();
3889 printerOwnerID.clear();
3890 printerNumberOfCopies = 0;
3891 return;
3892 }
3893
setAnnotationText(const char * value)3894 void DVInterface::setAnnotationText(const char *value)
3895 {
3896 if (value) annotationText=value; else annotationText.clear();
3897 return;
3898 }
3899
startExternalApplication(const char * application,const char * filename)3900 OFCondition DVInterface::startExternalApplication(const char *application, const char *filename)
3901 {
3902 if ((filename==NULL)||(application==NULL)) return EC_IllegalCall;
3903 DVPSHelper::cleanChildren(); // clean up old child processes before creating new ones
3904
3905 #ifdef HAVE_FORK
3906 // Unix version - call fork() and execl()
3907 pid_t pid = fork();
3908 if (pid < 0) return EC_IllegalCall; // fork failed - return error code
3909 else if (pid > 0) return EC_Normal; // we are the parent process
3910 else
3911 {
3912 // we are the child process
3913 if (execl(application, application, filename, OFreinterpret_cast(char *, 0)) < 0)
3914 {
3915 DCMPSTAT_ERROR("Unable to execute '" << application << "'");
3916 }
3917 // if execl succeeds, this part will not get executed.
3918 // if execl fails, there is not much we can do except bailing out.
3919 abort();
3920 }
3921 #else
3922 // Windows version - call CreateProcess()
3923
3924 // initialize startup info
3925 PROCESS_INFORMATION procinfo;
3926 STARTUPINFOA sinfo;
3927 OFBitmanipTemplate<char>::zeroMem((char *)&sinfo, sizeof(sinfo));
3928 sinfo.cb = sizeof(sinfo);
3929 char commandline[4096];
3930 sprintf(commandline, "%s %s", application, filename);
3931 #ifdef DEBUG
3932 if (CreateProcessA(NULL, commandline, NULL, NULL, 0, 0, NULL, NULL, &sinfo, &procinfo))
3933 #else
3934 if (CreateProcessA(NULL, commandline, NULL, NULL, 0, DETACHED_PROCESS, NULL, NULL, &sinfo, &procinfo))
3935 #endif
3936 {
3937 return EC_Normal;
3938 } else {
3939 DCMPSTAT_ERROR("Unable to execute '" << application << "'");
3940 }
3941 #endif
3942 return EC_IllegalCall;
3943 }
3944
dumpIOD(const char * filename)3945 OFCondition DVInterface::dumpIOD(const char *filename)
3946 {
3947 OFCondition result = startExternalApplication(getDumpToolName(), filename);
3948 if (result != EC_Normal)
3949 DCMPSTAT_LOGFILE("Dump IOD failed: could not start dump application");
3950 return result;
3951 }
3952
dumpIOD(const char * studyUID,const char * seriesUID,const char * instanceUID)3953 OFCondition DVInterface::dumpIOD(const char *studyUID, const char *seriesUID, const char *instanceUID)
3954 {
3955 OFCondition result = EC_IllegalCall;
3956 if (studyUID && seriesUID && instanceUID)
3957 {
3958 if (EC_Normal == (result = lockDatabase()))
3959 {
3960 const char *filename = getFilename(studyUID, seriesUID, instanceUID);
3961 if (filename)
3962 result = dumpIOD(filename);
3963 else
3964 {
3965 result = EC_IllegalCall;
3966 DCMPSTAT_LOGFILE("Dump IOD from database failed: could not lock index file");
3967 }
3968 } else
3969 DCMPSTAT_LOGFILE("Dump IOD from database failed: UIDs not in index file");
3970 } else
3971 DCMPSTAT_LOGFILE("Dump IOD from database failed: invalid UIDs");
3972 return result;
3973 }
3974
checkIOD(const char * filename)3975 OFCondition DVInterface::checkIOD(const char *filename)
3976 {
3977 OFCondition result = startExternalApplication(getCheckToolName(), filename);
3978 if (result != EC_Normal)
3979 DCMPSTAT_LOGFILE("Check IOD failed: could not start evaluator application");
3980 return result;
3981 }
3982
checkIOD(const char * studyUID,const char * seriesUID,const char * instanceUID)3983 OFCondition DVInterface::checkIOD(const char *studyUID, const char *seriesUID, const char *instanceUID)
3984 {
3985 OFCondition result = EC_IllegalCall;
3986 if (studyUID && seriesUID && instanceUID)
3987 {
3988 if (EC_Normal == (result = lockDatabase()))
3989 {
3990 const char *filename = getFilename(studyUID, seriesUID, instanceUID);
3991 if (filename)
3992 result = checkIOD(filename);
3993 else
3994 {
3995 result = EC_IllegalCall;
3996 DCMPSTAT_LOGFILE("Check IOD from database failed: could not lock index file");
3997 }
3998 } else
3999 DCMPSTAT_LOGFILE("Check IOD from database failed: UIDs not in index file");
4000 } else
4001 DCMPSTAT_LOGFILE("Check IOD from database failed: invalid UIDs");
4002 return result;
4003 }
4004
4005 #ifdef WITH_OPENSSL
4006
4007 /* buf : buffer to write password into
4008 * size : length of buffer in bytes
4009 * rwflag : nonzero if the password will be used as a new password, i.e. user should be asked to repeat the password
4010 * userdata: arbitrary pointer that can be set with SSL_CTX_set_default_passwd_cb_userdata()
4011 * returns : number of bytes written to password buffer, -1 upon error
4012 */
4013 extern "C" int DVInterfacePasswordCallback(char *buf, int size, int rwflag, void *userdata);
4014
DVInterfacePasswordCallback(char * buf,int size,int,void * userdata)4015 int DVInterfacePasswordCallback(char *buf, int size, int /* rwflag */, void *userdata)
4016 {
4017 if (userdata == NULL) return -1;
4018 OFString *password = OFstatic_cast(OFString *, userdata);
4019 int passwordSize = OFstatic_cast(int, password->length());
4020 if (passwordSize > size) passwordSize = size;
4021 strncpy(buf, password->c_str(), passwordSize);
4022 return passwordSize;
4023 }
4024
4025 #endif
4026
4027
4028 #ifdef WITH_OPENSSL
verifyUserPassword(const char * userID,const char * passwd)4029 OFBool DVInterface::verifyUserPassword(const char *userID, const char *passwd)
4030 #else
4031 OFBool DVInterface::verifyUserPassword(const char * /*userID*/, const char * /*passwd*/)
4032 #endif
4033 {
4034 OFBool result = OFFalse;
4035 #ifdef WITH_OPENSSL
4036 OFString filename;
4037 OFString privateKeyPasswd;
4038 if (passwd) privateKeyPasswd = passwd;
4039 OFBool isPEMFormat = getTLSPEMFormat();
4040 const char *userKey = getUserPrivateKey(userID);
4041 if (userKey == NULL)
4042 DCMPSTAT_LOGFILE("Cannot verify user password: unknown user or undefined private key file");
4043 else
4044 {
4045 const char *userDir = getUserCertificateFolder();
4046 if (userDir)
4047 {
4048 filename = userDir;
4049 filename += PATH_SEPARATOR;
4050 }
4051 filename += userKey;
4052
4053 /* attempt to load the private key with the given password*/
4054 EVP_PKEY *pkey = NULL;
4055 BIO *in = BIO_new(BIO_s_file());
4056 if (in)
4057 {
4058 if (BIO_read_filename(in, filename.c_str()) > 0)
4059 {
4060 if (isPEMFormat)
4061 {
4062 pkey = PEM_read_bio_PrivateKey(in, NULL, DVInterfacePasswordCallback, &privateKeyPasswd);
4063 if (pkey) result = OFTrue;
4064 } else {
4065 // ASN.1/DER encoded keys are never encrypted, thus no callback here.
4066 pkey = d2i_PrivateKey_bio(in, NULL);
4067 if (pkey) result = OFTrue;
4068 }
4069 } else
4070 DCMPSTAT_LOGFILE("Cannot verify user password: private key file not found");
4071 BIO_free(in);
4072 }
4073 if (pkey) EVP_PKEY_free(pkey);
4074 }
4075 #else
4076 DCMPSTAT_LOGFILE("Cannot verify user password: not compiled with OpenSSL support");
4077 #endif
4078 return result;
4079 }
4080
4081 #ifdef WITH_OPENSSL
verifyAndSignStructuredReport(const char * userID,const char * passwd,DVPSVerifyAndSignMode mode)4082 OFCondition DVInterface::verifyAndSignStructuredReport(const char *userID, const char *passwd, DVPSVerifyAndSignMode mode)
4083 #else
4084 OFCondition DVInterface::verifyAndSignStructuredReport(const char *userID, const char * /*passwd*/, DVPSVerifyAndSignMode mode)
4085 #endif
4086 {
4087 OFCondition result = EC_IllegalCall;
4088 if ((pReport != NULL) && (userID != NULL))
4089 {
4090 OFString userName(getUserDICOMName(userID));
4091 OFString userOrg(getUserOrganization(userID));
4092 OFString userCV, userCSD, userCSV, userCM;
4093 DSRCodedEntryValue userCode(getUserCodeValue(userID, userCV), getUserCodingSchemeDesignator(userID, userCSD),
4094 getUserCodingSchemeVersion(userID, userCSV), getUserCodeMeaning(userID, userCM));
4095 /* verify document */
4096 if (pReport->verifyDocument(userName, userCode, userOrg) == EC_Normal)
4097 {
4098 if ((mode == DVPSY_verifyAndSign) || (mode == DVPSY_verifyAndSign_finalize))
4099 {
4100 #ifdef WITH_OPENSSL
4101 if (pSignatureHandler)
4102 {
4103 DcmStack stack;
4104 DcmItem dataset;
4105 if (pReport->write(dataset, &stack) == EC_Normal)
4106 {
4107 DcmAttributeTag tagList(DcmTag(0, 0) /* irrelevant value */);
4108 if (mode == DVPSY_verifyAndSign)
4109 {
4110 /* do not sign particular attributes */
4111 tagList.putTagVal(DCM_SOPInstanceUID, 0);
4112 tagList.putTagVal(DCM_VerifyingObserverSequence, 1);
4113 tagList.putTagVal(DCM_InstanceCreationDate, 2);
4114 tagList.putTagVal(DCM_InstanceCreationTime, 3);
4115 tagList.putTagVal(DCM_InstanceCreatorUID, 4);
4116 }
4117 else if (mode == DVPSY_verifyAndSign_finalize)
4118 {
4119 /* always sign the entire document */
4120 stack.clear();
4121 }
4122 /* if no item is marked, sign entire dataset */
4123 if (stack.empty())
4124 stack.push(&dataset);
4125 /* digitally sign document */
4126 if (pSignatureHandler->createSignature(dataset, stack, tagList, userID, passwd) == EC_Normal)
4127 {
4128 DSRDocument *newReport = new DSRDocument();
4129 if (newReport != NULL)
4130 {
4131 if (newReport->read(dataset, DSRTypes::RF_readDigitalSignatures) == EC_Normal)
4132 {
4133 /* replace report in memory */
4134 delete pReport;
4135 pReport = newReport;
4136 pSignatureHandler->updateDigitalSignatureInformation(dataset, DVPSS_structuredReport, OFFalse /* onRead? */);
4137 if (mode == DVPSY_verifyAndSign_finalize)
4138 result = pReport->finalizeDocument();
4139 else
4140 result = EC_Normal;
4141 }
4142 } else
4143 result = EC_MemoryExhausted;
4144 }
4145 }
4146 }
4147 #else
4148 DCMPSTAT_LOGFILE("Cannot sign structured report: not compiled with OpenSSL support");
4149 #endif
4150 } else
4151 result= EC_Normal;
4152 }
4153 }
4154 return result;
4155 }
4156
getCurrentSignatureValidationHTML(DVPSObjectType objtype) const4157 const char *DVInterface::getCurrentSignatureValidationHTML(DVPSObjectType objtype) const
4158 {
4159 return pSignatureHandler->getCurrentSignatureValidationHTML(objtype);
4160 }
4161
getCurrentSignatureValidationOverview() const4162 const char *DVInterface::getCurrentSignatureValidationOverview() const
4163 {
4164 return pSignatureHandler->getCurrentSignatureValidationOverview();
4165 }
4166
getCurrentSignatureStatus(DVPSObjectType objtype) const4167 DVPSSignatureStatus DVInterface::getCurrentSignatureStatus(DVPSObjectType objtype) const
4168 {
4169 return pSignatureHandler->getCurrentSignatureStatus(objtype);
4170 }
4171
getCombinedImagePStateSignatureStatus() const4172 DVPSSignatureStatus DVInterface::getCombinedImagePStateSignatureStatus() const
4173 {
4174 return pSignatureHandler->getCombinedImagePStateSignatureStatus();
4175 }
4176
getNumberOfCorrectSignatures(DVPSObjectType objtype) const4177 unsigned long DVInterface::getNumberOfCorrectSignatures(DVPSObjectType objtype) const
4178 {
4179 return pSignatureHandler->getNumberOfCorrectSignatures(objtype);
4180 }
4181
getNumberOfUntrustworthySignatures(DVPSObjectType objtype) const4182 unsigned long DVInterface::getNumberOfUntrustworthySignatures(DVPSObjectType objtype) const
4183 {
4184 return pSignatureHandler->getNumberOfUntrustworthySignatures(objtype);
4185 }
4186
getNumberOfCorruptSignatures(DVPSObjectType objtype) const4187 unsigned long DVInterface::getNumberOfCorruptSignatures(DVPSObjectType objtype) const
4188 {
4189 return pSignatureHandler->getNumberOfCorruptSignatures(objtype);
4190 }
4191
disableImageAndPState()4192 void DVInterface::disableImageAndPState()
4193 {
4194 pSignatureHandler->disableImageAndPState();
4195 }
4196