# HG changeset patch # User Sebastien Jodogne # Date 1403689241 -7200 # Node ID 3fb427ac3f53886cb686164b8994489a85aa6c54 # Parent ac42ca61eee66b1468c5da16c9963053efe0d7b7# Parent b3f6fb1130cd60680e954fe055ce74214b18bf57 integration mainline -> plugins diff -r ac42ca61eee6 -r 3fb427ac3f53 CMakeLists.txt --- a/CMakeLists.txt Tue Jun 24 16:37:06 2014 +0200 +++ b/CMakeLists.txt Wed Jun 25 11:40:41 2014 +0200 @@ -415,6 +415,10 @@ ) endif() + elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + # TODO + target_link_libraries(OrthancClient pthread) + else() message(FATAL_ERROR "Support your platform here") endif() diff -r ac42ca61eee6 -r 3fb427ac3f53 Core/MultiThreading/Mutex.cpp --- a/Core/MultiThreading/Mutex.cpp Tue Jun 24 16:37:06 2014 +0200 +++ b/Core/MultiThreading/Mutex.cpp Wed Jun 25 11:40:41 2014 +0200 @@ -37,7 +37,7 @@ #if defined(_WIN32) #include -#elif defined(__linux) || defined(__FreeBSD_kernel__) +#elif defined(__linux) || defined(__FreeBSD_kernel__) || defined(__APPLE__) #include #else #error Support your platform here @@ -75,7 +75,7 @@ } -#elif defined(__linux) || defined(__FreeBSD_kernel__) +#elif defined(__linux) || defined(__FreeBSD_kernel__) || defined(__APPLE__) struct Mutex::PImpl { diff -r ac42ca61eee6 -r 3fb427ac3f53 Core/MultiThreading/ReaderWriterLock.h --- a/Core/MultiThreading/ReaderWriterLock.h Tue Jun 24 16:37:06 2014 +0200 +++ b/Core/MultiThreading/ReaderWriterLock.h Wed Jun 25 11:40:41 2014 +0200 @@ -34,9 +34,11 @@ #include "ILockable.h" +#include + namespace Orthanc { - class ReaderWriterLock + class ReaderWriterLock : public boost::noncopyable { private: struct PImpl; diff -r ac42ca61eee6 -r 3fb427ac3f53 Core/Toolbox.cpp --- a/Core/Toolbox.cpp Tue Jun 24 16:37:06 2014 +0200 +++ b/Core/Toolbox.cpp Wed Jun 25 11:40:41 2014 +0200 @@ -60,11 +60,11 @@ #include #endif -#if BOOST_HAS_LOCALE == 1 +#if BOOST_HAS_LOCALE != 1 +#error Since version 0.7.6, Orthanc entirely relies on boost::locale +#endif + #include -#else -#include -#endif #include "../Resources/md5/md5.h" #include "../Resources/base64/base64.h" @@ -74,68 +74,11 @@ // Patch for the missing "_strtoll" symbol when compiling with Visual Studio extern "C" { -int64_t _strtoi64(const char *nptr, char **endptr, int base); -int64_t strtoll(const char *nptr, char **endptr, int base) -{ - return _strtoi64(nptr, endptr, base); -} -} -#endif - - -#if BOOST_HAS_LOCALE == 0 -namespace -{ - class IconvRabi + int64_t _strtoi64(const char *nptr, char **endptr, int base); + int64_t strtoll(const char *nptr, char **endptr, int base) { - private: - iconv_t context_; - - public: - IconvRabi(const char* tocode, const char* fromcode) - { - context_ = iconv_open(tocode, fromcode); - if (!context_) - { - throw Orthanc::OrthancException("Unknown code page"); - } - } - - ~IconvRabi() - { - iconv_close(context_); - } - - std::string Convert(const std::string& source) - { - if (source.size() == 0) - { - return ""; - } - - std::string result; - char* sourcePos = const_cast(&source[0]); - size_t sourceLeft = source.size(); - - std::vector storage(source.size() + 10); - - while (sourceLeft > 0) - { - char* tmp = &storage[0]; - size_t outputLeft = storage.size(); - size_t err = iconv(context_, &sourcePos, &sourceLeft, &tmp, &outputLeft); - if (err < 0) - { - throw Orthanc::OrthancException("Bad character in sequence"); - } - - size_t count = storage.size() - outputLeft; - result += std::string(&storage[0], count); - } - - return result; - } - }; + return _strtoi64(nptr, endptr, base); + } } #endif @@ -162,7 +105,7 @@ { #if defined(_WIN32) ::Sleep(static_cast(microSeconds / static_cast(1000))); -#elif defined(__linux) || defined(__FreeBSD_kernel__) +#elif defined(__linux) || defined(__APPLE__) || defined(__FreeBSD_kernel__) usleep(microSeconds); #else #error Support your platform here @@ -554,7 +497,6 @@ std::string Toolbox::ConvertToUtf8(const std::string& source, const char* fromEncoding) { -#if BOOST_HAS_LOCALE == 1 try { return boost::locale::conv::to_utf(source, fromEncoding); @@ -564,17 +506,6 @@ // Bad input string or bad encoding return ConvertToAscii(source); } -#else - IconvRabi iconv("UTF-8", fromEncoding); - try - { - return iconv.Convert(source); - } - catch (OrthancException) - { - return ConvertToAscii(source); - } -#endif } @@ -582,7 +513,7 @@ { std::string result; - result.reserve(source.size()); + result.reserve(source.size() + 1); for (size_t i = 0; i < source.size(); i++) { if (source[i] < 128 && source[i] >= 0 && !iscntrl(source[i])) diff -r ac42ca61eee6 -r 3fb427ac3f53 DarwinCompilation.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DarwinCompilation.txt Wed Jun 25 11:40:41 2014 +0200 @@ -0,0 +1,52 @@ +This file is a complement to "INSTALL", which contains instructions +that are specific to Mac OS X (Darwin). + + +Static linking for OS X using XCode +=================================== + +The most simple way of building Orthanc under OS X consists in +statically linking against all the third-party dependencies. In this +case, no package manager such as Homebrew or MacPorts is required. +The build tool (CMake) will download the sources of all the required +packages and automatically compile them. + + +Prerequisites +------------- + +1) XCode must be installed. + +2) CMake must be installed (http://www.cmake.org/). + +3) It is assumed that Orthanc source code is placed in the folder + "~/Orthanc" and that the binaries will be compiled to + "~/OrthancBuild". + + +Prepare the build with CMake +---------------------------- + +# cd ~/OrthancBuild +# cmake -GXcode -DCMAKE_OSX_DEPLOYMENT_TARGET=10.8 -DSTATIC_BUILD=ON -DSTANDALONE_BUILD=ON .. + +NB: Adapt the value of "CMAKE_OSX_DEPLOYMENT_TARGET" with respect to +your version of XCode. + + +Build the Debug version of Orthanc +---------------------------------- + +# xcodebuild +# ./Debug/UnitTests + +The binaries of Orthanc are located at "~/OrthancBuild/Debug/Orthanc". + + +Build the Release version of Orthanc +------------------------------------ + +# xcodebuild -configuration Release +# ./Debug/UnitTests + +The binaries of Orthanc are located at "~/OrthancBuild/Release/Orthanc". diff -r ac42ca61eee6 -r 3fb427ac3f53 INSTALL --- a/INSTALL Tue Jun 24 16:37:06 2014 +0200 +++ b/INSTALL Wed Jun 25 11:40:41 2014 +0200 @@ -47,6 +47,13 @@ +Native OS X Compilation +----------------------- + +See the file "DarwinCompilation.txt". + + + Native Windows build with Microsoft Visual Studio 2005 ------------------------------------------------------ diff -r ac42ca61eee6 -r 3fb427ac3f53 LinuxCompilation.txt --- a/LinuxCompilation.txt Tue Jun 24 16:37:06 2014 +0200 +++ b/LinuxCompilation.txt Wed Jun 25 11:40:41 2014 +0200 @@ -12,6 +12,10 @@ automatically compile them. This process should work on all the Linux distributions. +We make the assumption that Orthanc source code is placed in the +folder "~/Orthanc" and that the binaries will be compiled to +"~/OrthancBuild". + To build binaries with debug information: diff -r ac42ca61eee6 -r 3fb427ac3f53 NEWS --- a/NEWS Tue Jun 24 16:37:06 2014 +0200 +++ b/NEWS Wed Jun 25 11:40:41 2014 +0200 @@ -2,6 +2,8 @@ =============================== * Introduction of the Orthanc Plugin SDK +* Official support of OS X (Darwin) +* Options to limit the number of results for an incoming C-FIND query * Support of kFreeBSD diff -r ac42ca61eee6 -r 3fb427ac3f53 OrthancServer/DicomModification.cpp --- a/OrthancServer/DicomModification.cpp Tue Jun 24 16:37:06 2014 +0200 +++ b/OrthancServer/DicomModification.cpp Wed Jun 25 11:40:41 2014 +0200 @@ -37,6 +37,7 @@ #include "FromDcmtkBridge.h" #include // For std::auto_ptr +#include namespace Orthanc { @@ -238,6 +239,7 @@ if (level_ == ResourceType_Patient && !IsReplaced(DICOM_TAG_PATIENT_ID)) { + LOG(ERROR) << "When modifying a patient, her PatientID is required to be modified"; throw OrthancException(ErrorCode_BadRequest); } diff -r ac42ca61eee6 -r 3fb427ac3f53 OrthancServer/DicomProtocol/DicomUserConnection.cpp --- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp Tue Jun 24 16:37:06 2014 +0200 +++ b/OrthancServer/DicomProtocol/DicomUserConnection.cpp Wed Jun 25 11:40:41 2014 +0200 @@ -107,7 +107,7 @@ #endif -#if defined(__FreeBSD_kernel__) +#if !defined(HOST_NAME_MAX) && defined(_POSIX_HOST_NAME_MAX) /** * TO IMPROVE: "_POSIX_HOST_NAME_MAX is only the minimum value that * HOST_NAME_MAX can ever have [...] Therefore you cannot allocate an @@ -217,21 +217,21 @@ unsigned int presentationContextId = 1; for (std::list::const_iterator it = reservedStorageSOPClasses_.begin(); - it != reservedStorageSOPClasses_.end(); it++) + it != reservedStorageSOPClasses_.end(); ++it) { RegisterStorageSOPClass(pimpl_->params_, presentationContextId, *it, asPreferred, asFallback); } for (std::set::const_iterator it = storageSOPClasses_.begin(); - it != storageSOPClasses_.end(); it++) + it != storageSOPClasses_.end(); ++it) { RegisterStorageSOPClass(pimpl_->params_, presentationContextId, *it, asPreferred, asFallback); } for (std::set::const_iterator it = defaultStorageSOPClasses_.begin(); - it != defaultStorageSOPClasses_.end(); it++) + it != defaultStorageSOPClasses_.end(); ++it) { RegisterStorageSOPClass(pimpl_->params_, presentationContextId, *it, asPreferred, asFallback); diff -r ac42ca61eee6 -r 3fb427ac3f53 OrthancServer/DicomProtocol/IFindRequestHandler.h --- a/OrthancServer/DicomProtocol/IFindRequestHandler.h Tue Jun 24 16:37:06 2014 +0200 +++ b/OrthancServer/DicomProtocol/IFindRequestHandler.h Wed Jun 25 11:40:41 2014 +0200 @@ -47,7 +47,13 @@ { } - virtual void Handle(DicomFindAnswers& answers, + /** + * Can throw exceptions. Returns "false" iff too many results have + * to be returned. In such a case, a "Matching terminated due to + * Cancel request" DIMSE code would be returned. + * https://www.dabsoft.ch/dicom/4/V.4.1/ + **/ + virtual bool Handle(DicomFindAnswers& answers, const DicomMap& input, const std::string& callingAETitle) = 0; }; diff -r ac42ca61eee6 -r 3fb427ac3f53 OrthancServer/DicomProtocol/RemoteModalityParameters.cpp --- a/OrthancServer/DicomProtocol/RemoteModalityParameters.cpp Tue Jun 24 16:37:06 2014 +0200 +++ b/OrthancServer/DicomProtocol/RemoteModalityParameters.cpp Wed Jun 25 11:40:41 2014 +0200 @@ -40,12 +40,12 @@ namespace Orthanc { - RemoteModalityParameters::RemoteModalityParameters() + RemoteModalityParameters::RemoteModalityParameters() : + aet_("ORTHANC"), + host_("localhost"), + port_(104), + manufacturer_(ModalityManufacturer_Generic) { - aet_ = "ORTHANC"; - host_ = "localhost"; - port_ = 104; - manufacturer_ = ModalityManufacturer_Generic; } void RemoteModalityParameters::SetPort(int port) diff -r ac42ca61eee6 -r 3fb427ac3f53 OrthancServer/Internals/DicomImageDecoder.cpp --- a/OrthancServer/Internals/DicomImageDecoder.cpp Tue Jun 24 16:37:06 2014 +0200 +++ b/OrthancServer/Internals/DicomImageDecoder.cpp Wed Jun 25 11:40:41 2014 +0200 @@ -100,108 +100,19 @@ namespace Orthanc { - class DicomImageDecoder::ImageSource - { - private: - std::string psmct_; - std::auto_ptr slowAccessor_; - std::auto_ptr fastAccessor_; - - public: - void Setup(DcmDataset& dataset, - unsigned int frame) - { - psmct_.clear(); - slowAccessor_.reset(NULL); - fastAccessor_.reset(NULL); - - // See also: http://support.dcmtk.org/wiki/dcmtk/howto/accessing-compressed-data - - DicomMap m; - FromDcmtkBridge::Convert(m, dataset); - - /** - * Create an accessor to the raw values of the DICOM image. - **/ - - DcmElement* e; - if (dataset.findAndGetElement(ToDcmtkBridge::Convert(DICOM_TAG_PIXEL_DATA), e).good() && - e != NULL) - { - Uint8* pixData = NULL; - if (e->getUint8Array(pixData) == EC_Normal) - { - slowAccessor_.reset(new DicomIntegerPixelAccessor(m, pixData, e->getLength())); - } - } - else if (DicomImageDecoder::DecodePsmctRle1(psmct_, dataset)) - { - LOG(INFO) << "The PMSCT_RLE1 decoding has succeeded"; - Uint8* pixData = NULL; - if (psmct_.size() > 0) - { - pixData = reinterpret_cast(&psmct_[0]); - } - - slowAccessor_.reset(new DicomIntegerPixelAccessor(m, pixData, psmct_.size())); - } - - if (slowAccessor_.get() == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - slowAccessor_->SetCurrentFrame(frame); - - - /** - * If possible, create a fast ImageAccessor to the image buffer. - **/ - - - } - - unsigned int GetWidth() const - { - assert(slowAccessor_.get() != NULL); - return slowAccessor_->GetInformation().GetWidth(); - } - - unsigned int GetHeight() const - { - assert(slowAccessor_.get() != NULL); - return slowAccessor_->GetInformation().GetHeight(); - } - - unsigned int GetChannelCount() const - { - assert(slowAccessor_.get() != NULL); - return slowAccessor_->GetInformation().GetChannelCount(); - } - - const DicomIntegerPixelAccessor& GetAccessor() const - { - assert(slowAccessor_.get() != NULL); - return *slowAccessor_; - } - - bool HasFastAccessor() const - { - return fastAccessor_.get() != NULL; - } - - const ImageAccessor& GetFastAccessor() const - { - assert(HasFastAccessor()); - return *fastAccessor_; - } - }; - - static const DicomTag DICOM_TAG_CONTENT(0x07a1, 0x100a); static const DicomTag DICOM_TAG_COMPRESSION_TYPE(0x07a1, 0x1011); - bool DicomImageDecoder::IsPsmctRle1(DcmDataset& dataset) + + static bool IsJpegLossless(const DcmDataset& dataset) + { + // http://support.dcmtk.org/docs/dcxfer_8h-source.html + return (dataset.getOriginalXfer() == EXS_JPEGLSLossless || + dataset.getOriginalXfer() == EXS_JPEGLSLossy); + } + + + static bool IsPsmctRle1(DcmDataset& dataset) { DcmElement* e; char* c; @@ -224,8 +135,8 @@ } - bool DicomImageDecoder::DecodePsmctRle1(std::string& output, - DcmDataset& dataset) + static bool DecodePsmctRle1(std::string& output, + DcmDataset& dataset) { // Check whether the DICOM instance contains an image encoded with // the PMSCT_RLE1 scheme. @@ -309,6 +220,104 @@ } + class DicomImageDecoder::ImageSource + { + private: + std::string psmct_; + std::auto_ptr slowAccessor_; + std::auto_ptr fastAccessor_; + + public: + void Setup(DcmDataset& dataset, + unsigned int frame) + { + psmct_.clear(); + slowAccessor_.reset(NULL); + fastAccessor_.reset(NULL); + + // See also: http://support.dcmtk.org/wiki/dcmtk/howto/accessing-compressed-data + + DicomMap m; + FromDcmtkBridge::Convert(m, dataset); + + /** + * Create an accessor to the raw values of the DICOM image. + **/ + + DcmElement* e; + if (dataset.findAndGetElement(ToDcmtkBridge::Convert(DICOM_TAG_PIXEL_DATA), e).good() && + e != NULL) + { + Uint8* pixData = NULL; + if (e->getUint8Array(pixData) == EC_Normal) + { + slowAccessor_.reset(new DicomIntegerPixelAccessor(m, pixData, e->getLength())); + } + } + else if (DecodePsmctRle1(psmct_, dataset)) + { + LOG(INFO) << "The PMSCT_RLE1 decoding has succeeded"; + Uint8* pixData = NULL; + if (psmct_.size() > 0) + { + pixData = reinterpret_cast(&psmct_[0]); + } + + slowAccessor_.reset(new DicomIntegerPixelAccessor(m, pixData, psmct_.size())); + } + + if (slowAccessor_.get() == NULL) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + slowAccessor_->SetCurrentFrame(frame); + + + /** + * If possible, create a fast ImageAccessor to the image buffer. + **/ + + + } + + unsigned int GetWidth() const + { + assert(slowAccessor_.get() != NULL); + return slowAccessor_->GetInformation().GetWidth(); + } + + unsigned int GetHeight() const + { + assert(slowAccessor_.get() != NULL); + return slowAccessor_->GetInformation().GetHeight(); + } + + unsigned int GetChannelCount() const + { + assert(slowAccessor_.get() != NULL); + return slowAccessor_->GetInformation().GetChannelCount(); + } + + const DicomIntegerPixelAccessor& GetAccessor() const + { + assert(slowAccessor_.get() != NULL); + return *slowAccessor_; + } + + bool HasFastAccessor() const + { + return fastAccessor_.get() != NULL; + } + + const ImageAccessor& GetFastAccessor() const + { + assert(HasFastAccessor()); + return *fastAccessor_; + } + }; + + void DicomImageDecoder::SetupImageBuffer(ImageBuffer& target, DcmDataset& dataset) { @@ -333,14 +342,6 @@ } - bool DicomImageDecoder::IsJpegLossless(const DcmDataset& dataset) - { - // http://support.dcmtk.org/docs/dcxfer_8h-source.html - return (dataset.getOriginalXfer() == EXS_JPEGLSLossless || - dataset.getOriginalXfer() == EXS_JPEGLSLossy); - } - - bool DicomImageDecoder::IsUncompressedImage(const DcmDataset& dataset) { // http://support.dcmtk.org/docs/dcxfer_8h-source.html diff -r ac42ca61eee6 -r 3fb427ac3f53 OrthancServer/Internals/DicomImageDecoder.h --- a/OrthancServer/Internals/DicomImageDecoder.h Tue Jun 24 16:37:06 2014 +0200 +++ b/OrthancServer/Internals/DicomImageDecoder.h Wed Jun 25 11:40:41 2014 +0200 @@ -52,13 +52,8 @@ static void SetupImageBuffer(ImageBuffer& target, DcmDataset& dataset); - static bool DecodePsmctRle1(std::string& output, - DcmDataset& dataset); - static bool IsUncompressedImage(const DcmDataset& dataset); - static bool IsJpegLossless(const DcmDataset& dataset); - static void DecodeUncompressedImage(ImageBuffer& target, DcmDataset& dataset, unsigned int frame); diff -r ac42ca61eee6 -r 3fb427ac3f53 OrthancServer/Internals/FindScp.cpp --- a/OrthancServer/Internals/FindScp.cpp Tue Jun 24 16:37:06 2014 +0200 +++ b/OrthancServer/Internals/FindScp.cpp Wed Jun 25 11:40:41 2014 +0200 @@ -100,6 +100,7 @@ DicomFindAnswers answers_; DcmDataset* lastRequest_; const std::string* callingAETitle_; + bool noCroppingOfResults_; }; @@ -125,12 +126,12 @@ try { - data.handler_->Handle(data.answers_, data.input_, *data.callingAETitle_); + data.noCroppingOfResults_ = data.handler_->Handle(data.answers_, data.input_, *data.callingAETitle_); } catch (OrthancException& e) { // Internal error! - LOG(ERROR) << "IFindRequestHandler Failed: " << e.What(); + LOG(ERROR) << "C-FIND request handler has failed: " << e.What(); response->DimseStatus = STATUS_FIND_Failed_UnableToProcess; *responseIdentifiers = NULL; return; @@ -148,12 +149,21 @@ if (responseCount <= static_cast(data.answers_.GetSize())) { + // There are pending results that are still to be sent response->DimseStatus = STATUS_Pending; *responseIdentifiers = ToDcmtkBridge::Convert(data.answers_.GetAnswer(responseCount - 1)); } + else if (data.noCroppingOfResults_) + { + // Success: All the results have been sent + response->DimseStatus = STATUS_Success; + *responseIdentifiers = NULL; + } else { - response->DimseStatus = STATUS_Success; + // Success, but the results were too numerous and had to be cropped + LOG(WARNING) << "Too many results for an incoming C-FIND query"; + response->DimseStatus = STATUS_FIND_Cancel_MatchingTerminatedDueToCancelRequest; *responseIdentifiers = NULL; } } @@ -170,6 +180,7 @@ data.lastRequest_ = NULL; data.handler_ = &handler; data.callingAETitle_ = &callingAETitle; + data.noCroppingOfResults_ = true; OFCondition cond = DIMSE_findProvider(assoc, presID, &msg->msg.CFindRQ, FindScpCallback, &data, diff -r ac42ca61eee6 -r 3fb427ac3f53 OrthancServer/OrthancFindRequestHandler.cpp --- a/OrthancServer/OrthancFindRequestHandler.cpp Tue Jun 24 16:37:06 2014 +0200 +++ b/OrthancServer/OrthancFindRequestHandler.cpp Wed Jun 25 11:40:41 2014 +0200 @@ -442,7 +442,26 @@ } - void OrthancFindRequestHandler::Handle(DicomFindAnswers& answers, + bool OrthancFindRequestHandler::HasReachedLimit(const DicomFindAnswers& answers, + ResourceType level) const + { + switch (level) + { + case ResourceType_Patient: + case ResourceType_Study: + case ResourceType_Series: + return (maxResults_ != 0 && answers.GetSize() >= maxResults_); + + case ResourceType_Instance: + return (maxInstances_ != 0 && answers.GetSize() >= maxInstances_); + + default: + throw OrthancException(ErrorCode_InternalError); + } + } + + + bool OrthancFindRequestHandler::Handle(DicomFindAnswers& answers, const DicomMap& input, const std::string& callingAETitle) { @@ -580,6 +599,12 @@ if (Matches(info, query)) { + if (HasReachedLimit(answers, level)) + { + // Too many results, stop before recording this new match + return false; + } + AddAnswer(answers, info, query); } } @@ -589,6 +614,8 @@ // This resource has probably been deleted during the find request } } + + return true; // All the matching resources have been returned } } diff -r ac42ca61eee6 -r 3fb427ac3f53 OrthancServer/OrthancFindRequestHandler.h --- a/OrthancServer/OrthancFindRequestHandler.h Tue Jun 24 16:37:06 2014 +0200 +++ b/OrthancServer/OrthancFindRequestHandler.h Wed Jun 25 11:40:41 2014 +0200 @@ -41,15 +41,42 @@ { private: ServerContext& context_; + unsigned int maxResults_; + unsigned int maxInstances_; + + bool HasReachedLimit(const DicomFindAnswers& answers, + ResourceType level) const; public: OrthancFindRequestHandler(ServerContext& context) : - context_(context) + context_(context), + maxResults_(0), + maxInstances_(0) { } - virtual void Handle(DicomFindAnswers& answers, + virtual bool Handle(DicomFindAnswers& answers, const DicomMap& input, const std::string& callingAETitle); + + unsigned int GetMaxResults() const + { + return maxResults_; + } + + void SetMaxResults(unsigned int results) + { + maxResults_ = results; + } + + unsigned int GetMaxInstances() const + { + return maxInstances_; + } + + void SetMaxInstances(unsigned int instances) + { + maxInstances_ = instances; + } }; } diff -r ac42ca61eee6 -r 3fb427ac3f53 OrthancServer/OrthancInitialization.cpp --- a/OrthancServer/OrthancInitialization.cpp Tue Jun 24 16:37:06 2014 +0200 +++ b/OrthancServer/OrthancInitialization.cpp Wed Jun 25 11:40:41 2014 +0200 @@ -299,7 +299,7 @@ { LOG(ERROR) << "Syntax error in the definition of modality \"" << name << "\". Please check your configuration file."; - throw e; + throw; } } @@ -330,7 +330,7 @@ { LOG(ERROR) << "Syntax error in the definition of peer \"" << name << "\". Please check your configuration file."; - throw e; + throw; } } diff -r ac42ca61eee6 -r 3fb427ac3f53 OrthancServer/ServerContext.cpp --- a/OrthancServer/ServerContext.cpp Tue Jun 24 16:37:06 2014 +0200 +++ b/OrthancServer/ServerContext.cpp Wed Jun 25 11:40:41 2014 +0200 @@ -286,7 +286,7 @@ LogMissingRequiredTag(dicomSummary); } - throw e; + throw; } } diff -r ac42ca61eee6 -r 3fb427ac3f53 OrthancServer/main.cpp --- a/OrthancServer/main.cpp Tue Jun 24 16:37:06 2014 +0200 +++ b/OrthancServer/main.cpp Wed Jun 25 11:40:41 2014 +0200 @@ -100,7 +100,32 @@ virtual IFindRequestHandler* ConstructFindRequestHandler() { - return new OrthancFindRequestHandler(context_); + std::auto_ptr result(new OrthancFindRequestHandler(context_)); + + result->SetMaxResults(Configuration::GetGlobalIntegerParameter("LimitFindResults", 0)); + result->SetMaxInstances(Configuration::GetGlobalIntegerParameter("LimitFindInstances", 0)); + + if (result->GetMaxResults() == 0) + { + LOG(INFO) << "No limit on the number of C-FIND results at the Patient, Study and Series levels"; + } + else + { + LOG(INFO) << "Maximum " << result->GetMaxResults() + << " results for C-FIND queries at the Patient, Study and Series levels"; + } + + if (result->GetMaxInstances() == 0) + { + LOG(INFO) << "No limit on the number of C-FIND results at the Instance level"; + } + else + { + LOG(INFO) << "Maximum " << result->GetMaxInstances() + << " instances will be returned for C-FIND queries at the Instance level"; + } + + return result.release(); } virtual IMoveRequestHandler* ConstructMoveRequestHandler() diff -r ac42ca61eee6 -r 3fb427ac3f53 Resources/CMake/BoostConfiguration.cmake --- a/Resources/CMake/BoostConfiguration.cmake Tue Jun 24 16:37:06 2014 +0200 +++ b/Resources/CMake/BoostConfiguration.cmake Wed Jun 25 11:40:41 2014 +0200 @@ -8,7 +8,7 @@ #set(Boost_USE_STATIC_LIBS ON) find_package(Boost - COMPONENTS filesystem thread system date_time regex) + COMPONENTS filesystem thread system date_time regex locale) if (NOT Boost_FOUND) message(FATAL_ERROR "Unable to locate Boost on this system") @@ -53,7 +53,9 @@ ) set(BOOST_SOURCES) + if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD") list(APPEND BOOST_SOURCES ${BOOST_SOURCES_DIR}/libs/thread/src/pthread/once.cpp @@ -77,10 +79,17 @@ add_definitions( -DBOOST_LOCALE_WITH_WCONV=1 ) + else() message(FATAL_ERROR "Support your platform here") endif() + if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + list(APPEND BOOST_SOURCES + ${BOOST_SOURCES_DIR}/libs/filesystem/src/utf8_codecvt_facet.cpp + ) + endif() + aux_source_directory(${BOOST_SOURCES_DIR}/libs/regex/src BOOST_REGEX_SOURCES) list(APPEND BOOST_SOURCES @@ -121,6 +130,6 @@ source_group(ThirdParty\\Boost REGULAR_EXPRESSION ${BOOST_SOURCES_DIR}/.*) else() add_definitions( - -DBOOST_HAS_LOCALE=0 + -DBOOST_HAS_LOCALE=1 ) endif() diff -r ac42ca61eee6 -r 3fb427ac3f53 Resources/CMake/Compiler.cmake --- a/Resources/CMake/Compiler.cmake Tue Jun 24 16:37:06 2014 +0200 +++ b/Resources/CMake/Compiler.cmake Wed Jun 25 11:40:41 2014 +0200 @@ -70,6 +70,12 @@ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--allow-multiple-definition -static-libgcc -static-libstdc++") endif() +elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + add_definitions( + -D_XOPEN_SOURCE=1 + ) + link_libraries(iconv) + endif() diff -r ac42ca61eee6 -r 3fb427ac3f53 Resources/CMake/DcmtkConfiguration.cmake --- a/Resources/CMake/DcmtkConfiguration.cmake Tue Jun 24 16:37:06 2014 +0200 +++ b/Resources/CMake/DcmtkConfiguration.cmake Wed Jun 25 11:40:41 2014 +0200 @@ -12,7 +12,6 @@ endif() - if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK) SET(DCMTK_VERSION_NUMBER 360) SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.0) @@ -88,6 +87,7 @@ # Source for the logging facility of DCMTK AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/oflog/libsrc DCMTK_SOURCES) if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD") list(REMOVE_ITEM DCMTK_SOURCES ${DCMTK_SOURCES_DIR}/oflog/libsrc/windebap.cc diff -r ac42ca61eee6 -r 3fb427ac3f53 Resources/CMake/GoogleLogConfiguration.cmake --- a/Resources/CMake/GoogleLogConfiguration.cmake Tue Jun 24 16:37:06 2014 +0200 +++ b/Resources/CMake/GoogleLogConfiguration.cmake Wed Jun 25 11:40:41 2014 +0200 @@ -29,6 +29,7 @@ set(ac_google_end_namespace "}") if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD") set(ac_cv_have_unistd_h 1) set(ac_cv_have_stdint_h 1) @@ -85,6 +86,7 @@ endif() if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD") if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") # Install the specific configuration for LSB SDK @@ -92,6 +94,12 @@ ${CMAKE_SOURCE_DIR}/Resources/CMake/GoogleLogConfigurationLSB.h ${GOOGLE_LOG_SOURCES_DIR}/src/config.h COPYONLY) + elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") + # Install the specific configuration for Mac OS + configure_file( + ${CMAKE_SOURCE_DIR}/Resources/CMake/GoogleLogConfigurationDarwin.h + ${GOOGLE_LOG_SOURCES_DIR}/src/config.h + COPYONLY) else() configure_file( ${CMAKE_SOURCE_DIR}/Resources/CMake/GoogleLogConfiguration.h diff -r ac42ca61eee6 -r 3fb427ac3f53 Resources/CMake/GoogleLogConfigurationDarwin.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/CMake/GoogleLogConfigurationDarwin.h Wed Jun 25 11:40:41 2014 +0200 @@ -0,0 +1,175 @@ +/* src/config.h. Generated from config.h.in by configure. */ +/* src/config.h.in. Generated from configure.ac by autoheader. */ + +/* Namespace for Google classes */ +#define GOOGLE_NAMESPACE google + +/* Define if you have the `dladdr' function */ +/* #undef HAVE_DLADDR */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_EXECINFO_H 1 + +/* Define if you have the `fcntl' function */ +#define HAVE_FCNTL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_GLOB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#define HAVE_LIBPTHREAD 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBUNWIND_H */ + +/* define if you have google gflags library */ +/* #undef HAVE_LIB_GFLAGS */ + +/* define if you have google gmock library */ +/* #undef HAVE_LIB_GMOCK */ + +/* define if you have google gtest library */ +/* #undef HAVE_LIB_GTEST */ + +/* define if you have libunwind */ +/* #undef HAVE_LIB_UNWIND */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* define if the compiler implements namespaces */ +#define HAVE_NAMESPACES 1 + +/* Define if you have POSIX threads libraries and header files. */ +#define HAVE_PTHREAD 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PWD_H 1 + +/* define if the compiler implements pthread_rwlock_* */ +#define HAVE_RWLOCK 1 + +/* Define if you have the `sigaltstack' function */ +#define HAVE_SIGALTSTACK 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYSCALL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_STAT_H 1 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SYSCALL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_TYPES_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_UCONTEXT_H 1 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UCONTEXT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* define if the compiler supports using expression for operator */ +#define HAVE_USING_OPERATOR 1 + +/* define if your compiler has __attribute__ */ +#define HAVE___ATTRIBUTE__ 1 + +/* define if your compiler has __builtin_expect */ +#define HAVE___BUILTIN_EXPECT 1 + +/* define if your compiler has __sync_val_compare_and_swap */ +#define HAVE___SYNC_VAL_COMPARE_AND_SWAP 1 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "glog" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "opensource@google.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "glog" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "glog 0.3.2" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "glog" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.3.2" + +/* How to access the PC from a struct ucontext */ +/*#include +#include +#ifdef REG_RIP +#define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP] +#else +#undef PC_FROM_UCONTEXT +#endif*/ + +// This is required for older versions of Linux +#undef PC_FROM_UCONTEXT + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef PTHREAD_CREATE_JOINABLE */ + +/* The size of `void *', as computed by sizeof. */ +#define SIZEOF_VOID_P 8 + +/* Define to 1 if you have the ANSI C header files. */ +/* #undef STDC_HEADERS */ + +/* the namespace where STL code like vector<> is defined */ +#define STL_NAMESPACE std + +/* location of source code */ +#define TEST_SRC_DIR "." + +/* Version number of package */ +#define VERSION "0.3.2" + +/* Stops putting the code inside the Google namespace */ +#define _END_GOOGLE_NAMESPACE_ } + +/* Puts following code inside the Google namespace */ +#define _START_GOOGLE_NAMESPACE_ namespace google { diff -r ac42ca61eee6 -r 3fb427ac3f53 Resources/CMake/LibCurlConfiguration.cmake --- a/Resources/CMake/LibCurlConfiguration.cmake Tue Jun 24 16:37:06 2014 +0200 +++ b/Resources/CMake/LibCurlConfiguration.cmake Wed Jun 25 11:40:41 2014 +0200 @@ -41,6 +41,7 @@ endif() if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD") if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") SET(TMP_OS "x86_64") diff -r ac42ca61eee6 -r 3fb427ac3f53 Resources/Configuration.json --- a/Resources/Configuration.json Tue Jun 24 16:37:06 2014 +0200 +++ b/Resources/Configuration.json Wed Jun 25 11:40:41 2014 +0200 @@ -165,5 +165,14 @@ // will be computed and stored in the Orthanc database. This // information can be used to detect disk corruption, at the price // of a small performance overhead. - "StoreMD5ForAttachments" : true + "StoreMD5ForAttachments" : true, + + // The maximum number of results for a single C-FIND request at the + // Patient, Study or Series level. Setting this option to "0" means + // no limit. + "LimitFindResults" : 0, + + // The maximum number of results for a single C-FIND request at the + // Instance level. Setting this option to "0" means no limit. + "LimitFindInstances" : 0 } diff -r ac42ca61eee6 -r 3fb427ac3f53 UnitTestsSources/UnitTestsMain.cpp --- a/UnitTestsSources/UnitTestsMain.cpp Tue Jun 24 16:37:06 2014 +0200 +++ b/UnitTestsSources/UnitTestsMain.cpp Wed Jun 25 11:40:41 2014 +0200 @@ -622,6 +622,9 @@ #if defined(_WIN32) ASSERT_EQ(Endianness_Little, Toolbox::DetectEndianness()); +#elif defined(__APPLE__) + ASSERT_EQ(Endianness_Little, Toolbox::DetectEndianness()); + #elif defined(__linux) || defined(__FreeBSD_kernel__) #if !defined(__BYTE_ORDER)