/src/dcmtk/dcmdata/libsrc/dcvrod.cc
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Copyright (C) 2013-2026, 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 DcmOtherDouble |
19 | | * |
20 | | */ |
21 | | |
22 | | |
23 | | #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ |
24 | | |
25 | | #include "dcmtk/ofstd/ofuuidgn.h" |
26 | | #include "dcmtk/ofstd/ofstd.h" |
27 | | #include "dcmtk/ofstd/ofmath.h" |
28 | | |
29 | | #include "dcmtk/dcmdata/dcvrod.h" |
30 | | #include "dcmtk/dcmdata/dcswap.h" |
31 | | #include "dcmtk/dcmdata/dcjson.h" |
32 | | |
33 | | #include <cmath> |
34 | | |
35 | | // ******************************** |
36 | | |
37 | | |
38 | | DcmOtherDouble::DcmOtherDouble(const DcmTag &tag, |
39 | | const Uint32 len) |
40 | 0 | : DcmFloatingPointDouble(tag, len) |
41 | 0 | { |
42 | 0 | } |
43 | | |
44 | | |
45 | | DcmOtherDouble::DcmOtherDouble(const DcmOtherDouble &old) |
46 | 0 | : DcmFloatingPointDouble(old) |
47 | 0 | { |
48 | 0 | } |
49 | | |
50 | | |
51 | | DcmOtherDouble::~DcmOtherDouble() |
52 | 0 | { |
53 | 0 | } |
54 | | |
55 | | |
56 | | DcmOtherDouble &DcmOtherDouble::operator=(const DcmOtherDouble &obj) |
57 | 0 | { |
58 | 0 | DcmFloatingPointDouble::operator=(obj); |
59 | 0 | return *this; |
60 | 0 | } |
61 | | |
62 | | |
63 | | OFCondition DcmOtherDouble::copyFrom(const DcmObject& rhs) |
64 | 0 | { |
65 | 0 | if (this != &rhs) |
66 | 0 | { |
67 | 0 | if (rhs.ident() != ident()) return EC_IllegalCall; |
68 | 0 | *this = OFstatic_cast(const DcmOtherDouble &, rhs); |
69 | 0 | } |
70 | 0 | return EC_Normal; |
71 | 0 | } |
72 | | |
73 | | |
74 | | // ******************************** |
75 | | |
76 | | |
77 | | DcmEVR DcmOtherDouble::ident() const |
78 | 0 | { |
79 | 0 | return EVR_OD; |
80 | 0 | } |
81 | | |
82 | | |
83 | | OFCondition DcmOtherDouble::checkValue(const OFString & /*vm*/, |
84 | | const OFBool /*oldFormat*/) |
85 | 0 | { |
86 | | /* currently no checks are performed */ |
87 | 0 | return EC_Normal; |
88 | 0 | } |
89 | | |
90 | | |
91 | | unsigned long DcmOtherDouble::getVM() |
92 | 0 | { |
93 | | /* value multiplicity for OD is defined as 1 */ |
94 | 0 | return 1; |
95 | 0 | } |
96 | | |
97 | | |
98 | | // ******************************** |
99 | | |
100 | | /* need to check for "Not a Number" in order to avoid possible output of "-nan" */ |
101 | | static inline void checkAndOutputFloatValue(STD_NAMESPACE ostream &out, |
102 | | const Float64 value) |
103 | 0 | { |
104 | 0 | if (OFMath::isnan(value)) |
105 | 0 | out << "nan"; |
106 | 0 | else |
107 | 0 | out << value; |
108 | 0 | } |
109 | | |
110 | | OFCondition DcmOtherDouble::writeXML(STD_NAMESPACE ostream &out, |
111 | | const size_t flags) |
112 | 0 | { |
113 | 0 | OFCondition l_error = EC_Normal; |
114 | | /* always write XML start tag */ |
115 | 0 | writeXMLStartTag(out, flags); |
116 | | /* OD data requires special handling in the Native DICOM Model format */ |
117 | 0 | if (flags & DCMTypes::XF_useNativeModel) |
118 | 0 | { |
119 | | /* for an empty value field, we do not need to do anything */ |
120 | 0 | if (getLengthField() > 0) |
121 | 0 | { |
122 | | /* encode binary data as Base64 */ |
123 | 0 | if (flags & DCMTypes::XF_encodeBase64) |
124 | 0 | { |
125 | 0 | out << "<InlineBinary>"; |
126 | | /* the Native DICOM Model requires little endian byte ordering */ |
127 | 0 | Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian)); |
128 | 0 | OFStandard::encodeBase64(out, byteValues, OFstatic_cast(size_t, getLengthField())); |
129 | 0 | out << "</InlineBinary>" << OFendl; |
130 | 0 | } else { |
131 | | /* generate a new UID but the binary data is not (yet) written. */ |
132 | 0 | OFshared_ptr<OFUUID> const uuid = OFUUIDGenerator::create(); |
133 | 0 | if (uuid) { |
134 | 0 | out << "<BulkData uuid=\""; |
135 | 0 | uuid->print(out, OFUUID::NotationCanonical); |
136 | 0 | out << "\"/>" << OFendl; |
137 | 0 | } else { |
138 | 0 | l_error = EC_MemoryExhausted; |
139 | 0 | } |
140 | 0 | } |
141 | 0 | } |
142 | 0 | } else { |
143 | | /* write element value (if loaded) */ |
144 | 0 | if (valueLoaded()) |
145 | 0 | { |
146 | 0 | Float64 *floatValues = NULL; |
147 | | /* get and check 64 bit float data */ |
148 | 0 | if (getFloat64Array(floatValues).good() && (floatValues != NULL)) |
149 | 0 | { |
150 | 0 | const size_t count = getNumberOfValues(); |
151 | | /* count can be zero if we have an invalid element with less than eight bytes length */ |
152 | 0 | if (count > 0) |
153 | 0 | { |
154 | | /* increase default precision - see DcmFloatingPointDouble::print() */ |
155 | 0 | const STD_NAMESPACE streamsize oldPrecision = out.precision(17); |
156 | | /* use the standard "C" locale for proper decimal point */ |
157 | 0 | const STD_NAMESPACE locale oldLocale = out.imbue(STD_NAMESPACE locale("C")); |
158 | | /* print float values with separators */ |
159 | 0 | checkAndOutputFloatValue(out, *(floatValues++)); |
160 | 0 | for (unsigned long i = 1; i < count; i++) |
161 | 0 | { |
162 | 0 | out << "\\"; |
163 | 0 | checkAndOutputFloatValue(out, *(floatValues++)); |
164 | 0 | } |
165 | | /* reset i/o manipulators and locale */ |
166 | 0 | out.precision(oldPrecision); |
167 | 0 | out.imbue(oldLocale); |
168 | 0 | } |
169 | 0 | } |
170 | 0 | } |
171 | 0 | } |
172 | | /* always write XML end tag */ |
173 | 0 | writeXMLEndTag(out, flags); |
174 | | |
175 | | /* always report success */ |
176 | 0 | return l_error; |
177 | 0 | } |
178 | | |
179 | | |
180 | | // ******************************** |
181 | | |
182 | | |
183 | | OFCondition DcmOtherDouble::writeJson(STD_NAMESPACE ostream &out, |
184 | | DcmJsonFormat &format) |
185 | 0 | { |
186 | 0 | OFCondition result = EC_Normal; |
187 | | |
188 | | /* write JSON Opener */ |
189 | 0 | writeJsonOpener(out, format); |
190 | | |
191 | | /* for an empty value field, we do not need to do anything */ |
192 | 0 | if (getLengthField() > 0) |
193 | 0 | { |
194 | | /* adjust byte order to little endian */ |
195 | 0 | Uint8 *byteValues = OFstatic_cast(Uint8 *, getValue(EBO_LittleEndian)); |
196 | 0 | result = format.writeBinaryAttribute(out, getTag(), getLengthField(), byteValues); |
197 | 0 | } |
198 | | |
199 | | /* write JSON Closer */ |
200 | 0 | writeJsonCloser(out, format); |
201 | 0 | return result; |
202 | 0 | } |
203 | | |
204 | | |
205 | | // ******************************** |
206 | | |
207 | | |
208 | | OFCondition DcmOtherDouble::createFloat64Array(const Uint32 numDoubles, |
209 | | Float64 *&doubleVals) |
210 | 0 | { |
211 | 0 | Uint32 bytesRequired = 0; |
212 | | /* make sure that max length is not exceeded */ |
213 | 0 | if (OFStandard::safeMult(numDoubles, OFstatic_cast(Uint32, sizeof(Float64)), bytesRequired)) |
214 | 0 | errorFlag = createEmptyValue(bytesRequired); |
215 | 0 | else |
216 | 0 | errorFlag = EC_ElemLengthExceeds32BitField; |
217 | 0 | if (errorFlag.good()) |
218 | 0 | doubleVals = OFstatic_cast(Float64 *, this->getValue()); |
219 | 0 | else |
220 | 0 | doubleVals = NULL; |
221 | 0 | return errorFlag; |
222 | 0 | } |