# HG changeset patch # User Alain Mazy # Date 1724941100 -7200 # Node ID bbeefd4567dcff1882267c4fe357be7e13139712 # Parent 9d6167ddcb35e8aa6ba259fd5b484206a91f2c00 removed graveyeards diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/EclipseCodingStyle.xml --- a/OrthancFramework/Resources/Graveyard/EclipseCodingStyle.xml Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,167 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/FromDcmtkBridge.cpp --- a/OrthancFramework/Resources/Graveyard/FromDcmtkBridge.cpp Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - **/ - - - DcmElement* FromDcmtkBridge::CreateElementForTag(const DicomTag& tag) - { - DcmTag key(tag.GetGroup(), tag.GetElement()); - - if (tag.IsPrivate()) - { - // This raises BitBucket issue 140 (Modifying private tags with - // REST API changes VR from LO to UN) - // https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=140 - LOG(WARNING) << "You are using DCMTK < 3.6.1: All the private tags " - "are considered as having a binary value representation"; - return new DcmOtherByteOtherWord(key); - } - else if (IsBinaryTag(key)) - { - return new DcmOtherByteOtherWord(key); - } - - switch (key.getEVR()) - { - // http://support.dcmtk.org/docs/dcvr_8h-source.html - - /** - * Binary types, handled above - **/ - -#if DCMTK_VERSION_NUMBER >= 361 - case EVR_OD: -#endif - -#if DCMTK_VERSION_NUMBER >= 362 - case EVR_OL: -#endif - - case EVR_OB: // other byte - case EVR_OF: // other float - case EVR_OW: // other word - case EVR_UN: // unknown value representation - case EVR_ox: // OB or OW depending on context - throw OrthancException(ErrorCode_InternalError); - - - /** - * String types. - * http://support.dcmtk.org/docs/classDcmByteString.html - **/ - - case EVR_AS: // age string - return new DcmAgeString(key); - - case EVR_AE: // application entity title - return new DcmApplicationEntity(key); - - case EVR_CS: // code string - return new DcmCodeString(key); - - case EVR_DA: // date string - return new DcmDate(key); - - case EVR_DT: // date time string - return new DcmDateTime(key); - - case EVR_DS: // decimal string - return new DcmDecimalString(key); - - case EVR_IS: // integer string - return new DcmIntegerString(key); - - case EVR_TM: // time string - return new DcmTime(key); - - case EVR_UI: // unique identifier - return new DcmUniqueIdentifier(key); - - case EVR_ST: // short text - return new DcmShortText(key); - - case EVR_LO: // long string - return new DcmLongString(key); - - case EVR_LT: // long text - return new DcmLongText(key); - - case EVR_UT: // unlimited text - return new DcmUnlimitedText(key); - - case EVR_SH: // short string - return new DcmShortString(key); - - case EVR_PN: // person name - return new DcmPersonName(key); - -#if DCMTK_VERSION_NUMBER >= 361 - case EVR_UC: // unlimited characters - return new DcmUnlimitedCharacters(key); -#endif - -#if DCMTK_VERSION_NUMBER >= 361 - case EVR_UR: // URI/URL - return new DcmUniversalResourceIdentifierOrLocator(key); -#endif - - - /** - * Numerical types - **/ - - case EVR_SL: // signed long - return new DcmSignedLong(key); - - case EVR_SS: // signed short - return new DcmSignedShort(key); - - case EVR_UL: // unsigned long - return new DcmUnsignedLong(key); - - case EVR_US: // unsigned short - return new DcmUnsignedShort(key); - - case EVR_FL: // float single-precision - return new DcmFloatingPointSingle(key); - - case EVR_FD: // float double-precision - return new DcmFloatingPointDouble(key); - - - /** - * Sequence types, should never occur at this point. - **/ - - case EVR_SQ: // sequence of items - throw OrthancException(ErrorCode_ParameterOutOfRange); - - - /** - * TODO - **/ - - case EVR_AT: // attribute tag - throw OrthancException(ErrorCode_NotImplemented); - - - /** - * Internal to DCMTK. - **/ - - case EVR_xs: // SS or US depending on context - case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) - case EVR_na: // na="not applicable", for data which has no VR - case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor - case EVR_item: // used internally for items - case EVR_metainfo: // used internally for meta info datasets - case EVR_dataset: // used internally for datasets - case EVR_fileFormat: // used internally for DICOM files - case EVR_dicomDir: // used internally for DICOMDIR objects - case EVR_dirRecord: // used internally for DICOMDIR records - case EVR_pixelSQ: // used internally for pixel sequences in a compressed image - case EVR_pixelItem: // used internally for pixel items in a compressed image - case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) - case EVR_PixelData: // used internally for uncompressed pixeld data - case EVR_OverlayData: // used internally for overlay data - case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR - default: - break; - } - - throw OrthancException(ErrorCode_InternalError); - } diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasks.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasks.h Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - **/ - - -#pragma once - -#include "../ICommand.h" - -#include -#include - -namespace Orthanc -{ - class BagOfTasks : public boost::noncopyable - { - private: - typedef std::list Tasks; - - Tasks tasks_; - - public: - ~BagOfTasks() - { - for (Tasks::iterator it = tasks_.begin(); it != tasks_.end(); ++it) - { - delete *it; - } - } - - ICommand* Pop() - { - ICommand* task = tasks_.front(); - tasks_.pop_front(); - return task; - } - - void Push(ICommand* task) // Takes ownership - { - if (task != NULL) - { - tasks_.push_back(task); - } - } - - size_t GetSize() const - { - return tasks_.size(); - } - - bool IsEmpty() const - { - return tasks_.empty(); - } - }; -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasksProcessor.cpp --- a/OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasksProcessor.cpp Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,268 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - **/ - - -#include "../PrecompiledHeaders.h" -#include "BagOfTasksProcessor.h" - -#include "../Logging.h" -#include "../OrthancException.h" - -#include - -namespace Orthanc -{ - class BagOfTasksProcessor::Task : public IDynamicObject - { - private: - uint64_t bag_; - std::auto_ptr command_; - - public: - Task(uint64_t bag, - ICommand* command) : - bag_(bag), - command_(command) - { - } - - bool Execute() - { - try - { - return command_->Execute(); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Exception while processing a bag of tasks: " << e.What(); - return false; - } - catch (std::runtime_error& e) - { - LOG(ERROR) << "Runtime exception while processing a bag of tasks: " << e.what(); - return false; - } - catch (...) - { - LOG(ERROR) << "Native exception while processing a bag of tasks"; - return false; - } - } - - uint64_t GetBag() - { - return bag_; - } - }; - - - void BagOfTasksProcessor::SignalProgress(Task& task, - Bag& bag) - { - assert(bag.done_ < bag.size_); - - bag.done_ += 1; - - if (bag.done_ == bag.size_) - { - exitStatus_[task.GetBag()] = (bag.status_ == BagStatus_Running); - bagFinished_.notify_all(); - } - } - - void BagOfTasksProcessor::Worker(BagOfTasksProcessor* that) - { - while (that->continue_) - { - std::auto_ptr obj(that->queue_.Dequeue(100)); - if (obj.get() != NULL) - { - Task& task = *dynamic_cast(obj.get()); - - { - boost::mutex::scoped_lock lock(that->mutex_); - - Bags::iterator bag = that->bags_.find(task.GetBag()); - assert(bag != that->bags_.end()); - assert(bag->second.done_ < bag->second.size_); - - if (bag->second.status_ != BagStatus_Running) - { - // Do not execute this task, as its parent bag of tasks - // has failed or is tagged as canceled - that->SignalProgress(task, bag->second); - continue; - } - } - - bool success = task.Execute(); - - { - boost::mutex::scoped_lock lock(that->mutex_); - - Bags::iterator bag = that->bags_.find(task.GetBag()); - assert(bag != that->bags_.end()); - - if (!success) - { - bag->second.status_ = BagStatus_Failed; - } - - that->SignalProgress(task, bag->second); - } - } - } - } - - - void BagOfTasksProcessor::Cancel(int64_t bag) - { - boost::mutex::scoped_lock lock(mutex_); - - Bags::iterator it = bags_.find(bag); - if (it != bags_.end()) - { - it->second.status_ = BagStatus_Canceled; - } - } - - - bool BagOfTasksProcessor::Join(int64_t bag) - { - boost::mutex::scoped_lock lock(mutex_); - - while (continue_) - { - ExitStatus::iterator it = exitStatus_.find(bag); - if (it == exitStatus_.end()) // The bag is still running - { - bagFinished_.wait(lock); - } - else - { - bool status = it->second; - exitStatus_.erase(it); - return status; - } - } - - return false; // The processor is stopping - } - - - float BagOfTasksProcessor::GetProgress(int64_t bag) - { - boost::mutex::scoped_lock lock(mutex_); - - Bags::const_iterator it = bags_.find(bag); - if (it == bags_.end()) - { - // The bag of tasks has finished - return 1.0f; - } - else - { - return (static_cast(it->second.done_) / - static_cast(it->second.size_)); - } - } - - - bool BagOfTasksProcessor::Handle::Join() - { - if (hasJoined_) - { - return status_; - } - else - { - status_ = that_.Join(bag_); - hasJoined_ = true; - return status_; - } - } - - - BagOfTasksProcessor::BagOfTasksProcessor(size_t countThreads) : - countBags_(0), - continue_(true) - { - if (countThreads == 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - threads_.resize(countThreads); - - for (size_t i = 0; i < threads_.size(); i++) - { - threads_[i] = new boost::thread(Worker, this); - } - } - - - BagOfTasksProcessor::~BagOfTasksProcessor() - { - continue_ = false; - - bagFinished_.notify_all(); // Wakes up all the pending "Join()" - - for (size_t i = 0; i < threads_.size(); i++) - { - if (threads_[i]) - { - if (threads_[i]->joinable()) - { - threads_[i]->join(); - } - - delete threads_[i]; - threads_[i] = NULL; - } - } - } - - - BagOfTasksProcessor::Handle* BagOfTasksProcessor::Submit(BagOfTasks& tasks) - { - if (tasks.GetSize() == 0) - { - return new Handle(*this, 0, true); - } - - boost::mutex::scoped_lock lock(mutex_); - - uint64_t id = countBags_; - countBags_ += 1; - - Bag bag(tasks.GetSize()); - bags_[id] = bag; - - while (!tasks.IsEmpty()) - { - queue_.Enqueue(new Task(id, tasks.Pop())); - } - - return new Handle(*this, id, false); - } -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasksProcessor.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasksProcessor.h Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,141 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - **/ - - -#pragma once - -#include "BagOfTasks.h" -#include "SharedMessageQueue.h" - -#include -#include - -namespace Orthanc -{ - class BagOfTasksProcessor : public boost::noncopyable - { - private: - enum BagStatus - { - BagStatus_Running, - BagStatus_Canceled, - BagStatus_Failed - }; - - - struct Bag - { - size_t size_; - size_t done_; - BagStatus status_; - - Bag() : - size_(0), - done_(0), - status_(BagStatus_Failed) - { - } - - explicit Bag(size_t size) : - size_(size), - done_(0), - status_(BagStatus_Running) - { - } - }; - - class Task; - - - typedef std::map Bags; - typedef std::map ExitStatus; - - SharedMessageQueue queue_; - - boost::mutex mutex_; - uint64_t countBags_; - Bags bags_; - std::vector threads_; - ExitStatus exitStatus_; - bool continue_; - - boost::condition_variable bagFinished_; - - static void Worker(BagOfTasksProcessor* that); - - void Cancel(int64_t bag); - - bool Join(int64_t bag); - - float GetProgress(int64_t bag); - - void SignalProgress(Task& task, - Bag& bag); - - public: - class Handle : public boost::noncopyable - { - friend class BagOfTasksProcessor; - - private: - BagOfTasksProcessor& that_; - uint64_t bag_; - bool hasJoined_; - bool status_; - - Handle(BagOfTasksProcessor& that, - uint64_t bag, - bool empty) : - that_(that), - bag_(bag), - hasJoined_(empty) - { - } - - public: - ~Handle() - { - Join(); - } - - void Cancel() - { - that_.Cancel(bag_); - } - - bool Join(); - - float GetProgress() - { - return that_.GetProgress(bag_); - } - }; - - - explicit BagOfTasksProcessor(size_t countThreads); - - ~BagOfTasksProcessor(); - - Handle* Submit(BagOfTasks& tasks); - }; -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/Multithreading/ICommand.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/ICommand.h Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - **/ - - -#pragma once - -#include "IDynamicObject.h" - -namespace Orthanc -{ - /** - * This class is the base class for the "Command" design pattern. - * http://en.wikipedia.org/wiki/Command_pattern - **/ - class ICommand : public IDynamicObject - { - public: - virtual bool Execute() = 0; - }; -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/Multithreading/ILockable.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/ILockable.h Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - **/ - - -#pragma once - -#include - -namespace Orthanc -{ - class ILockable : public boost::noncopyable - { - friend class Locker; - - protected: - virtual void Lock() = 0; - - virtual void Unlock() = 0; - - public: - virtual ~ILockable() - { - } - }; -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/Multithreading/Locker.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/Locker.h Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - **/ - - -#pragma once - -#include "ILockable.h" - -namespace Orthanc -{ - class Locker : public boost::noncopyable - { - private: - ILockable& lockable_; - - public: - Locker(ILockable& lockable) : lockable_(lockable) - { - lockable_.Lock(); - } - - virtual ~Locker() - { - lockable_.Unlock(); - } - }; -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/Multithreading/Mutex.cpp --- a/OrthancFramework/Resources/Graveyard/Multithreading/Mutex.cpp Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - **/ - - -#include "../PrecompiledHeaders.h" -#include "Mutex.h" - -#include "../OrthancException.h" - -#if defined(_WIN32) -#include -#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) -#include -#else -#error Support your platform here -#endif - -namespace Orthanc -{ -#if defined (_WIN32) - - struct Mutex::PImpl - { - CRITICAL_SECTION criticalSection_; - }; - - Mutex::Mutex() - { - pimpl_ = new PImpl; - ::InitializeCriticalSection(&pimpl_->criticalSection_); - } - - Mutex::~Mutex() - { - ::DeleteCriticalSection(&pimpl_->criticalSection_); - delete pimpl_; - } - - void Mutex::Lock() - { - ::EnterCriticalSection(&pimpl_->criticalSection_); - } - - void Mutex::Unlock() - { - ::LeaveCriticalSection(&pimpl_->criticalSection_); - } - - -#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) - - struct Mutex::PImpl - { - pthread_mutex_t mutex_; - }; - - Mutex::Mutex() - { - pimpl_ = new PImpl; - - if (pthread_mutex_init(&pimpl_->mutex_, NULL) != 0) - { - delete pimpl_; - throw OrthancException(ErrorCode_InternalError); - } - } - - Mutex::~Mutex() - { - pthread_mutex_destroy(&pimpl_->mutex_); - delete pimpl_; - } - - void Mutex::Lock() - { - if (pthread_mutex_lock(&pimpl_->mutex_) != 0) - { - throw OrthancException(ErrorCode_InternalError); - } - } - - void Mutex::Unlock() - { - if (pthread_mutex_unlock(&pimpl_->mutex_) != 0) - { - throw OrthancException(ErrorCode_InternalError); - } - } - -#else -#error Support your plateform here -#endif -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/Multithreading/Mutex.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/Mutex.h Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - **/ - - -#pragma once - -#include "ILockable.h" - -namespace Orthanc -{ - class Mutex : public ILockable - { - private: - struct PImpl; - - PImpl *pimpl_; - - protected: - virtual void Lock(); - - virtual void Unlock(); - - public: - Mutex(); - - ~Mutex(); - }; -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/Multithreading/ReaderWriterLock.cpp --- a/OrthancFramework/Resources/Graveyard/Multithreading/ReaderWriterLock.cpp Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - **/ - - -#include "../PrecompiledHeaders.h" -#include "ReaderWriterLock.h" - -#include - -namespace Orthanc -{ - namespace - { - // Anonymous namespace to avoid clashes between compilation - // modules. - - class ReaderLockable : public ILockable - { - private: - boost::shared_mutex& lock_; - - protected: - virtual void Lock() - { - lock_.lock_shared(); - } - - virtual void Unlock() - { - lock_.unlock_shared(); - } - - public: - explicit ReaderLockable(boost::shared_mutex& lock) : lock_(lock) - { - } - }; - - - class WriterLockable : public ILockable - { - private: - boost::shared_mutex& lock_; - - protected: - virtual void Lock() - { - lock_.lock(); - } - - virtual void Unlock() - { - lock_.unlock(); - } - - public: - explicit WriterLockable(boost::shared_mutex& lock) : lock_(lock) - { - } - }; - } - - struct ReaderWriterLock::PImpl - { - boost::shared_mutex lock_; - ReaderLockable reader_; - WriterLockable writer_; - - PImpl() : reader_(lock_), writer_(lock_) - { - } - }; - - - ReaderWriterLock::ReaderWriterLock() - { - pimpl_ = new PImpl; - } - - - ReaderWriterLock::~ReaderWriterLock() - { - delete pimpl_; - } - - - ILockable& ReaderWriterLock::ForReader() - { - return pimpl_->reader_; - } - - - ILockable& ReaderWriterLock::ForWriter() - { - return pimpl_->writer_; - } -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/Multithreading/ReaderWriterLock.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/ReaderWriterLock.h Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - **/ - - -#pragma once - -#include "ILockable.h" - -#include - -namespace Orthanc -{ - class ReaderWriterLock : public boost::noncopyable - { - private: - struct PImpl; - - PImpl *pimpl_; - - public: - ReaderWriterLock(); - - virtual ~ReaderWriterLock(); - - ILockable& ForReader(); - - ILockable& ForWriter(); - }; -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancFramework/Resources/Graveyard/TestTranscoding.cpp --- a/OrthancFramework/Resources/Graveyard/TestTranscoding.cpp Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,991 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - **/ - - - bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, - DcmFileFormat& dicom, - DicomTransferSyntax syntax) - { - E_TransferSyntax xfer; - if (!LookupDcmtkTransferSyntax(xfer, syntax)) - { - return false; - } - else if (!dicom.validateMetaInfo(xfer).good()) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot setup the transfer syntax to write a DICOM instance"); - } - else - { - return SaveToMemoryBufferInternal(buffer, dicom, xfer); - } - } - - - bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, - DcmFileFormat& dicom) - { - E_TransferSyntax xfer = dicom.getDataset()->getCurrentXfer(); - if (xfer == EXS_Unknown) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot write a DICOM instance with unknown transfer syntax"); - } - else if (!dicom.validateMetaInfo(xfer).good()) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot setup the transfer syntax to write a DICOM instance"); - } - else - { - return SaveToMemoryBufferInternal(buffer, dicom, xfer); - } - } - - - - - -#include -#include -#include - -#include "../Core/DicomParsing/Internals/DicomFrameIndex.h" - -namespace Orthanc -{ - class IParsedDicomImage : public boost::noncopyable - { - public: - virtual ~IParsedDicomImage() - { - } - - virtual DicomTransferSyntax GetTransferSyntax() = 0; - - virtual std::string GetSopClassUid() = 0; - - virtual std::string GetSopInstanceUid() = 0; - - virtual unsigned int GetFramesCount() = 0; - - // Can return NULL, for compressed transfer syntaxes - virtual ImageAccessor* GetUncompressedFrame(unsigned int frame) = 0; - - virtual void GetCompressedFrame(std::string& target, - unsigned int frame) = 0; - - virtual void WriteToMemoryBuffer(std::string& target) = 0; - }; - - - class IDicomImageReader : public boost::noncopyable - { - public: - virtual ~IDicomImageReader() - { - } - - virtual IParsedDicomImage* Read(const void* data, - size_t size) = 0; - - virtual IParsedDicomImage* Transcode(const void* data, - size_t size, - DicomTransferSyntax syntax, - bool allowNewSopInstanceUid) = 0; - }; - - - class DcmtkImageReader : public IDicomImageReader - { - private: - class Image : public IParsedDicomImage - { - private: - std::unique_ptr dicom_; - std::unique_ptr index_; - DicomTransferSyntax transferSyntax_; - std::string sopClassUid_; - std::string sopInstanceUid_; - - static std::string GetStringTag(DcmDataset& dataset, - const DcmTagKey& tag) - { - const char* value = NULL; - - if (!dataset.findAndGetString(tag, value).good() || - value == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Missing SOP class/instance UID in DICOM instance"); - } - else - { - return std::string(value); - } - } - - public: - Image(DcmFileFormat* dicom, - DicomTransferSyntax syntax) : - dicom_(dicom), - transferSyntax_(syntax) - { - if (dicom == NULL || - dicom_->getDataset() == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - - DcmDataset& dataset = *dicom_->getDataset(); - index_.reset(new DicomFrameIndex(dataset)); - - sopClassUid_ = GetStringTag(dataset, DCM_SOPClassUID); - sopInstanceUid_ = GetStringTag(dataset, DCM_SOPInstanceUID); - } - - virtual DicomTransferSyntax GetTransferSyntax() ORTHANC_OVERRIDE - { - return transferSyntax_; - } - - virtual std::string GetSopClassUid() ORTHANC_OVERRIDE - { - return sopClassUid_; - } - - virtual std::string GetSopInstanceUid() ORTHANC_OVERRIDE - { - return sopInstanceUid_; - } - - virtual unsigned int GetFramesCount() ORTHANC_OVERRIDE - { - return index_->GetFramesCount(); - } - - virtual void WriteToMemoryBuffer(std::string& target) ORTHANC_OVERRIDE - { - assert(dicom_.get() != NULL); - if (!FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, transferSyntax_)) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot write the DICOM instance to a memory buffer"); - } - } - - virtual ImageAccessor* GetUncompressedFrame(unsigned int frame) ORTHANC_OVERRIDE - { - assert(dicom_.get() != NULL && - dicom_->getDataset() != NULL); - return DicomImageDecoder::Decode(*dicom_->getDataset(), frame); - } - - virtual void GetCompressedFrame(std::string& target, - unsigned int frame) ORTHANC_OVERRIDE - { - assert(index_.get() != NULL); - index_->GetRawFrame(target, frame); - } - }; - - unsigned int lossyQuality_; - - static DicomTransferSyntax DetectTransferSyntax(DcmFileFormat& dicom) - { - if (dicom.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - DcmDataset& dataset = *dicom.getDataset(); - - E_TransferSyntax xfer = dataset.getCurrentXfer(); - if (xfer == EXS_Unknown) - { - dataset.updateOriginalXfer(); - xfer = dataset.getCurrentXfer(); - if (xfer == EXS_Unknown) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot determine the transfer syntax of the DICOM instance"); - } - } - - DicomTransferSyntax syntax; - if (FromDcmtkBridge::LookupOrthancTransferSyntax(syntax, xfer)) - { - return syntax; - } - else - { - throw OrthancException( - ErrorCode_BadFileFormat, - "Unsupported transfer syntax: " + boost::lexical_cast(xfer)); - } - } - - - static uint16_t GetBitsStored(DcmFileFormat& dicom) - { - if (dicom.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - uint16_t bitsStored; - if (dicom.getDataset()->findAndGetUint16(DCM_BitsStored, bitsStored).good()) - { - return bitsStored; - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Missing \"Bits Stored\" tag in DICOM instance"); - } - } - - - public: - DcmtkImageReader() : - lossyQuality_(90) - { - } - - void SetLossyQuality(unsigned int quality) - { - if (quality <= 0 || - quality > 100) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - lossyQuality_ = quality; - } - } - - unsigned int GetLossyQuality() const - { - return lossyQuality_; - } - - virtual IParsedDicomImage* Read(const void* data, - size_t size) - { - std::unique_ptr dicom(FromDcmtkBridge::LoadFromMemoryBuffer(data, size)); - if (dicom.get() == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - DicomTransferSyntax transferSyntax = DetectTransferSyntax(*dicom); - - return new Image(dicom.release(), transferSyntax); - } - - virtual IParsedDicomImage* Transcode(const void* data, - size_t size, - DicomTransferSyntax syntax, - bool allowNewSopInstanceUid) - { - std::unique_ptr dicom(FromDcmtkBridge::LoadFromMemoryBuffer(data, size)); - if (dicom.get() == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - const uint16_t bitsStored = GetBitsStored(*dicom); - - if (syntax == DetectTransferSyntax(*dicom)) - { - // No transcoding is needed - return new Image(dicom.release(), syntax); - } - - if (syntax == DicomTransferSyntax_LittleEndianImplicit && - FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_LittleEndianImplicit, NULL)) - { - return new Image(dicom.release(), syntax); - } - - if (syntax == DicomTransferSyntax_LittleEndianExplicit && - FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_LittleEndianExplicit, NULL)) - { - return new Image(dicom.release(), syntax); - } - - if (syntax == DicomTransferSyntax_BigEndianExplicit && - FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_BigEndianExplicit, NULL)) - { - return new Image(dicom.release(), syntax); - } - - if (syntax == DicomTransferSyntax_DeflatedLittleEndianExplicit && - FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL)) - { - return new Image(dicom.release(), syntax); - } - -#if ORTHANC_ENABLE_JPEG == 1 - if (syntax == DicomTransferSyntax_JPEGProcess1 && - allowNewSopInstanceUid && - bitsStored == 8) - { - DJ_RPLossy rpLossy(lossyQuality_); - - if (FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_JPEGProcess1, &rpLossy)) - { - return new Image(dicom.release(), syntax); - } - } -#endif - -#if ORTHANC_ENABLE_JPEG == 1 - if (syntax == DicomTransferSyntax_JPEGProcess2_4 && - allowNewSopInstanceUid && - bitsStored <= 12) - { - DJ_RPLossy rpLossy(lossyQuality_); - if (FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_JPEGProcess2_4, &rpLossy)) - { - return new Image(dicom.release(), syntax); - } - } -#endif - - //LOG(INFO) << "Unable to transcode DICOM image using the built-in reader"; - return NULL; - } - }; - - - - class IDicomTranscoder1 : public boost::noncopyable - { - public: - virtual ~IDicomTranscoder1() - { - } - - virtual DcmFileFormat& GetDicom() = 0; - - virtual DicomTransferSyntax GetTransferSyntax() = 0; - - virtual std::string GetSopClassUid() = 0; - - virtual std::string GetSopInstanceUid() = 0; - - virtual unsigned int GetFramesCount() = 0; - - virtual ImageAccessor* DecodeFrame(unsigned int frame) = 0; - - virtual void GetCompressedFrame(std::string& target, - unsigned int frame) = 0; - - // NB: Transcoding can change the value of "GetSopInstanceUid()" - // and "GetTransferSyntax()" if lossy compression is applied - virtual bool Transcode(std::string& target, - DicomTransferSyntax syntax, - bool allowNewSopInstanceUid) = 0; - - virtual void WriteToMemoryBuffer(std::string& target) = 0; - }; - - - class DcmtkTranscoder2 : public IDicomTranscoder1 - { - private: - std::unique_ptr dicom_; - std::unique_ptr index_; - DicomTransferSyntax transferSyntax_; - std::string sopClassUid_; - std::string sopInstanceUid_; - uint16_t bitsStored_; - unsigned int lossyQuality_; - - static std::string GetStringTag(DcmDataset& dataset, - const DcmTagKey& tag) - { - const char* value = NULL; - - if (!dataset.findAndGetString(tag, value).good() || - value == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Missing SOP class/instance UID in DICOM instance"); - } - else - { - return std::string(value); - } - } - - void Setup(DcmFileFormat* dicom) - { - lossyQuality_ = 90; - - dicom_.reset(dicom); - - if (dicom == NULL || - dicom_->getDataset() == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - - DcmDataset& dataset = *dicom_->getDataset(); - index_.reset(new DicomFrameIndex(dataset)); - - E_TransferSyntax xfer = dataset.getCurrentXfer(); - if (xfer == EXS_Unknown) - { - dataset.updateOriginalXfer(); - xfer = dataset.getCurrentXfer(); - if (xfer == EXS_Unknown) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot determine the transfer syntax of the DICOM instance"); - } - } - - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transferSyntax_, xfer)) - { - throw OrthancException( - ErrorCode_BadFileFormat, - "Unsupported transfer syntax: " + boost::lexical_cast(xfer)); - } - - if (!dataset.findAndGetUint16(DCM_BitsStored, bitsStored_).good()) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Missing \"Bits Stored\" tag in DICOM instance"); - } - - sopClassUid_ = GetStringTag(dataset, DCM_SOPClassUID); - sopInstanceUid_ = GetStringTag(dataset, DCM_SOPInstanceUID); - } - - public: - DcmtkTranscoder2(DcmFileFormat* dicom) // Takes ownership - { - Setup(dicom); - } - - DcmtkTranscoder2(const void* dicom, - size_t size) - { - Setup(FromDcmtkBridge::LoadFromMemoryBuffer(dicom, size)); - } - - void SetLossyQuality(unsigned int quality) - { - if (quality <= 0 || - quality > 100) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - lossyQuality_ = quality; - } - } - - unsigned int GetLossyQuality() const - { - return lossyQuality_; - } - - unsigned int GetBitsStored() const - { - return bitsStored_; - } - - virtual DcmFileFormat& GetDicom() - { - assert(dicom_ != NULL); - return *dicom_; - } - - virtual DicomTransferSyntax GetTransferSyntax() ORTHANC_OVERRIDE - { - return transferSyntax_; - } - - virtual std::string GetSopClassUid() ORTHANC_OVERRIDE - { - return sopClassUid_; - } - - virtual std::string GetSopInstanceUid() ORTHANC_OVERRIDE - { - return sopInstanceUid_; - } - - virtual unsigned int GetFramesCount() ORTHANC_OVERRIDE - { - return index_->GetFramesCount(); - } - - virtual void WriteToMemoryBuffer(std::string& target) ORTHANC_OVERRIDE - { - if (!FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_)) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot write the DICOM instance to a memory buffer"); - } - } - - virtual ImageAccessor* DecodeFrame(unsigned int frame) ORTHANC_OVERRIDE - { - assert(dicom_->getDataset() != NULL); - return DicomImageDecoder::Decode(*dicom_->getDataset(), frame); - } - - virtual void GetCompressedFrame(std::string& target, - unsigned int frame) ORTHANC_OVERRIDE - { - index_->GetRawFrame(target, frame); - } - - virtual bool Transcode(std::string& target, - DicomTransferSyntax syntax, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE - { - assert(dicom_ != NULL && - dicom_->getDataset() != NULL); - - if (syntax == GetTransferSyntax()) - { - printf("NO TRANSCODING\n"); - - // No change in the transfer syntax => simply serialize the current dataset - WriteToMemoryBuffer(target); - return true; - } - - printf(">> %d\n", bitsStored_); - - if (syntax == DicomTransferSyntax_LittleEndianImplicit && - FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) && - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) - { - transferSyntax_ = DicomTransferSyntax_LittleEndianImplicit; - return true; - } - - if (syntax == DicomTransferSyntax_LittleEndianExplicit && - FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) && - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) - { - transferSyntax_ = DicomTransferSyntax_LittleEndianExplicit; - return true; - } - - if (syntax == DicomTransferSyntax_BigEndianExplicit && - FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) && - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) - { - transferSyntax_ = DicomTransferSyntax_BigEndianExplicit; - return true; - } - - if (syntax == DicomTransferSyntax_DeflatedLittleEndianExplicit && - FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) && - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) - { - transferSyntax_ = DicomTransferSyntax_DeflatedLittleEndianExplicit; - return true; - } - -#if ORTHANC_ENABLE_JPEG == 1 - if (syntax == DicomTransferSyntax_JPEGProcess1 && - allowNewSopInstanceUid && - GetBitsStored() == 8) - { - DJ_RPLossy rpLossy(lossyQuality_); - - if (FromDcmtkBridge::Transcode(*dicom_, syntax, &rpLossy) && - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) - { - transferSyntax_ = DicomTransferSyntax_JPEGProcess1; - sopInstanceUid_ = GetStringTag(*dicom_->getDataset(), DCM_SOPInstanceUID); - return true; - } - } -#endif - -#if ORTHANC_ENABLE_JPEG == 1 - if (syntax == DicomTransferSyntax_JPEGProcess2_4 && - allowNewSopInstanceUid && - GetBitsStored() <= 12) - { - DJ_RPLossy rpLossy(lossyQuality_); - if (FromDcmtkBridge::Transcode(*dicom_, syntax, &rpLossy) && - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) - { - transferSyntax_ = DicomTransferSyntax_JPEGProcess2_4; - sopInstanceUid_ = GetStringTag(*dicom_->getDataset(), DCM_SOPInstanceUID); - return true; - } - } -#endif - - return false; - } - }; -} - - - - -#include - - -static void TestFile(const std::string& path) -{ - static unsigned int count = 0; - count++; - - - printf("** %s\n", path.c_str()); - - std::string s; - SystemToolbox::ReadFile(s, path); - - Orthanc::DcmtkTranscoder2 transcoder(s.c_str(), s.size()); - - /*if (transcoder.GetBitsStored() != 8) // TODO - return; */ - - { - char buf[1024]; - sprintf(buf, "/tmp/source-%06d.dcm", count); - printf(">> %s\n", buf); - Orthanc::SystemToolbox::WriteFile(s, buf); - } - - printf("[%s] [%s] [%s] %d %d\n", GetTransferSyntaxUid(transcoder.GetTransferSyntax()), - transcoder.GetSopClassUid().c_str(), transcoder.GetSopInstanceUid().c_str(), - transcoder.GetFramesCount(), transcoder.GetTransferSyntax()); - - for (size_t i = 0; i < transcoder.GetFramesCount(); i++) - { - std::string f; - transcoder.GetCompressedFrame(f, i); - - if (i == 0) - { - char buf[1024]; - sprintf(buf, "/tmp/frame-%06d.raw", count); - printf(">> %s\n", buf); - Orthanc::SystemToolbox::WriteFile(f, buf); - } - } - - { - std::string t; - transcoder.WriteToMemoryBuffer(t); - - Orthanc::DcmtkTranscoder2 transcoder2(t.c_str(), t.size()); - printf(">> %d %d ; %lu bytes\n", transcoder.GetTransferSyntax(), transcoder2.GetTransferSyntax(), t.size()); - } - - { - std::string a = transcoder.GetSopInstanceUid(); - DicomTransferSyntax b = transcoder.GetTransferSyntax(); - - DicomTransferSyntax syntax = DicomTransferSyntax_JPEGProcess2_4; - //DicomTransferSyntax syntax = DicomTransferSyntax_LittleEndianExplicit; - - std::string t; - bool ok = transcoder.Transcode(t, syntax, true); - printf("Transcoding: %d\n", ok); - - if (ok) - { - printf("[%s] => [%s]\n", a.c_str(), transcoder.GetSopInstanceUid().c_str()); - printf("[%s] => [%s]\n", GetTransferSyntaxUid(b), - GetTransferSyntaxUid(transcoder.GetTransferSyntax())); - - { - char buf[1024]; - sprintf(buf, "/tmp/transcoded-%06d.dcm", count); - printf(">> %s\n", buf); - Orthanc::SystemToolbox::WriteFile(t, buf); - } - - Orthanc::DcmtkTranscoder2 transcoder2(t.c_str(), t.size()); - printf(" => transcoded transfer syntax %d ; %lu bytes\n", transcoder2.GetTransferSyntax(), t.size()); - } - } - - printf("\n"); -} - -TEST(Toto, DISABLED_Transcode) -{ - //OFLog::configure(OFLogger::DEBUG_LOG_LEVEL); - - if (1) - { - const char* const PATH = "/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes"; - - for (boost::filesystem::directory_iterator it(PATH); - it != boost::filesystem::directory_iterator(); ++it) - { - if (boost::filesystem::is_regular_file(it->status())) - { - TestFile(it->path().string()); - } - } - } - - if (0) - { - TestFile("/home/jodogne/Subversion/orthanc-tests/Database/Multiframe.dcm"); - TestFile("/home/jodogne/Subversion/orthanc-tests/Database/Issue44/Monochrome1-Jpeg.dcm"); - } - - if (0) - { - TestFile("/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/1.2.840.10008.1.2.1.dcm"); - } -} - - -TEST(Toto, DISABLED_Transcode2) -{ - for (int i = 0; i <= DicomTransferSyntax_XML; i++) - { - DicomTransferSyntax a = (DicomTransferSyntax) i; - - std::string path = ("/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/" + - std::string(GetTransferSyntaxUid(a)) + ".dcm"); - if (Orthanc::SystemToolbox::IsRegularFile(path)) - { - printf("\n======= %s\n", GetTransferSyntaxUid(a)); - - std::string source; - Orthanc::SystemToolbox::ReadFile(source, path); - - DcmtkImageReader reader; - - { - std::unique_ptr image( - reader.Read(source.c_str(), source.size())); - ASSERT_TRUE(image.get() != NULL); - ASSERT_EQ(a, image->GetTransferSyntax()); - - std::string target; - image->WriteToMemoryBuffer(target); - } - - for (int j = 0; j <= DicomTransferSyntax_XML; j++) - { - DicomTransferSyntax b = (DicomTransferSyntax) j; - //if (a == b) continue; - - std::unique_ptr image( - reader.Transcode(source.c_str(), source.size(), b, true)); - if (image.get() != NULL) - { - printf("[%s] -> [%s]\n", GetTransferSyntaxUid(a), GetTransferSyntaxUid(b)); - - std::string target; - image->WriteToMemoryBuffer(target); - - char buf[1024]; - sprintf(buf, "/tmp/%s-%s.dcm", GetTransferSyntaxUid(a), GetTransferSyntaxUid(b)); - - SystemToolbox::WriteFile(target, buf); - } - else if (a != DicomTransferSyntax_JPEG2000 && - a != DicomTransferSyntax_JPEG2000LosslessOnly) - { - ASSERT_TRUE(b != DicomTransferSyntax_LittleEndianImplicit && - b != DicomTransferSyntax_LittleEndianExplicit && - b != DicomTransferSyntax_BigEndianExplicit && - b != DicomTransferSyntax_DeflatedLittleEndianExplicit); - } - } - } - } -} - - -#include "../Core/DicomNetworking/DicomAssociation.h" -#include "../Core/DicomNetworking/DicomControlUserConnection.h" -#include "../Core/DicomNetworking/DicomStoreUserConnection.h" - -TEST(Toto, DISABLED_DicomAssociation) -{ - DicomAssociationParameters params; - params.SetLocalApplicationEntityTitle("ORTHANC"); - params.SetRemoteApplicationEntityTitle("PACS"); - params.SetRemotePort(2001); - -#if 0 - DicomAssociation assoc; - assoc.ProposeGenericPresentationContext(UID_StorageCommitmentPushModelSOPClass); - assoc.ProposeGenericPresentationContext(UID_VerificationSOPClass); - assoc.ProposePresentationContext(UID_ComputedRadiographyImageStorage, - DicomTransferSyntax_JPEGProcess1); - assoc.ProposePresentationContext(UID_ComputedRadiographyImageStorage, - DicomTransferSyntax_JPEGProcess2_4); - assoc.ProposePresentationContext(UID_ComputedRadiographyImageStorage, - DicomTransferSyntax_JPEG2000); - - assoc.Open(params); - - int presID = ASC_findAcceptedPresentationContextID(&assoc.GetDcmtkAssociation(), UID_ComputedRadiographyImageStorage); - printf(">> %d\n", presID); - - std::map pc; - printf(">> %d\n", assoc.LookupAcceptedPresentationContext(pc, UID_ComputedRadiographyImageStorage)); - - for (std::map::const_iterator - it = pc.begin(); it != pc.end(); ++it) - { - printf("[%s] => %d\n", GetTransferSyntaxUid(it->first), it->second); - } -#else - { - DicomControlUserConnection assoc(params); - - try - { - printf(">> %d\n", assoc.Echo()); - } - catch (OrthancException&) - { - } - } - - params.SetRemoteApplicationEntityTitle("PACS"); - params.SetRemotePort(2000); - - { - DicomControlUserConnection assoc(params); - printf(">> %d\n", assoc.Echo()); - } - -#endif -} - -static void TestTranscode(DicomStoreUserConnection& scu, - const std::string& sopClassUid, - DicomTransferSyntax transferSyntax) -{ - std::set accepted; - - scu.LookupTranscoding(accepted, sopClassUid, transferSyntax); - if (accepted.empty()) - { - throw OrthancException(ErrorCode_NetworkProtocol, - "The SOP class is not supported by the remote modality"); - } - - { - unsigned int count = 0; - for (std::set::const_iterator - it = accepted.begin(); it != accepted.end(); ++it) - { - LOG(INFO) << "available for transcoding " << (count++) << ": " << sopClassUid - << " / " << GetTransferSyntaxUid(*it); - } - } - - if (accepted.find(transferSyntax) != accepted.end()) - { - printf("**** OK, without transcoding !! [%s]\n", GetTransferSyntaxUid(transferSyntax)); - } - else - { - // Transcoding - only in Orthanc >= 1.7.0 - - const DicomTransferSyntax uncompressed[] = { - DicomTransferSyntax_LittleEndianImplicit, // Default transfer syntax - DicomTransferSyntax_LittleEndianExplicit, - DicomTransferSyntax_BigEndianExplicit - }; - - bool found = false; - for (size_t i = 0; i < 3; i++) - { - if (accepted.find(uncompressed[i]) != accepted.end()) - { - printf("**** TRANSCODING to %s\n", GetTransferSyntaxUid(uncompressed[i])); - found = true; - break; - } - } - - if (!found) - { - printf("**** KO KO KO\n"); - } - } -} - - -TEST(Toto, DISABLED_Store) -{ - DicomAssociationParameters params; - params.SetLocalApplicationEntityTitle("ORTHANC"); - params.SetRemoteApplicationEntityTitle("STORESCP"); - params.SetRemotePort(2000); - - DicomStoreUserConnection assoc(params); - assoc.RegisterStorageClass(UID_MRImageStorage, DicomTransferSyntax_JPEGProcess1); - assoc.RegisterStorageClass(UID_MRImageStorage, DicomTransferSyntax_JPEGProcess2_4); - //assoc.RegisterStorageClass(UID_MRImageStorage, DicomTransferSyntax_LittleEndianExplicit); - - //assoc.SetUncompressedSyntaxesProposed(false); // Necessary for transcoding - assoc.SetCommonClassesProposed(false); - assoc.SetRetiredBigEndianProposed(true); - TestTranscode(assoc, UID_MRImageStorage, DicomTransferSyntax_LittleEndianExplicit); - TestTranscode(assoc, UID_MRImageStorage, DicomTransferSyntax_JPEG2000); - TestTranscode(assoc, UID_MRImageStorage, DicomTransferSyntax_JPEG2000); -} - - -TEST(Toto, DISABLED_Store2) -{ - DicomAssociationParameters params; - params.SetLocalApplicationEntityTitle("ORTHANC"); - params.SetRemoteApplicationEntityTitle("STORESCP"); - params.SetRemotePort(2000); - - DicomStoreUserConnection assoc(params); - //assoc.SetCommonClassesProposed(false); - assoc.SetRetiredBigEndianProposed(true); - - std::string s; - Orthanc::SystemToolbox::ReadFile(s, "/tmp/i/" + std::string(GetTransferSyntaxUid(DicomTransferSyntax_BigEndianExplicit)) +".dcm"); - - std::string c, i; - assoc.Store(c, i, s.c_str(), s.size()); - printf("[%s] [%s]\n", c.c_str(), i.c_str()); -} - diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupIdentifierQuery.cpp --- a/OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupIdentifierQuery.cpp Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,205 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "LookupIdentifierQuery.h" - -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../../Core/OrthancException.h" -#include "../ServerToolbox.h" -#include "SetOfResources.h" - -#include - - - -namespace Orthanc -{ - LookupIdentifierQuery::SingleConstraint:: - SingleConstraint(const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value) : - tag_(tag), - type_(type), - value_(ServerToolbox::NormalizeIdentifier(value)) - { - } - - - LookupIdentifierQuery::RangeConstraint:: - RangeConstraint(const DicomTag& tag, - const std::string& start, - const std::string& end) : - tag_(tag), - start_(ServerToolbox::NormalizeIdentifier(start)), - end_(ServerToolbox::NormalizeIdentifier(end)) - { - } - - - LookupIdentifierQuery::Disjunction::~Disjunction() - { - for (size_t i = 0; i < singleConstraints_.size(); i++) - { - delete singleConstraints_[i]; - } - - for (size_t i = 0; i < rangeConstraints_.size(); i++) - { - delete rangeConstraints_[i]; - } - } - - - void LookupIdentifierQuery::Disjunction::Add(const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value) - { - singleConstraints_.push_back(new SingleConstraint(tag, type, value)); - } - - - void LookupIdentifierQuery::Disjunction::AddRange(const DicomTag& tag, - const std::string& start, - const std::string& end) - { - rangeConstraints_.push_back(new RangeConstraint(tag, start, end)); - } - - - LookupIdentifierQuery::~LookupIdentifierQuery() - { - for (Disjunctions::iterator it = disjunctions_.begin(); - it != disjunctions_.end(); ++it) - { - delete *it; - } - } - - - bool LookupIdentifierQuery::IsIdentifier(const DicomTag& tag) - { - return ServerToolbox::IsIdentifier(tag, level_); - } - - - void LookupIdentifierQuery::AddConstraint(DicomTag tag, - IdentifierConstraintType type, - const std::string& value) - { - assert(IsIdentifier(tag)); - disjunctions_.push_back(new Disjunction); - disjunctions_.back()->Add(tag, type, value); - } - - - void LookupIdentifierQuery::AddRange(DicomTag tag, - const std::string& start, - const std::string& end) - { - assert(IsIdentifier(tag)); - disjunctions_.push_back(new Disjunction); - disjunctions_.back()->AddRange(tag, start, end); - } - - - LookupIdentifierQuery::Disjunction& LookupIdentifierQuery::AddDisjunction() - { - disjunctions_.push_back(new Disjunction); - return *disjunctions_.back(); - } - - - void LookupIdentifierQuery::Apply(std::list& result, - IDatabaseWrapper& database) - { - SetOfResources resources(database, level_); - Apply(resources, database); - - resources.Flatten(result); - } - - - void LookupIdentifierQuery::Apply(SetOfResources& result, - IDatabaseWrapper& database) - { - for (size_t i = 0; i < disjunctions_.size(); i++) - { - std::list a; - - for (size_t j = 0; j < disjunctions_[i]->GetSingleConstraintsCount(); j++) - { - const SingleConstraint& constraint = disjunctions_[i]->GetSingleConstraint(j); - std::list b; - database.LookupIdentifier(b, level_, constraint.GetTag(), - constraint.GetType(), constraint.GetValue()); - - a.splice(a.end(), b); - } - - for (size_t j = 0; j < disjunctions_[i]->GetRangeConstraintsCount(); j++) - { - const RangeConstraint& constraint = disjunctions_[i]->GetRangeConstraint(j); - std::list b; - database.LookupIdentifierRange(b, level_, constraint.GetTag(), - constraint.GetStart(), constraint.GetEnd()); - - a.splice(a.end(), b); - } - - result.Intersect(a); - } - } - - - void LookupIdentifierQuery::Print(std::ostream& s) const - { - s << "Constraint: " << std::endl; - for (Disjunctions::const_iterator - it = disjunctions_.begin(); it != disjunctions_.end(); ++it) - { - if (it == disjunctions_.begin()) - s << " "; - else - s << "OR "; - - for (size_t j = 0; j < (*it)->GetSingleConstraintsCount(); j++) - { - const SingleConstraint& c = (*it)->GetSingleConstraint(j); - s << FromDcmtkBridge::GetTagName(c.GetTag(), ""); - - switch (c.GetType()) - { - case IdentifierConstraintType_Equal: s << " == "; break; - case IdentifierConstraintType_SmallerOrEqual: s << " <= "; break; - case IdentifierConstraintType_GreaterOrEqual: s << " >= "; break; - case IdentifierConstraintType_Wildcard: s << " ~= "; break; - default: - s << " ? "; - } - - s << c.GetValue() << std::endl; - } - } - } -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupIdentifierQuery.h --- a/OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupIdentifierQuery.h Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,197 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../IDatabaseWrapper.h" - -#include "SetOfResources.h" - -#include -#include - -namespace Orthanc -{ - /** - * Primitive for wildcard matching, as defined in DICOM: - * http://dicom.nema.org/dicom/2013/output/chtml/part04/sect_C.2.html#sect_C.2.2.2.4 - * - * "Any occurrence of an "*" or a "?", then "*" shall match any - * sequence of characters (including a zero length value) and "?" - * shall match any single character. This matching is case - * sensitive, except for Attributes with an PN Value - * Representation (e.g., Patient Name (0010,0010))." - * - * Pay attention to the fact that "*" (resp. "?") generally - * corresponds to "%" (resp. "_") in primitive LIKE of SQL. The - * values "%", "_", "\" should in the user request should - * respectively be escaped as "\%", "\_" and "\\". - * - * This matching must be case sensitive: The special case of PN VR - * is taken into consideration by normalizing the query string in - * method "NormalizeIdentifier()". - **/ - - class LookupIdentifierQuery : public boost::noncopyable - { - // This class encodes a conjunction ("AND") of disjunctions. Each - // disjunction represents an "OR" of several constraints. - - public: - class SingleConstraint - { - private: - DicomTag tag_; - IdentifierConstraintType type_; - std::string value_; - - public: - SingleConstraint(const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value); - - const DicomTag& GetTag() const - { - return tag_; - } - - IdentifierConstraintType GetType() const - { - return type_; - } - - const std::string& GetValue() const - { - return value_; - } - }; - - - class RangeConstraint - { - private: - DicomTag tag_; - std::string start_; - std::string end_; - - public: - RangeConstraint(const DicomTag& tag, - const std::string& start, - const std::string& end); - - const DicomTag& GetTag() const - { - return tag_; - } - - const std::string& GetStart() const - { - return start_; - } - - const std::string& GetEnd() const - { - return end_; - } - }; - - - class Disjunction : public boost::noncopyable - { - private: - std::vector singleConstraints_; - std::vector rangeConstraints_; - - public: - ~Disjunction(); - - void Add(const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value); - - void AddRange(const DicomTag& tag, - const std::string& start, - const std::string& end); - - size_t GetSingleConstraintsCount() const - { - return singleConstraints_.size(); - } - - const SingleConstraint& GetSingleConstraint(size_t i) const - { - return *singleConstraints_[i]; - } - - size_t GetRangeConstraintsCount() const - { - return rangeConstraints_.size(); - } - - const RangeConstraint& GetRangeConstraint(size_t i) const - { - return *rangeConstraints_[i]; - } - }; - - - private: - typedef std::vector Disjunctions; - - ResourceType level_; - Disjunctions disjunctions_; - - public: - LookupIdentifierQuery(ResourceType level) : level_(level) - { - } - - ~LookupIdentifierQuery(); - - bool IsIdentifier(const DicomTag& tag); - - void AddConstraint(DicomTag tag, - IdentifierConstraintType type, - const std::string& value); - - void AddRange(DicomTag tag, - const std::string& start, - const std::string& end); - - Disjunction& AddDisjunction(); - - ResourceType GetLevel() const - { - return level_; - } - - // The database must be locked - void Apply(std::list& result, - IDatabaseWrapper& database); - - void Apply(SetOfResources& result, - IDatabaseWrapper& database); - - void Print(std::ostream& s) const; - }; -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupResource.cpp --- a/OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupResource.cpp Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,469 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "LookupResource.h" - -#include "../../Core/OrthancException.h" -#include "../../Core/FileStorage/StorageAccessor.h" -#include "../ServerToolbox.h" -#include "../../Core/DicomParsing/FromDcmtkBridge.h" - - -namespace Orthanc -{ - static bool DoesDicomMapMatch(const DicomMap& dicom, - const DicomTag& tag, - const IFindConstraint& constraint) - { - const DicomValue* value = dicom.TestAndGetValue(tag); - - return (value != NULL && - !value->IsNull() && - !value->IsBinary() && - constraint.Match(value->GetContent())); - } - - - LookupResource::Level::Level(ResourceType level) : level_(level) - { - const DicomTag* tags = NULL; - size_t size; - - ServerToolbox::LoadIdentifiers(tags, size, level); - - for (size_t i = 0; i < size; i++) - { - identifiers_.insert(tags[i]); - } - - DicomMap::LoadMainDicomTags(tags, size, level); - - for (size_t i = 0; i < size; i++) - { - if (identifiers_.find(tags[i]) == identifiers_.end()) - { - mainTags_.insert(tags[i]); - } - } - } - - LookupResource::Level::~Level() - { - for (Constraints::iterator it = mainTagsConstraints_.begin(); - it != mainTagsConstraints_.end(); ++it) - { - delete it->second; - } - - for (Constraints::iterator it = identifiersConstraints_.begin(); - it != identifiersConstraints_.end(); ++it) - { - delete it->second; - } - } - - bool LookupResource::Level::Add(const DicomTag& tag, - std::auto_ptr& constraint) - { - if (identifiers_.find(tag) != identifiers_.end()) - { - if (level_ == ResourceType_Patient) - { - // The filters on the patient level must be cloned to the study level - identifiersConstraints_[tag] = constraint->Clone(); - } - else - { - identifiersConstraints_[tag] = constraint.release(); - } - - return true; - } - else if (mainTags_.find(tag) != mainTags_.end()) - { - if (level_ == ResourceType_Patient) - { - // The filters on the patient level must be cloned to the study level - mainTagsConstraints_[tag] = constraint->Clone(); - } - else - { - mainTagsConstraints_[tag] = constraint.release(); - } - - return true; - } - else - { - // This is not a main DICOM tag - return false; - } - } - - - bool LookupResource::Level::IsMatch(const DicomMap& dicom) const - { - for (Constraints::const_iterator it = identifiersConstraints_.begin(); - it != identifiersConstraints_.end(); ++it) - { - assert(it->second != NULL); - - if (!DoesDicomMapMatch(dicom, it->first, *it->second)) - { - return false; - } - } - - for (Constraints::const_iterator it = mainTagsConstraints_.begin(); - it != mainTagsConstraints_.end(); ++it) - { - assert(it->second != NULL); - - if (!DoesDicomMapMatch(dicom, it->first, *it->second)) - { - return false; - } - } - - return true; - } - - - LookupResource::LookupResource(ResourceType level) : level_(level) - { - switch (level) - { - case ResourceType_Patient: - levels_[ResourceType_Patient] = new Level(ResourceType_Patient); - break; - - case ResourceType_Instance: - levels_[ResourceType_Instance] = new Level(ResourceType_Instance); - // Do not add "break" here - - case ResourceType_Series: - levels_[ResourceType_Series] = new Level(ResourceType_Series); - // Do not add "break" here - - case ResourceType_Study: - levels_[ResourceType_Study] = new Level(ResourceType_Study); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - - LookupResource::~LookupResource() - { - for (Levels::iterator it = levels_.begin(); - it != levels_.end(); ++it) - { - delete it->second; - } - - for (Constraints::iterator it = unoptimizedConstraints_.begin(); - it != unoptimizedConstraints_.end(); ++it) - { - delete it->second; - } - } - - - - bool LookupResource::AddInternal(ResourceType level, - const DicomTag& tag, - std::auto_ptr& constraint) - { - Levels::iterator it = levels_.find(level); - if (it != levels_.end()) - { - if (it->second->Add(tag, constraint)) - { - return true; - } - } - - return false; - } - - - void LookupResource::Add(const DicomTag& tag, - IFindConstraint* constraint) - { - std::auto_ptr c(constraint); - - if (!AddInternal(ResourceType_Patient, tag, c) && - !AddInternal(ResourceType_Study, tag, c) && - !AddInternal(ResourceType_Series, tag, c) && - !AddInternal(ResourceType_Instance, tag, c)) - { - unoptimizedConstraints_[tag] = c.release(); - } - } - - - static bool Match(const DicomMap& tags, - const DicomTag& tag, - const IFindConstraint& constraint) - { - const DicomValue* value = tags.TestAndGetValue(tag); - - if (value == NULL || - value->IsNull() || - value->IsBinary()) - { - return false; - } - else - { - return constraint.Match(value->GetContent()); - } - } - - - void LookupResource::Level::Apply(SetOfResources& candidates, - IDatabaseWrapper& database) const - { - // First, use the indexed identifiers - LookupIdentifierQuery query(level_); - - for (Constraints::const_iterator it = identifiersConstraints_.begin(); - it != identifiersConstraints_.end(); ++it) - { - it->second->Setup(query, it->first); - } - - query.Apply(candidates, database); - - /*{ - query.Print(std::cout); - std::list source; - candidates.Flatten(source); - printf("=> %d\n", source.size()); - }*/ - - // Secondly, filter using the main DICOM tags - if (!identifiersConstraints_.empty() || - !mainTagsConstraints_.empty()) - { - std::list source; - candidates.Flatten(source); - candidates.Clear(); - - std::list filtered; - for (std::list::const_iterator candidate = source.begin(); - candidate != source.end(); ++candidate) - { - DicomMap tags; - database.GetMainDicomTags(tags, *candidate); - - bool match = true; - - // Re-apply the identifier constraints, as their "Setup" - // method is less restrictive than their "Match" method - for (Constraints::const_iterator it = identifiersConstraints_.begin(); - match && it != identifiersConstraints_.end(); ++it) - { - if (!Match(tags, it->first, *it->second)) - { - match = false; - } - } - - for (Constraints::const_iterator it = mainTagsConstraints_.begin(); - match && it != mainTagsConstraints_.end(); ++it) - { - if (!Match(tags, it->first, *it->second)) - { - match = false; - } - } - - if (match) - { - filtered.push_back(*candidate); - } - } - - candidates.Intersect(filtered); - } - } - - - - bool LookupResource::IsMatch(const DicomMap& dicom) const - { - for (Levels::const_iterator it = levels_.begin(); it != levels_.end(); ++it) - { - if (!it->second->IsMatch(dicom)) - { - return false; - } - } - - for (Constraints::const_iterator it = unoptimizedConstraints_.begin(); - it != unoptimizedConstraints_.end(); ++it) - { - assert(it->second != NULL); - - if (!DoesDicomMapMatch(dicom, it->first, *it->second)) - { - return false; - } - } - - return true; - } - - - void LookupResource::ApplyLevel(SetOfResources& candidates, - ResourceType level, - IDatabaseWrapper& database) const - { - Levels::const_iterator it = levels_.find(level); - if (it != levels_.end()) - { - it->second->Apply(candidates, database); - } - - if (level == ResourceType_Study && - modalitiesInStudy_.get() != NULL) - { - // There is a constraint on the "ModalitiesInStudy" DICOM - // extension. Check out whether one child series has one of the - // allowed modalities - std::list allStudies, matchingStudies; - candidates.Flatten(allStudies); - - for (std::list::const_iterator - study = allStudies.begin(); study != allStudies.end(); ++study) - { - std::list childrenSeries; - database.GetChildrenInternalId(childrenSeries, *study); - - for (std::list::const_iterator - series = childrenSeries.begin(); series != childrenSeries.end(); ++series) - { - DicomMap tags; - database.GetMainDicomTags(tags, *series); - - const DicomValue* value = tags.TestAndGetValue(DICOM_TAG_MODALITY); - if (value != NULL && - !value->IsNull() && - !value->IsBinary()) - { - if (modalitiesInStudy_->Match(value->GetContent())) - { - matchingStudies.push_back(*study); - break; - } - } - } - } - - candidates.Intersect(matchingStudies); - } - } - - - void LookupResource::FindCandidates(std::list& result, - IDatabaseWrapper& database) const - { - ResourceType startingLevel; - if (level_ == ResourceType_Patient) - { - startingLevel = ResourceType_Patient; - } - else - { - startingLevel = ResourceType_Study; - } - - SetOfResources candidates(database, startingLevel); - - switch (level_) - { - case ResourceType_Patient: - ApplyLevel(candidates, ResourceType_Patient, database); - break; - - case ResourceType_Study: - ApplyLevel(candidates, ResourceType_Study, database); - break; - - case ResourceType_Series: - ApplyLevel(candidates, ResourceType_Study, database); - candidates.GoDown(); - ApplyLevel(candidates, ResourceType_Series, database); - break; - - case ResourceType_Instance: - ApplyLevel(candidates, ResourceType_Study, database); - candidates.GoDown(); - ApplyLevel(candidates, ResourceType_Series, database); - candidates.GoDown(); - ApplyLevel(candidates, ResourceType_Instance, database); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - candidates.Flatten(result); - } - - - void LookupResource::SetModalitiesInStudy(const std::string& modalities) - { - modalitiesInStudy_.reset(new ListConstraint(true /* case sensitive */)); - - std::vector items; - Toolbox::TokenizeString(items, modalities, '\\'); - - for (size_t i = 0; i < items.size(); i++) - { - modalitiesInStudy_->AddAllowedValue(items[i]); - } - } - - - void LookupResource::AddDicomConstraint(const DicomTag& tag, - const std::string& dicomQuery, - bool caseSensitive) - { - // http://www.itk.org/Wiki/DICOM_QueryRetrieve_Explained - // http://dicomiseasy.blogspot.be/2012/01/dicom-queryretrieve-part-i.html - if (tag == DICOM_TAG_MODALITIES_IN_STUDY) - { - SetModalitiesInStudy(dicomQuery); - } - else - { - Add(tag, IFindConstraint::ParseDicomConstraint(tag, dicomQuery, caseSensitive)); - } - } - -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupResource.h --- a/OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupResource.h Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ListConstraint.h" -#include "SetOfResources.h" - -#include - -namespace Orthanc -{ - class LookupResource : public boost::noncopyable - { - private: - typedef std::map Constraints; - - class Level - { - private: - ResourceType level_; - std::set identifiers_; - std::set mainTags_; - Constraints identifiersConstraints_; - Constraints mainTagsConstraints_; - - public: - Level(ResourceType level); - - ~Level(); - - bool Add(const DicomTag& tag, - std::auto_ptr& constraint); - - void Apply(SetOfResources& candidates, - IDatabaseWrapper& database) const; - - bool IsMatch(const DicomMap& dicom) const; - }; - - typedef std::map Levels; - - ResourceType level_; - Levels levels_; - Constraints unoptimizedConstraints_; // Constraints on non-main DICOM tags - std::auto_ptr modalitiesInStudy_; - - bool AddInternal(ResourceType level, - const DicomTag& tag, - std::auto_ptr& constraint); - - void ApplyLevel(SetOfResources& candidates, - ResourceType level, - IDatabaseWrapper& database) const; - - public: - LookupResource(ResourceType level); - - ~LookupResource(); - - ResourceType GetLevel() const - { - return level_; - } - - void SetModalitiesInStudy(const std::string& modalities); - - void Add(const DicomTag& tag, - IFindConstraint* constraint); // Takes ownership - - void AddDicomConstraint(const DicomTag& tag, - const std::string& dicomQuery, - bool caseSensitive); - - void FindCandidates(std::list& result, - IDatabaseWrapper& database) const; - - bool HasOnlyMainDicomTags() const - { - return unoptimizedConstraints_.empty(); - } - - bool IsMatch(const DicomMap& dicom) const; - }; -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancServer/Resources/Graveyard/DatabasePluginSample/CMakeLists.txt --- a/OrthancServer/Resources/Graveyard/DatabasePluginSample/CMakeLists.txt Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -project(SampleDatabasePlugin) - -# Parameters of the build -SET(SAMPLE_DATABASE_VERSION "0.0" CACHE STRING "Version of the plugin") -SET(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)") -SET(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages") -SET(STANDALONE_BUILD ON) - -# Advanced parameters to fine-tune linking against system libraries -SET(USE_SYSTEM_BOOST ON CACHE BOOL "Use the system version of Boost") -SET(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp") -SET(USE_SYSTEM_SQLITE ON CACHE BOOL "Use the system version of SQLite") - -include(${CMAKE_SOURCE_DIR}/../../../Plugins/Samples/Common/OrthancPlugins.cmake) - -include(${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake) -set(ENABLE_SQLITE ON) -include(${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake) - -EmbedResources( - --system-exception # Use "std::runtime_error" instead of "OrthancException" for embedded resources - PREPARE_DATABASE ${CMAKE_SOURCE_DIR}/../../../Sources/Database/PrepareDatabase.sql - ) - -message("Setting the version of the plugin to ${SAMPLE_DATABASE_VERSION}") - -add_definitions( - -DORTHANC_SQLITE_STANDALONE=1 - -DORTHANC_ENABLE_PLUGINS=1 - -DORTHANC_SANDBOXED=0 - -DSAMPLE_DATABASE_VERSION="${SAMPLE_DATABASE_VERSION}" - ) - -add_library(SampleDatabase SHARED - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/DicomFormat/DicomArray.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/DicomFormat/DicomMap.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/DicomFormat/DicomTag.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/DicomFormat/DicomValue.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/Enumerations.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/SQLite/Connection.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/SQLite/FunctionContext.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/SQLite/Statement.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/SQLite/StatementId.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/SQLite/StatementReference.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/SQLite/Transaction.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/Toolbox.cpp - ${CMAKE_SOURCE_DIR}/../../../Plugins/Engine/PluginsEnumerations.cpp - - Database.cpp - Plugin.cpp - DatabaseWrapperBase.cpp - - ${BOOST_SOURCES} - ${JSONCPP_SOURCES} - ${SQLITE_SOURCES} - ${AUTOGENERATED_SOURCES} - ) - -set_target_properties(SampleDatabase PROPERTIES - VERSION ${SAMPLE_DATABASE_VERSION} - SOVERSION ${SAMPLE_DATABASE_VERSION}) - -install( - TARGETS SampleDatabase - RUNTIME DESTINATION lib # Destination for Windows - LIBRARY DESTINATION share/orthanc/plugins # Destination for Linux - ) diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancServer/Resources/Graveyard/DatabasePluginSample/Database.cpp --- a/OrthancServer/Resources/Graveyard/DatabasePluginSample/Database.cpp Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,555 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "Database.h" - -#include "../../../../OrthancFramework/Sources/DicomFormat/DicomArray.h" - -#include -#include - - -namespace Internals -{ - class SignalFileDeleted : public Orthanc::SQLite::IScalarFunction - { - private: - OrthancPlugins::DatabaseBackendOutput& output_; - - public: - SignalFileDeleted(OrthancPlugins::DatabaseBackendOutput& output) : output_(output) - { - } - - virtual const char* GetName() const - { - return "SignalFileDeleted"; - } - - virtual unsigned int GetCardinality() const - { - return 7; - } - - virtual void Compute(Orthanc::SQLite::FunctionContext& context) - { - std::string uncompressedMD5, compressedMD5; - - if (!context.IsNullValue(5)) - { - uncompressedMD5 = context.GetStringValue(5); - } - - if (!context.IsNullValue(6)) - { - compressedMD5 = context.GetStringValue(6); - } - - output_.SignalDeletedAttachment(context.GetStringValue(0), - context.GetIntValue(1), - context.GetInt64Value(2), - uncompressedMD5, - context.GetIntValue(3), - context.GetInt64Value(4), - compressedMD5); - } - }; - - - class SignalResourceDeleted : public Orthanc::SQLite::IScalarFunction - { - private: - OrthancPlugins::DatabaseBackendOutput& output_; - - public: - SignalResourceDeleted(OrthancPlugins::DatabaseBackendOutput& output) : output_(output) - { - } - - virtual const char* GetName() const - { - return "SignalResourceDeleted"; - } - - virtual unsigned int GetCardinality() const - { - return 2; - } - - virtual void Compute(Orthanc::SQLite::FunctionContext& context) - { - output_.SignalDeletedResource(context.GetStringValue(0), - Orthanc::Plugins::Convert(static_cast(context.GetIntValue(1)))); - } - }; -} - - -class Database::SignalRemainingAncestor : public Orthanc::SQLite::IScalarFunction -{ -private: - bool hasRemainingAncestor_; - std::string remainingPublicId_; - OrthancPluginResourceType remainingType_; - -public: - SignalRemainingAncestor() : - hasRemainingAncestor_(false), - remainingType_(OrthancPluginResourceType_Instance) // Some dummy value - { - } - - void Reset() - { - hasRemainingAncestor_ = false; - } - - virtual const char* GetName() const - { - return "SignalRemainingAncestor"; - } - - virtual unsigned int GetCardinality() const - { - return 2; - } - - virtual void Compute(Orthanc::SQLite::FunctionContext& context) - { - if (!hasRemainingAncestor_ || - remainingType_ >= context.GetIntValue(1)) - { - hasRemainingAncestor_ = true; - remainingPublicId_ = context.GetStringValue(0); - remainingType_ = Orthanc::Plugins::Convert(static_cast(context.GetIntValue(1))); - } - } - - bool HasRemainingAncestor() const - { - return hasRemainingAncestor_; - } - - const std::string& GetRemainingAncestorId() const - { - assert(hasRemainingAncestor_); - return remainingPublicId_; - } - - OrthancPluginResourceType GetRemainingAncestorType() const - { - assert(hasRemainingAncestor_); - return remainingType_; - } -}; - - - -Database::Database(const std::string& path) : - path_(path), - base_(db_), - signalRemainingAncestor_(NULL) -{ -} - - -void Database::Open() -{ - db_.Open(path_); - - db_.Execute("PRAGMA ENCODING=\"UTF-8\";"); - - // http://www.sqlite.org/pragma.html - db_.Execute("PRAGMA SYNCHRONOUS=NORMAL;"); - db_.Execute("PRAGMA JOURNAL_MODE=WAL;"); - db_.Execute("PRAGMA LOCKING_MODE=EXCLUSIVE;"); - db_.Execute("PRAGMA WAL_AUTOCHECKPOINT=1000;"); - //db_.Execute("PRAGMA TEMP_STORE=memory"); - - if (!db_.DoesTableExist("GlobalProperties")) - { - std::string query; - Orthanc::EmbeddedResources::GetFileResource(query, Orthanc::EmbeddedResources::PREPARE_DATABASE); - db_.Execute(query); - } - - signalRemainingAncestor_ = new SignalRemainingAncestor; - db_.Register(signalRemainingAncestor_); - db_.Register(new Internals::SignalFileDeleted(GetOutput())); - db_.Register(new Internals::SignalResourceDeleted(GetOutput())); -} - - -void Database::Close() -{ - db_.Close(); -} - - -void Database::AddAttachment(int64_t id, - const OrthancPluginAttachment& attachment) -{ - Orthanc::FileInfo info(attachment.uuid, - static_cast(attachment.contentType), - attachment.uncompressedSize, - attachment.uncompressedHash, - static_cast(attachment.compressionType), - attachment.compressedSize, - attachment.compressedHash); - base_.AddAttachment(id, info); -} - - -void Database::DeleteResource(int64_t id) -{ - signalRemainingAncestor_->Reset(); - - Orthanc::SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM Resources WHERE internalId=?"); - s.BindInt64(0, id); - s.Run(); - - if (signalRemainingAncestor_->HasRemainingAncestor()) - { - GetOutput().SignalRemainingAncestor(signalRemainingAncestor_->GetRemainingAncestorId(), - signalRemainingAncestor_->GetRemainingAncestorType()); - } -} - - -static void Answer(OrthancPlugins::DatabaseBackendOutput& output, - const Orthanc::ServerIndexChange& change) -{ - output.AnswerChange(change.GetSeq(), - change.GetChangeType(), - Orthanc::Plugins::Convert(change.GetResourceType()), - change.GetPublicId(), - change.GetDate()); -} - - -static void Answer(OrthancPlugins::DatabaseBackendOutput& output, - const Orthanc::ExportedResource& resource) -{ - output.AnswerExportedResource(resource.GetSeq(), - Orthanc::Plugins::Convert(resource.GetResourceType()), - resource.GetPublicId(), - resource.GetModality(), - resource.GetDate(), - resource.GetPatientId(), - resource.GetStudyInstanceUid(), - resource.GetSeriesInstanceUid(), - resource.GetSopInstanceUid()); -} - - -void Database::GetChanges(bool& done /*out*/, - int64_t since, - uint32_t maxResults) -{ - typedef std::list Changes; - - Changes changes; - base_.GetChanges(changes, done, since, maxResults); - - for (Changes::const_iterator it = changes.begin(); it != changes.end(); ++it) - { - Answer(GetOutput(), *it); - } -} - - -void Database::GetExportedResources(bool& done /*out*/, - int64_t since, - uint32_t maxResults) -{ - typedef std::list Resources; - - Resources resources; - base_.GetExportedResources(resources, done, since, maxResults); - - for (Resources::const_iterator it = resources.begin(); it != resources.end(); ++it) - { - Answer(GetOutput(), *it); - } -} - - -void Database::GetLastChange() -{ - std::list change; - Orthanc::ErrorCode code = base_.GetLastChange(change); - - if (code != Orthanc::ErrorCode_Success) - { - throw OrthancPlugins::DatabaseException(static_cast(code)); - } - - if (!change.empty()) - { - Answer(GetOutput(), change.front()); - } -} - - -void Database::GetLastExportedResource() -{ - std::list resource; - base_.GetLastExportedResource(resource); - - if (!resource.empty()) - { - Answer(GetOutput(), resource.front()); - } -} - - -void Database::GetMainDicomTags(int64_t id) -{ - Orthanc::DicomMap tags; - base_.GetMainDicomTags(tags, id); - - Orthanc::DicomArray arr(tags); - for (size_t i = 0; i < arr.GetSize(); i++) - { - GetOutput().AnswerDicomTag(arr.GetElement(i).GetTag().GetGroup(), - arr.GetElement(i).GetTag().GetElement(), - arr.GetElement(i).GetValue().GetContent()); - } -} - - -std::string Database::GetPublicId(int64_t resourceId) -{ - std::string id; - if (base_.GetPublicId(id, resourceId)) - { - return id; - } - else - { - throw OrthancPlugins::DatabaseException(OrthancPluginErrorCode_UnknownResource); - } -} - - -OrthancPluginResourceType Database::GetResourceType(int64_t resourceId) -{ - Orthanc::ResourceType result; - Orthanc::ErrorCode code = base_.GetResourceType(result, resourceId); - - if (code == Orthanc::ErrorCode_Success) - { - return Orthanc::Plugins::Convert(result); - } - else - { - throw OrthancPlugins::DatabaseException(static_cast(code)); - } -} - - - -template -static void ConvertList(std::list& target, - const std::list& source) -{ - for (typename std::list::const_iterator - it = source.begin(); it != source.end(); ++it) - { - target.push_back(*it); - } -} - - -void Database::ListAvailableMetadata(std::list& target /*out*/, - int64_t id) -{ - std::list tmp; - base_.ListAvailableMetadata(tmp, id); - ConvertList(target, tmp); -} - - -void Database::ListAvailableAttachments(std::list& target /*out*/, - int64_t id) -{ - std::list tmp; - base_.ListAvailableAttachments(tmp, id); - ConvertList(target, tmp); -} - - -void Database::LogChange(const OrthancPluginChange& change) -{ - int64_t id; - OrthancPluginResourceType type; - if (!LookupResource(id, type, change.publicId) || - type != change.resourceType) - { - throw OrthancPlugins::DatabaseException(OrthancPluginErrorCode_DatabasePlugin); - } - - Orthanc::ServerIndexChange tmp(change.seq, - static_cast(change.changeType), - Orthanc::Plugins::Convert(change.resourceType), - change.publicId, - change.date); - - base_.LogChange(id, tmp); -} - - -void Database::LogExportedResource(const OrthancPluginExportedResource& resource) -{ - Orthanc::ExportedResource tmp(resource.seq, - Orthanc::Plugins::Convert(resource.resourceType), - resource.publicId, - resource.modality, - resource.date, - resource.patientId, - resource.studyInstanceUid, - resource.seriesInstanceUid, - resource.sopInstanceUid); - - base_.LogExportedResource(tmp); -} - - -bool Database::LookupAttachment(int64_t id, - int32_t contentType) -{ - Orthanc::FileInfo attachment; - if (base_.LookupAttachment(attachment, id, static_cast(contentType))) - { - GetOutput().AnswerAttachment(attachment.GetUuid(), - attachment.GetContentType(), - attachment.GetUncompressedSize(), - attachment.GetUncompressedMD5(), - attachment.GetCompressionType(), - attachment.GetCompressedSize(), - attachment.GetCompressedMD5()); - return true; - } - else - { - return false; - } -} - - -bool Database::LookupParent(int64_t& parentId /*out*/, - int64_t resourceId) -{ - bool found; - Orthanc::ErrorCode code = base_.LookupParent(found, parentId, resourceId); - - if (code == Orthanc::ErrorCode_Success) - { - return found; - } - else - { - throw OrthancPlugins::DatabaseException(static_cast(code)); - } -} - - -bool Database::LookupResource(int64_t& id /*out*/, - OrthancPluginResourceType& type /*out*/, - const char* publicId) -{ - Orthanc::ResourceType tmp; - if (base_.LookupResource(id, tmp, publicId)) - { - type = Orthanc::Plugins::Convert(tmp); - return true; - } - else - { - return false; - } -} - - -void Database::StartTransaction() -{ - transaction_.reset(new Orthanc::SQLite::Transaction(db_)); - transaction_->Begin(); -} - - -void Database::RollbackTransaction() -{ - transaction_->Rollback(); - transaction_.reset(NULL); -} - - -void Database::CommitTransaction() -{ - transaction_->Commit(); - transaction_.reset(NULL); -} - - -uint32_t Database::GetDatabaseVersion() -{ - std::string version; - - if (!LookupGlobalProperty(version, Orthanc::GlobalProperty_DatabaseSchemaVersion)) - { - throw OrthancPlugins::DatabaseException(OrthancPluginErrorCode_InternalError); - } - - try - { - return boost::lexical_cast(version); - } - catch (boost::bad_lexical_cast&) - { - throw OrthancPlugins::DatabaseException(OrthancPluginErrorCode_InternalError); - } -} - - -void Database::UpgradeDatabase(uint32_t targetVersion, - OrthancPluginStorageArea* storageArea) -{ - if (targetVersion == 6) - { - OrthancPluginErrorCode code = OrthancPluginReconstructMainDicomTags(GetOutput().GetContext(), storageArea, - OrthancPluginResourceType_Study); - if (code == OrthancPluginErrorCode_Success) - { - code = OrthancPluginReconstructMainDicomTags(GetOutput().GetContext(), storageArea, - OrthancPluginResourceType_Series); - } - - if (code != OrthancPluginErrorCode_Success) - { - throw OrthancPlugins::DatabaseException(code); - } - - base_.SetGlobalProperty(Orthanc::GlobalProperty_DatabaseSchemaVersion, "6"); - } -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancServer/Resources/Graveyard/DatabasePluginSample/Database.h --- a/OrthancServer/Resources/Graveyard/DatabasePluginSample/Database.h Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,275 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "OrthancCppDatabasePlugin.h" - -#include "../../../../OrthancFramework/Sources/SQLite/Connection.h" -#include "../../../../OrthancFramework/Sources/SQLite/Transaction.h" -#include "../../../Plugins/Engine/PluginsEnumerations.h" -#include "DatabaseWrapperBase.h" - -#include - -class Database : public OrthancPlugins::IDatabaseBackend -{ -private: - class SignalRemainingAncestor; - - std::string path_; - Orthanc::SQLite::Connection db_; - Orthanc::DatabaseWrapperBase base_; - SignalRemainingAncestor* signalRemainingAncestor_; - - std::auto_ptr transaction_; - -public: - Database(const std::string& path); - - virtual void Open(); - - virtual void Close(); - - virtual void AddAttachment(int64_t id, - const OrthancPluginAttachment& attachment); - - virtual void AttachChild(int64_t parent, - int64_t child) - { - base_.AttachChild(parent, child); - } - - virtual void ClearChanges() - { - db_.Execute("DELETE FROM Changes"); - } - - virtual void ClearExportedResources() - { - db_.Execute("DELETE FROM ExportedResources"); - } - - virtual int64_t CreateResource(const char* publicId, - OrthancPluginResourceType type) - { - return base_.CreateResource(publicId, Orthanc::Plugins::Convert(type)); - } - - virtual void DeleteAttachment(int64_t id, - int32_t attachment) - { - base_.DeleteAttachment(id, static_cast(attachment)); - } - - virtual void DeleteMetadata(int64_t id, - int32_t metadataType) - { - base_.DeleteMetadata(id, static_cast(metadataType)); - } - - virtual void DeleteResource(int64_t id); - - virtual void GetAllInternalIds(std::list& target, - OrthancPluginResourceType resourceType) - { - base_.GetAllInternalIds(target, Orthanc::Plugins::Convert(resourceType)); - } - - virtual void GetAllPublicIds(std::list& target, - OrthancPluginResourceType resourceType) - { - base_.GetAllPublicIds(target, Orthanc::Plugins::Convert(resourceType)); - } - - virtual void GetAllPublicIds(std::list& target, - OrthancPluginResourceType resourceType, - uint64_t since, - uint64_t limit) - { - base_.GetAllPublicIds(target, Orthanc::Plugins::Convert(resourceType), since, limit); - } - - virtual void GetChanges(bool& done /*out*/, - int64_t since, - uint32_t maxResults); - - virtual void GetChildrenInternalId(std::list& target /*out*/, - int64_t id) - { - base_.GetChildrenInternalId(target, id); - } - - virtual void GetChildrenPublicId(std::list& target /*out*/, - int64_t id) - { - base_.GetChildrenPublicId(target, id); - } - - virtual void GetExportedResources(bool& done /*out*/, - int64_t since, - uint32_t maxResults); - - virtual void GetLastChange(); - - virtual void GetLastExportedResource(); - - virtual void GetMainDicomTags(int64_t id); - - virtual std::string GetPublicId(int64_t resourceId); - - virtual uint64_t GetResourceCount(OrthancPluginResourceType resourceType) - { - return base_.GetResourceCount(Orthanc::Plugins::Convert(resourceType)); - } - - virtual OrthancPluginResourceType GetResourceType(int64_t resourceId); - - virtual uint64_t GetTotalCompressedSize() - { - return base_.GetTotalCompressedSize(); - } - - virtual uint64_t GetTotalUncompressedSize() - { - return base_.GetTotalUncompressedSize(); - } - - virtual bool IsExistingResource(int64_t internalId) - { - return base_.IsExistingResource(internalId); - } - - virtual bool IsProtectedPatient(int64_t internalId) - { - return base_.IsProtectedPatient(internalId); - } - - virtual void ListAvailableMetadata(std::list& target /*out*/, - int64_t id); - - virtual void ListAvailableAttachments(std::list& target /*out*/, - int64_t id); - - virtual void LogChange(const OrthancPluginChange& change); - - virtual void LogExportedResource(const OrthancPluginExportedResource& resource); - - virtual bool LookupAttachment(int64_t id, - int32_t contentType); - - virtual bool LookupGlobalProperty(std::string& target /*out*/, - int32_t property) - { - return base_.LookupGlobalProperty(target, static_cast(property)); - } - - virtual void LookupIdentifier(std::list& target /*out*/, - OrthancPluginResourceType level, - uint16_t group, - uint16_t element, - OrthancPluginIdentifierConstraint constraint, - const char* value) - { - base_.LookupIdentifier(target, Orthanc::Plugins::Convert(level), - Orthanc::DicomTag(group, element), - Orthanc::Plugins::Convert(constraint), value); - } - - virtual bool LookupMetadata(std::string& target /*out*/, - int64_t id, - int32_t metadataType) - { - return base_.LookupMetadata(target, id, static_cast(metadataType)); - } - - virtual bool LookupParent(int64_t& parentId /*out*/, - int64_t resourceId); - - virtual bool LookupResource(int64_t& id /*out*/, - OrthancPluginResourceType& type /*out*/, - const char* publicId); - - virtual bool SelectPatientToRecycle(int64_t& internalId /*out*/) - { - return base_.SelectPatientToRecycle(internalId); - } - - virtual bool SelectPatientToRecycle(int64_t& internalId /*out*/, - int64_t patientIdToAvoid) - { - return base_.SelectPatientToRecycle(internalId, patientIdToAvoid); - } - - - virtual void SetGlobalProperty(int32_t property, - const char* value) - { - base_.SetGlobalProperty(static_cast(property), value); - } - - virtual void SetMainDicomTag(int64_t id, - uint16_t group, - uint16_t element, - const char* value) - { - base_.SetMainDicomTag(id, Orthanc::DicomTag(group, element), value); - } - - virtual void SetIdentifierTag(int64_t id, - uint16_t group, - uint16_t element, - const char* value) - { - base_.SetIdentifierTag(id, Orthanc::DicomTag(group, element), value); - } - - virtual void SetMetadata(int64_t id, - int32_t metadataType, - const char* value) - { - base_.SetMetadata(id, static_cast(metadataType), value); - } - - virtual void SetProtectedPatient(int64_t internalId, - bool isProtected) - { - base_.SetProtectedPatient(internalId, isProtected); - } - - virtual void StartTransaction(); - - virtual void RollbackTransaction(); - - virtual void CommitTransaction(); - - virtual uint32_t GetDatabaseVersion(); - - virtual void UpgradeDatabase(uint32_t targetVersion, - OrthancPluginStorageArea* storageArea); - - virtual void ClearMainDicomTags(int64_t internalId) - { - base_.ClearMainDicomTags(internalId); - } -}; diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancServer/Resources/Graveyard/DatabasePluginSample/DatabaseWrapperBase.cpp --- a/OrthancServer/Resources/Graveyard/DatabasePluginSample/DatabaseWrapperBase.cpp Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,747 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../../Sources/PrecompiledHeadersServer.h" -#include "DatabaseWrapperBase.h" - -#include -#include - -namespace Orthanc -{ - void DatabaseWrapperBase::SetGlobalProperty(GlobalProperty property, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO GlobalProperties VALUES(?, ?)"); - s.BindInt(0, property); - s.BindString(1, value); - s.Run(); - } - - bool DatabaseWrapperBase::LookupGlobalProperty(std::string& target, - GlobalProperty property) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT value FROM GlobalProperties WHERE property=?"); - s.BindInt(0, property); - - if (!s.Step()) - { - return false; - } - else - { - target = s.ColumnString(0); - return true; - } - } - - int64_t DatabaseWrapperBase::CreateResource(const std::string& publicId, - ResourceType type) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Resources VALUES(NULL, ?, ?, NULL)"); - s.BindInt(0, type); - s.BindString(1, publicId); - s.Run(); - return db_.GetLastInsertRowId(); - } - - bool DatabaseWrapperBase::LookupResource(int64_t& id, - ResourceType& type, - const std::string& publicId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT internalId, resourceType FROM Resources WHERE publicId=?"); - s.BindString(0, publicId); - - if (!s.Step()) - { - return false; - } - else - { - id = s.ColumnInt(0); - type = static_cast(s.ColumnInt(1)); - - // Check whether there is a single resource with this public id - assert(!s.Step()); - - return true; - } - } - - ErrorCode DatabaseWrapperBase::LookupParent(bool& found, - int64_t& parentId, - int64_t resourceId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT parentId FROM Resources WHERE internalId=?"); - s.BindInt64(0, resourceId); - - if (!s.Step()) - { - return ErrorCode_UnknownResource; - } - - if (s.ColumnIsNull(0)) - { - found = false; - } - else - { - found = true; - parentId = s.ColumnInt(0); - } - - return ErrorCode_Success; - } - - bool DatabaseWrapperBase::GetPublicId(std::string& result, - int64_t resourceId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT publicId FROM Resources WHERE internalId=?"); - s.BindInt64(0, resourceId); - - if (!s.Step()) - { - return false; - } - else - { - result = s.ColumnString(0); - return true; - } - } - - - ErrorCode DatabaseWrapperBase::GetResourceType(ResourceType& result, - int64_t resourceId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT resourceType FROM Resources WHERE internalId=?"); - s.BindInt64(0, resourceId); - - if (s.Step()) - { - result = static_cast(s.ColumnInt(0)); - return ErrorCode_Success; - } - else - { - return ErrorCode_UnknownResource; - } - } - - - void DatabaseWrapperBase::AttachChild(int64_t parent, - int64_t child) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "UPDATE Resources SET parentId = ? WHERE internalId = ?"); - s.BindInt64(0, parent); - s.BindInt64(1, child); - s.Run(); - } - - - void DatabaseWrapperBase::SetMetadata(int64_t id, - MetadataType type, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO Metadata VALUES(?, ?, ?)"); - s.BindInt64(0, id); - s.BindInt(1, type); - s.BindString(2, value); - s.Run(); - } - - void DatabaseWrapperBase::DeleteMetadata(int64_t id, - MetadataType type) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM Metadata WHERE id=? and type=?"); - s.BindInt64(0, id); - s.BindInt(1, type); - s.Run(); - } - - bool DatabaseWrapperBase::LookupMetadata(std::string& target, - int64_t id, - MetadataType type) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT value FROM Metadata WHERE id=? AND type=?"); - s.BindInt64(0, id); - s.BindInt(1, type); - - if (!s.Step()) - { - return false; - } - else - { - target = s.ColumnString(0); - return true; - } - } - - void DatabaseWrapperBase::ListAvailableMetadata(std::list& target, - int64_t id) - { - target.clear(); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT type FROM Metadata WHERE id=?"); - s.BindInt64(0, id); - - while (s.Step()) - { - target.push_back(static_cast(s.ColumnInt(0))); - } - } - - - void DatabaseWrapperBase::AddAttachment(int64_t id, - const FileInfo& attachment) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO AttachedFiles VALUES(?, ?, ?, ?, ?, ?, ?, ?)"); - s.BindInt64(0, id); - s.BindInt(1, attachment.GetContentType()); - s.BindString(2, attachment.GetUuid()); - s.BindInt64(3, attachment.GetCompressedSize()); - s.BindInt64(4, attachment.GetUncompressedSize()); - s.BindInt(5, attachment.GetCompressionType()); - s.BindString(6, attachment.GetUncompressedMD5()); - s.BindString(7, attachment.GetCompressedMD5()); - s.Run(); - } - - - void DatabaseWrapperBase::DeleteAttachment(int64_t id, - FileContentType attachment) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM AttachedFiles WHERE id=? AND fileType=?"); - s.BindInt64(0, id); - s.BindInt(1, attachment); - s.Run(); - } - - - - void DatabaseWrapperBase::ListAvailableAttachments(std::list& target, - int64_t id) - { - target.clear(); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT fileType FROM AttachedFiles WHERE id=?"); - s.BindInt64(0, id); - - while (s.Step()) - { - target.push_back(static_cast(s.ColumnInt(0))); - } - } - - bool DatabaseWrapperBase::LookupAttachment(FileInfo& attachment, - int64_t id, - FileContentType contentType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT uuid, uncompressedSize, compressionType, compressedSize, uncompressedMD5, compressedMD5 FROM AttachedFiles WHERE id=? AND fileType=?"); - s.BindInt64(0, id); - s.BindInt(1, contentType); - - if (!s.Step()) - { - return false; - } - else - { - attachment = FileInfo(s.ColumnString(0), - contentType, - s.ColumnInt64(1), - s.ColumnString(4), - static_cast(s.ColumnInt(2)), - s.ColumnInt64(3), - s.ColumnString(5)); - return true; - } - } - - - void DatabaseWrapperBase::ClearMainDicomTags(int64_t id) - { - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM DicomIdentifiers WHERE id=?"); - s.BindInt64(0, id); - s.Run(); - } - - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM MainDicomTags WHERE id=?"); - s.BindInt64(0, id); - s.Run(); - } - } - - - void DatabaseWrapperBase::SetMainDicomTag(int64_t id, - const DicomTag& tag, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO MainDicomTags VALUES(?, ?, ?, ?)"); - s.BindInt64(0, id); - s.BindInt(1, tag.GetGroup()); - s.BindInt(2, tag.GetElement()); - s.BindString(3, value); - s.Run(); - } - - - void DatabaseWrapperBase::SetIdentifierTag(int64_t id, - const DicomTag& tag, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO DicomIdentifiers VALUES(?, ?, ?, ?)"); - s.BindInt64(0, id); - s.BindInt(1, tag.GetGroup()); - s.BindInt(2, tag.GetElement()); - s.BindString(3, value); - s.Run(); - } - - - void DatabaseWrapperBase::GetMainDicomTags(DicomMap& map, - int64_t id) - { - map.Clear(); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM MainDicomTags WHERE id=?"); - s.BindInt64(0, id); - while (s.Step()) - { - map.SetValue(s.ColumnInt(1), - s.ColumnInt(2), - s.ColumnString(3), false); - } - } - - - - void DatabaseWrapperBase::GetChildrenPublicId(std::list& target, - int64_t id) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.publicId FROM Resources AS a, Resources AS b " - "WHERE a.parentId = b.internalId AND b.internalId = ?"); - s.BindInt64(0, id); - - target.clear(); - - while (s.Step()) - { - target.push_back(s.ColumnString(0)); - } - } - - - void DatabaseWrapperBase::GetChildrenInternalId(std::list& target, - int64_t id) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.internalId FROM Resources AS a, Resources AS b " - "WHERE a.parentId = b.internalId AND b.internalId = ?"); - s.BindInt64(0, id); - - target.clear(); - - while (s.Step()) - { - target.push_back(s.ColumnInt64(0)); - } - } - - - void DatabaseWrapperBase::LogChange(int64_t internalId, - const ServerIndexChange& change) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Changes VALUES(NULL, ?, ?, ?, ?)"); - s.BindInt(0, change.GetChangeType()); - s.BindInt64(1, internalId); - s.BindInt(2, change.GetResourceType()); - s.BindString(3, change.GetDate()); - s.Run(); - } - - - ErrorCode DatabaseWrapperBase::GetChangesInternal(std::list& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults) - { - target.clear(); - - while (target.size() < maxResults && s.Step()) - { - int64_t seq = s.ColumnInt64(0); - ChangeType changeType = static_cast(s.ColumnInt(1)); - ResourceType resourceType = static_cast(s.ColumnInt(3)); - const std::string& date = s.ColumnString(4); - - int64_t internalId = s.ColumnInt64(2); - std::string publicId; - if (!GetPublicId(publicId, internalId)) - { - return ErrorCode_UnknownResource; - } - - target.push_back(ServerIndexChange(seq, changeType, resourceType, publicId, date)); - } - - done = !(target.size() == maxResults && s.Step()); - return ErrorCode_Success; - } - - - ErrorCode DatabaseWrapperBase::GetChanges(std::list& target, - bool& done, - int64_t since, - uint32_t maxResults) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes WHERE seq>? ORDER BY seq LIMIT ?"); - s.BindInt64(0, since); - s.BindInt(1, maxResults + 1); - return GetChangesInternal(target, done, s, maxResults); - } - - ErrorCode DatabaseWrapperBase::GetLastChange(std::list& target) - { - bool done; // Ignored - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes ORDER BY seq DESC LIMIT 1"); - return GetChangesInternal(target, done, s, 1); - } - - - void DatabaseWrapperBase::LogExportedResource(const ExportedResource& resource) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "INSERT INTO ExportedResources VALUES(NULL, ?, ?, ?, ?, ?, ?, ?, ?)"); - - s.BindInt(0, resource.GetResourceType()); - s.BindString(1, resource.GetPublicId()); - s.BindString(2, resource.GetModality()); - s.BindString(3, resource.GetPatientId()); - s.BindString(4, resource.GetStudyInstanceUid()); - s.BindString(5, resource.GetSeriesInstanceUid()); - s.BindString(6, resource.GetSopInstanceUid()); - s.BindString(7, resource.GetDate()); - s.Run(); - } - - - void DatabaseWrapperBase::GetExportedResourcesInternal(std::list& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults) - { - target.clear(); - - while (target.size() < maxResults && s.Step()) - { - int64_t seq = s.ColumnInt64(0); - ResourceType resourceType = static_cast(s.ColumnInt(1)); - std::string publicId = s.ColumnString(2); - - ExportedResource resource(seq, - resourceType, - publicId, - s.ColumnString(3), // modality - s.ColumnString(8), // date - s.ColumnString(4), // patient ID - s.ColumnString(5), // study instance UID - s.ColumnString(6), // series instance UID - s.ColumnString(7)); // sop instance UID - - target.push_back(resource); - } - - done = !(target.size() == maxResults && s.Step()); - } - - - void DatabaseWrapperBase::GetExportedResources(std::list& target, - bool& done, - int64_t since, - uint32_t maxResults) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT * FROM ExportedResources WHERE seq>? ORDER BY seq LIMIT ?"); - s.BindInt64(0, since); - s.BindInt(1, maxResults + 1); - GetExportedResourcesInternal(target, done, s, maxResults); - } - - - void DatabaseWrapperBase::GetLastExportedResource(std::list& target) - { - bool done; // Ignored - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT * FROM ExportedResources ORDER BY seq DESC LIMIT 1"); - GetExportedResourcesInternal(target, done, s, 1); - } - - - - uint64_t DatabaseWrapperBase::GetTotalCompressedSize() - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT SUM(compressedSize) FROM AttachedFiles"); - s.Run(); - return static_cast(s.ColumnInt64(0)); - } - - - uint64_t DatabaseWrapperBase::GetTotalUncompressedSize() - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT SUM(uncompressedSize) FROM AttachedFiles"); - s.Run(); - return static_cast(s.ColumnInt64(0)); - } - - void DatabaseWrapperBase::GetAllInternalIds(std::list& target, - ResourceType resourceType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT internalId FROM Resources WHERE resourceType=?"); - s.BindInt(0, resourceType); - - target.clear(); - while (s.Step()) - { - target.push_back(s.ColumnInt64(0)); - } - } - - - void DatabaseWrapperBase::GetAllPublicIds(std::list& target, - ResourceType resourceType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT publicId FROM Resources WHERE resourceType=?"); - s.BindInt(0, resourceType); - - target.clear(); - while (s.Step()) - { - target.push_back(s.ColumnString(0)); - } - } - - void DatabaseWrapperBase::GetAllPublicIds(std::list& target, - ResourceType resourceType, - size_t since, - size_t limit) - { - if (limit == 0) - { - target.clear(); - return; - } - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT publicId FROM Resources WHERE resourceType=? LIMIT ? OFFSET ?"); - s.BindInt(0, resourceType); - s.BindInt64(1, limit); - s.BindInt64(2, since); - - target.clear(); - while (s.Step()) - { - target.push_back(s.ColumnString(0)); - } - } - - - uint64_t DatabaseWrapperBase::GetResourceCount(ResourceType resourceType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT COUNT(*) FROM Resources WHERE resourceType=?"); - s.BindInt(0, resourceType); - - if (!s.Step()) - { - return 0; - } - else - { - int64_t c = s.ColumnInt(0); - assert(!s.Step()); - return c; - } - } - - - bool DatabaseWrapperBase::SelectPatientToRecycle(int64_t& internalId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT patientId FROM PatientRecyclingOrder ORDER BY seq ASC LIMIT 1"); - - if (!s.Step()) - { - // No patient remaining or all the patients are protected - return false; - } - else - { - internalId = s.ColumnInt(0); - return true; - } - } - - bool DatabaseWrapperBase::SelectPatientToRecycle(int64_t& internalId, - int64_t patientIdToAvoid) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT patientId FROM PatientRecyclingOrder " - "WHERE patientId != ? ORDER BY seq ASC LIMIT 1"); - s.BindInt64(0, patientIdToAvoid); - - if (!s.Step()) - { - // No patient remaining or all the patients are protected - return false; - } - else - { - internalId = s.ColumnInt(0); - return true; - } - } - - bool DatabaseWrapperBase::IsProtectedPatient(int64_t internalId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT * FROM PatientRecyclingOrder WHERE patientId = ?"); - s.BindInt64(0, internalId); - return !s.Step(); - } - - void DatabaseWrapperBase::SetProtectedPatient(int64_t internalId, - bool isProtected) - { - if (isProtected) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM PatientRecyclingOrder WHERE patientId=?"); - s.BindInt64(0, internalId); - s.Run(); - } - else if (IsProtectedPatient(internalId)) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO PatientRecyclingOrder VALUES(NULL, ?)"); - s.BindInt64(0, internalId); - s.Run(); - } - else - { - // Nothing to do: The patient is already unprotected - } - } - - - - bool DatabaseWrapperBase::IsExistingResource(int64_t internalId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT * FROM Resources WHERE internalId=?"); - s.BindInt64(0, internalId); - return s.Step(); - } - - - - void DatabaseWrapperBase::LookupIdentifier(std::list& target, - ResourceType level, - const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value) - { - static const char* COMMON = ("SELECT d.id FROM DicomIdentifiers AS d, Resources AS r WHERE " - "d.id = r.internalId AND r.resourceType=? AND " - "d.tagGroup=? AND d.tagElement=? AND "); - - std::auto_ptr s; - - switch (type) - { - case IdentifierConstraintType_GreaterOrEqual: - s.reset(new SQLite::Statement(db_, std::string(COMMON) + "d.value>=?")); - break; - - case IdentifierConstraintType_SmallerOrEqual: - s.reset(new SQLite::Statement(db_, std::string(COMMON) + "d.value<=?")); - break; - - case IdentifierConstraintType_Wildcard: - s.reset(new SQLite::Statement(db_, std::string(COMMON) + "d.value GLOB ?")); - break; - - case IdentifierConstraintType_Equal: - default: - s.reset(new SQLite::Statement(db_, std::string(COMMON) + "d.value=?")); - break; - } - - assert(s.get() != NULL); - - s->BindInt(0, level); - s->BindInt(1, tag.GetGroup()); - s->BindInt(2, tag.GetElement()); - s->BindString(3, value); - - target.clear(); - - while (s->Step()) - { - target.push_back(s->ColumnInt64(0)); - } - } - - - void DatabaseWrapperBase::LookupIdentifierRange(std::list& target, - ResourceType level, - const DicomTag& tag, - const std::string& start, - const std::string& end) - { - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT d.id FROM DicomIdentifiers AS d, Resources AS r WHERE " - "d.id = r.internalId AND r.resourceType=? AND " - "d.tagGroup=? AND d.tagElement=? AND d.value>=? AND d.value<=?"); - - statement.BindInt(0, level); - statement.BindInt(1, tag.GetGroup()); - statement.BindInt(2, tag.GetElement()); - statement.BindString(3, start); - statement.BindString(4, end); - - target.clear(); - - while (statement.Step()) - { - target.push_back(statement.ColumnInt64(0)); - } - } -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancServer/Resources/Graveyard/DatabasePluginSample/DatabaseWrapperBase.h --- a/OrthancServer/Resources/Graveyard/DatabasePluginSample/DatabaseWrapperBase.h Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../../../OrthancFramework/Sources/DicomFormat/DicomMap.h" -#include "../../../../OrthancFramework/Sources/DicomFormat/DicomTag.h" -#include "../../../../OrthancFramework/Sources/Enumerations.h" -#include "../../../../OrthancFramework/Sources/FileStorage/FileInfo.h" -#include "../../../../OrthancFramework/Sources/SQLite/Connection.h" -#include "../../../Sources/ExportedResource.h" -#include "../../../Sources/ServerIndexChange.h" -#include "../../../Sources/ServerEnumerations.h" - -#include - - -namespace Orthanc -{ - /** - * This class is shared between the Orthanc core and the sample - * database plugin whose code is in - * "../Plugins/Samples/DatabasePlugin". - **/ - class DatabaseWrapperBase - { - private: - SQLite::Connection& db_; - - ErrorCode GetChangesInternal(std::list& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults); - - void GetExportedResourcesInternal(std::list& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults); - - public: - DatabaseWrapperBase(SQLite::Connection& db) : db_(db) - { - } - - void SetGlobalProperty(GlobalProperty property, - const std::string& value); - - bool LookupGlobalProperty(std::string& target, - GlobalProperty property); - - int64_t CreateResource(const std::string& publicId, - ResourceType type); - - bool LookupResource(int64_t& id, - ResourceType& type, - const std::string& publicId); - - ErrorCode LookupParent(bool& found, - int64_t& parentId, - int64_t resourceId); - - bool GetPublicId(std::string& result, - int64_t resourceId); - - ErrorCode GetResourceType(ResourceType& result, - int64_t resourceId); - - void AttachChild(int64_t parent, - int64_t child); - - void SetMetadata(int64_t id, - MetadataType type, - const std::string& value); - - void DeleteMetadata(int64_t id, - MetadataType type); - - bool LookupMetadata(std::string& target, - int64_t id, - MetadataType type); - - void ListAvailableMetadata(std::list& target, - int64_t id); - - void AddAttachment(int64_t id, - const FileInfo& attachment); - - void DeleteAttachment(int64_t id, - FileContentType attachment); - - void ListAvailableAttachments(std::list& target, - int64_t id); - - bool LookupAttachment(FileInfo& attachment, - int64_t id, - FileContentType contentType); - - - void ClearMainDicomTags(int64_t id); - - - void SetMainDicomTag(int64_t id, - const DicomTag& tag, - const std::string& value); - - void SetIdentifierTag(int64_t id, - const DicomTag& tag, - const std::string& value); - - void GetMainDicomTags(DicomMap& map, - int64_t id); - - void GetChildrenPublicId(std::list& target, - int64_t id); - - void GetChildrenInternalId(std::list& target, - int64_t id); - - void LogChange(int64_t internalId, - const ServerIndexChange& change); - - ErrorCode GetChanges(std::list& target, - bool& done, - int64_t since, - uint32_t maxResults); - - ErrorCode GetLastChange(std::list& target); - - void LogExportedResource(const ExportedResource& resource); - - void GetExportedResources(std::list& target, - bool& done, - int64_t since, - uint32_t maxResults); - - void GetLastExportedResource(std::list& target); - - uint64_t GetTotalCompressedSize(); - - uint64_t GetTotalUncompressedSize(); - - void GetAllInternalIds(std::list& target, - ResourceType resourceType); - - void GetAllPublicIds(std::list& target, - ResourceType resourceType); - - void GetAllPublicIds(std::list& target, - ResourceType resourceType, - size_t since, - size_t limit); - - uint64_t GetResourceCount(ResourceType resourceType); - - bool SelectPatientToRecycle(int64_t& internalId); - - bool SelectPatientToRecycle(int64_t& internalId, - int64_t patientIdToAvoid); - - bool IsProtectedPatient(int64_t internalId); - - void SetProtectedPatient(int64_t internalId, - bool isProtected); - - bool IsExistingResource(int64_t internalId); - - void LookupIdentifier(std::list& result, - ResourceType level, - const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value); - - void LookupIdentifierRange(std::list& result, - ResourceType level, - const DicomTag& tag, - const std::string& start, - const std::string& end); - }; -} - diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancServer/Resources/Graveyard/DatabasePluginSample/Plugin.cpp --- a/OrthancServer/Resources/Graveyard/DatabasePluginSample/Plugin.cpp Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "Database.h" - -#include -#include -#include - -static OrthancPluginContext* context_ = NULL; -static std::auto_ptr backend_; - - -extern "C" -{ - ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c) - { - context_ = c; - OrthancPluginLogWarning(context_, "Sample plugin is initializing"); - - /* Check the version of the Orthanc core */ - if (OrthancPluginCheckVersion(c) == 0) - { - char info[256]; - sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin", - c->orthancVersion, - ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, - ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, - ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); - OrthancPluginLogError(context_, info); - return -1; - } - - std::string path = "SampleDatabase.sqlite"; - uint32_t argCount = OrthancPluginGetCommandLineArgumentsCount(context_); - for (uint32_t i = 0; i < argCount; i++) - { - char* tmp = OrthancPluginGetCommandLineArgument(context_, i); - std::string argument(tmp); - OrthancPluginFreeString(context_, tmp); - - if (boost::starts_with(argument, "--database=")) - { - path = argument.substr(11); - } - } - - std::string s = "Using the following SQLite database: " + path; - OrthancPluginLogWarning(context_, s.c_str()); - - backend_.reset(new Database(path)); - OrthancPlugins::DatabaseBackendAdapter::Register(context_, *backend_); - - return 0; - } - - ORTHANC_PLUGINS_API void OrthancPluginFinalize() - { - backend_.reset(NULL); - } - - ORTHANC_PLUGINS_API const char* OrthancPluginGetName() - { - return "sample-database"; - } - - - ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() - { - return "1.0"; - } -} diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancServer/Resources/Graveyard/FindRefactoringForSQLite.cpp --- a/OrthancServer/Resources/Graveyard/FindRefactoringForSQLite.cpp Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,167 +0,0 @@ -#if 0 - // TODO-FIND: Remove this implementation, as it should be done by - // the compatibility mode implemented by "GenericFind" - - virtual void ExecuteFind(FindResponse& response, - const FindRequest& request, - const std::vector& normalized) ORTHANC_OVERRIDE - { -#if 0 - Compatibility::GenericFind find(*this); - find.Execute(response, request); -#else - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DROP TABLE IF EXISTS FilteredResourcesIds"); - s.Run(); - } - - { - - LookupFormatter formatter; - - std::string sqlLookup; - LookupFormatter::Apply(sqlLookup, - formatter, - normalized, - request.GetLevel(), - request.GetLabels(), - request.GetLabelsConstraint(), - (request.HasLimits() ? request.GetLimitsCount() : 0)); // TODO: handles since and count - - { - // first create a temporary table that with the filtered and ordered results - sqlLookup = "CREATE TEMPORARY TABLE FilteredResourcesIds AS " + sqlLookup; - - SQLite::Statement statement(db_, SQLITE_FROM_HERE_DYNAMIC(sqlLookup), sqlLookup); - formatter.Bind(statement); - statement.Run(); - } - - { - // create the response item with the public ids only - SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT publicId FROM FilteredResourcesIds"); - formatter.Bind(statement); - - while (statement.Step()) - { - const std::string resourceId = statement.ColumnString(0); - response.Add(new FindResponse::Resource(request.GetLevel(), resourceId)); - } - } - - // request Each response content through INNER JOIN with the temporary table - if (request.IsRetrieveMainDicomTags()) - { - // TODO-FIND: handle the case where we request tags from multiple levels - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT publicId, tagGroup, tagElement, value FROM MainDicomTags AS tags " - " INNER JOIN FilteredResourcesIds ON tags.id = FilteredResourcesIds.internalId"); - formatter.Bind(statement); - - while (statement.Step()) - { - const std::string& resourceId = statement.ColumnString(0); - assert(response.HasResource(resourceId)); - response.GetResource(resourceId).AddStringDicomTag(statement.ColumnInt(1), - statement.ColumnInt(2), - statement.ColumnString(3)); - } - } - - if (request.IsRetrieveChildrenIdentifiers()) - { - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT filtered.publicId, childLevel.publicId AS childPublicId " - "FROM Resources as currentLevel " - " INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = currentLevel.internalId " - " INNER JOIN Resources childLevel ON childLevel.parentId = currentLevel.internalId"); - formatter.Bind(statement); - - while (statement.Step()) - { - const std::string& resourceId = statement.ColumnString(0); - assert(response.HasResource(resourceId)); - response.GetResource(resourceId).AddChildIdentifier(GetChildResourceType(request.GetLevel()), statement.ColumnString(1)); - } - } - - if (request.IsRetrieveParentIdentifier()) - { - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT filtered.publicId, parentLevel.publicId AS parentPublicId " - "FROM Resources as currentLevel " - " INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = currentLevel.internalId " - " INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId"); - - while (statement.Step()) - { - const std::string& resourceId = statement.ColumnString(0); - const std::string& parentId = statement.ColumnString(1); - assert(response.HasResource(resourceId)); - response.GetResource(resourceId).SetParentIdentifier(parentId); - } - } - - if (request.IsRetrieveMetadata()) - { - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT filtered.publicId, metadata.type, metadata.value " - "FROM Metadata " - " INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = Metadata.id"); - - while (statement.Step()) - { - const std::string& resourceId = statement.ColumnString(0); - assert(response.HasResource(resourceId)); - response.GetResource(resourceId).AddMetadata(static_cast(statement.ColumnInt(1)), - statement.ColumnString(2)); - } - } - - if (request.IsRetrieveLabels()) - { - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT filtered.publicId, label " - "FROM Labels " - " INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = Labels.id"); - - while (statement.Step()) - { - const std::string& resourceId = statement.ColumnString(0); - assert(response.HasResource(resourceId)); - response.GetResource(resourceId).AddLabel(statement.ColumnString(1)); - } - } - - if (request.IsRetrieveAttachments()) - { - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT filtered.publicId, uuid, fileType, uncompressedSize, compressionType, compressedSize, " - " uncompressedMD5, compressedMD5 " - "FROM AttachedFiles " - " INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = AttachedFiles.id"); - - while (statement.Step()) - { - const std::string& resourceId = statement.ColumnString(0); - FileInfo attachment = FileInfo(statement.ColumnString(1), - static_cast(statement.ColumnInt(2)), - statement.ColumnInt64(3), - statement.ColumnString(6), - static_cast(statement.ColumnInt(4)), - statement.ColumnInt64(5), - statement.ColumnString(7)); - - assert(response.HasResource(resourceId)); - response.GetResource(resourceId).AddAttachment(attachment); - }; - } - - // TODO-FIND: implement other responseContent: ResponseContent_ChildInstanceId, ResponseContent_ChildrenMetadata (later: ResponseContent_IsStable) - - } - -#endif - } -#endif - diff -r 9d6167ddcb35 -r bbeefd4567dc OrthancServer/Resources/Graveyard/SetupAnonymization2011.cpp --- a/OrthancServer/Resources/Graveyard/SetupAnonymization2011.cpp Thu Aug 29 15:41:42 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,258 +0,0 @@ - /** - * This is a manual implementation by Alain Mazy. Only kept for reference. - * https://bitbucket.org/sjodogne/orthanc/commits/c6defdc4c611fca2ab528ba2c6937a742e0329a8?at=issue-46-anonymization - **/ - - void DicomModification::SetupAnonymization2011() - { - // This is Table E.1-1 from PS 3.15-2011 - DICOM Part 15: Security and System Management Profiles - // https://raw.githubusercontent.com/jodogne/dicom-specification/master/2011/11_15pu.pdf - - removals_.insert(DicomTag(0x0000, 0x1000)); // Affected SOP Instance UID - removals_.insert(DicomTag(0x0000, 0x1001)); // Requested SOP Instance UID - removals_.insert(DicomTag(0x0002, 0x0003)); // Media Storage SOP Instance UID => TODO: replace with a non-zero length UID that is internally consistent within a set of Instances - removals_.insert(DicomTag(0x0004, 0x1511)); // Referenced SOP Instance UID in File - removals_.insert(DicomTag(0x0008, 0x0010)); // Irradiation Event UID - removals_.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID - //removals_.insert(DicomTag(0x0008, 0x0018)); // SOP Instance UID => set in Apply() - clearings_.insert(DicomTag(0x0008, 0x0020)); // Study Date - clearings_.insert(DicomTag(0x0008, 0x0021)); // Series Date - clearings_.insert(DicomTag(0x0008, 0x0030)); // Study Time - clearings_.insert(DicomTag(0x0008, 0x0031)); // Series Time - removals_.insert(DicomTag(0x0008, 0x0022)); // Acquisition Date - removals_.insert(DicomTag(0x0008, 0x0023)); // Content Date - removals_.insert(DicomTag(0x0008, 0x0024)); // Overlay Date - removals_.insert(DicomTag(0x0008, 0x0025)); // Curve Date - removals_.insert(DicomTag(0x0008, 0x002a)); // Acquisition DateTime - removals_.insert(DicomTag(0x0008, 0x0032)); // Acquisition Time - removals_.insert(DicomTag(0x0008, 0x0033)); // Content Time - removals_.insert(DicomTag(0x0008, 0x0034)); // Overlay Time - removals_.insert(DicomTag(0x0008, 0x0035)); // Curve Time - removals_.insert(DicomTag(0x0008, 0x0050)); // Accession Number - removals_.insert(DicomTag(0x0008, 0x0058)); // Failed SOP Instance UID List - removals_.insert(DicomTag(0x0008, 0x0080)); // Institution Name - removals_.insert(DicomTag(0x0008, 0x0081)); // Institution Address - removals_.insert(DicomTag(0x0008, 0x0082)); // Institution Code Sequence - removals_.insert(DicomTag(0x0008, 0x0090)); // Referring Physician's Name - removals_.insert(DicomTag(0x0008, 0x0092)); // Referring Physician's Address - removals_.insert(DicomTag(0x0008, 0x0094)); // Referring Physician's Telephone Numbers - removals_.insert(DicomTag(0x0008, 0x0096)); // Referring Physician's Identification Sequence - removals_.insert(DicomTag(0x0008, 0x010d)); // Context Group Extension Creator UID - removals_.insert(DicomTag(0x0008, 0x0201)); // Timezone Offset From UTC - removals_.insert(DicomTag(0x0008, 0x0300)); // Current Patient Location - removals_.insert(DicomTag(0x0008, 0x1010)); // Station Name - removals_.insert(DicomTag(0x0008, 0x1030)); // Study Description - removals_.insert(DicomTag(0x0008, 0x103e)); // Series Description - removals_.insert(DicomTag(0x0008, 0x1040)); // Institutional Department Name - removals_.insert(DicomTag(0x0008, 0x1048)); // Physician(s) of Record - removals_.insert(DicomTag(0x0008, 0x1049)); // Physician(s) of Record Identification Sequence - removals_.insert(DicomTag(0x0008, 0x1050)); // Performing Physicians' Name - removals_.insert(DicomTag(0x0008, 0x1052)); // Performing Physicians Identification Sequence - removals_.insert(DicomTag(0x0008, 0x1060)); // Name of Physician(s) Reading Study - removals_.insert(DicomTag(0x0008, 0x1062)); // Physician Reading Study Identification Sequence - removals_.insert(DicomTag(0x0008, 0x1070)); // Operators' Name - removals_.insert(DicomTag(0x0008, 0x1072)); // Operators' Identification Sequence - removals_.insert(DicomTag(0x0008, 0x1080)); // Admitting Diagnoses Description - removals_.insert(DicomTag(0x0008, 0x1084)); // Admitting Diagnoses Code Sequence - removals_.insert(DicomTag(0x0008, 0x1110)); // Referenced Study Sequence - removals_.insert(DicomTag(0x0008, 0x1111)); // Referenced Performed Procedure Step Sequence - removals_.insert(DicomTag(0x0008, 0x1120)); // Referenced Patient Sequence - removals_.insert(DicomTag(0x0008, 0x1140)); // Referenced Image Sequence - removals_.insert(DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID - removals_.insert(DicomTag(0x0008, 0x1195)); // Transaction UID - removals_.insert(DicomTag(0x0008, 0x2111)); // Derivation Description - removals_.insert(DicomTag(0x0008, 0x2112)); // Source Image Sequence - removals_.insert(DicomTag(0x0008, 0x4000)); // Identifying Comments - removals_.insert(DicomTag(0x0008, 0x9123)); // Creator Version UID - //removals_.insert(DicomTag(0x0010, 0x0010)); // Patient's Name => cf. below (*) - //removals_.insert(DicomTag(0x0010, 0x0020)); // Patient ID => cf. below (*) - removals_.insert(DicomTag(0x0010, 0x0030)); // Patient's Birth Date - removals_.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time - clearings_.insert(DicomTag(0x0010, 0x0040)); // Patient's Sex - removals_.insert(DicomTag(0x0010, 0x0050)); // Patient's Insurance Plan Code Sequence - removals_.insert(DicomTag(0x0010, 0x0101)); // Patient's Primary Language Code Sequence - removals_.insert(DicomTag(0x0010, 0x0102)); // Patient's Primary Language Modifier Code Sequence - removals_.insert(DicomTag(0x0010, 0x1000)); // Other Patient Ids - removals_.insert(DicomTag(0x0010, 0x1001)); // Other Patient Names - removals_.insert(DicomTag(0x0010, 0x1002)); // Other Patient IDs Sequence - removals_.insert(DicomTag(0x0010, 0x1005)); // Patient's Birth Name - removals_.insert(DicomTag(0x0010, 0x1010)); // Patient's Age - removals_.insert(DicomTag(0x0010, 0x1020)); // Patient's Size - removals_.insert(DicomTag(0x0010, 0x1030)); // Patient's Weight - removals_.insert(DicomTag(0x0010, 0x1040)); // Patient's Address - removals_.insert(DicomTag(0x0010, 0x1050)); // Insurance Plan Identification - removals_.insert(DicomTag(0x0010, 0x1060)); // Patient's Mother's Birth Name - removals_.insert(DicomTag(0x0010, 0x1080)); // Military Rank - removals_.insert(DicomTag(0x0010, 0x1081)); // Branch of Service - removals_.insert(DicomTag(0x0010, 0x1090)); // Medical Record Locator - removals_.insert(DicomTag(0x0010, 0x2000)); // Medical Alerts - removals_.insert(DicomTag(0x0010, 0x2110)); // Allergies - removals_.insert(DicomTag(0x0010, 0x2150)); // Country of Residence - removals_.insert(DicomTag(0x0010, 0x2152)); // Region of Residence - removals_.insert(DicomTag(0x0010, 0x2154)); // PatientTelephoneNumbers - removals_.insert(DicomTag(0x0010, 0x2160)); // Ethnic Group - removals_.insert(DicomTag(0x0010, 0x2180)); // Occupation - removals_.insert(DicomTag(0x0010, 0x21a0)); // Smoking Status - removals_.insert(DicomTag(0x0010, 0x21b0)); // Additional Patient's History - removals_.insert(DicomTag(0x0010, 0x21c0)); // Pregnancy Status - removals_.insert(DicomTag(0x0010, 0x21d0)); // Last Menstrual Date - removals_.insert(DicomTag(0x0010, 0x21f0)); // Patient's Religious Preference - removals_.insert(DicomTag(0x0010, 0x2203)); // Patient's Sex Neutered - removals_.insert(DicomTag(0x0010, 0x2297)); // Responsible Person - removals_.insert(DicomTag(0x0010, 0x2299)); // Responsible Organization - removals_.insert(DicomTag(0x0010, 0x4000)); // Patient Comments - removals_.insert(DicomTag(0x0018, 0x0010)); // Contrast Bolus Agent - removals_.insert(DicomTag(0x0018, 0x1000)); // Device Serial Number - removals_.insert(DicomTag(0x0018, 0x1002)); // Device UID - removals_.insert(DicomTag(0x0018, 0x1004)); // Plate ID - removals_.insert(DicomTag(0x0018, 0x1005)); // Generator ID - removals_.insert(DicomTag(0x0018, 0x1007)); // Cassette ID - removals_.insert(DicomTag(0x0018, 0x1008)); // Gantry ID - removals_.insert(DicomTag(0x0018, 0x1030)); // Protocol Name - removals_.insert(DicomTag(0x0018, 0x1400)); // Acquisition Device Processing Description - removals_.insert(DicomTag(0x0018, 0x4000)); // Acquisition Comments - removals_.insert(DicomTag(0x0018, 0x700a)); // Detector ID - removals_.insert(DicomTag(0x0018, 0xa003)); // Contribution Description - removals_.insert(DicomTag(0x0018, 0x9424)); // Acquisition Protocol Description - //removals_.insert(DicomTag(0x0020, 0x000d)); // Study Instance UID => set in Apply() - //removals_.insert(DicomTag(0x0020, 0x000e)); // Series Instance UID => set in Apply() - removals_.insert(DicomTag(0x0020, 0x0010)); // Study ID - removals_.insert(DicomTag(0x0020, 0x0052)); // Frame of Reference UID - removals_.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID - removals_.insert(DicomTag(0x0020, 0x3401)); // Modifying Device ID - removals_.insert(DicomTag(0x0020, 0x3404)); // Modifying Device Manufacturer - removals_.insert(DicomTag(0x0020, 0x3406)); // Modified Image Description - removals_.insert(DicomTag(0x0020, 0x4000)); // Image Comments - removals_.insert(DicomTag(0x0020, 0x9158)); // Frame Comments - removals_.insert(DicomTag(0x0020, 0x9161)); // Concatenation UID - removals_.insert(DicomTag(0x0020, 0x9164)); // Dimension Organization UID - //removals_.insert(DicomTag(0x0028, 0x1199)); // Palette Color Lookup Table UID => TODO: replace with a non-zero length UID that is internally consistent within a set of Instances - //removals_.insert(DicomTag(0x0028, 0x1214)); // Large Palette Color Lookup Table UID => TODO: replace with a non-zero length UID that is internally consistent within a set of Instances - removals_.insert(DicomTag(0x0028, 0x4000)); // Image Presentation Comments - removals_.insert(DicomTag(0x0032, 0x0012)); // Study ID Issuer - removals_.insert(DicomTag(0x0032, 0x1020)); // Scheduled Study Location - removals_.insert(DicomTag(0x0032, 0x1021)); // Scheduled Study Location AE Title - removals_.insert(DicomTag(0x0032, 0x1030)); // Reason for Study - removals_.insert(DicomTag(0x0032, 0x1032)); // Requesting Physician - removals_.insert(DicomTag(0x0032, 0x1033)); // Requesting Service - removals_.insert(DicomTag(0x0032, 0x1060)); // Requesting Procedure Description - removals_.insert(DicomTag(0x0032, 0x1070)); // Requested Contrast Agent - removals_.insert(DicomTag(0x0032, 0x4000)); // Study Comments - removals_.insert(DicomTag(0x0038, 0x0010)); // Admission ID - removals_.insert(DicomTag(0x0038, 0x0011)); // Issuer of Admission ID - removals_.insert(DicomTag(0x0038, 0x001e)); // Scheduled Patient Institution Residence - removals_.insert(DicomTag(0x0038, 0x0020)); // Admitting Date - removals_.insert(DicomTag(0x0038, 0x0021)); // Admitting Time - removals_.insert(DicomTag(0x0038, 0x0040)); // Discharge Diagnosis Description - removals_.insert(DicomTag(0x0038, 0x0050)); // Special Needs - removals_.insert(DicomTag(0x0038, 0x0060)); // Service Episode ID - removals_.insert(DicomTag(0x0038, 0x0061)); // Issuer of Service Episode ID - removals_.insert(DicomTag(0x0038, 0x0062)); // Service Episode Description - removals_.insert(DicomTag(0x0038, 0x0400)); // Patient's Institution Residence - removals_.insert(DicomTag(0x0038, 0x0500)); // Patient State - removals_.insert(DicomTag(0x0038, 0x4000)); // Visit Comments - removals_.insert(DicomTag(0x0038, 0x1234)); // Referenced Patient Alias Sequence - removals_.insert(DicomTag(0x0040, 0x0001)); // Scheduled Station AE Title - removals_.insert(DicomTag(0x0040, 0x0002)); // Scheduled Procedure Step Start Date - removals_.insert(DicomTag(0x0040, 0x0003)); // Scheduled Procedure Step Start Time - removals_.insert(DicomTag(0x0040, 0x0004)); // Scheduled Procedure Step End Date - removals_.insert(DicomTag(0x0040, 0x0005)); // Scheduled Procedure Step End Time - removals_.insert(DicomTag(0x0040, 0x0006)); // Scheduled Performing Physician Name - removals_.insert(DicomTag(0x0040, 0x0007)); // Scheduled Procedure Step Description - removals_.insert(DicomTag(0x0040, 0x000b)); // Scheduled Performing Physician Identification Sequence - removals_.insert(DicomTag(0x0040, 0x0010)); // Scheduled Station Name - removals_.insert(DicomTag(0x0040, 0x0011)); // Scheduled Procedure Step Location - removals_.insert(DicomTag(0x0040, 0x0012)); // Pre-Medication - removals_.insert(DicomTag(0x0040, 0x0241)); // Performed Station AE Title - removals_.insert(DicomTag(0x0040, 0x0242)); // Performed Station Name - removals_.insert(DicomTag(0x0040, 0x0243)); // Performed Location - removals_.insert(DicomTag(0x0040, 0x0244)); // Performed Procedure Step Start Date - removals_.insert(DicomTag(0x0040, 0x0245)); // Performed Procedure Step Start Time - removals_.insert(DicomTag(0x0040, 0x0248)); // Performed Station Name Code Sequence - removals_.insert(DicomTag(0x0040, 0x0253)); // Performed Procedure Step ID - removals_.insert(DicomTag(0x0040, 0x0254)); // Performed Procedure Step Description - removals_.insert(DicomTag(0x0040, 0x0275)); // Request Attributes Sequence - removals_.insert(DicomTag(0x0040, 0x0280)); // Comments on Performed Procedure Step - removals_.insert(DicomTag(0x0040, 0x0555)); // Acquisition Context Sequence - removals_.insert(DicomTag(0x0040, 0x1001)); // Requested Procedure ID - removals_.insert(DicomTag(0x0040, 0x1010)); // Names of Intended Recipient of Results - removals_.insert(DicomTag(0x0040, 0x1011)); // Intended Recipient of Results Identification Sequence - removals_.insert(DicomTag(0x0040, 0x1004)); // Patient Transport Arrangements - removals_.insert(DicomTag(0x0040, 0x1005)); // Requested Procedure Location - removals_.insert(DicomTag(0x0040, 0x1101)); // Person Identification Code Sequence - removals_.insert(DicomTag(0x0040, 0x1102)); // Person Address - removals_.insert(DicomTag(0x0040, 0x1103)); // Person Telephone Numbers - removals_.insert(DicomTag(0x0040, 0x1400)); // Requested Procedure Comments - removals_.insert(DicomTag(0x0040, 0x2001)); // Reason for Imaging Service Request - removals_.insert(DicomTag(0x0040, 0x2008)); // Order Entered By - removals_.insert(DicomTag(0x0040, 0x2009)); // Order Enterer Location - removals_.insert(DicomTag(0x0040, 0x2010)); // Order Callback Phone Number - removals_.insert(DicomTag(0x0040, 0x2016)); // Placer Order Number of Imaging Service Request - removals_.insert(DicomTag(0x0040, 0x2017)); // Filler Order Number of Imaging Service Request - removals_.insert(DicomTag(0x0040, 0x2400)); // Imaging Service Request Comments - removals_.insert(DicomTag(0x0040, 0x4023)); // Referenced General Purpose Scheduled Procedure Step Transaction UID - removals_.insert(DicomTag(0x0040, 0x4025)); // Scheduled Station Name Code Sequence - removals_.insert(DicomTag(0x0040, 0x4027)); // Scheduled Station Geographic Location Code Sequence - removals_.insert(DicomTag(0x0040, 0x4030)); // Performed Station Geographic Location Code Sequence - removals_.insert(DicomTag(0x0040, 0x4034)); // Scheduled Human Performers Sequence - removals_.insert(DicomTag(0x0040, 0x4035)); // Actual Human Performers Sequence - removals_.insert(DicomTag(0x0040, 0x4036)); // Human Performers Organization - removals_.insert(DicomTag(0x0040, 0x4037)); // Human Performers Name - removals_.insert(DicomTag(0x0040, 0xa027)); // Verifying Organization - removals_.insert(DicomTag(0x0040, 0xa073)); // Verifying Observer Sequence - removals_.insert(DicomTag(0x0040, 0xa075)); // Verifying Observer Name - removals_.insert(DicomTag(0x0040, 0xa078)); // Author Observer Sequence - removals_.insert(DicomTag(0x0040, 0xa07a)); // Participant Sequence - removals_.insert(DicomTag(0x0040, 0xa07c)); // Custodial Organization Sequence - removals_.insert(DicomTag(0x0040, 0xa088)); // Verifying Observer Identification Code Sequence - removals_.insert(DicomTag(0x0040, 0xa123)); // Person Name - removals_.insert(DicomTag(0x0040, 0xa124)); // UID - removals_.insert(DicomTag(0x0040, 0xa730)); // Content Sequence - removals_.insert(DicomTag(0x0040, 0x3001)); // Confidentiality Constraint on Patient Data Description - removals_.insert(DicomTag(0x0040, 0xdb0c)); // Template Extension Organization UID - removals_.insert(DicomTag(0x0040, 0xdb0d)); // Template Extension Creator UID - removals_.insert(DicomTag(0x0070, 0x0001)); // Graphic Annotation Sequence - removals_.insert(DicomTag(0x0070, 0x0084)); // Content Creator's Name - removals_.insert(DicomTag(0x0070, 0x0086)); // Content Creator's Identification Code Sequence - removals_.insert(DicomTag(0x0070, 0x031a)); // Fiducial UID - removals_.insert(DicomTag(0x0088, 0x0140)); // Storage Media File-set UID - removals_.insert(DicomTag(0x0088, 0x0200)); // Icon Image Sequence - removals_.insert(DicomTag(0x0088, 0x0904)); // Topic Title - removals_.insert(DicomTag(0x0088, 0x0906)); // Topic Subject - removals_.insert(DicomTag(0x0088, 0x0910)); // Topic Author - removals_.insert(DicomTag(0x0088, 0x0912)); // Topic Key Words - removals_.insert(DicomTag(0x0400, 0x0100)); // Digital Signature UID - removals_.insert(DicomTag(0x0400, 0x0402)); // Referenced Digital Signature Sequence - removals_.insert(DicomTag(0x0400, 0x0403)); // Referenced SOP Instance MAC Sequence - removals_.insert(DicomTag(0x0400, 0x0404)); // MAC - removals_.insert(DicomTag(0x0400, 0x0550)); // Modified Attributes Sequence - removals_.insert(DicomTag(0x0400, 0x0561)); // Original Attributes Sequence - removals_.insert(DicomTag(0x2030, 0x0020)); // Text String - removals_.insert(DicomTag(0x3006, 0x0024)); // Referenced Frame of Reference UID - removals_.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID - removals_.insert(DicomTag(0x300a, 0x0013)); // Dose Reference UID - removals_.insert(DicomTag(0x300e, 0x0008)); // Reviewer Name - removals_.insert(DicomTag(0x4000, 0x0010)); // Arbitrary - removals_.insert(DicomTag(0x4000, 0x4000)); // Text Comments - removals_.insert(DicomTag(0x4008, 0x0042)); // Results ID Issuer - removals_.insert(DicomTag(0x4008, 0x0102)); // Interpretation Recorder - removals_.insert(DicomTag(0x4008, 0x010a)); // Interpretation Transcriber - removals_.insert(DicomTag(0x4008, 0x010b)); // Interpretation Text - removals_.insert(DicomTag(0x4008, 0x010c)); // Interpretation Author - removals_.insert(DicomTag(0x4008, 0x0111)); // Interpretation Approver Sequence - removals_.insert(DicomTag(0x4008, 0x0114)); // Physician Approving Interpretation - removals_.insert(DicomTag(0x4008, 0x0115)); // Interpretation Diagnosis Description - removals_.insert(DicomTag(0x4008, 0x0118)); // Results Distribution List Sequence - removals_.insert(DicomTag(0x4008, 0x0119)); // Distribution Name - removals_.insert(DicomTag(0x4008, 0x011a)); // Distribution Address - removals_.insert(DicomTag(0x4008, 0x0202)); // Interpretation ID Issuer - removals_.insert(DicomTag(0x4008, 0x0300)); // Impressions - removals_.insert(DicomTag(0x4008, 0x4000)); // Results Comments - removals_.insert(DicomTag(0xfffa, 0xfffa)); // Digital Signature Sequence - removals_.insert(DicomTag(0xfffc, 0xfffc)); // Data Set Trailing Padding - //removals_.insert(DicomTag(0x60xx, 0x4000)); // Overlay Comments => TODO - //removals_.insert(DicomTag(0x60xx, 0x3000)); // Overlay Data => TODO - - // Set the DeidentificationMethod tag - ReplaceInternal(DICOM_TAG_DEIDENTIFICATION_METHOD, ORTHANC_DEIDENTIFICATION_METHOD_2011); - }