Mercurial > hg > orthanc
view Plugins/Samples/Common/OrthancPluginCppWrapper.cpp @ 3356:f744730c294b
Orthanc now accepts chunked transfer encoding
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 29 Apr 2019 17:24:30 +0200 |
parents | 0f721f015b85 |
children | a48d652f1500 |
line wrap: on
line source
/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium * Copyright (C) 2017-2019 Osimis S.A., 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. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * 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/>. **/ #include "OrthancPluginCppWrapper.h" #include <json/reader.h> #include <json/writer.h> namespace OrthancPlugins { static OrthancPluginContext* globalContext_ = NULL; void SetGlobalContext(OrthancPluginContext* context) { if (context == NULL) { ORTHANC_PLUGINS_THROW_EXCEPTION(NullPointer); } else if (globalContext_ == NULL) { globalContext_ = context; } else { ORTHANC_PLUGINS_THROW_EXCEPTION(BadSequenceOfCalls); } } bool HasGlobalContext() { return globalContext_ != NULL; } OrthancPluginContext* GetGlobalContext() { if (globalContext_ == NULL) { ORTHANC_PLUGINS_THROW_EXCEPTION(BadSequenceOfCalls); } else { return globalContext_; } } void MemoryBuffer::Check(OrthancPluginErrorCode code) { if (code != OrthancPluginErrorCode_Success) { // Prevent using garbage information buffer_.data = NULL; buffer_.size = 0; ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code); } } bool MemoryBuffer::CheckHttp(OrthancPluginErrorCode code) { if (code != OrthancPluginErrorCode_Success) { // Prevent using garbage information buffer_.data = NULL; buffer_.size = 0; } if (code == OrthancPluginErrorCode_Success) { return true; } else if (code == OrthancPluginErrorCode_UnknownResource || code == OrthancPluginErrorCode_InexistentItem) { return false; } else { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code); } } MemoryBuffer::MemoryBuffer() { buffer_.data = NULL; buffer_.size = 0; } void MemoryBuffer::Clear() { if (buffer_.data != NULL) { OrthancPluginFreeMemoryBuffer(GetGlobalContext(), &buffer_); buffer_.data = NULL; buffer_.size = 0; } } void MemoryBuffer::Assign(OrthancPluginMemoryBuffer& other) { Clear(); buffer_.data = other.data; buffer_.size = other.size; other.data = NULL; other.size = 0; } void MemoryBuffer::Swap(MemoryBuffer& other) { std::swap(buffer_.data, other.buffer_.data); std::swap(buffer_.size, other.buffer_.size); } OrthancPluginMemoryBuffer MemoryBuffer::Release() { OrthancPluginMemoryBuffer result = buffer_; buffer_.data = NULL; buffer_.size = 0; return result; } void MemoryBuffer::ToString(std::string& target) const { if (buffer_.size == 0) { target.clear(); } else { target.assign(reinterpret_cast<const char*>(buffer_.data), buffer_.size); } } void MemoryBuffer::ToJson(Json::Value& target) const { if (buffer_.data == NULL || buffer_.size == 0) { ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); } const char* tmp = reinterpret_cast<const char*>(buffer_.data); Json::Reader reader; if (!reader.parse(tmp, tmp + buffer_.size, target)) { LogError("Cannot convert some memory buffer to JSON"); ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); } } bool MemoryBuffer::RestApiGet(const std::string& uri, bool applyPlugins) { Clear(); if (applyPlugins) { return CheckHttp(OrthancPluginRestApiGetAfterPlugins(GetGlobalContext(), &buffer_, uri.c_str())); } else { return CheckHttp(OrthancPluginRestApiGet(GetGlobalContext(), &buffer_, uri.c_str())); } } bool MemoryBuffer::RestApiGet(const std::string& uri, const std::map<std::string, std::string>& httpHeaders, bool applyPlugins) { Clear(); std::vector<const char*> headersKeys; std::vector<const char*> headersValues; for (std::map<std::string, std::string>::const_iterator it = httpHeaders.begin(); it != httpHeaders.end(); it++) { headersKeys.push_back(it->first.c_str()); headersValues.push_back(it->second.c_str()); } return CheckHttp(OrthancPluginRestApiGet2( GetGlobalContext(), &buffer_, uri.c_str(), httpHeaders.size(), (headersKeys.empty() ? NULL : &headersKeys[0]), (headersValues.empty() ? NULL : &headersValues[0]), applyPlugins)); } bool MemoryBuffer::RestApiPost(const std::string& uri, const char* body, size_t bodySize, bool applyPlugins) { Clear(); if (applyPlugins) { return CheckHttp(OrthancPluginRestApiPostAfterPlugins(GetGlobalContext(), &buffer_, uri.c_str(), body, bodySize)); } else { return CheckHttp(OrthancPluginRestApiPost(GetGlobalContext(), &buffer_, uri.c_str(), body, bodySize)); } } bool MemoryBuffer::RestApiPut(const std::string& uri, const char* body, size_t bodySize, bool applyPlugins) { Clear(); if (applyPlugins) { return CheckHttp(OrthancPluginRestApiPutAfterPlugins(GetGlobalContext(), &buffer_, uri.c_str(), body, bodySize)); } else { return CheckHttp(OrthancPluginRestApiPut(GetGlobalContext(), &buffer_, uri.c_str(), body, bodySize)); } } bool MemoryBuffer::RestApiPost(const std::string& uri, const Json::Value& body, bool applyPlugins) { Json::FastWriter writer; return RestApiPost(uri, writer.write(body), applyPlugins); } bool MemoryBuffer::RestApiPut(const std::string& uri, const Json::Value& body, bool applyPlugins) { Json::FastWriter writer; return RestApiPut(uri, writer.write(body), applyPlugins); } void MemoryBuffer::CreateDicom(const Json::Value& tags, OrthancPluginCreateDicomFlags flags) { Clear(); Json::FastWriter writer; std::string s = writer.write(tags); Check(OrthancPluginCreateDicom(GetGlobalContext(), &buffer_, s.c_str(), NULL, flags)); } void MemoryBuffer::CreateDicom(const Json::Value& tags, const OrthancImage& pixelData, OrthancPluginCreateDicomFlags flags) { Clear(); Json::FastWriter writer; std::string s = writer.write(tags); Check(OrthancPluginCreateDicom(GetGlobalContext(), &buffer_, s.c_str(), pixelData.GetObject(), flags)); } void MemoryBuffer::ReadFile(const std::string& path) { Clear(); Check(OrthancPluginReadFile(GetGlobalContext(), &buffer_, path.c_str())); } void MemoryBuffer::GetDicomQuery(const OrthancPluginWorklistQuery* query) { Clear(); Check(OrthancPluginWorklistGetDicomQuery(GetGlobalContext(), &buffer_, query)); } void OrthancString::Assign(char* str) { if (str == NULL) { ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); } else { Clear(); str_ = str; } } void OrthancString::Clear() { if (str_ != NULL) { OrthancPluginFreeString(GetGlobalContext(), str_); str_ = NULL; } } void OrthancString::ToString(std::string& target) const { if (str_ == NULL) { target.clear(); } else { target.assign(str_); } } void OrthancString::ToJson(Json::Value& target) const { if (str_ == NULL) { LogError("Cannot convert an empty memory buffer to JSON"); ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); } Json::Reader reader; if (!reader.parse(str_, target)) { LogError("Cannot convert some memory buffer to JSON"); ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); } } void MemoryBuffer::DicomToJson(Json::Value& target, OrthancPluginDicomToJsonFormat format, OrthancPluginDicomToJsonFlags flags, uint32_t maxStringLength) { OrthancString str; str.Assign(OrthancPluginDicomBufferToJson (GetGlobalContext(), GetData(), GetSize(), format, flags, maxStringLength)); str.ToJson(target); } bool MemoryBuffer::HttpGet(const std::string& url, const std::string& username, const std::string& password) { Clear(); return CheckHttp(OrthancPluginHttpGet(GetGlobalContext(), &buffer_, url.c_str(), username.empty() ? NULL : username.c_str(), password.empty() ? NULL : password.c_str())); } bool MemoryBuffer::HttpPost(const std::string& url, const std::string& body, const std::string& username, const std::string& password) { Clear(); return CheckHttp(OrthancPluginHttpPost(GetGlobalContext(), &buffer_, url.c_str(), body.c_str(), body.size(), username.empty() ? NULL : username.c_str(), password.empty() ? NULL : password.c_str())); } bool MemoryBuffer::HttpPut(const std::string& url, const std::string& body, const std::string& username, const std::string& password) { Clear(); return CheckHttp(OrthancPluginHttpPut(GetGlobalContext(), &buffer_, url.c_str(), body.empty() ? NULL : body.c_str(), body.size(), username.empty() ? NULL : username.c_str(), password.empty() ? NULL : password.c_str())); } void MemoryBuffer::GetDicomInstance(const std::string& instanceId) { Clear(); Check(OrthancPluginGetDicomForInstance(GetGlobalContext(), &buffer_, instanceId.c_str())); } bool HttpDelete(const std::string& url, const std::string& username, const std::string& password) { OrthancPluginErrorCode error = OrthancPluginHttpDelete (GetGlobalContext(), url.c_str(), username.empty() ? NULL : username.c_str(), password.empty() ? NULL : password.c_str()); if (error == OrthancPluginErrorCode_Success) { return true; } else if (error == OrthancPluginErrorCode_UnknownResource || error == OrthancPluginErrorCode_InexistentItem) { return false; } else { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error); } } void LogError(const std::string& message) { if (HasGlobalContext()) { OrthancPluginLogError(GetGlobalContext(), message.c_str()); } } void LogWarning(const std::string& message) { if (HasGlobalContext()) { OrthancPluginLogWarning(GetGlobalContext(), message.c_str()); } } void LogInfo(const std::string& message) { if (HasGlobalContext()) { OrthancPluginLogInfo(GetGlobalContext(), message.c_str()); } } OrthancConfiguration::OrthancConfiguration() { OrthancString str; str.Assign(OrthancPluginGetConfiguration(GetGlobalContext())); if (str.GetContent() == NULL) { LogError("Cannot access the Orthanc configuration"); ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); } str.ToJson(configuration_); if (configuration_.type() != Json::objectValue) { LogError("Unable to read the Orthanc configuration"); ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); } } std::string OrthancConfiguration::GetPath(const std::string& key) const { if (path_.empty()) { return key; } else { return path_ + "." + key; } } bool OrthancConfiguration::IsSection(const std::string& key) const { assert(configuration_.type() == Json::objectValue); return (configuration_.isMember(key) && configuration_[key].type() == Json::objectValue); } void OrthancConfiguration::GetSection(OrthancConfiguration& target, const std::string& key) const { assert(configuration_.type() == Json::objectValue); target.path_ = GetPath(key); if (!configuration_.isMember(key)) { target.configuration_ = Json::objectValue; } else { if (configuration_[key].type() != Json::objectValue) { LogError("The configuration section \"" + target.path_ + "\" is not an associative array as expected"); ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); } target.configuration_ = configuration_[key]; } } bool OrthancConfiguration::LookupStringValue(std::string& target, const std::string& key) const { assert(configuration_.type() == Json::objectValue); if (!configuration_.isMember(key)) { return false; } if (configuration_[key].type() != Json::stringValue) { LogError("The configuration option \"" + GetPath(key) + "\" is not a string as expected"); ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); } target = configuration_[key].asString(); return true; } bool OrthancConfiguration::LookupIntegerValue(int& target, const std::string& key) const { assert(configuration_.type() == Json::objectValue); if (!configuration_.isMember(key)) { return false; } switch (configuration_[key].type()) { case Json::intValue: target = configuration_[key].asInt(); return true; case Json::uintValue: target = configuration_[key].asUInt(); return true; default: LogError("The configuration option \"" + GetPath(key) + "\" is not an integer as expected"); ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); } } bool OrthancConfiguration::LookupUnsignedIntegerValue(unsigned int& target, const std::string& key) const { int tmp; if (!LookupIntegerValue(tmp, key)) { return false; } if (tmp < 0) { LogError("The configuration option \"" + GetPath(key) + "\" is not a positive integer as expected"); ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); } else { target = static_cast<unsigned int>(tmp); return true; } } bool OrthancConfiguration::LookupBooleanValue(bool& target, const std::string& key) const { assert(configuration_.type() == Json::objectValue); if (!configuration_.isMember(key)) { return false; } if (configuration_[key].type() != Json::booleanValue) { LogError("The configuration option \"" + GetPath(key) + "\" is not a Boolean as expected"); ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); } target = configuration_[key].asBool(); return true; } bool OrthancConfiguration::LookupFloatValue(float& target, const std::string& key) const { assert(configuration_.type() == Json::objectValue); if (!configuration_.isMember(key)) { return false; } switch (configuration_[key].type()) { case Json::realValue: target = configuration_[key].asFloat(); return true; case Json::intValue: target = static_cast<float>(configuration_[key].asInt()); return true; case Json::uintValue: target = static_cast<float>(configuration_[key].asUInt()); return true; default: LogError("The configuration option \"" + GetPath(key) + "\" is not an integer as expected"); ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); } } bool OrthancConfiguration::LookupListOfStrings(std::list<std::string>& target, const std::string& key, bool allowSingleString) const { assert(configuration_.type() == Json::objectValue); target.clear(); if (!configuration_.isMember(key)) { return false; } switch (configuration_[key].type()) { case Json::arrayValue: { bool ok = true; for (Json::Value::ArrayIndex i = 0; ok && i < configuration_[key].size(); i++) { if (configuration_[key][i].type() == Json::stringValue) { target.push_back(configuration_[key][i].asString()); } else { ok = false; } } if (ok) { return true; } break; } case Json::stringValue: if (allowSingleString) { target.push_back(configuration_[key].asString()); return true; } break; default: break; } LogError("The configuration option \"" + GetPath(key) + "\" is not a list of strings as expected"); ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); } bool OrthancConfiguration::LookupSetOfStrings(std::set<std::string>& target, const std::string& key, bool allowSingleString) const { std::list<std::string> lst; if (LookupListOfStrings(lst, key, allowSingleString)) { target.clear(); for (std::list<std::string>::const_iterator it = lst.begin(); it != lst.end(); ++it) { target.insert(*it); } return true; } else { return false; } } std::string OrthancConfiguration::GetStringValue(const std::string& key, const std::string& defaultValue) const { std::string tmp; if (LookupStringValue(tmp, key)) { return tmp; } else { return defaultValue; } } int OrthancConfiguration::GetIntegerValue(const std::string& key, int defaultValue) const { int tmp; if (LookupIntegerValue(tmp, key)) { return tmp; } else { return defaultValue; } } unsigned int OrthancConfiguration::GetUnsignedIntegerValue(const std::string& key, unsigned int defaultValue) const { unsigned int tmp; if (LookupUnsignedIntegerValue(tmp, key)) { return tmp; } else { return defaultValue; } } bool OrthancConfiguration::GetBooleanValue(const std::string& key, bool defaultValue) const { bool tmp; if (LookupBooleanValue(tmp, key)) { return tmp; } else { return defaultValue; } } float OrthancConfiguration::GetFloatValue(const std::string& key, float defaultValue) const { float tmp; if (LookupFloatValue(tmp, key)) { return tmp; } else { return defaultValue; } } void OrthancConfiguration::GetDictionary(std::map<std::string, std::string>& target, const std::string& key) const { assert(configuration_.type() == Json::objectValue); target.clear(); if (!configuration_.isMember(key)) { return; } if (configuration_[key].type() != Json::objectValue) { LogError("The configuration option \"" + GetPath(key) + "\" is not a string as expected"); ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); } Json::Value::Members members = configuration_[key].getMemberNames(); for (size_t i = 0; i < members.size(); i++) { const Json::Value& value = configuration_[key][members[i]]; if (value.type() == Json::stringValue) { target[members[i]] = value.asString(); } else { LogError("The configuration option \"" + GetPath(key) + "\" is not a dictionary mapping strings to strings"); ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); } } } void OrthancImage::Clear() { if (image_ != NULL) { OrthancPluginFreeImage(GetGlobalContext(), image_); image_ = NULL; } } void OrthancImage::CheckImageAvailable() const { if (image_ == NULL) { LogError("Trying to access a NULL image"); ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); } } OrthancImage::OrthancImage() : image_(NULL) { } OrthancImage::OrthancImage(OrthancPluginImage* image) : image_(image) { } OrthancImage::OrthancImage(OrthancPluginPixelFormat format, uint32_t width, uint32_t height) { image_ = OrthancPluginCreateImage(GetGlobalContext(), format, width, height); if (image_ == NULL) { LogError("Cannot create an image"); ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); } } OrthancImage::OrthancImage(OrthancPluginPixelFormat format, uint32_t width, uint32_t height, uint32_t pitch, void* buffer) { image_ = OrthancPluginCreateImageAccessor (GetGlobalContext(), format, width, height, pitch, buffer); if (image_ == NULL) { LogError("Cannot create an image accessor"); ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); } } void OrthancImage::UncompressPngImage(const void* data, size_t size) { Clear(); image_ = OrthancPluginUncompressImage(GetGlobalContext(), data, size, OrthancPluginImageFormat_Png); if (image_ == NULL) { LogError("Cannot uncompress a PNG image"); ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); } } void OrthancImage::UncompressJpegImage(const void* data, size_t size) { Clear(); image_ = OrthancPluginUncompressImage(GetGlobalContext(), data, size, OrthancPluginImageFormat_Jpeg); if (image_ == NULL) { LogError("Cannot uncompress a JPEG image"); ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); } } void OrthancImage::DecodeDicomImage(const void* data, size_t size, unsigned int frame) { Clear(); image_ = OrthancPluginDecodeDicomImage(GetGlobalContext(), data, size, frame); if (image_ == NULL) { LogError("Cannot uncompress a DICOM image"); ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); } } OrthancPluginPixelFormat OrthancImage::GetPixelFormat() const { CheckImageAvailable(); return OrthancPluginGetImagePixelFormat(GetGlobalContext(), image_); } unsigned int OrthancImage::GetWidth() const { CheckImageAvailable(); return OrthancPluginGetImageWidth(GetGlobalContext(), image_); } unsigned int OrthancImage::GetHeight() const { CheckImageAvailable(); return OrthancPluginGetImageHeight(GetGlobalContext(), image_); } unsigned int OrthancImage::GetPitch() const { CheckImageAvailable(); return OrthancPluginGetImagePitch(GetGlobalContext(), image_); } const void* OrthancImage::GetBuffer() const { CheckImageAvailable(); return OrthancPluginGetImageBuffer(GetGlobalContext(), image_); } void OrthancImage::CompressPngImage(MemoryBuffer& target) const { CheckImageAvailable(); OrthancPlugins::MemoryBuffer answer; OrthancPluginCompressPngImage(GetGlobalContext(), *answer, GetPixelFormat(), GetWidth(), GetHeight(), GetPitch(), GetBuffer()); target.Swap(answer); } void OrthancImage::CompressJpegImage(MemoryBuffer& target, uint8_t quality) const { CheckImageAvailable(); OrthancPlugins::MemoryBuffer answer; OrthancPluginCompressJpegImage(GetGlobalContext(), *answer, GetPixelFormat(), GetWidth(), GetHeight(), GetPitch(), GetBuffer(), quality); target.Swap(answer); } void OrthancImage::AnswerPngImage(OrthancPluginRestOutput* output) const { CheckImageAvailable(); OrthancPluginCompressAndAnswerPngImage(GetGlobalContext(), output, GetPixelFormat(), GetWidth(), GetHeight(), GetPitch(), GetBuffer()); } void OrthancImage::AnswerJpegImage(OrthancPluginRestOutput* output, uint8_t quality) const { CheckImageAvailable(); OrthancPluginCompressAndAnswerJpegImage(GetGlobalContext(), output, GetPixelFormat(), GetWidth(), GetHeight(), GetPitch(), GetBuffer(), quality); } #if HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 FindMatcher::FindMatcher(const OrthancPluginWorklistQuery* worklist) : matcher_(NULL), worklist_(worklist) { if (worklist_ == NULL) { ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); } } void FindMatcher::SetupDicom(const void* query, uint32_t size) { worklist_ = NULL; matcher_ = OrthancPluginCreateFindMatcher(GetGlobalContext(), query, size); if (matcher_ == NULL) { ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); } } FindMatcher::~FindMatcher() { // The "worklist_" field if (matcher_ != NULL) { OrthancPluginFreeFindMatcher(GetGlobalContext(), matcher_); } } bool FindMatcher::IsMatch(const void* dicom, uint32_t size) const { int32_t result; if (matcher_ != NULL) { result = OrthancPluginFindMatcherIsMatch(GetGlobalContext(), matcher_, dicom, size); } else if (worklist_ != NULL) { result = OrthancPluginWorklistIsMatch(GetGlobalContext(), worklist_, dicom, size); } else { ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); } if (result == 0) { return false; } else if (result == 1) { return true; } else { ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); } } #endif /* HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 */ void AnswerJson(const Json::Value& value, OrthancPluginRestOutput* output ) { Json::StyledWriter writer; std::string bodyString = writer.write(value); OrthancPluginAnswerBuffer(GetGlobalContext(), output, bodyString.c_str(), bodyString.size(), "application/json"); } void AnswerString(const std::string& answer, const char* mimeType, OrthancPluginRestOutput* output ) { OrthancPluginAnswerBuffer(GetGlobalContext(), output, answer.c_str(), answer.size(), mimeType); } void AnswerHttpError(uint16_t httpError, OrthancPluginRestOutput *output) { OrthancPluginSendHttpStatusCode(GetGlobalContext(), output, httpError); } void AnswerMethodNotAllowed(OrthancPluginRestOutput *output, const char* allowedMethods) { OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowedMethods); } bool RestApiGetString(std::string& result, const std::string& uri, bool applyPlugins) { MemoryBuffer answer; if (!answer.RestApiGet(uri, applyPlugins)) { return false; } else { answer.ToString(result); return true; } } bool RestApiGetString(std::string& result, const std::string& uri, const std::map<std::string, std::string>& httpHeaders, bool applyPlugins) { MemoryBuffer answer; if (!answer.RestApiGet(uri, httpHeaders, applyPlugins)) { return false; } else { answer.ToString(result); return true; } } bool RestApiGet(Json::Value& result, const std::string& uri, bool applyPlugins) { MemoryBuffer answer; if (!answer.RestApiGet(uri, applyPlugins)) { return false; } else { if (!answer.IsEmpty()) { answer.ToJson(result); } return true; } } bool RestApiPost(Json::Value& result, const std::string& uri, const char* body, size_t bodySize, bool applyPlugins) { MemoryBuffer answer; if (!answer.RestApiPost(uri, body, bodySize, applyPlugins)) { return false; } else { if (!answer.IsEmpty()) { answer.ToJson(result); } return true; } } bool RestApiPost(Json::Value& result, const std::string& uri, const Json::Value& body, bool applyPlugins) { Json::FastWriter writer; return RestApiPost(result, uri, writer.write(body), applyPlugins); } bool RestApiPut(Json::Value& result, const std::string& uri, const char* body, size_t bodySize, bool applyPlugins) { MemoryBuffer answer; if (!answer.RestApiPut(uri, body, bodySize, applyPlugins)) { return false; } else { if (!answer.IsEmpty()) // i.e, on a PUT to metadata/..., orthand returns an empty response { answer.ToJson(result); } return true; } } bool RestApiPut(Json::Value& result, const std::string& uri, const Json::Value& body, bool applyPlugins) { Json::FastWriter writer; return RestApiPut(result, uri, writer.write(body), applyPlugins); } bool RestApiDelete(const std::string& uri, bool applyPlugins) { OrthancPluginErrorCode error; if (applyPlugins) { error = OrthancPluginRestApiDeleteAfterPlugins(GetGlobalContext(), uri.c_str()); } else { error = OrthancPluginRestApiDelete(GetGlobalContext(), uri.c_str()); } if (error == OrthancPluginErrorCode_Success) { return true; } else if (error == OrthancPluginErrorCode_UnknownResource || error == OrthancPluginErrorCode_InexistentItem) { return false; } else { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error); } } void ReportMinimalOrthancVersion(unsigned int major, unsigned int minor, unsigned int revision) { LogError("Your version of the Orthanc core (" + std::string(GetGlobalContext()->orthancVersion) + ") is too old to run this plugin (version " + boost::lexical_cast<std::string>(major) + "." + boost::lexical_cast<std::string>(minor) + "." + boost::lexical_cast<std::string>(revision) + " is required)"); } bool CheckMinimalOrthancVersion(unsigned int major, unsigned int minor, unsigned int revision) { if (!HasGlobalContext()) { LogError("Bad Orthanc context in the plugin"); return false; } if (!strcmp(GetGlobalContext()->orthancVersion, "mainline")) { // Assume compatibility with the mainline return true; } // Parse the version of the Orthanc core int aa, bb, cc; if ( #ifdef _MSC_VER sscanf_s #else sscanf #endif (GetGlobalContext()->orthancVersion, "%4d.%4d.%4d", &aa, &bb, &cc) != 3 || aa < 0 || bb < 0 || cc < 0) { return false; } unsigned int a = static_cast<unsigned int>(aa); unsigned int b = static_cast<unsigned int>(bb); unsigned int c = static_cast<unsigned int>(cc); // Check the major version number if (a > major) { return true; } if (a < major) { return false; } // Check the minor version number assert(a == major); if (b > minor) { return true; } if (b < minor) { return false; } // Check the patch level version number assert(a == major && b == minor); if (c >= revision) { return true; } else { return false; } } #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0) const char* AutodetectMimeType(const std::string& path) { const char* mime = OrthancPluginAutodetectMimeType(GetGlobalContext(), path.c_str()); if (mime == NULL) { // Should never happen, just for safety return "application/octet-stream"; } else { return mime; } } #endif #if HAS_ORTHANC_PLUGIN_PEERS == 1 size_t OrthancPeers::GetPeerIndex(const std::string& name) const { size_t index; if (LookupName(index, name)) { return index; } else { LogError("Inexistent peer: " + name); ORTHANC_PLUGINS_THROW_EXCEPTION(UnknownResource); } } OrthancPeers::OrthancPeers() : peers_(NULL), timeout_(0) { peers_ = OrthancPluginGetPeers(GetGlobalContext()); if (peers_ == NULL) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); } uint32_t count = OrthancPluginGetPeersCount(GetGlobalContext(), peers_); for (uint32_t i = 0; i < count; i++) { const char* name = OrthancPluginGetPeerName(GetGlobalContext(), peers_, i); if (name == NULL) { OrthancPluginFreePeers(GetGlobalContext(), peers_); ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); } index_[name] = i; } } OrthancPeers::~OrthancPeers() { if (peers_ != NULL) { OrthancPluginFreePeers(GetGlobalContext(), peers_); } } bool OrthancPeers::LookupName(size_t& target, const std::string& name) const { Index::const_iterator found = index_.find(name); if (found == index_.end()) { return false; } else { target = found->second; return true; } } std::string OrthancPeers::GetPeerName(size_t index) const { if (index >= index_.size()) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); } else { const char* s = OrthancPluginGetPeerName(GetGlobalContext(), peers_, static_cast<uint32_t>(index)); if (s == NULL) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); } else { return s; } } } std::string OrthancPeers::GetPeerUrl(size_t index) const { if (index >= index_.size()) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); } else { const char* s = OrthancPluginGetPeerUrl(GetGlobalContext(), peers_, static_cast<uint32_t>(index)); if (s == NULL) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); } else { return s; } } } std::string OrthancPeers::GetPeerUrl(const std::string& name) const { return GetPeerUrl(GetPeerIndex(name)); } bool OrthancPeers::LookupUserProperty(std::string& value, size_t index, const std::string& key) const { if (index >= index_.size()) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); } else { const char* s = OrthancPluginGetPeerUserProperty(GetGlobalContext(), peers_, static_cast<uint32_t>(index), key.c_str()); if (s == NULL) { return false; } else { value.assign(s); return true; } } } bool OrthancPeers::LookupUserProperty(std::string& value, const std::string& peer, const std::string& key) const { return LookupUserProperty(value, GetPeerIndex(peer), key); } bool OrthancPeers::DoGet(MemoryBuffer& target, size_t index, const std::string& uri) const { if (index >= index_.size()) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); } OrthancPlugins::MemoryBuffer answer; uint16_t status; OrthancPluginErrorCode code = OrthancPluginCallPeerApi (GetGlobalContext(), *answer, NULL, &status, peers_, static_cast<uint32_t>(index), OrthancPluginHttpMethod_Get, uri.c_str(), 0, NULL, NULL, NULL, 0, timeout_); if (code == OrthancPluginErrorCode_Success) { target.Swap(answer); return (status == 200); } else { return false; } } bool OrthancPeers::DoGet(MemoryBuffer& target, const std::string& name, const std::string& uri) const { size_t index; return (LookupName(index, name) && DoGet(target, index, uri)); } bool OrthancPeers::DoGet(Json::Value& target, size_t index, const std::string& uri) const { MemoryBuffer buffer; if (DoGet(buffer, index, uri)) { buffer.ToJson(target); return true; } else { return false; } } bool OrthancPeers::DoGet(Json::Value& target, const std::string& name, const std::string& uri) const { MemoryBuffer buffer; if (DoGet(buffer, name, uri)) { buffer.ToJson(target); return true; } else { return false; } } bool OrthancPeers::DoPost(MemoryBuffer& target, const std::string& name, const std::string& uri, const std::string& body) const { size_t index; return (LookupName(index, name) && DoPost(target, index, uri, body)); } bool OrthancPeers::DoPost(Json::Value& target, size_t index, const std::string& uri, const std::string& body) const { MemoryBuffer buffer; if (DoPost(buffer, index, uri, body)) { buffer.ToJson(target); return true; } else { return false; } } bool OrthancPeers::DoPost(Json::Value& target, const std::string& name, const std::string& uri, const std::string& body) const { MemoryBuffer buffer; if (DoPost(buffer, name, uri, body)) { buffer.ToJson(target); return true; } else { return false; } } bool OrthancPeers::DoPost(MemoryBuffer& target, size_t index, const std::string& uri, const std::string& body) const { if (index >= index_.size()) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); } OrthancPlugins::MemoryBuffer answer; uint16_t status; OrthancPluginErrorCode code = OrthancPluginCallPeerApi (GetGlobalContext(), *answer, NULL, &status, peers_, static_cast<uint32_t>(index), OrthancPluginHttpMethod_Post, uri.c_str(), 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_); if (code == OrthancPluginErrorCode_Success) { target.Swap(answer); return (status == 200); } else { return false; } } bool OrthancPeers::DoPut(size_t index, const std::string& uri, const std::string& body) const { if (index >= index_.size()) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); } OrthancPlugins::MemoryBuffer answer; uint16_t status; OrthancPluginErrorCode code = OrthancPluginCallPeerApi (GetGlobalContext(), *answer, NULL, &status, peers_, static_cast<uint32_t>(index), OrthancPluginHttpMethod_Put, uri.c_str(), 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_); if (code == OrthancPluginErrorCode_Success) { return (status == 200); } else { return false; } } bool OrthancPeers::DoPut(const std::string& name, const std::string& uri, const std::string& body) const { size_t index; return (LookupName(index, name) && DoPut(index, uri, body)); } bool OrthancPeers::DoDelete(size_t index, const std::string& uri) const { if (index >= index_.size()) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); } OrthancPlugins::MemoryBuffer answer; uint16_t status; OrthancPluginErrorCode code = OrthancPluginCallPeerApi (GetGlobalContext(), *answer, NULL, &status, peers_, static_cast<uint32_t>(index), OrthancPluginHttpMethod_Delete, uri.c_str(), 0, NULL, NULL, NULL, 0, timeout_); if (code == OrthancPluginErrorCode_Success) { return (status == 200); } else { return false; } } bool OrthancPeers::DoDelete(const std::string& name, const std::string& uri) const { size_t index; return (LookupName(index, name) && DoDelete(index, uri)); } #endif #if HAS_ORTHANC_PLUGIN_JOB == 1 void OrthancJob::CallbackFinalize(void* job) { if (job != NULL) { delete reinterpret_cast<OrthancJob*>(job); } } float OrthancJob::CallbackGetProgress(void* job) { assert(job != NULL); try { return reinterpret_cast<OrthancJob*>(job)->progress_; } catch (...) { return 0; } } const char* OrthancJob::CallbackGetContent(void* job) { assert(job != NULL); try { return reinterpret_cast<OrthancJob*>(job)->content_.c_str(); } catch (...) { return 0; } } const char* OrthancJob::CallbackGetSerialized(void* job) { assert(job != NULL); try { const OrthancJob& tmp = *reinterpret_cast<OrthancJob*>(job); if (tmp.hasSerialized_) { return tmp.serialized_.c_str(); } else { return NULL; } } catch (...) { return 0; } } OrthancPluginJobStepStatus OrthancJob::CallbackStep(void* job) { assert(job != NULL); try { return reinterpret_cast<OrthancJob*>(job)->Step(); } catch (ORTHANC_PLUGINS_EXCEPTION_CLASS&) { return OrthancPluginJobStepStatus_Failure; } catch (...) { return OrthancPluginJobStepStatus_Failure; } } OrthancPluginErrorCode OrthancJob::CallbackStop(void* job, OrthancPluginJobStopReason reason) { assert(job != NULL); try { reinterpret_cast<OrthancJob*>(job)->Stop(reason); return OrthancPluginErrorCode_Success; } catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) { return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); } catch (...) { return OrthancPluginErrorCode_Plugin; } } OrthancPluginErrorCode OrthancJob::CallbackReset(void* job) { assert(job != NULL); try { reinterpret_cast<OrthancJob*>(job)->Reset(); return OrthancPluginErrorCode_Success; } catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) { return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); } catch (...) { return OrthancPluginErrorCode_Plugin; } } void OrthancJob::ClearContent() { Json::Value empty = Json::objectValue; UpdateContent(empty); } void OrthancJob::UpdateContent(const Json::Value& content) { if (content.type() != Json::objectValue) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_BadFileFormat); } else { Json::FastWriter writer; content_ = writer.write(content); } } void OrthancJob::ClearSerialized() { hasSerialized_ = false; serialized_.clear(); } void OrthancJob::UpdateSerialized(const Json::Value& serialized) { if (serialized.type() != Json::objectValue) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_BadFileFormat); } else { Json::FastWriter writer; serialized_ = writer.write(serialized); hasSerialized_ = true; } } void OrthancJob::UpdateProgress(float progress) { if (progress < 0 || progress > 1) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); } progress_ = progress; } OrthancJob::OrthancJob(const std::string& jobType) : jobType_(jobType), progress_(0) { ClearContent(); ClearSerialized(); } OrthancPluginJob* OrthancJob::Create(OrthancJob* job) { if (job == NULL) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_NullPointer); } OrthancPluginJob* orthanc = OrthancPluginCreateJob( GetGlobalContext(), job, CallbackFinalize, job->jobType_.c_str(), CallbackGetProgress, CallbackGetContent, CallbackGetSerialized, CallbackStep, CallbackStop, CallbackReset); if (orthanc == NULL) { ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); } else { return orthanc; } } std::string OrthancJob::Submit(OrthancJob* job, int priority) { OrthancPluginJob* orthanc = Create(job); char* id = OrthancPluginSubmitJob(GetGlobalContext(), orthanc, priority); if (id == NULL) { LogError("Plugin cannot submit job"); OrthancPluginFreeJob(GetGlobalContext(), orthanc); ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); } else { std::string tmp(id); tmp.assign(id); OrthancPluginFreeString(GetGlobalContext(), id); return tmp; } } #endif #if HAS_ORTHANC_PLUGIN_METRICS == 1 MetricsTimer::MetricsTimer(const char* name) : name_(name) { start_ = boost::posix_time::microsec_clock::universal_time(); } MetricsTimer::~MetricsTimer() { const boost::posix_time::ptime stop = boost::posix_time::microsec_clock::universal_time(); const boost::posix_time::time_duration diff = stop - start_; OrthancPluginSetMetricsValue(GetGlobalContext(), name_.c_str(), diff.total_milliseconds(), OrthancPluginMetricsType_Timer); } #endif }