1 /*
2  *
3  *  Copyright (C) 2000-2019, 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: DSRDateTimeTreeNode
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/dsrdtitn.h"
28 #include "dcmtk/dcmsr/dsrxmld.h"
29 
30 #include "dcmtk/dcmdata/dcdeftag.h"
31 #include "dcmtk/dcmdata/dcvrdt.h"
32 
33 
DSRDateTimeTreeNode(const E_RelationshipType relationshipType)34 DSRDateTimeTreeNode::DSRDateTimeTreeNode(const E_RelationshipType relationshipType)
35   : DSRDocumentTreeNode(relationshipType, VT_DateTime),
36     DSRStringValue()
37 {
38 }
39 
40 
DSRDateTimeTreeNode(const E_RelationshipType relationshipType,const OFString & dateTimeValue,const OFBool check)41 DSRDateTimeTreeNode::DSRDateTimeTreeNode(const E_RelationshipType relationshipType,
42                                          const OFString &dateTimeValue,
43                                          const OFBool check)
44   : DSRDocumentTreeNode(relationshipType, VT_DateTime),
45     DSRStringValue(dateTimeValue, check)
46 {
47 }
48 
49 
DSRDateTimeTreeNode(const DSRDateTimeTreeNode & node)50 DSRDateTimeTreeNode::DSRDateTimeTreeNode(const DSRDateTimeTreeNode &node)
51   : DSRDocumentTreeNode(node),
52     DSRStringValue(node)
53 {
54 }
55 
56 
~DSRDateTimeTreeNode()57 DSRDateTimeTreeNode::~DSRDateTimeTreeNode()
58 {
59 }
60 
61 
operator ==(const DSRDocumentTreeNode & node) const62 OFBool DSRDateTimeTreeNode::operator==(const DSRDocumentTreeNode &node) const
63 {
64     /* call comparison operator of base class (includes check of value type) */
65     OFBool result = DSRDocumentTreeNode::operator==(node);
66     if (result)
67     {
68         /* it's safe to cast the type since the value type has already been checked */
69         result = DSRStringValue::operator==(OFstatic_cast(const DSRDateTimeTreeNode &, node).getValue());
70     }
71     return result;
72 }
73 
74 
operator !=(const DSRDocumentTreeNode & node) const75 OFBool DSRDateTimeTreeNode::operator!=(const DSRDocumentTreeNode &node) const
76 {
77     /* call comparison operator of base class (includes check of value type) */
78     OFBool result = DSRDocumentTreeNode::operator!=(node);
79     if (!result)
80     {
81         /* it's safe to cast the type since the value type has already been checked */
82         result = DSRStringValue::operator!=(OFstatic_cast(const DSRDateTimeTreeNode &, node).getValue());
83     }
84     return result;
85 }
86 
87 
clone() const88 DSRDateTimeTreeNode *DSRDateTimeTreeNode::clone() const
89 {
90     return new DSRDateTimeTreeNode(*this);
91 }
92 
93 
clear()94 void DSRDateTimeTreeNode::clear()
95 {
96     DSRDocumentTreeNode::clear();
97     DSRStringValue::clear();
98 }
99 
100 
isValid() const101 OFBool DSRDateTimeTreeNode::isValid() const
102 {
103     /* ConceptNameCodeSequence required */
104     return DSRDocumentTreeNode::isValid() && getConceptName().isValid() && hasValidValue();
105 }
106 
107 
hasValidValue() const108 OFBool DSRDateTimeTreeNode::hasValidValue() const
109 {
110     return checkCurrentValue().good();
111 }
112 
113 
print(STD_NAMESPACE ostream & stream,const size_t flags) const114 OFCondition DSRDateTimeTreeNode::print(STD_NAMESPACE ostream &stream,
115                                        const size_t flags) const
116 {
117     OFCondition result = DSRDocumentTreeNode::print(stream, flags);
118     if (result.good())
119     {
120         DCMSR_PRINT_ANSI_ESCAPE_CODE(DCMSR_ANSI_ESCAPE_CODE_DELIMITER)
121         stream << "=";
122         DCMSR_PRINT_ANSI_ESCAPE_CODE(DCMSR_ANSI_ESCAPE_CODE_ITEM_VALUE)
123         DSRStringValue::print(stream);
124     }
125     return result;
126 }
127 
128 
writeXML(STD_NAMESPACE ostream & stream,const size_t flags) const129 OFCondition DSRDateTimeTreeNode::writeXML(STD_NAMESPACE ostream &stream,
130                                           const size_t flags) const
131 {
132     OFString tmpString;
133     OFCondition result = EC_Normal;
134     writeXMLItemStart(stream, flags);
135     result = DSRDocumentTreeNode::writeXML(stream, flags);
136     /* output time in ISO 8601 format */
137     DcmDateTime::getISOFormattedDateTimeFromString(getValue(), tmpString, OFTrue /*seconds*/, OFFalse /*fraction*/,
138         OFTrue /*timeZone*/, OFFalse /*createMissingPart*/, "T" /*dateTimeSeparator*/, "" /*timeZoneSeparator*/);
139     writeStringValueToXML(stream, tmpString, "value", (flags & XF_writeEmptyTags) > 0);
140     writeXMLItemEnd(stream, flags);
141     return result;
142 }
143 
144 
readContentItem(DcmItem & dataset,const size_t flags)145 OFCondition DSRDateTimeTreeNode::readContentItem(DcmItem &dataset,
146                                                  const size_t flags)
147 {
148     /* read DateTime */
149     return DSRStringValue::read(dataset, DCM_DateTime, flags);
150 }
151 
152 
writeContentItem(DcmItem & dataset) const153 OFCondition DSRDateTimeTreeNode::writeContentItem(DcmItem &dataset) const
154 {
155     /* write DateTime */
156     return DSRStringValue::write(dataset, DCM_DateTime);
157 }
158 
159 
readXMLContentItem(const DSRXMLDocument & doc,DSRXMLCursor cursor,const size_t)160 OFCondition DSRDateTimeTreeNode::readXMLContentItem(const DSRXMLDocument &doc,
161                                                     DSRXMLCursor cursor,
162                                                     const size_t /*flags*/)
163 {
164     OFString tmpString;
165     /* retrieve value from XML element "value" */
166     OFCondition result = setValue(getValueFromXMLNodeContent(doc, doc.getNamedChildNode(cursor, "value"), tmpString));
167     if (result == EC_IllegalParameter)
168         result = SR_EC_InvalidValue;
169     return result;
170 }
171 
172 
getValueFromXMLNodeContent(const DSRXMLDocument & doc,DSRXMLCursor cursor,OFString & dateTimeValue,const OFBool clearString)173 OFString &DSRDateTimeTreeNode::getValueFromXMLNodeContent(const DSRXMLDocument &doc,
174                                                           DSRXMLCursor cursor,
175                                                           OFString &dateTimeValue,
176                                                           const OFBool clearString)
177 {
178     if (clearString)
179         dateTimeValue.clear();
180     /* check whether node is valid */
181     if (cursor.valid())
182     {
183         OFString tmpString;
184         /* retrieve value from XML element */
185         if (!doc.getStringFromNodeContent(cursor, tmpString).empty())
186         {
187             OFDateTime tmpDateTime;
188             /* convert ISO to DICOM format */
189             if (tmpDateTime.setISOFormattedDateTime(tmpString))
190             {
191                 /* example of XML date/time format with time zone: 2010-12-31T15:30:00+01:00 */
192                 const OFBool hasTimeZone = (tmpString.length() >= 25);
193                 DcmDateTime::getDicomDateTimeFromOFDateTime(tmpDateTime, dateTimeValue,
194                     OFTrue /*seconds*/, OFFalse /*fraction*/, hasTimeZone /*timeZone*/);
195             }
196         }
197     }
198     return dateTimeValue;
199 }
200 
201 
renderHTMLContentItem(STD_NAMESPACE ostream & docStream,STD_NAMESPACE ostream &,const size_t,size_t &,const size_t flags) const202 OFCondition DSRDateTimeTreeNode::renderHTMLContentItem(STD_NAMESPACE ostream &docStream,
203                                                        STD_NAMESPACE ostream & /*annexStream*/,
204                                                        const size_t /*nestingLevel*/,
205                                                        size_t & /*annexNumber*/,
206                                                        const size_t flags) const
207 {
208     /* render ConceptName */
209     OFCondition result = renderHTMLConceptName(docStream, flags);
210     /* render DateTime */
211     if (result.good())
212     {
213         OFString htmlString;
214         if (!(flags & DSRTypes::HF_renderItemsSeparately))
215         {
216             if (flags & DSRTypes::HF_XHTML11Compatibility)
217                 docStream << "<span class=\"datetime\">";
218             else if (flags & DSRTypes::HF_HTML32Compatibility)
219                 docStream << "<u>";
220             else /* HTML 4.01 */
221                 docStream << "<span class=\"under\">";
222         }
223         docStream << dicomToReadableDateTime(getValue(), htmlString);
224         if (!(flags & DSRTypes::HF_renderItemsSeparately))
225         {
226             if (flags & DSRTypes::HF_HTML32Compatibility)
227                 docStream << "</u>";
228             else
229                 docStream << "</span>";
230         }
231         docStream << OFendl;
232     }
233     return result;
234 }
235 
236 
checkValue(const OFString & dateTimeValue) const237 OFCondition DSRDateTimeTreeNode::checkValue(const OFString &dateTimeValue) const
238 {
239     /* first, make sure that the mandatory value is non-empty */
240     OFCondition result = DSRStringValue::checkValue(dateTimeValue);
241     /* then, check whether the passed value is valid */
242     if (result.good())
243         result = DcmDateTime::checkStringValue(dateTimeValue, "1");
244     return result;
245 }
246