Mercurial > hg > orthanc
comparison Plugins/Engine/OrthancPlugins.cpp @ 2884:497a637366b4 db-changes
integration mainline->db-changes
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 12 Oct 2018 15:18:10 +0200 |
parents | 7133ad478eea |
children | 9d277f8ad698 |
comparison
equal
deleted
inserted
replaced
1762:2b91363cc1d1 | 2884:497a637366b4 |
---|---|
1 /** | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | 2 * Orthanc - A Lightweight, RESTful DICOM Store |
3 * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics | 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics |
4 * Department, University Hospital of Liege, Belgium | 4 * Department, University Hospital of Liege, Belgium |
5 * Copyright (C) 2017-2018 Osimis S.A., Belgium | |
5 * | 6 * |
6 * This program is free software: you can redistribute it and/or | 7 * This program is free software: you can redistribute it and/or |
7 * modify it under the terms of the GNU General Public License as | 8 * modify it under the terms of the GNU General Public License as |
8 * published by the Free Software Foundation, either version 3 of the | 9 * published by the Free Software Foundation, either version 3 of the |
9 * License, or (at your option) any later version. | 10 * License, or (at your option) any later version. |
31 | 32 |
32 | 33 |
33 #include "../../OrthancServer/PrecompiledHeadersServer.h" | 34 #include "../../OrthancServer/PrecompiledHeadersServer.h" |
34 #include "OrthancPlugins.h" | 35 #include "OrthancPlugins.h" |
35 | 36 |
36 #if ORTHANC_PLUGINS_ENABLED != 1 | 37 #if ORTHANC_ENABLE_PLUGINS != 1 |
37 #error The plugin support is disabled | 38 #error The plugin support is disabled |
38 #endif | 39 #endif |
39 | 40 |
40 | 41 |
41 #include "../../Core/ChunkedBuffer.h" | 42 #include "../../Core/ChunkedBuffer.h" |
43 #include "../../Core/DicomFormat/DicomArray.h" | |
42 #include "../../Core/HttpServer/HttpToolbox.h" | 44 #include "../../Core/HttpServer/HttpToolbox.h" |
43 #include "../../Core/Logging.h" | 45 #include "../../Core/Logging.h" |
44 #include "../../Core/OrthancException.h" | 46 #include "../../Core/OrthancException.h" |
47 #include "../../Core/SerializationToolbox.h" | |
45 #include "../../Core/Toolbox.h" | 48 #include "../../Core/Toolbox.h" |
46 #include "../../OrthancServer/FromDcmtkBridge.h" | 49 #include "../../Core/DicomParsing/FromDcmtkBridge.h" |
50 #include "../../Core/DicomParsing/ToDcmtkBridge.h" | |
47 #include "../../OrthancServer/OrthancInitialization.h" | 51 #include "../../OrthancServer/OrthancInitialization.h" |
48 #include "../../OrthancServer/ServerContext.h" | 52 #include "../../OrthancServer/ServerContext.h" |
49 #include "../../OrthancServer/ServerToolbox.h" | 53 #include "../../OrthancServer/ServerToolbox.h" |
54 #include "../../OrthancServer/Search/HierarchicalMatcher.h" | |
55 #include "../../Core/DicomParsing/Internals/DicomImageDecoder.h" | |
50 #include "../../Core/Compression/ZlibCompressor.h" | 56 #include "../../Core/Compression/ZlibCompressor.h" |
51 #include "../../Core/Compression/GzipCompressor.h" | 57 #include "../../Core/Compression/GzipCompressor.h" |
52 #include "../../Core/Images/Image.h" | 58 #include "../../Core/Images/Image.h" |
53 #include "../../Core/Images/PngReader.h" | 59 #include "../../Core/Images/PngReader.h" |
54 #include "../../Core/Images/PngWriter.h" | 60 #include "../../Core/Images/PngWriter.h" |
55 #include "../../Core/Images/JpegReader.h" | 61 #include "../../Core/Images/JpegReader.h" |
56 #include "../../Core/Images/JpegWriter.h" | 62 #include "../../Core/Images/JpegWriter.h" |
57 #include "../../Core/Images/ImageProcessing.h" | 63 #include "../../Core/Images/ImageProcessing.h" |
64 #include "../../OrthancServer/DefaultDicomImageDecoder.h" | |
65 #include "../../OrthancServer/OrthancFindRequestHandler.h" | |
58 #include "PluginsEnumerations.h" | 66 #include "PluginsEnumerations.h" |
67 #include "PluginsJob.h" | |
59 | 68 |
60 #include <boost/regex.hpp> | 69 #include <boost/regex.hpp> |
70 #include <dcmtk/dcmdata/dcdict.h> | |
71 #include <dcmtk/dcmdata/dcdicent.h> | |
61 | 72 |
62 namespace Orthanc | 73 namespace Orthanc |
63 { | 74 { |
75 static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, | |
76 const void* data, | |
77 size_t size) | |
78 { | |
79 target.size = size; | |
80 | |
81 if (size == 0) | |
82 { | |
83 target.data = NULL; | |
84 } | |
85 else | |
86 { | |
87 target.data = malloc(size); | |
88 if (target.data != NULL) | |
89 { | |
90 memcpy(target.data, data, size); | |
91 } | |
92 else | |
93 { | |
94 throw OrthancException(ErrorCode_NotEnoughMemory); | |
95 } | |
96 } | |
97 } | |
98 | |
99 | |
100 static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, | |
101 const std::string& str) | |
102 { | |
103 if (str.size() == 0) | |
104 { | |
105 target.size = 0; | |
106 target.data = NULL; | |
107 } | |
108 else | |
109 { | |
110 CopyToMemoryBuffer(target, str.c_str(), str.size()); | |
111 } | |
112 } | |
113 | |
114 | |
115 static char* CopyString(const std::string& str) | |
116 { | |
117 char *result = reinterpret_cast<char*>(malloc(str.size() + 1)); | |
118 if (result == NULL) | |
119 { | |
120 throw OrthancException(ErrorCode_NotEnoughMemory); | |
121 } | |
122 | |
123 if (str.size() == 0) | |
124 { | |
125 result[0] = '\0'; | |
126 } | |
127 else | |
128 { | |
129 memcpy(result, &str[0], str.size() + 1); | |
130 } | |
131 | |
132 return result; | |
133 } | |
134 | |
135 | |
64 namespace | 136 namespace |
65 { | 137 { |
66 class PluginStorageArea : public IStorageArea | 138 class PluginStorageArea : public IStorageArea |
67 { | 139 { |
68 private: | 140 private: |
177 IStorageArea* Create() const | 249 IStorageArea* Create() const |
178 { | 250 { |
179 return new PluginStorageArea(callbacks_, errorDictionary_); | 251 return new PluginStorageArea(callbacks_, errorDictionary_); |
180 } | 252 } |
181 }; | 253 }; |
182 } | 254 |
183 | 255 |
184 | 256 class OrthancPeers : public boost::noncopyable |
185 struct OrthancPlugins::PImpl | 257 { |
186 { | 258 private: |
259 std::vector<std::string> names_; | |
260 std::vector<WebServiceParameters> parameters_; | |
261 | |
262 void CheckIndex(size_t i) const | |
263 { | |
264 assert(names_.size() == parameters_.size()); | |
265 if (i >= names_.size()) | |
266 { | |
267 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
268 } | |
269 } | |
270 | |
271 public: | |
272 OrthancPeers() | |
273 { | |
274 std::set<std::string> peers; | |
275 Configuration::GetListOfOrthancPeers(peers); | |
276 | |
277 names_.reserve(peers.size()); | |
278 parameters_.reserve(peers.size()); | |
279 | |
280 for (std::set<std::string>::const_iterator | |
281 it = peers.begin(); it != peers.end(); ++it) | |
282 { | |
283 WebServiceParameters peer; | |
284 if (Configuration::GetOrthancPeer(peer, *it)) | |
285 { | |
286 names_.push_back(*it); | |
287 parameters_.push_back(peer); | |
288 } | |
289 } | |
290 } | |
291 | |
292 size_t GetPeersCount() const | |
293 { | |
294 return names_.size(); | |
295 } | |
296 | |
297 const std::string& GetPeerName(size_t i) const | |
298 { | |
299 CheckIndex(i); | |
300 return names_[i]; | |
301 } | |
302 | |
303 const WebServiceParameters& GetPeerParameters(size_t i) const | |
304 { | |
305 CheckIndex(i); | |
306 return parameters_[i]; | |
307 } | |
308 }; | |
309 } | |
310 | |
311 | |
312 class OrthancPlugins::PImpl | |
313 { | |
314 private: | |
315 boost::mutex contextMutex_; | |
316 ServerContext* context_; | |
317 | |
318 | |
319 public: | |
187 class RestCallback : public boost::noncopyable | 320 class RestCallback : public boost::noncopyable |
188 { | 321 { |
189 private: | 322 private: |
190 boost::regex regex_; | 323 boost::regex regex_; |
191 OrthancPluginRestCallback callback_; | 324 OrthancPluginRestCallback callback_; |
231 } | 364 } |
232 } | 365 } |
233 }; | 366 }; |
234 | 367 |
235 | 368 |
369 class ServerContextLock | |
370 { | |
371 private: | |
372 boost::mutex::scoped_lock lock_; | |
373 ServerContext* context_; | |
374 | |
375 public: | |
376 ServerContextLock(PImpl& that) : | |
377 lock_(that.contextMutex_), | |
378 context_(that.context_) | |
379 { | |
380 if (context_ == NULL) | |
381 { | |
382 throw OrthancException(ErrorCode_DatabaseNotInitialized); | |
383 } | |
384 } | |
385 | |
386 ServerContext& GetContext() | |
387 { | |
388 assert(context_ != NULL); | |
389 return *context_; | |
390 } | |
391 }; | |
392 | |
393 | |
394 void SetServerContext(ServerContext* context) | |
395 { | |
396 boost::mutex::scoped_lock lock(contextMutex_); | |
397 context_ = context; | |
398 } | |
399 | |
400 | |
236 typedef std::pair<std::string, _OrthancPluginProperty> Property; | 401 typedef std::pair<std::string, _OrthancPluginProperty> Property; |
237 typedef std::list<RestCallback*> RestCallbacks; | 402 typedef std::list<RestCallback*> RestCallbacks; |
238 typedef std::list<OrthancPluginOnStoredInstanceCallback> OnStoredCallbacks; | 403 typedef std::list<OrthancPluginOnStoredInstanceCallback> OnStoredCallbacks; |
239 typedef std::list<OrthancPluginOnChangeCallback> OnChangeCallbacks; | 404 typedef std::list<OrthancPluginOnChangeCallback> OnChangeCallbacks; |
405 typedef std::list<OrthancPluginIncomingHttpRequestFilter> IncomingHttpRequestFilters; | |
406 typedef std::list<OrthancPluginIncomingHttpRequestFilter2> IncomingHttpRequestFilters2; | |
407 typedef std::list<OrthancPluginDecodeImageCallback> DecodeImageCallbacks; | |
408 typedef std::list<OrthancPluginJobsUnserializer> JobsUnserializers; | |
240 typedef std::map<Property, std::string> Properties; | 409 typedef std::map<Property, std::string> Properties; |
241 | 410 |
242 PluginsManager manager_; | 411 PluginsManager manager_; |
243 ServerContext* context_; | 412 |
244 RestCallbacks restCallbacks_; | 413 RestCallbacks restCallbacks_; |
245 OnStoredCallbacks onStoredCallbacks_; | 414 OnStoredCallbacks onStoredCallbacks_; |
246 OnChangeCallbacks onChangeCallbacks_; | 415 OnChangeCallbacks onChangeCallbacks_; |
416 OrthancPluginFindCallback findCallback_; | |
417 OrthancPluginWorklistCallback worklistCallback_; | |
418 DecodeImageCallbacks decodeImageCallbacks_; | |
419 JobsUnserializers jobsUnserializers_; | |
420 _OrthancPluginMoveCallback moveCallbacks_; | |
421 IncomingHttpRequestFilters incomingHttpRequestFilters_; | |
422 IncomingHttpRequestFilters2 incomingHttpRequestFilters2_; | |
247 std::auto_ptr<StorageAreaFactory> storageArea_; | 423 std::auto_ptr<StorageAreaFactory> storageArea_; |
424 | |
248 boost::recursive_mutex restCallbackMutex_; | 425 boost::recursive_mutex restCallbackMutex_; |
249 boost::recursive_mutex storedCallbackMutex_; | 426 boost::recursive_mutex storedCallbackMutex_; |
250 boost::recursive_mutex changeCallbackMutex_; | 427 boost::recursive_mutex changeCallbackMutex_; |
428 boost::mutex findCallbackMutex_; | |
429 boost::mutex worklistCallbackMutex_; | |
430 boost::mutex decodeImageCallbackMutex_; | |
431 boost::mutex jobsUnserializersMutex_; | |
251 boost::recursive_mutex invokeServiceMutex_; | 432 boost::recursive_mutex invokeServiceMutex_; |
433 | |
252 Properties properties_; | 434 Properties properties_; |
253 int argc_; | 435 int argc_; |
254 char** argv_; | 436 char** argv_; |
255 std::auto_ptr<OrthancPluginDatabase> database_; | 437 std::auto_ptr<OrthancPluginDatabase> database_; |
256 PluginsErrorDictionary dictionary_; | 438 PluginsErrorDictionary dictionary_; |
257 | 439 |
258 PImpl() : | 440 PImpl() : |
259 context_(NULL), | 441 context_(NULL), |
442 findCallback_(NULL), | |
443 worklistCallback_(NULL), | |
260 argc_(1), | 444 argc_(1), |
261 argv_(NULL) | 445 argv_(NULL) |
262 { | 446 { |
447 memset(&moveCallbacks_, 0, sizeof(moveCallbacks_)); | |
263 } | 448 } |
264 }; | 449 }; |
265 | 450 |
266 | 451 |
267 | 452 |
268 static char* CopyString(const std::string& str) | 453 class OrthancPlugins::WorklistHandler : public IWorklistRequestHandler |
269 { | 454 { |
270 char *result = reinterpret_cast<char*>(malloc(str.size() + 1)); | 455 private: |
271 if (result == NULL) | 456 OrthancPlugins& that_; |
272 { | 457 std::auto_ptr<HierarchicalMatcher> matcher_; |
273 throw OrthancException(ErrorCode_NotEnoughMemory); | 458 std::auto_ptr<ParsedDicomFile> filtered_; |
274 } | 459 ParsedDicomFile* currentQuery_; |
275 | 460 |
276 if (str.size() == 0) | 461 void Reset() |
277 { | 462 { |
278 result[0] = '\0'; | 463 matcher_.reset(); |
279 } | 464 filtered_.reset(); |
280 else | 465 currentQuery_ = NULL; |
281 { | 466 } |
282 memcpy(result, &str[0], str.size() + 1); | 467 |
283 } | 468 public: |
284 | 469 WorklistHandler(OrthancPlugins& that) : that_(that) |
285 return result; | 470 { |
286 } | 471 Reset(); |
472 } | |
473 | |
474 virtual void Handle(DicomFindAnswers& answers, | |
475 ParsedDicomFile& query, | |
476 const std::string& remoteIp, | |
477 const std::string& remoteAet, | |
478 const std::string& calledAet, | |
479 ModalityManufacturer manufacturer) | |
480 { | |
481 static const char* LUA_CALLBACK = "IncomingWorklistRequestFilter"; | |
482 | |
483 { | |
484 PImpl::ServerContextLock lock(*that_.pimpl_); | |
485 LuaScripting::Lock lua(lock.GetContext().GetLuaScripting()); | |
486 | |
487 if (!lua.GetLua().IsExistingFunction(LUA_CALLBACK)) | |
488 { | |
489 currentQuery_ = &query; | |
490 } | |
491 else | |
492 { | |
493 Json::Value source, origin; | |
494 query.DatasetToJson(source, DicomToJsonFormat_Short, DicomToJsonFlags_None, 0); | |
495 | |
496 OrthancFindRequestHandler::FormatOrigin | |
497 (origin, remoteIp, remoteAet, calledAet, manufacturer); | |
498 | |
499 LuaFunctionCall call(lua.GetLua(), LUA_CALLBACK); | |
500 call.PushJson(source); | |
501 call.PushJson(origin); | |
502 | |
503 Json::Value target; | |
504 call.ExecuteToJson(target, true); | |
505 | |
506 filtered_.reset(ParsedDicomFile::CreateFromJson(target, DicomFromJsonFlags_None)); | |
507 currentQuery_ = filtered_.get(); | |
508 } | |
509 } | |
510 | |
511 matcher_.reset(new HierarchicalMatcher(*currentQuery_)); | |
512 | |
513 { | |
514 boost::mutex::scoped_lock lock(that_.pimpl_->worklistCallbackMutex_); | |
515 | |
516 if (that_.pimpl_->worklistCallback_) | |
517 { | |
518 OrthancPluginErrorCode error = that_.pimpl_->worklistCallback_ | |
519 (reinterpret_cast<OrthancPluginWorklistAnswers*>(&answers), | |
520 reinterpret_cast<const OrthancPluginWorklistQuery*>(this), | |
521 remoteAet.c_str(), | |
522 calledAet.c_str()); | |
523 | |
524 if (error != OrthancPluginErrorCode_Success) | |
525 { | |
526 Reset(); | |
527 that_.GetErrorDictionary().LogError(error, true); | |
528 throw OrthancException(static_cast<ErrorCode>(error)); | |
529 } | |
530 } | |
531 | |
532 Reset(); | |
533 } | |
534 } | |
535 | |
536 void GetDicomQuery(OrthancPluginMemoryBuffer& target) const | |
537 { | |
538 if (currentQuery_ == NULL) | |
539 { | |
540 throw OrthancException(ErrorCode_Plugin); | |
541 } | |
542 | |
543 std::string dicom; | |
544 currentQuery_->SaveToMemoryBuffer(dicom); | |
545 CopyToMemoryBuffer(target, dicom.c_str(), dicom.size()); | |
546 } | |
547 | |
548 bool IsMatch(const void* dicom, | |
549 size_t size) const | |
550 { | |
551 if (matcher_.get() == NULL) | |
552 { | |
553 throw OrthancException(ErrorCode_Plugin); | |
554 } | |
555 | |
556 ParsedDicomFile f(dicom, size); | |
557 return matcher_->Match(f); | |
558 } | |
559 | |
560 void AddAnswer(OrthancPluginWorklistAnswers* answers, | |
561 const void* dicom, | |
562 size_t size) const | |
563 { | |
564 if (matcher_.get() == NULL) | |
565 { | |
566 throw OrthancException(ErrorCode_Plugin); | |
567 } | |
568 | |
569 ParsedDicomFile f(dicom, size); | |
570 std::auto_ptr<ParsedDicomFile> summary(matcher_->Extract(f)); | |
571 reinterpret_cast<DicomFindAnswers*>(answers)->Add(*summary); | |
572 } | |
573 }; | |
574 | |
575 | |
576 class OrthancPlugins::FindHandler : public IFindRequestHandler | |
577 { | |
578 private: | |
579 OrthancPlugins& that_; | |
580 std::auto_ptr<DicomArray> currentQuery_; | |
581 | |
582 void Reset() | |
583 { | |
584 currentQuery_.reset(NULL); | |
585 } | |
586 | |
587 public: | |
588 FindHandler(OrthancPlugins& that) : that_(that) | |
589 { | |
590 Reset(); | |
591 } | |
592 | |
593 virtual void Handle(DicomFindAnswers& answers, | |
594 const DicomMap& input, | |
595 const std::list<DicomTag>& sequencesToReturn, | |
596 const std::string& remoteIp, | |
597 const std::string& remoteAet, | |
598 const std::string& calledAet, | |
599 ModalityManufacturer manufacturer) | |
600 { | |
601 DicomMap tmp; | |
602 tmp.Assign(input); | |
603 | |
604 for (std::list<DicomTag>::const_iterator it = sequencesToReturn.begin(); | |
605 it != sequencesToReturn.end(); ++it) | |
606 { | |
607 if (!input.HasTag(*it)) | |
608 { | |
609 tmp.SetValue(*it, "", false); | |
610 } | |
611 } | |
612 | |
613 { | |
614 boost::mutex::scoped_lock lock(that_.pimpl_->findCallbackMutex_); | |
615 currentQuery_.reset(new DicomArray(tmp)); | |
616 | |
617 if (that_.pimpl_->findCallback_) | |
618 { | |
619 OrthancPluginErrorCode error = that_.pimpl_->findCallback_ | |
620 (reinterpret_cast<OrthancPluginFindAnswers*>(&answers), | |
621 reinterpret_cast<const OrthancPluginFindQuery*>(this), | |
622 remoteAet.c_str(), | |
623 calledAet.c_str()); | |
624 | |
625 if (error != OrthancPluginErrorCode_Success) | |
626 { | |
627 Reset(); | |
628 that_.GetErrorDictionary().LogError(error, true); | |
629 throw OrthancException(static_cast<ErrorCode>(error)); | |
630 } | |
631 } | |
632 | |
633 Reset(); | |
634 } | |
635 } | |
636 | |
637 void Invoke(_OrthancPluginService service, | |
638 const _OrthancPluginFindOperation& operation) const | |
639 { | |
640 if (currentQuery_.get() == NULL) | |
641 { | |
642 throw OrthancException(ErrorCode_Plugin); | |
643 } | |
644 | |
645 switch (service) | |
646 { | |
647 case _OrthancPluginService_GetFindQuerySize: | |
648 *operation.resultUint32 = currentQuery_->GetSize(); | |
649 break; | |
650 | |
651 case _OrthancPluginService_GetFindQueryTag: | |
652 { | |
653 const DicomTag& tag = currentQuery_->GetElement(operation.index).GetTag(); | |
654 *operation.resultGroup = tag.GetGroup(); | |
655 *operation.resultElement = tag.GetElement(); | |
656 break; | |
657 } | |
658 | |
659 case _OrthancPluginService_GetFindQueryTagName: | |
660 { | |
661 const DicomElement& element = currentQuery_->GetElement(operation.index); | |
662 *operation.resultString = CopyString(FromDcmtkBridge::GetTagName(element)); | |
663 break; | |
664 } | |
665 | |
666 case _OrthancPluginService_GetFindQueryValue: | |
667 { | |
668 *operation.resultString = CopyString(currentQuery_->GetElement(operation.index).GetValue().GetContent()); | |
669 break; | |
670 } | |
671 | |
672 default: | |
673 throw OrthancException(ErrorCode_InternalError); | |
674 } | |
675 } | |
676 }; | |
677 | |
678 | |
679 | |
680 class OrthancPlugins::MoveHandler : public IMoveRequestHandler | |
681 { | |
682 private: | |
683 class Driver : public IMoveRequestIterator | |
684 { | |
685 private: | |
686 void* driver_; | |
687 unsigned int count_; | |
688 unsigned int pos_; | |
689 OrthancPluginApplyMove apply_; | |
690 OrthancPluginFreeMove free_; | |
691 | |
692 public: | |
693 Driver(void* driver, | |
694 unsigned int count, | |
695 OrthancPluginApplyMove apply, | |
696 OrthancPluginFreeMove free) : | |
697 driver_(driver), | |
698 count_(count), | |
699 pos_(0), | |
700 apply_(apply), | |
701 free_(free) | |
702 { | |
703 if (driver_ == NULL) | |
704 { | |
705 throw OrthancException(ErrorCode_Plugin); | |
706 } | |
707 } | |
708 | |
709 virtual ~Driver() | |
710 { | |
711 if (driver_ != NULL) | |
712 { | |
713 free_(driver_); | |
714 driver_ = NULL; | |
715 } | |
716 } | |
717 | |
718 virtual unsigned int GetSubOperationCount() const | |
719 { | |
720 return count_; | |
721 } | |
722 | |
723 virtual Status DoNext() | |
724 { | |
725 if (pos_ >= count_) | |
726 { | |
727 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
728 } | |
729 else | |
730 { | |
731 OrthancPluginErrorCode error = apply_(driver_); | |
732 if (error != OrthancPluginErrorCode_Success) | |
733 { | |
734 LOG(ERROR) << "Error while doing C-Move from plugin: " << EnumerationToString(static_cast<ErrorCode>(error)); | |
735 return Status_Failure; | |
736 } | |
737 else | |
738 { | |
739 pos_++; | |
740 return Status_Success; | |
741 } | |
742 } | |
743 } | |
744 }; | |
745 | |
746 | |
747 _OrthancPluginMoveCallback params_; | |
748 | |
749 | |
750 static std::string ReadTag(const DicomMap& input, | |
751 const DicomTag& tag) | |
752 { | |
753 const DicomValue* value = input.TestAndGetValue(tag); | |
754 if (value != NULL && | |
755 !value->IsBinary() && | |
756 !value->IsNull()) | |
757 { | |
758 return value->GetContent(); | |
759 } | |
760 else | |
761 { | |
762 return std::string(); | |
763 } | |
764 } | |
765 | |
766 | |
767 | |
768 public: | |
769 MoveHandler(OrthancPlugins& that) | |
770 { | |
771 boost::recursive_mutex::scoped_lock lock(that.pimpl_->invokeServiceMutex_); | |
772 params_ = that.pimpl_->moveCallbacks_; | |
773 | |
774 if (params_.callback == NULL || | |
775 params_.getMoveSize == NULL || | |
776 params_.applyMove == NULL || | |
777 params_.freeMove == NULL) | |
778 { | |
779 throw OrthancException(ErrorCode_Plugin); | |
780 } | |
781 } | |
782 | |
783 virtual IMoveRequestIterator* Handle(const std::string& targetAet, | |
784 const DicomMap& input, | |
785 const std::string& originatorIp, | |
786 const std::string& originatorAet, | |
787 const std::string& calledAet, | |
788 uint16_t originatorId) | |
789 { | |
790 std::string levelString = ReadTag(input, DICOM_TAG_QUERY_RETRIEVE_LEVEL); | |
791 std::string patientId = ReadTag(input, DICOM_TAG_PATIENT_ID); | |
792 std::string accessionNumber = ReadTag(input, DICOM_TAG_ACCESSION_NUMBER); | |
793 std::string studyInstanceUid = ReadTag(input, DICOM_TAG_STUDY_INSTANCE_UID); | |
794 std::string seriesInstanceUid = ReadTag(input, DICOM_TAG_SERIES_INSTANCE_UID); | |
795 std::string sopInstanceUid = ReadTag(input, DICOM_TAG_SOP_INSTANCE_UID); | |
796 | |
797 OrthancPluginResourceType level = OrthancPluginResourceType_None; | |
798 | |
799 if (!levelString.empty()) | |
800 { | |
801 level = Plugins::Convert(StringToResourceType(levelString.c_str())); | |
802 } | |
803 | |
804 void* driver = params_.callback(level, | |
805 patientId.empty() ? NULL : patientId.c_str(), | |
806 accessionNumber.empty() ? NULL : accessionNumber.c_str(), | |
807 studyInstanceUid.empty() ? NULL : studyInstanceUid.c_str(), | |
808 seriesInstanceUid.empty() ? NULL : seriesInstanceUid.c_str(), | |
809 sopInstanceUid.empty() ? NULL : sopInstanceUid.c_str(), | |
810 originatorAet.c_str(), | |
811 calledAet.c_str(), | |
812 targetAet.c_str(), | |
813 originatorId); | |
814 | |
815 if (driver == NULL) | |
816 { | |
817 LOG(ERROR) << "Plugin cannot create a driver for an incoming C-MOVE request"; | |
818 throw OrthancException(ErrorCode_Plugin); | |
819 } | |
820 | |
821 unsigned int size = params_.getMoveSize(driver); | |
822 | |
823 return new Driver(driver, size, params_.applyMove, params_.freeMove); | |
824 } | |
825 }; | |
826 | |
287 | 827 |
288 | 828 |
289 OrthancPlugins::OrthancPlugins() | 829 OrthancPlugins::OrthancPlugins() |
290 { | 830 { |
831 /* Sanity check of the compiler */ | |
291 if (sizeof(int32_t) != sizeof(OrthancPluginErrorCode) || | 832 if (sizeof(int32_t) != sizeof(OrthancPluginErrorCode) || |
292 sizeof(int32_t) != sizeof(OrthancPluginHttpMethod) || | 833 sizeof(int32_t) != sizeof(OrthancPluginHttpMethod) || |
293 sizeof(int32_t) != sizeof(_OrthancPluginService) || | 834 sizeof(int32_t) != sizeof(_OrthancPluginService) || |
294 sizeof(int32_t) != sizeof(_OrthancPluginProperty) || | 835 sizeof(int32_t) != sizeof(_OrthancPluginProperty) || |
295 sizeof(int32_t) != sizeof(OrthancPluginPixelFormat) || | 836 sizeof(int32_t) != sizeof(OrthancPluginPixelFormat) || |
299 sizeof(int32_t) != sizeof(OrthancPluginImageFormat) || | 840 sizeof(int32_t) != sizeof(OrthancPluginImageFormat) || |
300 sizeof(int32_t) != sizeof(OrthancPluginCompressionType) || | 841 sizeof(int32_t) != sizeof(OrthancPluginCompressionType) || |
301 sizeof(int32_t) != sizeof(OrthancPluginValueRepresentation) || | 842 sizeof(int32_t) != sizeof(OrthancPluginValueRepresentation) || |
302 sizeof(int32_t) != sizeof(OrthancPluginDicomToJsonFlags) || | 843 sizeof(int32_t) != sizeof(OrthancPluginDicomToJsonFlags) || |
303 sizeof(int32_t) != sizeof(OrthancPluginDicomToJsonFormat) || | 844 sizeof(int32_t) != sizeof(OrthancPluginDicomToJsonFormat) || |
845 sizeof(int32_t) != sizeof(OrthancPluginCreateDicomFlags) || | |
304 sizeof(int32_t) != sizeof(_OrthancPluginDatabaseAnswerType) || | 846 sizeof(int32_t) != sizeof(_OrthancPluginDatabaseAnswerType) || |
305 sizeof(int32_t) != sizeof(OrthancPluginIdentifierConstraint) || | 847 sizeof(int32_t) != sizeof(OrthancPluginIdentifierConstraint) || |
848 sizeof(int32_t) != sizeof(OrthancPluginInstanceOrigin) || | |
849 sizeof(int32_t) != sizeof(OrthancPluginJobStepStatus) || | |
306 static_cast<int>(OrthancPluginDicomToJsonFlags_IncludeBinary) != static_cast<int>(DicomToJsonFlags_IncludeBinary) || | 850 static_cast<int>(OrthancPluginDicomToJsonFlags_IncludeBinary) != static_cast<int>(DicomToJsonFlags_IncludeBinary) || |
307 static_cast<int>(OrthancPluginDicomToJsonFlags_IncludePrivateTags) != static_cast<int>(DicomToJsonFlags_IncludePrivateTags) || | 851 static_cast<int>(OrthancPluginDicomToJsonFlags_IncludePrivateTags) != static_cast<int>(DicomToJsonFlags_IncludePrivateTags) || |
308 static_cast<int>(OrthancPluginDicomToJsonFlags_IncludeUnknownTags) != static_cast<int>(DicomToJsonFlags_IncludeUnknownTags) || | 852 static_cast<int>(OrthancPluginDicomToJsonFlags_IncludeUnknownTags) != static_cast<int>(DicomToJsonFlags_IncludeUnknownTags) || |
309 static_cast<int>(OrthancPluginDicomToJsonFlags_IncludePixelData) != static_cast<int>(DicomToJsonFlags_IncludePixelData) || | 853 static_cast<int>(OrthancPluginDicomToJsonFlags_IncludePixelData) != static_cast<int>(DicomToJsonFlags_IncludePixelData) || |
310 static_cast<int>(OrthancPluginDicomToJsonFlags_ConvertBinaryToNull) != static_cast<int>(DicomToJsonFlags_ConvertBinaryToNull) || | 854 static_cast<int>(OrthancPluginDicomToJsonFlags_ConvertBinaryToNull) != static_cast<int>(DicomToJsonFlags_ConvertBinaryToNull) || |
311 static_cast<int>(OrthancPluginDicomToJsonFlags_ConvertBinaryToAscii) != static_cast<int>(DicomToJsonFlags_ConvertBinaryToAscii)) | 855 static_cast<int>(OrthancPluginDicomToJsonFlags_ConvertBinaryToAscii) != static_cast<int>(DicomToJsonFlags_ConvertBinaryToAscii) || |
312 { | 856 static_cast<int>(OrthancPluginCreateDicomFlags_DecodeDataUriScheme) != static_cast<int>(DicomFromJsonFlags_DecodeDataUriScheme) || |
313 /* Sanity check of the compiler */ | 857 static_cast<int>(OrthancPluginCreateDicomFlags_GenerateIdentifiers) != static_cast<int>(DicomFromJsonFlags_GenerateIdentifiers)) |
858 | |
859 { | |
314 throw OrthancException(ErrorCode_Plugin); | 860 throw OrthancException(ErrorCode_Plugin); |
315 } | 861 } |
316 | 862 |
317 pimpl_.reset(new PImpl()); | 863 pimpl_.reset(new PImpl()); |
318 pimpl_->manager_.RegisterServiceProvider(*this); | 864 pimpl_->manager_.RegisterServiceProvider(*this); |
319 } | 865 } |
320 | 866 |
321 | 867 |
322 void OrthancPlugins::SetServerContext(ServerContext& context) | 868 void OrthancPlugins::SetServerContext(ServerContext& context) |
323 { | 869 { |
324 pimpl_->context_ = &context; | 870 pimpl_->SetServerContext(&context); |
325 } | 871 } |
326 | 872 |
873 | |
874 void OrthancPlugins::ResetServerContext() | |
875 { | |
876 pimpl_->SetServerContext(NULL); | |
877 } | |
327 | 878 |
328 | 879 |
329 OrthancPlugins::~OrthancPlugins() | 880 OrthancPlugins::~OrthancPlugins() |
330 { | 881 { |
331 for (PImpl::RestCallbacks::iterator it = pimpl_->restCallbacks_.begin(); | 882 for (PImpl::RestCallbacks::iterator it = pimpl_->restCallbacks_.begin(); |
483 { | 1034 { |
484 return true; | 1035 return true; |
485 } | 1036 } |
486 else | 1037 else |
487 { | 1038 { |
488 GetErrorDictionary().LogError(error, true); | 1039 GetErrorDictionary().LogError(error, false); |
489 throw OrthancException(static_cast<ErrorCode>(error)); | 1040 throw OrthancException(static_cast<ErrorCode>(error)); |
490 } | 1041 } |
491 } | 1042 } |
492 | 1043 |
493 | 1044 |
544 change.GetPublicId().c_str()); | 1095 change.GetPublicId().c_str()); |
545 } | 1096 } |
546 | 1097 |
547 | 1098 |
548 | 1099 |
549 static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, | |
550 const void* data, | |
551 size_t size) | |
552 { | |
553 target.size = size; | |
554 | |
555 if (size == 0) | |
556 { | |
557 target.data = NULL; | |
558 } | |
559 else | |
560 { | |
561 target.data = malloc(size); | |
562 if (target.data != NULL) | |
563 { | |
564 memcpy(target.data, data, size); | |
565 } | |
566 else | |
567 { | |
568 throw OrthancException(ErrorCode_NotEnoughMemory); | |
569 } | |
570 } | |
571 } | |
572 | |
573 | |
574 static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, | |
575 const std::string& str) | |
576 { | |
577 if (str.size() == 0) | |
578 { | |
579 target.size = 0; | |
580 target.data = NULL; | |
581 } | |
582 else | |
583 { | |
584 CopyToMemoryBuffer(target, str.c_str(), str.size()); | |
585 } | |
586 } | |
587 | |
588 | |
589 void OrthancPlugins::RegisterRestCallback(const void* parameters, | 1100 void OrthancPlugins::RegisterRestCallback(const void* parameters, |
590 bool lock) | 1101 bool lock) |
591 { | 1102 { |
592 const _OrthancPluginRestCallback& p = | 1103 const _OrthancPluginRestCallback& p = |
593 *reinterpret_cast<const _OrthancPluginRestCallback*>(parameters); | 1104 *reinterpret_cast<const _OrthancPluginRestCallback*>(parameters); |
594 | 1105 |
595 LOG(INFO) << "Plugin has registered a REST callback " | 1106 LOG(INFO) << "Plugin has registered a REST callback " |
596 << (lock ? "with" : "witout") | 1107 << (lock ? "with" : "without") |
597 << " mutual exclusion on: " | 1108 << " mutual exclusion on: " |
598 << p.pathRegularExpression; | 1109 << p.pathRegularExpression; |
599 | 1110 |
600 pimpl_->restCallbacks_.push_back(new PImpl::RestCallback(p.pathRegularExpression, p.callback, lock)); | 1111 pimpl_->restCallbacks_.push_back(new PImpl::RestCallback(p.pathRegularExpression, p.callback, lock)); |
601 } | 1112 } |
619 | 1130 |
620 LOG(INFO) << "Plugin has registered an OnChange callback"; | 1131 LOG(INFO) << "Plugin has registered an OnChange callback"; |
621 pimpl_->onChangeCallbacks_.push_back(p.callback); | 1132 pimpl_->onChangeCallbacks_.push_back(p.callback); |
622 } | 1133 } |
623 | 1134 |
1135 | |
1136 void OrthancPlugins::RegisterWorklistCallback(const void* parameters) | |
1137 { | |
1138 const _OrthancPluginWorklistCallback& p = | |
1139 *reinterpret_cast<const _OrthancPluginWorklistCallback*>(parameters); | |
1140 | |
1141 boost::mutex::scoped_lock lock(pimpl_->worklistCallbackMutex_); | |
1142 | |
1143 if (pimpl_->worklistCallback_ != NULL) | |
1144 { | |
1145 LOG(ERROR) << "Can only register one plugin to handle modality worklists"; | |
1146 throw OrthancException(ErrorCode_Plugin); | |
1147 } | |
1148 else | |
1149 { | |
1150 LOG(INFO) << "Plugin has registered a callback to handle modality worklists"; | |
1151 pimpl_->worklistCallback_ = p.callback; | |
1152 } | |
1153 } | |
1154 | |
1155 | |
1156 void OrthancPlugins::RegisterFindCallback(const void* parameters) | |
1157 { | |
1158 const _OrthancPluginFindCallback& p = | |
1159 *reinterpret_cast<const _OrthancPluginFindCallback*>(parameters); | |
1160 | |
1161 boost::mutex::scoped_lock lock(pimpl_->findCallbackMutex_); | |
1162 | |
1163 if (pimpl_->findCallback_ != NULL) | |
1164 { | |
1165 LOG(ERROR) << "Can only register one plugin to handle C-FIND requests"; | |
1166 throw OrthancException(ErrorCode_Plugin); | |
1167 } | |
1168 else | |
1169 { | |
1170 LOG(INFO) << "Plugin has registered a callback to handle C-FIND requests"; | |
1171 pimpl_->findCallback_ = p.callback; | |
1172 } | |
1173 } | |
1174 | |
1175 | |
1176 void OrthancPlugins::RegisterMoveCallback(const void* parameters) | |
1177 { | |
1178 // invokeServiceMutex_ is assumed to be locked | |
1179 | |
1180 const _OrthancPluginMoveCallback& p = | |
1181 *reinterpret_cast<const _OrthancPluginMoveCallback*>(parameters); | |
1182 | |
1183 if (pimpl_->moveCallbacks_.callback != NULL) | |
1184 { | |
1185 LOG(ERROR) << "Can only register one plugin to handle C-MOVE requests"; | |
1186 throw OrthancException(ErrorCode_Plugin); | |
1187 } | |
1188 else | |
1189 { | |
1190 LOG(INFO) << "Plugin has registered a callback to handle C-MOVE requests"; | |
1191 pimpl_->moveCallbacks_ = p; | |
1192 } | |
1193 } | |
1194 | |
1195 | |
1196 void OrthancPlugins::RegisterDecodeImageCallback(const void* parameters) | |
1197 { | |
1198 const _OrthancPluginDecodeImageCallback& p = | |
1199 *reinterpret_cast<const _OrthancPluginDecodeImageCallback*>(parameters); | |
1200 | |
1201 boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); | |
1202 | |
1203 pimpl_->decodeImageCallbacks_.push_back(p.callback); | |
1204 LOG(INFO) << "Plugin has registered a callback to decode DICOM images (" | |
1205 << pimpl_->decodeImageCallbacks_.size() << " decoder(s) now active)"; | |
1206 } | |
1207 | |
1208 | |
1209 void OrthancPlugins::RegisterJobsUnserializer(const void* parameters) | |
1210 { | |
1211 const _OrthancPluginJobsUnserializer& p = | |
1212 *reinterpret_cast<const _OrthancPluginJobsUnserializer*>(parameters); | |
1213 | |
1214 boost::mutex::scoped_lock lock(pimpl_->jobsUnserializersMutex_); | |
1215 | |
1216 pimpl_->jobsUnserializers_.push_back(p.unserializer); | |
1217 LOG(INFO) << "Plugin has registered a callback to unserialize jobs (" | |
1218 << pimpl_->jobsUnserializers_.size() << " unserializer(s) now active)"; | |
1219 } | |
1220 | |
1221 | |
1222 void OrthancPlugins::RegisterIncomingHttpRequestFilter(const void* parameters) | |
1223 { | |
1224 const _OrthancPluginIncomingHttpRequestFilter& p = | |
1225 *reinterpret_cast<const _OrthancPluginIncomingHttpRequestFilter*>(parameters); | |
1226 | |
1227 LOG(INFO) << "Plugin has registered a callback to filter incoming HTTP requests"; | |
1228 pimpl_->incomingHttpRequestFilters_.push_back(p.callback); | |
1229 } | |
1230 | |
1231 | |
1232 void OrthancPlugins::RegisterIncomingHttpRequestFilter2(const void* parameters) | |
1233 { | |
1234 const _OrthancPluginIncomingHttpRequestFilter2& p = | |
1235 *reinterpret_cast<const _OrthancPluginIncomingHttpRequestFilter2*>(parameters); | |
1236 | |
1237 LOG(INFO) << "Plugin has registered a callback to filter incoming HTTP requests"; | |
1238 pimpl_->incomingHttpRequestFilters2_.push_back(p.callback); | |
1239 } | |
624 | 1240 |
625 | 1241 |
626 void OrthancPlugins::AnswerBuffer(const void* parameters) | 1242 void OrthancPlugins::AnswerBuffer(const void* parameters) |
627 { | 1243 { |
628 const _OrthancPluginAnswerBuffer& p = | 1244 const _OrthancPluginAnswerBuffer& p = |
770 | 1386 |
771 translatedOutput->Answer(compressed); | 1387 translatedOutput->Answer(compressed); |
772 } | 1388 } |
773 | 1389 |
774 | 1390 |
775 void OrthancPlugins::CheckContextAvailable() | |
776 { | |
777 if (!pimpl_->context_) | |
778 { | |
779 throw OrthancException(ErrorCode_DatabaseNotInitialized); | |
780 } | |
781 } | |
782 | |
783 | |
784 void OrthancPlugins::GetDicomForInstance(const void* parameters) | 1391 void OrthancPlugins::GetDicomForInstance(const void* parameters) |
785 { | 1392 { |
786 const _OrthancPluginGetDicomForInstance& p = | 1393 const _OrthancPluginGetDicomForInstance& p = |
787 *reinterpret_cast<const _OrthancPluginGetDicomForInstance*>(parameters); | 1394 *reinterpret_cast<const _OrthancPluginGetDicomForInstance*>(parameters); |
788 | 1395 |
789 std::string dicom; | 1396 std::string dicom; |
790 | 1397 |
791 CheckContextAvailable(); | 1398 { |
792 pimpl_->context_->ReadFile(dicom, p.instanceId, FileContentType_Dicom); | 1399 PImpl::ServerContextLock lock(*pimpl_); |
1400 lock.GetContext().ReadDicom(dicom, p.instanceId); | |
1401 } | |
793 | 1402 |
794 CopyToMemoryBuffer(*p.target, dicom); | 1403 CopyToMemoryBuffer(*p.target, dicom); |
795 } | 1404 } |
796 | 1405 |
797 | 1406 |
802 *reinterpret_cast<const _OrthancPluginRestApiGet*>(parameters); | 1411 *reinterpret_cast<const _OrthancPluginRestApiGet*>(parameters); |
803 | 1412 |
804 LOG(INFO) << "Plugin making REST GET call on URI " << p.uri | 1413 LOG(INFO) << "Plugin making REST GET call on URI " << p.uri |
805 << (afterPlugins ? " (after plugins)" : " (built-in API)"); | 1414 << (afterPlugins ? " (after plugins)" : " (built-in API)"); |
806 | 1415 |
807 CheckContextAvailable(); | 1416 IHttpHandler* handler; |
808 IHttpHandler& handler = pimpl_->context_->GetHttpHandler().RestrictToOrthancRestApi(!afterPlugins); | 1417 |
1418 { | |
1419 PImpl::ServerContextLock lock(*pimpl_); | |
1420 handler = &lock.GetContext().GetHttpHandler().RestrictToOrthancRestApi(!afterPlugins); | |
1421 } | |
809 | 1422 |
810 std::string result; | 1423 std::string result; |
811 if (HttpToolbox::SimpleGet(result, handler, RequestOrigin_Plugins, p.uri)) | 1424 if (HttpToolbox::SimpleGet(result, *handler, RequestOrigin_Plugins, p.uri)) |
812 { | 1425 { |
813 CopyToMemoryBuffer(*p.target, result); | 1426 CopyToMemoryBuffer(*p.target, result); |
814 } | 1427 } |
815 else | 1428 else |
816 { | 1429 { |
817 throw OrthancException(ErrorCode_BadRequest); | 1430 throw OrthancException(ErrorCode_UnknownResource); |
1431 } | |
1432 } | |
1433 | |
1434 | |
1435 void OrthancPlugins::RestApiGet2(const void* parameters) | |
1436 { | |
1437 const _OrthancPluginRestApiGet2& p = | |
1438 *reinterpret_cast<const _OrthancPluginRestApiGet2*>(parameters); | |
1439 | |
1440 LOG(INFO) << "Plugin making REST GET call on URI " << p.uri | |
1441 << (p.afterPlugins ? " (after plugins)" : " (built-in API)"); | |
1442 | |
1443 IHttpHandler::Arguments headers; | |
1444 | |
1445 for (uint32_t i = 0; i < p.headersCount; i++) | |
1446 { | |
1447 std::string name(p.headersKeys[i]); | |
1448 std::transform(name.begin(), name.end(), name.begin(), ::tolower); | |
1449 headers[name] = p.headersValues[i]; | |
1450 } | |
1451 | |
1452 IHttpHandler* handler; | |
1453 | |
1454 { | |
1455 PImpl::ServerContextLock lock(*pimpl_); | |
1456 handler = &lock.GetContext().GetHttpHandler().RestrictToOrthancRestApi(!p.afterPlugins); | |
1457 } | |
1458 | |
1459 std::string result; | |
1460 if (HttpToolbox::SimpleGet(result, *handler, RequestOrigin_Plugins, p.uri, headers)) | |
1461 { | |
1462 CopyToMemoryBuffer(*p.target, result); | |
1463 } | |
1464 else | |
1465 { | |
1466 throw OrthancException(ErrorCode_UnknownResource); | |
818 } | 1467 } |
819 } | 1468 } |
820 | 1469 |
821 | 1470 |
822 void OrthancPlugins::RestApiPostPut(bool isPost, | 1471 void OrthancPlugins::RestApiPostPut(bool isPost, |
827 *reinterpret_cast<const _OrthancPluginRestApiPostPut*>(parameters); | 1476 *reinterpret_cast<const _OrthancPluginRestApiPostPut*>(parameters); |
828 | 1477 |
829 LOG(INFO) << "Plugin making REST " << EnumerationToString(isPost ? HttpMethod_Post : HttpMethod_Put) | 1478 LOG(INFO) << "Plugin making REST " << EnumerationToString(isPost ? HttpMethod_Post : HttpMethod_Put) |
830 << " call on URI " << p.uri << (afterPlugins ? " (after plugins)" : " (built-in API)"); | 1479 << " call on URI " << p.uri << (afterPlugins ? " (after plugins)" : " (built-in API)"); |
831 | 1480 |
832 CheckContextAvailable(); | 1481 IHttpHandler* handler; |
833 IHttpHandler& handler = pimpl_->context_->GetHttpHandler().RestrictToOrthancRestApi(!afterPlugins); | 1482 |
834 | 1483 { |
1484 PImpl::ServerContextLock lock(*pimpl_); | |
1485 handler = &lock.GetContext().GetHttpHandler().RestrictToOrthancRestApi(!afterPlugins); | |
1486 } | |
1487 | |
835 std::string result; | 1488 std::string result; |
836 if (isPost ? | 1489 if (isPost ? |
837 HttpToolbox::SimplePost(result, handler, RequestOrigin_Plugins, p.uri, p.body, p.bodySize) : | 1490 HttpToolbox::SimplePost(result, *handler, RequestOrigin_Plugins, p.uri, p.body, p.bodySize) : |
838 HttpToolbox::SimplePut (result, handler, RequestOrigin_Plugins, p.uri, p.body, p.bodySize)) | 1491 HttpToolbox::SimplePut (result, *handler, RequestOrigin_Plugins, p.uri, p.body, p.bodySize)) |
839 { | 1492 { |
840 CopyToMemoryBuffer(*p.target, result); | 1493 CopyToMemoryBuffer(*p.target, result); |
841 } | 1494 } |
842 else | 1495 else |
843 { | 1496 { |
844 throw OrthancException(ErrorCode_BadRequest); | 1497 throw OrthancException(ErrorCode_UnknownResource); |
845 } | 1498 } |
846 } | 1499 } |
847 | 1500 |
848 | 1501 |
849 void OrthancPlugins::RestApiDelete(const void* parameters, | 1502 void OrthancPlugins::RestApiDelete(const void* parameters, |
851 { | 1504 { |
852 const char* uri = reinterpret_cast<const char*>(parameters); | 1505 const char* uri = reinterpret_cast<const char*>(parameters); |
853 LOG(INFO) << "Plugin making REST DELETE call on URI " << uri | 1506 LOG(INFO) << "Plugin making REST DELETE call on URI " << uri |
854 << (afterPlugins ? " (after plugins)" : " (built-in API)"); | 1507 << (afterPlugins ? " (after plugins)" : " (built-in API)"); |
855 | 1508 |
856 CheckContextAvailable(); | 1509 IHttpHandler* handler; |
857 IHttpHandler& handler = pimpl_->context_->GetHttpHandler().RestrictToOrthancRestApi(!afterPlugins); | 1510 |
858 | 1511 { |
859 if (!HttpToolbox::SimpleDelete(handler, RequestOrigin_Plugins, uri)) | 1512 PImpl::ServerContextLock lock(*pimpl_); |
860 { | 1513 handler = &lock.GetContext().GetHttpHandler().RestrictToOrthancRestApi(!afterPlugins); |
861 throw OrthancException(ErrorCode_BadRequest); | 1514 } |
1515 | |
1516 if (!HttpToolbox::SimpleDelete(*handler, RequestOrigin_Plugins, uri)) | |
1517 { | |
1518 throw OrthancException(ErrorCode_UnknownResource); | |
862 } | 1519 } |
863 } | 1520 } |
864 | 1521 |
865 | 1522 |
866 void OrthancPlugins::LookupResource(_OrthancPluginService service, | 1523 void OrthancPlugins::LookupResource(_OrthancPluginService service, |
907 | 1564 |
908 default: | 1565 default: |
909 throw OrthancException(ErrorCode_InternalError); | 1566 throw OrthancException(ErrorCode_InternalError); |
910 } | 1567 } |
911 | 1568 |
912 CheckContextAvailable(); | |
913 | |
914 std::list<std::string> result; | 1569 std::list<std::string> result; |
915 pimpl_->context_->GetIndex().LookupIdentifierExact(result, level, tag, p.argument); | 1570 |
1571 { | |
1572 PImpl::ServerContextLock lock(*pimpl_); | |
1573 lock.GetContext().GetIndex().LookupIdentifierExact(result, level, tag, p.argument); | |
1574 } | |
916 | 1575 |
917 if (result.size() == 1) | 1576 if (result.size() == 1) |
918 { | 1577 { |
919 *p.result = CopyString(result.front()); | 1578 *p.result = CopyString(result.front()); |
920 } | 1579 } |
989 *reinterpret_cast<DicomInstanceToStore*>(p.instance); | 1648 *reinterpret_cast<DicomInstanceToStore*>(p.instance); |
990 | 1649 |
991 switch (service) | 1650 switch (service) |
992 { | 1651 { |
993 case _OrthancPluginService_GetInstanceRemoteAet: | 1652 case _OrthancPluginService_GetInstanceRemoteAet: |
994 *p.resultString = instance.GetRemoteAet(); | 1653 *p.resultString = instance.GetOrigin().GetRemoteAetC(); |
995 return; | 1654 return; |
996 | 1655 |
997 case _OrthancPluginService_GetInstanceSize: | 1656 case _OrthancPluginService_GetInstanceSize: |
998 *p.resultInt64 = instance.GetBufferSize(); | 1657 *p.resultInt64 = instance.GetBufferSize(); |
999 return; | 1658 return; |
1021 s = writer.write(instance.GetJson()); | 1680 s = writer.write(instance.GetJson()); |
1022 } | 1681 } |
1023 else | 1682 else |
1024 { | 1683 { |
1025 Json::Value simplified; | 1684 Json::Value simplified; |
1026 Toolbox::SimplifyTags(simplified, instance.GetJson()); | 1685 ServerToolbox::SimplifyTags(simplified, instance.GetJson(), DicomToJsonFormat_Human); |
1027 s = writer.write(simplified); | 1686 s = writer.write(simplified); |
1028 } | 1687 } |
1029 | 1688 |
1030 *p.resultStringToFree = CopyString(s); | 1689 *p.resultStringToFree = CopyString(s); |
1031 return; | 1690 return; |
1032 } | 1691 } |
1692 | |
1693 case _OrthancPluginService_GetInstanceOrigin: // New in Orthanc 0.9.5 | |
1694 *p.resultOrigin = Plugins::Convert(instance.GetOrigin().GetRequestOrigin()); | |
1695 return; | |
1033 | 1696 |
1034 default: | 1697 default: |
1035 throw OrthancException(ErrorCode_InternalError); | 1698 throw OrthancException(ErrorCode_InternalError); |
1036 } | 1699 } |
1037 } | 1700 } |
1093 | 1756 |
1094 CopyToMemoryBuffer(*p.target, result); | 1757 CopyToMemoryBuffer(*p.target, result); |
1095 } | 1758 } |
1096 | 1759 |
1097 | 1760 |
1761 static OrthancPluginImage* ReturnImage(std::auto_ptr<ImageAccessor>& image) | |
1762 { | |
1763 // Images returned to plugins are assumed to be writeable. If the | |
1764 // input image is read-only, we return a copy so that it can be modified. | |
1765 | |
1766 if (image->IsReadOnly()) | |
1767 { | |
1768 std::auto_ptr<Image> copy(new Image(image->GetFormat(), image->GetWidth(), image->GetHeight(), false)); | |
1769 ImageProcessing::Copy(*copy, *image); | |
1770 image.reset(NULL); | |
1771 return reinterpret_cast<OrthancPluginImage*>(copy.release()); | |
1772 } | |
1773 else | |
1774 { | |
1775 return reinterpret_cast<OrthancPluginImage*>(image.release()); | |
1776 } | |
1777 } | |
1778 | |
1779 | |
1098 void OrthancPlugins::UncompressImage(const void* parameters) | 1780 void OrthancPlugins::UncompressImage(const void* parameters) |
1099 { | 1781 { |
1100 const _OrthancPluginUncompressImage& p = *reinterpret_cast<const _OrthancPluginUncompressImage*>(parameters); | 1782 const _OrthancPluginUncompressImage& p = *reinterpret_cast<const _OrthancPluginUncompressImage*>(parameters); |
1101 | 1783 |
1102 std::auto_ptr<ImageAccessor> image; | 1784 std::auto_ptr<ImageAccessor> image; |
1115 image.reset(new JpegReader); | 1797 image.reset(new JpegReader); |
1116 reinterpret_cast<JpegReader&>(*image).ReadFromMemory(p.data, p.size); | 1798 reinterpret_cast<JpegReader&>(*image).ReadFromMemory(p.data, p.size); |
1117 break; | 1799 break; |
1118 } | 1800 } |
1119 | 1801 |
1802 case OrthancPluginImageFormat_Dicom: | |
1803 { | |
1804 image.reset(Decode(p.data, p.size, 0)); | |
1805 break; | |
1806 } | |
1807 | |
1120 default: | 1808 default: |
1121 throw OrthancException(ErrorCode_ParameterOutOfRange); | 1809 throw OrthancException(ErrorCode_ParameterOutOfRange); |
1122 } | 1810 } |
1123 | 1811 |
1124 *(p.target) = reinterpret_cast<OrthancPluginImage*>(image.release()); | 1812 *(p.target) = ReturnImage(image); |
1125 } | 1813 } |
1126 | 1814 |
1127 | 1815 |
1128 void OrthancPlugins::CompressImage(const void* parameters) | 1816 void OrthancPlugins::CompressImage(const void* parameters) |
1129 { | 1817 { |
1130 const _OrthancPluginCompressImage& p = *reinterpret_cast<const _OrthancPluginCompressImage*>(parameters); | 1818 const _OrthancPluginCompressImage& p = *reinterpret_cast<const _OrthancPluginCompressImage*>(parameters); |
1131 | 1819 |
1132 std::string compressed; | 1820 std::string compressed; |
1133 | 1821 |
1822 ImageAccessor accessor; | |
1823 accessor.AssignReadOnly(Plugins::Convert(p.pixelFormat), p.width, p.height, p.pitch, p.buffer); | |
1824 | |
1134 switch (p.imageFormat) | 1825 switch (p.imageFormat) |
1135 { | 1826 { |
1136 case OrthancPluginImageFormat_Png: | 1827 case OrthancPluginImageFormat_Png: |
1137 { | 1828 { |
1138 PngWriter writer; | 1829 PngWriter writer; |
1139 writer.WriteToMemory(compressed, p.width, p.height, p.pitch, Plugins::Convert(p.pixelFormat), p.buffer); | 1830 writer.WriteToMemory(compressed, accessor); |
1140 break; | 1831 break; |
1141 } | 1832 } |
1142 | 1833 |
1143 case OrthancPluginImageFormat_Jpeg: | 1834 case OrthancPluginImageFormat_Jpeg: |
1144 { | 1835 { |
1145 JpegWriter writer; | 1836 JpegWriter writer; |
1146 writer.SetQuality(p.quality); | 1837 writer.SetQuality(p.quality); |
1147 writer.WriteToMemory(compressed, p.width, p.height, p.pitch, Plugins::Convert(p.pixelFormat), p.buffer); | 1838 writer.WriteToMemory(compressed, accessor); |
1148 break; | 1839 break; |
1149 } | 1840 } |
1150 | 1841 |
1151 default: | 1842 default: |
1152 throw OrthancException(ErrorCode_ParameterOutOfRange); | 1843 throw OrthancException(ErrorCode_ParameterOutOfRange); |
1201 CopyToMemoryBuffer(*p.target, s); | 1892 CopyToMemoryBuffer(*p.target, s); |
1202 } | 1893 } |
1203 } | 1894 } |
1204 | 1895 |
1205 | 1896 |
1897 void OrthancPlugins::CallHttpClient2(const void* parameters) | |
1898 { | |
1899 const _OrthancPluginCallHttpClient2& p = *reinterpret_cast<const _OrthancPluginCallHttpClient2*>(parameters); | |
1900 | |
1901 HttpClient client; | |
1902 client.SetUrl(p.url); | |
1903 client.SetConvertHeadersToLowerCase(false); | |
1904 | |
1905 if (p.timeout != 0) | |
1906 { | |
1907 client.SetTimeout(p.timeout); | |
1908 } | |
1909 | |
1910 if (p.username != NULL && | |
1911 p.password != NULL) | |
1912 { | |
1913 client.SetCredentials(p.username, p.password); | |
1914 } | |
1915 | |
1916 if (p.certificateFile != NULL) | |
1917 { | |
1918 std::string certificate(p.certificateFile); | |
1919 std::string key, password; | |
1920 | |
1921 if (p.certificateKeyFile) | |
1922 { | |
1923 key.assign(p.certificateKeyFile); | |
1924 } | |
1925 | |
1926 if (p.certificateKeyPassword) | |
1927 { | |
1928 password.assign(p.certificateKeyPassword); | |
1929 } | |
1930 | |
1931 client.SetClientCertificate(certificate, key, password); | |
1932 } | |
1933 | |
1934 client.SetPkcs11Enabled(p.pkcs11 ? true : false); | |
1935 | |
1936 for (uint32_t i = 0; i < p.headersCount; i++) | |
1937 { | |
1938 if (p.headersKeys[i] == NULL || | |
1939 p.headersValues[i] == NULL) | |
1940 { | |
1941 throw OrthancException(ErrorCode_NullPointer); | |
1942 } | |
1943 | |
1944 client.AddHeader(p.headersKeys[i], p.headersValues[i]); | |
1945 } | |
1946 | |
1947 switch (p.method) | |
1948 { | |
1949 case OrthancPluginHttpMethod_Get: | |
1950 client.SetMethod(HttpMethod_Get); | |
1951 break; | |
1952 | |
1953 case OrthancPluginHttpMethod_Post: | |
1954 client.SetMethod(HttpMethod_Post); | |
1955 client.GetBody().assign(p.body, p.bodySize); | |
1956 break; | |
1957 | |
1958 case OrthancPluginHttpMethod_Put: | |
1959 client.SetMethod(HttpMethod_Put); | |
1960 client.GetBody().assign(p.body, p.bodySize); | |
1961 break; | |
1962 | |
1963 case OrthancPluginHttpMethod_Delete: | |
1964 client.SetMethod(HttpMethod_Delete); | |
1965 break; | |
1966 | |
1967 default: | |
1968 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
1969 } | |
1970 | |
1971 std::string body; | |
1972 HttpClient::HttpHeaders headers; | |
1973 | |
1974 bool success = client.Apply(body, headers); | |
1975 | |
1976 // The HTTP request has succeeded | |
1977 *p.httpStatus = static_cast<uint16_t>(client.GetLastStatus()); | |
1978 | |
1979 if (!success) | |
1980 { | |
1981 HttpClient::ThrowException(client.GetLastStatus()); | |
1982 } | |
1983 | |
1984 // Copy the HTTP headers of the answer, if the plugin requested them | |
1985 if (p.answerHeaders != NULL) | |
1986 { | |
1987 Json::Value json = Json::objectValue; | |
1988 | |
1989 for (HttpClient::HttpHeaders::const_iterator | |
1990 it = headers.begin(); it != headers.end(); ++it) | |
1991 { | |
1992 json[it->first] = it->second; | |
1993 } | |
1994 | |
1995 std::string s = json.toStyledString(); | |
1996 CopyToMemoryBuffer(*p.answerHeaders, s); | |
1997 } | |
1998 | |
1999 // Copy the body of the answer if it makes sense | |
2000 if (p.method != OrthancPluginHttpMethod_Delete) | |
2001 { | |
2002 CopyToMemoryBuffer(*p.answerBody, body); | |
2003 } | |
2004 } | |
2005 | |
2006 | |
2007 void OrthancPlugins::CallPeerApi(const void* parameters) | |
2008 { | |
2009 const _OrthancPluginCallPeerApi& p = *reinterpret_cast<const _OrthancPluginCallPeerApi*>(parameters); | |
2010 const OrthancPeers& peers = *reinterpret_cast<const OrthancPeers*>(p.peers); | |
2011 | |
2012 HttpClient client(peers.GetPeerParameters(p.peerIndex), p.uri); | |
2013 client.SetConvertHeadersToLowerCase(false); | |
2014 | |
2015 if (p.timeout != 0) | |
2016 { | |
2017 client.SetTimeout(p.timeout); | |
2018 } | |
2019 | |
2020 for (uint32_t i = 0; i < p.additionalHeadersCount; i++) | |
2021 { | |
2022 if (p.additionalHeadersKeys[i] == NULL || | |
2023 p.additionalHeadersValues[i] == NULL) | |
2024 { | |
2025 throw OrthancException(ErrorCode_NullPointer); | |
2026 } | |
2027 | |
2028 client.AddHeader(p.additionalHeadersKeys[i], p.additionalHeadersValues[i]); | |
2029 } | |
2030 | |
2031 switch (p.method) | |
2032 { | |
2033 case OrthancPluginHttpMethod_Get: | |
2034 client.SetMethod(HttpMethod_Get); | |
2035 break; | |
2036 | |
2037 case OrthancPluginHttpMethod_Post: | |
2038 client.SetMethod(HttpMethod_Post); | |
2039 client.GetBody().assign(p.body, p.bodySize); | |
2040 break; | |
2041 | |
2042 case OrthancPluginHttpMethod_Put: | |
2043 client.SetMethod(HttpMethod_Put); | |
2044 client.GetBody().assign(p.body, p.bodySize); | |
2045 break; | |
2046 | |
2047 case OrthancPluginHttpMethod_Delete: | |
2048 client.SetMethod(HttpMethod_Delete); | |
2049 break; | |
2050 | |
2051 default: | |
2052 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
2053 } | |
2054 | |
2055 std::string body; | |
2056 HttpClient::HttpHeaders headers; | |
2057 | |
2058 bool success = client.Apply(body, headers); | |
2059 | |
2060 // The HTTP request has succeeded | |
2061 *p.httpStatus = static_cast<uint16_t>(client.GetLastStatus()); | |
2062 | |
2063 if (!success) | |
2064 { | |
2065 HttpClient::ThrowException(client.GetLastStatus()); | |
2066 } | |
2067 | |
2068 // Copy the HTTP headers of the answer, if the plugin requested them | |
2069 if (p.answerHeaders != NULL) | |
2070 { | |
2071 Json::Value json = Json::objectValue; | |
2072 | |
2073 for (HttpClient::HttpHeaders::const_iterator | |
2074 it = headers.begin(); it != headers.end(); ++it) | |
2075 { | |
2076 json[it->first] = it->second; | |
2077 } | |
2078 | |
2079 std::string s = json.toStyledString(); | |
2080 CopyToMemoryBuffer(*p.answerHeaders, s); | |
2081 } | |
2082 | |
2083 // Copy the body of the answer if it makes sense | |
2084 if (p.method != OrthancPluginHttpMethod_Delete) | |
2085 { | |
2086 CopyToMemoryBuffer(*p.answerBody, body); | |
2087 } | |
2088 } | |
2089 | |
2090 | |
1206 void OrthancPlugins::ConvertPixelFormat(const void* parameters) | 2091 void OrthancPlugins::ConvertPixelFormat(const void* parameters) |
1207 { | 2092 { |
1208 const _OrthancPluginConvertPixelFormat& p = *reinterpret_cast<const _OrthancPluginConvertPixelFormat*>(parameters); | 2093 const _OrthancPluginConvertPixelFormat& p = *reinterpret_cast<const _OrthancPluginConvertPixelFormat*>(parameters); |
1209 const ImageAccessor& source = *reinterpret_cast<const ImageAccessor*>(p.source); | 2094 const ImageAccessor& source = *reinterpret_cast<const ImageAccessor*>(p.source); |
1210 | 2095 |
1211 std::auto_ptr<ImageAccessor> target(new Image(Plugins::Convert(p.targetFormat), source.GetWidth(), source.GetHeight())); | 2096 std::auto_ptr<ImageAccessor> target(new Image(Plugins::Convert(p.targetFormat), source.GetWidth(), source.GetHeight(), false)); |
1212 ImageProcessing::Convert(*target, source); | 2097 ImageProcessing::Convert(*target, source); |
1213 | 2098 |
1214 *(p.target) = reinterpret_cast<OrthancPluginImage*>(target.release()); | 2099 *(p.target) = ReturnImage(target); |
1215 } | 2100 } |
1216 | 2101 |
1217 | 2102 |
1218 | 2103 |
1219 void OrthancPlugins::GetFontInfo(const void* parameters) | 2104 void OrthancPlugins::GetFontInfo(const void* parameters) |
1262 } | 2147 } |
1263 else | 2148 else |
1264 { | 2149 { |
1265 if (p.instanceId == NULL) | 2150 if (p.instanceId == NULL) |
1266 { | 2151 { |
1267 throw OrthancException(ErrorCode_ParameterOutOfRange); | 2152 throw OrthancException(ErrorCode_NullPointer); |
1268 } | 2153 } |
1269 | 2154 |
1270 std::string content; | 2155 std::string content; |
1271 pimpl_->context_->ReadFile(content, p.instanceId, FileContentType_Dicom); | 2156 |
2157 { | |
2158 PImpl::ServerContextLock lock(*pimpl_); | |
2159 lock.GetContext().ReadDicom(content, p.instanceId); | |
2160 } | |
2161 | |
1272 dicom.reset(new ParsedDicomFile(content)); | 2162 dicom.reset(new ParsedDicomFile(content)); |
1273 } | 2163 } |
1274 | 2164 |
1275 Json::Value json; | 2165 Json::Value json; |
1276 dicom->ToJson(json, Plugins::Convert(p.format), | 2166 dicom->DatasetToJson(json, Plugins::Convert(p.format), |
1277 static_cast<DicomToJsonFlags>(p.flags), p.maxStringLength); | 2167 static_cast<DicomToJsonFlags>(p.flags), p.maxStringLength); |
1278 | 2168 |
1279 Json::FastWriter writer; | 2169 Json::FastWriter writer; |
1280 *p.result = CopyString(writer.write(json)); | 2170 *p.result = CopyString(writer.write(json)); |
1281 } | 2171 } |
1282 | 2172 |
1283 | 2173 |
1284 bool OrthancPlugins::InvokeService(SharedLibrary& plugin, | 2174 void OrthancPlugins::ApplyCreateDicom(_OrthancPluginService service, |
1285 _OrthancPluginService service, | 2175 const void* parameters) |
1286 const void* parameters) | 2176 { |
1287 { | 2177 const _OrthancPluginCreateDicom& p = |
1288 VLOG(1) << "Calling service " << service << " from plugin " << plugin.GetPath(); | 2178 *reinterpret_cast<const _OrthancPluginCreateDicom*>(parameters); |
1289 | 2179 |
1290 boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); | 2180 Json::Value json; |
1291 | 2181 |
2182 if (p.json == NULL) | |
2183 { | |
2184 json = Json::objectValue; | |
2185 } | |
2186 else | |
2187 { | |
2188 Json::Reader reader; | |
2189 if (!reader.parse(p.json, json)) | |
2190 { | |
2191 throw OrthancException(ErrorCode_BadJson); | |
2192 } | |
2193 } | |
2194 | |
2195 std::string dicom; | |
2196 | |
2197 { | |
2198 std::auto_ptr<ParsedDicomFile> file | |
2199 (ParsedDicomFile::CreateFromJson(json, static_cast<DicomFromJsonFlags>(p.flags))); | |
2200 | |
2201 if (p.pixelData) | |
2202 { | |
2203 file->EmbedImage(*reinterpret_cast<const ImageAccessor*>(p.pixelData)); | |
2204 } | |
2205 | |
2206 file->SaveToMemoryBuffer(dicom); | |
2207 } | |
2208 | |
2209 CopyToMemoryBuffer(*p.target, dicom); | |
2210 } | |
2211 | |
2212 | |
2213 void OrthancPlugins::ComputeHash(_OrthancPluginService service, | |
2214 const void* parameters) | |
2215 { | |
2216 const _OrthancPluginComputeHash& p = | |
2217 *reinterpret_cast<const _OrthancPluginComputeHash*>(parameters); | |
2218 | |
2219 std::string hash; | |
1292 switch (service) | 2220 switch (service) |
1293 { | 2221 { |
2222 case _OrthancPluginService_ComputeMd5: | |
2223 Toolbox::ComputeMD5(hash, p.buffer, p.size); | |
2224 break; | |
2225 | |
2226 case _OrthancPluginService_ComputeSha1: | |
2227 Toolbox::ComputeSHA1(hash, p.buffer, p.size); | |
2228 break; | |
2229 | |
2230 default: | |
2231 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
2232 } | |
2233 | |
2234 *p.result = CopyString(hash); | |
2235 } | |
2236 | |
2237 | |
2238 void OrthancPlugins::ApplyCreateImage(_OrthancPluginService service, | |
2239 const void* parameters) | |
2240 { | |
2241 const _OrthancPluginCreateImage& p = | |
2242 *reinterpret_cast<const _OrthancPluginCreateImage*>(parameters); | |
2243 | |
2244 std::auto_ptr<ImageAccessor> result; | |
2245 | |
2246 switch (service) | |
2247 { | |
2248 case _OrthancPluginService_CreateImage: | |
2249 result.reset(new Image(Plugins::Convert(p.format), p.width, p.height, false)); | |
2250 break; | |
2251 | |
2252 case _OrthancPluginService_CreateImageAccessor: | |
2253 result.reset(new ImageAccessor); | |
2254 result->AssignWritable(Plugins::Convert(p.format), p.width, p.height, p.pitch, p.buffer); | |
2255 break; | |
2256 | |
2257 case _OrthancPluginService_DecodeDicomImage: | |
2258 { | |
2259 result.reset(Decode(p.constBuffer, p.bufferSize, p.frameIndex)); | |
2260 break; | |
2261 } | |
2262 | |
2263 default: | |
2264 throw OrthancException(ErrorCode_InternalError); | |
2265 } | |
2266 | |
2267 *(p.target) = ReturnImage(result); | |
2268 } | |
2269 | |
2270 | |
2271 void OrthancPlugins::ApplySendMultipartItem(const void* parameters) | |
2272 { | |
2273 // An exception might be raised in this function if the | |
2274 // connection was closed by the HTTP client. | |
2275 const _OrthancPluginAnswerBuffer& p = | |
2276 *reinterpret_cast<const _OrthancPluginAnswerBuffer*>(parameters); | |
2277 | |
2278 HttpOutput* output = reinterpret_cast<HttpOutput*>(p.output); | |
2279 | |
2280 std::map<std::string, std::string> headers; // No custom headers | |
2281 output->SendMultipartItem(p.answer, p.answerSize, headers); | |
2282 } | |
2283 | |
2284 | |
2285 void OrthancPlugins::ApplySendMultipartItem2(const void* parameters) | |
2286 { | |
2287 // An exception might be raised in this function if the | |
2288 // connection was closed by the HTTP client. | |
2289 const _OrthancPluginSendMultipartItem2& p = | |
2290 *reinterpret_cast<const _OrthancPluginSendMultipartItem2*>(parameters); | |
2291 HttpOutput* output = reinterpret_cast<HttpOutput*>(p.output); | |
2292 | |
2293 std::map<std::string, std::string> headers; | |
2294 for (uint32_t i = 0; i < p.headersCount; i++) | |
2295 { | |
2296 headers[p.headersKeys[i]] = p.headersValues[i]; | |
2297 } | |
2298 | |
2299 output->SendMultipartItem(p.answer, p.answerSize, headers); | |
2300 } | |
2301 | |
2302 | |
2303 void OrthancPlugins::DatabaseAnswer(const void* parameters) | |
2304 { | |
2305 const _OrthancPluginDatabaseAnswer& p = | |
2306 *reinterpret_cast<const _OrthancPluginDatabaseAnswer*>(parameters); | |
2307 | |
2308 if (pimpl_->database_.get() != NULL) | |
2309 { | |
2310 pimpl_->database_->AnswerReceived(p); | |
2311 } | |
2312 else | |
2313 { | |
2314 LOG(ERROR) << "Cannot invoke this service without a custom database back-end"; | |
2315 throw OrthancException(ErrorCode_BadRequest); | |
2316 } | |
2317 } | |
2318 | |
2319 | |
2320 namespace | |
2321 { | |
2322 class DictionaryReadLocker | |
2323 { | |
2324 private: | |
2325 const DcmDataDictionary& dictionary_; | |
2326 | |
2327 public: | |
2328 DictionaryReadLocker() : dictionary_(dcmDataDict.rdlock()) | |
2329 { | |
2330 } | |
2331 | |
2332 ~DictionaryReadLocker() | |
2333 { | |
2334 dcmDataDict.unlock(); | |
2335 } | |
2336 | |
2337 const DcmDataDictionary* operator->() | |
2338 { | |
2339 return &dictionary_; | |
2340 } | |
2341 }; | |
2342 } | |
2343 | |
2344 | |
2345 void OrthancPlugins::ApplyLookupDictionary(const void* parameters) | |
2346 { | |
2347 const _OrthancPluginLookupDictionary& p = | |
2348 *reinterpret_cast<const _OrthancPluginLookupDictionary*>(parameters); | |
2349 | |
2350 DicomTag tag(FromDcmtkBridge::ParseTag(p.name)); | |
2351 DcmTagKey tag2(tag.GetGroup(), tag.GetElement()); | |
2352 | |
2353 DictionaryReadLocker locker; | |
2354 const DcmDictEntry* entry = locker->findEntry(tag2, NULL); | |
2355 | |
2356 if (entry == NULL) | |
2357 { | |
2358 throw OrthancException(ErrorCode_UnknownDicomTag); | |
2359 } | |
2360 else | |
2361 { | |
2362 p.target->group = entry->getKey().getGroup(); | |
2363 p.target->element = entry->getKey().getElement(); | |
2364 p.target->vr = Plugins::Convert(FromDcmtkBridge::Convert(entry->getEVR())); | |
2365 p.target->minMultiplicity = static_cast<uint32_t>(entry->getVMMin()); | |
2366 p.target->maxMultiplicity = (entry->getVMMax() == DcmVariableVM ? 0 : static_cast<uint32_t>(entry->getVMMax())); | |
2367 } | |
2368 } | |
2369 | |
2370 | |
2371 bool OrthancPlugins::InvokeSafeService(SharedLibrary& plugin, | |
2372 _OrthancPluginService service, | |
2373 const void* parameters) | |
2374 { | |
2375 // Services that can be run without mutual exclusion | |
2376 | |
2377 switch (service) | |
2378 { | |
1294 case _OrthancPluginService_GetOrthancPath: | 2379 case _OrthancPluginService_GetOrthancPath: |
1295 { | 2380 { |
1296 std::string s = Toolbox::GetPathToExecutable(); | 2381 std::string s = SystemToolbox::GetPathToExecutable(); |
1297 *reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters)->result = CopyString(s); | 2382 *reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters)->result = CopyString(s); |
1298 return true; | 2383 return true; |
1299 } | 2384 } |
1300 | 2385 |
1301 case _OrthancPluginService_GetOrthancDirectory: | 2386 case _OrthancPluginService_GetOrthancDirectory: |
1302 { | 2387 { |
1303 std::string s = Toolbox::GetDirectoryOfExecutable(); | 2388 std::string s = SystemToolbox::GetDirectoryOfExecutable(); |
1304 *reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters)->result = CopyString(s); | 2389 *reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters)->result = CopyString(s); |
1305 return true; | 2390 return true; |
1306 } | 2391 } |
1307 | 2392 |
1308 case _OrthancPluginService_GetConfigurationPath: | 2393 case _OrthancPluginService_GetConfigurationPath: |
1323 | 2408 |
1324 case _OrthancPluginService_BufferCompression: | 2409 case _OrthancPluginService_BufferCompression: |
1325 BufferCompression(parameters); | 2410 BufferCompression(parameters); |
1326 return true; | 2411 return true; |
1327 | 2412 |
1328 case _OrthancPluginService_RegisterRestCallback: | |
1329 RegisterRestCallback(parameters, true); | |
1330 return true; | |
1331 | |
1332 case _OrthancPluginService_RegisterRestCallbackNoLock: | |
1333 RegisterRestCallback(parameters, false); | |
1334 return true; | |
1335 | |
1336 case _OrthancPluginService_RegisterOnStoredInstanceCallback: | |
1337 RegisterOnStoredInstanceCallback(parameters); | |
1338 return true; | |
1339 | |
1340 case _OrthancPluginService_RegisterOnChangeCallback: | |
1341 RegisterOnChangeCallback(parameters); | |
1342 return true; | |
1343 | |
1344 case _OrthancPluginService_AnswerBuffer: | 2413 case _OrthancPluginService_AnswerBuffer: |
1345 AnswerBuffer(parameters); | 2414 AnswerBuffer(parameters); |
1346 return true; | 2415 return true; |
1347 | 2416 |
1348 case _OrthancPluginService_CompressAndAnswerPngImage: | 2417 case _OrthancPluginService_CompressAndAnswerPngImage: |
1361 RestApiGet(parameters, false); | 2430 RestApiGet(parameters, false); |
1362 return true; | 2431 return true; |
1363 | 2432 |
1364 case _OrthancPluginService_RestApiGetAfterPlugins: | 2433 case _OrthancPluginService_RestApiGetAfterPlugins: |
1365 RestApiGet(parameters, true); | 2434 RestApiGet(parameters, true); |
2435 return true; | |
2436 | |
2437 case _OrthancPluginService_RestApiGet2: | |
2438 RestApiGet2(parameters); | |
1366 return true; | 2439 return true; |
1367 | 2440 |
1368 case _OrthancPluginService_RestApiPost: | 2441 case _OrthancPluginService_RestApiPost: |
1369 RestApiPostPut(true, parameters, false); | 2442 RestApiPostPut(true, parameters, false); |
1370 return true; | 2443 return true; |
1430 case _OrthancPluginService_GetInstanceData: | 2503 case _OrthancPluginService_GetInstanceData: |
1431 case _OrthancPluginService_GetInstanceJson: | 2504 case _OrthancPluginService_GetInstanceJson: |
1432 case _OrthancPluginService_GetInstanceSimplifiedJson: | 2505 case _OrthancPluginService_GetInstanceSimplifiedJson: |
1433 case _OrthancPluginService_HasInstanceMetadata: | 2506 case _OrthancPluginService_HasInstanceMetadata: |
1434 case _OrthancPluginService_GetInstanceMetadata: | 2507 case _OrthancPluginService_GetInstanceMetadata: |
2508 case _OrthancPluginService_GetInstanceOrigin: | |
1435 AccessDicomInstance(service, parameters); | 2509 AccessDicomInstance(service, parameters); |
1436 return true; | 2510 return true; |
1437 | |
1438 case _OrthancPluginService_RegisterStorageArea: | |
1439 { | |
1440 LOG(INFO) << "Plugin has registered a custom storage area"; | |
1441 const _OrthancPluginRegisterStorageArea& p = | |
1442 *reinterpret_cast<const _OrthancPluginRegisterStorageArea*>(parameters); | |
1443 | |
1444 if (pimpl_->storageArea_.get() == NULL) | |
1445 { | |
1446 pimpl_->storageArea_.reset(new StorageAreaFactory(plugin, p, GetErrorDictionary())); | |
1447 } | |
1448 else | |
1449 { | |
1450 throw OrthancException(ErrorCode_StorageAreaAlreadyRegistered); | |
1451 } | |
1452 | |
1453 return true; | |
1454 } | |
1455 | |
1456 case _OrthancPluginService_SetPluginProperty: | |
1457 { | |
1458 const _OrthancPluginSetPluginProperty& p = | |
1459 *reinterpret_cast<const _OrthancPluginSetPluginProperty*>(parameters); | |
1460 pimpl_->properties_[std::make_pair(p.plugin, p.property)] = p.value; | |
1461 return true; | |
1462 } | |
1463 | 2511 |
1464 case _OrthancPluginService_SetGlobalProperty: | 2512 case _OrthancPluginService_SetGlobalProperty: |
1465 { | 2513 { |
1466 const _OrthancPluginGlobalProperty& p = | 2514 const _OrthancPluginGlobalProperty& p = |
1467 *reinterpret_cast<const _OrthancPluginGlobalProperty*>(parameters); | 2515 *reinterpret_cast<const _OrthancPluginGlobalProperty*>(parameters); |
1469 { | 2517 { |
1470 return false; | 2518 return false; |
1471 } | 2519 } |
1472 else | 2520 else |
1473 { | 2521 { |
1474 CheckContextAvailable(); | 2522 PImpl::ServerContextLock lock(*pimpl_); |
1475 pimpl_->context_->GetIndex().SetGlobalProperty(static_cast<GlobalProperty>(p.property), p.value); | 2523 lock.GetContext().GetIndex().SetGlobalProperty(static_cast<GlobalProperty>(p.property), p.value); |
1476 return true; | 2524 return true; |
1477 } | 2525 } |
1478 } | 2526 } |
1479 | 2527 |
1480 case _OrthancPluginService_GetGlobalProperty: | 2528 case _OrthancPluginService_GetGlobalProperty: |
1481 { | 2529 { |
1482 CheckContextAvailable(); | |
1483 | |
1484 const _OrthancPluginGlobalProperty& p = | 2530 const _OrthancPluginGlobalProperty& p = |
1485 *reinterpret_cast<const _OrthancPluginGlobalProperty*>(parameters); | 2531 *reinterpret_cast<const _OrthancPluginGlobalProperty*>(parameters); |
1486 std::string result = pimpl_->context_->GetIndex().GetGlobalProperty(static_cast<GlobalProperty>(p.property), p.value); | 2532 |
2533 std::string result; | |
2534 | |
2535 { | |
2536 PImpl::ServerContextLock lock(*pimpl_); | |
2537 result = lock.GetContext().GetIndex().GetGlobalProperty(static_cast<GlobalProperty>(p.property), p.value); | |
2538 } | |
2539 | |
1487 *(p.result) = CopyString(result); | 2540 *(p.result) = CopyString(result); |
1488 return true; | 2541 return true; |
1489 } | |
1490 | |
1491 case _OrthancPluginService_GetCommandLineArgumentsCount: | |
1492 { | |
1493 const _OrthancPluginReturnSingleValue& p = | |
1494 *reinterpret_cast<const _OrthancPluginReturnSingleValue*>(parameters); | |
1495 *(p.resultUint32) = pimpl_->argc_ - 1; | |
1496 return true; | |
1497 } | |
1498 | |
1499 case _OrthancPluginService_GetCommandLineArgument: | |
1500 { | |
1501 const _OrthancPluginGlobalProperty& p = | |
1502 *reinterpret_cast<const _OrthancPluginGlobalProperty*>(parameters); | |
1503 | |
1504 if (p.property + 1 > pimpl_->argc_) | |
1505 { | |
1506 return false; | |
1507 } | |
1508 else | |
1509 { | |
1510 std::string arg = std::string(pimpl_->argv_[p.property + 1]); | |
1511 *(p.result) = CopyString(arg); | |
1512 return true; | |
1513 } | |
1514 } | |
1515 | |
1516 case _OrthancPluginService_RegisterDatabaseBackend: | |
1517 { | |
1518 LOG(INFO) << "Plugin has registered a custom database back-end"; | |
1519 | |
1520 const _OrthancPluginRegisterDatabaseBackend& p = | |
1521 *reinterpret_cast<const _OrthancPluginRegisterDatabaseBackend*>(parameters); | |
1522 | |
1523 if (pimpl_->database_.get() == NULL) | |
1524 { | |
1525 pimpl_->database_.reset(new OrthancPluginDatabase(plugin, GetErrorDictionary(), | |
1526 *p.backend, NULL, 0, p.payload)); | |
1527 } | |
1528 else | |
1529 { | |
1530 throw OrthancException(ErrorCode_DatabaseBackendAlreadyRegistered); | |
1531 } | |
1532 | |
1533 *(p.result) = reinterpret_cast<OrthancPluginDatabaseContext*>(pimpl_->database_.get()); | |
1534 | |
1535 return true; | |
1536 } | |
1537 | |
1538 case _OrthancPluginService_RegisterDatabaseBackendV2: | |
1539 { | |
1540 LOG(INFO) << "Plugin has registered a custom database back-end"; | |
1541 | |
1542 const _OrthancPluginRegisterDatabaseBackendV2& p = | |
1543 *reinterpret_cast<const _OrthancPluginRegisterDatabaseBackendV2*>(parameters); | |
1544 | |
1545 if (pimpl_->database_.get() == NULL) | |
1546 { | |
1547 pimpl_->database_.reset(new OrthancPluginDatabase(plugin, GetErrorDictionary(), | |
1548 *p.backend, p.extensions, | |
1549 p.extensionsSize, p.payload)); | |
1550 } | |
1551 else | |
1552 { | |
1553 throw OrthancException(ErrorCode_DatabaseBackendAlreadyRegistered); | |
1554 } | |
1555 | |
1556 *(p.result) = reinterpret_cast<OrthancPluginDatabaseContext*>(pimpl_->database_.get()); | |
1557 | |
1558 return true; | |
1559 } | |
1560 | |
1561 case _OrthancPluginService_DatabaseAnswer: | |
1562 { | |
1563 const _OrthancPluginDatabaseAnswer& p = | |
1564 *reinterpret_cast<const _OrthancPluginDatabaseAnswer*>(parameters); | |
1565 | |
1566 if (pimpl_->database_.get() != NULL) | |
1567 { | |
1568 pimpl_->database_->AnswerReceived(p); | |
1569 return true; | |
1570 } | |
1571 else | |
1572 { | |
1573 LOG(ERROR) << "Cannot invoke this service without a custom database back-end"; | |
1574 throw OrthancException(ErrorCode_BadRequest); | |
1575 } | |
1576 } | 2542 } |
1577 | 2543 |
1578 case _OrthancPluginService_GetExpectedDatabaseVersion: | 2544 case _OrthancPluginService_GetExpectedDatabaseVersion: |
1579 { | 2545 { |
1580 const _OrthancPluginReturnSingleValue& p = | 2546 const _OrthancPluginReturnSingleValue& p = |
1591 output->StartMultipart(p.subType, p.contentType); | 2557 output->StartMultipart(p.subType, p.contentType); |
1592 return true; | 2558 return true; |
1593 } | 2559 } |
1594 | 2560 |
1595 case _OrthancPluginService_SendMultipartItem: | 2561 case _OrthancPluginService_SendMultipartItem: |
1596 { | 2562 ApplySendMultipartItem(parameters); |
1597 // An exception might be raised in this function if the | 2563 return true; |
1598 // connection was closed by the HTTP client. | 2564 |
1599 const _OrthancPluginAnswerBuffer& p = | 2565 case _OrthancPluginService_SendMultipartItem2: |
1600 *reinterpret_cast<const _OrthancPluginAnswerBuffer*>(parameters); | 2566 ApplySendMultipartItem2(parameters); |
1601 HttpOutput* output = reinterpret_cast<HttpOutput*>(p.output); | 2567 return true; |
1602 output->SendMultipartItem(p.answer, p.answerSize); | |
1603 return true; | |
1604 } | |
1605 | 2568 |
1606 case _OrthancPluginService_ReadFile: | 2569 case _OrthancPluginService_ReadFile: |
1607 { | 2570 { |
1608 const _OrthancPluginReadFile& p = | 2571 const _OrthancPluginReadFile& p = |
1609 *reinterpret_cast<const _OrthancPluginReadFile*>(parameters); | 2572 *reinterpret_cast<const _OrthancPluginReadFile*>(parameters); |
1610 | 2573 |
1611 std::string content; | 2574 std::string content; |
1612 Toolbox::ReadFile(content, p.path); | 2575 SystemToolbox::ReadFile(content, p.path); |
1613 CopyToMemoryBuffer(*p.target, content.size() > 0 ? content.c_str() : NULL, content.size()); | 2576 CopyToMemoryBuffer(*p.target, content.size() > 0 ? content.c_str() : NULL, content.size()); |
1614 | 2577 |
1615 return true; | 2578 return true; |
1616 } | 2579 } |
1617 | 2580 |
1618 case _OrthancPluginService_WriteFile: | 2581 case _OrthancPluginService_WriteFile: |
1619 { | 2582 { |
1620 const _OrthancPluginWriteFile& p = | 2583 const _OrthancPluginWriteFile& p = |
1621 *reinterpret_cast<const _OrthancPluginWriteFile*>(parameters); | 2584 *reinterpret_cast<const _OrthancPluginWriteFile*>(parameters); |
1622 Toolbox::WriteFile(p.data, p.size, p.path); | 2585 SystemToolbox::WriteFile(p.data, p.size, p.path); |
1623 return true; | 2586 return true; |
1624 } | 2587 } |
1625 | 2588 |
1626 case _OrthancPluginService_GetErrorDescription: | 2589 case _OrthancPluginService_GetErrorDescription: |
1627 { | 2590 { |
1660 } | 2623 } |
1661 | 2624 |
1662 case _OrthancPluginService_GetImageBuffer: | 2625 case _OrthancPluginService_GetImageBuffer: |
1663 { | 2626 { |
1664 const _OrthancPluginGetImageInfo& p = *reinterpret_cast<const _OrthancPluginGetImageInfo*>(parameters); | 2627 const _OrthancPluginGetImageInfo& p = *reinterpret_cast<const _OrthancPluginGetImageInfo*>(parameters); |
1665 *(p.resultBuffer) = reinterpret_cast<const ImageAccessor*>(p.image)->GetConstBuffer(); | 2628 *(p.resultBuffer) = reinterpret_cast<const ImageAccessor*>(p.image)->GetBuffer(); |
1666 return true; | 2629 return true; |
1667 } | 2630 } |
1668 | 2631 |
1669 case _OrthancPluginService_FreeImage: | 2632 case _OrthancPluginService_FreeImage: |
1670 { | 2633 { |
1671 const _OrthancPluginFreeImage& p = *reinterpret_cast<const _OrthancPluginFreeImage*>(parameters); | 2634 const _OrthancPluginFreeImage& p = *reinterpret_cast<const _OrthancPluginFreeImage*>(parameters); |
1672 if (p.image == NULL) | 2635 |
1673 { | 2636 if (p.image != NULL) |
1674 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
1675 } | |
1676 else | |
1677 { | 2637 { |
1678 delete reinterpret_cast<ImageAccessor*>(p.image); | 2638 delete reinterpret_cast<ImageAccessor*>(p.image); |
1679 return true; | 2639 } |
1680 } | 2640 |
2641 return true; | |
1681 } | 2642 } |
1682 | 2643 |
1683 case _OrthancPluginService_UncompressImage: | 2644 case _OrthancPluginService_UncompressImage: |
1684 UncompressImage(parameters); | 2645 UncompressImage(parameters); |
1685 return true; | 2646 return true; |
1688 CompressImage(parameters); | 2649 CompressImage(parameters); |
1689 return true; | 2650 return true; |
1690 | 2651 |
1691 case _OrthancPluginService_CallHttpClient: | 2652 case _OrthancPluginService_CallHttpClient: |
1692 CallHttpClient(parameters); | 2653 CallHttpClient(parameters); |
2654 return true; | |
2655 | |
2656 case _OrthancPluginService_CallHttpClient2: | |
2657 CallHttpClient2(parameters); | |
1693 return true; | 2658 return true; |
1694 | 2659 |
1695 case _OrthancPluginService_ConvertPixelFormat: | 2660 case _OrthancPluginService_ConvertPixelFormat: |
1696 ConvertPixelFormat(parameters); | 2661 ConvertPixelFormat(parameters); |
1697 return true; | 2662 return true; |
1715 case _OrthancPluginService_StorageAreaCreate: | 2680 case _OrthancPluginService_StorageAreaCreate: |
1716 { | 2681 { |
1717 const _OrthancPluginStorageAreaCreate& p = | 2682 const _OrthancPluginStorageAreaCreate& p = |
1718 *reinterpret_cast<const _OrthancPluginStorageAreaCreate*>(parameters); | 2683 *reinterpret_cast<const _OrthancPluginStorageAreaCreate*>(parameters); |
1719 IStorageArea& storage = *reinterpret_cast<IStorageArea*>(p.storageArea); | 2684 IStorageArea& storage = *reinterpret_cast<IStorageArea*>(p.storageArea); |
1720 storage.Create(p.uuid, p.content, p.size, Plugins::Convert(p.type)); | 2685 storage.Create(p.uuid, p.content, static_cast<size_t>(p.size), Plugins::Convert(p.type)); |
1721 return true; | 2686 return true; |
1722 } | 2687 } |
1723 | 2688 |
1724 case _OrthancPluginService_StorageAreaRead: | 2689 case _OrthancPluginService_StorageAreaRead: |
1725 { | 2690 { |
1739 IStorageArea& storage = *reinterpret_cast<IStorageArea*>(p.storageArea); | 2704 IStorageArea& storage = *reinterpret_cast<IStorageArea*>(p.storageArea); |
1740 storage.Remove(p.uuid, Plugins::Convert(p.type)); | 2705 storage.Remove(p.uuid, Plugins::Convert(p.type)); |
1741 return true; | 2706 return true; |
1742 } | 2707 } |
1743 | 2708 |
2709 case _OrthancPluginService_DicomBufferToJson: | |
2710 case _OrthancPluginService_DicomInstanceToJson: | |
2711 ApplyDicomToJson(service, parameters); | |
2712 return true; | |
2713 | |
2714 case _OrthancPluginService_CreateDicom: | |
2715 ApplyCreateDicom(service, parameters); | |
2716 return true; | |
2717 | |
2718 case _OrthancPluginService_WorklistAddAnswer: | |
2719 { | |
2720 const _OrthancPluginWorklistAnswersOperation& p = | |
2721 *reinterpret_cast<const _OrthancPluginWorklistAnswersOperation*>(parameters); | |
2722 reinterpret_cast<const WorklistHandler*>(p.query)->AddAnswer(p.answers, p.dicom, p.size); | |
2723 return true; | |
2724 } | |
2725 | |
2726 case _OrthancPluginService_WorklistMarkIncomplete: | |
2727 { | |
2728 const _OrthancPluginWorklistAnswersOperation& p = | |
2729 *reinterpret_cast<const _OrthancPluginWorklistAnswersOperation*>(parameters); | |
2730 reinterpret_cast<DicomFindAnswers*>(p.answers)->SetComplete(false); | |
2731 return true; | |
2732 } | |
2733 | |
2734 case _OrthancPluginService_WorklistIsMatch: | |
2735 { | |
2736 const _OrthancPluginWorklistQueryOperation& p = | |
2737 *reinterpret_cast<const _OrthancPluginWorklistQueryOperation*>(parameters); | |
2738 *p.isMatch = reinterpret_cast<const WorklistHandler*>(p.query)->IsMatch(p.dicom, p.size); | |
2739 return true; | |
2740 } | |
2741 | |
2742 case _OrthancPluginService_WorklistGetDicomQuery: | |
2743 { | |
2744 const _OrthancPluginWorklistQueryOperation& p = | |
2745 *reinterpret_cast<const _OrthancPluginWorklistQueryOperation*>(parameters); | |
2746 reinterpret_cast<const WorklistHandler*>(p.query)->GetDicomQuery(*p.target); | |
2747 return true; | |
2748 } | |
2749 | |
2750 case _OrthancPluginService_FindAddAnswer: | |
2751 { | |
2752 const _OrthancPluginFindOperation& p = | |
2753 *reinterpret_cast<const _OrthancPluginFindOperation*>(parameters); | |
2754 reinterpret_cast<DicomFindAnswers*>(p.answers)->Add(p.dicom, p.size); | |
2755 return true; | |
2756 } | |
2757 | |
2758 case _OrthancPluginService_FindMarkIncomplete: | |
2759 { | |
2760 const _OrthancPluginFindOperation& p = | |
2761 *reinterpret_cast<const _OrthancPluginFindOperation*>(parameters); | |
2762 reinterpret_cast<DicomFindAnswers*>(p.answers)->SetComplete(false); | |
2763 return true; | |
2764 } | |
2765 | |
2766 case _OrthancPluginService_GetFindQuerySize: | |
2767 case _OrthancPluginService_GetFindQueryTag: | |
2768 case _OrthancPluginService_GetFindQueryTagName: | |
2769 case _OrthancPluginService_GetFindQueryValue: | |
2770 { | |
2771 const _OrthancPluginFindOperation& p = | |
2772 *reinterpret_cast<const _OrthancPluginFindOperation*>(parameters); | |
2773 reinterpret_cast<const FindHandler*>(p.query)->Invoke(service, p); | |
2774 return true; | |
2775 } | |
2776 | |
2777 case _OrthancPluginService_CreateImage: | |
2778 case _OrthancPluginService_CreateImageAccessor: | |
2779 case _OrthancPluginService_DecodeDicomImage: | |
2780 ApplyCreateImage(service, parameters); | |
2781 return true; | |
2782 | |
2783 case _OrthancPluginService_ComputeMd5: | |
2784 case _OrthancPluginService_ComputeSha1: | |
2785 ComputeHash(service, parameters); | |
2786 return true; | |
2787 | |
2788 case _OrthancPluginService_LookupDictionary: | |
2789 ApplyLookupDictionary(parameters); | |
2790 return true; | |
2791 | |
2792 case _OrthancPluginService_GenerateUuid: | |
2793 { | |
2794 *reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters)->result = | |
2795 CopyString(Toolbox::GenerateUuid()); | |
2796 return true; | |
2797 } | |
2798 | |
2799 case _OrthancPluginService_CreateFindMatcher: | |
2800 { | |
2801 const _OrthancPluginCreateFindMatcher& p = | |
2802 *reinterpret_cast<const _OrthancPluginCreateFindMatcher*>(parameters); | |
2803 ParsedDicomFile query(p.query, p.size); | |
2804 *(p.target) = reinterpret_cast<OrthancPluginFindMatcher*>(new HierarchicalMatcher(query)); | |
2805 return true; | |
2806 } | |
2807 | |
2808 case _OrthancPluginService_FreeFindMatcher: | |
2809 { | |
2810 const _OrthancPluginFreeFindMatcher& p = | |
2811 *reinterpret_cast<const _OrthancPluginFreeFindMatcher*>(parameters); | |
2812 | |
2813 if (p.matcher != NULL) | |
2814 { | |
2815 delete reinterpret_cast<HierarchicalMatcher*>(p.matcher); | |
2816 } | |
2817 | |
2818 return true; | |
2819 } | |
2820 | |
2821 case _OrthancPluginService_FindMatcherIsMatch: | |
2822 { | |
2823 const _OrthancPluginFindMatcherIsMatch& p = | |
2824 *reinterpret_cast<const _OrthancPluginFindMatcherIsMatch*>(parameters); | |
2825 | |
2826 if (p.matcher == NULL) | |
2827 { | |
2828 throw OrthancException(ErrorCode_NullPointer); | |
2829 } | |
2830 else | |
2831 { | |
2832 ParsedDicomFile query(p.dicom, p.size); | |
2833 *p.isMatch = reinterpret_cast<const HierarchicalMatcher*>(p.matcher)->Match(query) ? 1 : 0; | |
2834 return true; | |
2835 } | |
2836 } | |
2837 | |
2838 case _OrthancPluginService_GetPeers: | |
2839 { | |
2840 const _OrthancPluginGetPeers& p = | |
2841 *reinterpret_cast<const _OrthancPluginGetPeers*>(parameters); | |
2842 *(p.peers) = reinterpret_cast<OrthancPluginPeers*>(new OrthancPeers); | |
2843 return true; | |
2844 } | |
2845 | |
2846 case _OrthancPluginService_FreePeers: | |
2847 { | |
2848 const _OrthancPluginFreePeers& p = | |
2849 *reinterpret_cast<const _OrthancPluginFreePeers*>(parameters); | |
2850 | |
2851 if (p.peers != NULL) | |
2852 { | |
2853 delete reinterpret_cast<OrthancPeers*>(p.peers); | |
2854 } | |
2855 | |
2856 return true; | |
2857 } | |
2858 | |
2859 case _OrthancPluginService_GetPeersCount: | |
2860 { | |
2861 const _OrthancPluginGetPeersCount& p = | |
2862 *reinterpret_cast<const _OrthancPluginGetPeersCount*>(parameters); | |
2863 | |
2864 if (p.peers == NULL) | |
2865 { | |
2866 throw OrthancException(ErrorCode_NullPointer); | |
2867 } | |
2868 else | |
2869 { | |
2870 *(p.target) = reinterpret_cast<const OrthancPeers*>(p.peers)->GetPeersCount(); | |
2871 return true; | |
2872 } | |
2873 } | |
2874 | |
2875 case _OrthancPluginService_GetPeerName: | |
2876 { | |
2877 const _OrthancPluginGetPeerProperty& p = | |
2878 *reinterpret_cast<const _OrthancPluginGetPeerProperty*>(parameters); | |
2879 | |
2880 if (p.peers == NULL) | |
2881 { | |
2882 throw OrthancException(ErrorCode_NullPointer); | |
2883 } | |
2884 else | |
2885 { | |
2886 *(p.target) = reinterpret_cast<const OrthancPeers*>(p.peers)->GetPeerName(p.peerIndex).c_str(); | |
2887 return true; | |
2888 } | |
2889 } | |
2890 | |
2891 case _OrthancPluginService_GetPeerUrl: | |
2892 { | |
2893 const _OrthancPluginGetPeerProperty& p = | |
2894 *reinterpret_cast<const _OrthancPluginGetPeerProperty*>(parameters); | |
2895 | |
2896 if (p.peers == NULL) | |
2897 { | |
2898 throw OrthancException(ErrorCode_NullPointer); | |
2899 } | |
2900 else | |
2901 { | |
2902 *(p.target) = reinterpret_cast<const OrthancPeers*>(p.peers)->GetPeerParameters(p.peerIndex).GetUrl().c_str(); | |
2903 return true; | |
2904 } | |
2905 } | |
2906 | |
2907 case _OrthancPluginService_GetPeerUserProperty: | |
2908 { | |
2909 const _OrthancPluginGetPeerProperty& p = | |
2910 *reinterpret_cast<const _OrthancPluginGetPeerProperty*>(parameters); | |
2911 | |
2912 if (p.peers == NULL || | |
2913 p.userProperty == NULL) | |
2914 { | |
2915 throw OrthancException(ErrorCode_NullPointer); | |
2916 } | |
2917 else | |
2918 { | |
2919 const WebServiceParameters::Dictionary& properties = | |
2920 reinterpret_cast<const OrthancPeers*>(p.peers)->GetPeerParameters(p.peerIndex).GetUserProperties(); | |
2921 | |
2922 WebServiceParameters::Dictionary::const_iterator found = | |
2923 properties.find(p.userProperty); | |
2924 | |
2925 if (found == properties.end()) | |
2926 { | |
2927 *(p.target) = NULL; | |
2928 } | |
2929 else | |
2930 { | |
2931 *(p.target) = found->second.c_str(); | |
2932 } | |
2933 | |
2934 return true; | |
2935 } | |
2936 } | |
2937 | |
2938 case _OrthancPluginService_CallPeerApi: | |
2939 CallPeerApi(parameters); | |
2940 return true; | |
2941 | |
2942 case _OrthancPluginService_CreateJob: | |
2943 { | |
2944 const _OrthancPluginCreateJob& p = | |
2945 *reinterpret_cast<const _OrthancPluginCreateJob*>(parameters); | |
2946 *(p.target) = reinterpret_cast<OrthancPluginJob*>(new PluginsJob(p)); | |
2947 return true; | |
2948 } | |
2949 | |
2950 case _OrthancPluginService_FreeJob: | |
2951 { | |
2952 const _OrthancPluginFreeJob& p = | |
2953 *reinterpret_cast<const _OrthancPluginFreeJob*>(parameters); | |
2954 | |
2955 if (p.job != NULL) | |
2956 { | |
2957 delete reinterpret_cast<PluginsJob*>(p.job); | |
2958 } | |
2959 | |
2960 return true; | |
2961 } | |
2962 | |
2963 case _OrthancPluginService_SubmitJob: | |
2964 { | |
2965 const _OrthancPluginSubmitJob& p = | |
2966 *reinterpret_cast<const _OrthancPluginSubmitJob*>(parameters); | |
2967 | |
2968 std::string uuid; | |
2969 | |
2970 PImpl::ServerContextLock lock(*pimpl_); | |
2971 lock.GetContext().GetJobsEngine().GetRegistry().Submit | |
2972 (uuid, reinterpret_cast<PluginsJob*>(p.job), p.priority); | |
2973 | |
2974 *p.resultId = CopyString(uuid); | |
2975 | |
2976 return true; | |
2977 } | |
2978 | |
2979 default: | |
2980 return false; | |
2981 } | |
2982 } | |
2983 | |
2984 | |
2985 | |
2986 bool OrthancPlugins::InvokeProtectedService(SharedLibrary& plugin, | |
2987 _OrthancPluginService service, | |
2988 const void* parameters) | |
2989 { | |
2990 // Services that must be run in mutual exclusion. Guideline: | |
2991 // Whenever "pimpl_" is directly accessed by the service, it | |
2992 // should be listed here. | |
2993 | |
2994 switch (service) | |
2995 { | |
2996 case _OrthancPluginService_RegisterRestCallback: | |
2997 RegisterRestCallback(parameters, true); | |
2998 return true; | |
2999 | |
3000 case _OrthancPluginService_RegisterRestCallbackNoLock: | |
3001 RegisterRestCallback(parameters, false); | |
3002 return true; | |
3003 | |
3004 case _OrthancPluginService_RegisterOnStoredInstanceCallback: | |
3005 RegisterOnStoredInstanceCallback(parameters); | |
3006 return true; | |
3007 | |
3008 case _OrthancPluginService_RegisterOnChangeCallback: | |
3009 RegisterOnChangeCallback(parameters); | |
3010 return true; | |
3011 | |
3012 case _OrthancPluginService_RegisterWorklistCallback: | |
3013 RegisterWorklistCallback(parameters); | |
3014 return true; | |
3015 | |
3016 case _OrthancPluginService_RegisterFindCallback: | |
3017 RegisterFindCallback(parameters); | |
3018 return true; | |
3019 | |
3020 case _OrthancPluginService_RegisterMoveCallback: | |
3021 RegisterMoveCallback(parameters); | |
3022 return true; | |
3023 | |
3024 case _OrthancPluginService_RegisterDecodeImageCallback: | |
3025 RegisterDecodeImageCallback(parameters); | |
3026 return true; | |
3027 | |
3028 case _OrthancPluginService_RegisterJobsUnserializer: | |
3029 RegisterJobsUnserializer(parameters); | |
3030 return true; | |
3031 | |
3032 case _OrthancPluginService_RegisterIncomingHttpRequestFilter: | |
3033 RegisterIncomingHttpRequestFilter(parameters); | |
3034 return true; | |
3035 | |
3036 case _OrthancPluginService_RegisterIncomingHttpRequestFilter2: | |
3037 RegisterIncomingHttpRequestFilter2(parameters); | |
3038 return true; | |
3039 | |
3040 case _OrthancPluginService_RegisterStorageArea: | |
3041 { | |
3042 LOG(INFO) << "Plugin has registered a custom storage area"; | |
3043 const _OrthancPluginRegisterStorageArea& p = | |
3044 *reinterpret_cast<const _OrthancPluginRegisterStorageArea*>(parameters); | |
3045 | |
3046 if (pimpl_->storageArea_.get() == NULL) | |
3047 { | |
3048 pimpl_->storageArea_.reset(new StorageAreaFactory(plugin, p, GetErrorDictionary())); | |
3049 } | |
3050 else | |
3051 { | |
3052 throw OrthancException(ErrorCode_StorageAreaAlreadyRegistered); | |
3053 } | |
3054 | |
3055 return true; | |
3056 } | |
3057 | |
3058 case _OrthancPluginService_SetPluginProperty: | |
3059 { | |
3060 const _OrthancPluginSetPluginProperty& p = | |
3061 *reinterpret_cast<const _OrthancPluginSetPluginProperty*>(parameters); | |
3062 pimpl_->properties_[std::make_pair(p.plugin, p.property)] = p.value; | |
3063 return true; | |
3064 } | |
3065 | |
3066 case _OrthancPluginService_GetCommandLineArgumentsCount: | |
3067 { | |
3068 const _OrthancPluginReturnSingleValue& p = | |
3069 *reinterpret_cast<const _OrthancPluginReturnSingleValue*>(parameters); | |
3070 *(p.resultUint32) = pimpl_->argc_ - 1; | |
3071 return true; | |
3072 } | |
3073 | |
3074 case _OrthancPluginService_GetCommandLineArgument: | |
3075 { | |
3076 const _OrthancPluginGlobalProperty& p = | |
3077 *reinterpret_cast<const _OrthancPluginGlobalProperty*>(parameters); | |
3078 | |
3079 if (p.property + 1 > pimpl_->argc_) | |
3080 { | |
3081 return false; | |
3082 } | |
3083 else | |
3084 { | |
3085 std::string arg = std::string(pimpl_->argv_[p.property + 1]); | |
3086 *(p.result) = CopyString(arg); | |
3087 return true; | |
3088 } | |
3089 } | |
3090 | |
3091 case _OrthancPluginService_RegisterDatabaseBackend: | |
3092 { | |
3093 LOG(INFO) << "Plugin has registered a custom database back-end"; | |
3094 | |
3095 const _OrthancPluginRegisterDatabaseBackend& p = | |
3096 *reinterpret_cast<const _OrthancPluginRegisterDatabaseBackend*>(parameters); | |
3097 | |
3098 if (pimpl_->database_.get() == NULL) | |
3099 { | |
3100 pimpl_->database_.reset(new OrthancPluginDatabase(plugin, GetErrorDictionary(), | |
3101 *p.backend, NULL, 0, p.payload)); | |
3102 } | |
3103 else | |
3104 { | |
3105 throw OrthancException(ErrorCode_DatabaseBackendAlreadyRegistered); | |
3106 } | |
3107 | |
3108 *(p.result) = reinterpret_cast<OrthancPluginDatabaseContext*>(pimpl_->database_.get()); | |
3109 | |
3110 return true; | |
3111 } | |
3112 | |
3113 case _OrthancPluginService_RegisterDatabaseBackendV2: | |
3114 { | |
3115 LOG(INFO) << "Plugin has registered a custom database back-end"; | |
3116 | |
3117 const _OrthancPluginRegisterDatabaseBackendV2& p = | |
3118 *reinterpret_cast<const _OrthancPluginRegisterDatabaseBackendV2*>(parameters); | |
3119 | |
3120 if (pimpl_->database_.get() == NULL) | |
3121 { | |
3122 pimpl_->database_.reset(new OrthancPluginDatabase(plugin, GetErrorDictionary(), | |
3123 *p.backend, p.extensions, | |
3124 p.extensionsSize, p.payload)); | |
3125 } | |
3126 else | |
3127 { | |
3128 throw OrthancException(ErrorCode_DatabaseBackendAlreadyRegistered); | |
3129 } | |
3130 | |
3131 *(p.result) = reinterpret_cast<OrthancPluginDatabaseContext*>(pimpl_->database_.get()); | |
3132 | |
3133 return true; | |
3134 } | |
3135 | |
3136 case _OrthancPluginService_DatabaseAnswer: | |
3137 throw OrthancException(ErrorCode_InternalError); // Implemented before locking (*) | |
3138 | |
1744 case _OrthancPluginService_RegisterErrorCode: | 3139 case _OrthancPluginService_RegisterErrorCode: |
1745 { | 3140 { |
1746 const _OrthancPluginRegisterErrorCode& p = | 3141 const _OrthancPluginRegisterErrorCode& p = |
1747 *reinterpret_cast<const _OrthancPluginRegisterErrorCode*>(parameters); | 3142 *reinterpret_cast<const _OrthancPluginRegisterErrorCode*>(parameters); |
1748 *(p.target) = pimpl_->dictionary_.Register(plugin, p.code, p.httpStatus, p.message); | 3143 *(p.target) = pimpl_->dictionary_.Register(plugin, p.code, p.httpStatus, p.message); |
1753 { | 3148 { |
1754 const _OrthancPluginRegisterDictionaryTag& p = | 3149 const _OrthancPluginRegisterDictionaryTag& p = |
1755 *reinterpret_cast<const _OrthancPluginRegisterDictionaryTag*>(parameters); | 3150 *reinterpret_cast<const _OrthancPluginRegisterDictionaryTag*>(parameters); |
1756 FromDcmtkBridge::RegisterDictionaryTag(DicomTag(p.group, p.element), | 3151 FromDcmtkBridge::RegisterDictionaryTag(DicomTag(p.group, p.element), |
1757 Plugins::Convert(p.vr), p.name, | 3152 Plugins::Convert(p.vr), p.name, |
1758 p.minMultiplicity, p.maxMultiplicity); | 3153 p.minMultiplicity, p.maxMultiplicity, ""); |
3154 return true; | |
3155 } | |
3156 | |
3157 case _OrthancPluginService_RegisterPrivateDictionaryTag: | |
3158 { | |
3159 const _OrthancPluginRegisterPrivateDictionaryTag& p = | |
3160 *reinterpret_cast<const _OrthancPluginRegisterPrivateDictionaryTag*>(parameters); | |
3161 FromDcmtkBridge::RegisterDictionaryTag(DicomTag(p.group, p.element), | |
3162 Plugins::Convert(p.vr), p.name, | |
3163 p.minMultiplicity, p.maxMultiplicity, p.privateCreator); | |
1759 return true; | 3164 return true; |
1760 } | 3165 } |
1761 | 3166 |
1762 case _OrthancPluginService_ReconstructMainDicomTags: | 3167 case _OrthancPluginService_ReconstructMainDicomTags: |
1763 { | 3168 { |
1769 LOG(ERROR) << "The service ReconstructMainDicomTags can only be invoked by custom database plugins"; | 3174 LOG(ERROR) << "The service ReconstructMainDicomTags can only be invoked by custom database plugins"; |
1770 throw OrthancException(ErrorCode_DatabasePlugin); | 3175 throw OrthancException(ErrorCode_DatabasePlugin); |
1771 } | 3176 } |
1772 | 3177 |
1773 IStorageArea& storage = *reinterpret_cast<IStorageArea*>(p.storageArea); | 3178 IStorageArea& storage = *reinterpret_cast<IStorageArea*>(p.storageArea); |
1774 Toolbox::ReconstructMainDicomTags(*pimpl_->database_, storage, Plugins::Convert(p.level)); | 3179 ServerToolbox::ReconstructMainDicomTags(*pimpl_->database_, storage, Plugins::Convert(p.level)); |
1775 | 3180 |
1776 return true; | 3181 return true; |
1777 } | 3182 } |
1778 | |
1779 case _OrthancPluginService_DicomBufferToJson: | |
1780 case _OrthancPluginService_DicomInstanceToJson: | |
1781 ApplyDicomToJson(service, parameters); | |
1782 return true; | |
1783 | 3183 |
1784 default: | 3184 default: |
1785 { | 3185 { |
1786 // This service is unknown to the Orthanc plugin engine | 3186 // This service is unknown to the Orthanc plugin engine |
1787 return false; | 3187 return false; |
1788 } | 3188 } |
1789 } | 3189 } |
1790 } | 3190 } |
1791 | 3191 |
1792 | 3192 |
3193 | |
3194 bool OrthancPlugins::InvokeService(SharedLibrary& plugin, | |
3195 _OrthancPluginService service, | |
3196 const void* parameters) | |
3197 { | |
3198 VLOG(1) << "Calling service " << service << " from plugin " << plugin.GetPath(); | |
3199 | |
3200 if (service == _OrthancPluginService_DatabaseAnswer) | |
3201 { | |
3202 // This case solves a deadlock at (*) reported by James Webster | |
3203 // on 2015-10-27 that was present in versions of Orthanc <= | |
3204 // 0.9.4 and related to database plugins implementing a custom | |
3205 // index. The problem was that locking the database is already | |
3206 // ensured by the "ServerIndex" class if the invoked service is | |
3207 // "DatabaseAnswer". | |
3208 DatabaseAnswer(parameters); | |
3209 return true; | |
3210 } | |
3211 | |
3212 if (InvokeSafeService(plugin, service, parameters)) | |
3213 { | |
3214 // The invoked service does not require locking | |
3215 return true; | |
3216 } | |
3217 else | |
3218 { | |
3219 // The invoked service requires locking | |
3220 boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); // (*) | |
3221 return InvokeProtectedService(plugin, service, parameters); | |
3222 } | |
3223 } | |
3224 | |
3225 | |
1793 bool OrthancPlugins::HasStorageArea() const | 3226 bool OrthancPlugins::HasStorageArea() const |
1794 { | 3227 { |
3228 boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); | |
1795 return pimpl_->storageArea_.get() != NULL; | 3229 return pimpl_->storageArea_.get() != NULL; |
1796 } | 3230 } |
1797 | 3231 |
1798 bool OrthancPlugins::HasDatabaseBackend() const | 3232 bool OrthancPlugins::HasDatabaseBackend() const |
1799 { | 3233 { |
3234 boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); | |
1800 return pimpl_->database_.get() != NULL; | 3235 return pimpl_->database_.get() != NULL; |
1801 } | 3236 } |
1802 | 3237 |
1803 | 3238 |
1804 IStorageArea* OrthancPlugins::CreateStorageArea() | 3239 IStorageArea* OrthancPlugins::CreateStorageArea() |
1896 | 3331 |
1897 PluginsErrorDictionary& OrthancPlugins::GetErrorDictionary() | 3332 PluginsErrorDictionary& OrthancPlugins::GetErrorDictionary() |
1898 { | 3333 { |
1899 return pimpl_->dictionary_; | 3334 return pimpl_->dictionary_; |
1900 } | 3335 } |
3336 | |
3337 | |
3338 IWorklistRequestHandler* OrthancPlugins::ConstructWorklistRequestHandler() | |
3339 { | |
3340 if (HasWorklistHandler()) | |
3341 { | |
3342 return new WorklistHandler(*this); | |
3343 } | |
3344 else | |
3345 { | |
3346 return NULL; | |
3347 } | |
3348 } | |
3349 | |
3350 | |
3351 bool OrthancPlugins::HasWorklistHandler() | |
3352 { | |
3353 boost::mutex::scoped_lock lock(pimpl_->worklistCallbackMutex_); | |
3354 return pimpl_->worklistCallback_ != NULL; | |
3355 } | |
3356 | |
3357 | |
3358 IFindRequestHandler* OrthancPlugins::ConstructFindRequestHandler() | |
3359 { | |
3360 if (HasFindHandler()) | |
3361 { | |
3362 return new FindHandler(*this); | |
3363 } | |
3364 else | |
3365 { | |
3366 return NULL; | |
3367 } | |
3368 } | |
3369 | |
3370 | |
3371 bool OrthancPlugins::HasFindHandler() | |
3372 { | |
3373 boost::mutex::scoped_lock lock(pimpl_->findCallbackMutex_); | |
3374 return pimpl_->findCallback_ != NULL; | |
3375 } | |
3376 | |
3377 | |
3378 IMoveRequestHandler* OrthancPlugins::ConstructMoveRequestHandler() | |
3379 { | |
3380 if (HasMoveHandler()) | |
3381 { | |
3382 return new MoveHandler(*this); | |
3383 } | |
3384 else | |
3385 { | |
3386 return NULL; | |
3387 } | |
3388 } | |
3389 | |
3390 | |
3391 bool OrthancPlugins::HasMoveHandler() | |
3392 { | |
3393 boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); | |
3394 return pimpl_->moveCallbacks_.callback != NULL; | |
3395 } | |
3396 | |
3397 | |
3398 bool OrthancPlugins::HasCustomImageDecoder() | |
3399 { | |
3400 boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); | |
3401 return !pimpl_->decodeImageCallbacks_.empty(); | |
3402 } | |
3403 | |
3404 | |
3405 ImageAccessor* OrthancPlugins::DecodeUnsafe(const void* dicom, | |
3406 size_t size, | |
3407 unsigned int frame) | |
3408 { | |
3409 boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); | |
3410 | |
3411 for (PImpl::DecodeImageCallbacks::const_iterator | |
3412 decoder = pimpl_->decodeImageCallbacks_.begin(); | |
3413 decoder != pimpl_->decodeImageCallbacks_.end(); ++decoder) | |
3414 { | |
3415 OrthancPluginImage* pluginImage = NULL; | |
3416 if ((*decoder) (&pluginImage, dicom, size, frame) == OrthancPluginErrorCode_Success && | |
3417 pluginImage != NULL) | |
3418 { | |
3419 return reinterpret_cast<ImageAccessor*>(pluginImage); | |
3420 } | |
3421 } | |
3422 | |
3423 return NULL; | |
3424 } | |
3425 | |
3426 | |
3427 ImageAccessor* OrthancPlugins::Decode(const void* dicom, | |
3428 size_t size, | |
3429 unsigned int frame) | |
3430 { | |
3431 ImageAccessor* result = DecodeUnsafe(dicom, size, frame); | |
3432 | |
3433 if (result != NULL) | |
3434 { | |
3435 return result; | |
3436 } | |
3437 else | |
3438 { | |
3439 LOG(INFO) << "The installed image decoding plugins cannot handle an image, fallback to the built-in decoder"; | |
3440 DefaultDicomImageDecoder defaultDecoder; | |
3441 return defaultDecoder.Decode(dicom, size, frame); | |
3442 } | |
3443 } | |
3444 | |
3445 | |
3446 bool OrthancPlugins::IsAllowed(HttpMethod method, | |
3447 const char* uri, | |
3448 const char* ip, | |
3449 const char* username, | |
3450 const IHttpHandler::Arguments& httpHeaders, | |
3451 const IHttpHandler::GetArguments& getArguments) | |
3452 { | |
3453 OrthancPluginHttpMethod cMethod = Plugins::Convert(method); | |
3454 | |
3455 std::vector<const char*> httpKeys(httpHeaders.size()); | |
3456 std::vector<const char*> httpValues(httpHeaders.size()); | |
3457 | |
3458 size_t pos = 0; | |
3459 for (IHttpHandler::Arguments::const_iterator | |
3460 it = httpHeaders.begin(); it != httpHeaders.end(); ++it, pos++) | |
3461 { | |
3462 httpKeys[pos] = it->first.c_str(); | |
3463 httpValues[pos] = it->second.c_str(); | |
3464 } | |
3465 | |
3466 std::vector<const char*> getKeys(getArguments.size()); | |
3467 std::vector<const char*> getValues(getArguments.size()); | |
3468 | |
3469 for (size_t i = 0; i < getArguments.size(); i++) | |
3470 { | |
3471 getKeys[i] = getArguments[i].first.c_str(); | |
3472 getValues[i] = getArguments[i].second.c_str(); | |
3473 } | |
3474 | |
3475 // Improved callback with support for GET arguments, since Orthanc 1.3.0 | |
3476 for (PImpl::IncomingHttpRequestFilters2::const_iterator | |
3477 filter = pimpl_->incomingHttpRequestFilters2_.begin(); | |
3478 filter != pimpl_->incomingHttpRequestFilters2_.end(); ++filter) | |
3479 { | |
3480 int32_t allowed = (*filter) (cMethod, uri, ip, | |
3481 httpKeys.size(), | |
3482 httpKeys.empty() ? NULL : &httpKeys[0], | |
3483 httpValues.empty() ? NULL : &httpValues[0], | |
3484 getKeys.size(), | |
3485 getKeys.empty() ? NULL : &getKeys[0], | |
3486 getValues.empty() ? NULL : &getValues[0]); | |
3487 | |
3488 if (allowed == 0) | |
3489 { | |
3490 return false; | |
3491 } | |
3492 else if (allowed != 1) | |
3493 { | |
3494 // The callback is only allowed to answer 0 or 1 | |
3495 throw OrthancException(ErrorCode_Plugin); | |
3496 } | |
3497 } | |
3498 | |
3499 for (PImpl::IncomingHttpRequestFilters::const_iterator | |
3500 filter = pimpl_->incomingHttpRequestFilters_.begin(); | |
3501 filter != pimpl_->incomingHttpRequestFilters_.end(); ++filter) | |
3502 { | |
3503 int32_t allowed = (*filter) (cMethod, uri, ip, httpKeys.size(), | |
3504 httpKeys.empty() ? NULL : &httpKeys[0], | |
3505 httpValues.empty() ? NULL : &httpValues[0]); | |
3506 | |
3507 if (allowed == 0) | |
3508 { | |
3509 return false; | |
3510 } | |
3511 else if (allowed != 1) | |
3512 { | |
3513 // The callback is only allowed to answer 0 or 1 | |
3514 throw OrthancException(ErrorCode_Plugin); | |
3515 } | |
3516 } | |
3517 | |
3518 return true; | |
3519 } | |
3520 | |
3521 | |
3522 IJob* OrthancPlugins::UnserializeJob(const std::string& type, | |
3523 const Json::Value& value) | |
3524 { | |
3525 const std::string serialized = value.toStyledString(); | |
3526 | |
3527 boost::mutex::scoped_lock lock(pimpl_->jobsUnserializersMutex_); | |
3528 | |
3529 for (PImpl::JobsUnserializers::iterator | |
3530 unserializer = pimpl_->jobsUnserializers_.begin(); | |
3531 unserializer != pimpl_->jobsUnserializers_.end(); ++unserializer) | |
3532 { | |
3533 OrthancPluginJob* job = (*unserializer) (type.c_str(), serialized.c_str()); | |
3534 if (job != NULL) | |
3535 { | |
3536 return reinterpret_cast<PluginsJob*>(job); | |
3537 } | |
3538 } | |
3539 | |
3540 return NULL; | |
3541 } | |
1901 } | 3542 } |