1 /*
2 *
3 * Copyright (C) 2019-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: dcmdata
15 *
16 * Author: Joerg Riesmeier
17 *
18 * Purpose: Implementation of class DcmUnsigned64bitVeryLong
19 *
20 */
21
22
23 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
24 #include "dcmtk/dcmdata/dcvruv.h"
25
26 #include "dcmtk/ofstd/ofstream.h"
27 #include "dcmtk/dcmdata/dcjson.h"
28
29 #define INCLUDE_CSTDIO
30 #define INCLUDE_CSTRING
31 #define INCLUDE_CINTTYPES
32 #include "dcmtk/ofstd/ofstdinc.h"
33
34
35 // ********************************
36
37
DcmUnsigned64bitVeryLong(const DcmTag & tag)38 DcmUnsigned64bitVeryLong::DcmUnsigned64bitVeryLong(const DcmTag &tag)
39 : DcmElement(tag, 0)
40 {
41 }
42
43
DcmUnsigned64bitVeryLong(const DcmTag & tag,const Uint32 len)44 DcmUnsigned64bitVeryLong::DcmUnsigned64bitVeryLong(const DcmTag &tag,
45 const Uint32 len)
46 : DcmElement(tag, len)
47 {
48 }
49
50
DcmUnsigned64bitVeryLong(const DcmUnsigned64bitVeryLong & old)51 DcmUnsigned64bitVeryLong::DcmUnsigned64bitVeryLong(const DcmUnsigned64bitVeryLong &old)
52 : DcmElement(old)
53 {
54 }
55
56
~DcmUnsigned64bitVeryLong()57 DcmUnsigned64bitVeryLong::~DcmUnsigned64bitVeryLong()
58 {
59 }
60
61
operator =(const DcmUnsigned64bitVeryLong & obj)62 DcmUnsigned64bitVeryLong &DcmUnsigned64bitVeryLong::operator=(const DcmUnsigned64bitVeryLong &obj)
63 {
64 DcmElement::operator=(obj);
65 return *this;
66 }
67
68
compare(const DcmElement & rhs) const69 int DcmUnsigned64bitVeryLong::compare(const DcmElement& rhs) const
70 {
71 int result = DcmElement::compare(rhs);
72 if (result != 0)
73 {
74 return result;
75 }
76
77 /* cast away constness (dcmdata is not const correct...) */
78 DcmUnsigned64bitVeryLong* myThis = NULL;
79 DcmUnsigned64bitVeryLong* myRhs = NULL;
80 myThis = OFconst_cast(DcmUnsigned64bitVeryLong*, this);
81 myRhs = OFstatic_cast(DcmUnsigned64bitVeryLong*, OFconst_cast(DcmElement*, &rhs));
82
83 /* compare number of values */
84 unsigned long thisNumValues = myThis->getNumberOfValues();
85 unsigned long rhsNumValues = myRhs->getNumberOfValues();
86 if (thisNumValues < rhsNumValues)
87 {
88 return -1;
89 }
90 else if (thisNumValues > rhsNumValues)
91 {
92 return 1;
93 }
94
95 /* iterate over all components and test equality */
96 for (unsigned long count = 0; count < thisNumValues; count++)
97 {
98 Uint64 val = 0;
99 if (myThis->getUint64(val, count).good())
100 {
101 Uint64 rhsVal = 0;
102 if (myRhs->getUint64(rhsVal, count).good())
103 {
104 if (val > rhsVal)
105 {
106 return 1;
107 }
108 else if (val < rhsVal)
109 {
110 return -1;
111 }
112 }
113 }
114 }
115
116 /* all values as well as VM equal: objects are equal */
117 return 0;
118 }
119
120
copyFrom(const DcmObject & rhs)121 OFCondition DcmUnsigned64bitVeryLong::copyFrom(const DcmObject& rhs)
122 {
123 if (this != &rhs)
124 {
125 if (rhs.ident() != ident()) return EC_IllegalCall;
126 *this = OFstatic_cast(const DcmUnsigned64bitVeryLong &, rhs);
127 }
128 return EC_Normal;
129 }
130
131
132 // ********************************
133
134
ident() const135 DcmEVR DcmUnsigned64bitVeryLong::ident() const
136 {
137 return EVR_UV;
138 }
139
140
checkValue(const OFString & vm,const OFBool)141 OFCondition DcmUnsigned64bitVeryLong::checkValue(const OFString &vm,
142 const OFBool /*oldFormat*/)
143 {
144 /* check VM only */
145 return DcmElement::checkVM(getVM(), vm);
146 }
147
148
getVM()149 unsigned long DcmUnsigned64bitVeryLong::getVM()
150 {
151 return getNumberOfValues();
152 }
153
154
getNumberOfValues()155 unsigned long DcmUnsigned64bitVeryLong::getNumberOfValues()
156 {
157 return OFstatic_cast(unsigned long, getLengthField() / sizeof(Uint64));
158 }
159
160
161 // ********************************
162
163
print(STD_NAMESPACE ostream & out,const size_t flags,const int level,const char *,size_t *)164 void DcmUnsigned64bitVeryLong::print(STD_NAMESPACE ostream &out,
165 const size_t flags,
166 const int level,
167 const char * /*pixelFileName*/,
168 size_t * /*pixelCounter*/)
169 {
170 if (valueLoaded())
171 {
172 /* get unsigned integer data */
173 Uint64 *uintVals;
174 errorFlag = getUint64Array(uintVals);
175 if (uintVals != NULL)
176 {
177 /* do not use getVM() because derived classes might always return 1 */
178 const unsigned long count = getNumberOfValues();
179 /* double-check length field for valid value */
180 if (count > 0)
181 {
182 const unsigned long maxLength = (flags & DCMTypes::PF_shortenLongTagValues) ?
183 DCM_OptPrintLineLength : OFstatic_cast(unsigned long, -1) /*unlimited*/;
184 unsigned long printedLength = 0;
185 unsigned long newLength = 0;
186 char buffer[32];
187 /* print line start with tag and VR */
188 printInfoLineStart(out, flags, level);
189 /* print multiple values */
190 for (unsigned int i = 0; i < count; i++, uintVals++)
191 {
192 /* check whether first value is printed (omit delimiter) */
193 if (i == 0)
194 #ifdef PRIu64
195 sprintf(buffer, "%" PRIu64, *uintVals);
196 else
197 sprintf(buffer, "\\%" PRIu64, *uintVals);
198 #elif SIZEOF_LONG == 8
199 sprintf(buffer, "%lu", *uintVals);
200 else
201 sprintf(buffer, "\\%lu", *uintVals);
202 #else // assume "long long" is 64 bits
203 sprintf(buffer, "%llu", *uintVals);
204 else
205 sprintf(buffer, "\\%llu", *uintVals);
206 #endif
207 /* check whether current value sticks to the length limit */
208 newLength = printedLength + OFstatic_cast(unsigned long, strlen(buffer));
209 if ((newLength <= maxLength) && ((i + 1 == count) || (newLength + 3 <= maxLength)))
210 {
211 out << buffer;
212 printedLength = newLength;
213 } else {
214 /* check whether output has been truncated */
215 if (i + 1 < count)
216 {
217 out << "...";
218 printedLength += 3;
219 }
220 break;
221 }
222 }
223 /* print line end with length, VM and tag name */
224 printInfoLineEnd(out, flags, printedLength);
225 } else {
226 /* count can be zero if we have an invalid element with less than eight bytes length */
227 printInfoLine(out, flags, level, "(invalid value)");
228 }
229 } else
230 printInfoLine(out, flags, level, "(no value available)");
231 } else
232 printInfoLine(out, flags, level, "(not loaded)");
233 }
234
235
236 // ********************************
237
238
getUint64(Uint64 & uintVal,const unsigned long pos)239 OFCondition DcmUnsigned64bitVeryLong::getUint64(Uint64 &uintVal,
240 const unsigned long pos)
241 {
242 /* get unsigned integer data */
243 Uint64 *uintValues = NULL;
244 errorFlag = getUint64Array(uintValues);
245 /* check data before returning */
246 if (errorFlag.good())
247 {
248 if (uintValues == NULL)
249 errorFlag = EC_IllegalCall;
250 /* do not use getVM() because derived classes might always return 1 */
251 else if (pos >= getNumberOfValues())
252 errorFlag = EC_IllegalParameter;
253 else
254 uintVal = uintValues[pos];
255 }
256 /* clear value in case of error */
257 if (errorFlag.bad())
258 uintVal = 0;
259 return errorFlag;
260 }
261
262
getUint64Array(Uint64 * & uintVals)263 OFCondition DcmUnsigned64bitVeryLong::getUint64Array(Uint64 *&uintVals)
264 {
265 uintVals = OFstatic_cast(Uint64 *, getValue());
266 return errorFlag;
267 }
268
269
270 // ********************************
271
272
getOFString(OFString & stringVal,const unsigned long pos,OFBool)273 OFCondition DcmUnsigned64bitVeryLong::getOFString(OFString &stringVal,
274 const unsigned long pos,
275 OFBool /*normalize*/)
276 {
277 Uint64 uintVal;
278 /* get the specified numeric value */
279 errorFlag = getUint64(uintVal, pos);
280 if (errorFlag.good())
281 {
282 /* ... and convert it to a character string */
283 char buffer[32];
284 #ifdef PRIu64
285 sprintf(buffer, "%" PRIu64, uintVal);
286 #elif SIZEOF_LONG == 8
287 sprintf(buffer, "%lu", uintVal);
288 #else // assume "long long" is 64 bits
289 sprintf(buffer, "%llu", uintVal);
290 #endif
291 /* assign result */
292 stringVal = buffer;
293 }
294 return errorFlag;
295 }
296
297
298 // ********************************
299
300
putUint64(const Uint64 uintVal,const unsigned long pos)301 OFCondition DcmUnsigned64bitVeryLong::putUint64(const Uint64 uintVal,
302 const unsigned long pos)
303 {
304 Uint64 val = uintVal;
305 errorFlag = changeValue(&val, OFstatic_cast(Uint32, sizeof(Uint64) * pos), OFstatic_cast(Uint32, sizeof(Uint64)));
306 return errorFlag;
307 }
308
309
putUint64Array(const Uint64 * uintVals,const unsigned long numUints)310 OFCondition DcmUnsigned64bitVeryLong::putUint64Array(const Uint64 *uintVals,
311 const unsigned long numUints)
312 {
313 errorFlag = EC_Normal;
314 if (numUints > 0)
315 {
316 /* check for valid data */
317 if (uintVals != NULL)
318 errorFlag = putValue(uintVals, OFstatic_cast(Uint32, sizeof(Uint64) * OFstatic_cast(size_t, numUints)));
319 else
320 errorFlag = EC_CorruptedData;
321 } else
322 errorFlag = putValue(NULL, 0);
323 return errorFlag;
324 }
325
326
327 // ********************************
328
329
putString(const char * stringVal)330 OFCondition DcmUnsigned64bitVeryLong::putString(const char *stringVal)
331 {
332 /* determine length of the string value */
333 const size_t stringLen = (stringVal != NULL) ? strlen(stringVal) : 0;
334 /* call the real function */
335 return putString(stringVal, OFstatic_cast(Uint32, stringLen));
336 }
337
338
putString(const char * stringVal,const Uint32 stringLen)339 OFCondition DcmUnsigned64bitVeryLong::putString(const char *stringVal,
340 const Uint32 stringLen)
341 {
342 errorFlag = EC_Normal;
343 /* determine VM of the string */
344 const unsigned long vm = DcmElement::determineVM(stringVal, stringLen);
345 if (vm > 0)
346 {
347 Uint64 *field = new Uint64[vm];
348 OFString value;
349 size_t pos = 0;
350 /* retrieve unsigned integer data from character string */
351 for (unsigned long i = 0; (i < vm) && errorFlag.good(); i++)
352 {
353 /* get specified value from multi-valued string */
354 pos = DcmElement::getValueFromString(stringVal, pos, stringLen, value);
355 if (value.empty() ||
356 #ifdef SCNu64
357 (sscanf(value.c_str(), "%" SCNu64, &field[i]) != 1)
358 #elif SIZEOF_LONG == 8
359 (sscanf(value.c_str(), "%lu", &field[i]) != 1)
360 #else // assume "long long" is 64 bits
361 (sscanf(value.c_str(), "%llu", &field[i]) != 1)
362 #endif
363 )
364 {
365 errorFlag = EC_CorruptedData;
366 }
367 }
368 /* set binary data as the element value */
369 if (errorFlag.good())
370 errorFlag = putUint64Array(field, vm);
371 /* delete temporary buffer */
372 delete[] field;
373 } else
374 errorFlag = putValue(NULL, 0);
375 return errorFlag;
376 }
377
378
379 // ********************************
380
381
verify(const OFBool autocorrect)382 OFCondition DcmUnsigned64bitVeryLong::verify(const OFBool autocorrect)
383 {
384 /* check for valid value length */
385 if (getLengthField() % (sizeof(Uint64)) != 0)
386 {
387 errorFlag = EC_CorruptedData;
388 if (autocorrect)
389 {
390 /* strip to valid length */
391 setLengthField(getLengthField() - (getLengthField() % OFstatic_cast(Uint32, sizeof(Uint64))));
392 }
393 } else
394 errorFlag = EC_Normal;
395 return errorFlag;
396 }
397
398
399 // ********************************
400
401 // The largest number permitted in Javascript
402 #define JSON_MAX_SAFE_INTEGER 9007199254740991ull
403
writeJson(STD_NAMESPACE ostream & out,DcmJsonFormat & format)404 OFCondition DcmUnsigned64bitVeryLong::writeJson(STD_NAMESPACE ostream &out,
405 DcmJsonFormat &format)
406 {
407 /* always write JSON Opener */
408 writeJsonOpener(out, format);
409
410 if (!isEmpty())
411 {
412
413 /* write element value */
414 OFString bulkDataValue;
415 if (format.asBulkDataURI(getTag(), bulkDataValue))
416 {
417 format.printBulkDataURIPrefix(out);
418 DcmJsonFormat::printString(out, bulkDataValue);
419 }
420 else
421 {
422 const unsigned long vm = getVM();
423 OFString value;
424 Uint64 v = 0;
425
426 OFCondition status = getOFString(value, 0L);
427 if (status.bad()) return status;
428 format.printValuePrefix(out);
429
430 // check if we can represent the value as a JSON number.
431 // Unsigned JSON numbers should be <= JSON_MAX_SAFE_INTEGER.
432 status = getUint64(v, 0L);
433 if (status.bad() || (v > JSON_MAX_SAFE_INTEGER))
434 DcmJsonFormat::printValueString(out, value);
435 else DcmJsonFormat::printNumberInteger(out, value);
436
437 for (unsigned long valNo = 1; valNo < vm; ++valNo)
438 {
439 status = getOFString(value, valNo);
440 if (status.bad()) return status;
441 format.printNextArrayElementPrefix(out);
442
443 // check if we can represent the value as a JSON number.
444 // Unsigned JSON numbers should be <= JSON_MAX_SAFE_INTEGER.
445 status = getUint64(v, valNo);
446 if (status.bad() || (v > JSON_MAX_SAFE_INTEGER))
447 DcmJsonFormat::printValueString(out, value);
448 else DcmJsonFormat::printNumberInteger(out, value);
449 }
450 format.printValueSuffix(out);
451 }
452 }
453
454 /* write JSON Closer */
455 writeJsonCloser(out, format);
456 /* always report success */
457 return EC_Normal;
458 }
459