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