1 /*
2  *
3  *  Copyright (C) 2000-2017, 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: dcmsr
15  *
16  *  Author: Joerg Riesmeier
17  *
18  *  Purpose:
19  *    classes: DSRNumericMeasurementValue
20  *
21  */
22 
23 
24 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
25 
26 #include "dcmtk/dcmsr/dsrtypes.h"
27 #include "dcmtk/dcmsr/dsrnumvl.h"
28 #include "dcmtk/dcmsr/dsrxmld.h"
29 
30 #include "dcmtk/dcmdata/dcdeftag.h"
31 #include "dcmtk/dcmdata/dcvrds.h"
32 
33 
DSRNumericMeasurementValue()34 DSRNumericMeasurementValue::DSRNumericMeasurementValue()
35   : NumericValue(),
36     MeasurementUnit(),
37     ValueQualifier(),
38     FloatingPointValue(DCM_FloatingPointValue),
39     RationalNumeratorValue(DCM_RationalNumeratorValue),
40     RationalDenominatorValue(DCM_RationalDenominatorValue)
41 {
42 }
43 
44 
DSRNumericMeasurementValue(const OFString & numericValue,const DSRCodedEntryValue & measurementUnit,const OFBool check)45 DSRNumericMeasurementValue::DSRNumericMeasurementValue(const OFString &numericValue,
46                                                        const DSRCodedEntryValue &measurementUnit,
47                                                        const OFBool check)
48   : NumericValue(),
49     MeasurementUnit(),
50     ValueQualifier(),
51     FloatingPointValue(DCM_FloatingPointValue),
52     RationalNumeratorValue(DCM_RationalNumeratorValue),
53     RationalDenominatorValue(DCM_RationalDenominatorValue)
54 {
55     /* use the set method for checking purposes */
56     setValue(numericValue, measurementUnit, check);
57 }
58 
59 
DSRNumericMeasurementValue(const DSRCodedEntryValue & valueQualifier,const OFBool check)60 DSRNumericMeasurementValue::DSRNumericMeasurementValue(const DSRCodedEntryValue &valueQualifier,
61                                                        const OFBool check)
62   : NumericValue(),
63     MeasurementUnit(),
64     ValueQualifier(),
65     FloatingPointValue(DCM_FloatingPointValue),
66     RationalNumeratorValue(DCM_RationalNumeratorValue),
67     RationalDenominatorValue(DCM_RationalDenominatorValue)
68 {
69     /* use the set method for checking purposes */
70     setValue(valueQualifier, check);
71 }
72 
73 
DSRNumericMeasurementValue(const OFString & numericValue,const DSRCodedEntryValue & measurementUnit,const DSRCodedEntryValue & valueQualifier,const OFBool check)74 DSRNumericMeasurementValue::DSRNumericMeasurementValue(const OFString &numericValue,
75                                                        const DSRCodedEntryValue &measurementUnit,
76                                                        const DSRCodedEntryValue &valueQualifier,
77                                                        const OFBool check)
78   : NumericValue(),
79     MeasurementUnit(),
80     ValueQualifier(),
81     FloatingPointValue(DCM_FloatingPointValue),
82     RationalNumeratorValue(DCM_RationalNumeratorValue),
83     RationalDenominatorValue(DCM_RationalDenominatorValue)
84 {
85     /* use the set method for checking purposes */
86     setValue(numericValue, measurementUnit, valueQualifier, check);
87 }
88 
89 
DSRNumericMeasurementValue(const DSRNumericMeasurementValue & numericMeasurement)90 DSRNumericMeasurementValue::DSRNumericMeasurementValue(const DSRNumericMeasurementValue &numericMeasurement)
91   : NumericValue(numericMeasurement.NumericValue),
92     MeasurementUnit(numericMeasurement.MeasurementUnit),
93     ValueQualifier(numericMeasurement.ValueQualifier),
94     FloatingPointValue(numericMeasurement.FloatingPointValue),
95     RationalNumeratorValue(numericMeasurement.RationalNumeratorValue),
96     RationalDenominatorValue(numericMeasurement.RationalDenominatorValue)
97 {
98     /* do not check since this would be unexpected to the user */
99 }
100 
101 
~DSRNumericMeasurementValue()102 DSRNumericMeasurementValue::~DSRNumericMeasurementValue()
103 {
104 }
105 
106 
operator =(const DSRNumericMeasurementValue & numericMeasurement)107 DSRNumericMeasurementValue &DSRNumericMeasurementValue::operator=(const DSRNumericMeasurementValue &numericMeasurement)
108 {
109     /* do not check since this would be unexpected to the user */
110     NumericValue = numericMeasurement.NumericValue;
111     MeasurementUnit = numericMeasurement.MeasurementUnit;
112     ValueQualifier = numericMeasurement.ValueQualifier;
113     FloatingPointValue = numericMeasurement.FloatingPointValue;
114     RationalNumeratorValue = numericMeasurement.RationalNumeratorValue;
115     RationalDenominatorValue = numericMeasurement.RationalDenominatorValue;
116     return *this;
117 }
118 
119 
operator ==(const DSRNumericMeasurementValue & numericMeasurement) const120 OFBool DSRNumericMeasurementValue::operator==(const DSRNumericMeasurementValue &numericMeasurement) const
121 {
122     /* only the basic information is used for comparing the two values */
123     return (NumericValue == numericMeasurement.NumericValue) &&
124            (MeasurementUnit == numericMeasurement.MeasurementUnit) &&
125            (ValueQualifier == numericMeasurement.ValueQualifier);
126 }
127 
128 
operator !=(const DSRNumericMeasurementValue & numericMeasurement) const129 OFBool DSRNumericMeasurementValue::operator!=(const DSRNumericMeasurementValue &numericMeasurement) const
130 {
131     /* only the basic information is used for comparing the two values */
132     return (NumericValue != numericMeasurement.NumericValue) ||
133            (MeasurementUnit != numericMeasurement.MeasurementUnit) ||
134            (ValueQualifier != numericMeasurement.ValueQualifier);
135 }
136 
137 
clear()138 void DSRNumericMeasurementValue::clear()
139 {
140     NumericValue.clear();
141     MeasurementUnit.clear();
142     ValueQualifier.clear();
143     FloatingPointValue.clear();
144     RationalNumeratorValue.clear();
145     RationalDenominatorValue.clear();
146 }
147 
148 
isValid() const149 OFBool DSRNumericMeasurementValue::isValid() const
150 {
151     /* the MeasuredValueSequence can be empty (type 2) */
152     return (isEmpty() || (checkNumericValue(NumericValue).good() && checkMeasurementUnit(MeasurementUnit).good()))
153         && checkNumericValueQualifier(ValueQualifier).good();
154 }
155 
156 
isEmpty() const157 OFBool DSRNumericMeasurementValue::isEmpty() const
158 {
159     /* the NumericValueQualifierCodeSequence is not checked */
160     return NumericValue.empty() && MeasurementUnit.isEmpty();
161 }
162 
163 
isComplete() const164 OFBool DSRNumericMeasurementValue::isComplete() const
165 {
166     /* officially, the NumericValueQualifierCodeSequence is optional (type 3) */
167     return (!NumericValue.empty() && MeasurementUnit.isComplete()) || ValueQualifier.isComplete();
168 }
169 
170 
print(STD_NAMESPACE ostream & stream,const size_t flags) const171 OFCondition DSRNumericMeasurementValue::print(STD_NAMESPACE ostream &stream,
172                                               const size_t flags) const
173 {
174     if (isEmpty())
175     {
176         /* empty value */
177         stream << "empty";
178         /* check for optional numeric value qualifier */
179         if (!ValueQualifier.isEmpty())
180         {
181             stream << " ";
182             ValueQualifier.print(stream, OFTrue /*printCodeValue*/, flags);
183         }
184     } else {
185         OFString printString;
186         stream << "\"" << DSRTypes::convertToPrintString(NumericValue, printString) << "\" ";
187         MeasurementUnit.print(stream, OFTrue /*printCodeValue*/, flags);
188     }
189     return EC_Normal;
190 }
191 
192 
readXML(const DSRXMLDocument & doc,DSRXMLCursor cursor,const size_t flags)193 OFCondition DSRNumericMeasurementValue::readXML(const DSRXMLDocument &doc,
194                                                 DSRXMLCursor cursor,
195                                                 const size_t flags)
196 {
197     OFCondition result = SR_EC_CorruptedXMLStructure;
198     if (cursor.valid())
199     {
200         cursor.gotoChild();
201         /* get "value" element (might be absent since "Measured Value Sequence" is type 2) */
202         if (!doc.getStringFromNodeContent(doc.getNamedNode(cursor, "value", OFFalse /*required*/), NumericValue).empty())
203         {
204             /* get additional representations of the numeric value (if any) */
205             doc.getElementFromNodeContent(doc.getNamedNode(cursor, "float", OFFalse /*required*/), FloatingPointValue);
206             const DSRXMLCursor childNode = doc.getNamedNode(cursor, "rational", OFFalse /*required*/).getChild();
207             if (childNode.valid())
208             {
209                 doc.getElementFromNodeContent(doc.getNamedNode(childNode, "numerator"), RationalNumeratorValue);
210                 doc.getElementFromNodeContent(doc.getNamedNode(childNode, "denominator"), RationalDenominatorValue);
211             }
212             /* get "unit" element (only if "value" present) */
213             result = MeasurementUnit.readXML(doc, doc.getNamedNode(cursor, "unit"), flags);
214         } else
215             result = EC_Normal;
216         if (result.good())
217         {
218             /* get "qualifier" element (optional, do not report if absent or erroneous) */
219             ValueQualifier.readXML(doc, doc.getNamedNode(cursor, "qualifier", OFFalse /*required*/), flags);
220         }
221         if (!isValid())
222             result = SR_EC_InvalidValue;
223     }
224     return result;
225 }
226 
227 
writeXML(STD_NAMESPACE ostream & stream,const size_t flags) const228 OFCondition DSRNumericMeasurementValue::writeXML(STD_NAMESPACE ostream &stream,
229                                                  const size_t flags) const
230 {
231     /* write numeric value */
232     DSRTypes::writeStringValueToXML(stream, NumericValue, "value", (flags & DSRTypes::XF_writeEmptyTags) > 0);
233     /* write floating point representation */
234     Float64 floatValue;
235     const OFBool hasFloating = getFloatingPointRepresentation(floatValue).good();
236     if (hasFloating || (flags & DSRTypes::XF_writeEmptyTags))
237     {
238         stream << "<float>";
239         if (hasFloating)
240         {
241             /* increase default precision */
242             const STD_NAMESPACE streamsize oldPrecision = stream.precision(8);
243             stream << floatValue;
244             /* reset i/o manipulators */
245             stream.precision(oldPrecision);
246         }
247         stream << "</float>" << OFendl;
248     }
249     /* write rational representation */
250     Sint32 numeratorValue;
251     Uint32 denominatorValue;
252     const OFBool hasRational = getRationalRepresentation(numeratorValue, denominatorValue).good();
253     if (hasRational || (flags & DSRTypes::XF_writeEmptyTags))
254     {
255         stream << "<rational>" << OFendl;
256         if (hasRational)
257         {
258             stream << "<numerator>" << numeratorValue << "</numerator>" << OFendl;
259             stream << "<denominator>" << denominatorValue << "</denominator>" << OFendl;
260         }
261         stream << "</rational>" << OFendl;
262     }
263     /* write measurement unit */
264     if (!MeasurementUnit.isEmpty() || (flags & DSRTypes::XF_writeEmptyTags))
265     {
266         if (flags & DSRTypes::XF_codeComponentsAsAttribute)
267             stream << "<unit";     // bracket ">" is closed in the next writeXML() routine
268         else
269             stream << "<unit>" << OFendl;
270         MeasurementUnit.writeXML(stream, flags);
271         stream << "</unit>" << OFendl;
272     }
273     /* write value qualifier */
274     if (!ValueQualifier.isEmpty() || (flags & DSRTypes::XF_writeEmptyTags))
275     {
276         if (flags & DSRTypes::XF_codeComponentsAsAttribute)
277             stream << "<qualifier";     // bracket ">" is closed in the next writeXML() routine
278         else
279             stream << "<qualifier>" << OFendl;
280         ValueQualifier.writeXML(stream, flags);
281         stream << "</qualifier>" << OFendl;
282     }
283     return EC_Normal;
284 }
285 
286 
readItem(DcmItem & dataset,const size_t flags)287 OFCondition DSRNumericMeasurementValue::readItem(DcmItem &dataset,
288                                                  const size_t flags)
289 {
290     const OFBool acceptViolation = (flags & DSRTypes::RF_acceptInvalidContentItemValue) > 0;
291     /* read NumericValue */
292     OFCondition result = DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_NumericValue, NumericValue, "1", "1", "MeasuredValueSequence", acceptViolation);
293     if (result.good())
294     {
295         /* read some optional attributes */
296         DSRTypes::getAndCheckElementFromDataset(dataset, FloatingPointValue, "1", "1C", "MeasuredValueSequence");
297         if (DSRTypes::getAndCheckElementFromDataset(dataset, RationalNumeratorValue, "1", "1C", "MeasuredValueSequence").good())
298             DSRTypes::getAndCheckElementFromDataset(dataset, RationalDenominatorValue, "1", "1" /* was 1C */, "MeasuredValueSequence");
299         /* read MeasurementUnitsCodeSequence */
300         result = MeasurementUnit.readSequence(dataset, DCM_MeasurementUnitsCodeSequence, "1" /*type*/, flags);
301     }
302     return result;
303 }
304 
305 
writeItem(DcmItem & dataset) const306 OFCondition DSRNumericMeasurementValue::writeItem(DcmItem &dataset) const
307 {
308     /* write NumericValue */
309     OFCondition result = DSRTypes::putStringValueToDataset(dataset, DCM_NumericValue, NumericValue);
310     /* write some optional attributes */
311     DSRTypes::addElementToDataset(result, dataset, new DcmFloatingPointDouble(FloatingPointValue), "1", "1C", "MeasuredValueSequence");
312     DSRTypes::addElementToDataset(result, dataset, new DcmSignedLong(RationalNumeratorValue), "1", "1C", "MeasuredValueSequence");
313     DSRTypes::addElementToDataset(result, dataset, new DcmUnsignedLong(RationalDenominatorValue), "1", "1C", "MeasuredValueSequence");
314     /* write MeasurementUnitsCodeSequence */
315     if (result.good())
316         result = MeasurementUnit.writeSequence(dataset, DCM_MeasurementUnitsCodeSequence);
317     return result;
318 }
319 
320 
readSequence(DcmItem & dataset,const size_t flags)321 OFCondition DSRNumericMeasurementValue::readSequence(DcmItem &dataset,
322                                                      const size_t flags)
323 {
324     /* read MeasuredValueSequence */
325     DcmSequenceOfItems *dseq = NULL;
326     OFCondition result = dataset.findAndGetSequence(DCM_MeasuredValueSequence, dseq);
327     DSRTypes::checkElementValue(dseq, DCM_MeasuredValueSequence, "1", "2", result, "NUM content item");
328     if (result.good())
329     {
330         /* check for empty sequence (allowed!) */
331         if (!dseq->isEmpty())
332         {
333             /* read first item */
334             DcmItem *ditem = dseq->getItem(0);
335             if (ditem != NULL)
336                 result = readItem(*ditem, flags);
337             else
338                 result = SR_EC_InvalidDocumentTree;
339         }
340     }
341     if (result.good())
342     {
343         /* read NumericValueQualifierCodeSequence (optional) */
344         ValueQualifier.readSequence(dataset, DCM_NumericValueQualifierCodeSequence, "3" /*type*/, flags);
345     }
346     return result;
347 }
348 
349 
writeSequence(DcmItem & dataset) const350 OFCondition DSRNumericMeasurementValue::writeSequence(DcmItem &dataset) const
351 {
352     OFCondition result = EC_MemoryExhausted;
353     /* write MeasuredValueSequence */
354     DcmSequenceOfItems *dseq = new DcmSequenceOfItems(DCM_MeasuredValueSequence);
355     if (dseq != NULL)
356     {
357         /* check for empty value */
358         if (isEmpty())
359             result = EC_Normal;
360         else
361         {
362             DcmItem *ditem = new DcmItem();
363             if (ditem != NULL)
364             {
365                 /* write item */
366                 result = writeItem(*ditem);
367                 if (result.good())
368                     dseq->insert(ditem);
369                 else
370                     delete ditem;
371             } else
372                 result = EC_MemoryExhausted;
373         }
374         /* write sequence (might be empty) */
375         if (result.good())
376             result = dataset.insert(dseq, OFTrue /*replaceOld*/);
377         if (result.bad())
378             delete dseq;
379     }
380     if (result.good())
381     {
382         /* write NumericValueQualifierCodeSequence (optional) */
383         if (!ValueQualifier.isEmpty())
384             ValueQualifier.writeSequence(dataset, DCM_NumericValueQualifierCodeSequence);
385     }
386     return result;
387 }
388 
389 
renderHTML(STD_NAMESPACE ostream & docStream,STD_NAMESPACE ostream &,size_t &,const size_t flags) const390 OFCondition DSRNumericMeasurementValue::renderHTML(STD_NAMESPACE ostream &docStream,
391                                                    STD_NAMESPACE ostream & /*annexStream*/,
392                                                    size_t & /*annexNumber*/,
393                                                    const size_t flags) const
394 {
395     if (isEmpty())
396     {
397         /* empty value */
398         docStream << "<i>empty</i>";
399     } else {
400         OFString htmlString;
401         const OFBool fullCode = (flags & DSRTypes::HF_renderNumericUnitCodes) &&
402             ((flags & DSRTypes::HF_renderInlineCodes) || (flags & DSRTypes::HF_renderItemsSeparately));
403         if (!fullCode || (flags & DSRTypes::HF_useCodeDetailsTooltip))
404         {
405             if (flags & DSRTypes::HF_XHTML11Compatibility)
406                 docStream << "<span class=\"num\">";
407             else if (flags & DSRTypes::HF_HTML32Compatibility)
408                 docStream << "<u>";
409             else /* HTML 4.01 */
410                 docStream << "<span class=\"under\">";
411         }
412         docStream << DSRTypes::convertToHTMLString(NumericValue, htmlString, flags) << " ";
413         /* render full code of the measurement unit (value first?) or code value only */
414         MeasurementUnit.renderHTML(docStream, flags, fullCode, (flags & DSRTypes::HF_useCodeMeaningAsUnit) == 0 /*valueFirst*/);
415         if (!fullCode || (flags & DSRTypes::HF_useCodeDetailsTooltip))
416         {
417             if (flags & DSRTypes::HF_HTML32Compatibility)
418                 docStream << "</u>";
419             else
420                 docStream << "</span>";
421         }
422     }
423     if (!ValueQualifier.isEmpty())
424     {
425         /* render optional numeric value qualifier */
426         docStream << " [";
427         ValueQualifier.renderHTML(docStream, flags, (flags & DSRTypes::HF_renderInlineCodes) > 0 /*fullCode*/);
428         docStream << "]";
429     }
430     return EC_Normal;
431 }
432 
433 
getValue(DSRNumericMeasurementValue & numericMeasurement) const434 OFCondition DSRNumericMeasurementValue::getValue(DSRNumericMeasurementValue &numericMeasurement) const
435 {
436     numericMeasurement = *this;
437     return EC_Normal;
438 }
439 
440 
getMeasurementUnit(DSRCodedEntryValue & measurementUnit) const441 OFCondition DSRNumericMeasurementValue::getMeasurementUnit(DSRCodedEntryValue &measurementUnit) const
442 {
443     measurementUnit = MeasurementUnit;
444     return EC_Normal;
445 }
446 
447 
getNumericValueQualifier(DSRCodedEntryValue & valueQualifier) const448 OFCondition DSRNumericMeasurementValue::getNumericValueQualifier(DSRCodedEntryValue &valueQualifier) const
449 {
450     valueQualifier = ValueQualifier;
451     return EC_Normal;
452 }
453 
454 
getFloatingPointRepresentation(Float64 & floatingPoint) const455 OFCondition DSRNumericMeasurementValue::getFloatingPointRepresentation(Float64 &floatingPoint) const
456 {
457     OFCondition result = SR_EC_RepresentationNotAvailable;
458     /* cast away the const specifier (yes, this is ugly) */
459     DcmFloatingPointDouble &floatElement = OFconst_cast(DcmFloatingPointDouble &, FloatingPointValue);
460     if (!floatElement.isEmpty())
461         result = floatElement.getFloat64(floatingPoint);
462     return result;
463 }
464 
465 
getRationalRepresentation(Sint32 & rationalNumerator,Uint32 & rationalDenominator) const466 OFCondition DSRNumericMeasurementValue::getRationalRepresentation(Sint32 &rationalNumerator,
467                                                                   Uint32 &rationalDenominator) const
468 {
469     OFCondition result = SR_EC_RepresentationNotAvailable;
470     /* cast away the const specifier (yes, this is ugly) */
471     DcmSignedLong &signedElement = OFconst_cast(DcmSignedLong &, RationalNumeratorValue);
472     DcmUnsignedLong &unsignedElement = OFconst_cast(DcmUnsignedLong &, RationalDenominatorValue);
473     /* check whether both values are present or absent */
474     if (signedElement.isEmpty() != unsignedElement.isEmpty())
475         result = EC_CorruptedData;
476     /* determine rational numerator and denominator (if present) */
477     else if (!signedElement.isEmpty() && !unsignedElement.isEmpty())
478     {
479         result = signedElement.getSint32(rationalNumerator);
480         if (result.good())
481             result = unsignedElement.getUint32(rationalDenominator);
482     }
483     return result;
484 }
485 
486 
setValue(const DSRNumericMeasurementValue & numericMeasurement,const OFBool check)487 OFCondition DSRNumericMeasurementValue::setValue(const DSRNumericMeasurementValue &numericMeasurement,
488                                                  const OFBool check)
489 {
490     /* first set the basic parameters */
491     OFCondition result = setValue(numericMeasurement.NumericValue,
492                                   numericMeasurement.MeasurementUnit,
493                                   numericMeasurement.ValueQualifier,
494                                   check);
495     /* then the additional representations */
496     if (result.good())
497     {
498         Float64 floatValue;
499         if (numericMeasurement.getFloatingPointRepresentation(floatValue).good())
500             result = setFloatingPointRepresentation(floatValue, check);
501         if (result.good())
502         {
503             Sint32 numeratorValue;
504             Uint32 denominatorValue;
505             if (numericMeasurement.getRationalRepresentation(numeratorValue, denominatorValue).good())
506                 result = setRationalRepresentation(numeratorValue, denominatorValue, check);
507         }
508     }
509     return result;
510 }
511 
512 
setValue(const OFString & numericValue,const DSRCodedEntryValue & measurementUnit,const OFBool check)513 OFCondition DSRNumericMeasurementValue::setValue(const OFString &numericValue,
514                                                  const DSRCodedEntryValue &measurementUnit,
515                                                  const OFBool check)
516 {
517     const DSRCodedEntryValue valueQualifier;
518     /* call the function doing the real work */
519     return setValue(numericValue, measurementUnit, valueQualifier, check);
520 }
521 
522 
setValue(const DSRCodedEntryValue & valueQualifier,const OFBool check)523 OFCondition DSRNumericMeasurementValue::setValue(const DSRCodedEntryValue &valueQualifier,
524                                                  const OFBool check)
525 {
526     const DSRCodedEntryValue measurementUnit;
527     /* call the function doing the real work */
528     return setValue("" /*numericValue*/, measurementUnit, valueQualifier, check);
529 }
530 
531 
setValue(const OFString & numericValue,const DSRCodedEntryValue & measurementUnit,const DSRCodedEntryValue & valueQualifier,const OFBool check)532 OFCondition DSRNumericMeasurementValue::setValue(const OFString &numericValue,
533                                                  const DSRCodedEntryValue &measurementUnit,
534                                                  const DSRCodedEntryValue &valueQualifier,
535                                                  const OFBool check)
536 {
537     OFCondition result = EC_Normal;
538     if (check)
539     {
540         /* only check if at least one of the two values is non-empty */
541         if (!numericValue.empty() || !measurementUnit.isEmpty())
542         {
543             /* check whether the passed values are valid */
544             result = checkNumericValue(numericValue);
545             if (result.good())
546                 result = checkMeasurementUnit(measurementUnit);
547         }
548         if (result.good())
549             result = checkNumericValueQualifier(valueQualifier);
550     } else {
551         /* make sure that both values are either empty or non-empty */
552         if (numericValue.empty() != measurementUnit.isEmpty())
553             result = EC_IllegalParameter;
554     }
555     if (result.good())
556     {
557         NumericValue = numericValue;
558         MeasurementUnit = measurementUnit;
559         ValueQualifier = valueQualifier;
560         /* clear additional representations */
561         FloatingPointValue.clear();
562         RationalNumeratorValue.clear();
563         RationalDenominatorValue.clear();
564     }
565     return result;
566 }
567 
568 
setNumericValue(const OFString & numericValue,const OFBool check)569 OFCondition DSRNumericMeasurementValue::setNumericValue(const OFString &numericValue,
570                                                         const OFBool check)
571 {
572     OFCondition result = EC_Normal;
573     if (check)
574     {
575         /* check whether the passed value is valid */
576         result = checkNumericValue(numericValue);
577     } else {
578         /* make sure that the mandatory values are non-empty */
579         if (numericValue.empty())
580             result = EC_IllegalParameter;
581     }
582     if (result.good())
583     {
584         NumericValue = numericValue;
585         /* clear additional representations */
586         FloatingPointValue.clear();
587         RationalNumeratorValue.clear();
588         RationalDenominatorValue.clear();
589     }
590     return result;
591 }
592 
593 
setNumericValue(const DcmElement & delem,const unsigned long pos,const OFBool check)594 OFCondition DSRNumericMeasurementValue::setNumericValue(const DcmElement &delem,
595                                                         const unsigned long pos,
596                                                         const OFBool check)
597 {
598     OFString numericValue;
599     /* first, get the value from the element (need to cast away "const") */
600     OFCondition result = OFconst_cast(DcmElement &, delem).getOFString(numericValue, pos);
601     if (result.good())
602     {
603         /* then, check and set the value */
604         result = setNumericValue(numericValue, check);
605     }
606     return result;
607 }
608 
609 
setNumericValue(DcmItem & dataset,const DcmTagKey & tagKey,const unsigned long pos,const OFBool check)610 OFCondition DSRNumericMeasurementValue::setNumericValue(DcmItem &dataset,
611                                                         const DcmTagKey &tagKey,
612                                                         const unsigned long pos,
613                                                         const OFBool check)
614 {
615     OFString numericValue;
616     /* first, get the element value from the dataset */
617     OFCondition result = DSRTypes::getStringValueFromDataset(dataset, tagKey, numericValue, pos);
618     if (result.good())
619     {
620         /* then, check and set the value */
621         result = setNumericValue(numericValue, check);
622     }
623     return result;
624 }
625 
626 
setMeasurementUnit(const DSRCodedEntryValue & measurementUnit,const OFBool check)627 OFCondition DSRNumericMeasurementValue::setMeasurementUnit(const DSRCodedEntryValue &measurementUnit,
628                                                            const OFBool check)
629 {
630     OFCondition result = EC_Normal;
631     if (check)
632     {
633         /* check whether the passed value is valid */
634         result = checkMeasurementUnit(measurementUnit);
635     } else {
636         /* make sure that the mandatory values are non-empty */
637         if (measurementUnit.isEmpty())
638             result = EC_IllegalParameter;
639     }
640     if (result.good())
641         MeasurementUnit = measurementUnit;
642     return result;
643 }
644 
645 
setNumericValueQualifier(const DSRCodedEntryValue & valueQualifier,const OFBool check)646 OFCondition DSRNumericMeasurementValue::setNumericValueQualifier(const DSRCodedEntryValue &valueQualifier,
647                                                                  const OFBool check)
648 {
649     OFCondition result = EC_Normal;
650     /* check whether the passed value is valid */
651     if (check)
652         result = checkNumericValueQualifier(valueQualifier);
653     if (result.good())
654         ValueQualifier = valueQualifier;
655     return result;
656 }
657 
658 
setFloatingPointRepresentation(const Float64 floatingPoint,const OFBool)659 OFCondition DSRNumericMeasurementValue::setFloatingPointRepresentation(const Float64 floatingPoint,
660                                                                        const OFBool /*check*/)
661 {
662     /* make sure that only a single value is stored */
663     return FloatingPointValue.putFloat64Array(&floatingPoint, 1);
664 }
665 
666 
setRationalRepresentation(const Sint32 rationalNumerator,const Uint32 rationalDenominator,const OFBool check)667 OFCondition DSRNumericMeasurementValue::setRationalRepresentation(const Sint32 rationalNumerator,
668                                                                   const Uint32 rationalDenominator,
669                                                                   const OFBool check)
670 {
671     OFCondition result = EC_Normal;
672     /* check whether the passed values are valid */
673     if (check)
674         result = checkRationalRepresentation(rationalNumerator, rationalDenominator);
675     if (result.good())
676     {
677         /* make sure that only a single value is stored */
678         RationalNumeratorValue.putSint32Array(&rationalNumerator, 1);
679         RationalDenominatorValue.putUint32Array(&rationalDenominator, 1);
680     }
681     return result;
682 }
683 
684 
removeFloatingPointRepresentation()685 void DSRNumericMeasurementValue::removeFloatingPointRepresentation()
686 {
687     FloatingPointValue.clear();
688 }
689 
690 
removeRationalRepresentation()691 void DSRNumericMeasurementValue::removeRationalRepresentation()
692 {
693     RationalNumeratorValue.clear();
694     RationalDenominatorValue.clear();
695 }
696 
697 
checkNumericValue(const OFString & numericValue) const698 OFCondition DSRNumericMeasurementValue::checkNumericValue(const OFString &numericValue) const
699 {
700     /* numeric value should never be empty */
701     return numericValue.empty() ? SR_EC_InvalidValue
702                                 : DcmDecimalString::checkStringValue(numericValue, "1");
703 }
704 
705 
checkMeasurementUnit(const DSRCodedEntryValue & measurementUnit) const706 OFCondition DSRNumericMeasurementValue::checkMeasurementUnit(const DSRCodedEntryValue &measurementUnit) const
707 {
708     /* measurement unit should never be empty */
709     return measurementUnit.isEmpty() ? SR_EC_InvalidValue
710                                      : measurementUnit.checkCurrentValue();
711 }
712 
713 
checkNumericValueQualifier(const DSRCodedEntryValue & valueQualifier) const714 OFCondition DSRNumericMeasurementValue::checkNumericValueQualifier(const DSRCodedEntryValue &valueQualifier) const
715 {
716     /* numeric value qualifier might be empty */
717     return valueQualifier.isEmpty() ? EC_Normal
718                                     : valueQualifier.checkCurrentValue();
719 }
720 
721 
checkRationalRepresentation(const Sint32,const Uint32 rationalDenominator) const722 OFCondition DSRNumericMeasurementValue::checkRationalRepresentation(const Sint32 /*rationalNumerator*/,
723                                                                     const Uint32 rationalDenominator) const
724 {
725     /* avoid "division by zero" */
726     return (rationalDenominator == 0) ? SR_EC_InvalidValue
727                                       : EC_Normal;
728 }
729 
730 
checkCurrentValue() const731 OFCondition DSRNumericMeasurementValue::checkCurrentValue() const
732 {
733     OFCondition result = checkNumericValue(NumericValue);
734     if (result.good())
735         result = checkMeasurementUnit(MeasurementUnit);
736     if (result.good())
737         result = checkNumericValueQualifier(ValueQualifier);
738     if (result.good())
739     {
740         Sint32 numeratorValue;
741         Uint32 denominatorValue;
742         result = getRationalRepresentation(numeratorValue, denominatorValue);
743         if (result.good())
744             result = checkRationalRepresentation(numeratorValue, denominatorValue);
745         else if (result == SR_EC_RepresentationNotAvailable)
746             result = EC_Normal;
747     }
748     return result;
749 }
750 
751 
752 // output operators
753 
operator <<(STD_NAMESPACE ostream & stream,const DSRNumericMeasurementValue & numericMeasurement)754 STD_NAMESPACE ostream &operator<<(STD_NAMESPACE ostream &stream,
755                                   const DSRNumericMeasurementValue &numericMeasurement)
756 {
757     numericMeasurement.print(stream, 0 /*flags*/);
758     return stream;
759 }
760