Mercurial > hg > orthanc
annotate OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.cpp @ 4150:b56f3a37a4a1
optimization of ChunkedBuffer if many small chunks are added
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 19 Aug 2020 11:18:55 +0200 |
parents | bf7b9edf6b81 |
children | 7112a8af0b63 |
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 | |
339 | |
340 #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
|
341 void DicomWebJsonVisitor::FormatXml(std::string& target) const |
3202 | 342 { |
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
|
343 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
|
344 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
|
345 Toolbox::XmlToString(target, doc); |
3202 | 346 } |
347 #endif | |
348 | |
349 | |
350 void DicomWebJsonVisitor::VisitEmptySequence(const std::vector<DicomTag>& parentTags, | |
351 const std::vector<size_t>& parentIndexes, | |
352 const DicomTag& tag) | |
353 { | |
354 if (tag.GetElement() != 0x0000) | |
355 { | |
356 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
357 node[KEY_VR] = EnumerationToString(ValueRepresentation_Sequence); | |
358 } | |
359 } | |
360 | |
361 | |
362 void DicomWebJsonVisitor::VisitBinary(const std::vector<DicomTag>& parentTags, | |
363 const std::vector<size_t>& parentIndexes, | |
364 const DicomTag& tag, | |
365 ValueRepresentation vr, | |
366 const void* data, | |
367 size_t size) | |
368 { | |
369 assert(vr == ValueRepresentation_OtherByte || | |
370 vr == ValueRepresentation_OtherDouble || | |
371 vr == ValueRepresentation_OtherFloat || | |
372 vr == ValueRepresentation_OtherLong || | |
373 vr == ValueRepresentation_OtherWord || | |
374 vr == ValueRepresentation_Unknown); | |
375 | |
376 if (tag.GetElement() != 0x0000) | |
377 { | |
378 BinaryMode mode; | |
379 std::string bulkDataUri; | |
380 | |
381 if (formatter_ == NULL) | |
382 { | |
383 mode = BinaryMode_InlineBinary; | |
384 } | |
385 else | |
386 { | |
387 mode = formatter_->Format(bulkDataUri, parentTags, parentIndexes, tag, vr); | |
388 } | |
389 | |
390 if (mode != BinaryMode_Ignore) | |
391 { | |
392 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
393 node[KEY_VR] = EnumerationToString(vr); | |
394 | |
395 switch (mode) | |
396 { | |
397 case BinaryMode_BulkDataUri: | |
398 node[KEY_BULK_DATA_URI] = bulkDataUri; | |
399 break; | |
400 | |
401 case BinaryMode_InlineBinary: | |
402 { | |
403 std::string tmp(static_cast<const char*>(data), size); | |
404 | |
405 std::string base64; | |
406 Toolbox::EncodeBase64(base64, tmp); | |
407 | |
408 node[KEY_INLINE_BINARY] = base64; | |
409 break; | |
410 } | |
411 | |
412 default: | |
413 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
414 } | |
415 } | |
416 } | |
417 } | |
418 | |
419 | |
420 void DicomWebJsonVisitor::VisitIntegers(const std::vector<DicomTag>& parentTags, | |
421 const std::vector<size_t>& parentIndexes, | |
422 const DicomTag& tag, | |
423 ValueRepresentation vr, | |
424 const std::vector<int64_t>& values) | |
425 { | |
426 if (tag.GetElement() != 0x0000 && | |
427 vr != ValueRepresentation_NotSupported) | |
428 { | |
429 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
430 node[KEY_VR] = EnumerationToString(vr); | |
431 | |
432 if (!values.empty()) | |
433 { | |
434 Json::Value content = Json::arrayValue; | |
435 for (size_t i = 0; i < values.size(); i++) | |
436 { | |
437 content.append(FormatInteger(values[i])); | |
438 } | |
439 | |
440 node[KEY_VALUE] = content; | |
441 } | |
442 } | |
443 } | |
444 | |
445 void DicomWebJsonVisitor::VisitDoubles(const std::vector<DicomTag>& parentTags, | |
446 const std::vector<size_t>& parentIndexes, | |
447 const DicomTag& tag, | |
448 ValueRepresentation vr, | |
449 const std::vector<double>& values) | |
450 { | |
451 if (tag.GetElement() != 0x0000 && | |
452 vr != ValueRepresentation_NotSupported) | |
453 { | |
454 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
455 node[KEY_VR] = EnumerationToString(vr); | |
456 | |
457 if (!values.empty()) | |
458 { | |
459 Json::Value content = Json::arrayValue; | |
460 for (size_t i = 0; i < values.size(); i++) | |
461 { | |
462 content.append(FormatDouble(values[i])); | |
463 } | |
464 | |
465 node[KEY_VALUE] = content; | |
466 } | |
467 } | |
468 } | |
469 | |
470 | |
471 void DicomWebJsonVisitor::VisitAttributes(const std::vector<DicomTag>& parentTags, | |
472 const std::vector<size_t>& parentIndexes, | |
473 const DicomTag& tag, | |
474 const std::vector<DicomTag>& values) | |
475 { | |
476 if (tag.GetElement() != 0x0000) | |
477 { | |
478 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
479 node[KEY_VR] = EnumerationToString(ValueRepresentation_AttributeTag); | |
480 | |
481 if (!values.empty()) | |
482 { | |
483 Json::Value content = Json::arrayValue; | |
484 for (size_t i = 0; i < values.size(); i++) | |
485 { | |
486 content.append(FormatTag(values[i])); | |
487 } | |
488 | |
489 node[KEY_VALUE] = content; | |
490 } | |
491 } | |
492 } | |
493 | |
494 | |
495 ITagVisitor::Action | |
496 DicomWebJsonVisitor::VisitString(std::string& newValue, | |
497 const std::vector<DicomTag>& parentTags, | |
498 const std::vector<size_t>& parentIndexes, | |
499 const DicomTag& tag, | |
500 ValueRepresentation vr, | |
501 const std::string& value) | |
502 { | |
503 if (tag.GetElement() == 0x0000 || | |
504 vr == ValueRepresentation_NotSupported) | |
505 { | |
506 return Action_None; | |
507 } | |
508 else | |
509 { | |
510 Json::Value& node = CreateNode(parentTags, parentIndexes, tag); | |
511 node[KEY_VR] = EnumerationToString(vr); | |
512 | |
3420
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
513 #if 0 |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
514 /** |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
515 * 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
|
516 * replaces the specific character set with "ISO_IR 192" |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
517 * (UNICODE UTF-8). On Google Cloud Healthcare, however, the |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
518 * source encoding is reported, which seems more logical. We |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
519 * thus choose the Google convention. Enabling this block will |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
520 * mimic the DCMTK behavior. |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
521 **/ |
3202 | 522 if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET) |
523 { | |
524 node[KEY_VALUE].append("ISO_IR 192"); | |
525 } | |
526 else | |
3420
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
527 #endif |
3202 | 528 { |
529 std::string truncated; | |
530 | |
531 if (!value.empty() && | |
532 value[value.size() - 1] == '\0') | |
533 { | |
534 truncated = value.substr(0, value.size() - 1); | |
535 } | |
536 else | |
537 { | |
538 truncated = value; | |
539 } | |
3420
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
540 |
3202 | 541 if (!truncated.empty()) |
542 { | |
543 std::vector<std::string> tokens; | |
544 Toolbox::TokenizeString(tokens, truncated, '\\'); | |
545 | |
3420
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
546 if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET && |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
547 tokens.size() > 1 && |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
548 tokens[0].empty()) |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
549 { |
3448
b3bdd6dc10f2
don't change encoding of SpecificCharacterSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3420
diff
changeset
|
550 // 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
|
551 // first element from the vector of encodings |
b3bdd6dc10f2
don't change encoding of SpecificCharacterSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3420
diff
changeset
|
552 tokens.erase(tokens.begin()); |
3420
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
553 } |
0a0e7eca95ae
fix encoding in DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3391
diff
changeset
|
554 |
3202 | 555 node[KEY_VALUE] = Json::arrayValue; |
556 for (size_t i = 0; i < tokens.size(); i++) | |
557 { | |
558 try | |
559 { | |
560 switch (vr) | |
561 { | |
562 case ValueRepresentation_PersonName: | |
563 { | |
564 Json::Value value = Json::objectValue; | |
565 if (!tokens[i].empty()) | |
566 { | |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
567 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
|
568 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
|
569 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
570 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
|
571 { |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
572 value[KEY_ALPHABETIC] = components[0]; |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
573 } |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
574 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
575 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
|
576 { |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
577 value[KEY_IDEOGRAPHIC] = components[1]; |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
578 } |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
579 |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
580 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
|
581 { |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
582 value[KEY_PHONETIC] = components[2]; |
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
583 } |
3202 | 584 } |
3221
4be505c2ac56
Separation of ideographic and phonetic characters in DICOMweb JSON and XML
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3203
diff
changeset
|
585 |
3202 | 586 node[KEY_VALUE].append(value); |
587 break; | |
588 } | |
589 | |
590 case ValueRepresentation_IntegerString: | |
3391 | 591 { |
592 /** | |
593 * The calls to "StripSpaces()" below fix the | |
594 * issue reported by Rana Asim Wajid on 2019-06-05 | |
595 * ("Error Exception while invoking plugin service | |
596 * 32: Bad file format"): | |
597 * https://groups.google.com/d/msg/orthanc-users/T32FovWPcCE/-hKFbfRJBgAJ | |
598 **/ | |
599 | |
600 std::string t = Orthanc::Toolbox::StripSpaces(tokens[i]); | |
601 if (t.empty()) | |
3202 | 602 { |
603 node[KEY_VALUE].append(Json::nullValue); | |
604 } | |
605 else | |
606 { | |
3391 | 607 int64_t value = boost::lexical_cast<int64_t>(t); |
3202 | 608 node[KEY_VALUE].append(FormatInteger(value)); |
609 } | |
3391 | 610 |
3202 | 611 break; |
3391 | 612 } |
3202 | 613 |
614 case ValueRepresentation_DecimalString: | |
3391 | 615 { |
616 std::string t = Orthanc::Toolbox::StripSpaces(tokens[i]); | |
617 if (t.empty()) | |
3202 | 618 { |
619 node[KEY_VALUE].append(Json::nullValue); | |
620 } | |
621 else | |
622 { | |
3391 | 623 double value = boost::lexical_cast<double>(t); |
3202 | 624 node[KEY_VALUE].append(FormatDouble(value)); |
625 } | |
3391 | 626 |
3202 | 627 break; |
3391 | 628 } |
629 | |
3202 | 630 default: |
631 if (tokens[i].empty()) | |
632 { | |
633 node[KEY_VALUE].append(Json::nullValue); | |
634 } | |
635 else | |
636 { | |
637 node[KEY_VALUE].append(tokens[i]); | |
638 } | |
639 | |
640 break; | |
641 } | |
642 } | |
643 catch (boost::bad_lexical_cast&) | |
644 { | |
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
|
645 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
|
646 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
|
647 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
|
648 { |
418a89acef3b
In DICOM-to-DICOMweb/JSON conversion, be more tolerant wrt. invalid DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3448
diff
changeset
|
649 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
|
650 } |
418a89acef3b
In DICOM-to-DICOMweb/JSON conversion, be more tolerant wrt. invalid DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3448
diff
changeset
|
651 |
418a89acef3b
In DICOM-to-DICOMweb/JSON conversion, be more tolerant wrt. invalid DICOM files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3448
diff
changeset
|
652 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
|
653 << ") with invalid content for VR " << EnumerationToString(vr) << tmp; |
3202 | 654 } |
655 } | |
656 } | |
657 } | |
658 } | |
659 | |
660 return Action_None; | |
661 } | |
662 } |