Mercurial > hg > orthanc-stone
comparison Framework/Oracle/GenericOracleRunner.cpp @ 1151:48befc2bf66d broker
ParseDicomFromWadoCommand
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 15 Nov 2019 17:34:19 +0100 |
parents | 7aad0984d38a |
children | 113131100638 |
comparison
equal
deleted
inserted
replaced
1150:7aad0984d38a | 1151:48befc2bf66d |
---|---|
28 #include "GetOrthancImageCommand.h" | 28 #include "GetOrthancImageCommand.h" |
29 #include "GetOrthancWebViewerJpegCommand.h" | 29 #include "GetOrthancWebViewerJpegCommand.h" |
30 #include "HttpCommand.h" | 30 #include "HttpCommand.h" |
31 #include "OracleCommandExceptionMessage.h" | 31 #include "OracleCommandExceptionMessage.h" |
32 #include "OrthancRestApiCommand.h" | 32 #include "OrthancRestApiCommand.h" |
33 #include "ParseDicomFromFileCommand.h" | |
34 #include "ParseDicomFromWadoCommand.h" | |
33 #include "ReadFileCommand.h" | 35 #include "ReadFileCommand.h" |
34 | 36 |
35 #if ORTHANC_ENABLE_DCMTK == 1 | 37 #if ORTHANC_ENABLE_DCMTK == 1 |
36 # include "ParseDicomFileCommand.h" | 38 # include "ParseDicomSuccessMessage.h" |
37 # include <dcmtk/dcmdata/dcdeftag.h> | 39 # include <dcmtk/dcmdata/dcdeftag.h> |
40 static unsigned int BUCKET_DICOMDIR = 0; | |
41 static unsigned int BUCKET_SOP = 1; | |
38 #endif | 42 #endif |
39 | 43 |
40 #include <Core/Compression/GzipCompressor.h> | 44 #include <Core/Compression/GzipCompressor.h> |
41 #include <Core/HttpClient.h> | 45 #include <Core/HttpClient.h> |
42 #include <Core/OrthancException.h> | 46 #include <Core/OrthancException.h> |
43 #include <Core/Toolbox.h> | 47 #include <Core/Toolbox.h> |
44 #include <Core/SystemToolbox.h> | 48 #include <Core/SystemToolbox.h> |
45 | 49 |
46 #include <boost/filesystem.hpp> | 50 #include <boost/filesystem.hpp> |
51 | |
52 #include <dcmtk/dcmdata/dcfilefo.h> | |
47 | 53 |
48 | 54 |
49 namespace OrthancStone | 55 namespace OrthancStone |
50 { | 56 { |
51 static void CopyHttpHeaders(Orthanc::HttpClient& client, | 57 static void CopyHttpHeaders(Orthanc::HttpClient& client, |
98 << " to " << answer.size() << " bytes"; | 104 << " to " << answer.size() << " bytes"; |
99 } | 105 } |
100 } | 106 } |
101 | 107 |
102 | 108 |
103 static void RunInternal(boost::weak_ptr<IObserver> receiver, | 109 static void RunHttpCommand(std::string& answer, |
104 IMessageEmitter& emitter, | 110 Orthanc::HttpClient::HttpHeaders& answerHeaders, |
105 const HttpCommand& command) | 111 const HttpCommand& command) |
106 { | 112 { |
107 Orthanc::HttpClient client; | 113 Orthanc::HttpClient client; |
108 client.SetUrl(command.GetUrl()); | 114 client.SetUrl(command.GetUrl()); |
109 client.SetMethod(command.GetMethod()); | 115 client.SetMethod(command.GetMethod()); |
110 client.SetTimeout(command.GetTimeout()); | 116 client.SetTimeout(command.GetTimeout()); |
120 command.GetMethod() == Orthanc::HttpMethod_Put) | 126 command.GetMethod() == Orthanc::HttpMethod_Put) |
121 { | 127 { |
122 client.SetBody(command.GetBody()); | 128 client.SetBody(command.GetBody()); |
123 } | 129 } |
124 | 130 |
131 client.ApplyAndThrowException(answer, answerHeaders); | |
132 DecodeAnswer(answer, answerHeaders); | |
133 } | |
134 | |
135 | |
136 static void RunInternal(boost::weak_ptr<IObserver> receiver, | |
137 IMessageEmitter& emitter, | |
138 const HttpCommand& command) | |
139 { | |
140 std::string answer; | |
141 Orthanc::HttpClient::HttpHeaders answerHeaders; | |
142 RunHttpCommand(answer, answerHeaders, command); | |
143 | |
144 HttpCommand::SuccessMessage message(command, answerHeaders, answer); | |
145 emitter.EmitMessage(receiver, message); | |
146 } | |
147 | |
148 | |
149 static void RunOrthancRestApiCommand(std::string& answer, | |
150 Orthanc::HttpClient::HttpHeaders& answerHeaders, | |
151 const Orthanc::WebServiceParameters& orthanc, | |
152 const OrthancRestApiCommand& command) | |
153 { | |
154 Orthanc::HttpClient client(orthanc, command.GetUri()); | |
155 client.SetMethod(command.GetMethod()); | |
156 client.SetTimeout(command.GetTimeout()); | |
157 | |
158 CopyHttpHeaders(client, command.GetHttpHeaders()); | |
159 | |
160 if (command.GetMethod() == Orthanc::HttpMethod_Post || | |
161 command.GetMethod() == Orthanc::HttpMethod_Put) | |
162 { | |
163 client.SetBody(command.GetBody()); | |
164 } | |
165 | |
166 client.ApplyAndThrowException(answer, answerHeaders); | |
167 DecodeAnswer(answer, answerHeaders); | |
168 } | |
169 | |
170 | |
171 static void RunInternal(boost::weak_ptr<IObserver> receiver, | |
172 IMessageEmitter& emitter, | |
173 const Orthanc::WebServiceParameters& orthanc, | |
174 const OrthancRestApiCommand& command) | |
175 { | |
176 std::string answer; | |
177 Orthanc::HttpClient::HttpHeaders answerHeaders; | |
178 RunOrthancRestApiCommand(answer, answerHeaders, orthanc, command); | |
179 | |
180 OrthancRestApiCommand::SuccessMessage message(command, answerHeaders, answer); | |
181 emitter.EmitMessage(receiver, message); | |
182 } | |
183 | |
184 | |
185 static void RunInternal(boost::weak_ptr<IObserver> receiver, | |
186 IMessageEmitter& emitter, | |
187 const Orthanc::WebServiceParameters& orthanc, | |
188 const GetOrthancImageCommand& command) | |
189 { | |
190 Orthanc::HttpClient client(orthanc, command.GetUri()); | |
191 client.SetTimeout(command.GetTimeout()); | |
192 | |
193 CopyHttpHeaders(client, command.GetHttpHeaders()); | |
194 | |
125 std::string answer; | 195 std::string answer; |
126 Orthanc::HttpClient::HttpHeaders answerHeaders; | 196 Orthanc::HttpClient::HttpHeaders answerHeaders; |
127 client.ApplyAndThrowException(answer, answerHeaders); | 197 client.ApplyAndThrowException(answer, answerHeaders); |
128 | 198 |
129 DecodeAnswer(answer, answerHeaders); | 199 DecodeAnswer(answer, answerHeaders); |
130 | 200 |
131 HttpCommand::SuccessMessage message(command, answerHeaders, answer); | 201 command.ProcessHttpAnswer(receiver, emitter, answer, answerHeaders); |
132 emitter.EmitMessage(receiver, message); | |
133 } | 202 } |
134 | 203 |
135 | 204 |
136 static void RunInternal(boost::weak_ptr<IObserver> receiver, | 205 static void RunInternal(boost::weak_ptr<IObserver> receiver, |
137 IMessageEmitter& emitter, | 206 IMessageEmitter& emitter, |
138 const Orthanc::WebServiceParameters& orthanc, | 207 const Orthanc::WebServiceParameters& orthanc, |
139 const OrthancRestApiCommand& command) | 208 const GetOrthancWebViewerJpegCommand& command) |
140 { | 209 { |
141 Orthanc::HttpClient client(orthanc, command.GetUri()); | 210 Orthanc::HttpClient client(orthanc, command.GetUri()); |
142 client.SetMethod(command.GetMethod()); | |
143 client.SetTimeout(command.GetTimeout()); | 211 client.SetTimeout(command.GetTimeout()); |
144 | 212 |
145 CopyHttpHeaders(client, command.GetHttpHeaders()); | 213 CopyHttpHeaders(client, command.GetHttpHeaders()); |
146 | |
147 if (command.GetMethod() == Orthanc::HttpMethod_Post || | |
148 command.GetMethod() == Orthanc::HttpMethod_Put) | |
149 { | |
150 client.SetBody(command.GetBody()); | |
151 } | |
152 | 214 |
153 std::string answer; | 215 std::string answer; |
154 Orthanc::HttpClient::HttpHeaders answerHeaders; | 216 Orthanc::HttpClient::HttpHeaders answerHeaders; |
155 client.ApplyAndThrowException(answer, answerHeaders); | 217 client.ApplyAndThrowException(answer, answerHeaders); |
156 | 218 |
157 DecodeAnswer(answer, answerHeaders); | 219 DecodeAnswer(answer, answerHeaders); |
158 | 220 |
159 OrthancRestApiCommand::SuccessMessage message(command, answerHeaders, answer); | 221 command.ProcessHttpAnswer(receiver, emitter, answer); |
222 } | |
223 | |
224 | |
225 static std::string GetPath(const std::string& root, | |
226 const std::string& file) | |
227 { | |
228 boost::filesystem::path a(root); | |
229 boost::filesystem::path b(file); | |
230 | |
231 boost::filesystem::path c; | |
232 if (b.is_absolute()) | |
233 { | |
234 c = b; | |
235 } | |
236 else | |
237 { | |
238 c = a / b; | |
239 } | |
240 | |
241 return c.string(); | |
242 } | |
243 | |
244 | |
245 static void RunInternal(boost::weak_ptr<IObserver> receiver, | |
246 IMessageEmitter& emitter, | |
247 const std::string& root, | |
248 const ReadFileCommand& command) | |
249 { | |
250 std::string path = GetPath(root, command.GetPath()); | |
251 LOG(TRACE) << "Oracle reading file: " << path; | |
252 | |
253 std::string content; | |
254 Orthanc::SystemToolbox::ReadFile(content, path, true /* log */); | |
255 | |
256 ReadFileCommand::SuccessMessage message(command, content); | |
160 emitter.EmitMessage(receiver, message); | 257 emitter.EmitMessage(receiver, message); |
161 } | 258 } |
162 | 259 |
163 | 260 |
164 static void RunInternal(boost::weak_ptr<IObserver> receiver, | 261 #if ORTHANC_ENABLE_DCMTK == 1 |
165 IMessageEmitter& emitter, | 262 static Orthanc::ParsedDicomFile* ParseDicom(uint64_t& fileSize, /* OUT */ |
263 const std::string& path, | |
264 bool isPixelData) | |
265 { | |
266 if (!Orthanc::SystemToolbox::IsRegularFile(path)) | |
267 { | |
268 throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentFile); | |
269 } | |
270 | |
271 LOG(TRACE) << "Parsing DICOM file, " << (isPixelData ? "with" : "without") | |
272 << " pixel data: " << path; | |
273 | |
274 boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time(); | |
275 | |
276 fileSize = Orthanc::SystemToolbox::GetFileSize(path); | |
277 | |
278 // Check for 32bit systems | |
279 if (fileSize != static_cast<uint64_t>(static_cast<size_t>(fileSize))) | |
280 { | |
281 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory); | |
282 } | |
283 | |
284 DcmFileFormat dicom; | |
285 bool ok; | |
286 | |
287 if (isPixelData) | |
288 { | |
289 ok = dicom.loadFile(path.c_str()).good(); | |
290 } | |
291 else | |
292 { | |
293 #if DCMTK_VERSION_NUMBER >= 362 | |
294 /** | |
295 * NB : We could stop at (0x3007, 0x0000) instead of | |
296 * DCM_PixelData as the Stone framework does not use further | |
297 * tags (cf. the Orthanc::DICOM_TAG_* constants), but we still | |
298 * use "PixelData" as this does not change the runtime much, and | |
299 * as it is more explicit. | |
300 **/ | |
301 static const DcmTagKey STOP = DCM_PixelData; | |
302 //static const DcmTagKey STOP(0x3007, 0x0000); | |
303 | |
304 ok = dicom.loadFileUntilTag(path.c_str(), EXS_Unknown, EGL_noChange, | |
305 DCM_MaxReadLength, ERM_autoDetect, STOP).good(); | |
306 #else | |
307 // The primitive "loadFileUntilTag" was introduced in DCMTK 3.6.2 | |
308 ok = dicom.loadFile(path.c_str()).good(); | |
309 #endif | |
310 } | |
311 | |
312 if (ok) | |
313 { | |
314 std::auto_ptr<Orthanc::ParsedDicomFile> result(new Orthanc::ParsedDicomFile(dicom)); | |
315 | |
316 boost::posix_time::ptime end = boost::posix_time::microsec_clock::local_time(); | |
317 LOG(TRACE) << path << ": parsed in " << (end-start).total_milliseconds() << " ms"; | |
318 | |
319 return result.release(); | |
320 } | |
321 else | |
322 { | |
323 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, | |
324 "Cannot parse file: " + path); | |
325 } | |
326 } | |
327 | |
328 | |
329 static void RunInternal(boost::weak_ptr<IObserver> receiver, | |
330 IMessageEmitter& emitter, | |
331 boost::shared_ptr<ParsedDicomCache> cache, | |
332 const std::string& root, | |
333 const ParseDicomFromFileCommand& command) | |
334 { | |
335 const std::string path = GetPath(root, command.GetPath()); | |
336 | |
337 if (cache) | |
338 { | |
339 ParsedDicomCache::Reader reader(*cache, BUCKET_DICOMDIR, path); | |
340 if (reader.IsValid() && | |
341 (!command.IsPixelDataIncluded() || | |
342 reader.HasPixelData())) | |
343 { | |
344 // Reuse the DICOM file from the cache | |
345 ParseDicomSuccessMessage message(command, reader.GetDicom(), reader.GetFileSize(), reader.HasPixelData()); | |
346 emitter.EmitMessage(receiver, message); | |
347 return; | |
348 } | |
349 } | |
350 | |
351 uint64_t fileSize; | |
352 std::auto_ptr<Orthanc::ParsedDicomFile> parsed(ParseDicom(fileSize, path, command.IsPixelDataIncluded())); | |
353 | |
354 if (fileSize != static_cast<size_t>(fileSize)) | |
355 { | |
356 // Cannot load such a large file on 32-bit architecture | |
357 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory); | |
358 } | |
359 | |
360 { | |
361 ParseDicomSuccessMessage message | |
362 (command, *parsed, static_cast<size_t>(fileSize), command.IsPixelDataIncluded()); | |
363 emitter.EmitMessage(receiver, message); | |
364 } | |
365 | |
366 if (cache) | |
367 { | |
368 // Store it into the cache for future use | |
369 | |
370 // Invalidate to overwrite DICOM instance that would already | |
371 // be stored without pixel data | |
372 cache->Invalidate(BUCKET_DICOMDIR, path); | |
373 | |
374 cache->Acquire(BUCKET_DICOMDIR, path, parsed.release(), | |
375 static_cast<size_t>(fileSize), command.IsPixelDataIncluded()); | |
376 } | |
377 } | |
378 | |
379 | |
380 static void RunInternal(boost::weak_ptr<IObserver> receiver, | |
381 IMessageEmitter& emitter, | |
382 boost::shared_ptr<ParsedDicomCache> cache, | |
166 const Orthanc::WebServiceParameters& orthanc, | 383 const Orthanc::WebServiceParameters& orthanc, |
167 const GetOrthancImageCommand& command) | 384 const ParseDicomFromWadoCommand& command) |
168 { | 385 { |
169 Orthanc::HttpClient client(orthanc, command.GetUri()); | 386 if (cache) |
170 client.SetTimeout(command.GetTimeout()); | 387 { |
171 | 388 ParsedDicomCache::Reader reader(*cache, BUCKET_SOP, command.GetSopInstanceUid()); |
172 CopyHttpHeaders(client, command.GetHttpHeaders()); | 389 if (reader.IsValid() && |
173 | 390 reader.HasPixelData()) |
391 { | |
392 // Reuse the DICOM file from the cache | |
393 ParseDicomSuccessMessage message(command, reader.GetDicom(), reader.GetFileSize(), reader.HasPixelData()); | |
394 emitter.EmitMessage(receiver, message); | |
395 return; | |
396 } | |
397 } | |
398 | |
174 std::string answer; | 399 std::string answer; |
175 Orthanc::HttpClient::HttpHeaders answerHeaders; | 400 Orthanc::HttpClient::HttpHeaders answerHeaders; |
176 client.ApplyAndThrowException(answer, answerHeaders); | 401 |
177 | 402 switch (command.GetRestCommand().GetType()) |
178 DecodeAnswer(answer, answerHeaders); | 403 { |
179 | 404 case IOracleCommand::Type_Http: |
180 command.ProcessHttpAnswer(receiver, emitter, answer, answerHeaders); | 405 RunHttpCommand(answer, answerHeaders, dynamic_cast<const HttpCommand&>(command.GetRestCommand())); |
181 } | 406 break; |
182 | 407 |
183 | 408 case IOracleCommand::Type_OrthancRestApi: |
184 static void RunInternal(boost::weak_ptr<IObserver> receiver, | 409 RunOrthancRestApiCommand(answer, answerHeaders, orthanc, |
185 IMessageEmitter& emitter, | 410 dynamic_cast<const OrthancRestApiCommand&>(command.GetRestCommand())); |
186 const Orthanc::WebServiceParameters& orthanc, | 411 break; |
187 const GetOrthancWebViewerJpegCommand& command) | 412 |
188 { | 413 default: |
189 Orthanc::HttpClient client(orthanc, command.GetUri()); | 414 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); |
190 client.SetTimeout(command.GetTimeout()); | 415 } |
191 | 416 |
192 CopyHttpHeaders(client, command.GetHttpHeaders()); | 417 size_t fileSize; |
193 | 418 std::auto_ptr<Orthanc::ParsedDicomFile> parsed(ParseDicomSuccessMessage::ParseWadoAnswer(fileSize, answer, answerHeaders)); |
194 std::string answer; | 419 |
195 Orthanc::HttpClient::HttpHeaders answerHeaders; | 420 { |
196 client.ApplyAndThrowException(answer, answerHeaders); | 421 ParseDicomSuccessMessage message(command, *parsed, fileSize, |
197 | 422 true /* pixel data always is included in WADO-RS */); |
198 DecodeAnswer(answer, answerHeaders); | 423 emitter.EmitMessage(receiver, message); |
199 | 424 } |
200 command.ProcessHttpAnswer(receiver, emitter, answer); | 425 |
201 } | 426 if (cache) |
202 | 427 { |
203 | 428 // Store it into the cache for future use |
204 static std::string GetPath(const std::string& root, | 429 cache->Acquire(BUCKET_SOP, command.GetSopInstanceUid(), parsed.release(), fileSize, true); |
205 const std::string& file) | 430 } |
206 { | 431 } |
207 boost::filesystem::path a(root); | |
208 boost::filesystem::path b(file); | |
209 | |
210 boost::filesystem::path c; | |
211 if (b.is_absolute()) | |
212 { | |
213 c = b; | |
214 } | |
215 else | |
216 { | |
217 c = a / b; | |
218 } | |
219 | |
220 return c.string(); | |
221 } | |
222 | |
223 | |
224 static void RunInternal(boost::weak_ptr<IObserver> receiver, | |
225 IMessageEmitter& emitter, | |
226 const std::string& root, | |
227 const ReadFileCommand& command) | |
228 { | |
229 std::string path = GetPath(root, command.GetPath()); | |
230 LOG(TRACE) << "Oracle reading file: " << path; | |
231 | |
232 std::string content; | |
233 Orthanc::SystemToolbox::ReadFile(content, path, true /* log */); | |
234 | |
235 ReadFileCommand::SuccessMessage message(command, content); | |
236 emitter.EmitMessage(receiver, message); | |
237 } | |
238 | |
239 | |
240 #if ORTHANC_ENABLE_DCMTK == 1 | |
241 namespace | |
242 { | |
243 class IDicomHandler : public boost::noncopyable | |
244 { | |
245 public: | |
246 virtual ~IDicomHandler() | |
247 { | |
248 } | |
249 | |
250 virtual void Handle(Orthanc::ParsedDicomFile* dicom, | |
251 const ParseDicomFileCommand& command, | |
252 const std::string& path, | |
253 uint64_t fileSize) = 0; | |
254 | |
255 static void Apply(IDicomHandler& handler, | |
256 const std::string& path, | |
257 const ParseDicomFileCommand& command) | |
258 { | |
259 if (!Orthanc::SystemToolbox::IsRegularFile(path)) | |
260 { | |
261 throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentFile); | |
262 } | |
263 | |
264 LOG(TRACE) << "Parsing DICOM file, " | |
265 << (command.IsPixelDataIncluded() ? "with" : "without") | |
266 << " pixel data: " << path; | |
267 | |
268 boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time(); | |
269 | |
270 uint64_t fileSize = Orthanc::SystemToolbox::GetFileSize(path); | |
271 | |
272 // Check for 32bit systems | |
273 if (fileSize != static_cast<uint64_t>(static_cast<size_t>(fileSize))) | |
274 { | |
275 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory); | |
276 } | |
277 | |
278 DcmFileFormat dicom; | |
279 bool ok; | |
280 | |
281 if (command.IsPixelDataIncluded()) | |
282 { | |
283 ok = dicom.loadFile(path.c_str()).good(); | |
284 } | |
285 else | |
286 { | |
287 #if DCMTK_VERSION_NUMBER >= 362 | |
288 /** | |
289 * NB : We could stop at (0x3007, 0x0000) instead of | |
290 * DCM_PixelData as the Stone framework does not use further | |
291 * tags (cf. the Orthanc::DICOM_TAG_* constants), but we | |
292 * still use "PixelData" as this does not change the runtime | |
293 * much, and as it is more explicit. | |
294 **/ | |
295 static const DcmTagKey STOP = DCM_PixelData; | |
296 //static const DcmTagKey STOP(0x3007, 0x0000); | |
297 | |
298 ok = dicom.loadFileUntilTag(path.c_str(), EXS_Unknown, EGL_noChange, | |
299 DCM_MaxReadLength, ERM_autoDetect, STOP).good(); | |
300 #else | |
301 // The primitive "loadFileUntilTag" was introduced in DCMTK 3.6.2 | |
302 ok = dicom.loadFile(path.c_str()).good(); | |
303 #endif | |
304 } | |
305 | |
306 if (ok) | |
307 { | |
308 handler.Handle(new Orthanc::ParsedDicomFile(dicom), command, path, fileSize); | |
309 | |
310 boost::posix_time::ptime end = boost::posix_time::microsec_clock::local_time(); | |
311 LOG(TRACE) << path << ": parsed in " << (end-start).total_milliseconds() << " ms"; | |
312 } | |
313 else | |
314 { | |
315 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, | |
316 "Cannot parse file: " + path); | |
317 } | |
318 } | |
319 }; | |
320 | |
321 | |
322 class DicomHandlerWithoutCache : public IDicomHandler | |
323 { | |
324 private: | |
325 boost::weak_ptr<IObserver> receiver_; | |
326 IMessageEmitter& emitter_; | |
327 | |
328 public: | |
329 DicomHandlerWithoutCache(boost::weak_ptr<IObserver> receiver, | |
330 IMessageEmitter& emitter) : | |
331 receiver_(receiver), | |
332 emitter_(emitter) | |
333 { | |
334 } | |
335 | |
336 virtual void Handle(Orthanc::ParsedDicomFile* dicom, | |
337 const ParseDicomFileCommand& command, | |
338 const std::string& path, | |
339 uint64_t fileSize) | |
340 { | |
341 std::auto_ptr<Orthanc::ParsedDicomFile> parsed(dicom); | |
342 | |
343 ParseDicomFileCommand::SuccessMessage message | |
344 (command, *parsed, static_cast<size_t>(fileSize), command.IsPixelDataIncluded()); | |
345 emitter_.EmitMessage(receiver_, message); | |
346 } | |
347 }; | |
348 | |
349 | |
350 class DicomHandlerWithCache : public IDicomHandler | |
351 { | |
352 private: | |
353 boost::weak_ptr<IObserver> receiver_; | |
354 IMessageEmitter& emitter_; | |
355 boost::shared_ptr<ParsedDicomCache> cache_; | |
356 | |
357 public: | |
358 DicomHandlerWithCache(boost::weak_ptr<IObserver> receiver, | |
359 IMessageEmitter& emitter, | |
360 boost::shared_ptr<ParsedDicomCache> cache) : | |
361 receiver_(receiver), | |
362 emitter_(emitter), | |
363 cache_(cache) | |
364 { | |
365 if (!cache) | |
366 { | |
367 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
368 } | |
369 } | |
370 | |
371 virtual void Handle(Orthanc::ParsedDicomFile* dicom, | |
372 const ParseDicomFileCommand& command, | |
373 const std::string& path, | |
374 uint64_t fileSize) | |
375 { | |
376 std::auto_ptr<Orthanc::ParsedDicomFile> parsed(dicom); | |
377 | |
378 { | |
379 ParseDicomFileCommand::SuccessMessage message | |
380 (command, *parsed, static_cast<size_t>(fileSize), command.IsPixelDataIncluded()); | |
381 emitter_.EmitMessage(receiver_, message); | |
382 } | |
383 | |
384 // Store it into the cache for future use | |
385 assert(cache_); | |
386 | |
387 // Invalidate to overwrite DICOM instance that would already | |
388 // be stored without pixel data | |
389 cache_->Invalidate(path); | |
390 | |
391 cache_->Acquire(path, parsed.release(), | |
392 static_cast<size_t>(fileSize), command.IsPixelDataIncluded()); | |
393 } | |
394 }; | |
395 } | |
396 | |
397 | |
398 static void RunInternal(boost::weak_ptr<IObserver> receiver, | |
399 IMessageEmitter& emitter, | |
400 boost::shared_ptr<ParsedDicomCache> cache, | |
401 const std::string& root, | |
402 const ParseDicomFileCommand& command) | |
403 { | |
404 const std::string path = GetPath(root, command.GetPath()); | |
405 | |
406 #if 1 | |
407 if (cache.get()) | |
408 { | |
409 { | |
410 ParsedDicomCache::Reader reader(*cache, path); | |
411 if (reader.IsValid() && | |
412 (!command.IsPixelDataIncluded() || | |
413 reader.HasPixelData())) | |
414 { | |
415 // Reuse the DICOM file from the cache | |
416 ParseDicomFileCommand::SuccessMessage message( | |
417 command, reader.GetDicom(), reader.GetFileSize(), reader.HasPixelData()); | |
418 emitter.EmitMessage(receiver, message); | |
419 return; | |
420 } | |
421 } | |
422 | |
423 DicomHandlerWithCache handler(receiver, emitter, cache); | |
424 IDicomHandler::Apply(handler, path, command); | |
425 } | |
426 else | |
427 { | |
428 // No cache available | |
429 DicomHandlerWithoutCache handler(receiver, emitter); | |
430 IDicomHandler::Apply(handler, path, command); | |
431 } | |
432 #else | |
433 DicomHandlerWithoutCache handler(receiver, emitter); | |
434 IDicomHandler::Apply(handler, path, command); | |
435 #endif | |
436 } | |
437 | |
438 #endif | 432 #endif |
439 | 433 |
440 | 434 |
441 void GenericOracleRunner::Run(boost::weak_ptr<IObserver> receiver, | 435 void GenericOracleRunner::Run(boost::weak_ptr<IObserver> receiver, |
442 IMessageEmitter& emitter, | 436 IMessageEmitter& emitter, |
474 case IOracleCommand::Type_ReadFile: | 468 case IOracleCommand::Type_ReadFile: |
475 RunInternal(receiver, emitter, rootDirectory_, | 469 RunInternal(receiver, emitter, rootDirectory_, |
476 dynamic_cast<const ReadFileCommand&>(command)); | 470 dynamic_cast<const ReadFileCommand&>(command)); |
477 break; | 471 break; |
478 | 472 |
479 case IOracleCommand::Type_ParseDicomFile: | 473 case IOracleCommand::Type_ParseDicomFromFile: |
474 case IOracleCommand::Type_ParseDicomFromWado: | |
480 #if ORTHANC_ENABLE_DCMTK == 1 | 475 #if ORTHANC_ENABLE_DCMTK == 1 |
481 RunInternal(receiver, emitter, dicomCache_, rootDirectory_, | 476 switch (command.GetType()) |
482 dynamic_cast<const ParseDicomFileCommand&>(command)); | 477 { |
478 case IOracleCommand::Type_ParseDicomFromFile: | |
479 RunInternal(receiver, emitter, dicomCache_, rootDirectory_, | |
480 dynamic_cast<const ParseDicomFromFileCommand&>(command)); | |
481 break; | |
482 | |
483 case IOracleCommand::Type_ParseDicomFromWado: | |
484 RunInternal(receiver, emitter, dicomCache_, orthanc_, | |
485 dynamic_cast<const ParseDicomFromWadoCommand&>(command)); | |
486 break; | |
487 | |
488 default: | |
489 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
490 } | |
483 break; | 491 break; |
484 #else | 492 #else |
485 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, | 493 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, |
486 "DCMTK must be enabled to parse DICOM files"); | 494 "DCMTK must be enabled to parse DICOM files"); |
487 #endif | 495 #endif |