Mercurial > hg > orthanc-databases
comparison SQLite/Plugins/IndexPlugin.cpp @ 212:821d4ba83dc3
reorganization
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 24 Mar 2021 15:47:14 +0100 |
parents | d74a92ac00ea |
children | c2e4a909de0e |
comparison
equal
deleted
inserted
replaced
211:d74a92ac00ea | 212:821d4ba83dc3 |
---|---|
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 **/ | 19 **/ |
20 | 20 |
21 | 21 |
22 #include "SQLiteIndex.h" | 22 #include "SQLiteIndex.h" |
23 #include "../../Framework/Plugins/DatabaseBackendAdapterV3.h" | |
23 #include "../../Framework/Plugins/PluginInitialization.h" | 24 #include "../../Framework/Plugins/PluginInitialization.h" |
24 | 25 |
25 #include <Compatibility.h> // For std::unique_ptr<> | 26 #include <Compatibility.h> // For std::unique_ptr<> |
26 #include <Logging.h> | 27 #include <Logging.h> |
27 | 28 |
28 static std::unique_ptr<OrthancDatabases::SQLiteIndex> backend_; | 29 static std::unique_ptr<OrthancDatabases::SQLiteIndex> backend_; |
29 | |
30 | |
31 | |
32 #if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in Orthanc 1.3.1 | |
33 # if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 9, 2) | |
34 | |
35 | |
36 #define ORTHANC_PLUGINS_DATABASE_CATCH(context) \ | |
37 catch (::Orthanc::OrthancException& e) \ | |
38 { \ | |
39 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); \ | |
40 } \ | |
41 catch (::std::runtime_error& e) \ | |
42 { \ | |
43 const std::string message = "Exception in database back-end: " + std::string(e.what()); \ | |
44 OrthancPluginLogError(context, message.c_str()); \ | |
45 return OrthancPluginErrorCode_DatabasePlugin; \ | |
46 } \ | |
47 catch (...) \ | |
48 { \ | |
49 OrthancPluginLogError(context, "Native exception"); \ | |
50 return OrthancPluginErrorCode_DatabasePlugin; \ | |
51 } | |
52 | |
53 | |
54 | |
55 namespace OrthancDatabases | |
56 { | |
57 class Output : public IDatabaseBackendOutput | |
58 { | |
59 private: | |
60 struct Metadata | |
61 { | |
62 int32_t metadata; | |
63 const char* value; | |
64 }; | |
65 | |
66 _OrthancPluginDatabaseAnswerType answerType_; | |
67 std::list<std::string> stringsStore_; | |
68 | |
69 std::vector<OrthancPluginAttachment> attachments_; | |
70 std::vector<OrthancPluginChange> changes_; | |
71 std::vector<OrthancPluginDicomTag> tags_; | |
72 std::vector<OrthancPluginExportedResource> exported_; | |
73 std::vector<OrthancPluginDatabaseEvent> events_; | |
74 std::vector<int32_t> integers32_; | |
75 std::vector<int64_t> integers64_; | |
76 std::vector<OrthancPluginMatchingResource> matches_; | |
77 std::vector<Metadata> metadata_; | |
78 std::vector<std::string> stringAnswers_; | |
79 | |
80 const char* StoreString(const std::string& s) | |
81 { | |
82 stringsStore_.push_back(s); | |
83 return stringsStore_.back().c_str(); | |
84 } | |
85 | |
86 void SetupAnswerType(_OrthancPluginDatabaseAnswerType type) | |
87 { | |
88 if (answerType_ == _OrthancPluginDatabaseAnswerType_None) | |
89 { | |
90 answerType_ = type; | |
91 } | |
92 else if (answerType_ != type) | |
93 { | |
94 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
95 } | |
96 } | |
97 | |
98 public: | |
99 Output() : | |
100 answerType_(_OrthancPluginDatabaseAnswerType_None) | |
101 { | |
102 } | |
103 | |
104 void Clear() | |
105 { | |
106 // We don't systematically clear all the vectors, in order to | |
107 // avoid spending unnecessary time | |
108 | |
109 switch (answerType_) | |
110 { | |
111 case _OrthancPluginDatabaseAnswerType_None: | |
112 break; | |
113 | |
114 case _OrthancPluginDatabaseAnswerType_Attachment: | |
115 attachments_.clear(); | |
116 break; | |
117 | |
118 case _OrthancPluginDatabaseAnswerType_Change: | |
119 changes_.clear(); | |
120 break; | |
121 | |
122 case _OrthancPluginDatabaseAnswerType_DicomTag: | |
123 tags_.clear(); | |
124 break; | |
125 | |
126 case _OrthancPluginDatabaseAnswerType_ExportedResource: | |
127 exported_.clear(); | |
128 break; | |
129 | |
130 case _OrthancPluginDatabaseAnswerType_Int32: | |
131 integers32_.clear(); | |
132 break; | |
133 | |
134 case _OrthancPluginDatabaseAnswerType_Int64: | |
135 integers64_.clear(); | |
136 break; | |
137 | |
138 case _OrthancPluginDatabaseAnswerType_MatchingResource: | |
139 matches_.clear(); | |
140 break; | |
141 | |
142 case _OrthancPluginDatabaseAnswerType_Metadata: | |
143 metadata_.clear(); | |
144 break; | |
145 | |
146 case _OrthancPluginDatabaseAnswerType_String: | |
147 stringAnswers_.clear(); | |
148 break; | |
149 | |
150 default: | |
151 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
152 } | |
153 | |
154 answerType_ = _OrthancPluginDatabaseAnswerType_None; | |
155 stringsStore_.clear(); | |
156 events_.clear(); | |
157 | |
158 assert(attachments_.empty()); | |
159 assert(changes_.empty()); | |
160 assert(tags_.empty()); | |
161 assert(exported_.empty()); | |
162 assert(events_.empty()); | |
163 assert(integers32_.empty()); | |
164 assert(integers64_.empty()); | |
165 assert(matches_.empty()); | |
166 assert(metadata_.empty()); | |
167 assert(stringAnswers_.empty()); | |
168 } | |
169 | |
170 | |
171 OrthancPluginErrorCode ReadAnswersCount(uint32_t& target) const | |
172 { | |
173 switch (answerType_) | |
174 { | |
175 case _OrthancPluginDatabaseAnswerType_None: | |
176 target = static_cast<uint32_t>(0); | |
177 break; | |
178 | |
179 case _OrthancPluginDatabaseAnswerType_Attachment: | |
180 target = static_cast<uint32_t>(attachments_.size()); | |
181 break; | |
182 | |
183 case _OrthancPluginDatabaseAnswerType_Change: | |
184 target = static_cast<uint32_t>(changes_.size()); | |
185 break; | |
186 | |
187 case _OrthancPluginDatabaseAnswerType_DicomTag: | |
188 target = static_cast<uint32_t>(tags_.size()); | |
189 break; | |
190 | |
191 case _OrthancPluginDatabaseAnswerType_ExportedResource: | |
192 target = static_cast<uint32_t>(exported_.size()); | |
193 break; | |
194 | |
195 case _OrthancPluginDatabaseAnswerType_Int32: | |
196 target = static_cast<uint32_t>(integers32_.size()); | |
197 break; | |
198 | |
199 case _OrthancPluginDatabaseAnswerType_Int64: | |
200 target = static_cast<uint32_t>(integers64_.size()); | |
201 break; | |
202 | |
203 case _OrthancPluginDatabaseAnswerType_MatchingResource: | |
204 target = static_cast<uint32_t>(matches_.size()); | |
205 break; | |
206 | |
207 case _OrthancPluginDatabaseAnswerType_Metadata: | |
208 target = static_cast<uint32_t>(metadata_.size()); | |
209 break; | |
210 | |
211 case _OrthancPluginDatabaseAnswerType_String: | |
212 target = static_cast<uint32_t>(stringAnswers_.size()); | |
213 break; | |
214 | |
215 default: | |
216 return OrthancPluginErrorCode_InternalError; | |
217 } | |
218 | |
219 return OrthancPluginErrorCode_Success; | |
220 } | |
221 | |
222 | |
223 OrthancPluginErrorCode ReadAnswerAttachment(OrthancPluginAttachment& target /* out */, | |
224 uint32_t index) const | |
225 { | |
226 if (index < attachments_.size()) | |
227 { | |
228 target = attachments_[index]; | |
229 return OrthancPluginErrorCode_Success; | |
230 } | |
231 else | |
232 { | |
233 return OrthancPluginErrorCode_ParameterOutOfRange; | |
234 } | |
235 } | |
236 | |
237 | |
238 OrthancPluginErrorCode ReadAnswerChange(OrthancPluginChange& target /* out */, | |
239 uint32_t index) const | |
240 { | |
241 if (index < changes_.size()) | |
242 { | |
243 target = changes_[index]; | |
244 return OrthancPluginErrorCode_Success; | |
245 } | |
246 else | |
247 { | |
248 return OrthancPluginErrorCode_ParameterOutOfRange; | |
249 } | |
250 } | |
251 | |
252 | |
253 OrthancPluginErrorCode ReadAnswerDicomTag(uint16_t& group, | |
254 uint16_t& element, | |
255 const char*& value, | |
256 uint32_t index) const | |
257 { | |
258 if (index < tags_.size()) | |
259 { | |
260 const OrthancPluginDicomTag& tag = tags_[index]; | |
261 group = tag.group; | |
262 element = tag.element; | |
263 value = tag.value; | |
264 return OrthancPluginErrorCode_Success; | |
265 } | |
266 else | |
267 { | |
268 return OrthancPluginErrorCode_ParameterOutOfRange; | |
269 } | |
270 } | |
271 | |
272 | |
273 OrthancPluginErrorCode ReadAnswerExportedResource(OrthancPluginExportedResource& target /* out */, | |
274 uint32_t index) const | |
275 { | |
276 if (index < exported_.size()) | |
277 { | |
278 target = exported_[index]; | |
279 return OrthancPluginErrorCode_Success; | |
280 } | |
281 else | |
282 { | |
283 return OrthancPluginErrorCode_ParameterOutOfRange; | |
284 } | |
285 } | |
286 | |
287 | |
288 OrthancPluginErrorCode ReadAnswerInt32(int32_t& target, | |
289 uint32_t index) const | |
290 { | |
291 if (index < integers32_.size()) | |
292 { | |
293 target = integers32_[index]; | |
294 return OrthancPluginErrorCode_Success; | |
295 } | |
296 else | |
297 { | |
298 return OrthancPluginErrorCode_ParameterOutOfRange; | |
299 } | |
300 } | |
301 | |
302 | |
303 OrthancPluginErrorCode ReadAnswerInt64(int64_t& target, | |
304 uint32_t index) const | |
305 { | |
306 if (index < integers64_.size()) | |
307 { | |
308 target = integers64_[index]; | |
309 return OrthancPluginErrorCode_Success; | |
310 } | |
311 else | |
312 { | |
313 return OrthancPluginErrorCode_ParameterOutOfRange; | |
314 } | |
315 } | |
316 | |
317 | |
318 OrthancPluginErrorCode ReadAnswerMatchingResource(OrthancPluginMatchingResource& target, | |
319 uint32_t index) const | |
320 { | |
321 if (index < matches_.size()) | |
322 { | |
323 target = matches_[index]; | |
324 return OrthancPluginErrorCode_Success; | |
325 } | |
326 else | |
327 { | |
328 return OrthancPluginErrorCode_ParameterOutOfRange; | |
329 } | |
330 } | |
331 | |
332 | |
333 OrthancPluginErrorCode ReadAnswerMetadata(int32_t& metadata, | |
334 const char*& value, | |
335 uint32_t index) const | |
336 { | |
337 if (index < metadata_.size()) | |
338 { | |
339 const Metadata& tmp = metadata_[index]; | |
340 metadata = tmp.metadata; | |
341 value = tmp.value; | |
342 return OrthancPluginErrorCode_Success; | |
343 } | |
344 else | |
345 { | |
346 return OrthancPluginErrorCode_ParameterOutOfRange; | |
347 } | |
348 } | |
349 | |
350 | |
351 OrthancPluginErrorCode ReadAnswerString(const char*& target, | |
352 uint32_t index) const | |
353 { | |
354 if (index < stringAnswers_.size()) | |
355 { | |
356 target = stringAnswers_[index].c_str(); | |
357 return OrthancPluginErrorCode_Success; | |
358 } | |
359 else | |
360 { | |
361 return OrthancPluginErrorCode_ParameterOutOfRange; | |
362 } | |
363 } | |
364 | |
365 | |
366 OrthancPluginErrorCode ReadEventsCount(uint32_t& target /* out */) const | |
367 { | |
368 target = static_cast<uint32_t>(events_.size()); | |
369 return OrthancPluginErrorCode_Success; | |
370 } | |
371 | |
372 | |
373 OrthancPluginErrorCode ReadEvent(OrthancPluginDatabaseEvent& event /* out */, | |
374 uint32_t index) const | |
375 { | |
376 if (index < events_.size()) | |
377 { | |
378 event = events_[index]; | |
379 return OrthancPluginErrorCode_Success; | |
380 } | |
381 else | |
382 { | |
383 return OrthancPluginErrorCode_ParameterOutOfRange; | |
384 } | |
385 } | |
386 | |
387 | |
388 virtual void SignalDeletedAttachment(const std::string& uuid, | |
389 int32_t contentType, | |
390 uint64_t uncompressedSize, | |
391 const std::string& uncompressedHash, | |
392 int32_t compressionType, | |
393 uint64_t compressedSize, | |
394 const std::string& compressedHash) ORTHANC_OVERRIDE | |
395 { | |
396 OrthancPluginDatabaseEvent event; | |
397 event.type = OrthancPluginDatabaseEventType_DeletedAttachment; | |
398 event.content.attachment.uuid = StoreString(uuid); | |
399 event.content.attachment.contentType = contentType; | |
400 event.content.attachment.uncompressedSize = uncompressedSize; | |
401 event.content.attachment.uncompressedHash = StoreString(uncompressedHash); | |
402 event.content.attachment.compressionType = compressionType; | |
403 event.content.attachment.compressedSize = compressedSize; | |
404 event.content.attachment.compressedHash = StoreString(compressedHash); | |
405 | |
406 events_.push_back(event); | |
407 } | |
408 | |
409 | |
410 virtual void SignalDeletedResource(const std::string& publicId, | |
411 OrthancPluginResourceType resourceType) ORTHANC_OVERRIDE | |
412 { | |
413 OrthancPluginDatabaseEvent event; | |
414 event.type = OrthancPluginDatabaseEventType_DeletedResource; | |
415 event.content.resource.level = resourceType; | |
416 event.content.resource.publicId = StoreString(publicId); | |
417 | |
418 events_.push_back(event); | |
419 } | |
420 | |
421 | |
422 virtual void SignalRemainingAncestor(const std::string& ancestorId, | |
423 OrthancPluginResourceType ancestorType) ORTHANC_OVERRIDE | |
424 { | |
425 OrthancPluginDatabaseEvent event; | |
426 event.type = OrthancPluginDatabaseEventType_RemainingAncestor; | |
427 event.content.resource.level = ancestorType; | |
428 event.content.resource.publicId = StoreString(ancestorId); | |
429 | |
430 events_.push_back(event); | |
431 } | |
432 | |
433 | |
434 virtual void AnswerAttachment(const std::string& uuid, | |
435 int32_t contentType, | |
436 uint64_t uncompressedSize, | |
437 const std::string& uncompressedHash, | |
438 int32_t compressionType, | |
439 uint64_t compressedSize, | |
440 const std::string& compressedHash) ORTHANC_OVERRIDE | |
441 { | |
442 SetupAnswerType(_OrthancPluginDatabaseAnswerType_Attachment); | |
443 | |
444 OrthancPluginAttachment attachment; | |
445 attachment.uuid = StoreString(uuid); | |
446 attachment.contentType = contentType; | |
447 attachment.uncompressedSize = uncompressedSize; | |
448 attachment.uncompressedHash = StoreString(uncompressedHash); | |
449 attachment.compressionType = compressionType; | |
450 attachment.compressedSize = compressedSize; | |
451 attachment.compressedHash = StoreString(compressedHash); | |
452 | |
453 attachments_.push_back(attachment); | |
454 } | |
455 | |
456 | |
457 virtual void AnswerChange(int64_t seq, | |
458 int32_t changeType, | |
459 OrthancPluginResourceType resourceType, | |
460 const std::string& publicId, | |
461 const std::string& date) ORTHANC_OVERRIDE | |
462 { | |
463 SetupAnswerType(_OrthancPluginDatabaseAnswerType_Change); | |
464 | |
465 OrthancPluginChange change; | |
466 change.seq = seq; | |
467 change.changeType = changeType; | |
468 change.resourceType = resourceType; | |
469 change.publicId = StoreString(publicId); | |
470 change.date = StoreString(date); | |
471 | |
472 changes_.push_back(change); | |
473 } | |
474 | |
475 | |
476 virtual void AnswerDicomTag(uint16_t group, | |
477 uint16_t element, | |
478 const std::string& value) ORTHANC_OVERRIDE | |
479 { | |
480 SetupAnswerType(_OrthancPluginDatabaseAnswerType_DicomTag); | |
481 | |
482 OrthancPluginDicomTag tag; | |
483 tag.group = group; | |
484 tag.element = element; | |
485 tag.value = StoreString(value); | |
486 | |
487 tags_.push_back(tag); | |
488 } | |
489 | |
490 | |
491 virtual void AnswerExportedResource(int64_t seq, | |
492 OrthancPluginResourceType resourceType, | |
493 const std::string& publicId, | |
494 const std::string& modality, | |
495 const std::string& date, | |
496 const std::string& patientId, | |
497 const std::string& studyInstanceUid, | |
498 const std::string& seriesInstanceUid, | |
499 const std::string& sopInstanceUid) ORTHANC_OVERRIDE | |
500 { | |
501 SetupAnswerType(_OrthancPluginDatabaseAnswerType_ExportedResource); | |
502 | |
503 OrthancPluginExportedResource exported; | |
504 exported.seq = seq; | |
505 exported.resourceType = resourceType; | |
506 exported.publicId = StoreString(publicId); | |
507 exported.modality = StoreString(modality); | |
508 exported.date = StoreString(date); | |
509 exported.patientId = StoreString(patientId); | |
510 exported.studyInstanceUid = StoreString(studyInstanceUid); | |
511 exported.seriesInstanceUid = StoreString(seriesInstanceUid); | |
512 exported.sopInstanceUid = StoreString(sopInstanceUid); | |
513 | |
514 exported_.push_back(exported); | |
515 } | |
516 | |
517 | |
518 virtual void AnswerMatchingResource(const std::string& resourceId) ORTHANC_OVERRIDE | |
519 { | |
520 SetupAnswerType(_OrthancPluginDatabaseAnswerType_MatchingResource); | |
521 | |
522 OrthancPluginMatchingResource match; | |
523 match.resourceId = StoreString(resourceId); | |
524 match.someInstanceId = NULL; | |
525 | |
526 matches_.push_back(match); | |
527 } | |
528 | |
529 | |
530 virtual void AnswerMatchingResource(const std::string& resourceId, | |
531 const std::string& someInstanceId) ORTHANC_OVERRIDE | |
532 { | |
533 SetupAnswerType(_OrthancPluginDatabaseAnswerType_MatchingResource); | |
534 | |
535 OrthancPluginMatchingResource match; | |
536 match.resourceId = StoreString(resourceId); | |
537 match.someInstanceId = StoreString(someInstanceId); | |
538 | |
539 matches_.push_back(match); | |
540 } | |
541 | |
542 | |
543 void AnswerIntegers32(const std::list<int32_t>& values) | |
544 { | |
545 SetupAnswerType(_OrthancPluginDatabaseAnswerType_Int32); | |
546 | |
547 integers32_.reserve(values.size()); | |
548 std::copy(std::begin(values), std::end(values), std::back_inserter(integers32_)); | |
549 } | |
550 | |
551 | |
552 void AnswerIntegers64(const std::list<int64_t>& values) | |
553 { | |
554 SetupAnswerType(_OrthancPluginDatabaseAnswerType_Int64); | |
555 | |
556 integers64_.reserve(values.size()); | |
557 std::copy(std::begin(values), std::end(values), std::back_inserter(integers64_)); | |
558 } | |
559 | |
560 | |
561 void AnswerInteger64(int64_t value) | |
562 { | |
563 SetupAnswerType(_OrthancPluginDatabaseAnswerType_Int64); | |
564 | |
565 integers64_.resize(1); | |
566 integers64_[0] = value; | |
567 } | |
568 | |
569 | |
570 void AnswerMetadata(int32_t metadata, | |
571 const std::string& value) | |
572 { | |
573 SetupAnswerType(_OrthancPluginDatabaseAnswerType_Metadata); | |
574 | |
575 Metadata tmp; | |
576 tmp.metadata = metadata; | |
577 tmp.value = StoreString(value); | |
578 | |
579 metadata_.push_back(tmp); | |
580 } | |
581 | |
582 | |
583 void AnswerStrings(const std::list<std::string>& values) | |
584 { | |
585 SetupAnswerType(_OrthancPluginDatabaseAnswerType_String); | |
586 | |
587 stringAnswers_.reserve(values.size()); | |
588 std::copy(std::begin(values), std::end(values), std::back_inserter(stringAnswers_)); | |
589 } | |
590 | |
591 | |
592 void AnswerString(const std::string& value) | |
593 { | |
594 SetupAnswerType(_OrthancPluginDatabaseAnswerType_String); | |
595 | |
596 if (stringAnswers_.empty()) | |
597 { | |
598 stringAnswers_.push_back(value); | |
599 } | |
600 else | |
601 { | |
602 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
603 } | |
604 } | |
605 }; | |
606 | |
607 | |
608 class Factory : public IDatabaseBackendOutput::IFactory | |
609 { | |
610 public: | |
611 Factory() | |
612 { | |
613 } | |
614 | |
615 virtual IDatabaseBackendOutput* CreateOutput() | |
616 { | |
617 return new Output; | |
618 } | |
619 }; | |
620 | |
621 | |
622 class Transaction : public boost::noncopyable | |
623 { | |
624 private: | |
625 boost::mutex::scoped_lock lock_; // TODO - REMOVE | |
626 IndexBackend& backend_; | |
627 std::unique_ptr<Output> output_; | |
628 | |
629 static boost::mutex& GetMutex() // TODO - REMOVE | |
630 { | |
631 static boost::mutex mutex_; | |
632 return mutex_; | |
633 } | |
634 | |
635 public: | |
636 Transaction(IndexBackend& backend) : | |
637 lock_(GetMutex()), | |
638 backend_(backend), | |
639 output_(new Output) | |
640 { | |
641 } | |
642 | |
643 ~Transaction() | |
644 { | |
645 } | |
646 | |
647 IndexBackend& GetBackend() const | |
648 { | |
649 return backend_; | |
650 } | |
651 | |
652 Output& GetOutput() const | |
653 { | |
654 return *output_; | |
655 } | |
656 | |
657 OrthancPluginContext* GetContext() const | |
658 { | |
659 return backend_.GetContext(); | |
660 } | |
661 }; | |
662 | |
663 | |
664 static OrthancPluginErrorCode ReadAnswersCount(OrthancPluginDatabaseTransaction* transaction, | |
665 uint32_t* target /* out */) | |
666 { | |
667 assert(target != NULL); | |
668 const Transaction& that = *reinterpret_cast<const Transaction*>(transaction); | |
669 return that.GetOutput().ReadAnswersCount(*target); | |
670 } | |
671 | |
672 | |
673 static OrthancPluginErrorCode ReadAnswerAttachment(OrthancPluginDatabaseTransaction* transaction, | |
674 OrthancPluginAttachment* target /* out */, | |
675 uint32_t index) | |
676 { | |
677 assert(target != NULL); | |
678 const Transaction& that = *reinterpret_cast<const Transaction*>(transaction); | |
679 return that.GetOutput().ReadAnswerAttachment(*target, index); | |
680 } | |
681 | |
682 | |
683 static OrthancPluginErrorCode ReadAnswerChange(OrthancPluginDatabaseTransaction* transaction, | |
684 OrthancPluginChange* target /* out */, | |
685 uint32_t index) | |
686 { | |
687 assert(target != NULL); | |
688 const Transaction& that = *reinterpret_cast<const Transaction*>(transaction); | |
689 return that.GetOutput().ReadAnswerChange(*target, index); | |
690 } | |
691 | |
692 | |
693 static OrthancPluginErrorCode ReadAnswerDicomTag(OrthancPluginDatabaseTransaction* transaction, | |
694 uint16_t* group, | |
695 uint16_t* element, | |
696 const char** value, | |
697 uint32_t index) | |
698 { | |
699 assert(group != NULL); | |
700 assert(element != NULL); | |
701 assert(value != NULL); | |
702 const Transaction& that = *reinterpret_cast<const Transaction*>(transaction); | |
703 return that.GetOutput().ReadAnswerDicomTag(*group, *element, *value, index); | |
704 } | |
705 | |
706 | |
707 static OrthancPluginErrorCode ReadAnswerExportedResource(OrthancPluginDatabaseTransaction* transaction, | |
708 OrthancPluginExportedResource* target /* out */, | |
709 uint32_t index) | |
710 { | |
711 assert(target != NULL); | |
712 const Transaction& that = *reinterpret_cast<const Transaction*>(transaction); | |
713 return that.GetOutput().ReadAnswerExportedResource(*target, index); | |
714 } | |
715 | |
716 | |
717 static OrthancPluginErrorCode ReadAnswerInt32(OrthancPluginDatabaseTransaction* transaction, | |
718 int32_t* target, | |
719 uint32_t index) | |
720 { | |
721 assert(target != NULL); | |
722 const Transaction& that = *reinterpret_cast<const Transaction*>(transaction); | |
723 return that.GetOutput().ReadAnswerInt32(*target, index); | |
724 } | |
725 | |
726 | |
727 static OrthancPluginErrorCode ReadAnswerInt64(OrthancPluginDatabaseTransaction* transaction, | |
728 int64_t* target, | |
729 uint32_t index) | |
730 { | |
731 assert(target != NULL); | |
732 const Transaction& that = *reinterpret_cast<const Transaction*>(transaction); | |
733 return that.GetOutput().ReadAnswerInt64(*target, index); | |
734 } | |
735 | |
736 | |
737 static OrthancPluginErrorCode ReadAnswerMatchingResource(OrthancPluginDatabaseTransaction* transaction, | |
738 OrthancPluginMatchingResource* target, | |
739 uint32_t index) | |
740 { | |
741 assert(target != NULL); | |
742 const Transaction& that = *reinterpret_cast<const Transaction*>(transaction); | |
743 return that.GetOutput().ReadAnswerMatchingResource(*target, index); | |
744 } | |
745 | |
746 | |
747 static OrthancPluginErrorCode ReadAnswerMetadata(OrthancPluginDatabaseTransaction* transaction, | |
748 int32_t* metadata, | |
749 const char** value, | |
750 uint32_t index) | |
751 { | |
752 assert(metadata != NULL); | |
753 assert(value != NULL); | |
754 const Transaction& that = *reinterpret_cast<const Transaction*>(transaction); | |
755 return that.GetOutput().ReadAnswerMetadata(*metadata, *value, index); | |
756 } | |
757 | |
758 | |
759 static OrthancPluginErrorCode ReadAnswerString(OrthancPluginDatabaseTransaction* transaction, | |
760 const char** target, | |
761 uint32_t index) | |
762 { | |
763 assert(target != NULL); | |
764 const Transaction& that = *reinterpret_cast<const Transaction*>(transaction); | |
765 return that.GetOutput().ReadAnswerString(*target, index); | |
766 } | |
767 | |
768 | |
769 static OrthancPluginErrorCode ReadEventsCount(OrthancPluginDatabaseTransaction* transaction, | |
770 uint32_t* target /* out */) | |
771 { | |
772 assert(target != NULL); | |
773 const Transaction& that = *reinterpret_cast<const Transaction*>(transaction); | |
774 return that.GetOutput().ReadEventsCount(*target); | |
775 } | |
776 | |
777 | |
778 static OrthancPluginErrorCode ReadEvent(OrthancPluginDatabaseTransaction* transaction, | |
779 OrthancPluginDatabaseEvent* event /* out */, | |
780 uint32_t index) | |
781 { | |
782 assert(event != NULL); | |
783 const Transaction& that = *reinterpret_cast<const Transaction*>(transaction); | |
784 return that.GetOutput().ReadEvent(*event, index); | |
785 } | |
786 | |
787 | |
788 static OrthancPluginErrorCode Open(void* database) | |
789 { | |
790 IndexBackend* backend = reinterpret_cast<IndexBackend*>(database); | |
791 | |
792 try | |
793 { | |
794 backend->Open(); | |
795 return OrthancPluginErrorCode_Success; | |
796 } | |
797 ORTHANC_PLUGINS_DATABASE_CATCH(backend->GetContext()); | |
798 } | |
799 | |
800 | |
801 static OrthancPluginErrorCode Close(void* database) | |
802 { | |
803 IndexBackend* backend = reinterpret_cast<IndexBackend*>(database); | |
804 | |
805 try | |
806 { | |
807 backend->Close(); | |
808 return OrthancPluginErrorCode_Success; | |
809 } | |
810 ORTHANC_PLUGINS_DATABASE_CATCH(backend->GetContext()); | |
811 } | |
812 | |
813 | |
814 static OrthancPluginErrorCode DestructDatabase(void* database) | |
815 { | |
816 // Nothing to delete, as this plugin uses a singleton to store backend | |
817 if (database == NULL) | |
818 { | |
819 return OrthancPluginErrorCode_InternalError; | |
820 } | |
821 else | |
822 { | |
823 return OrthancPluginErrorCode_Success; | |
824 } | |
825 } | |
826 | |
827 | |
828 static OrthancPluginErrorCode GetDatabaseVersion(void* database, | |
829 uint32_t* version) | |
830 { | |
831 IndexBackend* backend = reinterpret_cast<IndexBackend*>(database); | |
832 | |
833 try | |
834 { | |
835 *version = backend->GetDatabaseVersion(); | |
836 return OrthancPluginErrorCode_Success; | |
837 } | |
838 ORTHANC_PLUGINS_DATABASE_CATCH(backend->GetContext()); | |
839 } | |
840 | |
841 | |
842 static OrthancPluginErrorCode UpgradeDatabase(void* database, | |
843 OrthancPluginStorageArea* storageArea, | |
844 uint32_t targetVersion) | |
845 { | |
846 IndexBackend* backend = reinterpret_cast<IndexBackend*>(database); | |
847 | |
848 try | |
849 { | |
850 backend->UpgradeDatabase(targetVersion, storageArea); | |
851 return OrthancPluginErrorCode_Success; | |
852 } | |
853 ORTHANC_PLUGINS_DATABASE_CATCH(backend->GetContext()); | |
854 } | |
855 | |
856 | |
857 static OrthancPluginErrorCode StartTransaction(void* database, | |
858 OrthancPluginDatabaseTransaction** target /* out */, | |
859 OrthancPluginDatabaseTransactionType type) | |
860 { | |
861 IndexBackend* backend = reinterpret_cast<IndexBackend*>(database); | |
862 | |
863 try | |
864 { | |
865 std::unique_ptr<Transaction> transaction(new Transaction(*backend)); | |
866 | |
867 switch (type) | |
868 { | |
869 case OrthancPluginDatabaseTransactionType_ReadOnly: | |
870 backend->StartTransaction(TransactionType_ReadOnly); | |
871 break; | |
872 | |
873 case OrthancPluginDatabaseTransactionType_ReadWrite: | |
874 backend->StartTransaction(TransactionType_ReadWrite); | |
875 break; | |
876 | |
877 default: | |
878 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
879 } | |
880 | |
881 *target = reinterpret_cast<OrthancPluginDatabaseTransaction*>(transaction.release()); | |
882 | |
883 return OrthancPluginErrorCode_Success; | |
884 } | |
885 ORTHANC_PLUGINS_DATABASE_CATCH(backend->GetContext()); | |
886 } | |
887 | |
888 | |
889 static OrthancPluginErrorCode DestructTransaction(OrthancPluginDatabaseTransaction* transaction) | |
890 { | |
891 if (transaction == NULL) | |
892 { | |
893 return OrthancPluginErrorCode_NullPointer; | |
894 } | |
895 else | |
896 { | |
897 delete reinterpret_cast<Transaction*>(transaction); | |
898 return OrthancPluginErrorCode_Success; | |
899 } | |
900 } | |
901 | |
902 | |
903 static OrthancPluginErrorCode Rollback(OrthancPluginDatabaseTransaction* transaction) | |
904 { | |
905 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
906 | |
907 try | |
908 { | |
909 t->GetOutput().Clear(); | |
910 t->GetBackend().RollbackTransaction(); | |
911 return OrthancPluginErrorCode_Success; | |
912 } | |
913 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
914 } | |
915 | |
916 | |
917 static OrthancPluginErrorCode Commit(OrthancPluginDatabaseTransaction* transaction, | |
918 int64_t fileSizeDelta /* TODO - not used? */) | |
919 { | |
920 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
921 | |
922 try | |
923 { | |
924 t->GetOutput().Clear(); | |
925 t->GetBackend().CommitTransaction(); | |
926 return OrthancPluginErrorCode_Success; | |
927 } | |
928 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
929 } | |
930 | |
931 | |
932 static OrthancPluginErrorCode AddAttachment(OrthancPluginDatabaseTransaction* transaction, | |
933 int64_t id, | |
934 const OrthancPluginAttachment* attachment) | |
935 { | |
936 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
937 | |
938 try | |
939 { | |
940 t->GetOutput().Clear(); | |
941 t->GetBackend().AddAttachment(id, *attachment); | |
942 return OrthancPluginErrorCode_Success; | |
943 } | |
944 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
945 } | |
946 | |
947 | |
948 static OrthancPluginErrorCode ClearChanges(OrthancPluginDatabaseTransaction* transaction) | |
949 { | |
950 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
951 | |
952 try | |
953 { | |
954 t->GetOutput().Clear(); | |
955 t->GetBackend().ClearChanges(); | |
956 return OrthancPluginErrorCode_Success; | |
957 } | |
958 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
959 } | |
960 | |
961 | |
962 static OrthancPluginErrorCode ClearExportedResources(OrthancPluginDatabaseTransaction* transaction) | |
963 { | |
964 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
965 | |
966 try | |
967 { | |
968 t->GetOutput().Clear(); | |
969 t->GetBackend().ClearExportedResources(); | |
970 return OrthancPluginErrorCode_Success; | |
971 } | |
972 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
973 } | |
974 | |
975 | |
976 static OrthancPluginErrorCode ClearMainDicomTags(OrthancPluginDatabaseTransaction* transaction, | |
977 int64_t resourceId) | |
978 { | |
979 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
980 | |
981 try | |
982 { | |
983 t->GetOutput().Clear(); | |
984 t->GetBackend().ClearMainDicomTags(resourceId); | |
985 return OrthancPluginErrorCode_Success; | |
986 } | |
987 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
988 } | |
989 | |
990 | |
991 static OrthancPluginErrorCode CreateInstance(OrthancPluginDatabaseTransaction* transaction, | |
992 OrthancPluginCreateInstanceResult* target /* out */, | |
993 const char* hashPatient, | |
994 const char* hashStudy, | |
995 const char* hashSeries, | |
996 const char* hashInstance) | |
997 { | |
998 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
999 | |
1000 try | |
1001 { | |
1002 t->GetOutput().Clear(); | |
1003 | |
1004 if (t->GetBackend().HasCreateInstance()) | |
1005 { | |
1006 t->GetBackend().CreateInstance(*target, hashPatient, hashStudy, hashSeries, hashInstance); | |
1007 } | |
1008 else | |
1009 { | |
1010 t->GetBackend().CreateInstanceGeneric(*target, hashPatient, hashStudy, hashSeries, hashInstance); | |
1011 } | |
1012 | |
1013 return OrthancPluginErrorCode_Success; | |
1014 } | |
1015 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1016 } | |
1017 | |
1018 | |
1019 static OrthancPluginErrorCode DeleteAttachment(OrthancPluginDatabaseTransaction* transaction, | |
1020 int64_t id, | |
1021 int32_t contentType) | |
1022 { | |
1023 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1024 | |
1025 try | |
1026 { | |
1027 t->GetOutput().Clear(); | |
1028 t->GetBackend().DeleteAttachment(t->GetOutput(), id, contentType); | |
1029 return OrthancPluginErrorCode_Success; | |
1030 } | |
1031 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1032 } | |
1033 | |
1034 | |
1035 static OrthancPluginErrorCode DeleteMetadata(OrthancPluginDatabaseTransaction* transaction, | |
1036 int64_t id, | |
1037 int32_t metadataType) | |
1038 { | |
1039 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1040 | |
1041 try | |
1042 { | |
1043 t->GetOutput().Clear(); | |
1044 t->GetBackend().DeleteMetadata(id, metadataType); | |
1045 return OrthancPluginErrorCode_Success; | |
1046 } | |
1047 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1048 } | |
1049 | |
1050 | |
1051 static OrthancPluginErrorCode DeleteResource(OrthancPluginDatabaseTransaction* transaction, | |
1052 int64_t id) | |
1053 { | |
1054 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1055 | |
1056 try | |
1057 { | |
1058 t->GetOutput().Clear(); | |
1059 t->GetBackend().DeleteResource(t->GetOutput(), id); | |
1060 return OrthancPluginErrorCode_Success; | |
1061 } | |
1062 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1063 } | |
1064 | |
1065 | |
1066 static OrthancPluginErrorCode GetAllMetadata(OrthancPluginDatabaseTransaction* transaction, | |
1067 int64_t id) | |
1068 { | |
1069 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1070 | |
1071 try | |
1072 { | |
1073 t->GetOutput().Clear(); | |
1074 | |
1075 std::map<int32_t, std::string> values; | |
1076 t->GetBackend().GetAllMetadata(values, id); | |
1077 | |
1078 for (std::map<int32_t, std::string>::const_iterator it = values.begin(); it != values.end(); ++it) | |
1079 { | |
1080 t->GetOutput().AnswerMetadata(it->first, it->second); | |
1081 } | |
1082 | |
1083 return OrthancPluginErrorCode_Success; | |
1084 } | |
1085 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1086 } | |
1087 | |
1088 | |
1089 static OrthancPluginErrorCode GetAllPublicIds(OrthancPluginDatabaseTransaction* transaction, | |
1090 OrthancPluginResourceType resourceType) | |
1091 { | |
1092 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1093 | |
1094 try | |
1095 { | |
1096 t->GetOutput().Clear(); | |
1097 | |
1098 std::list<std::string> values; | |
1099 t->GetBackend().GetAllPublicIds(values, resourceType); | |
1100 t->GetOutput().AnswerStrings(values); | |
1101 | |
1102 return OrthancPluginErrorCode_Success; | |
1103 } | |
1104 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1105 } | |
1106 | |
1107 | |
1108 static OrthancPluginErrorCode GetAllPublicIdsWithLimit(OrthancPluginDatabaseTransaction* transaction, | |
1109 OrthancPluginResourceType resourceType, | |
1110 uint64_t since, | |
1111 uint64_t limit) | |
1112 { | |
1113 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1114 | |
1115 try | |
1116 { | |
1117 t->GetOutput().Clear(); | |
1118 | |
1119 std::list<std::string> values; | |
1120 t->GetBackend().GetAllPublicIds(values, resourceType, since, limit); | |
1121 t->GetOutput().AnswerStrings(values); | |
1122 | |
1123 return OrthancPluginErrorCode_Success; | |
1124 } | |
1125 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1126 } | |
1127 | |
1128 | |
1129 static OrthancPluginErrorCode GetChanges(OrthancPluginDatabaseTransaction* transaction, | |
1130 uint8_t* targetDone /* out */, | |
1131 int64_t since, | |
1132 uint32_t maxResults) | |
1133 { | |
1134 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1135 | |
1136 try | |
1137 { | |
1138 t->GetOutput().Clear(); | |
1139 | |
1140 bool done; | |
1141 t->GetBackend().GetChanges(t->GetOutput(), done, since, maxResults); | |
1142 *targetDone = (done ? 1 : 0); | |
1143 | |
1144 return OrthancPluginErrorCode_Success; | |
1145 } | |
1146 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1147 } | |
1148 | |
1149 | |
1150 static OrthancPluginErrorCode GetChildrenInternalId(OrthancPluginDatabaseTransaction* transaction, | |
1151 int64_t id) | |
1152 { | |
1153 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1154 | |
1155 try | |
1156 { | |
1157 t->GetOutput().Clear(); | |
1158 | |
1159 std::list<int64_t> values; | |
1160 t->GetBackend().GetChildrenInternalId(values, id); | |
1161 t->GetOutput().AnswerIntegers64(values); | |
1162 | |
1163 return OrthancPluginErrorCode_Success; | |
1164 } | |
1165 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1166 } | |
1167 | |
1168 | |
1169 static OrthancPluginErrorCode GetChildrenMetadata(OrthancPluginDatabaseTransaction* transaction, | |
1170 int64_t resourceId, | |
1171 int32_t metadata) | |
1172 { | |
1173 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1174 | |
1175 try | |
1176 { | |
1177 t->GetOutput().Clear(); | |
1178 | |
1179 std::list<std::string> values; | |
1180 t->GetBackend().GetChildrenMetadata(values, resourceId, metadata); | |
1181 t->GetOutput().AnswerStrings(values); | |
1182 | |
1183 return OrthancPluginErrorCode_Success; | |
1184 } | |
1185 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1186 } | |
1187 | |
1188 | |
1189 static OrthancPluginErrorCode GetChildrenPublicId(OrthancPluginDatabaseTransaction* transaction, | |
1190 int64_t id) | |
1191 { | |
1192 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1193 | |
1194 try | |
1195 { | |
1196 t->GetOutput().Clear(); | |
1197 | |
1198 std::list<std::string> values; | |
1199 t->GetBackend().GetChildrenPublicId(values, id); | |
1200 t->GetOutput().AnswerStrings(values); | |
1201 | |
1202 return OrthancPluginErrorCode_Success; | |
1203 } | |
1204 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1205 } | |
1206 | |
1207 | |
1208 static OrthancPluginErrorCode GetExportedResources(OrthancPluginDatabaseTransaction* transaction, | |
1209 uint8_t* targetDone /* out */, | |
1210 int64_t since, | |
1211 uint32_t maxResults) | |
1212 { | |
1213 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1214 | |
1215 try | |
1216 { | |
1217 t->GetOutput().Clear(); | |
1218 | |
1219 bool done; | |
1220 t->GetBackend().GetExportedResources(t->GetOutput(), done, since, maxResults); | |
1221 *targetDone = (done ? 1 : 0); | |
1222 | |
1223 return OrthancPluginErrorCode_Success; | |
1224 } | |
1225 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1226 } | |
1227 | |
1228 | |
1229 static OrthancPluginErrorCode GetLastChange(OrthancPluginDatabaseTransaction* transaction) | |
1230 { | |
1231 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1232 | |
1233 try | |
1234 { | |
1235 t->GetOutput().Clear(); | |
1236 t->GetBackend().GetLastChange(t->GetOutput()); | |
1237 return OrthancPluginErrorCode_Success; | |
1238 } | |
1239 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1240 } | |
1241 | |
1242 | |
1243 static OrthancPluginErrorCode GetLastChangeIndex(OrthancPluginDatabaseTransaction* transaction, | |
1244 int64_t* target) | |
1245 { | |
1246 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1247 | |
1248 try | |
1249 { | |
1250 t->GetOutput().Clear(); | |
1251 *target = t->GetBackend().GetLastChangeIndex(); | |
1252 return OrthancPluginErrorCode_Success; | |
1253 } | |
1254 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1255 } | |
1256 | |
1257 | |
1258 static OrthancPluginErrorCode GetLastExportedResource(OrthancPluginDatabaseTransaction* transaction) | |
1259 { | |
1260 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1261 | |
1262 try | |
1263 { | |
1264 t->GetOutput().Clear(); | |
1265 t->GetBackend().GetLastExportedResource(t->GetOutput()); | |
1266 return OrthancPluginErrorCode_Success; | |
1267 } | |
1268 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1269 } | |
1270 | |
1271 | |
1272 static OrthancPluginErrorCode GetMainDicomTags(OrthancPluginDatabaseTransaction* transaction, | |
1273 int64_t id) | |
1274 { | |
1275 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1276 | |
1277 try | |
1278 { | |
1279 t->GetOutput().Clear(); | |
1280 t->GetBackend().GetMainDicomTags(t->GetOutput(), id); | |
1281 return OrthancPluginErrorCode_Success; | |
1282 } | |
1283 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1284 } | |
1285 | |
1286 | |
1287 static OrthancPluginErrorCode GetPublicId(OrthancPluginDatabaseTransaction* transaction, | |
1288 int64_t id) | |
1289 { | |
1290 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1291 | |
1292 try | |
1293 { | |
1294 t->GetOutput().Clear(); | |
1295 t->GetOutput().AnswerString(t->GetBackend().GetPublicId(id)); | |
1296 return OrthancPluginErrorCode_Success; | |
1297 } | |
1298 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1299 } | |
1300 | |
1301 | |
1302 static OrthancPluginErrorCode GetResourcesCount(OrthancPluginDatabaseTransaction* transaction, | |
1303 uint64_t* target /* out */, | |
1304 OrthancPluginResourceType resourceType) | |
1305 { | |
1306 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1307 | |
1308 try | |
1309 { | |
1310 t->GetOutput().Clear(); | |
1311 *target = t->GetBackend().GetResourcesCount(resourceType); | |
1312 return OrthancPluginErrorCode_Success; | |
1313 } | |
1314 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1315 } | |
1316 | |
1317 | |
1318 static OrthancPluginErrorCode GetResourceType(OrthancPluginDatabaseTransaction* transaction, | |
1319 OrthancPluginResourceType* target /* out */, | |
1320 uint64_t resourceId) | |
1321 { | |
1322 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1323 | |
1324 try | |
1325 { | |
1326 t->GetOutput().Clear(); | |
1327 *target = t->GetBackend().GetResourceType(resourceId); | |
1328 return OrthancPluginErrorCode_Success; | |
1329 } | |
1330 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1331 } | |
1332 | |
1333 | |
1334 static OrthancPluginErrorCode GetTotalCompressedSize(OrthancPluginDatabaseTransaction* transaction, | |
1335 uint64_t* target /* out */) | |
1336 { | |
1337 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1338 | |
1339 try | |
1340 { | |
1341 t->GetOutput().Clear(); | |
1342 *target = t->GetBackend().GetTotalCompressedSize(); | |
1343 return OrthancPluginErrorCode_Success; | |
1344 } | |
1345 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1346 } | |
1347 | |
1348 | |
1349 static OrthancPluginErrorCode GetTotalUncompressedSize(OrthancPluginDatabaseTransaction* transaction, | |
1350 uint64_t* target /* out */) | |
1351 { | |
1352 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1353 | |
1354 try | |
1355 { | |
1356 t->GetOutput().Clear(); | |
1357 *target = t->GetBackend().GetTotalUncompressedSize(); | |
1358 return OrthancPluginErrorCode_Success; | |
1359 } | |
1360 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1361 } | |
1362 | |
1363 | |
1364 static OrthancPluginErrorCode IsDiskSizeAbove(OrthancPluginDatabaseTransaction* transaction, | |
1365 uint8_t* target, | |
1366 uint64_t threshold) | |
1367 { | |
1368 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1369 | |
1370 try | |
1371 { | |
1372 t->GetOutput().Clear(); | |
1373 bool above = (t->GetBackend().GetTotalCompressedSize() >= threshold); | |
1374 *target = (above ? 1 : 0); | |
1375 return OrthancPluginErrorCode_Success; | |
1376 } | |
1377 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1378 } | |
1379 | |
1380 | |
1381 static OrthancPluginErrorCode IsExistingResource(OrthancPluginDatabaseTransaction* transaction, | |
1382 uint8_t* target, | |
1383 int64_t resourceId) | |
1384 { | |
1385 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1386 | |
1387 try | |
1388 { | |
1389 t->GetOutput().Clear(); | |
1390 bool exists = t->GetBackend().IsExistingResource(resourceId); | |
1391 *target = (exists ? 1 : 0); | |
1392 return OrthancPluginErrorCode_Success; | |
1393 } | |
1394 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1395 } | |
1396 | |
1397 | |
1398 static OrthancPluginErrorCode IsProtectedPatient(OrthancPluginDatabaseTransaction* transaction, | |
1399 uint8_t* target, | |
1400 int64_t resourceId) | |
1401 { | |
1402 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1403 | |
1404 try | |
1405 { | |
1406 t->GetOutput().Clear(); | |
1407 bool isProtected = t->GetBackend().IsProtectedPatient(resourceId); | |
1408 *target = (isProtected ? 1 : 0); | |
1409 return OrthancPluginErrorCode_Success; | |
1410 } | |
1411 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1412 } | |
1413 | |
1414 | |
1415 static OrthancPluginErrorCode ListAvailableAttachments(OrthancPluginDatabaseTransaction* transaction, | |
1416 int64_t resourceId) | |
1417 { | |
1418 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1419 | |
1420 try | |
1421 { | |
1422 t->GetOutput().Clear(); | |
1423 | |
1424 std::list<int32_t> values; | |
1425 t->GetBackend().ListAvailableAttachments(values, resourceId); | |
1426 t->GetOutput().AnswerIntegers32(values); | |
1427 return OrthancPluginErrorCode_Success; | |
1428 } | |
1429 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1430 } | |
1431 | |
1432 | |
1433 static OrthancPluginErrorCode LogChange(OrthancPluginDatabaseTransaction* transaction, | |
1434 int32_t changeType, | |
1435 int64_t resourceId, | |
1436 OrthancPluginResourceType resourceType, | |
1437 const char* date) | |
1438 { | |
1439 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1440 | |
1441 try | |
1442 { | |
1443 t->GetOutput().Clear(); | |
1444 t->GetBackend().LogChange(changeType, resourceId, resourceType, date); | |
1445 return OrthancPluginErrorCode_Success; | |
1446 } | |
1447 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1448 } | |
1449 | |
1450 | |
1451 static OrthancPluginErrorCode LogExportedResource(OrthancPluginDatabaseTransaction* transaction, | |
1452 OrthancPluginResourceType resourceType, | |
1453 const char* publicId, | |
1454 const char* modality, | |
1455 const char* date, | |
1456 const char* patientId, | |
1457 const char* studyInstanceUid, | |
1458 const char* seriesInstanceUid, | |
1459 const char* sopInstanceUid) | |
1460 { | |
1461 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1462 | |
1463 try | |
1464 { | |
1465 OrthancPluginExportedResource exported; | |
1466 exported.seq = 0; | |
1467 exported.resourceType = resourceType; | |
1468 exported.publicId = publicId; | |
1469 exported.modality = modality; | |
1470 exported.date = date; | |
1471 exported.patientId = patientId; | |
1472 exported.studyInstanceUid = studyInstanceUid; | |
1473 exported.seriesInstanceUid = seriesInstanceUid; | |
1474 exported.sopInstanceUid = sopInstanceUid; | |
1475 | |
1476 t->GetOutput().Clear(); | |
1477 t->GetBackend().LogExportedResource(exported); | |
1478 return OrthancPluginErrorCode_Success; | |
1479 } | |
1480 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1481 } | |
1482 | |
1483 | |
1484 static OrthancPluginErrorCode LookupAttachment(OrthancPluginDatabaseTransaction* transaction, | |
1485 int64_t resourceId, | |
1486 int32_t contentType) | |
1487 { | |
1488 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1489 | |
1490 try | |
1491 { | |
1492 t->GetOutput().Clear(); | |
1493 t->GetBackend().LookupAttachment(t->GetOutput(), resourceId, contentType); | |
1494 return OrthancPluginErrorCode_Success; | |
1495 } | |
1496 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1497 } | |
1498 | |
1499 | |
1500 static OrthancPluginErrorCode LookupGlobalProperty(OrthancPluginDatabaseTransaction* transaction, | |
1501 int32_t property) | |
1502 { | |
1503 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1504 | |
1505 try | |
1506 { | |
1507 t->GetOutput().Clear(); | |
1508 | |
1509 std::string s; | |
1510 if (t->GetBackend().LookupGlobalProperty(s, property)) | |
1511 { | |
1512 t->GetOutput().AnswerString(s); | |
1513 } | |
1514 | |
1515 return OrthancPluginErrorCode_Success; | |
1516 } | |
1517 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1518 } | |
1519 | |
1520 | |
1521 static OrthancPluginErrorCode LookupMetadata(OrthancPluginDatabaseTransaction* transaction, | |
1522 int64_t id, | |
1523 int32_t metadata) | |
1524 { | |
1525 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1526 | |
1527 try | |
1528 { | |
1529 t->GetOutput().Clear(); | |
1530 | |
1531 std::string s; | |
1532 if (t->GetBackend().LookupMetadata(s, id, metadata)) | |
1533 { | |
1534 t->GetOutput().AnswerString(s); | |
1535 } | |
1536 | |
1537 return OrthancPluginErrorCode_Success; | |
1538 } | |
1539 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1540 } | |
1541 | |
1542 | |
1543 static OrthancPluginErrorCode LookupParent(OrthancPluginDatabaseTransaction* transaction, | |
1544 int64_t id) | |
1545 { | |
1546 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1547 | |
1548 try | |
1549 { | |
1550 t->GetOutput().Clear(); | |
1551 | |
1552 int64_t parentId; | |
1553 if (t->GetBackend().LookupParent(parentId, id)) | |
1554 { | |
1555 t->GetOutput().AnswerInteger64(parentId); | |
1556 } | |
1557 | |
1558 return OrthancPluginErrorCode_Success; | |
1559 } | |
1560 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1561 } | |
1562 | |
1563 | |
1564 static OrthancPluginErrorCode LookupResource(OrthancPluginDatabaseTransaction* transaction, | |
1565 uint8_t* isExisting /* out */, | |
1566 int64_t* id /* out */, | |
1567 OrthancPluginResourceType* type /* out */, | |
1568 const char* publicId) | |
1569 { | |
1570 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1571 | |
1572 try | |
1573 { | |
1574 t->GetOutput().Clear(); | |
1575 | |
1576 if (t->GetBackend().LookupResource(*id, *type, publicId)) | |
1577 { | |
1578 *isExisting = 1; | |
1579 } | |
1580 else | |
1581 { | |
1582 *isExisting = 0; | |
1583 } | |
1584 | |
1585 return OrthancPluginErrorCode_Success; | |
1586 } | |
1587 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1588 } | |
1589 | |
1590 | |
1591 static OrthancPluginErrorCode LookupResources(OrthancPluginDatabaseTransaction* transaction, | |
1592 uint32_t constraintsCount, | |
1593 const OrthancPluginDatabaseConstraint* constraints, | |
1594 OrthancPluginResourceType queryLevel, | |
1595 uint32_t limit, | |
1596 uint8_t requestSomeInstanceId) | |
1597 { | |
1598 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1599 | |
1600 try | |
1601 { | |
1602 t->GetOutput().Clear(); | |
1603 | |
1604 std::vector<Orthanc::DatabaseConstraint> lookup; | |
1605 lookup.reserve(constraintsCount); | |
1606 | |
1607 for (uint32_t i = 0; i < constraintsCount; i++) | |
1608 { | |
1609 lookup.push_back(Orthanc::DatabaseConstraint(constraints[i])); | |
1610 } | |
1611 | |
1612 t->GetBackend().LookupResources(t->GetOutput(), lookup, queryLevel, limit, (requestSomeInstanceId != 0)); | |
1613 return OrthancPluginErrorCode_Success; | |
1614 } | |
1615 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1616 } | |
1617 | |
1618 | |
1619 static OrthancPluginErrorCode LookupResourceAndParent(OrthancPluginDatabaseTransaction* transaction, | |
1620 uint8_t* isExisting /* out */, | |
1621 int64_t* id /* out */, | |
1622 OrthancPluginResourceType* type /* out */, | |
1623 const char* publicId) | |
1624 { | |
1625 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1626 | |
1627 try | |
1628 { | |
1629 t->GetOutput().Clear(); | |
1630 | |
1631 std::string parent; | |
1632 if (t->GetBackend().LookupResourceAndParent(*id, *type, parent, publicId)) | |
1633 { | |
1634 *isExisting = 1; | |
1635 | |
1636 if (!parent.empty()) | |
1637 { | |
1638 t->GetOutput().AnswerString(parent); | |
1639 } | |
1640 } | |
1641 else | |
1642 { | |
1643 *isExisting = 0; | |
1644 } | |
1645 | |
1646 return OrthancPluginErrorCode_Success; | |
1647 } | |
1648 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1649 } | |
1650 | |
1651 | |
1652 static OrthancPluginErrorCode SelectPatientToRecycle(OrthancPluginDatabaseTransaction* transaction) | |
1653 { | |
1654 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1655 | |
1656 try | |
1657 { | |
1658 t->GetOutput().Clear(); | |
1659 | |
1660 int64_t id; | |
1661 if (t->GetBackend().SelectPatientToRecycle(id)) | |
1662 { | |
1663 t->GetOutput().AnswerInteger64(id); | |
1664 } | |
1665 | |
1666 return OrthancPluginErrorCode_Success; | |
1667 } | |
1668 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1669 } | |
1670 | |
1671 | |
1672 static OrthancPluginErrorCode SelectPatientToRecycle2(OrthancPluginDatabaseTransaction* transaction, | |
1673 int64_t patientIdToAvoid) | |
1674 { | |
1675 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1676 | |
1677 try | |
1678 { | |
1679 t->GetOutput().Clear(); | |
1680 | |
1681 int64_t id; | |
1682 if (t->GetBackend().SelectPatientToRecycle(id, patientIdToAvoid)) | |
1683 { | |
1684 t->GetOutput().AnswerInteger64(id); | |
1685 } | |
1686 | |
1687 return OrthancPluginErrorCode_Success; | |
1688 } | |
1689 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1690 } | |
1691 | |
1692 | |
1693 static OrthancPluginErrorCode SetGlobalProperty(OrthancPluginDatabaseTransaction* transaction, | |
1694 int32_t property, | |
1695 const char* value) | |
1696 { | |
1697 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1698 | |
1699 try | |
1700 { | |
1701 t->GetOutput().Clear(); | |
1702 t->GetBackend().SetGlobalProperty(property, value); | |
1703 return OrthancPluginErrorCode_Success; | |
1704 } | |
1705 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1706 } | |
1707 | |
1708 | |
1709 static OrthancPluginErrorCode SetMetadata(OrthancPluginDatabaseTransaction* transaction, | |
1710 int64_t id, | |
1711 int32_t metadata, | |
1712 const char* value) | |
1713 { | |
1714 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1715 | |
1716 try | |
1717 { | |
1718 t->GetOutput().Clear(); | |
1719 t->GetBackend().SetMetadata(id, metadata, value); | |
1720 return OrthancPluginErrorCode_Success; | |
1721 } | |
1722 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1723 } | |
1724 | |
1725 | |
1726 static OrthancPluginErrorCode SetProtectedPatient(OrthancPluginDatabaseTransaction* transaction, | |
1727 int64_t id, | |
1728 uint8_t isProtected) | |
1729 { | |
1730 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1731 | |
1732 try | |
1733 { | |
1734 t->GetOutput().Clear(); | |
1735 t->GetBackend().SetProtectedPatient(id, (isProtected != 0)); | |
1736 return OrthancPluginErrorCode_Success; | |
1737 } | |
1738 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1739 } | |
1740 | |
1741 | |
1742 static OrthancPluginErrorCode SetResourcesContent(OrthancPluginDatabaseTransaction* transaction, | |
1743 uint32_t countIdentifierTags, | |
1744 const OrthancPluginResourcesContentTags* identifierTags, | |
1745 uint32_t countMainDicomTags, | |
1746 const OrthancPluginResourcesContentTags* mainDicomTags, | |
1747 uint32_t countMetadata, | |
1748 const OrthancPluginResourcesContentMetadata* metadata) | |
1749 { | |
1750 Transaction* t = reinterpret_cast<Transaction*>(transaction); | |
1751 | |
1752 try | |
1753 { | |
1754 t->GetOutput().Clear(); | |
1755 t->GetBackend().SetResourcesContent(countIdentifierTags, identifierTags, | |
1756 countMainDicomTags, mainDicomTags, | |
1757 countMetadata, metadata); | |
1758 return OrthancPluginErrorCode_Success; | |
1759 } | |
1760 ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); | |
1761 } | |
1762 | |
1763 | |
1764 static void RegisterV3(IndexBackend& database) | |
1765 { | |
1766 OrthancPluginDatabaseBackendV3 params; | |
1767 memset(¶ms, 0, sizeof(params)); | |
1768 | |
1769 params.readAnswersCount = ReadAnswersCount; | |
1770 params.readAnswerAttachment = ReadAnswerAttachment; | |
1771 params.readAnswerChange = ReadAnswerChange; | |
1772 params.readAnswerDicomTag = ReadAnswerDicomTag; | |
1773 params.readAnswerExportedResource = ReadAnswerExportedResource; | |
1774 params.readAnswerInt32 = ReadAnswerInt32; | |
1775 params.readAnswerInt64 = ReadAnswerInt64; | |
1776 params.readAnswerMatchingResource = ReadAnswerMatchingResource; | |
1777 params.readAnswerMetadata = ReadAnswerMetadata; | |
1778 params.readAnswerString = ReadAnswerString; | |
1779 | |
1780 params.readEventsCount = ReadEventsCount; | |
1781 params.readEvent = ReadEvent; | |
1782 | |
1783 params.open = Open; | |
1784 params.close = Close; | |
1785 params.destructDatabase = DestructDatabase; | |
1786 params.getDatabaseVersion = GetDatabaseVersion; | |
1787 params.upgradeDatabase = UpgradeDatabase; | |
1788 params.startTransaction = StartTransaction; | |
1789 params.destructTransaction = DestructTransaction; | |
1790 params.rollback = Rollback; | |
1791 params.commit = Commit; | |
1792 | |
1793 params.addAttachment = AddAttachment; | |
1794 params.clearChanges = ClearChanges; | |
1795 params.clearExportedResources = ClearExportedResources; | |
1796 params.clearMainDicomTags = ClearMainDicomTags; | |
1797 params.createInstance = CreateInstance; | |
1798 params.deleteAttachment = DeleteAttachment; | |
1799 params.deleteMetadata = DeleteMetadata; | |
1800 params.deleteResource = DeleteResource; | |
1801 params.getAllMetadata = GetAllMetadata; | |
1802 params.getAllPublicIds = GetAllPublicIds; | |
1803 params.getAllPublicIdsWithLimit = GetAllPublicIdsWithLimit; | |
1804 params.getChanges = GetChanges; | |
1805 params.getChildrenInternalId = GetChildrenInternalId; | |
1806 params.getChildrenMetadata = GetChildrenMetadata; | |
1807 params.getChildrenPublicId = GetChildrenPublicId; | |
1808 params.getExportedResources = GetExportedResources; | |
1809 params.getLastChange = GetLastChange; | |
1810 params.getLastChangeIndex = GetLastChangeIndex; | |
1811 params.getLastExportedResource = GetLastExportedResource; | |
1812 params.getMainDicomTags = GetMainDicomTags; | |
1813 params.getPublicId = GetPublicId; | |
1814 params.getResourcesCount = GetResourcesCount; | |
1815 params.getResourceType = GetResourceType; | |
1816 params.getTotalCompressedSize = GetTotalCompressedSize; | |
1817 params.getTotalUncompressedSize = GetTotalUncompressedSize; | |
1818 params.isDiskSizeAbove = IsDiskSizeAbove; | |
1819 params.isExistingResource = IsExistingResource; | |
1820 params.isProtectedPatient = IsProtectedPatient; | |
1821 params.listAvailableAttachments = ListAvailableAttachments; | |
1822 params.logChange = LogChange; | |
1823 params.logExportedResource = LogExportedResource; | |
1824 params.lookupAttachment = LookupAttachment; | |
1825 params.lookupGlobalProperty = LookupGlobalProperty; | |
1826 params.lookupMetadata = LookupMetadata; | |
1827 params.lookupParent = LookupParent; | |
1828 params.lookupResource = LookupResource; | |
1829 params.lookupResources = LookupResources; | |
1830 params.lookupResourceAndParent = LookupResourceAndParent; | |
1831 params.selectPatientToRecycle = SelectPatientToRecycle; | |
1832 params.selectPatientToRecycle2 = SelectPatientToRecycle2; | |
1833 params.setGlobalProperty = SetGlobalProperty; | |
1834 params.setMetadata = SetMetadata; | |
1835 params.setProtectedPatient = SetProtectedPatient; | |
1836 params.setResourcesContent = SetResourcesContent; | |
1837 | |
1838 OrthancPluginContext* context = database.GetContext(); | |
1839 | |
1840 if (OrthancPluginRegisterDatabaseBackendV3(context, ¶ms, sizeof(params), &database) != OrthancPluginErrorCode_Success) | |
1841 { | |
1842 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Unable to register the database backend"); | |
1843 } | |
1844 | |
1845 database.SetOutputFactory(new Factory); | |
1846 } | |
1847 } | |
1848 | |
1849 # endif | |
1850 #endif | |
1851 | |
1852 | 30 |
1853 | 31 |
1854 extern "C" | 32 extern "C" |
1855 { | 33 { |
1856 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) | 34 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) |
1893 | 71 |
1894 #if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in Orthanc 1.3.1 | 72 #if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in Orthanc 1.3.1 |
1895 # if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 9, 2) | 73 # if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 9, 2) |
1896 if (OrthancPluginCheckVersionAdvanced(context, 1, 9, 2) == 1) | 74 if (OrthancPluginCheckVersionAdvanced(context, 1, 9, 2) == 1) |
1897 { | 75 { |
1898 RegisterV3(*backend_); | 76 OrthancDatabases::DatabaseBackendAdapterV3::Register(*backend_); |
1899 hasLoadedV3 = true; | 77 hasLoadedV3 = true; |
1900 } | 78 } |
1901 # endif | 79 # endif |
1902 #endif | 80 #endif |
1903 | 81 |