# HG changeset patch # User Sebastien Jodogne # Date 1431014175 -7200 # Node ID 0ed8bbf355771527e294f1a775c01c18cc75976e # Parent 1b383403c08003598105dc206916d1c6df75768b start RetrieveBulkdata diff -r 1b383403c080 -r 0ed8bbf35577 Plugin/Plugin.cpp --- a/Plugin/Plugin.cpp Thu May 07 17:07:25 2015 +0200 +++ b/Plugin/Plugin.cpp Thu May 07 17:56:15 2015 +0200 @@ -77,6 +77,7 @@ OrthancPluginRegisterRestCallback(context, "/wado-rs/studies/([^/]*)/metadata", RetrieveStudyMetadata); OrthancPluginRegisterRestCallback(context, "/wado-rs/studies/([^/]*)/series/([^/]*)/metadata", RetrieveSeriesMetadata); OrthancPluginRegisterRestCallback(context, "/wado-rs/studies/([^/]*)/series/([^/]*)/instances/([^/]*)/metadata", RetrieveInstanceMetadata); + OrthancPluginRegisterRestCallback(context, "/wado-rs/studies/([^/]*)/series/([^/]*)/instances/([^/]*)/bulk/(.*)", RetrieveBulkData); // STOW-RS callbacks OrthancPluginRegisterRestCallback(context, "/stow-rs/studies", StowCallback); diff -r 1b383403c080 -r 0ed8bbf35577 Plugin/WadoRs.cpp --- a/Plugin/WadoRs.cpp Thu May 07 17:07:25 2015 +0200 +++ b/Plugin/WadoRs.cpp Thu May 07 17:56:15 2015 +0200 @@ -20,6 +20,8 @@ #include "Plugin.h" +#include + #include "../Core/Configuration.h" #include "../Core/Dicom.h" #include "../Core/DicomResults.h" @@ -126,6 +128,50 @@ +static bool AcceptBulkData(const OrthancPluginHttpRequest* request) +{ + std::string accept; + + if (!OrthancPlugins::LookupHttpHeader(accept, request, "accept")) + { + return true; // By default, return "multipart/related; type=application/octet-stream;" + } + + std::string application; + std::map attributes; + OrthancPlugins::ParseContentType(application, attributes, accept); + + if (application != "multipart/related" && + application != "*/*") + { + std::string s = "This WADO-RS plugin cannot generate the following bulk data type: " + accept; + OrthancPluginLogError(context_, s.c_str()); + return false; + } + + if (attributes.find("type") != attributes.end()) + { + std::string s = attributes["type"]; + OrthancPlugins::ToLowerCase(s); + if (s != "application/octet-stream") + { + std::string s = "This WADO-RS plugin only supports application/octet-stream return type for bulk data retrieval (" + accept + ")"; + OrthancPluginLogError(context_, s.c_str()); + return false; + } + } + + if (attributes.find("ra,ge") != attributes.end()) + { + std::string s = "This WADO-RS plugin does not support Range retrieval, it can only return entire bulk data object"; + OrthancPluginLogError(context_, s.c_str()); + return false; + } + + return true; +} + + static int32_t AnswerListOfDicomInstances(OrthancPluginRestOutput* output, const std::string& resource) { @@ -336,7 +382,7 @@ if (!AcceptMultipartDicom(request)) { OrthancPluginSendHttpStatusCode(context_, output, 400 /* Bad request */); - return false; + return 0; } std::string uri; @@ -364,7 +410,7 @@ if (!AcceptMultipartDicom(request)) { OrthancPluginSendHttpStatusCode(context_, output, 400 /* Bad request */); - return false; + return 0; } std::string uri; @@ -393,7 +439,7 @@ if (!AcceptMultipartDicom(request)) { OrthancPluginSendHttpStatusCode(context_, output, 400 /* Bad request */); - return false; + return 0; } std::string uri; @@ -430,7 +476,7 @@ if (!AcceptMetadata(request, isXml)) { OrthancPluginSendHttpStatusCode(context_, output, 400 /* Bad request */); - return false; + return 0; } std::string uri; @@ -459,7 +505,7 @@ if (!AcceptMetadata(request, isXml)) { OrthancPluginSendHttpStatusCode(context_, output, 400 /* Bad request */); - return false; + return 0; } std::string uri; @@ -488,7 +534,7 @@ if (!AcceptMetadata(request, isXml)) { OrthancPluginSendHttpStatusCode(context_, output, 400 /* Bad request */); - return false; + return 0; } std::string uri; @@ -505,3 +551,117 @@ return -1; } } + + + +static uint32_t Hex2Dec(char c) +{ + return (c >= '0' && c <= '9') ? c - '0' : c - 'a' + 10; +} + + +static bool ParseBulkTag(gdcm::Tag& tag, + const std::string& s) +{ + if (s.size() != 8) + { + return false; + } + + for (size_t i = 0; i < 8; i++) + { + if ((s[i] < '0' || s[i] > '9') && + (s[i] < 'a' || s[i] > 'f')) + { + return false; + } + } + + uint32_t g = ((Hex2Dec(s[0]) << 12) + + (Hex2Dec(s[1]) << 8) + + (Hex2Dec(s[2]) << 4) + + Hex2Dec(s[3])); + + uint32_t e = ((Hex2Dec(s[4]) << 12) + + (Hex2Dec(s[5]) << 8) + + (Hex2Dec(s[6]) << 4) + + Hex2Dec(s[7])); + + tag = gdcm::Tag(g, e); + return true; +} + + +static bool ExploreBulkData(std::string& content, + const std::vector& path, + size_t position, + const gdcm::DataSet& dataset) +{ + gdcm::Tag tag; + if (!ParseBulkTag(tag, path[position]) || + !dataset.FindDataElement(tag)) + { + return false; + } + + const gdcm::DataElement& element = dataset.GetDataElement(tag); + + if (position + 1 == path.size()) + { + const gdcm::ByteValue* data = element.GetByteValue(); + if (!data) + { + printf("AIE\n"); + return false; + } + + content.assign(data->GetPointer(), data->GetLength()); + return true; + } + + return false; +} + +int32_t RetrieveBulkData(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) +{ + try + { + if (!AcceptBulkData(request)) + { + OrthancPluginSendHttpStatusCode(context_, output, 400 /* Bad request */); + return 0; + } + + std::string uri, content; + if (LocateInstance(output, uri, request) && + OrthancPlugins::RestApiGetString(content, context_, uri + "/file")) + { + OrthancPlugins::ParsedDicomFile dicom(content); + + std::vector path; + OrthancPlugins::TokenizeString(path, request->groups[3], '/'); + + std::string result; + if (path.size() % 2 == 1 && + ExploreBulkData(result, path, 0, dicom.GetDataSet())) + { + OrthancPlugins::MultipartWriter writer("application/octet-stream"); + writer.AddPart(result); + writer.Answer(context_, output); + } + else + { + OrthancPluginSendHttpStatusCode(context_, output, 400 /* Bad request */); + } + } + + return 0; + } + catch (std::runtime_error& e) + { + OrthancPluginLogError(context_, e.what()); + return -1; + } +} diff -r 1b383403c080 -r 0ed8bbf35577 Plugin/WadoRs.h --- a/Plugin/WadoRs.h Thu May 07 17:07:25 2015 +0200 +++ b/Plugin/WadoRs.h Thu May 07 17:56:15 2015 +0200 @@ -46,3 +46,7 @@ int32_t RetrieveInstanceMetadata(OrthancPluginRestOutput* output, const char* url, const OrthancPluginHttpRequest* request); + +int32_t RetrieveBulkData(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request); diff -r 1b383403c080 -r 0ed8bbf35577 Status.txt --- a/Status.txt Thu May 07 17:07:25 2015 +0200 +++ b/Status.txt Thu May 07 17:56:15 2015 +0200 @@ -23,13 +23,30 @@ +================================ +6.5.4 WADO-RS / RetrieveFrames +================================ + +Not supported. + + ================================ -6.5.4 WADO-RS / RetrieveFrames 6.5.5 WADO-RS / RetrieveBulkdata ================================ -Not supported. +Supported +--------- + +* application/octet-stream response + + +Not supported +------------- + +* MediaType data response +* Range query (only entire bulk data object can be returned) + ================================