Coverage Report

Created: 2026-06-05 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}