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: DSRTextTreeNode
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/dsrtextn.h"
28 #include "dcmtk/dcmsr/dsrstrvl.h"
29 #include "dcmtk/dcmsr/dsrxmld.h"
30 
31 #include "dcmtk/dcmdata/dcdeftag.h"
32 #include "dcmtk/dcmdata/dcvrut.h"
33 
34 
DSRTextTreeNode(const E_RelationshipType relationshipType)35 DSRTextTreeNode::DSRTextTreeNode(const E_RelationshipType relationshipType)
36   : DSRDocumentTreeNode(relationshipType, VT_Text),
37     DSRStringValue()
38 {
39 }
40 
41 
DSRTextTreeNode(const E_RelationshipType relationshipType,const OFString & textValue,const OFBool check)42 DSRTextTreeNode::DSRTextTreeNode(const E_RelationshipType relationshipType,
43                                  const OFString &textValue,
44                                  const OFBool check)
45   : DSRDocumentTreeNode(relationshipType, VT_Text),
46     DSRStringValue(textValue, check)
47 {
48 }
49 
50 
DSRTextTreeNode(const DSRTextTreeNode & node)51 DSRTextTreeNode::DSRTextTreeNode(const DSRTextTreeNode &node)
52   : DSRDocumentTreeNode(node),
53     DSRStringValue(node)
54 {
55 }
56 
57 
~DSRTextTreeNode()58 DSRTextTreeNode::~DSRTextTreeNode()
59 {
60 }
61 
62 
operator ==(const DSRDocumentTreeNode & node) const63 OFBool DSRTextTreeNode::operator==(const DSRDocumentTreeNode &node) const
64 {
65     /* call comparison operator of base class (includes check of value type) */
66     OFBool result = DSRDocumentTreeNode::operator==(node);
67     if (result)
68     {
69         /* it's safe to cast the type since the value type has already been checked */
70         result = DSRStringValue::operator==(OFstatic_cast(const DSRTextTreeNode &, node).getValue());
71     }
72     return result;
73 }
74 
75 
operator !=(const DSRDocumentTreeNode & node) const76 OFBool DSRTextTreeNode::operator!=(const DSRDocumentTreeNode &node) const
77 {
78     /* call comparison operator of base class (includes check of value type) */
79     OFBool result = DSRDocumentTreeNode::operator!=(node);
80     if (!result)
81     {
82         /* it's safe to cast the type since the value type has already been checked */
83         result = DSRStringValue::operator!=(OFstatic_cast(const DSRTextTreeNode &, node).getValue());
84     }
85     return result;
86 }
87 
88 
clone() const89 DSRTextTreeNode *DSRTextTreeNode::clone() const
90 {
91     return new DSRTextTreeNode(*this);
92 }
93 
94 
clear()95 void DSRTextTreeNode::clear()
96 {
97     DSRDocumentTreeNode::clear();
98     DSRStringValue::clear();
99 }
100 
101 
isValid() const102 OFBool DSRTextTreeNode::isValid() const
103 {
104     /* ConceptNameCodeSequence required */
105     return DSRDocumentTreeNode::isValid() && getConceptName().isValid() && hasValidValue();
106 }
107 
108 
hasValidValue() const109 OFBool DSRTextTreeNode::hasValidValue() const
110 {
111     return checkCurrentValue().good();
112 }
113 
114 
isShort(const size_t) const115 OFBool DSRTextTreeNode::isShort(const size_t /*flags*/) const
116 {
117     return (getValue().length() <= 40);
118 }
119 
120 
print(STD_NAMESPACE ostream & stream,const size_t flags) const121 OFCondition DSRTextTreeNode::print(STD_NAMESPACE ostream &stream,
122                                    const size_t flags) const
123 {
124     OFCondition result = DSRDocumentTreeNode::print(stream, flags);
125     if (result.good())
126     {
127         DCMSR_PRINT_ANSI_ESCAPE_CODE(DCMSR_ANSI_ESCAPE_CODE_DELIMITER)
128         stream << "=";
129         DCMSR_PRINT_ANSI_ESCAPE_CODE(DCMSR_ANSI_ESCAPE_CODE_ITEM_VALUE)
130         if (flags & PF_shortenLongItemValues)
131             DSRStringValue::print(stream, 30);     // text output is limited to 30 characters
132         else
133             DSRStringValue::print(stream);
134     }
135     return result;
136 }
137 
138 
writeXML(STD_NAMESPACE ostream & stream,const size_t flags) const139 OFCondition DSRTextTreeNode::writeXML(STD_NAMESPACE ostream &stream,
140                                       const size_t flags) const
141 {
142     OFCondition result = EC_Normal;
143     writeXMLItemStart(stream, flags);
144     result = DSRDocumentTreeNode::writeXML(stream, flags);
145     writeStringValueToXML(stream, getValue(), "value", (flags & XF_writeEmptyTags) > 0);
146     writeXMLItemEnd(stream, flags);
147     return result;
148 }
149 
150 
readContentItem(DcmItem & dataset,const size_t flags)151 OFCondition DSRTextTreeNode::readContentItem(DcmItem &dataset,
152                                              const size_t flags)
153 {
154     /* read TextValue */
155     return DSRStringValue::read(dataset, DCM_TextValue, flags);
156 }
157 
158 
writeContentItem(DcmItem & dataset) const159 OFCondition DSRTextTreeNode::writeContentItem(DcmItem &dataset) const
160 {
161     /* write TextValue */
162     return DSRStringValue::write(dataset, DCM_TextValue);
163 }
164 
165 
readXMLContentItem(const DSRXMLDocument & doc,DSRXMLCursor cursor,const size_t flags)166 OFCondition DSRTextTreeNode::readXMLContentItem(const DSRXMLDocument &doc,
167                                                 DSRXMLCursor cursor,
168                                                 const size_t flags)
169 {
170     /* retrieve value from XML element "value" */
171     return DSRStringValue::readXML(doc, doc.getNamedChildNode(cursor, "value"), flags, OFTrue /*encoding*/);
172 }
173 
174 
renderHTMLContentItem(STD_NAMESPACE ostream & docStream,STD_NAMESPACE ostream &,const size_t,size_t &,const size_t flags) const175 OFCondition DSRTextTreeNode::renderHTMLContentItem(STD_NAMESPACE ostream &docStream,
176                                                    STD_NAMESPACE ostream & /*annexStream*/,
177                                                    const size_t /*nestingLevel*/,
178                                                    size_t & /*annexNumber*/,
179                                                    const size_t flags) const
180 {
181     OFString htmlString;
182     /* render ConceptName */
183     OFCondition result = renderHTMLConceptName(docStream, flags);
184     /* render TextValue */
185     if (flags & HF_renderItemInline)
186         docStream << "\"" << convertToHTMLString(getValue(), htmlString, flags) << "\"" << OFendl;
187     else
188         docStream << convertToHTMLString(getValue(), htmlString, flags, OFTrue /*newlineAllowed*/) << OFendl;
189     return result;
190 }
191 
192 
checkValue(const OFString & textValue) const193 OFCondition DSRTextTreeNode::checkValue(const OFString &textValue) const
194 {
195     /* first, make sure that the mandatory value is non-empty */
196     OFCondition result = DSRStringValue::checkValue(textValue);
197     /* then, check whether the passed value is valid with regards to VR and VM.
198      * tbd: unfortunately, we do not know the character set, so "UNKNOWN" is used. */
199     if (result.good())
200         result = DcmUnlimitedText::checkStringValue(textValue, "UNKNOWN");
201     return result;
202 }
203