[med-svn] [orthanc] 01/04: Imported Upstream version 1.0.0+dfsg
Sebastien Jodogne
jodogne-guest at moszumanska.debian.org
Wed Dec 16 12:49:14 UTC 2015
This is an automated email from the git hooks/post-receive script.
jodogne-guest pushed a commit to branch master
in repository orthanc.
commit c66c8cc4566b3e33c9db99e08a4829805ade0455
Author: jodogne-guest <s.jodogne at gmail.com>
Date: Wed Dec 16 13:24:09 2015 +0100
Imported Upstream version 1.0.0+dfsg
---
.hg_archival.txt | 6 +-
CMakeLists.txt | 2 +-
Core/HttpServer/HttpOutput.cpp | 70 +++--
Core/HttpServer/HttpOutput.h | 12 +-
NEWS | 11 +
OrthancServer/DicomDirWriter.cpp | 331 +++++++++------------
.../DicomProtocol/RemoteModalityParameters.cpp | 13 +-
OrthancServer/OrthancFindRequestHandler.cpp | 84 +++++-
OrthancServer/OrthancFindRequestHandler.h | 6 +
OrthancServer/OrthancInitialization.cpp | 59 ++--
OrthancServer/Search/HierarchicalMatcher.cpp | 12 +-
OrthancServer/Search/RangeConstraint.cpp | 11 +-
Plugins/Engine/OrthancPlugins.cpp | 47 ++-
Plugins/Engine/OrthancPlugins.h | 4 +
Plugins/Include/orthanc/OrthancCPlugin.h | 62 +++-
Plugins/Samples/ModalityWorklists/Plugin.cpp | 7 +-
Resources/CMake/DcmtkConfiguration.cmake | 6 +-
.../Samples/Lua/IncomingFindRequestFilter.lua | 14 +
18 files changed, 498 insertions(+), 259 deletions(-)
diff --git a/.hg_archival.txt b/.hg_archival.txt
index 2cc1f3b..6473729 100644
--- a/.hg_archival.txt
+++ b/.hg_archival.txt
@@ -1,5 +1,5 @@
repo: 3959d33612ccaadc0d4d707227fbed09ac35e5fe
-node: b4e8a031b0d86caf89e1a99fb7b86bb94d00c6a8
-branch: Orthanc-0.9.6
+node: 74cf1f350b45473e847fed4116c1b428fa3d7352
+branch: Orthanc-1.0.0
latesttag: null
-latesttagdistance: 1612
+latesttagdistance: 1626
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2737e27..7f6ae71 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8)
project(Orthanc)
# Version of the build, should always be "mainline" except in release branches
-set(ORTHANC_VERSION "0.9.6")
+set(ORTHANC_VERSION "1.0.0")
# Version of the database schema. History:
# * Orthanc 0.1.0 -> Orthanc 0.3.0 = no versioning
diff --git a/Core/HttpServer/HttpOutput.cpp b/Core/HttpServer/HttpOutput.cpp
index d28ae80..b749e90 100644
--- a/Core/HttpServer/HttpOutput.cpp
+++ b/Core/HttpServer/HttpOutput.cpp
@@ -449,12 +449,59 @@ namespace Orthanc
}
- void HttpOutput::StateMachine::SendMultipartItem(const void* item, size_t length)
+ void HttpOutput::StateMachine::SendMultipartItem(const void* item,
+ size_t length,
+ const std::map<std::string, std::string>& headers)
{
+ if (state_ != State_WritingMultipart)
+ {
+ throw OrthancException(ErrorCode_BadSequenceOfCalls);
+ }
+
std::string header = "--" + multipartBoundary_ + "\r\n";
- header += "Content-Type: " + multipartContentType_ + "\r\n";
- header += "Content-Length: " + boost::lexical_cast<std::string>(length) + "\r\n";
- header += "MIME-Version: 1.0\r\n\r\n";
+
+ bool hasContentType = false;
+ bool hasContentLength = false;
+ bool hasMimeVersion = false;
+
+ for (std::map<std::string, std::string>::const_iterator
+ it = headers.begin(); it != headers.end(); ++it)
+ {
+ header += it->first + ": " + it->second + "\r\n";
+
+ std::string tmp;
+ Toolbox::ToLowerCase(tmp, it->first);
+
+ if (tmp == "content-type")
+ {
+ hasContentType = true;
+ }
+
+ if (tmp == "content-length")
+ {
+ hasContentLength = true;
+ }
+
+ if (tmp == "mime-version")
+ {
+ hasMimeVersion = true;
+ }
+ }
+
+ if (!hasContentType)
+ {
+ header += "Content-Type: " + multipartContentType_ + "\r\n";
+ }
+
+ if (!hasContentLength)
+ {
+ header += "Content-Length: " + boost::lexical_cast<std::string>(length) + "\r\n";
+ }
+
+ if (!hasMimeVersion)
+ {
+ header += "MIME-Version: 1.0\r\n\r\n";
+ }
stream_.Send(false, header.c_str(), header.size());
@@ -463,7 +510,7 @@ namespace Orthanc
stream_.Send(false, item, length);
}
- stream_.Send(false, "\r\n", 2);
+ stream_.Send(false, "\r\n", 2);
}
@@ -489,19 +536,6 @@ namespace Orthanc
}
- void HttpOutput::SendMultipartItem(const std::string& item)
- {
- if (item.size() > 0)
- {
- stateMachine_.SendMultipartItem(item.c_str(), item.size());
- }
- else
- {
- stateMachine_.SendMultipartItem(NULL, 0);
- }
- }
-
-
void HttpOutput::Answer(IHttpStreamAnswer& stream)
{
HttpCompression compression = stream.SetupHttpCompression(isGzipAllowed_, isDeflateAllowed_);
diff --git a/Core/HttpServer/HttpOutput.h b/Core/HttpServer/HttpOutput.h
index 370d441..8e2386b 100644
--- a/Core/HttpServer/HttpOutput.h
+++ b/Core/HttpServer/HttpOutput.h
@@ -99,7 +99,9 @@ namespace Orthanc
void StartMultipart(const std::string& subType,
const std::string& contentType);
- void SendMultipartItem(const void* item, size_t length);
+ void SendMultipartItem(const void* item,
+ size_t length,
+ const std::map<std::string, std::string>& headers);
void CloseMultipart();
@@ -202,11 +204,11 @@ namespace Orthanc
stateMachine_.StartMultipart(subType, contentType);
}
- void SendMultipartItem(const std::string& item);
-
- void SendMultipartItem(const void* item, size_t size)
+ void SendMultipartItem(const void* item,
+ size_t size,
+ const std::map<std::string, std::string>& headers)
{
- stateMachine_.SendMultipartItem(item, size);
+ stateMachine_.SendMultipartItem(item, size, headers);
}
void CloseMultipart()
diff --git a/NEWS b/NEWS
index b762a16..6120d99 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,17 @@ Pending changes in the mainline
===============================
+Version 1.0.0 (2015/12/15)
+==========================
+
+* Lua: "IncomingFindRequestFilter()" to apply filters to incoming C-Find requests
+* New function in plugin SDK: "OrthancPluginSendMultipartItem2()"
+* Fix of DICOMDIR generation with DCMTK 3.6.1, support of encodings
+* Fix range search if the lower or upper limit is absent
+* Fix modality worklists lookups if tags with UN (unknown) VR are present
+* Warn about badly formatted modality/peer definitions in configuration file at startup
+
+
Version 0.9.6 (2015/12/08)
==========================
diff --git a/OrthancServer/DicomDirWriter.cpp b/OrthancServer/DicomDirWriter.cpp
index b5edb85..a7d838d 100644
--- a/OrthancServer/DicomDirWriter.cpp
+++ b/OrthancServer/DicomDirWriter.cpp
@@ -134,173 +134,107 @@ namespace Orthanc
Index index_;
- /*******************************************************************************
- * Functions adapted from "dcmdata/libsrc/dcddirif.cc" from DCMTK 3.6.0
- *******************************************************************************/
-
- // print an error message to the console (stderr) that something went wrong with an attribute
- static void printAttributeErrorMessage(const DcmTagKey &key,
- const OFCondition &error,
- const char *operation)
+ DcmDicomDir& GetDicomDir()
{
- if (error.bad())
+ if (dir_.get() == NULL)
{
- OFString str;
- if (operation != NULL)
- {
- str = "cannot ";
- str += operation;
- str += " ";
- }
- LOG(ERROR) << error.text() << ": " << str << DcmTag(key).getTagName() << " " << key;
+ dir_.reset(new DcmDicomDir(file_.GetPath().c_str(),
+ fileSetId_.c_str()));
+ //SetTagValue(dir_->getRootRecord(), DCM_SpecificCharacterSet, GetDicomSpecificCharacterSet(Encoding_Utf8));
}
- }
- // copy element from dataset to directory record
- static void copyElement(DcmItem& dataset,
- const DcmTagKey &key,
- DcmDirectoryRecord& record,
- const OFBool optional,
- const OFBool copyEmpty)
- {
- /* check whether tag exists in source dataset (if optional) */
- if (!optional || (copyEmpty && dataset.tagExists(key)) || dataset.tagExistsWithValue(key))
- {
- DcmElement *delem = NULL;
- /* get copy of element from source dataset */
- OFCondition status = dataset.findAndGetElement(key, delem, OFFalse /*searchIntoSub*/, OFTrue /*createCopy*/);
- if (status.good())
- {
- /* ... and insert it into the destination dataset (record) */
- status = record.insert(delem, OFTrue /*replaceOld*/);
- if (status.good())
- {
- DcmTag tag(key);
- /* check for correct VR in the dataset */
- if (delem->getVR() != tag.getEVR())
- {
- /* create warning message */
- LOG(WARNING) << "DICOMDIR: possibly wrong VR: "
- << tag.getTagName() << " " << key << " with "
- << DcmVR(delem->getVR()).getVRName() << " found, expected "
- << tag.getVRName() << " instead";
- }
- } else
- delete delem;
- } else if (status == EC_TagNotFound)
- status = record.insertEmptyElement(key);
- printAttributeErrorMessage(key, status, "insert");
- }
+ return *dir_;
}
- // copy optional string value from dataset to directory record
- static void copyStringWithDefault(DcmItem& dataset,
- const DcmTagKey &key,
- DcmDirectoryRecord& record,
- const char *defaultValue,
- const OFBool printWarning)
+
+ DcmDirectoryRecord& GetRoot()
{
- OFCondition status;
- if (dataset.tagExistsWithValue(key))
- {
- OFString stringValue;
- /* retrieve string value from source dataset and put it into the destination dataset */
- status = dataset.findAndGetOFStringArray(key, stringValue);
- if (status.good())
- status = record.putAndInsertString(key, stringValue.c_str());
- } else {
- if (printWarning && (defaultValue != NULL))
- {
- /* create warning message */
- LOG(WARNING) << "DICOMDIR: " << DcmTag(key).getTagName() << " "
- << key << " missing, using alternative: " << defaultValue;
- }
- /* put default value */
- status = record.putAndInsertString(key, defaultValue);
- }
+ return GetDicomDir().getRootRecord();
}
- // create alternative study date if absent in dataset
- static OFString &alternativeStudyDate(DcmItem& dataset,
- OFString &result)
+
+ static bool GetUtf8TagValue(std::string& result,
+ DcmItem& source,
+ Encoding encoding,
+ const DcmTagKey& key)
{
- /* use another date if present */
- if (dataset.findAndGetOFStringArray(DCM_SeriesDate, result).bad() || result.empty())
+ DcmElement* element = NULL;
+
+ if (source.findAndGetElement(key, element).good())
{
- if (dataset.findAndGetOFStringArray(DCM_AcquisitionDate, result).bad() || result.empty())
+ char* s = NULL;
+ if (element->isLeaf() &&
+ element->getString(s).good() &&
+ s != NULL)
{
- if (dataset.findAndGetOFStringArray(DCM_ContentDate, result).bad() || result.empty())
- {
- /* use current date, "19000101" in case of error */
- DcmDate::getCurrentDate(result);
- }
+ result = Toolbox::ConvertToUtf8(s, encoding);
+ return true;
}
}
- return result;
+
+ result.clear();
+ return false;
}
- // create alternative study time if absent in dataset
- static OFString &alternativeStudyTime(DcmItem& dataset,
- OFString &result)
+ static void SetTagValue(DcmDirectoryRecord& target,
+ const DcmTagKey& key,
+ const std::string& valueUtf8)
{
- /* use another time if present */
- if (dataset.findAndGetOFStringArray(DCM_SeriesTime, result).bad() || result.empty())
+ std::string s = Toolbox::ConvertFromUtf8(valueUtf8, Encoding_Ascii);
+
+ if (!target.putAndInsertString(key, s.c_str()).good())
{
- if (dataset.findAndGetOFStringArray(DCM_AcquisitionTime, result).bad() || result.empty())
- {
- if (dataset.findAndGetOFStringArray(DCM_ContentTime, result).bad() || result.empty())
- {
- /* use current time, "0000" in case of error */
- DcmTime::getCurrentTime(result);
- }
- }
+ throw OrthancException(ErrorCode_InternalError);
}
- return result;
}
+
- static void copyElementType1(DcmItem& dataset,
- const DcmTagKey &key,
- DcmDirectoryRecord& record)
+ static bool CopyString(DcmDirectoryRecord& target,
+ DcmDataset& source,
+ Encoding encoding,
+ const DcmTagKey& key,
+ bool optional,
+ bool copyEmpty)
{
- copyElement(dataset, key, record, OFFalse /*optional*/, OFFalse /*copyEmpty*/);
- }
+ if (optional &&
+ !source.tagExistsWithValue(key) &&
+ !(copyEmpty && source.tagExists(key)))
+ {
+ return false;
+ }
- static void copyElementType1C(DcmItem& dataset,
- const DcmTagKey &key,
- DcmDirectoryRecord& record)
- {
- copyElement(dataset, key, record, OFTrue /*optional*/, OFFalse /*copyEmpty*/);
- }
+ std::string value;
+ bool found = GetUtf8TagValue(value, source, encoding, key);
- static void copyElementType2(DcmItem& dataset,
- const DcmTagKey &key,
- DcmDirectoryRecord& record)
- {
- copyElement(dataset, key, record, OFFalse /*optional*/, OFTrue /*copyEmpty*/);
+ SetTagValue(target, key, value);
+ return found;
}
- /*******************************************************************************
- * End of functions adapted from "dcmdata/libsrc/dcddirif.cc" from DCMTK 3.6.0
- *******************************************************************************/
-
- DcmDicomDir& GetDicomDir()
+ static void CopyStringType1(DcmDirectoryRecord& target,
+ DcmDataset& source,
+ Encoding encoding,
+ const DcmTagKey& key)
{
- if (dir_.get() == NULL)
- {
- dir_.reset(new DcmDicomDir(file_.GetPath().c_str(),
- fileSetId_.c_str()));
- }
-
- return *dir_;
+ CopyString(target, source, encoding, key, false, false);
}
+ static void CopyStringType1C(DcmDirectoryRecord& target,
+ DcmDataset& source,
+ Encoding encoding,
+ const DcmTagKey& key)
+ {
+ CopyString(target, source, encoding, key, true, false);
+ }
- DcmDirectoryRecord& GetRoot()
+ static void CopyStringType2(DcmDirectoryRecord& target,
+ DcmDataset& source,
+ Encoding encoding,
+ const DcmTagKey& key)
{
- return GetDicomDir().getRootRecord();
+ CopyString(target, source, encoding, key, false, true);
}
@@ -310,109 +244,127 @@ namespace Orthanc
}
void FillPatient(DcmDirectoryRecord& record,
- DcmItem& dicom)
+ DcmDataset& dicom,
+ Encoding encoding)
{
// cf. "DicomDirInterface::buildPatientRecord()"
- copyElementType1C(dicom, DCM_PatientID, record);
- copyElementType2(dicom, DCM_PatientName, record);
+ CopyStringType1C(record, dicom, encoding, DCM_PatientID);
+ CopyStringType2(record, dicom, encoding, DCM_PatientName);
}
void FillStudy(DcmDirectoryRecord& record,
- DcmItem& dicom)
+ DcmDataset& dicom,
+ Encoding encoding)
{
// cf. "DicomDirInterface::buildStudyRecord()"
- OFString tmpString;
+ std::string nowDate, nowTime;
+ Toolbox::GetNowDicom(nowDate, nowTime);
+
+ std::string studyDate;
+ if (!GetUtf8TagValue(studyDate, dicom, encoding, DCM_StudyDate) &&
+ !GetUtf8TagValue(studyDate, dicom, encoding, DCM_SeriesDate) &&
+ !GetUtf8TagValue(studyDate, dicom, encoding, DCM_AcquisitionDate) &&
+ !GetUtf8TagValue(studyDate, dicom, encoding, DCM_ContentDate))
+ {
+ studyDate = nowDate;
+ }
+
+ std::string studyTime;
+ if (!GetUtf8TagValue(studyTime, dicom, encoding, DCM_StudyTime) &&
+ !GetUtf8TagValue(studyTime, dicom, encoding, DCM_SeriesTime) &&
+ !GetUtf8TagValue(studyTime, dicom, encoding, DCM_AcquisitionTime) &&
+ !GetUtf8TagValue(studyTime, dicom, encoding, DCM_ContentTime))
+ {
+ studyTime = nowTime;
+ }
+
/* copy attribute values from dataset to study record */
- copyStringWithDefault(dicom, DCM_StudyDate, record,
- alternativeStudyDate(dicom, tmpString).c_str(), OFTrue /*printWarning*/);
- copyStringWithDefault(dicom, DCM_StudyTime, record,
- alternativeStudyTime(dicom, tmpString).c_str(), OFTrue /*printWarning*/);
- copyElementType2(dicom, DCM_StudyDescription, record);
- copyElementType1(dicom, DCM_StudyInstanceUID, record);
+ SetTagValue(record, DCM_StudyDate, studyDate);
+ SetTagValue(record, DCM_StudyTime, studyTime);
+ CopyStringType2(record, dicom, encoding, DCM_StudyDescription);
+ CopyStringType1(record, dicom, encoding, DCM_StudyInstanceUID);
/* use type 1C instead of 1 in order to avoid unwanted overwriting */
- copyElementType1C(dicom, DCM_StudyID, record);
- copyElementType2(dicom, DCM_AccessionNumber, record);
+ CopyStringType1C(record, dicom, encoding, DCM_StudyID);
+ CopyStringType2(record, dicom, encoding, DCM_AccessionNumber);
}
void FillSeries(DcmDirectoryRecord& record,
- DcmItem& dicom)
+ DcmDataset& dicom,
+ Encoding encoding)
{
// cf. "DicomDirInterface::buildSeriesRecord()"
/* copy attribute values from dataset to series record */
- copyElementType1(dicom, DCM_Modality, record);
- copyElementType1(dicom, DCM_SeriesInstanceUID, record);
+ CopyStringType1(record, dicom, encoding, DCM_Modality);
+ CopyStringType1(record, dicom, encoding, DCM_SeriesInstanceUID);
/* use type 1C instead of 1 in order to avoid unwanted overwriting */
- copyElementType1C(dicom, DCM_SeriesNumber, record);
+ CopyStringType1C(record, dicom, encoding, DCM_SeriesNumber);
}
void FillInstance(DcmDirectoryRecord& record,
- DcmItem& dicom,
+ DcmDataset& dicom,
+ Encoding encoding,
DcmMetaInfo& metaInfo,
const char* path)
{
// cf. "DicomDirInterface::buildImageRecord()"
/* copy attribute values from dataset to image record */
- copyElementType1(dicom, DCM_InstanceNumber, record);
- //copyElementType1C(dicom, DCM_ImageType, record);
- copyElementType1C(dicom, DCM_ReferencedImageSequence, record);
-
- OFString tmp;
+ CopyStringType1(record, dicom, encoding, DCM_InstanceNumber);
+ //CopyElementType1C(record, dicom, encoding, DCM_ImageType);
- DcmElement* item = record.remove(DCM_ReferencedImageSequence);
- if (item != NULL)
- {
- delete item;
- }
+ // REMOVED since 0.9.7: copyElementType1C(dicom, DCM_ReferencedImageSequence, record);
- if (record.putAndInsertString(DCM_ReferencedFileID, path).bad() ||
- dicom.findAndGetOFStringArray(DCM_SOPClassUID, tmp).bad() ||
- record.putAndInsertString(DCM_ReferencedSOPClassUIDInFile, tmp.c_str()).bad() ||
- dicom.findAndGetOFStringArray(DCM_SOPInstanceUID, tmp).bad() ||
- record.putAndInsertString(DCM_ReferencedSOPInstanceUIDInFile, tmp.c_str()).bad() ||
- metaInfo.findAndGetOFStringArray(DCM_TransferSyntaxUID, tmp).bad() ||
- record.putAndInsertString(DCM_ReferencedTransferSyntaxUIDInFile, tmp.c_str()).bad())
+ std::string sopClassUid, sopInstanceUid, transferSyntaxUid;
+ if (!GetUtf8TagValue(sopClassUid, dicom, encoding, DCM_SOPClassUID) ||
+ !GetUtf8TagValue(sopInstanceUid, dicom, encoding, DCM_SOPInstanceUID) ||
+ !GetUtf8TagValue(transferSyntaxUid, metaInfo, encoding, DCM_TransferSyntaxUID))
{
throw OrthancException(ErrorCode_BadFileFormat);
}
+
+ SetTagValue(record, DCM_ReferencedFileID, path);
+ SetTagValue(record, DCM_ReferencedSOPClassUIDInFile, sopClassUid);
+ SetTagValue(record, DCM_ReferencedSOPInstanceUIDInFile, sopInstanceUid);
+ SetTagValue(record, DCM_ReferencedTransferSyntaxUIDInFile, transferSyntaxUid);
}
bool CreateResource(DcmDirectoryRecord*& target,
ResourceType level,
- DcmFileFormat& dicom,
+ ParsedDicomFile& dicom,
const char* filename,
const char* path)
{
- DcmDataset& dataset = *dicom.getDataset();
+ DcmDataset& dataset = *dicom.GetDcmtkObject().getDataset();
+ Encoding encoding = dicom.GetEncoding();
- OFCondition result;
- OFString id;
+ bool found;
+ std::string id;
E_DirRecType type;
switch (level)
{
case ResourceType_Patient:
- result = dataset.findAndGetOFString(DCM_PatientID, id);
+ found = GetUtf8TagValue(id, dataset, encoding, DCM_PatientID);
type = ERT_Patient;
break;
case ResourceType_Study:
- result = dataset.findAndGetOFString(DCM_StudyInstanceUID, id);
+ found = GetUtf8TagValue(id, dataset, encoding, DCM_StudyInstanceUID);
type = ERT_Study;
break;
case ResourceType_Series:
- result = dataset.findAndGetOFString(DCM_SeriesInstanceUID, id);
+ found = GetUtf8TagValue(id, dataset, encoding, DCM_SeriesInstanceUID);
type = ERT_Series;
break;
case ResourceType_Instance:
- result = dataset.findAndGetOFString(DCM_SOPInstanceUID, id);
+ found = GetUtf8TagValue(id, dataset, encoding, DCM_SOPInstanceUID);
type = ERT_Image;
break;
@@ -420,9 +372,9 @@ namespace Orthanc
throw OrthancException(ErrorCode_InternalError);
}
- if (!result.good())
+ if (!found)
{
- throw OrthancException(ErrorCode_InternalError);
+ throw OrthancException(ErrorCode_BadFileFormat);
}
IndexKey key = std::make_pair(level, std::string(id.c_str()));
@@ -439,29 +391,26 @@ namespace Orthanc
switch (level)
{
case ResourceType_Patient:
- FillPatient(*record, dataset);
+ FillPatient(*record, dataset, encoding);
break;
case ResourceType_Study:
- FillStudy(*record, dataset);
+ FillStudy(*record, dataset, encoding);
break;
case ResourceType_Series:
- FillSeries(*record, dataset);
+ FillSeries(*record, dataset, encoding);
break;
case ResourceType_Instance:
- FillInstance(*record, dataset, *dicom.getMetaInfo(), path);
+ FillInstance(*record, dataset, encoding, *dicom.GetDcmtkObject().getMetaInfo(), path);
break;
default:
throw OrthancException(ErrorCode_InternalError);
}
- if (record->isAffectedBySpecificCharacterSet())
- {
- copyElementType1C(dataset, DCM_SpecificCharacterSet, *record);
- }
+ CopyStringType1C(*record, dataset, encoding, DCM_SpecificCharacterSet);
target = record.get();
GetRoot().insertSub(record.release());
@@ -527,26 +476,24 @@ namespace Orthanc
path = directory + '\\' + filename;
}
- DcmFileFormat& fileFormat = dicom.GetDcmtkObject();
-
DcmDirectoryRecord* instance;
- bool isNewInstance = pimpl_->CreateResource(instance, ResourceType_Instance, fileFormat, filename.c_str(), path.c_str());
+ bool isNewInstance = pimpl_->CreateResource(instance, ResourceType_Instance, dicom, filename.c_str(), path.c_str());
if (isNewInstance)
{
DcmDirectoryRecord* series;
- bool isNewSeries = pimpl_->CreateResource(series, ResourceType_Series, fileFormat, filename.c_str(), NULL);
+ bool isNewSeries = pimpl_->CreateResource(series, ResourceType_Series, dicom, filename.c_str(), NULL);
series->insertSub(instance);
if (isNewSeries)
{
DcmDirectoryRecord* study;
- bool isNewStudy = pimpl_->CreateResource(study, ResourceType_Study, fileFormat, filename.c_str(), NULL);
+ bool isNewStudy = pimpl_->CreateResource(study, ResourceType_Study, dicom, filename.c_str(), NULL);
study->insertSub(series);
if (isNewStudy)
{
DcmDirectoryRecord* patient;
- pimpl_->CreateResource(patient, ResourceType_Patient, fileFormat, filename.c_str(), NULL);
+ pimpl_->CreateResource(patient, ResourceType_Patient, dicom, filename.c_str(), NULL);
patient->insertSub(study);
}
}
diff --git a/OrthancServer/DicomProtocol/RemoteModalityParameters.cpp b/OrthancServer/DicomProtocol/RemoteModalityParameters.cpp
index efb8182..1338f33 100644
--- a/OrthancServer/DicomProtocol/RemoteModalityParameters.cpp
+++ b/OrthancServer/DicomProtocol/RemoteModalityParameters.cpp
@@ -33,6 +33,7 @@
#include "../PrecompiledHeadersServer.h"
#include "RemoteModalityParameters.h"
+#include "../../Core/Logging.h"
#include "../../Core/OrthancException.h"
#include <boost/lexical_cast.hpp>
@@ -97,7 +98,17 @@ namespace Orthanc
if (modality.size() == 4)
{
- SetManufacturer(modality.get(3u, "").asString());
+ const std::string& manufacturer = modality.get(3u, "").asString();
+
+ try
+ {
+ SetManufacturer(manufacturer);
+ }
+ catch (OrthancException&)
+ {
+ LOG(ERROR) << "Unknown modality manufacturer: \"" << manufacturer << "\"";
+ throw;
+ }
}
else
{
diff --git a/OrthancServer/OrthancFindRequestHandler.cpp b/OrthancServer/OrthancFindRequestHandler.cpp
index 27b0832..6844336 100644
--- a/OrthancServer/OrthancFindRequestHandler.cpp
+++ b/OrthancServer/OrthancFindRequestHandler.cpp
@@ -34,6 +34,7 @@
#include "OrthancFindRequestHandler.h"
#include "../Core/DicomFormat/DicomArray.h"
+#include "../Core/Lua/LuaFunctionCall.h"
#include "../Core/Logging.h"
#include "FromDcmtkBridge.h"
#include "OrthancInitialization.h"
@@ -159,6 +160,71 @@ namespace Orthanc
}
+ bool OrthancFindRequestHandler::ApplyLuaFilter(DicomMap& target,
+ const DicomMap& source,
+ const std::string& remoteIp,
+ const std::string& remoteAet,
+ const std::string& calledAet)
+ {
+ Json::Value output;
+
+ {
+ LuaScripting::Locker locker(context_.GetLua());
+ static const char* NAME = "IncomingFindRequestFilter";
+
+ if (!locker.GetLua().IsExistingFunction(NAME))
+ {
+ return false;
+ }
+
+ Json::Value tmp = Json::objectValue;
+ DicomArray a(source);
+
+ for (size_t i = 0; i < a.GetSize(); i++)
+ {
+ const DicomValue& v = a.GetElement(i).GetValue();
+ std::string s = (v.IsNull() || v.IsBinary()) ? "" : v.GetContent();
+ tmp[a.GetElement(i).GetTag().Format()] = s;
+ }
+
+ Json::Value origin = Json::objectValue;
+ origin["RemoteIp"] = remoteIp;
+ origin["RemoteAet"] = remoteAet;
+ origin["CalledAet"] = calledAet;
+
+ LuaFunctionCall call(locker.GetLua(), NAME);
+ call.PushJson(tmp);
+ call.PushJson(origin);
+
+ call.ExecuteToJson(output, true);
+ }
+
+ // The Lua context is released at this point
+
+ if (output.type() != Json::objectValue)
+ {
+ LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table";
+ throw OrthancException(ErrorCode_LuaBadOutput);
+ }
+
+ Json::Value::Members members = output.getMemberNames();
+
+ for (size_t i = 0; i < members.size(); i++)
+ {
+ if (output[members[i]].type() != Json::stringValue)
+ {
+ LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table mapping names of DICOM tags to strings";
+ throw OrthancException(ErrorCode_LuaBadOutput);
+ }
+
+ DicomTag tag(FromDcmtkBridge::ParseTag(members[i]));
+ target.SetValue(tag, output[members[i]].asString());
+ }
+
+ return true;
+ }
+
+
void OrthancFindRequestHandler::Handle(DicomFindAnswers& answers,
const DicomMap& input,
const std::list<DicomTag>& sequencesToReturn,
@@ -181,10 +247,24 @@ namespace Orthanc
/**
+ * Possibly apply the user-supplied Lua filter.
+ **/
+
+ DicomMap lua;
+ const DicomMap* filteredInput = &input;
+
+ if (ApplyLuaFilter(lua, input, remoteIp, remoteAet, calledAet))
+ {
+ filteredInput = &lua;
+ }
+
+
+ /**
* Retrieve the query level.
**/
- const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL);
+ assert(filteredInput != NULL);
+ const DicomValue* levelTmp = filteredInput->TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL);
if (levelTmp == NULL ||
levelTmp->IsNull() ||
levelTmp->IsBinary())
@@ -204,7 +284,7 @@ namespace Orthanc
}
- DicomArray query(input);
+ DicomArray query(*filteredInput);
LOG(INFO) << "DICOM C-Find request at level: " << EnumerationToString(level);
for (size_t i = 0; i < query.GetSize(); i++)
diff --git a/OrthancServer/OrthancFindRequestHandler.h b/OrthancServer/OrthancFindRequestHandler.h
index b44cef9..601e5d7 100644
--- a/OrthancServer/OrthancFindRequestHandler.h
+++ b/OrthancServer/OrthancFindRequestHandler.h
@@ -52,6 +52,12 @@ namespace Orthanc
const DicomTag& tag,
ModalityManufacturer manufacturer);
+ bool ApplyLuaFilter(DicomMap& target,
+ const DicomMap& source,
+ const std::string& remoteIp,
+ const std::string& remoteAet,
+ const std::string& calledAet);
+
public:
OrthancFindRequestHandler(ServerContext& context) :
context_(context),
diff --git a/OrthancServer/OrthancInitialization.cpp b/OrthancServer/OrthancInitialization.cpp
index a273ad5..a28be68 100644
--- a/OrthancServer/OrthancInitialization.cpp
+++ b/OrthancServer/OrthancInitialization.cpp
@@ -71,7 +71,7 @@
namespace Orthanc
{
- static boost::mutex globalMutex_;
+ static boost::recursive_mutex globalMutex_;
static Json::Value configuration_;
static boost::filesystem::path defaultDirectory_;
static std::string configurationAbsolutePath_;
@@ -243,6 +243,26 @@ namespace Orthanc
}
+ static void ValidateGlobalConfiguration()
+ {
+ std::set<std::string> ids;
+
+ Configuration::GetListOfOrthancPeers(ids);
+ for (std::set<std::string>::const_iterator it = ids.begin(); it != ids.end(); ++it)
+ {
+ OrthancPeerParameters peer;
+ Configuration::GetOrthancPeer(peer, *it);
+ }
+
+ Configuration::GetListOfDicomModalities(ids);
+ for (std::set<std::string>::const_iterator it = ids.begin(); it != ids.end(); ++it)
+ {
+ RemoteModalityParameters modality;
+ Configuration::GetDicomModalityUsingSymbolicName(modality, *it);
+ }
+ }
+
+
static void RegisterUserMetadata()
{
if (configuration_.isMember("UserMetadata"))
@@ -367,7 +387,7 @@ namespace Orthanc
void OrthancInitialize(const char* configurationFile)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
#if ORTHANC_SSL_ENABLED == 1
// https://wiki.openssl.org/index.php/Library_Initialization
@@ -385,6 +405,7 @@ namespace Orthanc
// Read the user-provided configuration
ReadGlobalConfiguration(configurationFile);
+ ValidateGlobalConfiguration();
HttpClient::GlobalInitialize(GetGlobalBoolParameterInternal("HttpsVerifyPeers", true),
GetGlobalStringParameterInternal("HttpsCACertificates", ""));
@@ -412,7 +433,7 @@ namespace Orthanc
void OrthancFinalize()
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
HttpClient::GlobalFinalize();
#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
@@ -444,7 +465,7 @@ namespace Orthanc
std::string Configuration::GetGlobalStringParameter(const std::string& parameter,
const std::string& defaultValue)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
return GetGlobalStringParameterInternal(parameter, defaultValue);
}
@@ -452,7 +473,7 @@ namespace Orthanc
int Configuration::GetGlobalIntegerParameter(const std::string& parameter,
int defaultValue)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
if (configuration_.isMember(parameter))
{
@@ -476,7 +497,7 @@ namespace Orthanc
bool Configuration::GetGlobalBoolParameter(const std::string& parameter,
bool defaultValue)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
return GetGlobalBoolParameterInternal(parameter, defaultValue);
}
@@ -484,7 +505,7 @@ namespace Orthanc
void Configuration::GetDicomModalityUsingSymbolicName(RemoteModalityParameters& modality,
const std::string& name)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
if (!configuration_.isMember("DicomModalities"))
{
@@ -517,7 +538,7 @@ namespace Orthanc
void Configuration::GetOrthancPeer(OrthancPeerParameters& peer,
const std::string& name)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
if (!configuration_.isMember("OrthancPeers"))
{
@@ -550,7 +571,7 @@ namespace Orthanc
const char* parameter,
bool onlyAlphanumeric)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
target.clear();
@@ -589,6 +610,8 @@ namespace Orthanc
void Configuration::GetListOfDicomModalities(std::set<std::string>& target)
{
+ target.clear();
+
if (!ReadKeys(target, "DicomModalities", true))
{
LOG(ERROR) << "Only alphanumeric and dash characters are allowed in the names of the modalities";
@@ -599,6 +622,8 @@ namespace Orthanc
void Configuration::GetListOfOrthancPeers(std::set<std::string>& target)
{
+ target.clear();
+
if (!ReadKeys(target, "OrthancPeers", true))
{
LOG(ERROR) << "Only alphanumeric and dash characters are allowed in the names of Orthanc peers";
@@ -610,7 +635,7 @@ namespace Orthanc
void Configuration::SetupRegisteredUsers(MongooseServer& httpServer)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
httpServer.ClearUsers();
@@ -664,7 +689,7 @@ namespace Orthanc
std::string Configuration::InterpretStringParameterAsPath(const std::string& parameter)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
return InterpretRelativePath(defaultDirectory_.string(), parameter);
}
@@ -672,7 +697,7 @@ namespace Orthanc
void Configuration::GetGlobalListOfStringsParameter(std::list<std::string>& target,
const std::string& key)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
target.clear();
@@ -777,7 +802,7 @@ namespace Orthanc
void Configuration::UpdateModality(const std::string& symbolicName,
const RemoteModalityParameters& modality)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
if (!configuration_.isMember("DicomModalities"))
{
@@ -801,7 +826,7 @@ namespace Orthanc
void Configuration::RemoveModality(const std::string& symbolicName)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
if (!configuration_.isMember("DicomModalities"))
{
@@ -823,7 +848,7 @@ namespace Orthanc
void Configuration::UpdatePeer(const std::string& symbolicName,
const OrthancPeerParameters& peer)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
if (!configuration_.isMember("OrthancPeers"))
{
@@ -848,7 +873,7 @@ namespace Orthanc
void Configuration::RemovePeer(const std::string& symbolicName)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
if (!configuration_.isMember("OrthancPeers"))
{
@@ -980,7 +1005,7 @@ namespace Orthanc
void Configuration::GetConfiguration(Json::Value& result)
{
- boost::mutex::scoped_lock lock(globalMutex_);
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
result = configuration_;
}
diff --git a/OrthancServer/Search/HierarchicalMatcher.cpp b/OrthancServer/Search/HierarchicalMatcher.cpp
index 115c9f0..f54e396 100644
--- a/OrthancServer/Search/HierarchicalMatcher.cpp
+++ b/OrthancServer/Search/HierarchicalMatcher.cpp
@@ -33,6 +33,7 @@
#include "../PrecompiledHeadersServer.h"
#include "HierarchicalMatcher.h"
+#include "../../Core/Logging.h"
#include "../../Core/OrthancException.h"
#include "../FromDcmtkBridge.h"
#include "../ToDcmtkBridge.h"
@@ -125,7 +126,14 @@ namespace Orthanc
if (value->IsBinary())
{
- throw OrthancException(ErrorCode_BadRequest);
+ if (!value->GetContent().empty())
+ {
+ LOG(WARNING) << "This C-Find modality worklist query contains a non-empty tag ("
+ << tag.Format() << ") with UN (unknown) value representation. "
+ << "It will be ignored.";
+ }
+
+ constraints_[tag] = NULL;
}
else if (value->IsNull() ||
value->GetContent().empty())
@@ -235,7 +243,7 @@ namespace Orthanc
if (!item.findAndGetSequence(tag, sequence).good() ||
sequence == NULL)
{
- return true;
+ continue;
}
bool match = false;
diff --git a/OrthancServer/Search/RangeConstraint.cpp b/OrthancServer/Search/RangeConstraint.cpp
index f6c1ed0..f629f16 100644
--- a/OrthancServer/Search/RangeConstraint.cpp
+++ b/OrthancServer/Search/RangeConstraint.cpp
@@ -55,8 +55,15 @@ namespace Orthanc
void RangeConstraint::Setup(LookupIdentifierQuery& lookup,
const DicomTag& tag) const
{
- lookup.AddConstraint(tag, IdentifierConstraintType_GreaterOrEqual, lower_);
- lookup.AddConstraint(tag, IdentifierConstraintType_SmallerOrEqual, upper_);
+ if (!lower_.empty())
+ {
+ lookup.AddConstraint(tag, IdentifierConstraintType_GreaterOrEqual, lower_);
+ }
+
+ if (!upper_.empty())
+ {
+ lookup.AddConstraint(tag, IdentifierConstraintType_SmallerOrEqual, upper_);
+ }
}
diff --git a/Plugins/Engine/OrthancPlugins.cpp b/Plugins/Engine/OrthancPlugins.cpp
index 39f0816..32e9682 100644
--- a/Plugins/Engine/OrthancPlugins.cpp
+++ b/Plugins/Engine/OrthancPlugins.cpp
@@ -1574,7 +1574,39 @@ namespace Orthanc
*(p.target) = ReturnImage(result);
}
-
+
+
+ void OrthancPlugins::ApplySendMultipartItem(const void* parameters)
+ {
+ // An exception might be raised in this function if the
+ // connection was closed by the HTTP client.
+ const _OrthancPluginAnswerBuffer& p =
+ *reinterpret_cast<const _OrthancPluginAnswerBuffer*>(parameters);
+
+ HttpOutput* output = reinterpret_cast<HttpOutput*>(p.output);
+
+ std::map<std::string, std::string> headers; // No custom headers
+ output->SendMultipartItem(p.answer, p.answerSize, headers);
+ }
+
+
+ void OrthancPlugins::ApplySendMultipartItem2(const void* parameters)
+ {
+ // An exception might be raised in this function if the
+ // connection was closed by the HTTP client.
+ const _OrthancPluginSendMultipartItem2& p =
+ *reinterpret_cast<const _OrthancPluginSendMultipartItem2*>(parameters);
+ HttpOutput* output = reinterpret_cast<HttpOutput*>(p.output);
+
+ std::map<std::string, std::string> headers;
+ for (uint32_t i = 0; i < p.headersCount; i++)
+ {
+ headers[p.headersKeys[i]] = p.headersValues[i];
+ }
+
+ output->SendMultipartItem(p.answer, p.answerSize, headers);
+ }
+
void OrthancPlugins::DatabaseAnswer(const void* parameters)
{
@@ -1969,15 +2001,12 @@ namespace Orthanc
}
case _OrthancPluginService_SendMultipartItem:
- {
- // An exception might be raised in this function if the
- // connection was closed by the HTTP client.
- const _OrthancPluginAnswerBuffer& p =
- *reinterpret_cast<const _OrthancPluginAnswerBuffer*>(parameters);
- HttpOutput* output = reinterpret_cast<HttpOutput*>(p.output);
- output->SendMultipartItem(p.answer, p.answerSize);
+ ApplySendMultipartItem(parameters);
+ return true;
+
+ case _OrthancPluginService_SendMultipartItem2:
+ ApplySendMultipartItem2(parameters);
return true;
- }
case _OrthancPluginService_ReadFile:
{
diff --git a/Plugins/Engine/OrthancPlugins.h b/Plugins/Engine/OrthancPlugins.h
index 10ab72a..e535a67 100644
--- a/Plugins/Engine/OrthancPlugins.h
+++ b/Plugins/Engine/OrthancPlugins.h
@@ -152,6 +152,10 @@ namespace Orthanc
void ApplyLookupDictionary(const void* parameters);
+ void ApplySendMultipartItem(const void* parameters);
+
+ void ApplySendMultipartItem2(const void* parameters);
+
void ComputeHash(_OrthancPluginService service,
const void* parameters);
diff --git a/Plugins/Include/orthanc/OrthancCPlugin.h b/Plugins/Include/orthanc/OrthancCPlugin.h
index fe40348..36fc61b 100644
--- a/Plugins/Include/orthanc/OrthancCPlugin.h
+++ b/Plugins/Include/orthanc/OrthancCPlugin.h
@@ -112,9 +112,9 @@
#define ORTHANC_PLUGINS_API
#endif
-#define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER 0
-#define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER 9
-#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER 5
+#define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER 1
+#define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER 0
+#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER 0
@@ -424,6 +424,7 @@ extern "C"
_OrthancPluginService_SendMultipartItem = 2009,
_OrthancPluginService_SendHttpStatus = 2010,
_OrthancPluginService_CompressAndAnswerImage = 2011,
+ _OrthancPluginService_SendMultipartItem2 = 2012,
/* Access to the Orthanc database and API */
_OrthancPluginService_GetDicomForInstance = 3000,
@@ -2719,7 +2720,7 @@ extern "C"
* @param subType The sub-type of the multipart answer ("mixed" or "related").
* @param contentType The MIME type of the items in the multipart answer.
* @return 0 if success, or the error code if failure.
- * @see OrthancPluginSendMultipartItem()
+ * @see OrthancPluginSendMultipartItem(), OrthancPluginSendMultipartItem2()
* @ingroup REST
**/
ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginStartMultipartAnswer(
@@ -2748,6 +2749,7 @@ extern "C"
* @param answerSize Number of bytes of the item.
* @return 0 if success, or the error code if failure (this notably happens
* if the connection is closed by the client).
+ * @see OrthancPluginSendMultipartItem2()
* @ingroup REST
**/
ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSendMultipartItem(
@@ -4677,6 +4679,58 @@ extern "C"
}
+
+ typedef struct
+ {
+ OrthancPluginRestOutput* output;
+ const char* answer;
+ uint32_t answerSize;
+ uint32_t headersCount;
+ const char* const* headersKeys;
+ const char* const* headersValues;
+ } _OrthancPluginSendMultipartItem2;
+
+ /**
+ * @brief Send an item as a part of some HTTP multipart answer, with custom headers.
+ *
+ * This function sends an item as a part of some HTTP multipart
+ * answer that was initiated by OrthancPluginStartMultipartAnswer(). In addition to
+ * OrthancPluginSendMultipartItem(), this function will set HTTP header associated
+ * with the item.
+ *
+ * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+ * @param output The HTTP connection to the client application.
+ * @param answer Pointer to the memory buffer containing the item.
+ * @param answerSize Number of bytes of the item.
+ * @param headersCount The number of HTTP headers.
+ * @param headersKeys Array containing the keys of the HTTP headers.
+ * @param headersValues Array containing the values of the HTTP headers.
+ * @return 0 if success, or the error code if failure (this notably happens
+ * if the connection is closed by the client).
+ * @see OrthancPluginSendMultipartItem()
+ * @ingroup REST
+ **/
+ ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSendMultipartItem2(
+ OrthancPluginContext* context,
+ OrthancPluginRestOutput* output,
+ const char* answer,
+ uint32_t answerSize,
+ uint32_t headersCount,
+ const char* const* headersKeys,
+ const char* const* headersValues)
+ {
+ _OrthancPluginSendMultipartItem2 params;
+ params.output = output;
+ params.answer = answer;
+ params.answerSize = answerSize;
+ params.headersCount = headersCount;
+ params.headersKeys = headersKeys;
+ params.headersValues = headersValues;
+
+ return context->InvokeService(context, _OrthancPluginService_SendMultipartItem2, ¶ms);
+ }
+
+
#ifdef __cplusplus
}
#endif
diff --git a/Plugins/Samples/ModalityWorklists/Plugin.cpp b/Plugins/Samples/ModalityWorklists/Plugin.cpp
index 7178d95..4840f31 100644
--- a/Plugins/Samples/ModalityWorklists/Plugin.cpp
+++ b/Plugins/Samples/ModalityWorklists/Plugin.cpp
@@ -131,8 +131,11 @@ OrthancPluginErrorCode Callback(OrthancPluginWorklistAnswers* answers,
return OrthancPluginErrorCode_InternalError;
}
- std::cout << "Received worklist query from remote modality " << remoteAet
- << ":" << std::endl << json.toStyledString();
+ {
+ std::string msg = ("Received worklist query from remote modality " +
+ std::string(remoteAet) + ":\n" + json.toStyledString());
+ OrthancPluginLogInfo(context_, msg.c_str());
+ }
boost::filesystem::path source(folder_);
boost::filesystem::directory_iterator end;
diff --git a/Resources/CMake/DcmtkConfiguration.cmake b/Resources/CMake/DcmtkConfiguration.cmake
index 64007a2..4bc5ce2 100644
--- a/Resources/CMake/DcmtkConfiguration.cmake
+++ b/Resources/CMake/DcmtkConfiguration.cmake
@@ -191,7 +191,7 @@ else()
elseif (EXISTS "${DCMTK_DIR}/config/osconfig.h") # This is for Arch Linux
set(DCMTK_CONFIGURATION_FILE "${DCMTK_DIR}/config/osconfig.h")
else()
- message(FATAL_ERROR "Please install libdcmtk1-dev")
+ message(FATAL_ERROR "Please install libdcmtk*-dev")
endif()
# Autodetection of the version of DCMTK
@@ -220,8 +220,12 @@ if (NOT DCMTK_USE_EMBEDDED_DICTIONARIES)
if (DCMTK_DICTIONARY_DIR STREQUAL "")
find_path(DCMTK_DICTIONARY_DIR_AUTO dicom.dic
/usr/share/dcmtk
+ /usr/share/libdcmtk1
/usr/share/libdcmtk2
+ /usr/share/libdcmtk3
/usr/share/libdcmtk4
+ /usr/share/libdcmtk5
+ /usr/share/libdcmtk6
/usr/local/share/dcmtk
)
diff --git a/Resources/Samples/Lua/IncomingFindRequestFilter.lua b/Resources/Samples/Lua/IncomingFindRequestFilter.lua
new file mode 100644
index 0000000..cb5955d
--- /dev/null
+++ b/Resources/Samples/Lua/IncomingFindRequestFilter.lua
@@ -0,0 +1,14 @@
+-- This example solves the following problem:
+-- https://groups.google.com/d/msg/orthanc-users/PLWKqVVaXLs/n_0x4vKhAgAJ
+
+function IncomingFindRequestFilter(source, origin)
+ -- First display the content of the C-Find query
+ PrintRecursive(source)
+ PrintRecursive(origin)
+
+ -- Remove the "PrivateCreator" tag from the query
+ local v = source
+ v['5555,0010'] = nil
+
+ return v
+end
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/orthanc.git
More information about the debian-med-commit
mailing list