Mercurial > hg > orthanc
annotate OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.cpp @ 4303:44b53a2c0a13
improving detection of ABI compatibility
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 06 Nov 2020 15:37:30 +0100 |
parents | 785a2713323e |
children | 50b0c69b653a |
rev | line source |
---|---|
3202 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
3640
94f4a18a79cc
upgrade to year 2020
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3464
diff
changeset
|
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium |
3202 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
4119
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
8 * modify it under the terms of the GNU Lesser General Public License |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
9 * as published by the Free Software Foundation, either version 3 of |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
10 * the License, or (at your option) any later version. |
3202 | 11 * |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
4119
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
15 * Lesser General Public License for more details. |
3202 | 16 * |
4119
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
17 * You should have received a copy of the GNU Lesser General Public |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
18 * License along with this program. If not, see |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
19 * <http://www.gnu.org/licenses/>. |
3202 | 20 **/ |
21 | |
22 | |
23 #include "../PrecompiledHeaders.h" | |
24 #include "DicomWebJsonVisitor.h" | |
25 | |
26 #include "../OrthancException.h" | |
27 #include "../Toolbox.h" | |
28 #include "FromDcmtkBridge.h" | |
29 | |
30 #include <boost/math/special_functions/round.hpp> | |
31 #include <boost/lexical_cast.hpp> | |
32 | |
33 | |
34 static const char* const KEY_ALPHABETIC = "Alphabetic"; | |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
35 static const char* const KEY_IDEOGRAPHIC = "Ideographic"; |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
36 static const char* const KEY_PHONETIC = "Phonetic"; |
3202 | 37 static const char* const KEY_BULK_DATA_URI = "BulkDataURI"; |
38 static const char* const KEY_INLINE_BINARY = "InlineBinary"; | |
39 static const char* const KEY_SQ = "SQ"; | |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
40 static const char* const KEY_TAG = "tag"; |
3202 | 41 static const char* const KEY_VALUE = "Value"; |
42 static const char* const KEY_VR = "vr"; | |
43 | |
44 | |
45 namespace Orthanc | |
46 { | |
47 #if ORTHANC_ENABLE_PUGIXML == 1 | |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
48 static void DecomposeXmlPersonName(pugi::xml_node& target, |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
49 const std::string& source) |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
50 { |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
51 std::vector<std::string> tokens; |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
52 Toolbox::TokenizeString(tokens, source, '^'); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
53 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
54 if (tokens.size() >= 1) |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
55 { |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
56 target.append_child("FamilyName").text() = tokens[0].c_str(); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
57 } |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
58 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
59 if (tokens.size() >= 2) |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
60 { |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
61 target.append_child("GivenName").text() = tokens[1].c_str(); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
62 } |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
63 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
64 if (tokens.size() >= 3) |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
65 { |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
66 target.append_child("MiddleName").text() = tokens[2].c_str(); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
67 } |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
68 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
69 if (tokens.size() >= 4) |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
70 { |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
71 target.append_child("NamePrefix").text() = tokens[3].c_str(); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
72 } |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
73 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
74 if (tokens.size() >= 5) |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
75 { |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
76 target.append_child("NameSuffix").text() = tokens[4].c_str(); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
77 } |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
78 } |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
79 |
3202 | 80 static void ExploreXmlDataset(pugi::xml_node& target, |
81 const Json::Value& source) | |
82 { | |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
83 // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.3.html#table_F.3.1-1 |
3202 | 84 assert(source.type() == Json::objectValue); |
85 | |
86 Json::Value::Members members = source.getMemberNames(); | |
87 for (size_t i = 0; i < members.size(); i++) | |
88 { | |
89 const DicomTag tag = FromDcmtkBridge::ParseTag(members[i]); | |
90 const Json::Value& content = source[members[i]]; | |
91 | |
92 assert(content.type() == Json::objectValue && | |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
93 content.isMember(KEY_VR) && |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
94 content[KEY_VR].type() == Json::stringValue); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
95 const std::string vr = content[KEY_VR].asString(); |
3202 | 96 |
97 const std::string keyword = FromDcmtkBridge::GetTagName(tag, ""); | |
98 | |
99 pugi::xml_node node = target.append_child("DicomAttribute"); | |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
100 node.append_attribute(KEY_TAG).set_value(members[i].c_str()); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
101 node.append_attribute(KEY_VR).set_value(vr.c_str()); |
3202 | 102 |
103 if (keyword != std::string(DcmTag_ERROR_TagName)) | |
104 { | |
105 node.append_attribute("keyword").set_value(keyword.c_str()); | |
106 } | |
107 | |
108 if (content.isMember(KEY_VALUE)) | |
109 { | |
110 assert(content[KEY_VALUE].type() == Json::arrayValue); | |
111 | |
112 for (Json::Value::ArrayIndex j = 0; j < content[KEY_VALUE].size(); j++) | |
113 { | |
114 std::string number = boost::lexical_cast<std::string>(j + 1); | |
115 | |
116 if (vr == "SQ") | |
117 { | |
118 if (content[KEY_VALUE][j].type() == Json::objectValue) | |
119 { | |
120 pugi::xml_node child = node.append_child("Item"); | |
121 child.append_attribute("number").set_value(number.c_str()); | |
122 ExploreXmlDataset(child, content[KEY_VALUE][j]); | |
123 } | |
124 } | |
125 if (vr == "PN") | |
126 { | |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
127 bool hasAlphabetic = (content[KEY_VALUE][j].isMember(KEY_ALPHABETIC) && |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
128 content[KEY_VALUE][j][KEY_ALPHABETIC].type() == Json::stringValue); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
129 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
130 bool hasIdeographic = (content[KEY_VALUE][j].isMember(KEY_IDEOGRAPHIC) && |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
131 content[KEY_VALUE][j][KEY_IDEOGRAPHIC].type() == Json::stringValue); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
132 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
133 bool hasPhonetic = (content[KEY_VALUE][j].isMember(KEY_PHONETIC) && |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
134 content[KEY_VALUE][j][KEY_PHONETIC].type() == Json::stringValue); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
135 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
136 if (hasAlphabetic || |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
137 hasIdeographic || |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
138 hasPhonetic) |
3202 | 139 { |
140 pugi::xml_node child = node.append_child("PersonName"); | |
141 child.append_attribute("number").set_value(number.c_str()); | |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
142 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
143 if (hasAlphabetic) |
3202 | 144 { |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
145 pugi::xml_node name = child.append_child(KEY_ALPHABETIC); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
146 DecomposeXmlPersonName(name, content[KEY_VALUE][j][KEY_ALPHABETIC].asString()); |
3202 | 147 } |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
148 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
149 if (hasIdeographic) |
3202 | 150 { |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
151 pugi::xml_node name = child.append_child(KEY_IDEOGRAPHIC); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
152 DecomposeXmlPersonName(name, content[KEY_VALUE][j][KEY_IDEOGRAPHIC].asString()); |
3202 | 153 } |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
154 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
155 if (hasPhonetic) |
3202 | 156 { |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
157 pugi::xml_node name = child.append_child(KEY_PHONETIC); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
158 DecomposeXmlPersonName(name, content[KEY_VALUE][j][KEY_PHONETIC].asString()); |
3202 | 159 } |
160 } | |
161 } | |
162 else | |
163 { | |
164 pugi::xml_node child = node.append_child("Value"); | |
165 child.append_attribute("number").set_value(number.c_str()); | |
166 | |
167 switch (content[KEY_VALUE][j].type()) | |
168 { | |
169 case Json::stringValue: | |
170 child.text() = content[KEY_VALUE][j].asCString(); | |
171 break; | |
172 | |
173 case Json::realValue: | |
174 child.text() = content[KEY_VALUE][j].asFloat(); | |
175 break; | |
176 | |
177 case Json::intValue: | |
178 child.text() = content[KEY_VALUE][j].asInt(); | |
179 break; | |
180 | |
181 case Json::uintValue: | |
182 child.text() = content[KEY_VALUE][j].asUInt(); | |
183 break; | |
184 | |
185 default: | |
186 break; | |
187 } | |
188 } | |
189 } | |
190 } | |
191 else if (content.isMember(KEY_BULK_DATA_URI) && | |
192 content[KEY_BULK_DATA_URI].type() == Json::stringValue) | |
193 { | |
194 pugi::xml_node child = node.append_child("BulkData"); | |
195 child.append_attribute("URI").set_value(content[KEY_BULK_DATA_URI].asCString()); | |
196 } | |
197 else if (content.isMember(KEY_INLINE_BINARY) && | |
198 content[KEY_INLINE_BINARY].type() == Json::stringValue) | |
199 { | |
200 pugi::xml_node child = node.append_child("InlineBinary"); | |
201 child.text() = content[KEY_INLINE_BINARY].asCString(); | |
202 } | |
203 } | |
204 } | |
205 #endif | |
206 | |
207 | |
208 #if ORTHANC_ENABLE_PUGIXML == 1 | |
209 static void DicomWebJsonToXml(pugi::xml_document& target, | |
210 const Json::Value& source) | |
211 { | |
212 pugi::xml_node root = target.append_child("NativeDicomModel"); | |
213 root.append_attribute("xmlns").set_value("http://dicom.nema.org/PS3.19/models/NativeDICOM"); | |
214 root.append_attribute("xsi:schemaLocation").set_value("http://dicom.nema.org/PS3.19/models/NativeDICOM"); | |
215 root.append_attribute("xmlns:xsi").set_value("http://www.w3.org/2001/XMLSchema-instance"); | |
216 | |
217 ExploreXmlDataset(root, source); | |
218 | |
219 pugi::xml_node decl = target.prepend_child(pugi::node_declaration); | |
220 decl.append_attribute("version").set_value("1.0"); | |
221 decl.append_attribute("encoding").set_value("utf-8"); | |
222 } | |
223 #endif | |
224 | |
225 | |
226 std::string DicomWebJsonVisitor::FormatTag(const DicomTag& tag) | |
227 { | |
228 char buf[16]; | |
229 sprintf(buf, "%04X%04X", tag.GetGroup(), tag.GetElement()); | |
230 return std::string(buf); | |
231 } | |
232 | |
233 | |
234 Json::Value& DicomWebJsonVisitor::CreateNode(const std::vector<DicomTag>& parentTags, | |
235 const std::vector<size_t>& parentIndexes, | |
236 const DicomTag& tag) | |
237 { | |
238 assert(parentTags.size() == parentIndexes.size()); | |
239 | |
240 Json::Value* node = &result_; | |
241 | |
242 for (size_t i = 0; i < parentTags.size(); i++) | |
243 { | |
244 std::string t = FormatTag(parentTags[i]); | |
245 | |
246 if (!node->isMember(t)) | |
247 { | |
248 Json::Value item = Json::objectValue; | |
249 item[KEY_VR] = KEY_SQ; | |
250 item[KEY_VALUE] = Json::arrayValue; | |
251 item[KEY_VALUE].append(Json::objectValue); | |
252 (*node) [t] = item; | |
253 | |
254 node = &(*node)[t][KEY_VALUE][0]; | |
255 } | |
256 else if ((*node) [t].type() != Json::objectValue || | |
257 !(*node) [t].isMember(KEY_VR) || | |
258 (*node) [t][KEY_VR].type() != Json::stringValue || | |
259 (*node) [t][KEY_VR].asString() != KEY_SQ || | |
260 !(*node) [t].isMember(KEY_VALUE) || | |
261 (*node) [t][KEY_VALUE].type() != Json::arrayValue) | |
262 { | |
263 throw OrthancException(ErrorCode_InternalError); | |
264 } | |
265 else | |
266 { | |
267 size_t currentSize = (*node) [t][KEY_VALUE].size(); | |
268 | |
269 if (parentIndexes[i] < currentSize) | |
270 { | |
271 // The node already exists | |
272 } | |
273 else if (parentIndexes[i] == currentSize) | |
274 { | |
275 (*node) [t][KEY_VALUE].append(Json::objectValue); | |
276 } | |
277 else | |
278 { | |
279 throw OrthancException(ErrorCode_InternalError); | |
280 } | |
281 | |
282 node = &(*node) [t][KEY_VALUE][Json::ArrayIndex(parentIndexes[i])]; | |
283 } | |
284 } | |
285 | |
286 assert(node->type() == Json::objectValue); | |
287 | |
288 std::string t = FormatTag(tag); | |
289 if (node->isMember(t)) | |
290 { | |
291 throw OrthancException(ErrorCode_InternalError); | |
292 } | |
293 else | |
294 { | |
295 (*node) [t] = Json::objectValue; | |
296 return (*node) [t]; | |
297 } | |
298 } | |
299 | |
300 | |
301 Json::Value DicomWebJsonVisitor::FormatInteger(int64_t value) | |
302 { | |
303 if (value < 0) | |
304 { | |
305 return Json::Value(static_cast<int32_t>(value)); | |
306 } | |
307 else | |
308 { | |
309 return Json::Value(static_cast<uint32_t>(value)); | |
310 } | |
311 } | |
312 | |
313 | |
314 Json::Value DicomWebJsonVisitor::FormatDouble(double value) | |
315 { | |
3312 | 316 try |
317 { | |
318 long long a = boost::math::llround<double>(value); | |
3202 | 319 |
3312 | 320 double d = fabs(value - static_cast<double>(a)); |
3202 | 321 |
3312 | 322 if (d <= std::numeric_limits<double>::epsilon() * 100.0) |
323 { | |
324 return FormatInteger(a); | |
325 } | |
326 else | |
327 { | |
328 return Json::Value(value); | |
329 } | |
330 } | |
331 catch (boost::math::rounding_error&) | |
3202 | 332 { |
3312 | 333 // Can occur if "long long" is too small to receive this value |
334 // (e.g. infinity) | |
3202 | 335 return Json::Value(value); |
336 } | |
337 } | |
338 | |
4297 | 339 DicomWebJsonVisitor::DicomWebJsonVisitor() : |
340 formatter_(NULL) | |
341 { | |
342 Clear(); | |
343 } | |
344 | |
345 void DicomWebJsonVisitor::SetFormatter(DicomWebJsonVisitor::IBinaryFormatter &formatter) | |
346 { | |
347 formatter_ = &formatter; | |
348 } | |
349 | |
350 void DicomWebJsonVisitor::Clear() | |
351 { | |
352 result_ = Json::objectValue; | |
353 } | |
354 | |
355 const Json::Value &DicomWebJsonVisitor::GetResult() const | |
356 { | |
357 return result_; | |
358 } | |
359 | |
3202 | 360 |
361 #if ORTHANC_ENABLE_PUGIXML == 1 | |
3203
810772486249
URI "/instances/.../file" can return DICOMweb JSON or XML, depending on Accept header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3202
diff
changeset
|
362 void DicomWebJsonVisitor::FormatXml(std::string& target) const |
3202 | 363 { |
3203
810772486249
URI "/instances/.../file" can return DICOMweb JSON or XML, depending on Accept header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3202
diff
changeset
|
364 pugi::xml_document doc; |
810772486249
URI "/instances/.../file" can return DICOMweb JSON or XML, depending on Accept header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3202
diff
changeset
|
365 DicomWebJsonToXml(doc, result_); |
810772486249
URI "/instances/.../file" can return DICOMweb JSON or XML, depending on Accept header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3202
diff
changeset
|
366 Toolbox::XmlToString(target, doc); |
3202 | 367 } |
368 #endif | |
369 | |
370 | |
4297 | 371 void DicomWebJsonVisitor::VisitNotSupported(const std::vector<DicomTag> &parentTags, |
372 const std::vector<size_t> &parentIndexes, | |
373 const DicomTag &tag, | |
374 ValueRepresentation vr) | |
375 { | |
376 } | |
377 | |
378 | |
3202 | 379 void DicomWebJsonVisitor::VisitEmptySequence(const std::vector<DicomTag>& parentTags, |
380 const std::vector<size_t>& parentIndexes, | |
381 const DicomTag& tag) | |
382 { | |
383 if (tag.GetElement() != 0x0000) | |
384 { | |
385 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
386 node[KEY_VR] = EnumerationToString(ValueRepresentation_Sequence); | |
387 } | |
388 } | |
389 | |
390 | |
391 void DicomWebJsonVisitor::VisitBinary(const std::vector<DicomTag>& parentTags, | |
392 const std::vector<size_t>& parentIndexes, | |
393 const DicomTag& tag, | |
394 ValueRepresentation vr, | |
395 const void* data, | |
396 size_t size) | |
397 { | |
398 assert(vr == ValueRepresentation_OtherByte || | |
399 vr == ValueRepresentation_OtherDouble || | |
400 vr == ValueRepresentation_OtherFloat || | |
401 vr == ValueRepresentation_OtherLong || | |
402 vr == ValueRepresentation_OtherWord || | |
403 vr == ValueRepresentation_Unknown); | |
404 | |
405 if (tag.GetElement() != 0x0000) | |
406 { | |
407 BinaryMode mode; | |
408 std::string bulkDataUri; | |
409 | |
410 if (formatter_ == NULL) | |
411 { | |
412 mode = BinaryMode_InlineBinary; | |
413 } | |
414 else | |
415 { | |
416 mode = formatter_->Format(bulkDataUri, parentTags, parentIndexes, tag, vr); | |
417 } | |
418 | |
419 if (mode != BinaryMode_Ignore) | |
420 { | |
421 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
422 node[KEY_VR] = EnumerationToString(vr); | |
423 | |
424 switch (mode) | |
425 { | |
426 case BinaryMode_BulkDataUri: | |
427 node[KEY_BULK_DATA_URI] = bulkDataUri; | |
428 break; | |
429 | |
430 case BinaryMode_InlineBinary: | |
431 { | |
432 std::string tmp(static_cast<const char*>(data), size); | |
433 | |
434 std::string base64; | |
435 Toolbox::EncodeBase64(base64, tmp); | |
436 | |
437 node[KEY_INLINE_BINARY] = base64; | |
438 break; | |
439 } | |
440 | |
441 default: | |
442 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
443 } | |
444 } | |
445 } | |
446 } | |
447 | |
448 | |
449 void DicomWebJsonVisitor::VisitIntegers(const std::vector<DicomTag>& parentTags, | |
450 const std::vector<size_t>& parentIndexes, | |
451 const DicomTag& tag, | |
452 ValueRepresentation vr, | |
453 const std::vector<int64_t>& values) | |
454 { | |
455 if (tag.GetElement() != 0x0000 && | |
456 vr != ValueRepresentation_NotSupported) | |
457 { | |
458 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
459 node[KEY_VR] = EnumerationToString(vr); | |
460 | |
461 if (!values.empty()) | |
462 { | |
463 Json::Value content = Json::arrayValue; | |
464 for (size_t i = 0; i < values.size(); i++) | |
465 { | |
466 content.append(FormatInteger(values[i])); | |
467 } | |
468 | |
469 node[KEY_VALUE] = content; | |
470 } | |
471 } | |
472 } | |
473 | |
474 void DicomWebJsonVisitor::VisitDoubles(const std::vector<DicomTag>& parentTags, | |
475 const std::vector<size_t>& parentIndexes, | |
476 const DicomTag& tag, | |
477 ValueRepresentation vr, | |
478 const std::vector<double>& values) | |
479 { | |
480 if (tag.GetElement() != 0x0000 && | |
481 vr != ValueRepresentation_NotSupported) | |
482 { | |
483 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
484 node[KEY_VR] = EnumerationToString(vr); | |
485 | |
486 if (!values.empty()) | |
487 { | |
488 Json::Value content = Json::arrayValue; | |
489 for (size_t i = 0; i < values.size(); i++) | |
490 { | |
491 content.append(FormatDouble(values[i])); | |
492 } | |
493 | |
494 node[KEY_VALUE] = content; | |
495 } | |
496 } | |
497 } | |
498 | |
499 | |
500 void DicomWebJsonVisitor::VisitAttributes(const std::vector<DicomTag>& parentTags, | |
501 const std::vector<size_t>& parentIndexes, | |
502 const DicomTag& tag, | |
503 const std::vector<DicomTag>& values) | |
504 { | |
505 if (tag.GetElement() != 0x0000) | |
506 { | |
507 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
508 node[KEY_VR] = EnumerationToString(ValueRepresentation_AttributeTag); | |
509 | |
510 if (!values.empty()) | |
511 { | |
512 Json::Value content = Json::arrayValue; | |
513 for (size_t i = 0; i < values.size(); i++) | |
514 { | |
515 content.append(FormatTag(values[i])); | |
516 } | |
517 | |
518 node[KEY_VALUE] = content; | |
519 } | |
520 } | |
521 } | |
522 | |
523 | |
524 ITagVisitor::Action | |
525 DicomWebJsonVisitor::VisitString(std::string& newValue, | |
526 const std::vector<DicomTag>& parentTags, | |
527 const std::vector<size_t>& parentIndexes, | |
528 const DicomTag& tag, | |
529 ValueRepresentation vr, | |
530 const std::string& value) | |
531 { | |
532 if (tag.GetElement() == 0x0000 || | |
533 vr == ValueRepresentation_NotSupported) | |
534 { | |
535 return Action_None; | |
536 } | |
537 else | |
538 { | |
539 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
540 node[KEY_VR] = EnumerationToString(vr); | |
541 | |
3420
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
542 #if 0 |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
543 /** |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
544 * TODO - The JSON file has an UTF-8 encoding, thus DCMTK |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
545 * replaces the specific character set with "ISO_IR 192" |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
546 * (UNICODE UTF-8). On Google Cloud Healthcare, however, the |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
547 * source encoding is reported, which seems more logical. We |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
548 * thus choose the Google convention. Enabling this block will |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
549 * mimic the DCMTK behavior. |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
550 **/ |
3202 | 551 if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET) |
552 { | |
553 node[KEY_VALUE].append("ISO_IR 192"); | |
554 } | |
555 else | |
3420
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
556 #endif |
3202 | 557 { |
558 std::string truncated; | |
559 | |
560 if (!value.empty() && | |
561 value[value.size() - 1] == '\0') | |
562 { | |
563 truncated = value.substr(0, value.size() - 1); | |
564 } | |
565 else | |
566 { | |
567 truncated = value; | |
568 } | |
3420
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
569 |
3202 | 570 if (!truncated.empty()) |
571 { | |
572 std::vector<std::string> tokens; | |
573 Toolbox::TokenizeString(tokens, truncated, '\\'); | |
574 | |
3420
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
575 if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET && |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
576 tokens.size() > 1 && |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
577 tokens[0].empty()) |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
578 { |
3448
b3bdd6dc10f2
don't change encoding of SpecificCharacterSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3420
diff
changeset
|
579 // Specific character set with code extension: Remove the |
b3bdd6dc10f2
don't change encoding of SpecificCharacterSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3420
diff
changeset
|
580 // first element from the vector of encodings |
b3bdd6dc10f2
don't change encoding of SpecificCharacterSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3420
diff
changeset
|
581 tokens.erase(tokens.begin()); |
3420
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
582 } |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
583 |
3202 | 584 node[KEY_VALUE] = Json::arrayValue; |
585 for (size_t i = 0; i < tokens.size(); i++) | |
586 { | |
587 try | |
588 { | |
589 switch (vr) | |
590 { | |
591 case ValueRepresentation_PersonName: | |
592 { | |
4200 | 593 Json::Value tmp = Json::objectValue; |
3202 | 594 if (!tokens[i].empty()) |
595 { | |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
596 std::vector<std::string> components; |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
597 Toolbox::TokenizeString(components, tokens[i], '='); |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
598 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
599 if (components.size() >= 1) |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
600 { |
4200 | 601 tmp[KEY_ALPHABETIC] = components[0]; |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
602 } |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
603 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
604 if (components.size() >= 2) |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
605 { |
4200 | 606 tmp[KEY_IDEOGRAPHIC] = components[1]; |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
607 } |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
608 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
609 if (components.size() >= 3) |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
610 { |
4200 | 611 tmp[KEY_PHONETIC] = components[2]; |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
612 } |
3202 | 613 } |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
614 |
4200 | 615 node[KEY_VALUE].append(tmp); |
3202 | 616 break; |
617 } | |
618 | |
619 case ValueRepresentation_IntegerString: | |
3391 | 620 { |
621 /** | |
622 * The calls to "StripSpaces()" below fix the | |
623 * issue reported by Rana Asim Wajid on 2019-06-05 | |
624 * ("Error Exception while invoking plugin service | |
625 * 32: Bad file format"): | |
626 * https://groups.google.com/d/msg/orthanc-users/T32FovWPcCE/-hKFbfRJBgAJ | |
627 **/ | |
628 | |
4297 | 629 std::string t = Toolbox::StripSpaces(tokens[i]); |
3391 | 630 if (t.empty()) |
3202 | 631 { |
632 node[KEY_VALUE].append(Json::nullValue); | |
633 } | |
634 else | |
635 { | |
4200 | 636 int64_t tmp = boost::lexical_cast<int64_t>(t); |
637 node[KEY_VALUE].append(FormatInteger(tmp)); | |
3202 | 638 } |
3391 | 639 |
3202 | 640 break; |
3391 | 641 } |
3202 | 642 |
643 case ValueRepresentation_DecimalString: | |
3391 | 644 { |
4297 | 645 std::string t = Toolbox::StripSpaces(tokens[i]); |
3391 | 646 if (t.empty()) |
3202 | 647 { |
648 node[KEY_VALUE].append(Json::nullValue); | |
649 } | |
650 else | |
651 { | |
4200 | 652 double tmp = boost::lexical_cast<double>(t); |
653 node[KEY_VALUE].append(FormatDouble(tmp)); | |
3202 | 654 } |
3391 | 655 |
3202 | 656 break; |
3391 | 657 } |
658 | |
3202 | 659 default: |
660 if (tokens[i].empty()) | |
661 { | |
662 node[KEY_VALUE].append(Json::nullValue); | |
663 } | |
664 else | |
665 { | |
666 node[KEY_VALUE].append(tokens[i]); | |
667 } | |
668 | |
669 break; | |
670 } | |
671 } | |
672 catch (boost::bad_lexical_cast&) | |
673 { | |
3464
418a89acef3b
In DICOM-to-DICOMweb/JSON conversion, be more tolerant wrt. invalid DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3448
diff
changeset
|
674 std::string tmp; |
418a89acef3b
In DICOM-to-DICOMweb/JSON conversion, be more tolerant wrt. invalid DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3448
diff
changeset
|
675 if (value.size() < 64 && |
418a89acef3b
In DICOM-to-DICOMweb/JSON conversion, be more tolerant wrt. invalid DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3448
diff
changeset
|
676 Toolbox::IsAsciiString(value)) |
418a89acef3b
In DICOM-to-DICOMweb/JSON conversion, be more tolerant wrt. invalid DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3448
diff
changeset
|
677 { |
418a89acef3b
In DICOM-to-DICOMweb/JSON conversion, be more tolerant wrt. invalid DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3448
diff
changeset
|
678 tmp = ": " + value; |
418a89acef3b
In DICOM-to-DICOMweb/JSON conversion, be more tolerant wrt. invalid DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3448
diff
changeset
|
679 } |
418a89acef3b
In DICOM-to-DICOMweb/JSON conversion, be more tolerant wrt. invalid DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3448
diff
changeset
|
680 |
418a89acef3b
In DICOM-to-DICOMweb/JSON conversion, be more tolerant wrt. invalid DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3448
diff
changeset
|
681 LOG(WARNING) << "Ignoring DICOM tag (" << tag.Format() |
418a89acef3b
In DICOM-to-DICOMweb/JSON conversion, be more tolerant wrt. invalid DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3448
diff
changeset
|
682 << ") with invalid content for VR " << EnumerationToString(vr) << tmp; |
3202 | 683 } |
684 } | |
685 } | |
686 } | |
687 } | |
688 | |
689 return Action_None; | |
690 } | |
691 } |