# HG changeset patch # User Sebastien Jodogne # Date 1478708444 -3600 # Node ID da2cf3ace87a64835d9596e1076dc119bda83946 # Parent 0b9034112fdefdfffd8ff47e43802ba5ce4fa6e9 sync diff -r 0b9034112fde -r da2cf3ace87a Framework/Orthanc/Core/HttpClient.cpp --- a/Framework/Orthanc/Core/HttpClient.cpp Wed Nov 09 15:29:53 2016 +0100 +++ b/Framework/Orthanc/Core/HttpClient.cpp Wed Nov 09 17:20:44 2016 +0100 @@ -37,6 +37,7 @@ #include "OrthancException.h" #include "Logging.h" #include "ChunkedBuffer.h" +#include "SystemToolbox.h" #include #include @@ -773,14 +774,14 @@ throw OrthancException(ErrorCode_ParameterOutOfRange); } - if (!Toolbox::IsRegularFile(certificateFile)) + if (!SystemToolbox::IsRegularFile(certificateFile)) { LOG(ERROR) << "Cannot open certificate file: " << certificateFile; throw OrthancException(ErrorCode_InexistentFile); } if (!certificateKeyFile.empty() && - !Toolbox::IsRegularFile(certificateKeyFile)) + !SystemToolbox::IsRegularFile(certificateKeyFile)) { LOG(ERROR) << "Cannot open key file: " << certificateKeyFile; throw OrthancException(ErrorCode_InexistentFile); diff -r 0b9034112fde -r da2cf3ace87a Framework/Orthanc/Core/Images/JpegReader.cpp --- a/Framework/Orthanc/Core/Images/JpegReader.cpp Wed Nov 09 15:29:53 2016 +0100 +++ b/Framework/Orthanc/Core/Images/JpegReader.cpp Wed Nov 09 17:20:44 2016 +0100 @@ -36,7 +36,7 @@ #include "JpegErrorManager.h" #include "../OrthancException.h" #include "../Logging.h" -#include "../Toolbox.h" +#include "../SystemToolbox.h" namespace Orthanc { @@ -96,7 +96,7 @@ void JpegReader::ReadFromFile(const std::string& filename) { - FILE* fp = Toolbox::OpenFile(filename, FileMode_ReadBinary); + FILE* fp = SystemToolbox::OpenFile(filename, FileMode_ReadBinary); if (!fp) { throw OrthancException(ErrorCode_InexistentFile); diff -r 0b9034112fde -r da2cf3ace87a Framework/Orthanc/Core/Images/PngReader.cpp --- a/Framework/Orthanc/Core/Images/PngReader.cpp Wed Nov 09 15:29:53 2016 +0100 +++ b/Framework/Orthanc/Core/Images/PngReader.cpp Wed Nov 09 17:20:44 2016 +0100 @@ -34,6 +34,7 @@ #include "PngReader.h" #include "../OrthancException.h" +#include "../SystemToolbox.h" #include "../Toolbox.h" #include @@ -49,7 +50,7 @@ FileRabi(const char* filename) { - fp_ = Toolbox::OpenFile(filename, FileMode_ReadBinary); + fp_ = SystemToolbox::OpenFile(filename, FileMode_ReadBinary); if (!fp_) { throw OrthancException(ErrorCode_InexistentFile); diff -r 0b9034112fde -r da2cf3ace87a Framework/Orthanc/Core/Logging.cpp --- a/Framework/Orthanc/Core/Logging.cpp Wed Nov 09 15:29:53 2016 +0100 +++ b/Framework/Orthanc/Core/Logging.cpp Wed Nov 09 17:20:44 2016 +0100 @@ -83,6 +83,7 @@ #include "OrthancException.h" #include "Enumerations.h" #include "Toolbox.h" +#include "SystemToolbox.h" #include #include @@ -150,7 +151,7 @@ boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); boost::filesystem::path root(directory); - boost::filesystem::path exe(Toolbox::GetPathToExecutable()); + boost::filesystem::path exe(SystemToolbox::GetPathToExecutable()); if (!boost::filesystem::exists(root) || !boost::filesystem::is_directory(root)) @@ -166,7 +167,7 @@ now.time_of_day().hours(), now.time_of_day().minutes(), now.time_of_day().seconds(), - Toolbox::GetProcessId()); + SystemToolbox::GetProcessId()); std::string programName = exe.filename().replace_extension("").string(); diff -r 0b9034112fde -r da2cf3ace87a Framework/Orthanc/Core/PrecompiledHeaders.h --- a/Framework/Orthanc/Core/PrecompiledHeaders.h Wed Nov 09 15:29:53 2016 +0100 +++ b/Framework/Orthanc/Core/PrecompiledHeaders.h Wed Nov 09 17:20:44 2016 +0100 @@ -56,6 +56,5 @@ #include "Logging.h" #include "OrthancException.h" #include "Toolbox.h" -#include "Uuid.h" #endif diff -r 0b9034112fde -r da2cf3ace87a Framework/Orthanc/Core/SystemToolbox.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Orthanc/Core/SystemToolbox.cpp Wed Nov 09 17:20:44 2016 +0100 @@ -0,0 +1,502 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include "PrecompiledHeaders.h" +#include "SystemToolbox.h" + + +#if BOOST_HAS_DATE_TIME == 1 +#include +#endif + + +#if defined(_WIN32) +#include +#include // For "_spawnvp()" and "_getpid()" +#else +#include // For "execvp()" +#include // For "waitpid()" +#endif + +#if defined(__APPLE__) && defined(__MACH__) +#include /* _NSGetExecutablePath */ +#include /* PATH_MAX */ +#endif + +#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) +#include /* PATH_MAX */ +#include +#include +#endif + + +#include "Logging.h" +#include "OrthancException.h" +#include "Toolbox.h" + +#include +#include + + +namespace Orthanc +{ + static bool finish_; + static ServerBarrierEvent barrierEvent_; + +#if defined(_WIN32) + static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType) + { + // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx + finish_ = true; + return true; + } +#else + static void SignalHandler(int signal) + { + if (signal == SIGHUP) + { + barrierEvent_ = ServerBarrierEvent_Reload; + } + + finish_ = true; + } +#endif + + + static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag) + { +#if defined(_WIN32) + SetConsoleCtrlHandler(ConsoleControlHandler, true); +#else + signal(SIGINT, SignalHandler); + signal(SIGQUIT, SignalHandler); + signal(SIGTERM, SignalHandler); + signal(SIGHUP, SignalHandler); +#endif + + // Active loop that awakens every 100ms + finish_ = false; + barrierEvent_ = ServerBarrierEvent_Stop; + while (!(*stopFlag || finish_)) + { + Toolbox::USleep(100 * 1000); + } + +#if defined(_WIN32) + SetConsoleCtrlHandler(ConsoleControlHandler, false); +#else + signal(SIGINT, NULL); + signal(SIGQUIT, NULL); + signal(SIGTERM, NULL); + signal(SIGHUP, NULL); +#endif + + return barrierEvent_; + } + + + ServerBarrierEvent SystemToolbox::ServerBarrier(const bool& stopFlag) + { + return ServerBarrierInternal(&stopFlag); + } + + + ServerBarrierEvent SystemToolbox::ServerBarrier() + { + const bool stopFlag = false; + return ServerBarrierInternal(&stopFlag); + } + + + static std::streamsize GetStreamSize(std::istream& f) + { + // http://www.cplusplus.com/reference/iostream/istream/tellg/ + f.seekg(0, std::ios::end); + std::streamsize size = f.tellg(); + f.seekg(0, std::ios::beg); + + return size; + } + + + void SystemToolbox::ReadFile(std::string& content, + const std::string& path) + { + if (!IsRegularFile(path)) + { + LOG(ERROR) << std::string("The path does not point to a regular file: ") << path; + throw OrthancException(ErrorCode_RegularFileExpected); + } + + boost::filesystem::ifstream f; + f.open(path, std::ifstream::in | std::ifstream::binary); + if (!f.good()) + { + throw OrthancException(ErrorCode_InexistentFile); + } + + std::streamsize size = GetStreamSize(f); + content.resize(size); + if (size != 0) + { + f.read(reinterpret_cast(&content[0]), size); + } + + f.close(); + } + + + bool SystemToolbox::ReadHeader(std::string& header, + const std::string& path, + size_t headerSize) + { + if (!IsRegularFile(path)) + { + LOG(ERROR) << std::string("The path does not point to a regular file: ") << path; + throw OrthancException(ErrorCode_RegularFileExpected); + } + + boost::filesystem::ifstream f; + f.open(path, std::ifstream::in | std::ifstream::binary); + if (!f.good()) + { + throw OrthancException(ErrorCode_InexistentFile); + } + + bool full = true; + + { + std::streamsize size = GetStreamSize(f); + if (size <= 0) + { + headerSize = 0; + full = false; + } + else if (static_cast(size) < headerSize) + { + headerSize = size; // Truncate to the size of the file + full = false; + } + } + + header.resize(headerSize); + if (headerSize != 0) + { + f.read(reinterpret_cast(&header[0]), headerSize); + } + + f.close(); + + return full; + } + + + void SystemToolbox::WriteFile(const void* content, + size_t size, + const std::string& path) + { + boost::filesystem::ofstream f; + f.open(path, std::ofstream::out | std::ofstream::binary); + if (!f.good()) + { + throw OrthancException(ErrorCode_CannotWriteFile); + } + + if (size != 0) + { + f.write(reinterpret_cast(content), size); + + if (!f.good()) + { + f.close(); + throw OrthancException(ErrorCode_FileStorageCannotWrite); + } + } + + f.close(); + } + + + void SystemToolbox::WriteFile(const std::string& content, + const std::string& path) + { + WriteFile(content.size() > 0 ? content.c_str() : NULL, + content.size(), path); + } + + + void SystemToolbox::RemoveFile(const std::string& path) + { + if (boost::filesystem::exists(path)) + { + if (IsRegularFile(path)) + { + boost::filesystem::remove(path); + } + else + { + throw OrthancException(ErrorCode_RegularFileExpected); + } + } + } + + + uint64_t SystemToolbox::GetFileSize(const std::string& path) + { + try + { + return static_cast(boost::filesystem::file_size(path)); + } + catch (boost::filesystem::filesystem_error&) + { + throw OrthancException(ErrorCode_InexistentFile); + } + } + + + void SystemToolbox::MakeDirectory(const std::string& path) + { + if (boost::filesystem::exists(path)) + { + if (!boost::filesystem::is_directory(path)) + { + throw OrthancException(ErrorCode_DirectoryOverFile); + } + } + else + { + if (!boost::filesystem::create_directories(path)) + { + throw OrthancException(ErrorCode_MakeDirectory); + } + } + } + + + bool SystemToolbox::IsExistingFile(const std::string& path) + { + return boost::filesystem::exists(path); + } + + +#if defined(_WIN32) + static std::string GetPathToExecutableInternal() + { + // Yes, this is ugly, but there is no simple way to get the + // required buffer size, so we use a big constant + std::vector buffer(32768); + /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast(buffer.size() - 1)); + return std::string(&buffer[0]); + } + +#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) + static std::string GetPathToExecutableInternal() + { + std::vector buffer(PATH_MAX + 1); + ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1); + if (bytes == 0) + { + throw OrthancException(ErrorCode_PathToExecutable); + } + + return std::string(&buffer[0]); + } + +#elif defined(__APPLE__) && defined(__MACH__) + static std::string GetPathToExecutableInternal() + { + char pathbuf[PATH_MAX + 1]; + unsigned int bufsize = static_cast(sizeof(pathbuf)); + + _NSGetExecutablePath( pathbuf, &bufsize); + + return std::string(pathbuf); + } + +#else +#error Support your platform here +#endif + + + std::string SystemToolbox::GetPathToExecutable() + { + boost::filesystem::path p(GetPathToExecutableInternal()); + return boost::filesystem::absolute(p).string(); + } + + + std::string SystemToolbox::GetDirectoryOfExecutable() + { + boost::filesystem::path p(GetPathToExecutableInternal()); + return boost::filesystem::absolute(p.parent_path()).string(); + } + + + void SystemToolbox::ExecuteSystemCommand(const std::string& command, + const std::vector& arguments) + { + // Convert the arguments as a C array + std::vector args(arguments.size() + 2); + + args.front() = const_cast(command.c_str()); + + for (size_t i = 0; i < arguments.size(); i++) + { + args[i + 1] = const_cast(arguments[i].c_str()); + } + + args.back() = NULL; + + int status; + +#if defined(_WIN32) + // http://msdn.microsoft.com/en-us/library/275khfab.aspx + status = static_cast(_spawnvp(_P_OVERLAY, command.c_str(), &args[0])); + +#else + int pid = fork(); + + if (pid == -1) + { + // Error in fork() +#if ORTHANC_ENABLE_LOGGING == 1 + LOG(ERROR) << "Cannot fork a child process"; +#endif + + throw OrthancException(ErrorCode_SystemCommand); + } + else if (pid == 0) + { + // Execute the system command in the child process + execvp(command.c_str(), &args[0]); + + // We should never get here + _exit(1); + } + else + { + // Wait for the system command to exit + waitpid(pid, &status, 0); + } +#endif + + if (status != 0) + { +#if ORTHANC_ENABLE_LOGGING == 1 + LOG(ERROR) << "System command failed with status code " << status; +#endif + + throw OrthancException(ErrorCode_SystemCommand); + } + } + + + int SystemToolbox::GetProcessId() + { +#if defined(_WIN32) + return static_cast(_getpid()); +#else + return static_cast(getpid()); +#endif + } + + + bool SystemToolbox::IsRegularFile(const std::string& path) + { + namespace fs = boost::filesystem; + + try + { + if (fs::exists(path)) + { + fs::file_status status = fs::status(path); + return (status.type() == boost::filesystem::regular_file || + status.type() == boost::filesystem::reparse_file); // Fix BitBucket issue #11 + } + } + catch (fs::filesystem_error&) + { + } + + return false; + } + + + FILE* SystemToolbox::OpenFile(const std::string& path, + FileMode mode) + { +#if defined(_WIN32) + // TODO Deal with special characters by converting to the current locale +#endif + + const char* m; + switch (mode) + { + case FileMode_ReadBinary: + m = "rb"; + break; + + case FileMode_WriteBinary: + m = "wb"; + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + return fopen(path.c_str(), m); + } + + +#if BOOST_HAS_DATE_TIME == 1 + std::string SystemToolbox::GetNowIsoString() + { + boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); + return boost::posix_time::to_iso_string(now); + } + + void SystemToolbox::GetNowDicom(std::string& date, + std::string& time) + { + boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); + tm tm = boost::posix_time::to_tm(now); + + char s[32]; + sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + date.assign(s); + + // TODO milliseconds + sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0); + time.assign(s); + } +#endif +} diff -r 0b9034112fde -r da2cf3ace87a Framework/Orthanc/Core/SystemToolbox.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Orthanc/Core/SystemToolbox.h Wed Nov 09 17:20:44 2016 +0100 @@ -0,0 +1,100 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#if !defined(ORTHANC_SANDBOXED) +# error The macro ORTHANC_SANDBOXED must be defined +#endif + +#if ORTHANC_SANDBOXED == 1 +# error The namespace SystemToolbox cannot be used in sandboxed environments +#endif + +#include "Enumerations.h" + +#include +#include +#include + +namespace Orthanc +{ + namespace SystemToolbox + { + ServerBarrierEvent ServerBarrier(const bool& stopFlag); + + ServerBarrierEvent ServerBarrier(); + + void ReadFile(std::string& content, + const std::string& path); + + bool ReadHeader(std::string& header, + const std::string& path, + size_t headerSize); + + void WriteFile(const void* content, + size_t size, + const std::string& path); + + void WriteFile(const std::string& content, + const std::string& path); + + void RemoveFile(const std::string& path); + + uint64_t GetFileSize(const std::string& path); + + void MakeDirectory(const std::string& path); + + bool IsExistingFile(const std::string& path); + + std::string GetPathToExecutable(); + + std::string GetDirectoryOfExecutable(); + + void ExecuteSystemCommand(const std::string& command, + const std::vector& arguments); + + int GetProcessId(); + + bool IsRegularFile(const std::string& path); + + FILE* OpenFile(const std::string& path, + FileMode mode); + +#if BOOST_HAS_DATE_TIME == 1 + std::string GetNowIsoString(); + + void GetNowDicom(std::string& date, + std::string& time); +#endif + } +} diff -r 0b9034112fde -r da2cf3ace87a Framework/Orthanc/Core/Toolbox.cpp --- a/Framework/Orthanc/Core/Toolbox.cpp Wed Nov 09 15:29:53 2016 +0100 +++ b/Framework/Orthanc/Core/Toolbox.cpp Wed Nov 09 17:20:44 2016 +0100 @@ -36,55 +36,29 @@ #include "OrthancException.h" #include "Logging.h" +#include +#include +#include +#include + #include #include #include -#include -#include -#include -#include #include #include -#if BOOST_HAS_DATE_TIME == 1 -#include -#endif - #if BOOST_HAS_REGEX == 1 -#include -#endif - -#if defined(_WIN32) -#include -#include // For "_spawnvp()" and "_getpid()" -#else -#include // For "execvp()" -#include // For "waitpid()" -#endif - -#if defined(__APPLE__) && defined(__MACH__) -#include /* _NSGetExecutablePath */ -#include /* PATH_MAX */ -#endif - -#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) -#include /* PATH_MAX */ -#include -#include +# include #endif #if BOOST_HAS_LOCALE != 1 -#error Since version 0.7.6, Orthanc entirely relies on boost::locale +# error Since version 0.7.6, Orthanc entirely relies on boost::locale #endif -#include - - #if ORTHANC_ENABLE_MD5 == 1 # include "../Resources/ThirdParty/md5/md5.h" #endif - #if ORTHANC_ENABLE_BASE64 == 1 # include "../Resources/ThirdParty/base64/base64.h" #endif @@ -103,9 +77,23 @@ #endif + +// Inclusions for UUID +// http://stackoverflow.com/a/1626302 + +extern "C" +{ +#ifdef WIN32 +# include +#else +# include +#endif +} + + #if ORTHANC_ENABLE_PUGIXML == 1 -#include "ChunkedBuffer.h" -#include +# include "ChunkedBuffer.h" +# include #endif @@ -123,75 +111,6 @@ } -#if ORTHANC_SANDBOXED == 0 - static bool finish_; - static ServerBarrierEvent barrierEvent_; - -#if defined(_WIN32) - static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType) - { - // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx - finish_ = true; - return true; - } -#else - static void SignalHandler(int signal) - { - if (signal == SIGHUP) - { - barrierEvent_ = ServerBarrierEvent_Reload; - } - - finish_ = true; - } -#endif - - - static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag) - { -#if defined(_WIN32) - SetConsoleCtrlHandler(ConsoleControlHandler, true); -#else - signal(SIGINT, SignalHandler); - signal(SIGQUIT, SignalHandler); - signal(SIGTERM, SignalHandler); - signal(SIGHUP, SignalHandler); -#endif - - // Active loop that awakens every 100ms - finish_ = false; - barrierEvent_ = ServerBarrierEvent_Stop; - while (!(*stopFlag || finish_)) - { - Toolbox::USleep(100 * 1000); - } - -#if defined(_WIN32) - SetConsoleCtrlHandler(ConsoleControlHandler, false); -#else - signal(SIGINT, NULL); - signal(SIGQUIT, NULL); - signal(SIGTERM, NULL); - signal(SIGHUP, NULL); -#endif - - return barrierEvent_; - } - - - ServerBarrierEvent Toolbox::ServerBarrier(const bool& stopFlag) - { - return ServerBarrierInternal(&stopFlag); - } - - ServerBarrierEvent Toolbox::ServerBarrier() - { - const bool stopFlag = false; - return ServerBarrierInternal(&stopFlag); - } -#endif /* ORTHANC_SANDBOXED */ - - void Toolbox::ToUpperCase(std::string& s) { std::transform(s.begin(), s.end(), s.begin(), toupper); @@ -219,149 +138,6 @@ } - static std::streamsize GetStreamSize(std::istream& f) - { - // http://www.cplusplus.com/reference/iostream/istream/tellg/ - f.seekg(0, std::ios::end); - std::streamsize size = f.tellg(); - f.seekg(0, std::ios::beg); - - return size; - } - - -#if ORTHANC_SANDBOXED == 0 - void Toolbox::ReadFile(std::string& content, - const std::string& path) - { - if (!IsRegularFile(path)) - { - LOG(ERROR) << std::string("The path does not point to a regular file: ") << path; - throw OrthancException(ErrorCode_RegularFileExpected); - } - - boost::filesystem::ifstream f; - f.open(path, std::ifstream::in | std::ifstream::binary); - if (!f.good()) - { - throw OrthancException(ErrorCode_InexistentFile); - } - - std::streamsize size = GetStreamSize(f); - content.resize(size); - if (size != 0) - { - f.read(reinterpret_cast(&content[0]), size); - } - - f.close(); - } -#endif - - -#if ORTHANC_SANDBOXED == 0 - bool Toolbox::ReadHeader(std::string& header, - const std::string& path, - size_t headerSize) - { - if (!IsRegularFile(path)) - { - LOG(ERROR) << std::string("The path does not point to a regular file: ") << path; - throw OrthancException(ErrorCode_RegularFileExpected); - } - - boost::filesystem::ifstream f; - f.open(path, std::ifstream::in | std::ifstream::binary); - if (!f.good()) - { - throw OrthancException(ErrorCode_InexistentFile); - } - - bool full = true; - - { - std::streamsize size = GetStreamSize(f); - if (size <= 0) - { - headerSize = 0; - full = false; - } - else if (static_cast(size) < headerSize) - { - headerSize = size; // Truncate to the size of the file - full = false; - } - } - - header.resize(headerSize); - if (headerSize != 0) - { - f.read(reinterpret_cast(&header[0]), headerSize); - } - - f.close(); - - return full; - } -#endif - - -#if ORTHANC_SANDBOXED == 0 - void Toolbox::WriteFile(const void* content, - size_t size, - const std::string& path) - { - boost::filesystem::ofstream f; - f.open(path, std::ofstream::out | std::ofstream::binary); - if (!f.good()) - { - throw OrthancException(ErrorCode_CannotWriteFile); - } - - if (size != 0) - { - f.write(reinterpret_cast(content), size); - - if (!f.good()) - { - f.close(); - throw OrthancException(ErrorCode_FileStorageCannotWrite); - } - } - - f.close(); - } -#endif - - -#if ORTHANC_SANDBOXED == 0 - void Toolbox::WriteFile(const std::string& content, - const std::string& path) - { - WriteFile(content.size() > 0 ? content.c_str() : NULL, - content.size(), path); - } -#endif - - -#if ORTHANC_SANDBOXED == 0 - void Toolbox::RemoveFile(const std::string& path) - { - if (boost::filesystem::exists(path)) - { - if (IsRegularFile(path)) - { - boost::filesystem::remove(path); - } - else - { - throw OrthancException(ErrorCode_RegularFileExpected); - } - } - } -#endif - - void Toolbox::SplitUriComponents(UriComponents& components, const std::string& uri) { @@ -529,22 +305,6 @@ } - -#if ORTHANC_SANDBOXED == 0 - uint64_t Toolbox::GetFileSize(const std::string& path) - { - try - { - return static_cast(boost::filesystem::file_size(path)); - } - catch (boost::filesystem::filesystem_error&) - { - throw OrthancException(ErrorCode_InexistentFile); - } - } -#endif - - #if ORTHANC_ENABLE_MD5 == 1 static char GetHexadecimalCharacter(uint8_t value) { @@ -661,65 +421,6 @@ #endif - -#if defined(_WIN32) - static std::string GetPathToExecutableInternal() - { - // Yes, this is ugly, but there is no simple way to get the - // required buffer size, so we use a big constant - std::vector buffer(32768); - /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast(buffer.size() - 1)); - return std::string(&buffer[0]); - } - -#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) - static std::string GetPathToExecutableInternal() - { - std::vector buffer(PATH_MAX + 1); - ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1); - if (bytes == 0) - { - throw OrthancException(ErrorCode_PathToExecutable); - } - - return std::string(&buffer[0]); - } - -#elif defined(__APPLE__) && defined(__MACH__) - static std::string GetPathToExecutableInternal() - { - char pathbuf[PATH_MAX + 1]; - unsigned int bufsize = static_cast(sizeof(pathbuf)); - - _NSGetExecutablePath( pathbuf, &bufsize); - - return std::string(pathbuf); - } - -#elif ORTHANC_SANDBOXED == 1 - // Sandboxed Orthanc, no access to the executable - -#else -#error Support your platform here -#endif - - -#if ORTHANC_SANDBOXED == 0 - std::string Toolbox::GetPathToExecutable() - { - boost::filesystem::path p(GetPathToExecutableInternal()); - return boost::filesystem::absolute(p).string(); - } - - - std::string Toolbox::GetDirectoryOfExecutable() - { - boost::filesystem::path p(GetPathToExecutableInternal()); - return boost::filesystem::absolute(p.parent_path()).string(); - } -#endif - - static const char* GetBoostLocaleEncoding(const Encoding sourceEncoding) { switch (sourceEncoding) @@ -997,30 +698,6 @@ } -#if BOOST_HAS_DATE_TIME == 1 - std::string Toolbox::GetNowIsoString() - { - boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); - return boost::posix_time::to_iso_string(now); - } - - void Toolbox::GetNowDicom(std::string& date, - std::string& time) - { - boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); - tm tm = boost::posix_time::to_tm(now); - - char s[32]; - sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); - date.assign(s); - - // TODO milliseconds - sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0); - time.assign(s); - } -#endif - - std::string Toolbox::StripSpaces(const std::string& source) { size_t first = 0; @@ -1178,35 +855,6 @@ } -#if ORTHANC_SANDBOXED == 0 - void Toolbox::MakeDirectory(const std::string& path) - { - if (boost::filesystem::exists(path)) - { - if (!boost::filesystem::is_directory(path)) - { - throw OrthancException(ErrorCode_DirectoryOverFile); - } - } - else - { - if (!boost::filesystem::create_directories(path)) - { - throw OrthancException(ErrorCode_MakeDirectory); - } - } - } -#endif - - -#if ORTHANC_SANDBOXED == 0 - bool Toolbox::IsExistingFile(const std::string& path) - { - return boost::filesystem::exists(path); - } -#endif - - #if ORTHANC_ENABLE_PUGIXML == 1 class ChunkedBufferWriter : public pugi::xml_writer { @@ -1329,66 +977,6 @@ #endif -#if ORTHANC_SANDBOXED == 0 - void Toolbox::ExecuteSystemCommand(const std::string& command, - const std::vector& arguments) - { - // Convert the arguments as a C array - std::vector args(arguments.size() + 2); - - args.front() = const_cast(command.c_str()); - - for (size_t i = 0; i < arguments.size(); i++) - { - args[i + 1] = const_cast(arguments[i].c_str()); - } - - args.back() = NULL; - - int status; - -#if defined(_WIN32) - // http://msdn.microsoft.com/en-us/library/275khfab.aspx - status = static_cast(_spawnvp(_P_OVERLAY, command.c_str(), &args[0])); - -#else - int pid = fork(); - - if (pid == -1) - { - // Error in fork() -#if ORTHANC_ENABLE_LOGGING == 1 - LOG(ERROR) << "Cannot fork a child process"; -#endif - - throw OrthancException(ErrorCode_SystemCommand); - } - else if (pid == 0) - { - // Execute the system command in the child process - execvp(command.c_str(), &args[0]); - - // We should never get here - _exit(1); - } - else - { - // Wait for the system command to exit - waitpid(pid, &status, 0); - } -#endif - - if (status != 0) - { -#if ORTHANC_ENABLE_LOGGING == 1 - LOG(ERROR) << "System command failed with status code " << status; -#endif - - throw OrthancException(ErrorCode_SystemCommand); - } - } -#endif - bool Toolbox::IsInteger(const std::string& str) { @@ -1496,68 +1084,6 @@ return str.compare(0, prefix.size(), prefix) == 0; } } - - -#if ORTHANC_SANDBOXED == 0 - int Toolbox::GetProcessId() - { -#if defined(_WIN32) - return static_cast(_getpid()); -#else - return static_cast(getpid()); -#endif - } -#endif - - -#if ORTHANC_SANDBOXED == 0 - bool Toolbox::IsRegularFile(const std::string& path) - { - namespace fs = boost::filesystem; - - try - { - if (fs::exists(path)) - { - fs::file_status status = fs::status(path); - return (status.type() == boost::filesystem::regular_file || - status.type() == boost::filesystem::reparse_file); // Fix BitBucket issue #11 - } - } - catch (fs::filesystem_error&) - { - } - - return false; - } -#endif - - - FILE* Toolbox::OpenFile(const std::string& path, - FileMode mode) - { -#if defined(_WIN32) - // TODO Deal with special characters by converting to the current locale -#endif - - const char* m; - switch (mode) - { - case FileMode_ReadBinary: - m = "rb"; - break; - - case FileMode_WriteBinary: - m = "wb"; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - return fopen(path.c_str(), m); - } - static bool IsUnreservedCharacter(char c) @@ -1698,4 +1224,73 @@ return static_cast(v); } } + + + std::string Toolbox::GenerateUuid() + { +#ifdef WIN32 + UUID uuid; + UuidCreate ( &uuid ); + + unsigned char * str; + UuidToStringA ( &uuid, &str ); + + std::string s( ( char* ) str ); + + RpcStringFreeA ( &str ); +#else + uuid_t uuid; + uuid_generate_random ( uuid ); + char s[37]; + uuid_unparse ( uuid, s ); +#endif + return s; + } + + + bool Toolbox::IsUuid(const std::string& str) + { + if (str.size() != 36) + { + return false; + } + + for (size_t i = 0; i < str.length(); i++) + { + if (i == 8 || i == 13 || i == 18 || i == 23) + { + if (str[i] != '-') + return false; + } + else + { + if (!isalnum(str[i])) + return false; + } + } + + return true; + } + + + bool Toolbox::StartsWithUuid(const std::string& str) + { + if (str.size() < 36) + { + return false; + } + + if (str.size() == 36) + { + return IsUuid(str); + } + + assert(str.size() > 36); + if (!isspace(str[36])) + { + return false; + } + + return IsUuid(str.substr(0, 36)); + } } diff -r 0b9034112fde -r da2cf3ace87a Framework/Orthanc/Core/Toolbox.h --- a/Framework/Orthanc/Core/Toolbox.h Wed Nov 09 15:29:53 2016 +0100 +++ b/Framework/Orthanc/Core/Toolbox.h Wed Nov 09 17:20:44 2016 +0100 @@ -56,9 +56,17 @@ # error The macro BOOST_HAS_REGEX must be defined #endif -#if !defined(ORTHANC_SANDBOXED) -# define ORTHANC_SANDBOXED 0 -#endif + +/** + * NOTE: GUID vs. UUID + * The simple answer is: no difference, they are the same thing. Treat + * them as a 16 byte (128 bits) value that is used as a unique + * value. In Microsoft-speak they are called GUIDs, but call them + * UUIDs when not using Microsoft-speak. + * http://stackoverflow.com/questions/246930/is-there-any-difference-between-a-guid-and-a-uuid + **/ + + namespace Orthanc { @@ -72,12 +80,6 @@ { void USleep(uint64_t microSeconds); -#if ORTHANC_SANDBOXED == 0 - ServerBarrierEvent ServerBarrier(const bool& stopFlag); - - ServerBarrierEvent ServerBarrier(); -#endif - void ToUpperCase(std::string& s); // Inplace version void ToLowerCase(std::string& s); // Inplace version @@ -88,24 +90,6 @@ void ToLowerCase(std::string& result, const std::string& source); -#if ORTHANC_SANDBOXED == 0 - void ReadFile(std::string& content, - const std::string& path); - - bool ReadHeader(std::string& header, - const std::string& path, - size_t headerSize); - - void WriteFile(const std::string& content, - const std::string& path); - - void WriteFile(const void* content, - size_t size, - const std::string& path); - - void RemoveFile(const std::string& path); -#endif - void SplitUriComponents(UriComponents& components, const std::string& uri); @@ -121,10 +105,6 @@ std::string FlattenUri(const UriComponents& components, size_t fromLevel = 0); -#if ORTHANC_SANDBOXED == 0 - uint64_t GetFileSize(const std::string& path); -#endif - #if ORTHANC_ENABLE_MD5 == 1 void ComputeMD5(std::string& result, const std::string& data); @@ -164,12 +144,6 @@ const std::string& content); #endif -#if ORTHANC_SANDBOXED == 0 - std::string GetPathToExecutable(); - - std::string GetDirectoryOfExecutable(); -#endif - std::string ConvertToUtf8(const std::string& source, Encoding sourceEncoding); @@ -183,13 +157,6 @@ std::string StripSpaces(const std::string& source); -#if BOOST_HAS_DATE_TIME == 1 - std::string GetNowIsoString(); - - void GetNowDicom(std::string& date, - std::string& time); -#endif - // In-place percent-decoding for URL void UrlDecode(std::string& s); @@ -203,12 +170,6 @@ const std::string& source, char separator); -#if ORTHANC_SANDBOXED == 0 - void MakeDirectory(const std::string& path); - - bool IsExistingFile(const std::string& path); -#endif - #if ORTHANC_ENABLE_PUGIXML == 1 void JsonToXml(std::string& target, const Json::Value& source, @@ -216,11 +177,6 @@ const std::string& arrayElement = "item"); #endif -#if ORTHANC_SANDBOXED == 0 - void ExecuteSystemCommand(const std::string& command, - const std::vector& arguments); -#endif - bool IsInteger(const std::string& str); void CopyJsonWithoutComments(Json::Value& target, @@ -229,15 +185,6 @@ bool StartsWith(const std::string& str, const std::string& prefix); -#if ORTHANC_SANDBOXED == 0 - int GetProcessId(); - - bool IsRegularFile(const std::string& path); -#endif - - FILE* OpenFile(const std::string& path, - FileMode mode); - void UriEncode(std::string& target, const std::string& source); @@ -256,5 +203,11 @@ unsigned int GetJsonUnsignedIntegerField(const ::Json::Value& json, const std::string& key, unsigned int defaultValue); + + std::string GenerateUuid(); + + bool IsUuid(const std::string& str); + + bool StartsWithUuid(const std::string& str); } } diff -r 0b9034112fde -r da2cf3ace87a Framework/Orthanc/Core/WebServiceParameters.cpp --- a/Framework/Orthanc/Core/WebServiceParameters.cpp Wed Nov 09 15:29:53 2016 +0100 +++ b/Framework/Orthanc/Core/WebServiceParameters.cpp Wed Nov 09 17:20:44 2016 +0100 @@ -37,6 +37,10 @@ #include "../Core/Toolbox.h" #include "../Core/OrthancException.h" +#if ORTHANC_SANDBOXED == 0 +# include "../Core/SystemToolbox.h" +#endif + #include namespace Orthanc @@ -57,6 +61,7 @@ } +#if ORTHANC_SANDBOXED == 0 void WebServiceParameters::SetClientCertificate(const std::string& certificateFile, const std::string& certificateKeyFile, const std::string& certificateKeyPassword) @@ -66,14 +71,14 @@ throw OrthancException(ErrorCode_ParameterOutOfRange); } - if (!Toolbox::IsRegularFile(certificateFile)) + if (!SystemToolbox::IsRegularFile(certificateFile)) { LOG(ERROR) << "Cannot open certificate file: " << certificateFile; throw OrthancException(ErrorCode_InexistentFile); } if (!certificateKeyFile.empty() && - !Toolbox::IsRegularFile(certificateKeyFile)) + !SystemToolbox::IsRegularFile(certificateKeyFile)) { LOG(ERROR) << "Cannot open key file: " << certificateKeyFile; throw OrthancException(ErrorCode_InexistentFile); @@ -84,6 +89,7 @@ certificateKeyFile_ = certificateKeyFile; certificateKeyPassword_ = certificateKeyPassword; } +#endif static void AddTrailingSlash(std::string& url) @@ -171,12 +177,14 @@ SetUsername(GetStringMember(peer, "Username", "")); SetPassword(GetStringMember(peer, "Password", "")); +#if ORTHANC_SANDBOXED == 0 if (peer.isMember("CertificateFile")) { SetClientCertificate(GetStringMember(peer, "CertificateFile", ""), GetStringMember(peer, "CertificateKeyFile", ""), GetStringMember(peer, "CertificateKeyPassword", "")); } +#endif if (peer.isMember("Pkcs11")) { diff -r 0b9034112fde -r da2cf3ace87a Framework/Orthanc/Core/WebServiceParameters.h --- a/Framework/Orthanc/Core/WebServiceParameters.h Wed Nov 09 15:29:53 2016 +0100 +++ b/Framework/Orthanc/Core/WebServiceParameters.h Wed Nov 09 17:20:44 2016 +0100 @@ -32,6 +32,10 @@ #pragma once +#if !defined(ORTHANC_SANDBOXED) +# error The macro ORTHANC_SANDBOXED must be defined +#endif + #include #include @@ -88,9 +92,11 @@ void ClearClientCertificate(); +#if ORTHANC_SANDBOXED == 0 void SetClientCertificate(const std::string& certificateFile, const std::string& certificateKeyFile, const std::string& certificateKeyPassword); +#endif const std::string& GetCertificateFile() const { diff -r 0b9034112fde -r da2cf3ace87a Framework/Orthanc/Resources/CMake/BoostConfiguration.cmake --- a/Framework/Orthanc/Resources/CMake/BoostConfiguration.cmake Wed Nov 09 15:29:53 2016 +0100 +++ b/Framework/Orthanc/Resources/CMake/BoostConfiguration.cmake Wed Nov 09 17:20:44 2016 +0100 @@ -125,10 +125,11 @@ add_definitions( -DBOOST_HAS_FILESYSTEM_V3=0 -D__INTEGRITY=1 - -DORTHANC_SANDBOXED=1 ) else() - add_definitions(-DBOOST_HAS_FILESYSTEM_V3=1) + add_definitions( + -DBOOST_HAS_FILESYSTEM_V3=1 + ) list(APPEND BOOST_SOURCES ${BOOST_FILESYSTEM_SOURCES_DIR}/codecvt_error_category.cpp ${BOOST_FILESYSTEM_SOURCES_DIR}/operations.cpp diff -r 0b9034112fde -r da2cf3ace87a Resources/CMake/OrthancStone.cmake --- a/Resources/CMake/OrthancStone.cmake Wed Nov 09 15:29:53 2016 +0100 +++ b/Resources/CMake/OrthancStone.cmake Wed Nov 09 17:20:44 2016 +0100 @@ -92,6 +92,7 @@ -DORTHANC_ENABLE_BASE64=1 -DORTHANC_ENABLE_PUGIXML=0 -DORTHANC_ENABLE_PKCS11=0 + -DORTHANC_SANDBOXED=0 ) @@ -186,6 +187,7 @@ ${ORTHANC_ROOT}/Core/Images/JpegReader.cpp ${ORTHANC_ROOT}/Core/Images/PngReader.cpp ${ORTHANC_ROOT}/Core/Logging.cpp + ${ORTHANC_ROOT}/Core/SystemToolbox.cpp ${ORTHANC_ROOT}/Core/Toolbox.cpp ${ORTHANC_ROOT}/Core/WebServiceParameters.cpp ${ORTHANC_ROOT}/Resources/ThirdParty/base64/base64.cpp diff -r 0b9034112fde -r da2cf3ace87a Resources/SyncOrthancFolder.py --- a/Resources/SyncOrthancFolder.py Wed Nov 09 15:29:53 2016 +0100 +++ b/Resources/SyncOrthancFolder.py Wed Nov 09 17:20:44 2016 +0100 @@ -44,6 +44,8 @@ 'Core/Logging.h', 'Core/OrthancException.h', 'Core/PrecompiledHeaders.h', + 'Core/SystemToolbox.cpp', + 'Core/SystemToolbox.h', 'Core/Toolbox.cpp', 'Core/Toolbox.h', 'Core/WebServiceParameters.cpp',