1 /*
2  *
3  *  Copyright (C) 1998-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: DVPSReferencedImage_PList
20  *
21  */
22 
23 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
24 #include "dcmtk/dcmdata/dcdeftag.h"
25 #include "dcmtk/dcmdata/dcsequen.h"
26 #include "dcmtk/dcmpstat/dvpsril.h"
27 #include "dcmtk/dcmpstat/dvpsri.h"      /* for DVPSReferencedImage */
28 #include "dcmtk/dcmpstat/dvpsrsl.h"     /* DVPSReferencedSeries_PList */
29 #include "dcmtk/dcmpstat/dvpsrs.h"      /* for DVPSReferencedSeries, needed by MSVC5 with STL */
30 #include "dcmtk/dcmpstat/dvpsdef.h"
31 
32 
DVPSReferencedImage_PList()33 DVPSReferencedImage_PList::DVPSReferencedImage_PList()
34 : list_()
35 {
36 }
37 
DVPSReferencedImage_PList(const DVPSReferencedImage_PList & arg)38 DVPSReferencedImage_PList::DVPSReferencedImage_PList(const DVPSReferencedImage_PList &arg)
39 : list_()
40 {
41   OFListConstIterator(DVPSReferencedImage *) first = arg.list_.begin();
42   OFListConstIterator(DVPSReferencedImage *) last = arg.list_.end();
43   while (first != last)
44   {
45     list_.push_back((*first)->clone());
46     ++first;
47   }
48 }
49 
~DVPSReferencedImage_PList()50 DVPSReferencedImage_PList::~DVPSReferencedImage_PList()
51 {
52   clear();
53 }
54 
clear()55 void DVPSReferencedImage_PList::clear()
56 {
57   OFListIterator(DVPSReferencedImage *) first = list_.begin();
58   OFListIterator(DVPSReferencedImage *) last = list_.end();
59   while (first != last)
60   {
61     delete (*first);
62     first = list_.erase(first);
63   }
64 }
65 
read(DcmItem & dset)66 OFCondition DVPSReferencedImage_PList::read(DcmItem &dset)
67 {
68   OFCondition result = EC_Normal;
69   DcmStack stack;
70   DVPSReferencedImage *newImage = NULL;
71   DcmSequenceOfItems *dseq=NULL;
72   DcmItem *ditem=NULL;
73 
74   if (EC_Normal == dset.search(DCM_ReferencedImageSequence, stack, ESM_fromHere, OFFalse))
75   {
76     dseq=(DcmSequenceOfItems *)stack.top();
77     if (dseq)
78     {
79       unsigned long numItems = dseq->card();
80       for (unsigned int i=0; i<numItems; i++)
81       {
82         ditem = dseq->getItem(i);
83         newImage = new DVPSReferencedImage();
84         if (newImage && ditem)
85         {
86           result = newImage->read(*ditem);
87           list_.push_back(newImage);
88         } else result = EC_MemoryExhausted;
89       }
90     }
91   }
92 
93   return result;
94 }
95 
write(DcmItem & dset)96 OFCondition DVPSReferencedImage_PList::write(DcmItem &dset)
97 {
98   OFCondition result = EC_Normal;
99   DcmSequenceOfItems *dseq=NULL;
100   DcmItem *ditem=NULL;
101 
102   dseq = new DcmSequenceOfItems(DCM_ReferencedImageSequence);
103   if (dseq)
104   {
105     OFListIterator(DVPSReferencedImage *) first = list_.begin();
106     OFListIterator(DVPSReferencedImage *) last = list_.end();
107     while (first != last)
108     {
109       if (result==EC_Normal)
110       {
111         ditem = new DcmItem();
112         if (ditem)
113         {
114           result = (*first)->write(*ditem);
115           if (result==EC_Normal) dseq->insert(ditem); else delete ditem;
116         } else result = EC_MemoryExhausted;
117       }
118       ++first;
119     }
120     if (result==EC_Normal) dset.insert(dseq, OFTrue /*replaceOld*/); else delete dseq;
121   } else result = EC_MemoryExhausted;
122   return result;
123 }
124 
isValid(OFString & sopclassuid)125 OFBool DVPSReferencedImage_PList::isValid(OFString& sopclassuid)
126 {
127   if (size() == 0)
128   {
129     DCMPSTAT_WARN("referenced image SQ contains empty item in presentation state");
130     return OFFalse;
131   }
132   OFBool result = OFTrue;
133   OFListIterator(DVPSReferencedImage *) first = list_.begin();
134   OFListIterator(DVPSReferencedImage *) last = list_.end();
135   while ((result == OFTrue) && (first != last))
136   {
137     result = (*first)->validateSOPClassUID(sopclassuid);
138     ++first;
139   }
140   return result;
141 }
142 
findImageReference(const char * sopinstanceuid)143 DVPSReferencedImage *DVPSReferencedImage_PList::findImageReference(const char *sopinstanceuid)
144 {
145   OFListIterator(DVPSReferencedImage *) first = list_.begin();
146   OFListIterator(DVPSReferencedImage *) last = list_.end();
147   while (first != last)
148   {
149     if ((*first)->isSOPInstanceUID(sopinstanceuid)) return *first;
150     ++first;
151   }
152   return NULL;
153 }
154 
removeFrameReference(const char * sopinstanceuid,unsigned long frame,unsigned long numberOfFrames)155 void DVPSReferencedImage_PList::removeFrameReference(const char *sopinstanceuid, unsigned long frame, unsigned long numberOfFrames)
156 {
157   if ((frame<1)||(numberOfFrames<frame)) return;
158   OFListIterator(DVPSReferencedImage *) first = list_.begin();
159   OFListIterator(DVPSReferencedImage *) last = list_.end();
160   while (first != last)
161   {
162     if ((*first)->isSOPInstanceUID(sopinstanceuid))
163     {
164       (*first)->removeFrameReference(frame, numberOfFrames);
165       if ((*first)->appliesToAllFrames())
166       {
167         delete (*first);
168         first = list_.erase(first);
169       } else ++first;
170     } else ++first;
171   }
172   return;
173 }
174 
removeImageReference(const char * sopinstanceuid)175 void DVPSReferencedImage_PList::removeImageReference(const char *sopinstanceuid)
176 {
177   OFListIterator(DVPSReferencedImage *) first = list_.begin();
178   OFListIterator(DVPSReferencedImage *) last = list_.end();
179   while (first != last)
180   {
181     if ((*first)->isSOPInstanceUID(sopinstanceuid))
182     {
183       delete (*first);
184       first = list_.erase(first);
185     } else ++first;
186   }
187   return;
188 }
189 
addImageReference(const char * sopclassUID,const char * instanceUID,const char * frames)190 OFCondition DVPSReferencedImage_PList::addImageReference(
191     const char *sopclassUID,
192     const char *instanceUID,
193     const char *frames)
194 {
195   OFCondition result = EC_Normal;
196 
197   /* make sure that we don't create two references to the same image */
198   if (findImageReference(instanceUID)) result = EC_IllegalCall;
199   else
200   {
201     DVPSReferencedImage *image = new DVPSReferencedImage();
202     if (image)
203     {
204       image->setSOPClassUID(sopclassUID);
205       image->setSOPInstanceUID(instanceUID);
206       if (frames) image->setFrameNumbers(frames);
207       list_.push_back(image);
208     } else result = EC_MemoryExhausted;
209   }
210   return result;
211 }
212 
addImageReference(const char * sopclassUID,const char * instanceUID,unsigned long frame,DVPSObjectApplicability applicability)213 OFCondition DVPSReferencedImage_PList::addImageReference(
214     const char *sopclassUID,
215     const char *instanceUID,
216     unsigned long frame,
217     DVPSObjectApplicability applicability)
218 {
219   if ((sopclassUID==NULL)||(instanceUID==NULL)||(applicability==DVPSB_allImages)) return EC_IllegalCall;
220   const char *framenumber=NULL;
221   if (applicability==DVPSB_currentFrame)
222   {
223     char frameString[100];
224     sprintf(frameString, "%ld", frame);
225     framenumber = frameString;
226   }
227   return addImageReference(sopclassUID, instanceUID, framenumber);
228 }
229 
230 
getImageReference(size_t idx,OFString & sopclassUID,OFString & instanceUID,OFString & frames)231 OFCondition DVPSReferencedImage_PList::getImageReference(
232     size_t idx,
233     OFString& sopclassUID,
234     OFString& instanceUID,
235     OFString& frames)
236 {
237   if (size() <= idx) return EC_IllegalCall;
238   OFListIterator(DVPSReferencedImage *) first = list_.begin();
239   OFListIterator(DVPSReferencedImage *) last = list_.end();
240   while (first != last)
241   {
242     if (idx==0) return (*first)->getImageReference(sopclassUID, instanceUID, frames); else
243     {
244       idx--;
245       ++first;
246     }
247   }
248   return EC_IllegalCall;
249 }
250 
removeImageReference(DVPSReferencedSeries_PList & allReferences,const char * instanceUID,unsigned long frame,unsigned long numberOfFrames,DVPSObjectApplicability applicability)251 void DVPSReferencedImage_PList::removeImageReference(
252     DVPSReferencedSeries_PList& allReferences,
253     const char *instanceUID,
254     unsigned long frame,
255     unsigned long numberOfFrames,
256     DVPSObjectApplicability applicability)
257 {
258 
259   if (applicability == DVPSB_allImages)
260   {
261     clear();
262     return;
263   }
264 
265   // if list of image references is empty, add all existing references
266   if (size() == 0)
267   {
268     OFString seriesUID;
269     OFString sopclassUID;
270     OFString sopinstanceUID;
271     OFString frames;
272     OFString aetitle;
273     OFString filesetID;
274     OFString filesetUID;
275     const char *cframes=NULL;
276 
277     size_t numberOfReferences = allReferences.numberOfImageReferences();
278     for (size_t i=0; i<numberOfReferences; i++)
279     {
280       sopclassUID.clear();
281       sopinstanceUID.clear();
282       frames.clear();
283       if (EC_Normal == allReferences.getImageReference(i, seriesUID, sopclassUID, sopinstanceUID, frames,
284         aetitle, filesetID, filesetUID))
285       {
286       	if (frames.size() > 0) cframes=frames.c_str(); else cframes=NULL;
287       	addImageReference(sopclassUID.c_str(), sopinstanceUID.c_str(), cframes);
288       }
289     }
290   }
291   if (applicability == DVPSB_currentImage) removeImageReference(instanceUID);
292   else removeFrameReference(instanceUID, frame, numberOfFrames);
293   return;
294 }
295 
isApplicable(const char * instanceUID,unsigned long frame)296 OFBool DVPSReferencedImage_PList::isApplicable(const char *instanceUID, unsigned long frame)
297 {
298   if (size() == 0) return OFTrue; // if no image references exist, the object is valid "globally".
299   DVPSReferencedImage *imageRef = findImageReference(instanceUID);
300   if (imageRef) return imageRef->appliesToFrame(frame);
301   return OFFalse;
302 }
303 
matchesApplicability(const char * instanceUID,unsigned long frame,DVPSObjectApplicability applicability)304 OFBool DVPSReferencedImage_PList::matchesApplicability(const char *instanceUID, unsigned long frame, DVPSObjectApplicability applicability)
305 {
306   DVPSReferencedImage *imageRef = NULL;
307   switch (applicability)
308   {
309     case DVPSB_currentFrame:
310       // we match if referenced image SQ contains exactly one item
311       // referencing only the current frame of the current image
312       if (size() == 1)
313       {
314       	imageRef = findImageReference(instanceUID);
315       	if (imageRef) return imageRef->appliesOnlyToFrame(frame);
316       }
317       break;
318     case DVPSB_currentImage:
319       // we match if referenced image SQ contains exactly one item
320       // referencing all frames of the current image
321       if (size() == 1)
322       {
323       	imageRef = findImageReference(instanceUID);
324       	if (imageRef) return imageRef->appliesToAllFrames();
325       }
326       break;
327     case DVPSB_allImages:
328       // applicability matches if referenced image SQ is empty
329       if (size() == 0) return OFTrue;
330       break;
331   }
332   return OFFalse;
333 }
334