Skip to content
Commits on Source (4)
repo: d5f45924411123cfd02d035fd50b8e37536eadef
node: b5f71018159133105d5cc1eb60d852a385bab998
branch: OrthancDicomWeb-0.5
node: ce4e5f0769c81584a8851cff3d1b0fd56283574f
branch: OrthancDicomWeb-0.6
latesttag: null
latesttagdistance: 210
changessincelatesttag: 221
latesttagdistance: 250
changessincelatesttag: 264
......@@ -5,7 +5,7 @@ DICOMweb plugin for Orthanc
Authors
-------
* Sebastien Jodogne <s.jodogne@gmail.com>
* Sebastien Jodogne <s.jodogne@orthanc-labs.com>
Overall design and lead developer.
......
# Orthanc - A Lightweight, RESTful DICOM Store
# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
# Department, University Hospital of Liege, Belgium
# Copyright (C) 2017-2018 Osimis S.A., 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 Affero General Public License
......@@ -21,13 +21,13 @@ cmake_minimum_required(VERSION 2.8)
project(OrthancDicomWeb)
set(ORTHANC_DICOM_WEB_VERSION "0.5")
set(ORTHANC_DICOM_WEB_VERSION "0.6")
if (ORTHANC_DICOM_WEB_VERSION STREQUAL "mainline")
set(ORTHANC_FRAMEWORK_VERSION "mainline")
set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
else()
set(ORTHANC_FRAMEWORK_VERSION "1.3.2")
set(ORTHANC_FRAMEWORK_VERSION "1.5.5")
set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
endif()
......@@ -42,6 +42,7 @@ set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory
# Advanced parameters to fine-tune linking against system libraries
set(USE_SYSTEM_GDCM ON CACHE BOOL "Use the system version of Grassroot DICOM (GDCM)")
set(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK")
set(ORTHANC_SDK_VERSION "1.5.4" CACHE STRING "Version of the Orthanc plugin SDK to use, if not using the system version (can be \"1.5.4\", or \"framework\")")
......@@ -64,7 +65,13 @@ include(${CMAKE_SOURCE_DIR}/Resources/CMake/GdcmConfiguration.cmake)
if (STATIC_BUILD OR NOT USE_SYSTEM_ORTHANC_SDK)
include_directories(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Sdk-1.1.0)
if (ORTHANC_SDK_VERSION STREQUAL "1.5.4")
include_directories(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Sdk-1.5.4)
elseif (ORTHANC_SDK_VERSION STREQUAL "framework")
include_directories(${ORTHANC_ROOT}/Plugins/Include)
else()
message(FATAL_ERROR "Unsupported version of the Orthanc plugin SDK: ${ORTHANC_SDK_VERSION}")
endif()
else ()
CHECK_INCLUDE_FILE_CXX(orthanc/OrthancCPlugin.h HAVE_ORTHANC_H)
if (NOT HAVE_ORTHANC_H)
......@@ -107,12 +114,12 @@ include_directories(${ORTHANC_ROOT}/Core) # To access "OrthancException.h"
add_definitions(
-DHAS_ORTHANC_EXCEPTION=1
-DORTHANC_ENABLE_LOGGING_PLUGIN=1
)
set(CORE_SOURCES
Plugin/Configuration.cpp
Plugin/Dicom.cpp
Plugin/DicomResults.cpp
Plugin/GdcmParsedDicomFile.cpp
${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
${ORTHANC_CORE_SOURCES}
......@@ -120,6 +127,7 @@ set(CORE_SOURCES
add_library(OrthancDicomWeb SHARED ${CORE_SOURCES}
${CMAKE_SOURCE_DIR}/Plugin/DicomWebClient.cpp
${CMAKE_SOURCE_DIR}/Plugin/DicomWebFormatter.cpp
${CMAKE_SOURCE_DIR}/Plugin/DicomWebServers.cpp
${CMAKE_SOURCE_DIR}/Plugin/Plugin.cpp
${CMAKE_SOURCE_DIR}/Plugin/QidoRs.cpp
......
......@@ -2,7 +2,22 @@ Pending changes in the mainline
===============================
Version 0.5 (2018-08-19)
Version 0.6 (2019-02-27)
========================
=> Minimum SDK version: 1.5.4 <=
* Sending "HttpHeaders" of the "DicomWeb.Servers" configuration to remote DICOMweb servers
* Improved WADO-RS compatibility if Orthanc is acting as a DICOMweb client
* More detailed information about errors is provided in the HTTP answers
* Fix issue #96 / #5 (WADO-RS: RetrieveFrames rejects valid accept headers)
* Fix issue #111 / #3 (QIDO-RS: wrong serialization of empty values)
* Fix issue #112 / #4 (QIDO-RS: wrong serialization of number values)
* Fix issue #113 / #2 (QIDO-RS: wrong serialization of PN VR)
* Upgrade to GDCM 2.8.8 in static builds
Version 0.5 (2018-04-19)
========================
* New option: "QidoCaseSensitive" to make queries to QIDO-RS server case insensitive
......@@ -12,7 +27,7 @@ Version 0.5 (2018-08-19)
* Fix generation of numeric tags part of sequences for ".../metadata" routes
* Support for OpenBSD
* Support for Linux Standard Base
* Upgrade to GDCM 2.8.4 for static builds
* Upgrade to GDCM 2.8.4 in static builds
* Resort to Orthanc framework
......
......@@ -2,7 +2,7 @@
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 Osimis S.A., 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 Affero General Public License
......@@ -26,9 +26,9 @@
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>
#include "Plugin.h"
#include "DicomWebServers.h"
#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
#include <Core/Toolbox.h>
namespace OrthancPlugins
......@@ -91,7 +91,6 @@ namespace OrthancPlugins
static void ParseMultipartHeaders(bool& hasLength /* out */,
size_t& length /* out */,
std::string& contentType /* out */,
OrthancPluginContext* context,
const char* startHeaders,
const char* endHeaders)
{
......@@ -131,7 +130,7 @@ namespace OrthancPlugins
}
catch (boost::bad_lexical_cast&)
{
OrthancPluginLogWarning(context, "Unable to parse the Content-Length of a multipart item");
LogWarning("Unable to parse the Content-Length of a multipart item");
}
}
else if (key == "content-type")
......@@ -144,7 +143,6 @@ namespace OrthancPlugins
static const char* ParseMultipartItem(std::vector<MultipartItem>& result,
OrthancPluginContext* context,
const char* start,
const char* end,
const boost::regex& nextSeparator)
......@@ -167,7 +165,7 @@ namespace OrthancPlugins
bool hasLength;
size_t length;
std::string contentType;
ParseMultipartHeaders(hasLength, length, contentType, context, startHeaders, endHeaders);
ParseMultipartHeaders(hasLength, length, contentType, startHeaders, endHeaders);
boost::cmatch separator;
......@@ -200,7 +198,6 @@ namespace OrthancPlugins
void ParseMultipartBody(std::vector<MultipartItem>& result,
OrthancPluginContext* context,
const char* body,
const uint64_t bodySize,
const std::string& boundary)
......@@ -239,7 +236,7 @@ namespace OrthancPlugins
}
else
{
current = ParseMultipartItem(result, context, current + 2, end, nextSeparator);
current = ParseMultipartItem(result, current + 2, end, nextSeparator);
}
}
}
......@@ -252,8 +249,8 @@ namespace OrthancPlugins
{
if (value.type() != Json::objectValue)
{
OrthancPlugins::Configuration::LogError("This is not a JSON object");
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
"This is not a JSON object");
}
if (!value.isMember(key))
......@@ -265,9 +262,9 @@ namespace OrthancPlugins
if (tmp.type() != Json::objectValue)
{
OrthancPlugins::Configuration::LogError("The field \"" + key + "\" of a JSON object is "
"not a JSON associative array as expected");
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
"The field \"" + key + "\" of a JSON object is "
"not a JSON associative array as expected");
}
Json::Value::Members names = tmp.getMemberNames();
......@@ -276,9 +273,9 @@ namespace OrthancPlugins
{
if (tmp[names[i]].type() != Json::stringValue)
{
OrthancPlugins::Configuration::LogError("Some value in the associative array \"" + key +
"\" is not a string as expected");
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
"Some value in the associative array \"" + key +
"\" is not a string as expected");
}
else
{
......@@ -288,17 +285,36 @@ namespace OrthancPlugins
}
bool ParseTag(Orthanc::DicomTag& target,
const std::string& name)
{
OrthancPluginDictionaryEntry entry;
if (OrthancPluginLookupDictionary(OrthancPlugins::GetGlobalContext(), &entry, name.c_str()) == OrthancPluginErrorCode_Success)
{
target = Orthanc::DicomTag(entry.group, entry.element);
return true;
}
else
{
return false;
}
}
namespace Configuration
{
// Assume Latin-1 encoding by default (as in the Orthanc core)
static Orthanc::Encoding defaultEncoding_ = Orthanc::Encoding_Latin1;
static OrthancConfiguration configuration_;
static std::auto_ptr<OrthancConfiguration> configuration_;
void Initialize(OrthancPluginContext* context)
{
OrthancPlugins::OrthancConfiguration global(context);
global.GetSection(configuration_, "DicomWeb");
void Initialize()
{
configuration_.reset(new OrthancConfiguration);
OrthancPlugins::OrthancConfiguration global;
global.GetSection(*configuration_, "DicomWeb");
std::string s;
if (global.LookupStringValue(s, "DefaultEncoding"))
......@@ -307,41 +323,39 @@ namespace OrthancPlugins
}
OrthancPlugins::OrthancConfiguration servers;
configuration_.GetSection(servers, "Servers");
configuration_->GetSection(servers, "Servers");
OrthancPlugins::DicomWebServers::GetInstance().Load(servers.GetJson());
}
OrthancPluginContext* GetContext()
{
return configuration_.GetContext();
}
std::string GetStringValue(const std::string& key,
const std::string& defaultValue)
{
return configuration_.GetStringValue(key, defaultValue);
assert(configuration_.get() != NULL);
return configuration_->GetStringValue(key, defaultValue);
}
bool GetBooleanValue(const std::string& key,
bool defaultValue)
{
return configuration_.GetBooleanValue(key, defaultValue);
assert(configuration_.get() != NULL);
return configuration_->GetBooleanValue(key, defaultValue);
}
unsigned int GetUnsignedIntegerValue(const std::string& key,
unsigned int defaultValue)
{
return configuration_.GetUnsignedIntegerValue(key, defaultValue);
assert(configuration_.get() != NULL);
return configuration_->GetUnsignedIntegerValue(key, defaultValue);
}
std::string GetRoot()
{
std::string root = configuration_.GetStringValue("Root", "/dicom-web/");
assert(configuration_.get() != NULL);
std::string root = configuration_->GetStringValue("Root", "/dicom-web/");
// Make sure the root URI starts and ends with a slash
if (root.size() == 0 ||
......@@ -361,7 +375,8 @@ namespace OrthancPlugins
std::string GetWadoRoot()
{
std::string root = configuration_.GetStringValue("WadoRoot", "/wado/");
assert(configuration_.get() != NULL);
std::string root = configuration_->GetStringValue("WadoRoot", "/wado/");
// Make sure the root URI starts with a slash
if (root.size() == 0 ||
......@@ -382,8 +397,9 @@ namespace OrthancPlugins
std::string GetBaseUrl(const OrthancPluginHttpRequest* request)
{
std::string host = configuration_.GetStringValue("Host", "");
bool ssl = configuration_.GetBooleanValue("Ssl", false);
assert(configuration_.get() != NULL);
std::string host = configuration_->GetStringValue("Host", "");
bool ssl = configuration_->GetBooleanValue("Ssl", false);
if (host.empty() &&
!LookupHttpHeader(host, request, "host"))
......@@ -418,24 +434,6 @@ namespace OrthancPlugins
}
void LogError(const std::string& message)
{
OrthancPluginLogError(GetContext(), message.c_str());
}
void LogWarning(const std::string& message)
{
OrthancPluginLogWarning(GetContext(), message.c_str());
}
void LogInfo(const std::string& message)
{
OrthancPluginLogInfo(GetContext(), message.c_str());
}
Orthanc::Encoding GetDefaultEncoding()
{
return defaultEncoding_;
......
......@@ -2,7 +2,7 @@
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 Osimis S.A., 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 Affero General Public License
......@@ -21,6 +21,7 @@
#pragma once
#include <Core/DicomFormat/DicomTag.h>
#include <Core/Enumerations.h>
#include <orthanc/OrthancCPlugin.h>
......@@ -36,6 +37,14 @@
namespace OrthancPlugins
{
static const Orthanc::DicomTag DICOM_TAG_RETRIEVE_URL(0x0008, 0x1190);
static const Orthanc::DicomTag DICOM_TAG_FAILURE_REASON(0x0008, 0x1197);
static const Orthanc::DicomTag DICOM_TAG_WARNING_REASON(0x0008, 0x1196);
static const Orthanc::DicomTag DICOM_TAG_FAILED_SOP_SEQUENCE(0x0008, 0x1198);
static const Orthanc::DicomTag DICOM_TAG_REFERENCED_SOP_SEQUENCE(0x0008, 0x1199);
static const Orthanc::DicomTag DICOM_TAG_REFERENCED_SOP_CLASS_UID(0x0008, 0x1150);
static const Orthanc::DicomTag DICOM_TAG_REFERENCED_SOP_INSTANCE_UID(0x0008, 0x1155);
struct MultipartItem
{
const char* data_;
......@@ -52,7 +61,6 @@ namespace OrthancPlugins
const std::string& header);
void ParseMultipartBody(std::vector<MultipartItem>& result,
OrthancPluginContext* context,
const char* body,
const uint64_t bodySize,
const std::string& boundary);
......@@ -61,12 +69,13 @@ namespace OrthancPlugins
const Json::Value& value,
const std::string& key);
bool ParseTag(Orthanc::DicomTag& target,
const std::string& name);
namespace Configuration
{
void Initialize(OrthancPluginContext* context);
void Initialize();
OrthancPluginContext* GetContext();
std::string GetStringValue(const std::string& key,
const std::string& defaultValue);
......@@ -87,12 +96,6 @@ namespace OrthancPlugins
const std::string& seriesInstanceUid,
const std::string& sopInstanceUid);
void LogError(const std::string& message);
void LogWarning(const std::string& message);
void LogInfo(const std::string& message);
Orthanc::Encoding GetDefaultEncoding();
}
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 Osimis S.A., Belgium
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
**/
#include "DicomResults.h"
#include "Dicom.h"
#include <Core/Toolbox.h>
#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
#include <boost/lexical_cast.hpp>
#include <boost/noncopyable.hpp>
namespace OrthancPlugins
{
DicomResults::DicomResults(OrthancPluginContext* context,
OrthancPluginRestOutput* output,
const std::string& wadoBase,
const gdcm::Dict& dictionary,
bool isXml,
bool isBulkAccessible) :
context_(context),
output_(output),
wadoBase_(wadoBase),
dictionary_(dictionary),
isFirst_(true),
isXml_(isXml),
isBulkAccessible_(isBulkAccessible)
{
if (isXml_ &&
OrthancPluginStartMultipartAnswer(context_, output_, "related", "application/dicom+xml") != 0)
{
OrthancPlugins::Configuration::LogError("Unable to create a multipart stream of DICOM+XML answers");
throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
}
jsonWriter_.AddChunk("[\n");
}
void DicomResults::AddInternal(const std::string& item)
{
if (isXml_)
{
if (OrthancPluginSendMultipartItem(context_, output_, item.c_str(), item.size()) != 0)
{
OrthancPlugins::Configuration::LogError("Unable to create a multipart stream of DICOM+XML answers");
throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
}
}
else
{
if (!isFirst_)
{
jsonWriter_.AddChunk(",\n");
}
jsonWriter_.AddChunk(item);
}
isFirst_ = false;
}
void DicomResults::AddInternal(const gdcm::DataSet& dicom)
{
std::string item;
if (isXml_)
{
GenerateSingleDicomAnswer(item, wadoBase_, dictionary_, dicom, true, isBulkAccessible_);
}
else
{
GenerateSingleDicomAnswer(item, wadoBase_, dictionary_, dicom, false, isBulkAccessible_);
}
AddInternal(item);
isFirst_ = false;
}
namespace
{
class ITagVisitor : public boost::noncopyable
{
public:
virtual ~ITagVisitor()
{
}
virtual void Visit(const gdcm::Tag& tag,
bool isSequence,
const std::string& vr,
const std::string& type,
const Json::Value& value) = 0;
static void Apply(ITagVisitor& visitor,
const Json::Value& source,
const gdcm::Dict& dictionary)
{
if (source.type() != Json::objectValue)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
}
Json::Value::Members members = source.getMemberNames();
for (size_t i = 0; i < members.size(); i++)
{
if (members[i].size() != 9 ||
members[i][4] != ',' ||
source[members[i]].type() != Json::objectValue ||
!source[members[i]].isMember("Value") ||
!source[members[i]].isMember("Type") ||
source[members[i]]["Type"].type() != Json::stringValue)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
}
const Json::Value& value = source[members[i]]["Value"];
const std::string type = source[members[i]]["Type"].asString();
gdcm::Tag tag(OrthancPlugins::ParseTag(dictionary, members[i]));
bool isSequence = false;
std::string vr = GetVRName(isSequence, dictionary, tag);
if (tag == DICOM_TAG_RETRIEVE_URL)
{
// The VR of this attribute has changed from UT to UR.
vr = "UR";
}
else
{
vr = GetVRName(isSequence, dictionary, tag);
}
visitor.Visit(tag, isSequence, vr, type, value);
}
}
};
class TagVisitorBase : public ITagVisitor
{
protected:
const Json::Value& source_;
const gdcm::Dict& dictionary_;
const std::string& bulkUri_;
public:
TagVisitorBase(const Json::Value& source,
const gdcm::Dict& dictionary,
const std::string& bulkUri) :
source_(source),
dictionary_(dictionary),
bulkUri_(bulkUri)
{
}
};
class JsonVisitor : public TagVisitorBase
{
private:
Json::Value& target_;
public:
JsonVisitor(Json::Value& target,
const Json::Value& source,
const gdcm::Dict& dictionary,
const std::string& bulkUri) :
TagVisitorBase(source, dictionary, bulkUri),
target_(target)
{
target_ = Json::objectValue;
}
virtual void Visit(const gdcm::Tag& tag,
bool isSequence,
const std::string& vr,
const std::string& type,
const Json::Value& value)
{
const std::string formattedTag = OrthancPlugins::FormatTag(tag);
Json::Value node = Json::objectValue;
node["vr"] = vr;
bool ok = false;
if (isSequence)
{
// Deal with sequences
if (type != "Sequence" ||
value.type() != Json::arrayValue)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
}
node["Value"] = Json::arrayValue;
for (Json::Value::ArrayIndex i = 0; i < value.size(); i++)
{
if (value[i].type() != Json::objectValue)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
}
Json::Value child;
std::string childUri;
if (!bulkUri_.empty())
{
std::string number = boost::lexical_cast<std::string>(i);
childUri = bulkUri_ + formattedTag + "/" + number + "/";
}
JsonVisitor visitor(child, value[i], dictionary_, childUri);
JsonVisitor::Apply(visitor, value[i], dictionary_);
node["Value"].append(child);
}
ok = true;
}
else if (type == "String" &&
value.type() == Json::stringValue)
{
// Deal with string representations
node["Value"] = Json::arrayValue;
node["Value"].append(value.asString());
ok = true;
}
else
{
// Bulk data
if (!bulkUri_.empty())
{
node["BulkDataURI"] = bulkUri_ + formattedTag;
ok = true;
}
}
if (ok)
{
target_[formattedTag] = node;
}
}
};
class XmlVisitor : public TagVisitorBase
{
private:
pugi::xml_node& target_;
public:
XmlVisitor(pugi::xml_node& target,
const Json::Value& source,
const gdcm::Dict& dictionary,
const std::string& bulkUri) :
TagVisitorBase(source, dictionary, bulkUri),
target_(target)
{
}
virtual void Visit(const gdcm::Tag& tag,
bool isSequence,
const std::string& vr,
const std::string& type,
const Json::Value& value)
{
const std::string formattedTag = OrthancPlugins::FormatTag(tag);
pugi::xml_node node = target_.append_child("DicomAttribute");
node.append_attribute("tag").set_value(formattedTag.c_str());
node.append_attribute("vr").set_value(vr.c_str());
const char* keyword = GetKeyword(dictionary_, tag);
if (keyword != NULL)
{
node.append_attribute("keyword").set_value(keyword);
}
if (isSequence)
{
// Deal with sequences
if (type != "Sequence" ||
value.type() != Json::arrayValue)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
}
for (Json::Value::ArrayIndex i = 0; i < value.size(); i++)
{
if (value[i].type() != Json::objectValue)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
}
pugi::xml_node child = node.append_child("Item");
std::string number = boost::lexical_cast<std::string>(i + 1);
child.append_attribute("number").set_value(number.c_str());
std::string childUri;
if (!bulkUri_.empty())
{
childUri = bulkUri_ + formattedTag + "/" + number + "/";
}
XmlVisitor visitor(child, value[i], dictionary_, childUri);
XmlVisitor::Apply(visitor, value[i], dictionary_);
}
}
else if (type == "String" &&
value.type() == Json::stringValue)
{
// Deal with string representations
pugi::xml_node item = node.append_child("Value");
item.append_attribute("number").set_value("1");
item.append_child(pugi::node_pcdata).set_value(value.asCString());
}
else
{
// Bulk data
if (!bulkUri_.empty())
{
pugi::xml_node value = node.append_child("BulkData");
std::string uri = bulkUri_ + formattedTag;
value.append_attribute("uri").set_value(uri.c_str());
}
}
}
};
}
static void OrthancToDicomWebXml(pugi::xml_document& target,
const Json::Value& source,
const gdcm::Dict& dictionary,
const std::string& bulkUriRoot)
{
pugi::xml_node root = target.append_child("NativeDicomModel");
root.append_attribute("xmlns").set_value("http://dicom.nema.org/PS3.19/models/NativeDICOM");
root.append_attribute("xsi:schemaLocation").set_value("http://dicom.nema.org/PS3.19/models/NativeDICOM");
root.append_attribute("xmlns:xsi").set_value("http://www.w3.org/2001/XMLSchema-instance");
XmlVisitor visitor(root, source, dictionary, bulkUriRoot);
ITagVisitor::Apply(visitor, source, dictionary);
pugi::xml_node decl = target.prepend_child(pugi::node_declaration);
decl.append_attribute("version").set_value("1.0");
decl.append_attribute("encoding").set_value("utf-8");
}
void DicomResults::AddFromOrthanc(const Json::Value& dicom,
const std::string& wadoUrl)
{
std::string bulkUriRoot;
if (isBulkAccessible_)
{
bulkUriRoot = wadoUrl + "bulk/";
}
if (isXml_)
{
pugi::xml_document doc;
OrthancToDicomWebXml(doc, dicom, dictionary_, bulkUriRoot);
ChunkedBufferWriter writer;
doc.save(writer, " ", pugi::format_default, pugi::encoding_utf8);
std::string item;
writer.Flatten(item);
AddInternal(item);
}
else
{
Json::Value v;
JsonVisitor visitor(v, dicom, dictionary_, bulkUriRoot);
ITagVisitor::Apply(visitor, dicom, dictionary_);
Json::FastWriter writer;
AddInternal(writer.write(v));
}
}
void DicomResults::Answer()
{
if (isXml_)
{
// Nothing to do in this case
}
else
{
jsonWriter_.AddChunk("]\n");
std::string answer;
jsonWriter_.Flatten(answer);
OrthancPluginAnswerBuffer(context_, output_, answer.c_str(), answer.size(), "application/dicom+json");
}
}
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 Osimis S.A., Belgium
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
**/
#pragma once
#include "ChunkedBuffer.h"
#include <orthanc/OrthancCPlugin.h>
#include <gdcmDataSet.h>
#include <gdcmDict.h>
#include <gdcmFile.h>
#include <json/value.h>
namespace OrthancPlugins
{
class DicomResults
{
private:
OrthancPluginContext* context_;
OrthancPluginRestOutput* output_;
std::string wadoBase_;
const gdcm::Dict& dictionary_;
Orthanc::ChunkedBuffer jsonWriter_; // Used for JSON output
bool isFirst_;
bool isXml_;
bool isBulkAccessible_;
void AddInternal(const std::string& item);
void AddInternal(const gdcm::DataSet& dicom);
public:
DicomResults(OrthancPluginContext* context,
OrthancPluginRestOutput* output,
const std::string& wadoBase,
const gdcm::Dict& dictionary,
bool isXml,
bool isBulkAccessible);
void Add(const gdcm::File& file)
{
AddInternal(file.GetDataSet());
}
void Add(const gdcm::DataSet& subset)
{
AddInternal(subset);
}
void AddFromOrthanc(const Json::Value& dicom,
const std::string& wadoUrl);
void Answer();
};
}
This diff is collapsed.
......@@ -2,7 +2,7 @@
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 Osimis S.A., 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 Affero General Public License
......
/**
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
**/
#include "DicomWebFormatter.h"
#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
namespace OrthancPlugins
{
static std::string FormatTag(uint16_t group,
uint16_t element)
{
char buf[16];
sprintf(buf, "%04x%04x", group, element);
return std::string(buf);
}
void DicomWebFormatter::Callback(OrthancPluginDicomWebNode *node,
OrthancPluginDicomWebSetBinaryNode setter,
uint32_t levelDepth,
const uint16_t *levelTagGroup,
const uint16_t *levelTagElement,
const uint32_t *levelIndex,
uint16_t tagGroup,
uint16_t tagElement,
OrthancPluginValueRepresentation vr)
{
const DicomWebFormatter& that = GetSingleton();
switch (that.mode_)
{
case OrthancPluginDicomWebBinaryMode_Ignore:
case OrthancPluginDicomWebBinaryMode_InlineBinary:
setter(node, that.mode_, NULL);
break;
case OrthancPluginDicomWebBinaryMode_BulkDataUri:
{
std::string uri = GetSingleton().bulkRoot_;
for (size_t i = 0; i < levelDepth; i++)
{
uri += ("/" + FormatTag(levelTagGroup[i], levelTagElement[i]) + "/" +
boost::lexical_cast<std::string>(levelIndex[i] + 1));
}
uri += "/" + FormatTag(tagGroup, tagElement);
setter(node, that.mode_, uri.c_str());
break;
}
}
}
DicomWebFormatter::Locker::Locker(OrthancPluginDicomWebBinaryMode mode,
const std::string& bulkRoot) :
that_(GetSingleton()),
lock_(that_.mutex_)
{
that_.mode_ = mode;
that_.bulkRoot_ = bulkRoot;
}
void DicomWebFormatter::Locker::Apply(std::string& target,
OrthancPluginContext* context,
const void* data,
size_t size,
bool xml)
{
OrthancString s;
if (xml)
{
s.Assign(OrthancPluginEncodeDicomWebXml(context, data, size, Callback));
}
else
{
s.Assign(OrthancPluginEncodeDicomWebJson(context, data, size, Callback));
}
s.ToString(target);
}
void DicomWebFormatter::Locker::Apply(std::string& target,
OrthancPluginContext* context,
const Json::Value& value,
bool xml)
{
MemoryBuffer dicom;
dicom.CreateDicom(value, OrthancPluginCreateDicomFlags_None);
Apply(target, context, dicom.GetData(), dicom.GetSize(), xml);
}
DicomWebFormatter::HttpWriter::HttpWriter(OrthancPluginRestOutput* output,
bool isXml) :
context_(OrthancPlugins::GetGlobalContext()),
output_(output),
isXml_(isXml),
first_(true)
{
if (context_ == NULL ||
output_ == NULL)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
}
if (isXml_)
{
OrthancPluginStartMultipartAnswer(context_, output_, "related", "application/dicom+xml");
}
else
{
jsonBuffer_.AddChunk("[");
}
}
void DicomWebFormatter::HttpWriter::AddInternal(const void* dicom,
size_t size,
OrthancPluginDicomWebBinaryMode mode,
const std::string& bulkRoot)
{
if (!first_ &&
!isXml_)
{
jsonBuffer_.AddChunk(",");
}
first_ = false;
std::string item;
{
// TODO - Avoid a global mutex => Need to change Orthanc SDK
OrthancPlugins::DicomWebFormatter::Locker locker(mode, bulkRoot);
locker.Apply(item, context_, dicom, size, isXml_);
}
if (isXml_)
{
OrthancPluginSendMultipartItem(context_, output_, item.c_str(), item.size());
}
else
{
jsonBuffer_.AddChunk(item);
}
}
void DicomWebFormatter::HttpWriter::AddJson(const Json::Value& value)
{
MemoryBuffer dicom;
dicom.CreateDicom(value, OrthancPluginCreateDicomFlags_None);
AddInternal(dicom.GetData(), dicom.GetSize(), OrthancPluginDicomWebBinaryMode_Ignore, "");
}
void DicomWebFormatter::HttpWriter::Send()
{
if (!isXml_)
{
jsonBuffer_.AddChunk("]");
std::string answer;
jsonBuffer_.Flatten(answer);
OrthancPluginAnswerBuffer(context_, output_, answer.c_str(), answer.size(), "application/dicom+json");
}
}
}
/**
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
**/
#pragma once
#include <Core/ChunkedBuffer.h>
#include <orthanc/OrthancCPlugin.h>
#include <json/value.h>
#include <boost/noncopyable.hpp>
#include <boost/thread/mutex.hpp>
namespace OrthancPlugins
{
class DicomWebFormatter : public boost::noncopyable
{
private:
boost::mutex mutex_;
OrthancPluginDicomWebBinaryMode mode_;
std::string bulkRoot_;
static DicomWebFormatter& GetSingleton()
{
static DicomWebFormatter formatter;
return formatter;
}
static void Callback(OrthancPluginDicomWebNode *node,
OrthancPluginDicomWebSetBinaryNode setter,
uint32_t levelDepth,
const uint16_t *levelTagGroup,
const uint16_t *levelTagElement,
const uint32_t *levelIndex,
uint16_t tagGroup,
uint16_t tagElement,
OrthancPluginValueRepresentation vr);
public:
class Locker : public boost::noncopyable
{
private:
DicomWebFormatter& that_;
boost::mutex::scoped_lock lock_;
public:
Locker(OrthancPluginDicomWebBinaryMode mode,
const std::string& bulkRoot);
void Apply(std::string& target,
OrthancPluginContext* context,
const void* data,
size_t size,
bool xml);
void Apply(std::string& target,
OrthancPluginContext* context,
const Json::Value& value,
bool xml);
};
class HttpWriter : public boost::noncopyable
{
private:
OrthancPluginContext* context_;
OrthancPluginRestOutput* output_;
bool isXml_;
bool first_;
Orthanc::ChunkedBuffer jsonBuffer_;
void AddInternal(const void* dicom,
size_t size,
OrthancPluginDicomWebBinaryMode mode,
const std::string& bulkRoot);
public:
HttpWriter(OrthancPluginRestOutput* output,
bool isXml);
void AddDicom(const void* dicom,
size_t size,
const std::string& bulkRoot)
{
AddInternal(dicom, size, OrthancPluginDicomWebBinaryMode_BulkDataUri, bulkRoot);
}
void AddJson(const Json::Value& value);
void Send();
};
};
}
......@@ -2,7 +2,7 @@
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 Osimis S.A., 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 Affero General Public License
......@@ -56,8 +56,8 @@ namespace OrthancPlugins
for (size_t i = 0; i < members.size(); i++)
{
std::auto_ptr<Orthanc::WebServiceParameters> parameters(new Orthanc::WebServiceParameters);
parameters->FromJson(servers[members[i]]);
std::auto_ptr<Orthanc::WebServiceParameters> parameters
(new Orthanc::WebServiceParameters(servers[members[i]]));
servers_[members[i]] = parameters.release();
}
......@@ -65,15 +65,16 @@ namespace OrthancPlugins
}
catch (Orthanc::OrthancException& e)
{
OrthancPlugins::Configuration::LogError("Exception while parsing the \"DicomWeb.Servers\" section "
"of the configuration file: " + std::string(e.What()));
OrthancPlugins::LogError("Exception while parsing the \"DicomWeb.Servers\" section "
"of the configuration file: " + std::string(e.What()));
throw;
}
if (!ok)
{
OrthancPlugins::Configuration::LogError("Cannot parse the \"DicomWeb.Servers\" section of the configuration file");
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
throw Orthanc::OrthancException(
Orthanc::ErrorCode_BadFileFormat,
"Cannot parse the \"DicomWeb.Servers\" section of the configuration file");
}
}
......@@ -93,8 +94,8 @@ namespace OrthancPlugins
if (server == servers_.end() ||
server->second == NULL)
{
OrthancPlugins::Configuration::LogError("Inexistent server: " + name);
throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem);
throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem,
"Inexistent server: " + name);
}
else
{
......@@ -154,18 +155,32 @@ namespace OrthancPlugins
url += uri;
}
std::vector<const char*> httpHeadersKeys(httpHeaders.size());
std::vector<const char*> httpHeadersValues(httpHeaders.size());
std::map<std::string, std::string> allHttpHeaders = server.GetHttpHeaders();
{
// Add the user-specified HTTP headers to the HTTP headers
// coming from the Orthanc configuration file
for (std::map<std::string, std::string>::const_iterator
it = httpHeaders.begin(); it != httpHeaders.end(); ++it)
{
allHttpHeaders[it->first] = it->second;
}
}
std::vector<const char*> httpHeadersKeys(allHttpHeaders.size());
std::vector<const char*> httpHeadersValues(allHttpHeaders.size());
{
size_t pos = 0;
for (std::map<std::string, std::string>::const_iterator
it = httpHeaders.begin(); it != httpHeaders.end(); ++it)
it = allHttpHeaders.begin(); it != allHttpHeaders.end(); ++it)
{
httpHeadersKeys[pos] = it->first.c_str();
httpHeadersValues[pos] = it->second.c_str();
pos += 1;
}
assert(pos == allHttpHeaders.size());
}
const char* bodyContent = NULL;
......@@ -179,10 +194,10 @@ namespace OrthancPlugins
bodySize = body.size();
}
OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
uint16_t status = 0;
MemoryBuffer answerHeadersTmp(context);
MemoryBuffer answerHeadersTmp;
OrthancPluginErrorCode code = OrthancPluginHttpClient(
context,
/* Outputs */
......@@ -190,7 +205,7 @@ namespace OrthancPlugins
method,
url.c_str(),
/* HTTP headers*/
httpHeaders.size(),
allHttpHeaders.size(),
httpHeadersKeys.empty() ? NULL : &httpHeadersKeys[0],
httpHeadersValues.empty() ? NULL : &httpHeadersValues[0],
bodyContent, bodySize,
......@@ -205,9 +220,10 @@ namespace OrthancPlugins
if (code != OrthancPluginErrorCode_Success ||
(status < 200 || status >= 300))
{
OrthancPlugins::Configuration::LogError("Cannot issue an HTTP query to " + url +
" (HTTP status: " + boost::lexical_cast<std::string>(status) + ")");
throw Orthanc::OrthancException(static_cast<Orthanc::ErrorCode>(code));
throw Orthanc::OrthancException(
static_cast<Orthanc::ErrorCode>(code),
"Cannot issue an HTTP query to " + url +
" (HTTP status: " + boost::lexical_cast<std::string>(status) + ")");
}
Json::Value json;
......@@ -242,9 +258,9 @@ namespace OrthancPlugins
{
if (resource.find('?') != std::string::npos)
{
OrthancPlugins::Configuration::LogError("The GET arguments must be provided in a separate field "
"(explicit \"?\" is disallowed): " + resource);
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
"The GET arguments must be provided in a separate field "
"(explicit \"?\" is disallowed): " + resource);
}
uri = resource;
......
......@@ -2,7 +2,7 @@
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 Osimis S.A., 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 Affero General Public License
......
......@@ -2,7 +2,7 @@
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 Osimis S.A., 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 Affero General Public License
......@@ -25,49 +25,32 @@
#include <Core/ChunkedBuffer.h>
#include <Core/Enumerations.h>
#include <Core/DicomFormat/DicomTag.h>
#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
#include <gdcmReader.h>
#include <gdcmDataSet.h>
#include <pugixml.hpp>
#include <gdcmDict.h>
#include <list>
namespace OrthancPlugins
{
static const gdcm::Tag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016);
static const gdcm::Tag DICOM_TAG_SOP_INSTANCE_UID(0x0008, 0x0018);
static const gdcm::Tag DICOM_TAG_STUDY_INSTANCE_UID(0x0020, 0x000d);
static const gdcm::Tag DICOM_TAG_SERIES_INSTANCE_UID(0x0020, 0x000e);
static const gdcm::Tag DICOM_TAG_REFERENCED_SOP_CLASS_UID(0x0008, 0x1150);
static const gdcm::Tag DICOM_TAG_REFERENCED_SOP_INSTANCE_UID(0x0008, 0x1155);
static const gdcm::Tag DICOM_TAG_RETRIEVE_URL(0x0008, 0x1190);
static const gdcm::Tag DICOM_TAG_FAILED_SOP_SEQUENCE(0x0008, 0x1198);
static const gdcm::Tag DICOM_TAG_FAILURE_REASON(0x0008, 0x1197);
static const gdcm::Tag DICOM_TAG_WARNING_REASON(0x0008, 0x1196);
static const gdcm::Tag DICOM_TAG_REFERENCED_SOP_SEQUENCE(0x0008, 0x1199);
static const gdcm::Tag DICOM_TAG_ACCESSION_NUMBER(0x0008, 0x0050);
static const gdcm::Tag DICOM_TAG_SPECIFIC_CHARACTER_SET(0x0008, 0x0005);
static const gdcm::Tag DICOM_TAG_PIXEL_DATA(0x7fe0, 0x0010);
static const gdcm::Tag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002);
static const gdcm::Tag DICOM_TAG_COLUMNS(0x0028, 0x0011);
static const gdcm::Tag DICOM_TAG_ROWS(0x0028, 0x0010);
static const gdcm::Tag DICOM_TAG_BITS_ALLOCATED(0x0028, 0x0100);
class ParsedDicomFile
class GdcmParsedDicomFile : public boost::noncopyable
{
private:
gdcm::Reader reader_;
void Setup(const std::string& dicom);
public:
explicit ParsedDicomFile(const OrthancPlugins::MultipartItem& item);
Orthanc::Encoding GetEncoding() const;
explicit ParsedDicomFile(const OrthancPlugins::MemoryBuffer& item);
public:
static void Initialize();
explicit GdcmParsedDicomFile(const OrthancPlugins::MemoryBuffer& item);
explicit ParsedDicomFile(const std::string& dicom)
explicit GdcmParsedDicomFile(const std::string& dicom)
{
Setup(dicom);
}
......@@ -90,65 +73,17 @@ namespace OrthancPlugins
const std::string& defaultValue,
bool stripSpaces) const;
std::string GetRawTagWithDefault(const Orthanc::DicomTag& tag,
const std::string& defaultValue,
bool stripSpaces) const;
bool GetStringTag(std::string& result,
const gdcm::Dict& dictionary,
const gdcm::Tag& tag,
bool stripSpaces) const;
bool GetIntegerTag(int& result,
const gdcm::Dict& dictionary,
const gdcm::Tag& tag) const;
Orthanc::Encoding GetEncoding() const;
std::string GetWadoUrl(const OrthancPluginHttpRequest* request) const;
};
const char* GetVRName(bool& isSequence /* out */,
const gdcm::Dict& dictionary,
const gdcm::Tag& tag);
void GenerateSingleDicomAnswer(std::string& result,
const std::string& wadoBase,
const gdcm::Dict& dictionary,
const gdcm::DataSet& dicom,
bool isXml,
bool isBulkAccessible);
void AnswerDicom(OrthancPluginContext* context,
OrthancPluginRestOutput* output,
const std::string& wadoBase,
const gdcm::Dict& dictionary,
const gdcm::DataSet& dicom,
bool isXml,
bool isBulkAccessible);
gdcm::Tag ParseTag(const gdcm::Dict& dictionary,
const std::string& key);
std::string FormatTag(const gdcm::Tag& tag);
const char* GetKeyword(const gdcm::Dict& dictionary,
const gdcm::Tag& tag);
class ChunkedBufferWriter : public pugi::xml_writer
{
private:
Orthanc::ChunkedBuffer buffer_;
public:
virtual void write(const void *data, size_t size)
{
if (size > 0)
{
buffer_.AddChunk(reinterpret_cast<const char*>(data), size);
}
}
void Flatten(std::string& s)
{
buffer_.Flatten(s);
}
};
}
......@@ -2,7 +2,7 @@
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 Osimis S.A., 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 Affero General Public License
......@@ -19,28 +19,17 @@
**/
#include "Plugin.h"
#include "DicomWebClient.h"
#include "DicomWebServers.h"
#include "GdcmParsedDicomFile.h"
#include "QidoRs.h"
#include "StowRs.h"
#include "DicomWebClient.h"
#include "WadoRs.h"
#include "WadoUri.h"
#include "Configuration.h"
#include "DicomWebServers.h"
#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
#include <Core/Toolbox.h>
#include <gdcmDictEntry.h>
#include <gdcmDict.h>
#include <gdcmDicts.h>
#include <gdcmGlobal.h>
// Global state
const gdcm::Dict* dictionary_ = NULL;
void SwitchStudies(OrthancPluginRestOutput* output,
const char* url,
......@@ -59,7 +48,7 @@ void SwitchStudies(OrthancPluginRestOutput* output,
break;
default:
OrthancPluginSendMethodNotAllowed(OrthancPlugins::Configuration::GetContext(), output, "GET,POST");
OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "GET,POST");
break;
}
}
......@@ -82,7 +71,7 @@ void SwitchStudy(OrthancPluginRestOutput* output,
break;
default:
OrthancPluginSendMethodNotAllowed(OrthancPlugins::Configuration::GetContext(), output, "GET,POST");
OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "GET,POST");
break;
}
}
......@@ -102,7 +91,7 @@ void ListServers(OrthancPluginRestOutput* output,
const char* url,
const OrthancPluginHttpRequest* request)
{
OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
if (request->method != OrthancPluginHttpMethod_Get)
{
......@@ -150,7 +139,7 @@ void ListServerOperations(OrthancPluginRestOutput* output,
const char* /*url*/,
const OrthancPluginHttpRequest* request)
{
OrthancPluginContext* context = OrthancPlugins::Configuration::GetContext();
OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
if (request->method != OrthancPluginHttpMethod_Get)
{
......@@ -186,6 +175,8 @@ extern "C"
ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)
{
assert(DisplayPerformanceWarning(context));
OrthancPlugins::SetGlobalContext(context);
Orthanc::Logging::Initialize(context);
/* Check the version of the Orthanc core */
if (OrthancPluginCheckVersion(context) == 0)
......@@ -205,10 +196,10 @@ extern "C"
try
{
// Read the configuration
OrthancPlugins::Configuration::Initialize(context);
OrthancPlugins::Configuration::Initialize();
// Initialize GDCM
dictionary_ = &gdcm::Global::GetInstance().GetDicts().GetPublicDict();
OrthancPlugins::GdcmParsedDicomFile::Initialize();
// Configure the DICOMweb callbacks
if (OrthancPlugins::Configuration::GetBooleanValue("Enable", true))
......@@ -216,57 +207,57 @@ extern "C"
std::string root = OrthancPlugins::Configuration::GetRoot();
assert(!root.empty() && root[root.size() - 1] == '/');
OrthancPlugins::Configuration::LogWarning("URI to the DICOMweb REST API: " + root);
OrthancPlugins::RegisterRestCallback<SearchForInstances>(context, root + "instances", true);
OrthancPlugins::RegisterRestCallback<SearchForSeries>(context, root + "series", true);
OrthancPlugins::RegisterRestCallback<SwitchStudies>(context, root + "studies", true);
OrthancPlugins::RegisterRestCallback<SwitchStudy>(context, root + "studies/([^/]*)", true);
OrthancPlugins::RegisterRestCallback<SearchForInstances>(context, root + "studies/([^/]*)/instances", true);
OrthancPlugins::RegisterRestCallback<RetrieveStudyMetadata>(context, root + "studies/([^/]*)/metadata", true);
OrthancPlugins::RegisterRestCallback<SearchForSeries>(context, root + "studies/([^/]*)/series", true);
OrthancPlugins::RegisterRestCallback<RetrieveDicomSeries>(context, root + "studies/([^/]*)/series/([^/]*)", true);
OrthancPlugins::RegisterRestCallback<SearchForInstances>(context, root + "studies/([^/]*)/series/([^/]*)/instances", true);
OrthancPlugins::RegisterRestCallback<RetrieveDicomInstance>(context, root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)", true);
OrthancPlugins::RegisterRestCallback<RetrieveBulkData>(context, root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/bulk/(.*)", true);
OrthancPlugins::RegisterRestCallback<RetrieveInstanceMetadata>(context, root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/metadata", true);
OrthancPlugins::RegisterRestCallback<RetrieveSeriesMetadata>(context, root + "studies/([^/]*)/series/([^/]*)/metadata", true);
OrthancPlugins::RegisterRestCallback<RetrieveFrames>(context, root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames", true);
OrthancPlugins::RegisterRestCallback<RetrieveFrames>(context, root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames/([^/]*)", true);
OrthancPlugins::RegisterRestCallback<ListServers>(context, root + "servers", true);
OrthancPlugins::RegisterRestCallback<ListServerOperations>(context, root + "servers/([^/]*)", true);
OrthancPlugins::RegisterRestCallback<StowClient>(context, root + "servers/([^/]*)/stow", true);
OrthancPlugins::RegisterRestCallback<GetFromServer>(context, root + "servers/([^/]*)/get", true);
OrthancPlugins::RegisterRestCallback<RetrieveFromServer>(context, root + "servers/([^/]*)/retrieve", true);
OrthancPlugins::LogWarning("URI to the DICOMweb REST API: " + root);
OrthancPlugins::RegisterRestCallback<SearchForInstances>(root + "instances", true);
OrthancPlugins::RegisterRestCallback<SearchForSeries>(root + "series", true);
OrthancPlugins::RegisterRestCallback<SwitchStudies>(root + "studies", true);
OrthancPlugins::RegisterRestCallback<SwitchStudy>(root + "studies/([^/]*)", true);
OrthancPlugins::RegisterRestCallback<SearchForInstances>(root + "studies/([^/]*)/instances", true);
OrthancPlugins::RegisterRestCallback<RetrieveStudyMetadata>(root + "studies/([^/]*)/metadata", true);
OrthancPlugins::RegisterRestCallback<SearchForSeries>(root + "studies/([^/]*)/series", true);
OrthancPlugins::RegisterRestCallback<RetrieveDicomSeries>(root + "studies/([^/]*)/series/([^/]*)", true);
OrthancPlugins::RegisterRestCallback<SearchForInstances>(root + "studies/([^/]*)/series/([^/]*)/instances", true);
OrthancPlugins::RegisterRestCallback<RetrieveDicomInstance>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)", true);
OrthancPlugins::RegisterRestCallback<RetrieveBulkData>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/bulk/(.*)", true);
OrthancPlugins::RegisterRestCallback<RetrieveInstanceMetadata>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/metadata", true);
OrthancPlugins::RegisterRestCallback<RetrieveSeriesMetadata>(root + "studies/([^/]*)/series/([^/]*)/metadata", true);
OrthancPlugins::RegisterRestCallback<RetrieveFrames>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames", true);
OrthancPlugins::RegisterRestCallback<RetrieveFrames>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames/([^/]*)", true);
OrthancPlugins::RegisterRestCallback<ListServers>(root + "servers", true);
OrthancPlugins::RegisterRestCallback<ListServerOperations>(root + "servers/([^/]*)", true);
OrthancPlugins::RegisterRestCallback<StowClient>(root + "servers/([^/]*)/stow", true);
OrthancPlugins::RegisterRestCallback<GetFromServer>(root + "servers/([^/]*)/get", true);
OrthancPlugins::RegisterRestCallback<RetrieveFromServer>(root + "servers/([^/]*)/retrieve", true);
}
else
{
OrthancPlugins::Configuration::LogWarning("DICOMweb support is disabled");
OrthancPlugins::LogWarning("DICOMweb support is disabled");
}
// Configure the WADO callback
if (OrthancPlugins::Configuration::GetBooleanValue("EnableWado", true))
{
std::string wado = OrthancPlugins::Configuration::GetWadoRoot();
OrthancPlugins::Configuration::LogWarning("URI to the WADO-URI API: " + wado);
OrthancPlugins::LogWarning("URI to the WADO-URI API: " + wado);
OrthancPlugins::RegisterRestCallback<WadoUriCallback>(context, wado, true);
OrthancPlugins::RegisterRestCallback<WadoUriCallback>(wado, true);
}
else
{
OrthancPlugins::Configuration::LogWarning("WADO-URI support is disabled");
OrthancPlugins::LogWarning("WADO-URI support is disabled");
}
}
catch (Orthanc::OrthancException& e)
{
OrthancPlugins::Configuration::LogError("Exception while initializing the DICOMweb plugin: " +
std::string(e.What()));
OrthancPlugins::LogError("Exception while initializing the DICOMweb plugin: " +
std::string(e.What()));
return -1;
}
catch (...)
{
OrthancPlugins::Configuration::LogError("Exception while initializing the DICOMweb plugin");
OrthancPlugins::LogError("Exception while initializing the DICOMweb plugin");
return -1;
}
......
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 Osimis S.A., Belgium
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
**/
#pragma once
#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
#include <gdcmDict.h>
// TODO Remove this file
// Global state
extern const gdcm::Dict* dictionary_;
This diff is collapsed.
......@@ -2,7 +2,7 @@
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 Osimis S.A., 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 Affero General Public License
......