comparison OrthancServer/DicomInstanceToStore.cpp @ 2894:a27b0e9a3fd9 db-changes

refactoring DicomInstanceToStore
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 18 Oct 2018 10:35:09 +0200
parents c691fcf66071
children e5e3253a1164
comparison
equal deleted inserted replaced
2893:1723cbba55c7 2894:a27b0e9a3fd9
33 33
34 #include "PrecompiledHeadersServer.h" 34 #include "PrecompiledHeadersServer.h"
35 #include "DicomInstanceToStore.h" 35 #include "DicomInstanceToStore.h"
36 36
37 #include "../Core/DicomParsing/FromDcmtkBridge.h" 37 #include "../Core/DicomParsing/FromDcmtkBridge.h"
38 #include "../Core/DicomParsing/ParsedDicomFile.h"
38 #include "../Core/Logging.h" 39 #include "../Core/Logging.h"
40 #include "../Core/OrthancException.h"
39 41
40 #include <dcmtk/dcmdata/dcfilefo.h> 42 #include <dcmtk/dcmdata/dcfilefo.h>
41 #include <dcmtk/dcmdata/dcdeftag.h> 43 #include <dcmtk/dcmdata/dcdeftag.h>
42 44
43 45
44 namespace Orthanc 46 namespace Orthanc
45 { 47 {
48 // Anonymous namespace to avoid clashes between compilation modules
49 namespace
50 {
51 template <typename T>
52 class SmartContainer
53 {
54 private:
55 T* content_;
56 bool toDelete_;
57 bool isReadOnly_;
58
59 void Deallocate()
60 {
61 if (content_ && toDelete_)
62 {
63 delete content_;
64 toDelete_ = false;
65 content_ = NULL;
66 }
67 }
68
69 public:
70 SmartContainer() : content_(NULL), toDelete_(false), isReadOnly_(true)
71 {
72 }
73
74 ~SmartContainer()
75 {
76 Deallocate();
77 }
78
79 void Allocate()
80 {
81 Deallocate();
82 content_ = new T;
83 toDelete_ = true;
84 isReadOnly_ = false;
85 }
86
87 void TakeOwnership(T* content)
88 {
89 if (content == NULL)
90 {
91 throw OrthancException(ErrorCode_ParameterOutOfRange);
92 }
93
94 Deallocate();
95 content_ = content;
96 toDelete_ = true;
97 isReadOnly_ = false;
98 }
99
100 void SetReference(T& content) // Read and write assign, without transfering ownership
101 {
102 Deallocate();
103 content_ = &content;
104 toDelete_ = false;
105 isReadOnly_ = false;
106 }
107
108 void SetConstReference(const T& content) // Read-only assign, without transfering ownership
109 {
110 Deallocate();
111 content_ = &const_cast<T&>(content);
112 toDelete_ = false;
113 isReadOnly_ = true;
114 }
115
116 bool HasContent() const
117 {
118 return content_ != NULL;
119 }
120
121 T& GetContent()
122 {
123 if (content_ == NULL)
124 {
125 throw OrthancException(ErrorCode_BadSequenceOfCalls);
126 }
127
128 if (isReadOnly_)
129 {
130 throw OrthancException(ErrorCode_ReadOnly);
131 }
132
133 return *content_;
134 }
135
136 const T& GetConstContent() const
137 {
138 if (content_ == NULL)
139 {
140 throw OrthancException(ErrorCode_BadSequenceOfCalls);
141 }
142
143 return *content_;
144 }
145 };
146 }
147
148
149 struct DicomInstanceToStore::PImpl
150 {
151 DicomInstanceOrigin origin_;
152 SmartContainer<std::string> buffer_;
153 SmartContainer<ParsedDicomFile> parsed_;
154 SmartContainer<DicomMap> summary_;
155 SmartContainer<Json::Value> json_;
156 MetadataMap metadata_;
157
158 void ComputeMissingInformation()
159 {
160 if (buffer_.HasContent() &&
161 summary_.HasContent() &&
162 json_.HasContent())
163 {
164 // Fine, everything is available
165 return;
166 }
167
168 if (!buffer_.HasContent())
169 {
170 if (!parsed_.HasContent())
171 {
172 if (!summary_.HasContent())
173 {
174 throw OrthancException(ErrorCode_NotImplemented);
175 }
176 else
177 {
178 parsed_.TakeOwnership(new ParsedDicomFile(summary_.GetConstContent()));
179 }
180 }
181
182 // Serialize the parsed DICOM file
183 buffer_.Allocate();
184 if (!FromDcmtkBridge::SaveToMemoryBuffer(buffer_.GetContent(),
185 *parsed_.GetContent().GetDcmtkObject().getDataset()))
186 {
187 LOG(ERROR) << "Unable to serialize a DICOM file to a memory buffer";
188 throw OrthancException(ErrorCode_InternalError);
189 }
190 }
191
192 if (summary_.HasContent() &&
193 json_.HasContent())
194 {
195 return;
196 }
197
198 // At this point, we know that the DICOM file is available as a
199 // memory buffer, but that its summary or its JSON version is
200 // missing
201
202 if (!parsed_.HasContent())
203 {
204 parsed_.TakeOwnership(new ParsedDicomFile(buffer_.GetConstContent()));
205 }
206
207 // At this point, we have parsed the DICOM file
208
209 if (!summary_.HasContent())
210 {
211 summary_.Allocate();
212 FromDcmtkBridge::ExtractDicomSummary(summary_.GetContent(),
213 *parsed_.GetContent().GetDcmtkObject().getDataset());
214 }
215
216 if (!json_.HasContent())
217 {
218 json_.Allocate();
219
220 std::set<DicomTag> ignoreTagLength;
221 FromDcmtkBridge::ExtractDicomAsJson(json_.GetContent(),
222 *parsed_.GetContent().GetDcmtkObject().getDataset(),
223 ignoreTagLength);
224 }
225 }
226
227
228 const char* GetBufferData()
229 {
230 ComputeMissingInformation();
231
232 if (!buffer_.HasContent())
233 {
234 throw OrthancException(ErrorCode_InternalError);
235 }
236
237 if (buffer_.GetConstContent().size() == 0)
238 {
239 return NULL;
240 }
241 else
242 {
243 return buffer_.GetConstContent().c_str();
244 }
245 }
246
247
248 size_t GetBufferSize()
249 {
250 ComputeMissingInformation();
251
252 if (!buffer_.HasContent())
253 {
254 throw OrthancException(ErrorCode_InternalError);
255 }
256
257 return buffer_.GetConstContent().size();
258 }
259
260
261 const DicomMap& GetSummary()
262 {
263 ComputeMissingInformation();
264
265 if (!summary_.HasContent())
266 {
267 throw OrthancException(ErrorCode_InternalError);
268 }
269
270 return summary_.GetConstContent();
271 }
272
273
274 const Json::Value& GetJson()
275 {
276 ComputeMissingInformation();
277
278 if (!json_.HasContent())
279 {
280 throw OrthancException(ErrorCode_InternalError);
281 }
282
283 return json_.GetConstContent();
284 }
285
286
287 bool LookupTransferSyntax(std::string& result)
288 {
289 ComputeMissingInformation();
290
291 DicomMap header;
292 if (DicomMap::ParseDicomMetaInformation(header, GetBufferData(), GetBufferSize()))
293 {
294 const DicomValue* value = header.TestAndGetValue(DICOM_TAG_TRANSFER_SYNTAX_UID);
295 if (value != NULL &&
296 !value->IsBinary() &&
297 !value->IsNull())
298 {
299 result = Toolbox::StripSpaces(value->GetContent());
300 return true;
301 }
302 }
303
304 return false;
305 }
306 };
307
308
309 DicomInstanceToStore::DicomInstanceToStore() :
310 pimpl_(new PImpl)
311 {
312 }
313
314
315 void DicomInstanceToStore::SetOrigin(const DicomInstanceOrigin& origin)
316 {
317 pimpl_->origin_ = origin;
318 }
319
320
321 const DicomInstanceOrigin& DicomInstanceToStore::GetOrigin() const
322 {
323 return pimpl_->origin_;
324 }
325
326
327 void DicomInstanceToStore::SetBuffer(const std::string& dicom)
328 {
329 pimpl_->buffer_.SetConstReference(dicom);
330 }
331
332
333 void DicomInstanceToStore::SetParsedDicomFile(ParsedDicomFile& parsed)
334 {
335 pimpl_->parsed_.SetReference(parsed);
336 }
337
338
339 void DicomInstanceToStore::SetSummary(const DicomMap& summary)
340 {
341 pimpl_->summary_.SetConstReference(summary);
342 }
343
344
345 void DicomInstanceToStore::SetJson(const Json::Value& json)
346 {
347 pimpl_->json_.SetConstReference(json);
348 }
349
350
351 const DicomInstanceToStore::MetadataMap& DicomInstanceToStore::GetMetadata() const
352 {
353 return pimpl_->metadata_;
354 }
355
356
357 DicomInstanceToStore::MetadataMap& DicomInstanceToStore::GetMetadata()
358 {
359 return pimpl_->metadata_;
360 }
361
362
46 void DicomInstanceToStore::AddMetadata(ResourceType level, 363 void DicomInstanceToStore::AddMetadata(ResourceType level,
47 MetadataType metadata, 364 MetadataType metadata,
48 const std::string& value) 365 const std::string& value)
49 { 366 {
50 metadata_[std::make_pair(level, metadata)] = value; 367 pimpl_->metadata_[std::make_pair(level, metadata)] = value;
51 } 368 }
52
53
54 void DicomInstanceToStore::ComputeMissingInformation()
55 {
56 if (buffer_.HasContent() &&
57 summary_.HasContent() &&
58 json_.HasContent())
59 {
60 // Fine, everything is available
61 return;
62 }
63
64 if (!buffer_.HasContent())
65 {
66 if (!parsed_.HasContent())
67 {
68 if (!summary_.HasContent())
69 {
70 throw OrthancException(ErrorCode_NotImplemented);
71 }
72 else
73 {
74 parsed_.TakeOwnership(new ParsedDicomFile(summary_.GetConstContent()));
75 }
76 }
77
78 // Serialize the parsed DICOM file
79 buffer_.Allocate();
80 if (!FromDcmtkBridge::SaveToMemoryBuffer(buffer_.GetContent(),
81 *parsed_.GetContent().GetDcmtkObject().getDataset()))
82 {
83 LOG(ERROR) << "Unable to serialize a DICOM file to a memory buffer";
84 throw OrthancException(ErrorCode_InternalError);
85 }
86 }
87
88 if (summary_.HasContent() &&
89 json_.HasContent())
90 {
91 return;
92 }
93
94 // At this point, we know that the DICOM file is available as a
95 // memory buffer, but that its summary or its JSON version is
96 // missing
97
98 if (!parsed_.HasContent())
99 {
100 parsed_.TakeOwnership(new ParsedDicomFile(buffer_.GetConstContent()));
101 }
102
103 // At this point, we have parsed the DICOM file
104
105 if (!summary_.HasContent())
106 {
107 summary_.Allocate();
108 FromDcmtkBridge::ExtractDicomSummary(summary_.GetContent(),
109 *parsed_.GetContent().GetDcmtkObject().getDataset());
110 }
111
112 if (!json_.HasContent())
113 {
114 json_.Allocate();
115
116 std::set<DicomTag> ignoreTagLength;
117 FromDcmtkBridge::ExtractDicomAsJson(json_.GetContent(),
118 *parsed_.GetContent().GetDcmtkObject().getDataset(),
119 ignoreTagLength);
120 }
121 }
122
123 369
124 370
125 const char* DicomInstanceToStore::GetBufferData() 371 const char* DicomInstanceToStore::GetBufferData()
126 { 372 {
127 ComputeMissingInformation(); 373 return pimpl_->GetBufferData();
128
129 if (!buffer_.HasContent())
130 {
131 throw OrthancException(ErrorCode_InternalError);
132 }
133
134 if (buffer_.GetConstContent().size() == 0)
135 {
136 return NULL;
137 }
138 else
139 {
140 return buffer_.GetConstContent().c_str();
141 }
142 } 374 }
143 375
144 376
145 size_t DicomInstanceToStore::GetBufferSize() 377 size_t DicomInstanceToStore::GetBufferSize()
146 { 378 {
147 ComputeMissingInformation(); 379 return pimpl_->GetBufferSize();
148
149 if (!buffer_.HasContent())
150 {
151 throw OrthancException(ErrorCode_InternalError);
152 }
153
154 return buffer_.GetConstContent().size();
155 } 380 }
156 381
157 382
158 const DicomMap& DicomInstanceToStore::GetSummary() 383 const DicomMap& DicomInstanceToStore::GetSummary()
159 { 384 {
160 ComputeMissingInformation(); 385 return pimpl_->GetSummary();
161
162 if (!summary_.HasContent())
163 {
164 throw OrthancException(ErrorCode_InternalError);
165 }
166
167 return summary_.GetConstContent();
168 } 386 }
169 387
170 388
171 const Json::Value& DicomInstanceToStore::GetJson() 389 const Json::Value& DicomInstanceToStore::GetJson()
172 { 390 {
173 ComputeMissingInformation(); 391 return pimpl_->GetJson();
174
175 if (!json_.HasContent())
176 {
177 throw OrthancException(ErrorCode_InternalError);
178 }
179
180 return json_.GetConstContent();
181 } 392 }
182 393
183 394
184 bool DicomInstanceToStore::LookupTransferSyntax(std::string& result) 395 bool DicomInstanceToStore::LookupTransferSyntax(std::string& result)
185 { 396 {
186 ComputeMissingInformation(); 397 return pimpl_->LookupTransferSyntax(result);
187
188 DicomMap header;
189 if (DicomMap::ParseDicomMetaInformation(header, GetBufferData(), GetBufferSize()))
190 {
191 const DicomValue* value = header.TestAndGetValue(DICOM_TAG_TRANSFER_SYNTAX_UID);
192 if (value != NULL &&
193 !value->IsBinary() &&
194 !value->IsNull())
195 {
196 result = Toolbox::StripSpaces(value->GetContent());
197 return true;
198 }
199 }
200
201 return false;
202 } 398 }
203 } 399 }