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