1730 lines
48 KiB
C++
1730 lines
48 KiB
C++
/**
|
|
* 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-2025 Orthanc Team SRL, Belgium
|
|
* Copyright (C) 2021-2025 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 <http://www.gnu.org/licenses/>.
|
|
**/
|
|
|
|
|
|
#pragma once
|
|
|
|
#include "OrthancPluginException.h"
|
|
|
|
#include <orthanc/OrthancCPlugin.h>
|
|
#include <boost/noncopyable.hpp>
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
#include <json/value.h>
|
|
#include <vector>
|
|
#include <list>
|
|
#include <set>
|
|
#include <map>
|
|
|
|
|
|
|
|
/**
|
|
* The definition of ORTHANC_PLUGINS_VERSION_IS_ABOVE below is for
|
|
* backward compatibility with Orthanc SDK <= 1.3.0.
|
|
*
|
|
* $ hg diff -r Orthanc-1.3.0:Orthanc-1.3.1 ../../../Plugins/Include/orthanc/OrthancCPlugin.h
|
|
*
|
|
**/
|
|
#if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)
|
|
#define ORTHANC_PLUGINS_VERSION_IS_ABOVE(major, minor, revision) \
|
|
(ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER > major || \
|
|
(ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER == major && \
|
|
(ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER > minor || \
|
|
(ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER == minor && \
|
|
ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER >= revision))))
|
|
#endif
|
|
|
|
|
|
#if !defined(ORTHANC_FRAMEWORK_VERSION_IS_ABOVE)
|
|
#define ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(major, minor, revision) \
|
|
(ORTHANC_VERSION_MAJOR > major || \
|
|
(ORTHANC_VERSION_MAJOR == major && \
|
|
(ORTHANC_VERSION_MINOR > minor || \
|
|
(ORTHANC_VERSION_MINOR == minor && \
|
|
ORTHANC_VERSION_REVISION >= revision))))
|
|
#endif
|
|
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 2, 0)
|
|
// The "OrthancPluginFindMatcher()" primitive was introduced in Orthanc 1.2.0
|
|
# define HAS_ORTHANC_PLUGIN_FIND_MATCHER 1
|
|
#else
|
|
# define HAS_ORTHANC_PLUGIN_FIND_MATCHER 0
|
|
#endif
|
|
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 4, 2)
|
|
# define HAS_ORTHANC_PLUGIN_PEERS 1
|
|
# define HAS_ORTHANC_PLUGIN_JOB 1
|
|
#else
|
|
# define HAS_ORTHANC_PLUGIN_PEERS 0
|
|
# define HAS_ORTHANC_PLUGIN_JOB 0
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0)
|
|
# define HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS 1
|
|
#else
|
|
# define HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS 0
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
|
|
# define HAS_ORTHANC_PLUGIN_METRICS 1
|
|
#else
|
|
# define HAS_ORTHANC_PLUGIN_METRICS 0
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 1, 0)
|
|
# define HAS_ORTHANC_PLUGIN_HTTP_CLIENT 1
|
|
#else
|
|
# define HAS_ORTHANC_PLUGIN_HTTP_CLIENT 0
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7)
|
|
# define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT 1
|
|
#else
|
|
# define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT 0
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7)
|
|
# define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER 1
|
|
#else
|
|
# define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER 0
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 0)
|
|
# define HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP 1
|
|
#else
|
|
# define HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP 0
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 9, 2)
|
|
# define HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API 1
|
|
#else
|
|
# define HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API 0
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 10, 1)
|
|
# define HAS_ORTHANC_PLUGIN_WEBDAV 1
|
|
#else
|
|
# define HAS_ORTHANC_PLUGIN_WEBDAV 0
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 4)
|
|
# define HAS_ORTHANC_PLUGIN_LOG_MESSAGE 1
|
|
#else
|
|
# define HAS_ORTHANC_PLUGIN_LOG_MESSAGE 0
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 8)
|
|
# define HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES 1
|
|
# define HAS_ORTHANC_PLUGIN_QUEUES 1
|
|
#else
|
|
# define HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES 0
|
|
# define HAS_ORTHANC_PLUGIN_QUEUES 0
|
|
#endif
|
|
|
|
|
|
// Macro to tag a function as having been deprecated
|
|
#if (__cplusplus >= 201402L) // C++14
|
|
# define ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(f) [[deprecated]] f
|
|
#elif defined(__GNUC__) || defined(__clang__)
|
|
# define ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(f) f __attribute__((deprecated))
|
|
#elif defined(_MSC_VER)
|
|
# define ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(f) __declspec(deprecated) f
|
|
#else
|
|
# define ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED
|
|
#endif
|
|
|
|
|
|
#if !defined(__ORTHANC_FILE__)
|
|
# if defined(_MSC_VER)
|
|
# pragma message("Warning: Macro __ORTHANC_FILE__ is not defined, this will leak the full path of the source files in the binaries")
|
|
# else
|
|
# warning Warning: Macro __ORTHANC_FILE__ is not defined, this will leak the full path of the source files in the binaries
|
|
# endif
|
|
# define __ORTHANC_FILE__ __FILE__
|
|
#endif
|
|
|
|
|
|
#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
|
|
# define ORTHANC_PLUGINS_LOG_ERROR(msg) ::OrthancPlugins::LogMessage(OrthancPluginLogLevel_Error, __ORTHANC_FILE__, __LINE__, msg)
|
|
# define ORTHANC_PLUGINS_LOG_WARNING(msg) ::OrthancPlugins::LogMessage(OrthancPluginLogLevel_Warning, __ORTHANC_FILE__, __LINE__, msg)
|
|
# define ORTHANC_PLUGINS_LOG_INFO(msg) ::OrthancPlugins::LogMessage(OrthancPluginLogLevel_Info, __ORTHANC_FILE__, __LINE__, msg)
|
|
#else
|
|
# define ORTHANC_PLUGINS_LOG_ERROR(msg) ::OrthancPlugins::LogError(msg)
|
|
# define ORTHANC_PLUGINS_LOG_WARNING(msg) ::OrthancPlugins::LogWarning(msg)
|
|
# define ORTHANC_PLUGINS_LOG_INFO(msg) ::OrthancPlugins::LogInfo(msg)
|
|
#endif
|
|
|
|
|
|
namespace OrthancPlugins
|
|
{
|
|
typedef std::map<std::string, std::string> HttpHeaders;
|
|
|
|
typedef void (*RestCallback) (OrthancPluginRestOutput* output,
|
|
const char* url,
|
|
const OrthancPluginHttpRequest* request);
|
|
|
|
void SetGlobalContext(OrthancPluginContext* context);
|
|
|
|
void SetGlobalContext(OrthancPluginContext* context,
|
|
const char* pluginName);
|
|
|
|
void ResetGlobalContext();
|
|
|
|
bool HasGlobalContext();
|
|
|
|
OrthancPluginContext* GetGlobalContext();
|
|
|
|
|
|
class OrthancImage;
|
|
|
|
|
|
class MemoryBuffer : public boost::noncopyable
|
|
{
|
|
private:
|
|
OrthancPluginMemoryBuffer buffer_;
|
|
|
|
void Check(OrthancPluginErrorCode code);
|
|
|
|
bool CheckHttp(OrthancPluginErrorCode code);
|
|
|
|
public:
|
|
MemoryBuffer();
|
|
|
|
~MemoryBuffer()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
OrthancPluginMemoryBuffer* operator*()
|
|
{
|
|
return &buffer_;
|
|
}
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
|
|
// Copy of the given buffer into the memory managed by the Orthanc core
|
|
void Assign(const void* buffer,
|
|
size_t size);
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
|
|
void Assign(const std::string& s);
|
|
#endif
|
|
|
|
// This transfers ownership from "other" to "this"
|
|
void Assign(OrthancPluginMemoryBuffer& other);
|
|
|
|
void Swap(MemoryBuffer& other);
|
|
|
|
OrthancPluginMemoryBuffer Release();
|
|
|
|
const void* GetData() const
|
|
{
|
|
if (buffer_.size > 0)
|
|
{
|
|
return buffer_.data;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
size_t GetSize() const
|
|
{
|
|
return buffer_.size;
|
|
}
|
|
|
|
bool IsEmpty() const
|
|
{
|
|
return GetSize() == 0 || GetData() == NULL;
|
|
}
|
|
|
|
void Clear();
|
|
|
|
void ToString(std::string& target) const;
|
|
|
|
void ToJson(Json::Value& target) const;
|
|
|
|
bool RestApiGet(const std::string& uri,
|
|
bool applyPlugins);
|
|
|
|
bool RestApiGet(const std::string& uri,
|
|
const HttpHeaders& httpHeaders,
|
|
bool applyPlugins);
|
|
|
|
bool RestApiPost(const std::string& uri,
|
|
const void* body,
|
|
size_t bodySize,
|
|
bool applyPlugins);
|
|
|
|
bool RestApiPut(const std::string& uri,
|
|
const void* body,
|
|
size_t bodySize,
|
|
bool applyPlugins);
|
|
|
|
bool RestApiPost(const std::string& uri,
|
|
const Json::Value& body,
|
|
bool applyPlugins);
|
|
|
|
#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
|
|
bool RestApiPost(const std::string& uri,
|
|
const Json::Value& body,
|
|
const HttpHeaders& httpHeaders,
|
|
bool applyPlugins);
|
|
|
|
bool RestApiPost(const std::string& uri,
|
|
const void* body,
|
|
size_t bodySize,
|
|
const HttpHeaders& httpHeaders,
|
|
bool applyPlugins);
|
|
#endif
|
|
|
|
bool RestApiPut(const std::string& uri,
|
|
const Json::Value& body,
|
|
bool applyPlugins);
|
|
|
|
bool RestApiPost(const std::string& uri,
|
|
const std::string& body,
|
|
bool applyPlugins)
|
|
{
|
|
return RestApiPost(uri, body.empty() ? NULL : body.c_str(), body.size(), applyPlugins);
|
|
}
|
|
|
|
bool RestApiPut(const std::string& uri,
|
|
const std::string& body,
|
|
bool applyPlugins)
|
|
{
|
|
return RestApiPut(uri, body.empty() ? NULL : body.c_str(), body.size(), applyPlugins);
|
|
}
|
|
|
|
void CreateDicom(const Json::Value& tags,
|
|
OrthancPluginCreateDicomFlags flags);
|
|
|
|
void CreateDicom(const Json::Value& tags,
|
|
const OrthancImage& pixelData,
|
|
OrthancPluginCreateDicomFlags flags);
|
|
|
|
void ReadFile(const std::string& path);
|
|
|
|
void GetDicomQuery(const OrthancPluginWorklistQuery* query);
|
|
|
|
void DicomToJson(Json::Value& target,
|
|
OrthancPluginDicomToJsonFormat format,
|
|
OrthancPluginDicomToJsonFlags flags,
|
|
uint32_t maxStringLength);
|
|
|
|
bool HttpGet(const std::string& url,
|
|
const std::string& username,
|
|
const std::string& password);
|
|
|
|
bool HttpPost(const std::string& url,
|
|
const std::string& body,
|
|
const std::string& username,
|
|
const std::string& password);
|
|
|
|
bool HttpPut(const std::string& url,
|
|
const std::string& body,
|
|
const std::string& username,
|
|
const std::string& password);
|
|
|
|
void GetDicomInstance(const std::string& instanceId);
|
|
};
|
|
|
|
|
|
class OrthancString : public boost::noncopyable
|
|
{
|
|
private:
|
|
char* str_;
|
|
|
|
void Clear();
|
|
|
|
public:
|
|
OrthancString() :
|
|
str_(NULL)
|
|
{
|
|
}
|
|
|
|
~OrthancString()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
// This transfers ownership, warning: The string must have been
|
|
// allocated by the Orthanc core
|
|
void Assign(char* str);
|
|
|
|
const char* GetContent() const
|
|
{
|
|
return str_;
|
|
}
|
|
|
|
bool IsNullOrEmpty() const
|
|
{
|
|
return str_ == NULL || str_[0] == 0;
|
|
}
|
|
|
|
void ToString(std::string& target) const;
|
|
|
|
void ToJson(Json::Value& target) const;
|
|
|
|
void ToJsonWithoutComments(Json::Value& target) const;
|
|
};
|
|
|
|
|
|
class OrthancConfiguration : public boost::noncopyable
|
|
{
|
|
private:
|
|
Json::Value configuration_; // Necessarily a Json::objectValue
|
|
std::string path_;
|
|
|
|
std::string GetPath(const std::string& key) const;
|
|
|
|
void LoadConfiguration();
|
|
|
|
public:
|
|
OrthancConfiguration(); // loads the full Orthanc configuration
|
|
|
|
explicit OrthancConfiguration(bool load);
|
|
|
|
explicit OrthancConfiguration(const Json::Value& configuration, const std::string& path); // e.g. to load a section from a default json content
|
|
|
|
const Json::Value& GetJson() const
|
|
{
|
|
return configuration_;
|
|
}
|
|
|
|
bool IsSection(const std::string& key) const;
|
|
|
|
void GetSection(OrthancConfiguration& target,
|
|
const std::string& key) const;
|
|
|
|
bool LookupStringValue(std::string& target,
|
|
const std::string& key) const;
|
|
|
|
bool LookupIntegerValue(int& target,
|
|
const std::string& key) const;
|
|
|
|
bool LookupUnsignedIntegerValue(unsigned int& target,
|
|
const std::string& key) const;
|
|
|
|
bool LookupBooleanValue(bool& target,
|
|
const std::string& key) const;
|
|
|
|
bool LookupFloatValue(float& target,
|
|
const std::string& key) const;
|
|
|
|
bool LookupListOfStrings(std::list<std::string>& target,
|
|
const std::string& key,
|
|
bool allowSingleString) const;
|
|
|
|
bool LookupSetOfStrings(std::set<std::string>& target,
|
|
const std::string& key,
|
|
bool allowSingleString) const;
|
|
|
|
std::string GetStringValue(const std::string& key,
|
|
const std::string& defaultValue) const;
|
|
|
|
int GetIntegerValue(const std::string& key,
|
|
int defaultValue) const;
|
|
|
|
unsigned int GetUnsignedIntegerValue(const std::string& key,
|
|
unsigned int defaultValue) const;
|
|
|
|
bool GetBooleanValue(const std::string& key,
|
|
bool defaultValue) const;
|
|
|
|
float GetFloatValue(const std::string& key,
|
|
float defaultValue) const;
|
|
|
|
void GetDictionary(std::map<std::string, std::string>& target,
|
|
const std::string& key) const;
|
|
};
|
|
|
|
class OrthancImage : public boost::noncopyable
|
|
{
|
|
private:
|
|
OrthancPluginImage* image_;
|
|
|
|
void Clear();
|
|
|
|
void CheckImageAvailable() const;
|
|
|
|
public:
|
|
OrthancImage();
|
|
|
|
explicit OrthancImage(OrthancPluginImage* image);
|
|
|
|
OrthancImage(OrthancPluginPixelFormat format,
|
|
uint32_t width,
|
|
uint32_t height);
|
|
|
|
OrthancImage(OrthancPluginPixelFormat format,
|
|
uint32_t width,
|
|
uint32_t height,
|
|
uint32_t pitch,
|
|
void* buffer);
|
|
|
|
~OrthancImage()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
void UncompressPngImage(const void* data,
|
|
size_t size);
|
|
|
|
void UncompressJpegImage(const void* data,
|
|
size_t size);
|
|
|
|
void DecodeDicomImage(const void* data,
|
|
size_t size,
|
|
unsigned int frame);
|
|
|
|
OrthancPluginPixelFormat GetPixelFormat() const;
|
|
|
|
unsigned int GetWidth() const;
|
|
|
|
unsigned int GetHeight() const;
|
|
|
|
unsigned int GetPitch() const;
|
|
|
|
void* GetBuffer() const;
|
|
|
|
const OrthancPluginImage* GetObject() const
|
|
{
|
|
return image_;
|
|
}
|
|
|
|
void CompressPngImage(MemoryBuffer& target) const;
|
|
|
|
void CompressJpegImage(MemoryBuffer& target,
|
|
uint8_t quality) const;
|
|
|
|
void AnswerPngImage(OrthancPluginRestOutput* output) const;
|
|
|
|
void AnswerJpegImage(OrthancPluginRestOutput* output,
|
|
uint8_t quality) const;
|
|
|
|
void* GetWriteableBuffer();
|
|
|
|
OrthancPluginImage* Release();
|
|
};
|
|
|
|
|
|
#if HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1
|
|
class FindMatcher : public boost::noncopyable
|
|
{
|
|
private:
|
|
OrthancPluginFindMatcher* matcher_;
|
|
const OrthancPluginWorklistQuery* worklist_;
|
|
|
|
void SetupDicom(const void* query,
|
|
uint32_t size);
|
|
|
|
public:
|
|
explicit FindMatcher(const OrthancPluginWorklistQuery* worklist);
|
|
|
|
FindMatcher(const void* query,
|
|
uint32_t size)
|
|
{
|
|
SetupDicom(query, size);
|
|
}
|
|
|
|
explicit FindMatcher(const MemoryBuffer& dicom)
|
|
{
|
|
SetupDicom(dicom.GetData(), dicom.GetSize());
|
|
}
|
|
|
|
~FindMatcher();
|
|
|
|
bool IsMatch(const void* dicom,
|
|
uint32_t size) const;
|
|
|
|
bool IsMatch(const MemoryBuffer& dicom) const
|
|
{
|
|
return IsMatch(dicom.GetData(), dicom.GetSize());
|
|
}
|
|
};
|
|
#endif
|
|
|
|
|
|
bool ReadJson(Json::Value& target,
|
|
const std::string& source);
|
|
|
|
bool ReadJson(Json::Value& target,
|
|
const void* buffer,
|
|
size_t size);
|
|
|
|
bool ReadJsonWithoutComments(Json::Value& target,
|
|
const std::string& source);
|
|
|
|
bool ReadJsonWithoutComments(Json::Value& target,
|
|
const void* buffer,
|
|
size_t size);
|
|
|
|
void WriteFastJson(std::string& target,
|
|
const Json::Value& source);
|
|
|
|
void WriteStyledJson(std::string& target,
|
|
const Json::Value& source);
|
|
|
|
bool RestApiGet(Json::Value& result,
|
|
const std::string& uri,
|
|
bool applyPlugins);
|
|
|
|
bool RestApiGet(Json::Value& result,
|
|
const std::string& uri,
|
|
const HttpHeaders& httpHeaders,
|
|
bool applyPlugins);
|
|
|
|
bool RestApiGetString(std::string& result,
|
|
const std::string& uri,
|
|
bool applyPlugins);
|
|
|
|
bool RestApiGetString(std::string& result,
|
|
const std::string& uri,
|
|
const HttpHeaders& httpHeaders,
|
|
bool applyPlugins);
|
|
|
|
bool RestApiPost(std::string& result,
|
|
const std::string& uri,
|
|
const void* body,
|
|
size_t bodySize,
|
|
bool applyPlugins);
|
|
|
|
bool RestApiPost(Json::Value& result,
|
|
const std::string& uri,
|
|
const void* body,
|
|
size_t bodySize,
|
|
bool applyPlugins);
|
|
|
|
#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
|
|
bool RestApiPost(Json::Value& result,
|
|
const std::string& uri,
|
|
const Json::Value& body,
|
|
const HttpHeaders& httpHeaders,
|
|
bool applyPlugins);
|
|
#endif
|
|
|
|
bool RestApiPost(Json::Value& result,
|
|
const std::string& uri,
|
|
const Json::Value& body,
|
|
bool applyPlugins);
|
|
|
|
inline bool RestApiPost(Json::Value& result,
|
|
const std::string& uri,
|
|
const std::string& body,
|
|
bool applyPlugins)
|
|
{
|
|
return RestApiPost(result, uri, body.empty() ? NULL : body.c_str(),
|
|
body.size(), applyPlugins);
|
|
}
|
|
|
|
inline bool RestApiPost(Json::Value& result,
|
|
const std::string& uri,
|
|
const MemoryBuffer& body,
|
|
bool applyPlugins)
|
|
{
|
|
return RestApiPost(result, uri, body.GetData(),
|
|
body.GetSize(), applyPlugins);
|
|
}
|
|
|
|
bool RestApiPut(Json::Value& result,
|
|
const std::string& uri,
|
|
const void* body,
|
|
size_t bodySize,
|
|
bool applyPlugins);
|
|
|
|
bool RestApiPut(Json::Value& result,
|
|
const std::string& uri,
|
|
const Json::Value& body,
|
|
bool applyPlugins);
|
|
|
|
inline bool RestApiPut(Json::Value& result,
|
|
const std::string& uri,
|
|
const std::string& body,
|
|
bool applyPlugins)
|
|
{
|
|
return RestApiPut(result, uri, body.empty() ? NULL : body.c_str(),
|
|
body.size(), applyPlugins);
|
|
}
|
|
|
|
bool RestApiDelete(const std::string& uri,
|
|
bool applyPlugins);
|
|
|
|
bool HttpDelete(const std::string& url,
|
|
const std::string& username,
|
|
const std::string& password);
|
|
|
|
void AnswerJson(const Json::Value& value,
|
|
OrthancPluginRestOutput* output);
|
|
|
|
void AnswerString(const std::string& answer,
|
|
const char* mimeType,
|
|
OrthancPluginRestOutput* output);
|
|
|
|
void AnswerHttpError(uint16_t httpError,
|
|
OrthancPluginRestOutput* output);
|
|
|
|
void AnswerMethodNotAllowed(OrthancPluginRestOutput* output, const char* allowedMethods);
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0)
|
|
const char* AutodetectMimeType(const std::string& path);
|
|
#endif
|
|
|
|
#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
|
|
void LogMessage(OrthancPluginLogLevel level,
|
|
const char* file,
|
|
uint32_t line,
|
|
const std::string& message);
|
|
#endif
|
|
|
|
#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
|
|
// Use macro ORTHANC_PLUGINS_LOG_ERROR() instead
|
|
ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(void LogError(const std::string& message));
|
|
#else
|
|
void LogError(const std::string& message);
|
|
#endif
|
|
|
|
#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
|
|
// Use macro ORTHANC_PLUGINS_LOG_WARNING() instead
|
|
ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(void LogWarning(const std::string& message));
|
|
#else
|
|
void LogWarning(const std::string& message);
|
|
#endif
|
|
|
|
#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
|
|
// Use macro ORTHANC_PLUGINS_LOG_INFO() instead
|
|
ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(void LogInfo(const std::string& message));
|
|
#else
|
|
void LogInfo(const std::string& message);
|
|
#endif
|
|
|
|
void ReportMinimalOrthancVersion(unsigned int major,
|
|
unsigned int minor,
|
|
unsigned int revision);
|
|
|
|
bool CheckMinimalOrthancVersion(unsigned int major,
|
|
unsigned int minor,
|
|
unsigned int revision);
|
|
|
|
bool CheckMinimalVersion(const char* version,
|
|
unsigned int major,
|
|
unsigned int minor,
|
|
unsigned int revision);
|
|
|
|
namespace Internals
|
|
{
|
|
template <RestCallback Callback>
|
|
static OrthancPluginErrorCode Protect(OrthancPluginRestOutput* output,
|
|
const char* url,
|
|
const OrthancPluginHttpRequest* request)
|
|
{
|
|
try
|
|
{
|
|
Callback(output, url, request);
|
|
return OrthancPluginErrorCode_Success;
|
|
}
|
|
catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
|
|
{
|
|
#if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS == 1
|
|
if (HasGlobalContext() &&
|
|
e.HasDetails())
|
|
{
|
|
// The "false" instructs Orthanc not to log the detailed
|
|
// error message. This is to avoid duplicating the details,
|
|
// because "OrthancException" already does it on construction.
|
|
OrthancPluginSetHttpErrorDetails
|
|
(GetGlobalContext(), output, e.GetDetails(), false);
|
|
}
|
|
#endif
|
|
|
|
return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
|
|
}
|
|
catch (boost::bad_lexical_cast&)
|
|
{
|
|
return OrthancPluginErrorCode_BadFileFormat;
|
|
}
|
|
catch (...)
|
|
{
|
|
return OrthancPluginErrorCode_Plugin;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template <RestCallback Callback>
|
|
void RegisterRestCallback(const std::string& uri,
|
|
bool isThreadSafe)
|
|
{
|
|
if (isThreadSafe)
|
|
{
|
|
OrthancPluginRegisterRestCallbackNoLock
|
|
(GetGlobalContext(), uri.c_str(), Internals::Protect<Callback>);
|
|
}
|
|
else
|
|
{
|
|
OrthancPluginRegisterRestCallback
|
|
(GetGlobalContext(), uri.c_str(), Internals::Protect<Callback>);
|
|
}
|
|
}
|
|
|
|
|
|
#if HAS_ORTHANC_PLUGIN_PEERS == 1
|
|
class OrthancPeers : public boost::noncopyable
|
|
{
|
|
private:
|
|
typedef std::map<std::string, uint32_t> Index;
|
|
|
|
OrthancPluginPeers *peers_;
|
|
Index index_;
|
|
uint32_t timeout_;
|
|
|
|
size_t GetPeerIndex(const std::string& name) const;
|
|
|
|
public:
|
|
OrthancPeers();
|
|
|
|
~OrthancPeers();
|
|
|
|
uint32_t GetTimeout() const
|
|
{
|
|
return timeout_;
|
|
}
|
|
|
|
void SetTimeout(uint32_t timeout)
|
|
{
|
|
timeout_ = timeout;
|
|
}
|
|
|
|
bool LookupName(size_t& target,
|
|
const std::string& name) const;
|
|
|
|
std::string GetPeerName(size_t index) const;
|
|
|
|
std::string GetPeerUrl(size_t index) const;
|
|
|
|
std::string GetPeerUrl(const std::string& name) const;
|
|
|
|
size_t GetPeersCount() const
|
|
{
|
|
return index_.size();
|
|
}
|
|
|
|
bool LookupUserProperty(std::string& value,
|
|
size_t index,
|
|
const std::string& key) const;
|
|
|
|
bool LookupUserProperty(std::string& value,
|
|
const std::string& peer,
|
|
const std::string& key) const;
|
|
|
|
bool DoGet(MemoryBuffer& target,
|
|
size_t index,
|
|
const std::string& uri,
|
|
const HttpHeaders& headers) const;
|
|
|
|
bool DoGet(MemoryBuffer& target,
|
|
const std::string& name,
|
|
const std::string& uri,
|
|
const HttpHeaders& headers) const;
|
|
|
|
bool DoGet(Json::Value& target,
|
|
size_t index,
|
|
const std::string& uri,
|
|
const HttpHeaders& headers) const;
|
|
|
|
bool DoGet(Json::Value& target,
|
|
const std::string& name,
|
|
const std::string& uri,
|
|
const HttpHeaders& headers) const;
|
|
|
|
bool DoPost(MemoryBuffer& target,
|
|
size_t index,
|
|
const std::string& uri,
|
|
const std::string& body,
|
|
const HttpHeaders& headers) const;
|
|
|
|
bool DoPost(MemoryBuffer& target,
|
|
size_t index,
|
|
const std::string& uri,
|
|
const std::string& body,
|
|
const HttpHeaders& headers,
|
|
unsigned int timeout) const;
|
|
|
|
bool DoPost(MemoryBuffer& target,
|
|
const std::string& name,
|
|
const std::string& uri,
|
|
const std::string& body,
|
|
const HttpHeaders& headers) const;
|
|
|
|
bool DoPost(Json::Value& target,
|
|
size_t index,
|
|
const std::string& uri,
|
|
const std::string& body,
|
|
const HttpHeaders& headers) const;
|
|
|
|
bool DoPost(Json::Value& target,
|
|
size_t index,
|
|
const std::string& uri,
|
|
const std::string& body,
|
|
const HttpHeaders& headers,
|
|
unsigned int timeout) const;
|
|
|
|
bool DoPost(Json::Value& target,
|
|
const std::string& name,
|
|
const std::string& uri,
|
|
const std::string& body,
|
|
const HttpHeaders& headers) const;
|
|
|
|
bool DoPut(size_t index,
|
|
const std::string& uri,
|
|
const std::string& body,
|
|
const HttpHeaders& headers) const;
|
|
|
|
bool DoPut(const std::string& name,
|
|
const std::string& uri,
|
|
const std::string& body,
|
|
const HttpHeaders& headers) const;
|
|
|
|
bool DoDelete(size_t index,
|
|
const std::string& uri,
|
|
const HttpHeaders& headers) const;
|
|
|
|
bool DoDelete(const std::string& name,
|
|
const std::string& uri,
|
|
const HttpHeaders& headers) const;
|
|
};
|
|
#endif
|
|
|
|
|
|
|
|
#if HAS_ORTHANC_PLUGIN_JOB == 1
|
|
class OrthancJob : public boost::noncopyable
|
|
{
|
|
private:
|
|
std::string jobType_;
|
|
std::string content_;
|
|
bool hasSerialized_;
|
|
std::string serialized_;
|
|
float progress_;
|
|
|
|
static void CallbackFinalize(void* job);
|
|
|
|
static float CallbackGetProgress(void* job);
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 11, 3)
|
|
static OrthancPluginErrorCode CallbackGetContent(OrthancPluginMemoryBuffer* target,
|
|
void* job);
|
|
#else
|
|
static const char* CallbackGetContent(void* job);
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 11, 3)
|
|
static int32_t CallbackGetSerialized(OrthancPluginMemoryBuffer* target,
|
|
void* job);
|
|
#else
|
|
static const char* CallbackGetSerialized(void* job);
|
|
#endif
|
|
|
|
static OrthancPluginJobStepStatus CallbackStep(void* job);
|
|
|
|
static OrthancPluginErrorCode CallbackStop(void* job,
|
|
OrthancPluginJobStopReason reason);
|
|
|
|
static OrthancPluginErrorCode CallbackReset(void* job);
|
|
|
|
protected:
|
|
void ClearContent();
|
|
|
|
void UpdateContent(const Json::Value& content);
|
|
|
|
void ClearSerialized();
|
|
|
|
void UpdateSerialized(const Json::Value& serialized);
|
|
|
|
void UpdateProgress(float progress);
|
|
|
|
public:
|
|
explicit OrthancJob(const std::string& jobType);
|
|
|
|
virtual ~OrthancJob()
|
|
{
|
|
}
|
|
|
|
virtual OrthancPluginJobStepStatus Step() = 0;
|
|
|
|
virtual void Stop(OrthancPluginJobStopReason reason) = 0;
|
|
|
|
virtual void Reset() = 0;
|
|
|
|
static OrthancPluginJob* Create(OrthancJob* job /* takes ownership */);
|
|
|
|
static std::string Submit(OrthancJob* job /* takes ownership */,
|
|
int priority);
|
|
|
|
static void SubmitAndWait(Json::Value& result,
|
|
OrthancJob* job /* takes ownership */,
|
|
int priority);
|
|
|
|
// Submit a job from a POST on the REST API with the same
|
|
// conventions as in the Orthanc core (according to the
|
|
// "Synchronous" and "Priority" options)
|
|
static void SubmitFromRestApiPost(OrthancPluginRestOutput* output,
|
|
const Json::Value& body,
|
|
OrthancJob* job);
|
|
};
|
|
#endif
|
|
|
|
|
|
#if HAS_ORTHANC_PLUGIN_METRICS == 1
|
|
inline void SetMetricsValue(char* name,
|
|
float value)
|
|
{
|
|
OrthancPluginSetMetricsValue(GetGlobalContext(), name,
|
|
value, OrthancPluginMetricsType_Default);
|
|
}
|
|
|
|
class MetricsTimer : public boost::noncopyable
|
|
{
|
|
private:
|
|
std::string name_;
|
|
boost::posix_time::ptime start_;
|
|
|
|
public:
|
|
explicit MetricsTimer(const char* name);
|
|
|
|
~MetricsTimer();
|
|
};
|
|
#endif
|
|
|
|
|
|
#if HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1
|
|
class HttpClient : public boost::noncopyable
|
|
{
|
|
public:
|
|
class IRequestBody : public boost::noncopyable
|
|
{
|
|
public:
|
|
virtual ~IRequestBody()
|
|
{
|
|
}
|
|
|
|
virtual bool ReadNextChunk(std::string& chunk) = 0;
|
|
};
|
|
|
|
|
|
class IAnswer : public boost::noncopyable
|
|
{
|
|
public:
|
|
virtual ~IAnswer()
|
|
{
|
|
}
|
|
|
|
virtual void AddHeader(const std::string& key,
|
|
const std::string& value) = 0;
|
|
|
|
virtual void AddChunk(const void* data,
|
|
size_t size) = 0;
|
|
};
|
|
|
|
|
|
private:
|
|
class RequestBodyWrapper;
|
|
|
|
uint16_t httpStatus_;
|
|
OrthancPluginHttpMethod method_;
|
|
std::string url_;
|
|
HttpHeaders headers_;
|
|
std::string username_;
|
|
std::string password_;
|
|
uint32_t timeout_;
|
|
std::string certificateFile_;
|
|
std::string certificateKeyFile_;
|
|
std::string certificateKeyPassword_;
|
|
bool pkcs11_;
|
|
std::string fullBody_;
|
|
IRequestBody* chunkedBody_;
|
|
bool allowChunkedTransfers_;
|
|
|
|
#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1
|
|
void ExecuteWithStream(uint16_t& httpStatus, // out
|
|
IAnswer& answer, // out
|
|
IRequestBody& body) const;
|
|
#endif
|
|
|
|
void ExecuteWithoutStream(uint16_t& httpStatus, // out
|
|
HttpHeaders& answerHeaders, // out
|
|
std::string& answerBody, // out
|
|
const std::string& body) const;
|
|
|
|
public:
|
|
HttpClient();
|
|
|
|
uint16_t GetHttpStatus() const
|
|
{
|
|
return httpStatus_;
|
|
}
|
|
|
|
void SetMethod(OrthancPluginHttpMethod method)
|
|
{
|
|
method_ = method;
|
|
}
|
|
|
|
const std::string& GetUrl() const
|
|
{
|
|
return url_;
|
|
}
|
|
|
|
void SetUrl(const std::string& url)
|
|
{
|
|
url_ = url;
|
|
}
|
|
|
|
void SetHeaders(const HttpHeaders& headers)
|
|
{
|
|
headers_ = headers;
|
|
}
|
|
|
|
void AddHeader(const std::string& key,
|
|
const std::string& value)
|
|
{
|
|
headers_[key] = value;
|
|
}
|
|
|
|
void AddHeaders(const HttpHeaders& headers);
|
|
|
|
void SetCredentials(const std::string& username,
|
|
const std::string& password);
|
|
|
|
void ClearCredentials();
|
|
|
|
void SetTimeout(unsigned int timeout) // 0 for default timeout
|
|
{
|
|
timeout_ = timeout;
|
|
}
|
|
|
|
void SetCertificate(const std::string& certificateFile,
|
|
const std::string& keyFile,
|
|
const std::string& keyPassword);
|
|
|
|
void ClearCertificate();
|
|
|
|
void SetPkcs11(bool pkcs11)
|
|
{
|
|
pkcs11_ = pkcs11;
|
|
}
|
|
|
|
void ClearBody();
|
|
|
|
void SwapBody(std::string& body);
|
|
|
|
void SetBody(const std::string& body);
|
|
|
|
void SetBody(IRequestBody& body);
|
|
|
|
// This function can be used to disable chunked transfers if the
|
|
// remote server is Orthanc with a version <= 1.5.6.
|
|
void SetChunkedTransfersAllowed(bool allow)
|
|
{
|
|
allowChunkedTransfers_ = allow;
|
|
}
|
|
|
|
bool IsChunkedTransfersAllowed() const
|
|
{
|
|
return allowChunkedTransfers_;
|
|
}
|
|
|
|
void Execute(IAnswer& answer);
|
|
|
|
void Execute(HttpHeaders& answerHeaders /* out */,
|
|
std::string& answerBody /* out */);
|
|
|
|
void Execute(HttpHeaders& answerHeaders /* out */,
|
|
Json::Value& answerBody /* out */);
|
|
|
|
void Execute();
|
|
};
|
|
#endif
|
|
|
|
|
|
|
|
class IChunkedRequestReader : public boost::noncopyable
|
|
{
|
|
public:
|
|
virtual ~IChunkedRequestReader()
|
|
{
|
|
}
|
|
|
|
virtual void AddChunk(const void* data,
|
|
size_t size) = 0;
|
|
|
|
virtual void Execute(OrthancPluginRestOutput* output) = 0;
|
|
};
|
|
|
|
|
|
typedef IChunkedRequestReader* (*ChunkedRestCallback) (const char* url,
|
|
const OrthancPluginHttpRequest* request);
|
|
|
|
|
|
namespace Internals
|
|
{
|
|
void NullRestCallback(OrthancPluginRestOutput* output,
|
|
const char* url,
|
|
const OrthancPluginHttpRequest* request);
|
|
|
|
IChunkedRequestReader *NullChunkedRestCallback(const char* url,
|
|
const OrthancPluginHttpRequest* request);
|
|
|
|
|
|
#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
|
|
template <ChunkedRestCallback Callback>
|
|
static OrthancPluginErrorCode ChunkedProtect(OrthancPluginServerChunkedRequestReader** reader,
|
|
const char* url,
|
|
const OrthancPluginHttpRequest* request)
|
|
{
|
|
try
|
|
{
|
|
if (reader == NULL)
|
|
{
|
|
return OrthancPluginErrorCode_InternalError;
|
|
}
|
|
else
|
|
{
|
|
*reader = reinterpret_cast<OrthancPluginServerChunkedRequestReader*>(Callback(url, request));
|
|
if (*reader == NULL)
|
|
{
|
|
return OrthancPluginErrorCode_Plugin;
|
|
}
|
|
else
|
|
{
|
|
return OrthancPluginErrorCode_Success;
|
|
}
|
|
}
|
|
}
|
|
catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
|
|
{
|
|
return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
|
|
}
|
|
catch (boost::bad_lexical_cast&)
|
|
{
|
|
return OrthancPluginErrorCode_BadFileFormat;
|
|
}
|
|
catch (...)
|
|
{
|
|
return OrthancPluginErrorCode_Plugin;
|
|
}
|
|
}
|
|
|
|
OrthancPluginErrorCode ChunkedRequestReaderAddChunk(
|
|
OrthancPluginServerChunkedRequestReader* reader,
|
|
const void* data,
|
|
uint32_t size);
|
|
|
|
OrthancPluginErrorCode ChunkedRequestReaderExecute(
|
|
OrthancPluginServerChunkedRequestReader* reader,
|
|
OrthancPluginRestOutput* output);
|
|
|
|
void ChunkedRequestReaderFinalize(
|
|
OrthancPluginServerChunkedRequestReader* reader);
|
|
|
|
#else
|
|
|
|
OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output,
|
|
const char* url,
|
|
const OrthancPluginHttpRequest* request,
|
|
RestCallback GetHandler,
|
|
ChunkedRestCallback PostHandler,
|
|
RestCallback DeleteHandler,
|
|
ChunkedRestCallback PutHandler);
|
|
|
|
template<
|
|
RestCallback GetHandler,
|
|
ChunkedRestCallback PostHandler,
|
|
RestCallback DeleteHandler,
|
|
ChunkedRestCallback PutHandler
|
|
>
|
|
inline OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output,
|
|
const char* url,
|
|
const OrthancPluginHttpRequest* request)
|
|
{
|
|
return ChunkedRestCompatibility(output, url, request, GetHandler,
|
|
PostHandler, DeleteHandler, PutHandler);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
// NB: We use a templated class instead of a templated function, because
|
|
// default values are only available in functions since C++11
|
|
template<
|
|
RestCallback GetHandler = Internals::NullRestCallback,
|
|
ChunkedRestCallback PostHandler = Internals::NullChunkedRestCallback,
|
|
RestCallback DeleteHandler = Internals::NullRestCallback,
|
|
ChunkedRestCallback PutHandler = Internals::NullChunkedRestCallback
|
|
>
|
|
class ChunkedRestRegistration : public boost::noncopyable
|
|
{
|
|
public:
|
|
static void Apply(const std::string& uri)
|
|
{
|
|
#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
|
|
OrthancPluginRegisterChunkedRestCallback(
|
|
GetGlobalContext(), uri.c_str(),
|
|
GetHandler == Internals::NullRestCallback ? NULL : Internals::Protect<GetHandler>,
|
|
PostHandler == Internals::NullChunkedRestCallback ? NULL : Internals::ChunkedProtect<PostHandler>,
|
|
DeleteHandler == Internals::NullRestCallback ? NULL : Internals::Protect<DeleteHandler>,
|
|
PutHandler == Internals::NullChunkedRestCallback ? NULL : Internals::ChunkedProtect<PutHandler>,
|
|
Internals::ChunkedRequestReaderAddChunk,
|
|
Internals::ChunkedRequestReaderExecute,
|
|
Internals::ChunkedRequestReaderFinalize);
|
|
#else
|
|
OrthancPluginRegisterRestCallbackNoLock(
|
|
GetGlobalContext(), uri.c_str(),
|
|
Internals::ChunkedRestCompatibility<GetHandler, PostHandler, DeleteHandler, PutHandler>);
|
|
#endif
|
|
}
|
|
};
|
|
|
|
|
|
|
|
#if HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP == 1
|
|
class IStorageCommitmentScpHandler : public boost::noncopyable
|
|
{
|
|
public:
|
|
virtual ~IStorageCommitmentScpHandler()
|
|
{
|
|
}
|
|
|
|
virtual OrthancPluginStorageCommitmentFailureReason Lookup(const std::string& sopClassUid,
|
|
const std::string& sopInstanceUid) = 0;
|
|
|
|
static OrthancPluginErrorCode Lookup(OrthancPluginStorageCommitmentFailureReason* target,
|
|
void* rawHandler,
|
|
const char* sopClassUid,
|
|
const char* sopInstanceUid);
|
|
|
|
static void Destructor(void* rawHandler);
|
|
};
|
|
#endif
|
|
|
|
|
|
class DicomInstance : public boost::noncopyable
|
|
{
|
|
private:
|
|
bool toFree_;
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
|
|
const OrthancPluginDicomInstance* instance_;
|
|
#else
|
|
OrthancPluginDicomInstance* instance_;
|
|
#endif
|
|
|
|
public:
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
|
|
explicit DicomInstance(const OrthancPluginDicomInstance* instance);
|
|
#else
|
|
explicit DicomInstance(OrthancPluginDicomInstance* instance);
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
|
|
DicomInstance(const void* buffer,
|
|
size_t size);
|
|
#endif
|
|
|
|
~DicomInstance();
|
|
|
|
const OrthancPluginDicomInstance* GetObject() const
|
|
{
|
|
return instance_;
|
|
}
|
|
|
|
std::string GetRemoteAet() const;
|
|
|
|
const void* GetBuffer() const
|
|
{
|
|
return OrthancPluginGetInstanceData(GetGlobalContext(), instance_);
|
|
}
|
|
|
|
size_t GetSize() const
|
|
{
|
|
return static_cast<size_t>(OrthancPluginGetInstanceSize(GetGlobalContext(), instance_));
|
|
}
|
|
|
|
void GetJson(Json::Value& target) const;
|
|
|
|
void GetSimplifiedJson(Json::Value& target) const;
|
|
|
|
OrthancPluginInstanceOrigin GetOrigin() const
|
|
{
|
|
return OrthancPluginGetInstanceOrigin(GetGlobalContext(), instance_);
|
|
}
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
|
|
std::string GetTransferSyntaxUid() const;
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1)
|
|
bool HasPixelData() const;
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
|
|
unsigned int GetFramesCount() const
|
|
{
|
|
return OrthancPluginGetInstanceFramesCount(GetGlobalContext(), instance_);
|
|
}
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
|
|
void GetRawFrame(std::string& target,
|
|
unsigned int frameIndex) const;
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
|
|
OrthancImage* GetDecodedFrame(unsigned int frameIndex) const;
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
|
|
void Serialize(std::string& target) const;
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
|
|
static DicomInstance* Transcode(const void* buffer,
|
|
size_t size,
|
|
const std::string& transferSyntax);
|
|
#endif
|
|
|
|
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 1)
|
|
static DicomInstance* Load(const std::string& instanceId,
|
|
OrthancPluginLoadDicomInstanceMode mode);
|
|
#endif
|
|
};
|
|
|
|
// helper method to convert Http headers from the plugin SDK to a std::map
|
|
void GetHttpHeaders(HttpHeaders& result, const OrthancPluginHttpRequest* request);
|
|
|
|
// helper method to re-serialize the get arguments from the SDK into a string
|
|
void SerializeGetArguments(std::string& output, const OrthancPluginHttpRequest* request);
|
|
|
|
#if HAS_ORTHANC_PLUGIN_WEBDAV == 1
|
|
class IWebDavCollection : public boost::noncopyable
|
|
{
|
|
public:
|
|
class FileInfo
|
|
{
|
|
private:
|
|
std::string name_;
|
|
uint64_t contentSize_;
|
|
std::string mime_;
|
|
std::string dateTime_;
|
|
|
|
public:
|
|
FileInfo(const std::string& name,
|
|
uint64_t contentSize,
|
|
const std::string& dateTime) :
|
|
name_(name),
|
|
contentSize_(contentSize),
|
|
dateTime_(dateTime)
|
|
{
|
|
}
|
|
|
|
const std::string& GetName() const
|
|
{
|
|
return name_;
|
|
}
|
|
|
|
uint64_t GetContentSize() const
|
|
{
|
|
return contentSize_;
|
|
}
|
|
|
|
void SetMimeType(const std::string& mime)
|
|
{
|
|
mime_ = mime;
|
|
}
|
|
|
|
const std::string& GetMimeType() const
|
|
{
|
|
return mime_;
|
|
}
|
|
|
|
const std::string& GetDateTime() const
|
|
{
|
|
return dateTime_;
|
|
}
|
|
};
|
|
|
|
class FolderInfo
|
|
{
|
|
private:
|
|
std::string name_;
|
|
std::string dateTime_;
|
|
|
|
public:
|
|
FolderInfo(const std::string& name,
|
|
const std::string& dateTime) :
|
|
name_(name),
|
|
dateTime_(dateTime)
|
|
{
|
|
}
|
|
|
|
const std::string& GetName() const
|
|
{
|
|
return name_;
|
|
}
|
|
|
|
const std::string& GetDateTime() const
|
|
{
|
|
return dateTime_;
|
|
}
|
|
};
|
|
|
|
virtual ~IWebDavCollection()
|
|
{
|
|
}
|
|
|
|
virtual bool IsExistingFolder(const std::vector<std::string>& path) = 0;
|
|
|
|
virtual bool ListFolder(std::list<FileInfo>& files,
|
|
std::list<FolderInfo>& subfolders,
|
|
const std::vector<std::string>& path) = 0;
|
|
|
|
virtual bool GetFile(std::string& content /* out */,
|
|
std::string& mime /* out */,
|
|
std::string& dateTime /* out */,
|
|
const std::vector<std::string>& path) = 0;
|
|
|
|
virtual bool StoreFile(const std::vector<std::string>& path,
|
|
const void* data,
|
|
size_t size) = 0;
|
|
|
|
virtual bool CreateFolder(const std::vector<std::string>& path) = 0;
|
|
|
|
virtual bool DeleteItem(const std::vector<std::string>& path) = 0;
|
|
|
|
static void Register(const std::string& uri,
|
|
IWebDavCollection& collection);
|
|
};
|
|
#endif
|
|
|
|
void SetRootUri(const std::string& pluginIdentifier,
|
|
const std::string& uri);
|
|
|
|
void SetDescription(const std::string& pluginIdentifier,
|
|
const std::string& description);
|
|
|
|
void ExtendOrthancExplorer(const std::string& pluginIdentifier,
|
|
const std::string& javascript);
|
|
|
|
|
|
#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
|
|
class RestApiClient : public boost::noncopyable
|
|
{
|
|
private:
|
|
// Request
|
|
OrthancPluginHttpMethod method_;
|
|
std::string path_;
|
|
HttpHeaders requestHeaders_;
|
|
std::string requestBody_;
|
|
bool afterPlugins_;
|
|
|
|
// Answer
|
|
uint16_t httpStatus_;
|
|
HttpHeaders answerHeaders_;
|
|
std::string answerBody_;
|
|
|
|
public:
|
|
RestApiClient();
|
|
|
|
// used to forward a call from the plugin to the core
|
|
RestApiClient(const char* url,
|
|
const OrthancPluginHttpRequest* request);
|
|
|
|
void SetMethod(OrthancPluginHttpMethod method)
|
|
{
|
|
method_ = method;
|
|
}
|
|
|
|
OrthancPluginHttpMethod GetMethod() const
|
|
{
|
|
return method_;
|
|
}
|
|
|
|
void SetPath(const std::string& path)
|
|
{
|
|
path_ = path;
|
|
}
|
|
|
|
const std::string& GetPath() const
|
|
{
|
|
return path_;
|
|
}
|
|
|
|
void AddRequestHeader(const std::string& key,
|
|
const std::string& value);
|
|
|
|
const HttpHeaders& GetRequestHeaders() const
|
|
{
|
|
return requestHeaders_;
|
|
}
|
|
|
|
void SetRequestBody(const std::string& body)
|
|
{
|
|
requestBody_ = body;
|
|
}
|
|
|
|
void SwapRequestBody(std::string& body)
|
|
{
|
|
requestBody_.swap(body);
|
|
}
|
|
|
|
void SetAfterPlugins(bool afterPlugins)
|
|
{
|
|
afterPlugins_ = afterPlugins;
|
|
}
|
|
|
|
bool IsAfterPlugins() const
|
|
{
|
|
return afterPlugins_;
|
|
}
|
|
|
|
const std::string& GetRequestBody() const
|
|
{
|
|
return requestBody_;
|
|
}
|
|
|
|
bool Execute();
|
|
|
|
// Execute and forward the response as is
|
|
void Forward(OrthancPluginContext* context, OrthancPluginRestOutput* output);
|
|
|
|
uint16_t GetHttpStatus() const;
|
|
|
|
bool LookupAnswerHeader(std::string& value,
|
|
const std::string& key) const;
|
|
|
|
const std::string& GetAnswerBody() const;
|
|
|
|
bool GetAnswerJson(Json::Value& output) const;
|
|
};
|
|
#endif
|
|
|
|
|
|
#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
|
|
class KeyValueStore : public boost::noncopyable
|
|
{
|
|
public:
|
|
class Iterator : public boost::noncopyable
|
|
{
|
|
private:
|
|
OrthancPluginKeysValuesIterator *iterator_;
|
|
|
|
public:
|
|
Iterator(OrthancPluginKeysValuesIterator *iterator);
|
|
|
|
~Iterator();
|
|
|
|
bool Next();
|
|
|
|
std::string GetKey() const;
|
|
|
|
void GetValue(std::string& target) const;
|
|
};
|
|
|
|
private:
|
|
std::string storeId_;
|
|
|
|
public:
|
|
explicit KeyValueStore(const std::string& storeId) :
|
|
storeId_(storeId)
|
|
{
|
|
}
|
|
|
|
const std::string& GetStoreId() const
|
|
{
|
|
return storeId_;
|
|
}
|
|
|
|
void Store(const std::string& key,
|
|
const void* value,
|
|
size_t valueSize);
|
|
|
|
void Store(const std::string& key,
|
|
const std::string& value)
|
|
{
|
|
Store(key, value.empty() ? NULL : value.c_str(), value.size());
|
|
}
|
|
|
|
bool GetValue(std::string& value,
|
|
const std::string& key);
|
|
|
|
void DeleteKey(const std::string& key);
|
|
|
|
Iterator* CreateIterator();
|
|
};
|
|
#endif
|
|
|
|
|
|
#if HAS_ORTHANC_PLUGIN_QUEUES == 1
|
|
class Queue : public boost::noncopyable
|
|
{
|
|
private:
|
|
std::string queueId_;
|
|
|
|
bool DequeueInternal(std::string& value, OrthancPluginQueueOrigin origin);
|
|
|
|
public:
|
|
explicit Queue(const std::string& queueId) :
|
|
queueId_(queueId)
|
|
{
|
|
}
|
|
|
|
const std::string& GetQueueId() const
|
|
{
|
|
return queueId_;
|
|
}
|
|
|
|
void Enqueue(const void* value,
|
|
size_t valueSize);
|
|
|
|
void Enqueue(const std::string& value)
|
|
{
|
|
Enqueue(value.empty() ? NULL : value.c_str(), value.size());
|
|
}
|
|
|
|
bool DequeueBack(std::string& value)
|
|
{
|
|
return DequeueInternal(value, OrthancPluginQueueOrigin_Back);
|
|
}
|
|
|
|
bool DequeueFront(std::string& value)
|
|
{
|
|
return DequeueInternal(value, OrthancPluginQueueOrigin_Front);
|
|
}
|
|
|
|
uint64_t GetSize();
|
|
};
|
|
#endif
|
|
}
|