1 /*
2  *
3  *  Copyright (C) 1998-2018, 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
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/dcitem.h"
26 #include "dcmtk/dcmpstat/dvpsri.h"
27 #include "dcmtk/dcmpstat/dvpsdef.h"   /* for constants and macros */
28 
29 #define INCLUDE_CSTDIO
30 #include "dcmtk/ofstd/ofstdinc.h"
31 
32 
33 /* --------------- class DVPSReferencedImage --------------- */
34 
DVPSReferencedImage()35 DVPSReferencedImage::DVPSReferencedImage()
36 : referencedSOPClassUID(DCM_ReferencedSOPClassUID)
37 , referencedSOPInstanceUID(DCM_ReferencedSOPInstanceUID)
38 , referencedFrameNumber(DCM_ReferencedFrameNumber)
39 , frameCache(NULL)
40 , frameCacheEntries(0)
41 {
42 }
43 
DVPSReferencedImage(const DVPSReferencedImage & copy)44 DVPSReferencedImage::DVPSReferencedImage(const DVPSReferencedImage& copy)
45 : referencedSOPClassUID(copy.referencedSOPClassUID)
46 , referencedSOPInstanceUID(copy.referencedSOPInstanceUID)
47 , referencedFrameNumber(copy.referencedFrameNumber)
48 , frameCache(NULL) // we don't copy the frame cache
49 , frameCacheEntries(0)
50 {
51 }
52 
~DVPSReferencedImage()53 DVPSReferencedImage::~DVPSReferencedImage()
54 {
55   if (frameCache) delete[] frameCache;
56 }
57 
read(DcmItem & dset)58 OFCondition DVPSReferencedImage::read(DcmItem &dset)
59 {
60   OFCondition result = EC_Normal;
61   DcmStack stack;
62 
63   flushCache();
64 
65   READ_FROM_DATASET(DcmUniqueIdentifier, EVR_UI, referencedSOPClassUID)
66   READ_FROM_DATASET(DcmUniqueIdentifier, EVR_UI, referencedSOPInstanceUID)
67   READ_FROM_DATASET(DcmIntegerString, EVR_IS, referencedFrameNumber)
68 
69   /* Now perform basic sanity checks */
70 
71   if (referencedSOPClassUID.getLength() == 0)
72   {
73     result=EC_IllegalCall;
74     DCMPSTAT_WARN("presentation state contains a referenced image SQ item with referencedSOPClassUID absent or empty");
75   }
76   else if (referencedSOPClassUID.getVM() != 1)
77   {
78     result=EC_IllegalCall;
79     DCMPSTAT_WARN("presentation state contains a referenced image SQ item with referencedSOPClassUID VM != 1");
80   }
81 
82   if (referencedSOPInstanceUID.getLength() == 0)
83   {
84     result=EC_IllegalCall;
85     DCMPSTAT_WARN("presentation state contains a referenced image SQ item with referencedSOPInstanceUID absent or empty");
86   }
87   else if (referencedSOPInstanceUID.getVM() != 1)
88   {
89     result=EC_IllegalCall;
90     DCMPSTAT_WARN("presentation state contains a referenced image SQ item with referencedSOPInstanceUID VM != 1");
91   }
92 
93   return result;
94 }
95 
write(DcmItem & dset)96 OFCondition DVPSReferencedImage::write(DcmItem &dset)
97 {
98   OFCondition result = EC_Normal;
99   DcmElement *delem=NULL;
100 
101   ADD_TO_DATASET(DcmUniqueIdentifier, referencedSOPClassUID)
102   ADD_TO_DATASET(DcmUniqueIdentifier, referencedSOPInstanceUID)
103   if (referencedFrameNumber.getLength() >0) { ADD_TO_DATASET(DcmIntegerString, referencedFrameNumber) }
104 
105   return result;
106 }
107 
validateSOPClassUID(OFString & sopclassuid)108 OFBool DVPSReferencedImage::validateSOPClassUID(OFString& sopclassuid)
109 {
110   OFBool result = OFTrue;
111   if (sopclassuid.empty()) referencedSOPClassUID.getOFString(sopclassuid, 0);
112   else
113   {
114     OFString currentUID;
115     referencedSOPClassUID.getOFString(currentUID, 0);
116     if (currentUID != sopclassuid)
117     {
118       result = OFFalse;
119       DCMPSTAT_WARN("images of different SOP classes referenced in presentation state");
120     }
121   }
122   return result;
123 }
124 
setSOPClassUID(const char * uid)125 void DVPSReferencedImage::setSOPClassUID(const char *uid)
126 {
127   if (uid) referencedSOPClassUID.putString(uid); else referencedSOPClassUID.clear();
128   return;
129 }
130 
setSOPInstanceUID(const char * uid)131 void DVPSReferencedImage::setSOPInstanceUID(const char *uid)
132 {
133   if (uid) referencedSOPInstanceUID.putString(uid); else referencedSOPInstanceUID.clear();
134   return;
135 }
136 
setFrameNumbers(const char * frames)137 void DVPSReferencedImage::setFrameNumbers(const char *frames)
138 {
139   if (frames) referencedFrameNumber.putString(frames); else referencedFrameNumber.clear();
140   flushCache();
141   return;
142 }
143 
isSOPInstanceUID(const char * uid)144 OFBool DVPSReferencedImage::isSOPInstanceUID(const char *uid)
145 {
146   OFString aString;
147   if (uid && (EC_Normal == referencedSOPInstanceUID.getOFString(aString,0)))
148   {
149     if (aString == uid) return OFTrue;
150   }
151   return OFFalse;
152 }
153 
getImageReference(OFString & sopclassUID,OFString & instanceUID,OFString & frames)154 OFCondition DVPSReferencedImage::getImageReference(
155     OFString& sopclassUID,
156     OFString& instanceUID,
157     OFString& frames)
158 {
159   OFCondition result = referencedSOPClassUID.getOFString(sopclassUID,0);
160   if (EC_Normal == result) result = referencedSOPInstanceUID.getOFString(instanceUID,0);
161   if (EC_Normal == result) result = referencedFrameNumber.getOFStringArray(frames);
162   return result;
163 }
164 
flushCache()165 void DVPSReferencedImage::flushCache()
166 {
167   if (frameCache) delete[] frameCache;
168   frameCache = NULL;
169   frameCacheEntries = 0;
170 }
171 
appliesToAllFrames()172 OFBool DVPSReferencedImage::appliesToAllFrames()
173 {
174   if (referencedFrameNumber.getLength() == 0) return OFTrue;
175   if (referencedFrameNumber.getVM() == 0) return OFTrue;
176   return OFFalse;
177 }
178 
updateCache()179 void DVPSReferencedImage::updateCache()
180 {
181   Sint32 val=0;
182   unsigned long i;
183   if (frameCache==NULL)
184   {
185     frameCacheEntries = (Uint32) referencedFrameNumber.getVM();
186     if (frameCacheEntries > 0)
187     {
188       frameCache = new Sint32[frameCacheEntries];
189       if (frameCache)
190       {
191         for (i=0; i<frameCacheEntries; i++)
192         {
193           if (EC_Normal == referencedFrameNumber.getSint32(val, i)) frameCache[i]=val; else frameCache[i]=0;
194         }
195       } else frameCacheEntries=0; // out of memory
196     }
197   }
198 }
199 
appliesToFrame(unsigned long frame)200 OFBool DVPSReferencedImage::appliesToFrame(unsigned long frame)
201 {
202   if (referencedFrameNumber.getLength()==0) return OFTrue;
203   Sint32 val=0;
204   unsigned long i;
205   updateCache();
206   if (frameCache)
207   {
208     val = (Sint32) frame;
209     for (i=0; i<frameCacheEntries; i++) if (val == frameCache[i]) return OFTrue;
210     return OFFalse;
211   }
212   return OFTrue; // referencedFrameNumber seems to contain garbage.
213 }
214 
appliesOnlyToFrame(unsigned long frame)215 OFBool DVPSReferencedImage::appliesOnlyToFrame(unsigned long frame)
216 {
217   Sint32 val=0;
218   if (referencedFrameNumber.getVM() == 1)
219   {
220     if (EC_Normal == referencedFrameNumber.getSint32(val, 0))
221     {
222       if (frame == (unsigned long)val) return OFTrue;
223     }
224   }
225   return OFFalse;
226 }
227 
removeFrameReference(unsigned long frame,unsigned long numberOfFrames)228 void DVPSReferencedImage::removeFrameReference(unsigned long frame, unsigned long numberOfFrames)
229 {
230   unsigned long i;
231   char str[20];
232   OFString aString;
233 
234   updateCache();
235   referencedFrameNumber.clear();
236   if (frameCache)
237   {
238     for (i=0; i<frameCacheEntries; i++)
239     {
240       if (frameCache[i] != (Sint32)frame)
241       {
242       	if (aString.size() ==0) sprintf(str, "%ld", (long)(frameCache[i])); else sprintf(str, "\\%ld", (long)(frameCache[i]));
243       	aString += str;
244       }
245     }
246   } else {
247     for (i=1; i<=numberOfFrames; i++)
248     {
249       if (i != frame)
250       {
251       	if (aString.size() ==0) sprintf(str, "%ld", i); else sprintf(str, "\\%ld", i);
252       	aString += str;
253       }
254     }
255   }
256   referencedFrameNumber.putString(aString.c_str());
257   flushCache();
258 }
259