1 /*
2  *
3  *  Copyright (C) 1999-2010, OFFIS e.V.
4  *  All rights reserved.  See COPYRIGHT file for details.
5  *
6  *  This software and supporting documentation were developed by
7  *
8  *    OFFIS e.V.
9  *    R&D Division Health
10  *    Escherweg 2
11  *    D-26121 Oldenburg, Germany
12  *
13  *
14  *  Module: dcmpstat
15  *
16  *  Author: Marco Eichelberg
17  *
18  *  Purpose:
19  *    classes: DVPSImageBoxContent_PList
20  *
21  */
22 
23 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
24 #include "dcmtk/dcmpstat/dvpsibl.h"
25 #include "dcmtk/dcmpstat/dvpsib.h"      /* for DVPSImageBoxContent */
26 #include "dcmtk/dcmpstat/dvpshlp.h"     /* for class DVPSHelper */
27 
28 /* --------------- class DVPSImageBoxContent_PList --------------- */
29 
DVPSImageBoxContent_PList()30 DVPSImageBoxContent_PList::DVPSImageBoxContent_PList()
31 : list_()
32 {
33 }
34 
DVPSImageBoxContent_PList(const DVPSImageBoxContent_PList & arg)35 DVPSImageBoxContent_PList::DVPSImageBoxContent_PList(const DVPSImageBoxContent_PList &arg)
36 : list_()
37 {
38   OFListConstIterator(DVPSImageBoxContent *) first = arg.list_.begin();
39   OFListConstIterator(DVPSImageBoxContent *) last = arg.list_.end();
40   while (first != last)
41   {
42     list_.push_back((*first)->clone());
43     ++first;
44   }
45 }
46 
~DVPSImageBoxContent_PList()47 DVPSImageBoxContent_PList::~DVPSImageBoxContent_PList()
48 {
49   clear();
50 }
51 
clear()52 void DVPSImageBoxContent_PList::clear()
53 {
54   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
55   OFListIterator(DVPSImageBoxContent *) last = list_.end();
56   while (first != last)
57   {
58     delete (*first);
59     first = list_.erase(first);
60   }
61 }
62 
read(DcmItem & dset,DVPSPresentationLUT_PList & presentationLUTList)63 OFCondition DVPSImageBoxContent_PList::read(DcmItem &dset, DVPSPresentationLUT_PList& presentationLUTList)
64 {
65   OFCondition result = EC_Normal;
66   DcmStack stack;
67   DVPSImageBoxContent *newImage = NULL;
68   DcmSequenceOfItems *dseq=NULL;
69   DcmItem *ditem=NULL;
70 
71   if (EC_Normal == dset.search(DCM_RETIRED_ImageBoxContentSequence, stack, ESM_fromHere, OFFalse))
72   {
73     dseq=(DcmSequenceOfItems *)stack.top();
74     if (dseq)
75     {
76       unsigned long numItems = dseq->card();
77       for (unsigned int i=0; i<numItems; i++)
78       {
79         ditem = dseq->getItem(i);
80         newImage = new DVPSImageBoxContent();
81         if (newImage && ditem)
82         {
83           result = newImage->read(*ditem, presentationLUTList);
84           list_.push_back(newImage);
85         } else result = EC_MemoryExhausted;
86       }
87     }
88   }
89 
90   return result;
91 }
92 
write(DcmItem & dset,OFBool writeRequestedImageSize,size_t numItems,OFBool ignoreEmptyImages,OFBool writeReferencedPLUTSQ)93 OFCondition DVPSImageBoxContent_PList::write(
94   DcmItem &dset,
95   OFBool writeRequestedImageSize,
96   size_t numItems,
97   OFBool ignoreEmptyImages,
98   OFBool writeReferencedPLUTSQ)
99 {
100   if (size()==0) return EC_IllegalCall; // can't write if sequence is empty
101 
102   OFCondition result = EC_Normal;
103   DcmSequenceOfItems *dseq=NULL;
104   DcmItem *ditem=NULL;
105   OFBool working = OFTrue;
106   unsigned long numWritten = 0;
107 
108   dseq = new DcmSequenceOfItems(DCM_RETIRED_ImageBoxContentSequence);
109   if (dseq)
110   {
111     OFListIterator(DVPSImageBoxContent *) first = list_.begin();
112     OFListIterator(DVPSImageBoxContent *) last = list_.end();
113     while ((first != last) && working)
114     {
115       if ((result==EC_Normal) && ((! ignoreEmptyImages)||((*first)->getImageBoxPosition() > 0)))
116       {
117         ditem = new DcmItem();
118         if (ditem)
119         {
120           result = (*first)->write(*ditem, writeRequestedImageSize, writeReferencedPLUTSQ);
121           if (result==EC_Normal)
122           {
123             dseq->insert(ditem);
124             numWritten++;
125           } else delete ditem;
126         } else result = EC_MemoryExhausted;
127       }
128       ++first;
129       if (numItems && (--numItems==0)) working=OFFalse;
130     }
131     // we're not allowed to store SP objects with empty image box list sequence
132     if ((result==EC_Normal) && (numWritten > 0)) dset.insert(dseq, OFTrue /*replaceOld*/); else delete dseq;
133   } else result = EC_MemoryExhausted;
134   return result;
135 }
136 
createDefaultValues(OFBool renumber,OFBool ignoreEmptyImages)137 OFCondition DVPSImageBoxContent_PList::createDefaultValues(OFBool renumber, OFBool ignoreEmptyImages)
138 {
139   if (size()==0) return EC_IllegalCall; // can't write if sequence is empty
140   OFCondition result = EC_Normal;
141   unsigned long counter = 1;
142 
143   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
144   OFListIterator(DVPSImageBoxContent *) last = list_.end();
145   while ((first != last)&&(EC_Normal == result))
146   {
147     result = (*first)->createDefaultValues(renumber, counter++, ignoreEmptyImages);
148     ++first;
149   }
150   return result;
151 }
152 
addImageSOPClasses(DcmSequenceOfItems & seq,size_t numItems)153 OFCondition DVPSImageBoxContent_PList::addImageSOPClasses(DcmSequenceOfItems& seq, size_t numItems)
154 {
155   OFCondition result = EC_Normal;
156   OFBool working = OFTrue;
157   const char *c = NULL;
158   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
159   OFListIterator(DVPSImageBoxContent *) last = list_.end();
160   while ((first != last) && working)
161   {
162     if (EC_Normal == result)
163     {
164       c = (*first)->getSOPClassUID();
165       if (c && (! DVPSHelper::haveReferencedUIDItem(seq, c))) result = DVPSHelper::addReferencedUIDItem(seq, c);
166     }
167     ++first;
168     if (numItems && (--numItems==0)) working=OFFalse;
169   }
170   return result;
171 }
172 
addImageBox(const char * instanceuid,const char * retrieveaetitle,const char * refstudyuid,const char * refseriesuid,const char * refsopclassuid,const char * refsopinstanceuid,const char * requestedimagesize,const char * patientid,const char * presentationlutuid)173 OFCondition DVPSImageBoxContent_PList::addImageBox(
174   const char *instanceuid,
175   const char *retrieveaetitle,
176   const char *refstudyuid,
177   const char *refseriesuid,
178   const char *refsopclassuid,
179   const char *refsopinstanceuid,
180   const char *requestedimagesize,
181   const char *patientid,
182   const char *presentationlutuid)
183 {
184   OFCondition result = EC_Normal;
185   DVPSImageBoxContent *newImage = new DVPSImageBoxContent();
186   if (newImage)
187   {
188     result = newImage->setContent(instanceuid, retrieveaetitle, refstudyuid,
189                refseriesuid, refsopclassuid, refsopinstanceuid,
190                requestedimagesize, patientid, presentationlutuid);
191     if (EC_Normal == result) list_.push_back(newImage); else delete newImage;
192   } else result = EC_MemoryExhausted;
193   return result;
194 }
195 
addImageBox(DVPSImageBoxContent * box)196 OFCondition DVPSImageBoxContent_PList::addImageBox(DVPSImageBoxContent * box)
197 {
198    list_.push_back(box);
199    return(EC_Normal);
200 }
201 
setRequestedDecimateCropBehaviour(DVPSDecimateCropBehaviour value)202 OFCondition DVPSImageBoxContent_PList::setRequestedDecimateCropBehaviour(DVPSDecimateCropBehaviour value)
203 {
204   OFCondition result=EC_Normal;
205   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
206   OFListIterator(DVPSImageBoxContent *) last = list_.end();
207   while (first != last)
208   {
209     result = (*first)->setRequestedDecimateCropBehaviour(value);
210     if (EC_Normal != result) return result;
211     ++first;
212   }
213   return result;
214 }
215 
deleteImage(size_t idx)216 OFCondition DVPSImageBoxContent_PList::deleteImage(size_t idx)
217 {
218   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
219   OFListIterator(DVPSImageBoxContent *) last = list_.end();
220   while ((first != last)&&(idx--)) ++first;
221   if (first != last)
222   {
223     delete (*first);
224     list_.erase(first);
225     return EC_Normal;
226   }
227   return EC_IllegalCall;
228 }
229 
deleteMultipleImages(size_t number)230 OFCondition DVPSImageBoxContent_PList::deleteMultipleImages(size_t number)
231 {
232   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
233   OFListIterator(DVPSImageBoxContent *) last = list_.end();
234   while ((first != last)&&(number--))
235   {
236     delete (*first);
237     first = list_.erase(first);
238   }
239   return EC_Normal;
240 }
241 
getImageBox(size_t idx)242 DVPSImageBoxContent *DVPSImageBoxContent_PList::getImageBox(size_t idx)
243 {
244   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
245   OFListIterator(DVPSImageBoxContent *) last = list_.end();
246   while (first != last)
247   {
248     if (idx==0) return *first;
249     idx--;
250     ++first;
251   }
252   return NULL;
253 }
254 
imageHasAdditionalSettings(size_t idx)255 OFBool DVPSImageBoxContent_PList::imageHasAdditionalSettings(size_t idx)
256 {
257   DVPSImageBoxContent *box = getImageBox(idx);
258   if (box) return box->hasAdditionalSettings();
259   return OFFalse;
260 }
261 
setImagePolarity(size_t idx,const char * value)262 OFCondition DVPSImageBoxContent_PList::setImagePolarity(size_t idx, const char *value)
263 {
264   DVPSImageBoxContent *box = getImageBox(idx);
265   if (box) return box->setPolarity(value);
266   return EC_IllegalCall;
267 }
268 
setImageRequestedSize(size_t idx,const char * value)269 OFCondition DVPSImageBoxContent_PList::setImageRequestedSize(size_t idx, const char *value)
270 {
271   DVPSImageBoxContent *box = getImageBox(idx);
272   if (box) return box->setRequestedImageSize(value);
273   return EC_IllegalCall;
274 }
275 
setImageMagnificationType(size_t idx,const char * value)276 OFCondition DVPSImageBoxContent_PList::setImageMagnificationType(size_t idx, const char *value)
277 {
278   DVPSImageBoxContent *box = getImageBox(idx);
279   if (box) return box->setMagnificationType(value);
280   return EC_IllegalCall;
281 }
282 
setImageSmoothingType(size_t idx,const char * value)283 OFCondition DVPSImageBoxContent_PList::setImageSmoothingType(size_t idx, const char *value)
284 {
285   DVPSImageBoxContent *box = getImageBox(idx);
286   if (box) return box->setSmoothingType(value);
287   return EC_IllegalCall;
288 }
289 
setImageConfigurationInformation(size_t idx,const char * value)290 OFCondition DVPSImageBoxContent_PList::setImageConfigurationInformation(size_t idx, const char *value)
291 {
292   DVPSImageBoxContent *box = getImageBox(idx);
293   if (box) return box->setConfigurationInformation(value);
294   return EC_IllegalCall;
295 }
296 
setImageSOPInstanceUID(size_t idx,const char * value)297 OFCondition DVPSImageBoxContent_PList::setImageSOPInstanceUID(size_t idx, const char *value)
298 {
299   DVPSImageBoxContent *box = getImageBox(idx);
300   if (box) return box->setSOPInstanceUID(value);
301   return EC_IllegalCall;
302 }
303 
getImagePolarity(size_t idx)304 const char *DVPSImageBoxContent_PList::getImagePolarity(size_t idx)
305 {
306   DVPSImageBoxContent *box = getImageBox(idx);
307   if (box) return box->getPolarity();
308   return NULL;
309 }
310 
getImageRequestedSize(size_t idx)311 const char *DVPSImageBoxContent_PList::getImageRequestedSize(size_t idx)
312 {
313   DVPSImageBoxContent *box = getImageBox(idx);
314   if (box) return box->getRequestedImageSize();
315   return NULL;
316 }
317 
getImageMagnificationType(size_t idx)318 const char *DVPSImageBoxContent_PList::getImageMagnificationType(size_t idx)
319 {
320   DVPSImageBoxContent *box = getImageBox(idx);
321   if (box) return box->getMagnificationType();
322   return NULL;
323 }
324 
getImageSmoothingType(size_t idx)325 const char *DVPSImageBoxContent_PList::getImageSmoothingType(size_t idx)
326 {
327   DVPSImageBoxContent *box = getImageBox(idx);
328   if (box) return box->getSmoothingType();
329   return NULL;
330 }
331 
getImageConfigurationInformation(size_t idx)332 const char *DVPSImageBoxContent_PList::getImageConfigurationInformation(size_t idx)
333 {
334   DVPSImageBoxContent *box = getImageBox(idx);
335   if (box) return box->getConfigurationInformation();
336   return NULL;
337 }
338 
getSOPInstanceUID(size_t idx)339 const char *DVPSImageBoxContent_PList::getSOPInstanceUID(size_t idx)
340 {
341   DVPSImageBoxContent *box = getImageBox(idx);
342   if (box) return box->getSOPInstanceUID();
343   return NULL;
344 }
345 
getReferencedPresentationLUTInstanceUID(size_t idx)346 const char *DVPSImageBoxContent_PList::getReferencedPresentationLUTInstanceUID(size_t idx)
347 {
348   DVPSImageBoxContent *box = getImageBox(idx);
349   if (box) return box->getReferencedPresentationLUTInstanceUID();
350   return NULL;
351 }
352 
setAllImagesToDefault()353 OFCondition DVPSImageBoxContent_PList::setAllImagesToDefault()
354 {
355   OFCondition result = EC_Normal;
356   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
357   OFListIterator(DVPSImageBoxContent *) last = list_.end();
358   while (first != last)
359   {
360     result = (*first)->setDefault();
361     ++first;
362     if (EC_Normal != result) return result;
363   }
364   return result;
365 }
366 
getImageReference(size_t idx,const char * & studyUID,const char * & seriesUID,const char * & instanceUID)367 OFCondition DVPSImageBoxContent_PList::getImageReference(size_t idx, const char *&studyUID, const char *&seriesUID, const char *&instanceUID)
368 {
369   DVPSImageBoxContent *box = getImageBox(idx);
370   if (box) return box->getImageReference(studyUID, seriesUID, instanceUID);
371   return EC_IllegalCall;
372 }
373 
prepareBasicImageBox(size_t idx,DcmItem & dset)374 OFCondition DVPSImageBoxContent_PList::prepareBasicImageBox(size_t idx, DcmItem &dset)
375 {
376   DVPSImageBoxContent *box = getImageBox(idx);
377   if (box) return box->prepareBasicImageBox(dset);
378   return EC_IllegalCall;
379 }
380 
presentationLUTInstanceUIDisUsed(const char * uid)381 OFBool DVPSImageBoxContent_PList::presentationLUTInstanceUIDisUsed(const char *uid)
382 {
383   OFString uidS;
384   if (uid) uidS = uid;
385   const char *c;
386 
387   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
388   OFListIterator(DVPSImageBoxContent *) last = list_.end();
389   while (first != last)
390   {
391     c = (*first)->getReferencedPresentationLUTInstanceUID();
392     if (c && (uidS == c)) return OFTrue;
393     ++first;
394   }
395   return OFFalse;
396 }
397 
haveSinglePresentationLUTUsed(const char * filmBox)398 const char *DVPSImageBoxContent_PList::haveSinglePresentationLUTUsed(const char *filmBox)
399 {
400   OFList<char *> uidList;
401   if (filmBox==NULL) filmBox = "";
402   const char *c;
403   OFString aString;
404   OFBool found;
405   OFListIterator(char *) uidfirst;
406   OFListIterator(char *) uidlast;
407 
408   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
409   OFListIterator(DVPSImageBoxContent *) last = list_.end();
410   while (first != last)
411   {
412     c = (*first)->getReferencedPresentationLUTInstanceUID();
413     if ((c == NULL)||(strlen(c)==0)) c = filmBox;
414     aString = c;  // aString now contains the UID of the P-LUT to be used for this image, if any.
415     uidfirst = uidList.begin();
416     uidlast = uidList.end();
417     found = OFFalse;
418     while (uidfirst != uidlast)
419     {
420       if (aString == (*uidfirst))
421       {
422       	found = OFTrue;
423         break;
424       }
425       ++uidfirst;
426     }
427     if (!found) uidList.push_back((char *)c);
428     ++first;
429   }
430 
431   if (uidList.size()==1) return *(uidList.begin()); // if there is only one LUT, return it
432   return NULL;
433 }
434 
435 
printSCPCreate(unsigned long numBoxes,DcmUniqueIdentifier & studyUID,DcmUniqueIdentifier & seriesUID,const char * aetitle)436 OFBool DVPSImageBoxContent_PList::printSCPCreate(
437   unsigned long numBoxes,
438   DcmUniqueIdentifier& studyUID,
439   DcmUniqueIdentifier& seriesUID,
440   const char *aetitle)
441 {
442   clear();
443   DVPSImageBoxContent *box = NULL;
444   char uid[100];
445   for (unsigned long i=0; i<numBoxes; i++)
446   {
447     box = new DVPSImageBoxContent();
448     if (box)
449     {
450       if ((EC_Normal == box->setSOPInstanceUID(dcmGenerateUniqueIdentifier(uid))) &&
451           (EC_Normal == box->setUIDsAndAETitle(studyUID, seriesUID, aetitle)))
452       {
453         list_.push_back(box);
454       }
455       else
456       {
457       	delete box;
458       	return OFFalse;
459       }
460     } else return OFFalse;
461   }
462   return OFTrue;
463 }
464 
465 
writeReferencedImageBoxSQ(DcmItem & dset)466 OFCondition DVPSImageBoxContent_PList::writeReferencedImageBoxSQ(DcmItem &dset)
467 {
468   if (size()==0) return EC_IllegalCall; // can't write if sequence is empty
469 
470   OFCondition result = EC_Normal;
471   DcmSequenceOfItems *dseq=NULL;
472   DcmItem *ditem=NULL;
473   DcmUniqueIdentifier *uid=NULL;
474   const char *instanceUID=NULL;
475 
476   dseq = new DcmSequenceOfItems(DCM_ReferencedImageBoxSequence);
477   if (dseq)
478   {
479     OFListIterator(DVPSImageBoxContent *) first = list_.begin();
480     OFListIterator(DVPSImageBoxContent *) last = list_.end();
481     while (first != last)
482     {
483       if (result==EC_Normal)
484       {
485         ditem = new DcmItem();
486         if (ditem)
487         {
488           uid = new DcmUniqueIdentifier(DCM_ReferencedSOPClassUID);
489           if (uid) result = uid->putString(UID_BasicGrayscaleImageBoxSOPClass); else result = EC_MemoryExhausted;
490           if (EC_Normal == result) result = ditem->insert(uid, OFTrue /*replaceOld*/); else delete uid;
491 
492           uid = new DcmUniqueIdentifier(DCM_ReferencedSOPInstanceUID);
493           instanceUID = (*first)->getSOPInstanceUID();
494           if (uid && instanceUID) result = uid->putString(instanceUID); else result = EC_MemoryExhausted;
495           if (EC_Normal == result) result = ditem->insert(uid, OFTrue /*replaceOld*/); else delete uid;
496 
497           if (result==EC_Normal) dseq->insert(ditem); else delete ditem;
498         } else result = EC_MemoryExhausted;
499       }
500       ++first;
501     }
502     if (result==EC_Normal) dset.insert(dseq, OFTrue /*replaceOld*/); else delete dseq;
503   } else result = EC_MemoryExhausted;
504   return result;
505 }
506 
507 
matchesPresentationLUT(DVPSPrintPresentationLUTAlignment align) const508 OFBool DVPSImageBoxContent_PList::matchesPresentationLUT(DVPSPrintPresentationLUTAlignment align) const
509 {
510   OFBool result = OFTrue;
511   OFListConstIterator(DVPSImageBoxContent *) first = list_.begin();
512   OFListConstIterator(DVPSImageBoxContent *) last = list_.end();
513   while (first != last)
514   {
515     result = result && (*first)->matchesPresentationLUT(align);
516     ++first;
517   }
518   return result;
519 }
520 
521 
duplicateImageBox(const char * uid)522 DVPSImageBoxContent *DVPSImageBoxContent_PList::duplicateImageBox(const char *uid)
523 {
524   if (uid == NULL) return NULL;
525 
526   OFString aString(uid);
527   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
528   OFListIterator(DVPSImageBoxContent *) last = list_.end();
529   while (first != last)
530   {
531     if (aString == (*first)->getSOPInstanceUID()) return (*first)->clone();
532     ++first;
533   }
534   return NULL;
535 }
536 
haveImagePositionClash(const char * uid,Uint16 position)537 OFBool DVPSImageBoxContent_PList::haveImagePositionClash(const char *uid, Uint16 position)
538 {
539   if (uid == NULL) return OFFalse;
540 
541   OFString aString(uid);
542   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
543   OFListIterator(DVPSImageBoxContent *) last = list_.end();
544   while (first != last)
545   {
546     if (((*first)->getImageBoxPosition() == position)&&(aString != (*first)->getSOPInstanceUID())) return OFTrue; //clash
547     ++first;
548   }
549   return OFFalse;
550 }
551 
552 
replace(DVPSImageBoxContent * newImageBox)553 void DVPSImageBoxContent_PList::replace(DVPSImageBoxContent *newImageBox)
554 {
555   if (! newImageBox) return;
556 
557   OFString aString(newImageBox->getSOPInstanceUID());
558   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
559   OFListIterator(DVPSImageBoxContent *) last = list_.end();
560   while (first != last)
561   {
562     if (aString == (*first)->getSOPInstanceUID())
563     {
564       delete (*first);
565       first = list_.erase(first);
566     }
567     else ++first;
568   }
569   list_.push_back(newImageBox);
570 }
571 
emptyPageWarning()572 OFBool DVPSImageBoxContent_PList::emptyPageWarning()
573 {
574   OFListIterator(DVPSImageBoxContent *) first = list_.begin();
575   OFListIterator(DVPSImageBoxContent *) last = list_.end();
576   while (first != last)
577   {
578     if ((*first)->getImageBoxPosition() > 0) return OFFalse;
579     ++first;
580   }
581   return OFTrue;
582 }
583