Mercurial > hg > orthanc
changeset 6304:36cd91a53403
merged utf8-branch -> default
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Tue, 09 Sep 2025 15:35:30 +0200 |
parents | 88b7494557f2 (current diff) a933e08efd7f (diff) |
children | e6755569b9d2 |
files | NEWS OrthancFramework/Sources/HttpServer/HttpServer.cpp |
diffstat | 50 files changed, 495 insertions(+), 252 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Tue Sep 09 14:26:51 2025 +0200 +++ b/NEWS Tue Sep 09 15:35:30 2025 +0200 @@ -10,7 +10,12 @@ was not able to send a full buffer over the network, Orthanc was not retrying to send the remaining part. This is now fixed. (https://discourse.orthanc-server.org/t/incomplete-zip-downloads-from-get-studies-id-media/6046) - +* Reworked all the paths handling, improving general support of non ASCII-only paths on Windows, + specifically for the Storage directories and for the configuration files. + However, on Windows, some features might still not support non ASCII-only paths: + - Reading a DCMTK dictionary ("ExternalDictionaries" configuration) + - Using a "TemporaryDirectory" to save zip file or to export DICOMDIR + - The "SslCertificate" and other related configurations Version 1.12.9 (2025-08-11)
--- a/OrthancFramework/Sources/Compression/HierarchicalZipWriter.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/Compression/HierarchicalZipWriter.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -149,7 +149,7 @@ } - HierarchicalZipWriter::HierarchicalZipWriter(const char* path) + HierarchicalZipWriter::HierarchicalZipWriter(const boost::filesystem::path& path) { writer_.SetOutputPath(path); writer_.Open();
--- a/OrthancFramework/Sources/Compression/HierarchicalZipWriter.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/Compression/HierarchicalZipWriter.h Tue Sep 09 15:35:30 2025 +0200 @@ -29,6 +29,7 @@ #include <map> #include <list> #include <boost/lexical_cast.hpp> +#include <boost/filesystem.hpp> #if ORTHANC_BUILD_UNIT_TESTS == 1 # include <gtest/gtest_prod.h> @@ -83,7 +84,7 @@ ZipWriter writer_; public: - explicit HierarchicalZipWriter(const char* path); + explicit HierarchicalZipWriter(const boost::filesystem::path& path); HierarchicalZipWriter(ZipWriter::IOutputStream* stream, // transfers ownership bool isZip64);
--- a/OrthancFramework/Sources/Compression/ZipReader.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/Compression/ZipReader.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -248,7 +248,7 @@ #if ORTHANC_SANDBOXED != 1 - bool ZipReader::IsZipFile(const std::string& path) + bool ZipReader::IsZipFile(const boost::filesystem::path& path) { std::string content; SystemToolbox::ReadFileRange(content, path, 0, 4, @@ -409,20 +409,20 @@ #if ORTHANC_SANDBOXED != 1 - ZipReader* ZipReader::CreateFromFile(const std::string& path) + ZipReader* ZipReader::CreateFromFile(const boost::filesystem::path& path) { if (!IsZipFile(path)) { - throw OrthancException(ErrorCode_BadFileFormat, "The file doesn't contain a ZIP archive: " + path); + throw OrthancException(ErrorCode_BadFileFormat, "The file doesn't contain a ZIP archive: " + SystemToolbox::PathToUtf8(path)); } else { std::unique_ptr<ZipReader> reader(new ZipReader); - reader->pimpl_->unzip_ = unzOpen64(path.c_str()); + reader->pimpl_->unzip_ = unzOpen64(SystemToolbox::PathToUtf8(path).c_str()); if (reader->pimpl_->unzip_ == NULL) { - throw OrthancException(ErrorCode_BadFileFormat, "Cannot open ZIP archive from file: " + path); + throw OrthancException(ErrorCode_BadFileFormat, "Cannot open ZIP archive from file: " + SystemToolbox::PathToUtf8(path)); } else {
--- a/OrthancFramework/Sources/Compression/ZipReader.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/Compression/ZipReader.h Tue Sep 09 15:35:30 2025 +0200 @@ -44,6 +44,9 @@ #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> +#if ORTHANC_SANDBOXED != 1 +# include <boost/filesystem.hpp> +#endif namespace Orthanc { @@ -73,7 +76,7 @@ static ZipReader* CreateFromMemory(const std::string& buffer); #if ORTHANC_SANDBOXED != 1 - static ZipReader* CreateFromFile(const std::string& path); + static ZipReader *CreateFromFile(const boost::filesystem::path& path); #endif static bool IsZipMemoryBuffer(const void* buffer, @@ -82,7 +85,7 @@ static bool IsZipMemoryBuffer(const std::string& content); #if ORTHANC_SANDBOXED != 1 - static bool IsZipFile(const std::string& path); + static bool IsZipFile(const boost::filesystem::path& path); #endif }; }
--- a/OrthancFramework/Sources/Compression/ZipWriter.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/Compression/ZipWriter.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -544,11 +544,11 @@ if (isZip64_) { - pimpl_->file_ = zipOpen64(path_.c_str(), mode); + pimpl_->file_ = zipOpen64(SystemToolbox::PathToUtf8(path_).c_str(), mode); } else { - pimpl_->file_ = zipOpen(path_.c_str(), mode); + pimpl_->file_ = zipOpen(SystemToolbox::PathToUtf8(path_).c_str(), mode); } if (!pimpl_->file_) @@ -559,13 +559,13 @@ } } - void ZipWriter::SetOutputPath(const char* path) + void ZipWriter::SetOutputPath(const boost::filesystem::path& path) { Close(); path_ = path; } - const std::string &ZipWriter::GetOutputPath() const + const boost::filesystem::path& ZipWriter::GetOutputPath() const { return path_; } @@ -603,7 +603,7 @@ return compressionLevel_; } - void ZipWriter::OpenFile(const char* path) + void ZipWriter::OpenFile(const char* filename) { Open(); @@ -614,7 +614,7 @@ if (isZip64_) { - result = zipOpenNewFileInZip64(pimpl_->file_, path, + result = zipOpenNewFileInZip64(pimpl_->file_, filename, &zfi, NULL, 0, NULL, 0, @@ -624,7 +624,7 @@ } else { - result = zipOpenNewFileInZip(pimpl_->file_, path, + result = zipOpenNewFileInZip(pimpl_->file_, filename, &zfi, NULL, 0, NULL, 0,
--- a/OrthancFramework/Sources/Compression/ZipWriter.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/Compression/ZipWriter.h Tue Sep 09 15:35:30 2025 +0200 @@ -46,6 +46,7 @@ #include <string> #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> +#include <boost/filesystem.hpp> namespace Orthanc { @@ -132,7 +133,7 @@ bool hasFileInZip_; bool append_; uint8_t compressionLevel_; - std::string path_; + boost::filesystem::path path_; std::unique_ptr<IOutputStream> outputStream_; @@ -159,11 +160,11 @@ bool IsOpen() const; - void SetOutputPath(const char* path); + void SetOutputPath(const boost::filesystem::path& path); - const std::string& GetOutputPath() const; + const boost::filesystem::path& GetOutputPath() const; - void OpenFile(const char* path); + void OpenFile(const char* filename); void Write(const void* data, size_t length);
--- a/OrthancFramework/Sources/DicomParsing/DicomDirWriter.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomDirWriter.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -135,7 +135,7 @@ { if (dir_.get() == NULL) { - dir_.reset(new DcmDicomDir(file_.GetPath().c_str(), + dir_.reset(new DcmDicomDir(SystemToolbox::PathToUtf8(file_.GetPath()).c_str(), fileSetId_.c_str())); //SetTagValue(dir_->getRootRecord(), DCM_SpecificCharacterSet, GetDicomSpecificCharacterSet(Encoding_Utf8)); }
--- a/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -46,6 +46,7 @@ #if ORTHANC_SANDBOXED == 0 # include "../TemporaryFile.h" +# include "../SystemToolbox.h" #endif #include <list> @@ -179,7 +180,7 @@ TemporaryFile tmp; tmp.Write(content); - if (!dictionary.loadDictionary(tmp.GetPath().c_str())) + if (!dictionary.loadDictionary(SystemToolbox::PathToUtf8(tmp.GetPath()).c_str())) { throw OrthancException(ErrorCode_InternalError, "Cannot read embedded dictionary. Under Windows, make sure that "
--- a/OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -72,7 +72,7 @@ return path; } - void FilesystemStorage::Setup(const std::string& root) + void FilesystemStorage::Setup(const boost::filesystem::path& root) { //root_ = boost::filesystem::absolute(root).string(); root_ = root; @@ -80,13 +80,13 @@ SystemToolbox::MakeDirectory(root); } - FilesystemStorage::FilesystemStorage(const std::string &root) : + FilesystemStorage::FilesystemStorage(const boost::filesystem::path &root) : fsyncOnWrite_(false) { Setup(root); } - FilesystemStorage::FilesystemStorage(const std::string &root, + FilesystemStorage::FilesystemStorage(const boost::filesystem::path &root, bool fsyncOnWrite) : fsyncOnWrite_(fsyncOnWrite) { @@ -171,7 +171,7 @@ try { - SystemToolbox::WriteFile(content, size, path.string(), fsyncOnWrite_); + SystemToolbox::WriteFile(content, size, path, fsyncOnWrite_); LOG(INFO) << "Created attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, size) << ")"; return; @@ -214,7 +214,7 @@ std::string content; SystemToolbox::ReadFileRange( - content, GetPath(uuid).string(), start, end, true /* throw if overflow */); + content, GetPath(uuid), start, end, true /* throw if overflow */); LOG(INFO) << "Read range of attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, content.size()) << ")"; return StringMemoryBuffer::CreateFromSwap(content);
--- a/OrthancFramework/Sources/FileStorage/FilesystemStorage.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/FileStorage/FilesystemStorage.h Tue Sep 09 15:35:30 2025 +0200 @@ -55,7 +55,7 @@ boost::filesystem::path GetPath(const std::string& uuid) const; - void Setup(const std::string& root); + void Setup(const boost::filesystem::path& root); #if ORTHANC_BUILDING_FRAMEWORK_LIBRARY == 1 // Alias for binary compatibility with Orthanc Framework 1.7.2 => don't use it anymore @@ -70,9 +70,9 @@ #endif public: - explicit FilesystemStorage(const std::string& root); + explicit FilesystemStorage(const boost::filesystem::path& root); - FilesystemStorage(const std::string& root, + FilesystemStorage(const boost::filesystem::path& root, bool fsyncOnWrite); virtual void Create(const std::string& uuid,
--- a/OrthancFramework/Sources/HttpClient.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/HttpClient.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -459,7 +459,7 @@ private: boost::mutex mutex_; bool httpsVerifyPeers_; - std::string httpsCACertificates_; + boost::filesystem::path httpsCACertificates_; std::string proxy_; long timeout_; bool verbose_; @@ -480,7 +480,7 @@ } void ConfigureSsl(bool httpsVerifyPeers, - const std::string& httpsCACertificates) + const boost::filesystem::path& httpsCACertificates) { boost::mutex::scoped_lock lock(mutex_); httpsVerifyPeers_ = httpsVerifyPeers; @@ -488,7 +488,7 @@ } void GetSslConfiguration(bool& httpsVerifyPeers, - std::string& httpsCACertificates) + boost::filesystem::path& httpsCACertificates) { boost::mutex::scoped_lock lock(mutex_); httpsVerifyPeers = httpsVerifyPeers_; @@ -1179,19 +1179,19 @@ return verifyPeers_; } - void HttpClient::SetHttpsCACertificates(const std::string &certificates) + void HttpClient::SetHttpsCACertificates(const boost::filesystem::path& certificates) { caCertificates_ = certificates; } - const std::string &HttpClient::GetHttpsCACertificates() const + const boost::filesystem::path& HttpClient::GetHttpsCACertificates() const { return caCertificates_; } void HttpClient::ConfigureSsl(bool httpsVerifyPeers, - const std::string& httpsVerifyCertificates) + const boost::filesystem::path& httpsVerifyCertificates) { #if ORTHANC_ENABLE_SSL == 1 if (httpsVerifyPeers) @@ -1337,8 +1337,8 @@ } - void HttpClient::SetClientCertificate(const std::string& certificateFile, - const std::string& certificateKeyFile, + void HttpClient::SetClientCertificate(const boost::filesystem::path& certificateFile, + const boost::filesystem::path &certificateKeyFile, const std::string& certificateKeyPassword) { if (certificateFile.empty()) @@ -1349,14 +1349,14 @@ if (!SystemToolbox::IsRegularFile(certificateFile)) { throw OrthancException(ErrorCode_InexistentFile, - "Cannot open certificate file: " + certificateFile); + "Cannot open certificate file: " + SystemToolbox::PathToUtf8(certificateFile)); } if (!certificateKeyFile.empty() && !SystemToolbox::IsRegularFile(certificateKeyFile)) { throw OrthancException(ErrorCode_InexistentFile, - "Cannot open key file: " + certificateKeyFile); + "Cannot open key file: " + SystemToolbox::PathToUtf8(certificateKeyFile)); } clientCertificateFile_ = certificateFile; @@ -1374,17 +1374,17 @@ return pkcs11Enabled_; } - const std::string &HttpClient::GetClientCertificateFile() const + const boost::filesystem::path& HttpClient::GetClientCertificateFile() const { return clientCertificateFile_; } - const std::string &HttpClient::GetClientCertificateKeyFile() const + const boost::filesystem::path& HttpClient::GetClientCertificateKeyFile() const { return clientCertificateKeyFile_; } - const std::string &HttpClient::GetClientCertificateKeyPassword() const + const std::string& HttpClient::GetClientCertificateKeyPassword() const { return clientCertificateKeyPassword_; }
--- a/OrthancFramework/Sources/HttpClient.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/HttpClient.h Tue Sep 09 15:35:30 2025 +0200 @@ -31,6 +31,7 @@ #include <string> #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> +#include <boost/filesystem.hpp> #include <json/value.h> #if !defined(ORTHANC_ENABLE_CURL) @@ -100,9 +101,9 @@ long timeout_; std::string proxy_; bool verifyPeers_; - std::string caCertificates_; - std::string clientCertificateFile_; - std::string clientCertificateKeyFile_; + boost::filesystem::path caCertificates_; + boost::filesystem::path clientCertificateFile_; + boost::filesystem::path clientCertificateKeyFile_; std::string clientCertificateKeyPassword_; bool pkcs11Enabled_; bool headersToLowerCase_; @@ -196,21 +197,21 @@ bool IsHttpsVerifyPeers() const; - void SetHttpsCACertificates(const std::string& certificates); + void SetHttpsCACertificates(const boost::filesystem::path& certificates); - const std::string& GetHttpsCACertificates() const; + const boost::filesystem::path& GetHttpsCACertificates() const; - void SetClientCertificate(const std::string& certificateFile, - const std::string& certificateKeyFile, + void SetClientCertificate(const boost::filesystem::path& certificateFile, + const boost::filesystem::path& certificateKeyFile, const std::string& certificateKeyPassword); void SetPkcs11Enabled(bool enabled); bool IsPkcs11Enabled() const; - const std::string& GetClientCertificateFile() const; + const boost::filesystem::path& GetClientCertificateFile() const; - const std::string& GetClientCertificateKeyFile() const; + const boost::filesystem::path& GetClientCertificateKeyFile() const; const std::string& GetClientCertificateKeyPassword() const; @@ -231,7 +232,7 @@ bool verbose); static void ConfigureSsl(bool httpsVerifyPeers, - const std::string& httpsCACertificates); + const boost::filesystem::path& httpsCACertificates); static void SetDefaultVerbose(bool verbose);
--- a/OrthancFramework/Sources/HttpServer/FilesystemHttpSender.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpSender.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -25,6 +25,7 @@ #include "FilesystemHttpSender.h" #include "../OrthancException.h" +#include "../SystemToolbox.h" static const size_t CHUNK_SIZE = 64 * 1024; // Use 64KB chunks @@ -33,7 +34,7 @@ void FilesystemHttpSender::Initialize(const boost::filesystem::path& path) { SetContentFilename(path.filename().string()); - file_.open(path.string().c_str(), std::ifstream::binary); + file_.open(SystemToolbox::PathToUtf8(path).c_str(), std::ifstream::binary); if (!file_.is_open()) { @@ -47,7 +48,7 @@ FilesystemHttpSender::FilesystemHttpSender(const std::string& path) { - Initialize(path); + Initialize(SystemToolbox::PathFromUtf8(path)); } FilesystemHttpSender::FilesystemHttpSender(const boost::filesystem::path& path) @@ -62,6 +63,13 @@ Initialize(path); } + FilesystemHttpSender::FilesystemHttpSender(const boost::filesystem::path& path, + MimeType contentType) + { + SetContentType(contentType); + Initialize(path); + } + FilesystemHttpSender::FilesystemHttpSender(const FilesystemStorage& storage, const std::string& uuid) {
--- a/OrthancFramework/Sources/HttpServer/FilesystemHttpSender.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpSender.h Tue Sep 09 15:35:30 2025 +0200 @@ -49,6 +49,9 @@ FilesystemHttpSender(const std::string& path, MimeType contentType); + FilesystemHttpSender(const boost::filesystem::path& path, + MimeType contentType); + FilesystemHttpSender(const FilesystemStorage& storage, const std::string& uuid);
--- a/OrthancFramework/Sources/HttpServer/HttpServer.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpServer.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -32,6 +32,7 @@ #include "../Logging.h" #include "../OrthancException.h" #include "../TemporaryFile.h" +#include "../SystemToolbox.h" #include "HttpToolbox.h" #include "IHttpHandler.h" #include "MultipartStreamReader.h" @@ -1575,7 +1576,7 @@ catch (boost::filesystem::filesystem_error& e) { throw OrthancException(ErrorCode_InternalError, - "Error while accessing the filesystem: " + e.path1().string()); + "Error while accessing the filesystem: " + SystemToolbox::PathToUtf8(e.path1())); } catch (std::runtime_error&) { @@ -1806,7 +1807,7 @@ { // Set the trusted client certificates (for X509 mutual authentication) options.push_back("ssl_ca_file"); - options.push_back(trustedClientCertificates_.c_str()); + options.push_back(SystemToolbox::PathToUtf8(trustedClientCertificates_).c_str()); } if (ssl_) @@ -1824,7 +1825,7 @@ // Set the SSL certificate, if any options.push_back("ssl_certificate"); - options.push_back(certificate_.c_str()); + options.push_back(SystemToolbox::PathToUtf8(certificate_).c_str()); }; assert(options.size() % 2 == 0); @@ -2067,7 +2068,7 @@ #endif } - const std::string &HttpServer::GetSslCertificate() const + const boost::filesystem::path& HttpServer::GetSslCertificate() const { return certificate_; } @@ -2084,7 +2085,7 @@ return ssl_; } - void HttpServer::SetSslCertificate(const char* path) + void HttpServer::SetSslCertificate(const boost::filesystem::path& path) { Stop(); certificate_ = path; @@ -2095,7 +2096,7 @@ return remoteAllowed_; } - void HttpServer::SetSslTrustedClientCertificates(const char* path) + void HttpServer::SetSslTrustedClientCertificates(const boost::filesystem::path &path) { Stop(); trustedClientCertificates_ = path;
--- a/OrthancFramework/Sources/HttpServer/HttpServer.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpServer.h Tue Sep 09 15:35:30 2025 +0200 @@ -57,6 +57,8 @@ #include <set> #include <stdint.h> #include <boost/shared_ptr.hpp> +#include <boost/filesystem.hpp> + namespace Orthanc { @@ -99,9 +101,9 @@ bool remoteAllowed_; bool authentication_; bool sslVerifyPeers_; - std::string trustedClientCertificates_; + boost::filesystem::path trustedClientCertificates_; bool ssl_; - std::string certificate_; + boost::filesystem::path certificate_; unsigned int sslMinimumVersion_; bool sslHasCiphers_; std::string sslCiphers_; @@ -160,7 +162,7 @@ void SetSslCiphers(const std::list<std::string>& ciphers); - void SetSslTrustedClientCertificates(const char* path); + void SetSslTrustedClientCertificates(const boost::filesystem::path& path); bool IsKeepAliveEnabled() const; @@ -170,9 +172,9 @@ void SetKeepAliveTimeout(unsigned int timeout); - const std::string& GetSslCertificate() const; + const boost::filesystem::path& GetSslCertificate() const; - void SetSslCertificate(const char* path); + void SetSslCertificate(const boost::filesystem::path& path); bool IsRemoteAccessAllowed() const;
--- a/OrthancFramework/Sources/Images/JpegReader.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/Images/JpegReader.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -94,7 +94,7 @@ #if ORTHANC_SANDBOXED == 0 - void JpegReader::ReadFromFile(const std::string& filename) + void JpegReader::ReadFromFile(const boost::filesystem::path& filename) { FILE* fp = SystemToolbox::OpenFile(filename, FileMode_ReadBinary); if (!fp)
--- a/OrthancFramework/Sources/Images/JpegReader.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/Images/JpegReader.h Tue Sep 09 15:35:30 2025 +0200 @@ -40,6 +40,11 @@ #include <string> +#if ORTHANC_SANDBOXED != 1 +#include <boost/filesystem.hpp> +#endif + + namespace Orthanc { class ORTHANC_PUBLIC JpegReader : public ImageAccessor @@ -49,7 +54,7 @@ public: #if ORTHANC_SANDBOXED == 0 - void ReadFromFile(const std::string& filename); + void ReadFromFile(const boost::filesystem::path& filename); #endif void ReadFromMemory(const void* buffer,
--- a/OrthancFramework/Sources/Images/PamReader.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/Images/PamReader.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -272,7 +272,7 @@ #if ORTHANC_SANDBOXED == 0 - void PamReader::ReadFromFile(const std::string& filename) + void PamReader::ReadFromFile(const boost::filesystem::path& filename) { SystemToolbox::ReadFile(content_, filename); ParseContent();
--- a/OrthancFramework/Sources/Images/PamReader.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/Images/PamReader.h Tue Sep 09 15:35:30 2025 +0200 @@ -26,6 +26,10 @@ #include "ImageAccessor.h" +#if ORTHANC_SANDBOXED != 1 +#include <boost/filesystem.hpp> +#endif + #if !defined(ORTHANC_SANDBOXED) # error The macro ORTHANC_SANDBOXED must be defined #endif @@ -72,7 +76,7 @@ virtual ~PamReader(); #if ORTHANC_SANDBOXED == 0 - void ReadFromFile(const std::string& filename); + void ReadFromFile(const boost::filesystem::path& filename); #endif void ReadFromMemory(const std::string& buffer);
--- a/OrthancFramework/Sources/Images/PngReader.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/Images/PngReader.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -44,7 +44,7 @@ { FILE* fp_; - explicit FileRabi(const char* filename) + explicit FileRabi(const boost::filesystem::path& filename) { fp_ = SystemToolbox::OpenFile(filename, FileMode_ReadBinary); if (!fp_) @@ -215,9 +215,9 @@ #if ORTHANC_SANDBOXED == 0 - void PngReader::ReadFromFile(const std::string& filename) + void PngReader::ReadFromFile(const boost::filesystem::path& filename) { - FileRabi f(filename.c_str()); + FileRabi f(filename); char header[8]; if (fread(header, 1, 8, f.fp_) != 8)
--- a/OrthancFramework/Sources/Images/PngReader.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/Images/PngReader.h Tue Sep 09 15:35:30 2025 +0200 @@ -44,6 +44,11 @@ # error The macro ORTHANC_SANDBOXED must be defined #endif +#if ORTHANC_SANDBOXED != 1 +#include <boost/filesystem.hpp> +#endif + + namespace Orthanc { class ORTHANC_PUBLIC PngReader : public ImageAccessor @@ -61,7 +66,7 @@ PngReader(); #if ORTHANC_SANDBOXED == 0 - void ReadFromFile(const std::string& filename); + void ReadFromFile(const boost::filesystem::path& filename); #endif void ReadFromMemory(const void* buffer,
--- a/OrthancFramework/Sources/SharedLibrary.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/SharedLibrary.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -27,6 +27,7 @@ #include "Logging.h" #include "OrthancException.h" +#include "SystemToolbox.h" #include <boost/filesystem.hpp> @@ -40,15 +41,15 @@ namespace Orthanc { - SharedLibrary::SharedLibrary(const std::string& path) : + SharedLibrary::SharedLibrary(const boost::filesystem::path& path) : path_(path), handle_(NULL) { #if defined(_WIN32) - handle_ = ::LoadLibraryA(path_.c_str()); + handle_ = ::LoadLibraryW(path_.wstring().c_str()); if (handle_ == NULL) { - LOG(ERROR) << "LoadLibrary(" << path_ << ") failed: Error " << ::GetLastError(); + LOG(ERROR) << "LoadLibrary(" << SystemToolbox::PathToUtf8(path_) << ") failed: Error " << ::GetLastError(); if (::GetLastError() == ERROR_BAD_EXE_FORMAT && sizeof(void*) == 4) @@ -120,7 +121,7 @@ } - const std::string &SharedLibrary::GetPath() const + const boost::filesystem::path& SharedLibrary::GetPath() const { return path_; }
--- a/OrthancFramework/Sources/SharedLibrary.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/SharedLibrary.h Tue Sep 09 15:35:30 2025 +0200 @@ -40,6 +40,7 @@ #include <string> #include <boost/noncopyable.hpp> +#include <boost/filesystem.hpp> namespace Orthanc { @@ -53,17 +54,17 @@ #endif private: - std::string path_; + boost::filesystem::path path_; void *handle_; FunctionPointer GetFunctionInternal(const std::string& name); public: - explicit SharedLibrary(const std::string& path); + explicit SharedLibrary(const boost::filesystem::path& path); ~SharedLibrary(); - const std::string& GetPath() const; + const boost::filesystem::path& GetPath() const; bool HasFunction(const std::string& name);
--- a/OrthancFramework/Sources/SystemToolbox.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/SystemToolbox.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -222,24 +222,23 @@ void SystemToolbox::ReadFile(std::string& content, - const std::string& path, + const boost::filesystem::path& path, bool log) { if (!IsRegularFile(path)) { throw OrthancException(ErrorCode_RegularFileExpected, - "The path does not point to a regular file: " + path, + "The path does not point to a regular file: " + PathToUtf8(path), log); } try { boost::filesystem::ifstream f; - f.open(PathFromUtf8(path), std::ifstream::in | std::ifstream::binary); + f.open(path, std::ifstream::in | std::ifstream::binary); if (!f.good()) { - throw OrthancException(ErrorCode_InexistentFile, - "File not found: " + path, + throw OrthancException(ErrorCode_InexistentFile, "File not found: " + PathToUtf8(path), log); } @@ -269,27 +268,51 @@ } } + void SystemToolbox::ReadFile(std::string &content, + const std::string& path, + bool log) + { + ReadFile(content, PathFromUtf8(path), log); + } - void SystemToolbox::ReadFile(std::string &content, const std::string &path) - { + void SystemToolbox::ReadFile(std::string& content, const boost::filesystem::path& path) + { ReadFile(content, path, true /* log */); } + void SystemToolbox::ReadFile(std::string &content, const std::string &path) + { + ReadFile(content, PathFromUtf8(path), true /* log */); + } + + void SystemToolbox::ReadFile(std::string &content, const char* path) + { + ReadFile(content, std::string(path)); + } + + bool SystemToolbox::ReadHeader(std::string& header, + const std::string& path, + size_t headerSize) + { + return ReadHeader(header, PathFromUtf8(path), headerSize); + } + + bool SystemToolbox::ReadHeader(std::string& header, - const std::string& path, + const boost::filesystem::path& path, size_t headerSize) { if (!IsRegularFile(path)) { throw OrthancException(ErrorCode_RegularFileExpected, - "The path does not point to a regular file: " + path); + "The path does not point to a regular file: " + PathToUtf8(path)); } try { boost::filesystem::ifstream f; - f.open(PathFromUtf8(path), std::ifstream::in | std::ifstream::binary); + f.open(path, std::ifstream::in | std::ifstream::binary); if (!f.good()) { throw OrthancException(ErrorCode_InexistentFile); @@ -423,12 +446,27 @@ content.size(), path, callFsync); } + void SystemToolbox::WriteFile(const std::string &content, + const boost::filesystem::path& path, + bool callFsync) + { + WriteFile(content.size() > 0 ? content.c_str() : NULL, + content.size(), path, callFsync); + } void SystemToolbox::WriteFile(const std::string &content, const std::string &path) { WriteFile(content, path, false /* don't automatically call fsync */); } + + void SystemToolbox::WriteFile(const std::string &content, + const boost::filesystem::path& path) + { + WriteFile(content.size() > 0 ? content.c_str() : NULL, + content.size(), path, false /* don't automatically call fsync */); + } + void SystemToolbox::RemoveFile(const std::string& path) { @@ -537,6 +575,11 @@ void SystemToolbox::MakeDirectory(const std::string& path) { + MakeDirectory(PathFromUtf8(path)); + } + + void SystemToolbox::MakeDirectory(const boost::filesystem::path& path) + { if (boost::filesystem::exists(path)) { if (!boost::filesystem::is_directory(path)) @@ -633,7 +676,7 @@ #ifdef _WIN32 - std::wstring Utf8ToWString(const std::string &str) + std::wstring SystemToolbox::Utf8ToWString(const std::string &str) { if (str.empty()) { @@ -648,7 +691,7 @@ return wstr; } - std::string WStringToUtf8(const std::wstring &wstr) + std::string SystemToolbox::WStringToUtf8(const std::wstring &wstr) { if (wstr.empty()) { @@ -663,12 +706,27 @@ return str; } + std::wstring SystemToolbox::WStringFromCharPtr(const char *str) + { + if (str == NULL) + { + return std::wstring(); + } + + int sizeNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + + std::wstring wstr(sizeNeeded, 0); + MultiByteToWideChar(CP_UTF8, 0, str, -1, &wstr[0], sizeNeeded); + + return wstr; + + } #endif boost::filesystem::path SystemToolbox::PathFromUtf8(const std::string &utf8) { -#ifdef _WIN32 - return boost::filesystem::path(Utf8ToWString(utf8)); +#if defined(_WIN32) && !defined(__MINGW32__) // non-ASCII paths are not supported when building with MinGW +return boost::filesystem::path(Utf8ToWString(utf8)); #else return boost::filesystem::path(utf8); // POSIX: std::string is UTF-8 #endif @@ -676,7 +734,7 @@ std::string SystemToolbox::PathToUtf8(const boost::filesystem::path &p) { -#ifdef _WIN32 +#if defined(_WIN32) && !defined(__MINGW32__) // non-ASCII paths are not supported when building with MinGW return WStringToUtf8(p.wstring()); #else return p.string(); // POSIX: already UTF-8 @@ -785,14 +843,34 @@ } - FILE* SystemToolbox::OpenFile(const std::string& path, + FILE *SystemToolbox::OpenFile(const std::string &path, + FileMode mode) + { + return OpenFile(PathFromUtf8(path), mode); + } + + FILE* SystemToolbox::OpenFile(const boost::filesystem::path& path, FileMode mode) { #if defined(_WIN32) - // TODO Deal with special characters by converting to the current locale -#endif + const wchar_t *m; + switch (mode) + { + case FileMode_ReadBinary: + m = L"rb"; + break; - const char* m; + case FileMode_WriteBinary: + m = L"wb"; + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + return _wfopen(path.wstring().c_str(), m); +#else + const char *m; switch (mode) { case FileMode_ReadBinary: @@ -808,6 +886,7 @@ } return fopen(path.c_str(), m); +#endif } @@ -1056,16 +1135,15 @@ } - std::string SystemToolbox::InterpretRelativePath(const std::string& baseDirectory, - const std::string& relativePath) + boost::filesystem::path SystemToolbox::InterpretRelativePath(const boost::filesystem::path& baseDirectory, + const std::string& relativePath) { - boost::filesystem::path base(baseDirectory); - boost::filesystem::path relative(relativePath); + boost::filesystem::path relative = SystemToolbox::PathFromUtf8(relativePath); /** The following lines should be equivalent to this one: - return (base / relative).string(); + return (base / relative); However, for some unknown reason, some versions of Boost do not make the proper path resolution when "baseDirectory" is an @@ -1074,17 +1152,27 @@ if (relative.is_absolute()) { - return relative.string(); + return relative; } else { - return (base / relative).string(); + return baseDirectory / relative; } } + void SystemToolbox::ReadFileRange(std::string &content, + const std::string &path, + uint64_t start, // Inclusive + uint64_t end, // Exclusive + bool throwIfOverflow) + { + ReadFileRange(content, SystemToolbox::PathFromUtf8(path), start, end, throwIfOverflow); + } + + void SystemToolbox::ReadFileRange(std::string& content, - const std::string& path, + const boost::filesystem::path& path, uint64_t start, // Inclusive uint64_t end, // Exclusive bool throwIfOverflow) @@ -1097,15 +1185,15 @@ if (!IsRegularFile(path)) { throw OrthancException(ErrorCode_RegularFileExpected, - "The path does not point to a regular file: " + path); + "The path does not point to a regular file: " + SystemToolbox::PathToUtf8(path)); } boost::filesystem::ifstream f; - f.open(PathFromUtf8(path), std::ifstream::in | std::ifstream::binary); + f.open(path, std::ifstream::in | std::ifstream::binary); if (!f.good()) { - throw OrthancException(ErrorCode_InexistentFile, - "File not found: " + path); + throw OrthancException(ErrorCode_InexistentFile, + "File not found: " + SystemToolbox::PathToUtf8(path)); } uint64_t fileSize = static_cast<uint64_t>(GetStreamSize(f));
--- a/OrthancFramework/Sources/SystemToolbox.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/SystemToolbox.h Tue Sep 09 15:35:30 2025 +0200 @@ -60,14 +60,28 @@ static void ReadFile(std::string& content, const std::string& path, bool log); + + static void ReadFile(std::string &content, + const boost::filesystem::path& path, + bool log); + + static void ReadFile(std::string &content, + const char* path); static void ReadFile(std::string& content, const std::string& path); + static void ReadFile(std::string &content, + const boost::filesystem::path& path); + static bool ReadHeader(std::string& header, const std::string& path, size_t headerSize); + static bool ReadHeader(std::string &header, + const boost::filesystem::path& path, + size_t headerSize); + static void WriteFile(const void* content, size_t size, const std::string& path, @@ -89,6 +103,13 @@ static void WriteFile(const std::string& content, const std::string& path); + static void WriteFile(const std::string &content, + const boost::filesystem::path& path); + + static void WriteFile(const std::string &content, + const boost::filesystem::path& path, + bool callFsync); + static void RemoveFile(const std::string& path); static uint64_t GetFileSize(const std::string& path); @@ -115,6 +136,8 @@ static void MakeDirectory(const std::string& path); + static void MakeDirectory(const boost::filesystem::path& path); + static bool IsExistingFile(const std::string& path); static std::string GetPathToExecutable(); @@ -133,6 +156,9 @@ static FILE* OpenFile(const std::string& path, FileMode mode); + static FILE* OpenFile(const boost::filesystem::path& path, + FileMode mode); + static MimeType AutodetectMimeType(const char* path) // used only in Unit Tests { return AutodetectMimeType(std::string(path)); @@ -160,8 +186,8 @@ static void GetEnvironmentVariables(std::map<std::string, std::string>& env); - static std::string InterpretRelativePath(const std::string& baseDirectory, - const std::string& relativePath); + static boost::filesystem::path InterpretRelativePath(const boost::filesystem::path& baseDirectory, + const std::string& relativePath); static void ReadFileRange(std::string& content, const std::string& path, @@ -169,6 +195,21 @@ uint64_t end, // Exclusive bool throwIfOverflow); + static void ReadFileRange(std::string &content, + const boost::filesystem::path& path, + uint64_t start, // Inclusive + uint64_t end, // Exclusive + bool throwIfOverflow); + static void GetMacAddresses(std::set<std::string>& target); + +#ifdef _WIN32 + static std::wstring Utf8ToWString(const std::string &str); + + static std::string WStringToUtf8(const std::wstring &wstr); + + static std::wstring WStringFromCharPtr(const char *wstr); +#endif + }; }
--- a/OrthancFramework/Sources/TemporaryFile.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/TemporaryFile.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -34,12 +34,12 @@ namespace Orthanc { - static std::string CreateTemporaryPath(const char* temporaryDirectory, - const char* extension) + static boost::filesystem::path CreateTemporaryPath(const boost::filesystem::path& temporaryDirectory, + const char* extension) { boost::filesystem::path dir; - if (temporaryDirectory == NULL) + if (temporaryDirectory.empty()) { #if BOOST_HAS_FILESYSTEM_V3 == 1 dir = boost::filesystem::temp_directory_path(); @@ -69,19 +69,19 @@ } dir /= filename; - return dir.string(); + return dir; } TemporaryFile::TemporaryFile() : - path_(CreateTemporaryPath(NULL, NULL)) + path_(CreateTemporaryPath("", NULL)) { } - TemporaryFile::TemporaryFile(const std::string& temporaryDirectory, + TemporaryFile::TemporaryFile(const boost::filesystem::path& temporaryDirectory, const std::string& extension) : - path_(CreateTemporaryPath(temporaryDirectory.c_str(), extension.c_str())) + path_(CreateTemporaryPath(temporaryDirectory, extension.c_str())) { } @@ -91,7 +91,7 @@ boost::filesystem::remove(path_); } - const std::string &TemporaryFile::GetPath() const + const boost::filesystem::path& TemporaryFile::GetPath() const { return path_; } @@ -106,7 +106,7 @@ catch (OrthancException& e) { throw OrthancException(e.GetErrorCode(), - "Can't create temporary file \"" + path_ + + "Can't create temporary file \"" + SystemToolbox::PathToUtf8(path_) + "\" with " + boost::lexical_cast<std::string>(content.size()) + " bytes: Check you have write access to the " "temporary directory and that it is not full"); @@ -122,8 +122,8 @@ } catch (OrthancException& e) { - throw OrthancException(e.GetErrorCode(), - "Can't read temporary file \"" + path_ + + throw OrthancException(e.GetErrorCode(), + "Can't read temporary file \"" + SystemToolbox::PathToUtf8(path_) + "\": Another process has corrupted the temporary directory"); } }
--- a/OrthancFramework/Sources/TemporaryFile.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/Sources/TemporaryFile.h Tue Sep 09 15:35:30 2025 +0200 @@ -35,6 +35,7 @@ #endif #include <boost/noncopyable.hpp> +#include <boost/filesystem.hpp> #include <stdint.h> #include <string> @@ -43,17 +44,17 @@ class ORTHANC_PUBLIC TemporaryFile : public boost::noncopyable { private: - std::string path_; + boost::filesystem::path path_; public: TemporaryFile(); - TemporaryFile(const std::string& temporaryFolder, + TemporaryFile(const boost::filesystem::path& temporaryFolder, const std::string& extension); ~TemporaryFile(); - const std::string& GetPath() const; + const boost::filesystem::path& GetPath() const; void Write(const std::string& content);
--- a/OrthancFramework/UnitTestsSources/FileStorageTests.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/UnitTestsSources/FileStorageTests.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -108,7 +108,7 @@ std::vector<uint8_t> data; StringToVector(data, Toolbox::GenerateUuid()); - SystemToolbox::WriteFile("toto", "UnitTestsStorageTop/12"); + SystemToolbox::WriteFile("toto", SystemToolbox::PathFromUtf8("UnitTestsStorageTop/12")); ASSERT_THROW(s.Create("12345678-1234-1234-1234-1234567890ab", &data[0], data.size(), FileContentType_Unknown), OrthancException); s.Clear(); } @@ -121,8 +121,8 @@ std::vector<uint8_t> data; StringToVector(data, Toolbox::GenerateUuid()); - SystemToolbox::MakeDirectory("UnitTestsStorageChild/12"); - SystemToolbox::WriteFile("toto", "UnitTestsStorageChild/12/34"); + SystemToolbox::MakeDirectory(SystemToolbox::PathFromUtf8("UnitTestsStorageChild/12")); + SystemToolbox::WriteFile("toto", SystemToolbox::PathFromUtf8("UnitTestsStorageChild/12/34")); ASSERT_THROW(s.Create("12345678-1234-1234-1234-1234567890ab", &data[0], data.size(), FileContentType_Unknown), OrthancException); s.Clear(); } @@ -135,12 +135,27 @@ std::vector<uint8_t> data; StringToVector(data, Toolbox::GenerateUuid()); - SystemToolbox::MakeDirectory("UnitTestsStorageFileAlreadyExists/12/34"); - SystemToolbox::WriteFile("toto", "UnitTestsStorageFileAlreadyExists/12/34/12345678-1234-1234-1234-1234567890ab"); + SystemToolbox::MakeDirectory(SystemToolbox::PathFromUtf8("UnitTestsStorageFileAlreadyExists/12/34")); + SystemToolbox::WriteFile("toto", SystemToolbox::PathFromUtf8("UnitTestsStorageFileAlreadyExists/12/34/12345678-1234-1234-1234-1234567890ab")); ASSERT_THROW(s.Create("12345678-1234-1234-1234-1234567890ab", &data[0], data.size(), FileContentType_Unknown), OrthancException); s.Clear(); } +#if !defined(__MINGW32__) // non-ASCII paths are not supported when built with mingw +TEST(FilesystemStorage, FileAlreadyExistsUtf8) +{ + FilesystemStorage s(SystemToolbox::PathFromUtf8("\xd0\x95UnitTestsStorageFileAlreadyExists")); + s.Clear(); + + std::vector<uint8_t> data; + StringToVector(data, Toolbox::GenerateUuid()); + + SystemToolbox::MakeDirectory(SystemToolbox::PathFromUtf8("\xd0\x95UnitTestsStorageFileAlreadyExists/12/34")); + SystemToolbox::WriteFile("toto", SystemToolbox::PathFromUtf8("\xd0\x95UnitTestsStorageFileAlreadyExists/12/34/12345678-1234-1234-1234-1234567890ab")); + ASSERT_THROW(s.Create("12345678-1234-1234-1234-1234567890ab", &data[0], data.size(), FileContentType_Unknown), OrthancException); + s.Clear(); +} +#endif TEST(FilesystemStorage, EndToEnd) {
--- a/OrthancFramework/UnitTestsSources/FrameworkTests.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/UnitTestsSources/FrameworkTests.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -642,8 +642,8 @@ #if defined(__linux__) TEST(Toolbox, AbsoluteDirectory) { - ASSERT_EQ("/tmp/hello", SystemToolbox::InterpretRelativePath("/tmp", "hello")); - ASSERT_EQ("/tmp", SystemToolbox::InterpretRelativePath("/tmp", "/tmp")); + ASSERT_EQ("/tmp/hello", SystemToolbox::PathToUtf8(SystemToolbox::InterpretRelativePath("/tmp", "hello"))); + ASSERT_EQ("/tmp", SystemToolbox::PathToUtf8(SystemToolbox::InterpretRelativePath("/tmp", "/tmp"))); } #endif @@ -651,7 +651,7 @@ #if ORTHANC_SANDBOXED != 1 TEST(Toolbox, WriteFile) { - std::string path; + boost::filesystem::path path; { TemporaryFile tmp; @@ -663,28 +663,28 @@ s.append("World"); ASSERT_EQ(11u, s.size()); - SystemToolbox::WriteFile(s, path.c_str()); + SystemToolbox::WriteFile(s, path); std::string t; - SystemToolbox::ReadFile(t, path.c_str()); + SystemToolbox::ReadFile(t, path); ASSERT_EQ(11u, t.size()); ASSERT_EQ(0, t[5]); ASSERT_EQ(0, memcmp(s.c_str(), t.c_str(), s.size())); std::string h; - ASSERT_EQ(true, SystemToolbox::ReadHeader(h, path.c_str(), 1)); + ASSERT_EQ(true, SystemToolbox::ReadHeader(h, path, 1)); ASSERT_EQ(1u, h.size()); ASSERT_EQ('H', h[0]); - ASSERT_TRUE(SystemToolbox::ReadHeader(h, path.c_str(), 0)); + ASSERT_TRUE(SystemToolbox::ReadHeader(h, path, 0)); ASSERT_EQ(0u, h.size()); - ASSERT_FALSE(SystemToolbox::ReadHeader(h, path.c_str(), 32)); + ASSERT_FALSE(SystemToolbox::ReadHeader(h, path, 32)); ASSERT_EQ(11u, h.size()); ASSERT_EQ(0, memcmp(s.c_str(), h.c_str(), s.size())); } std::string u; - ASSERT_THROW(SystemToolbox::ReadFile(u, path.c_str()), OrthancException); + ASSERT_THROW(SystemToolbox::ReadFile(u, path), OrthancException); { TemporaryFile tmp;
--- a/OrthancFramework/UnitTestsSources/ImageTests.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/UnitTestsSources/ImageTests.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -310,7 +310,7 @@ #if ORTHANC_SANDBOXED != 1 Orthanc::IImageWriter::WriteToFile(w, "UnitTestsResults/hello.jpg", img); - Orthanc::SystemToolbox::WriteFile(s, "UnitTestsResults/hello2.jpg"); + Orthanc::SystemToolbox::WriteFile(s, Orthanc::SystemToolbox::PathFromUtf8("UnitTestsResults/hello2.jpg")); std::string t; Orthanc::SystemToolbox::ReadFile(t, "UnitTestsResults/hello.jpg"); @@ -327,7 +327,7 @@ #if ORTHANC_SANDBOXED != 1 Orthanc::JpegReader r2; - r2.ReadFromFile("UnitTestsResults/hello.jpg"); + r2.ReadFromFile(Orthanc::SystemToolbox::PathFromUtf8("UnitTestsResults/hello.jpg")); ASSERT_EQ(16u, r2.GetWidth()); ASSERT_EQ(16u, r2.GetHeight()); #endif
--- a/OrthancFramework/UnitTestsSources/RestApiTests.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/UnitTestsSources/RestApiTests.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -117,7 +117,7 @@ TEST(HttpClient, Ssl) { - SystemToolbox::WriteFile(GITHUB_CERTIFICATES, "UnitTestsResults/github.cert"); + SystemToolbox::WriteFile(GITHUB_CERTIFICATES, SystemToolbox::PathFromUtf8("UnitTestsResults/github.cert")); /*{ std::string s;
--- a/OrthancFramework/UnitTestsSources/ZipTests.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancFramework/UnitTestsSources/ZipTests.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -194,7 +194,7 @@ Orthanc::ZipWriter w; ASSERT_EQ(0u, w.GetArchiveSize()); - w.SetOutputPath(f.GetPath().c_str()); + w.SetOutputPath(f.GetPath()); w.Open(); w.OpenFile("world/hello"); w.Write("Hello world"); @@ -207,7 +207,7 @@ std::unique_ptr<ZipReader> reader(ZipReader::CreateFromFile(f.GetPath())); ASSERT_EQ(1u, reader->GetFilesCount()); - + std::string filename, content; ASSERT_TRUE(reader->ReadNextFile(filename, content)); ASSERT_EQ("world/hello", filename);
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -1758,8 +1758,7 @@ boost::shared_mutex auditLogHandlersMutex_; // New in Orthanc 1.12.9 Properties properties_; - int argc_; - char** argv_; + std::vector<std::string> arguments_; std::unique_ptr<OrthancPluginDatabase> database_; std::unique_ptr<OrthancPluginDatabaseV3> databaseV3_; // New in Orthanc 1.9.2 std::unique_ptr<OrthancPluginDatabaseV4> databaseV4_; // New in Orthanc 1.12.0 @@ -1775,8 +1774,6 @@ worklistCallback_(NULL), receivedInstanceCallback_(NULL), httpAuthentication_(NULL), - argc_(1), - argv_(NULL), databaseServerIdentifier_(databaseServerIdentifier), maxDatabaseRetries_(0), hasStorageAreaCustomData_(false) @@ -5223,7 +5220,7 @@ *reinterpret_cast<const _OrthancPluginReadFile*>(parameters); std::string content; - SystemToolbox::ReadFile(content, p.path); + SystemToolbox::ReadFile(content, SystemToolbox::PathFromUtf8(p.path)); CopyToMemoryBuffer(p.target, content); return true; @@ -6084,7 +6081,7 @@ { const _OrthancPluginReturnSingleValue& p = *reinterpret_cast<const _OrthancPluginReturnSingleValue*>(parameters); - *(p.resultUint32) = pimpl_->argc_ - 1; + *(p.resultUint32) = static_cast<uint32_t>(pimpl_->arguments_.size()) - 1; return true; } @@ -6093,14 +6090,13 @@ const _OrthancPluginGlobalProperty& p = *reinterpret_cast<const _OrthancPluginGlobalProperty*>(parameters); - if (p.property + 1 > pimpl_->argc_) + if (p.property + 1 > static_cast<int32_t>(pimpl_->arguments_.size())) { return false; } else { - std::string arg = std::string(pimpl_->argv_[p.property + 1]); - *(p.result) = CopyString(arg); + *(p.result) = CopyString(pimpl_->arguments_[p.property + 1]); return true; } } @@ -6430,15 +6426,14 @@ } - void OrthancPlugins::SetCommandLineArguments(int argc, char* argv[]) - { - if (argc < 1 || argv == NULL) + void OrthancPlugins::SetCommandLineArguments(const std::vector<std::string>& arguments) + { + if (arguments.size() == 0) { throw OrthancException(ErrorCode_ParameterOutOfRange); } - pimpl_->argc_ = argc; - pimpl_->argv_ = argv; + pimpl_->arguments_ = arguments; }
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.h Tue Sep 09 15:35:30 2025 +0200 @@ -338,7 +338,7 @@ const char* GetProperty(const char* plugin, _OrthancPluginProperty property) const; - void SetCommandLineArguments(int argc, char* argv[]); + void SetCommandLineArguments(const std::vector<std::string>& arguments); PluginsManager& GetManager();
--- a/OrthancServer/Plugins/Engine/PluginsManager.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsManager.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -32,6 +32,7 @@ #include "../../../OrthancFramework/Sources/Logging.h" #include "../../../OrthancFramework/Sources/OrthancException.h" #include "../../../OrthancFramework/Sources/Toolbox.h" +#include "../../../OrthancFramework/Sources/SystemToolbox.h" #include <cassert> #include <memory> @@ -51,7 +52,7 @@ namespace Orthanc { PluginsManager::Plugin::Plugin(PluginsManager& pluginManager, - const std::string& path) : + const boost::filesystem::path& path) : library_(path), pluginManager_(pluginManager) { @@ -240,23 +241,22 @@ } - void PluginsManager::RegisterPlugin(const std::string& path) + void PluginsManager::RegisterPlugin(const boost::filesystem::path& path) { if (!boost::filesystem::exists(path)) { - boost::filesystem::path p(path); - std::string extension = p.extension().string(); + std::string extension = path.extension().string(); Toolbox::ToLowerCase(extension); if (extension == PLUGIN_EXTENSION) { // if this is a plugin path, fail to start - throw OrthancException(ErrorCode_SharedLibrary, "Inexistent path to plugin: " + path); + throw OrthancException(ErrorCode_SharedLibrary, "Inexistent path to plugin: " + SystemToolbox::PathToUtf8(path)); } else { // it might be a directory -> just log a warning - LOG(WARNING) << "Inexistent path to plugins: " << path; + LOG(WARNING) << "Inexistent path to plugins: " << SystemToolbox::PathToUtf8(path); return; } } @@ -293,7 +293,7 @@ } - void PluginsManager::ScanFolderForPlugins(const std::string& folder, + void PluginsManager::ScanFolderForPlugins(const boost::filesystem::path& folder, bool isRecursive) { using namespace boost::filesystem; @@ -303,14 +303,14 @@ return; } - CLOG(INFO, PLUGINS) << "Scanning folder " << folder << " for plugins"; + CLOG(INFO, PLUGINS) << "Scanning folder " << SystemToolbox::PathToUtf8(folder) << " for plugins"; directory_iterator end_it; // default construction yields past-the-end for (directory_iterator it(folder); it != end_it; ++it) { - std::string path = it->path().string(); + boost::filesystem::path path = it->path(); if (is_directory(it->status())) {
--- a/OrthancServer/Plugins/Engine/PluginsManager.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsManager.h Tue Sep 09 15:35:30 2025 +0200 @@ -29,6 +29,7 @@ #include <map> #include <list> +#include <boost/filesystem.hpp> namespace Orthanc { @@ -45,7 +46,7 @@ public: Plugin(PluginsManager& pluginManager, - const std::string& path); + const boost::filesystem::path& path); SharedLibrary& GetSharedLibrary() { @@ -87,9 +88,9 @@ ~PluginsManager(); - void RegisterPlugin(const std::string& path); + void RegisterPlugin(const boost::filesystem::path& path); - void ScanFolderForPlugins(const std::string& path, + void ScanFolderForPlugins(const boost::filesystem::path& path, bool isRecursive); void RegisterServiceProvider(IPluginServiceProvider& provider)
--- a/OrthancServer/Plugins/Samples/AdoptDicomInstance/Plugin.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Plugins/Samples/AdoptDicomInstance/Plugin.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -32,7 +32,7 @@ static boost::filesystem::path storageDirectory_; -static std::string GetStorageDirectoryPath(const char* uuid) +static boost::filesystem::path GetStorageDirectoryPath(const char* uuid) { if (uuid == NULL) { @@ -40,7 +40,7 @@ } else { - return (storageDirectory_ / std::string(uuid)).string(); + return (storageDirectory_ / std::string(uuid)); } }
--- a/OrthancServer/Resources/Samples/Tools/RecoverCompressedFile.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Resources/Samples/Tools/RecoverCompressedFile.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -27,12 +27,43 @@ #include <stdio.h> -int main(int argc, const char* argv[]) +#if defined(_WIN32) || defined(__CYGWIN__) +#include <windows.h> +#endif + + +#if defined(_WIN32) && !defined(__MINGW32__) +// arguments are passed as UTF-16 on Windows +int wmain(int argc, wchar_t *argv[]) { - if (argc != 2 && argc != 3) + // Set Windows console output to UTF-8 (otherwise, strings are considered to be in UTF-16. For example, Cyrillic UTF-8 strings appear as garbage without that config) + SetConsoleOutputCP(CP_UTF8); + + // Transform the UTF-16 arguments into UTF-8 arguments + std::vector<std::string> arguments; // UTF-8 arguments + + for (int i = 0; i < argc; i++) + { + std::wstring argument(argv[i]); + arguments.push_back(Orthanc::SystemToolbox::WStringToUtf8(argument)); + } + +#else +int main(int argc, char *argv[]) +{ + std::vector<std::string> arguments; // UTF-8 arguments + + // the arguments are assumed to be directly in UTF-8 + for (int i = 0; i < argc; i++) + { + arguments.push_back(argv[i]); + } +#endif + + if (arguments.size() != 2 && arguments.size() != 3) { fprintf(stderr, "Maintenance tool to recover a DICOM file that was compressed by Orthanc.\n\n"); - fprintf(stderr, "Usage: %s <input> [output]\n", argv[0]); + fprintf(stderr, "Usage: %s <input> [output]\n", Orthanc::SystemToolbox::PathToUtf8(arguments[0]).c_str()); fprintf(stderr, "If \"output\" is not given, the data will be output to stdout\n"); return -1; } @@ -43,7 +74,7 @@ fflush(stderr); std::string content; - Orthanc::SystemToolbox::ReadFile(content, argv[1]); + Orthanc::SystemToolbox::ReadFile(content, Orthanc::SystemToolbox::PathFromUtf8(arguments[1])); fprintf(stderr, "Decompressing the content of the file...\n"); fflush(stderr); @@ -59,7 +90,7 @@ if (argc == 3) { - Orthanc::SystemToolbox::WriteFile(uncompressed, argv[2]); + Orthanc::SystemToolbox::WriteFile(uncompressed, Orthanc::SystemToolbox::PathFromUtf8(arguments[2])); } else {
--- a/OrthancServer/Sources/LuaScripting.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Sources/LuaScripting.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -1096,8 +1096,8 @@ for (std::list<std::string>::const_iterator it = luaScripts.begin(); it != luaScripts.end(); ++it) { - std::string path = configLock.GetConfiguration().InterpretStringParameterAsPath(*it); - LOG(INFO) << "Installing the Lua scripts from: " << path; + boost::filesystem::path path = configLock.GetConfiguration().InterpretStringParameterAsPath(*it); + LOG(INFO) << "Installing the Lua scripts from: " << SystemToolbox::PathToUtf8(path); std::string script; SystemToolbox::ReadFile(script, path);
--- a/OrthancServer/Sources/OrthancConfiguration.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Sources/OrthancConfiguration.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -56,13 +56,13 @@ std::map<std::string, std::string> env; SystemToolbox::GetEnvironmentVariables(env); - LOG(WARNING) << "Reading the configuration from: " << path; + LOG(WARNING) << "Reading the configuration from: " << SystemToolbox::PathToUtf8(path); Json::Value config; { std::string content; - SystemToolbox::ReadFile(content, path.string()); + SystemToolbox::ReadFile(content, path); content = Toolbox::SubstituteVariables(content, env); @@ -71,7 +71,7 @@ tmp.type() != Json::objectValue) { throw OrthancException(ErrorCode_BadJson, - "The configuration file does not follow the JSON syntax: " + path.string()); + "The configuration file does not follow the JSON syntax: " + SystemToolbox::PathToUtf8(path)); } Toolbox::CopyJsonWithoutComments(config, tmp); @@ -103,11 +103,11 @@ static void ScanFolderForConfiguration(Json::Value& target, - const char* folder) + const boost::filesystem::path& folder) { using namespace boost::filesystem; - LOG(WARNING) << "Scanning folder \"" << folder << "\" for configuration files"; + LOG(WARNING) << "Scanning folder \"" << Orthanc::SystemToolbox::PathToUtf8(folder) << "\" for configuration files"; directory_iterator end_it; // default construction yields past-the-end for (directory_iterator it(folder); @@ -121,25 +121,25 @@ if (extension == ".json") { - AddFileToConfiguration(target, it->path().string()); + AddFileToConfiguration(target, it->path()); } } } } - static void ReadConfiguration(Json::Value& target, - const char* configurationFile) + static void ReadConfiguration(Json::Value& target, + const boost::filesystem::path &configurationFile) { target = Json::objectValue; - if (configurationFile != NULL) + if (!configurationFile.empty()) { if (!boost::filesystem::exists(configurationFile)) { throw OrthancException(ErrorCode_InexistentFile, "Inexistent path to configuration: " + - std::string(configurationFile)); + SystemToolbox::PathToUtf8(configurationFile)); } if (boost::filesystem::is_directory(configurationFile)) @@ -583,7 +583,7 @@ } - void OrthancConfiguration::Read(const char* configurationFile) + void OrthancConfiguration::Read(const boost::filesystem::path& configurationFile) { // Read the content of the configuration configurationFileArg_ = configurationFile; @@ -593,11 +593,11 @@ defaultDirectory_ = boost::filesystem::current_path(); configurationAbsolutePath_ = ""; - if (configurationFile) + if (configurationFile.empty()) { if (boost::filesystem::is_directory(configurationFile)) { - defaultDirectory_ = boost::filesystem::path(configurationFile); + defaultDirectory_ = configurationFile; configurationAbsolutePath_ = boost::filesystem::absolute(configurationFile).parent_path().string(); } else @@ -750,10 +750,10 @@ } - std::string OrthancConfiguration::InterpretStringParameterAsPath( + boost::filesystem::path OrthancConfiguration::InterpretStringParameterAsPath( const std::string& parameter) const { - return SystemToolbox::InterpretRelativePath(defaultDirectory_.string(), parameter); + return SystemToolbox::InterpretRelativePath(defaultDirectory_, parameter); }
--- a/OrthancServer/Sources/OrthancConfiguration.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Sources/OrthancConfiguration.h Tue Sep 09 15:35:30 2025 +0200 @@ -67,7 +67,7 @@ boost::filesystem::path defaultDirectory_; std::string configurationAbsolutePath_; FontRegistry fontRegistry_; - const char* configurationFileArg_; + boost::filesystem::path configurationFileArg_; Modalities modalities_; Peers peers_; JobsEngineThreadsCount jobsEngineThreadsCount_; @@ -75,7 +75,6 @@ std::set<Warnings> disabledWarnings_; OrthancConfiguration() : - configurationFileArg_(NULL), serverIndex_(NULL) { } @@ -164,7 +163,7 @@ return fontRegistry_; } - void Read(const char* configurationFile); + void Read(const boost::filesystem::path &configurationFile); // "SetServerIndex()" must have been called void LoadModalitiesAndPeers(); @@ -209,7 +208,7 @@ RegisteredUsersStatus SetupRegisteredUsers(HttpServer& httpServer) const; - std::string InterpretStringParameterAsPath(const std::string& parameter) const; + boost::filesystem::path InterpretStringParameterAsPath(const std::string& parameter) const; void GetListOfStringsParameter(std::list<std::string>& target, const std::string& key) const;
--- a/OrthancServer/Sources/OrthancInitialization.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Sources/OrthancInitialization.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -334,7 +334,7 @@ - void OrthancInitialize(const char* configurationFile) + void OrthancInitialize(const boost::filesystem::path& configurationFile) { static const char* const LOCALE = "Locale"; static const char* const PKCS11 = "Pkcs11"; @@ -442,7 +442,7 @@ boost::filesystem::path indexDirectory = lock.GetConfiguration().InterpretStringParameterAsPath( lock.GetConfiguration().GetStringParameter("IndexDirectory", storageDirectoryStr)); - LOG(WARNING) << "SQLite index directory: " << indexDirectory; + LOG(WARNING) << "SQLite index directory: " << SystemToolbox::PathToUtf8(indexDirectory); try { @@ -452,7 +452,7 @@ { } - return new SQLiteDatabaseWrapper(indexDirectory.string() + "/index"); + return new SQLiteDatabaseWrapper(Orthanc::SystemToolbox::PathToUtf8(indexDirectory) + "/index"); } @@ -466,7 +466,7 @@ FilesystemStorage storage_; public: - FilesystemStorageWithoutDicom(const std::string& path, + FilesystemStorageWithoutDicom(const boost::filesystem::path& path, bool fsyncOnWrite) : storage_(path, fsyncOnWrite) { @@ -528,19 +528,19 @@ boost::filesystem::path storageDirectory = lock.GetConfiguration().InterpretStringParameterAsPath(storageDirectoryStr); - LOG(WARNING) << "Storage directory: " << storageDirectory; + LOG(WARNING) << "Storage directory: " << SystemToolbox::PathToUtf8(storageDirectory); // New in Orthanc 1.7.4 bool fsyncOnWrite = lock.GetConfiguration().GetBooleanParameter(SYNC_STORAGE_AREA, true); if (lock.GetConfiguration().GetBooleanParameter(STORE_DICOM, true)) { - return new PluginStorageAreaAdapter(new FilesystemStorage(storageDirectory.string(), fsyncOnWrite)); + return new PluginStorageAreaAdapter(new FilesystemStorage(storageDirectory, fsyncOnWrite)); } else { LOG(WARNING) << "The DICOM files will not be stored, Orthanc running in index-only mode"; - return new PluginStorageAreaAdapter(new FilesystemStorageWithoutDicom(storageDirectory.string(), fsyncOnWrite)); + return new PluginStorageAreaAdapter(new FilesystemStorageWithoutDicom(storageDirectory, fsyncOnWrite)); } }
--- a/OrthancServer/Sources/OrthancInitialization.h Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Sources/OrthancInitialization.h Tue Sep 09 15:35:30 2025 +0200 @@ -29,7 +29,7 @@ namespace Orthanc { - void OrthancInitialize(const char* configurationFile = NULL); + void OrthancInitialize(const boost::filesystem::path& configurationFile); void OrthancFinalize();
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -190,14 +190,12 @@ if (plugins.HasStorageArea()) { - std::string p = plugins.GetStorageAreaLibrary().GetPath(); - result[STORAGE_AREA_PLUGIN] = boost::filesystem::canonical(p).string(); + result[STORAGE_AREA_PLUGIN] = SystemToolbox::PathToUtf8(plugins.GetStorageAreaLibrary().GetPath()); } if (plugins.HasDatabaseBackend()) { - std::string p = plugins.GetDatabaseBackendLibrary().GetPath(); - result[DATABASE_BACKEND_PLUGIN] = boost::filesystem::canonical(p).string(); + result[DATABASE_BACKEND_PLUGIN] = SystemToolbox::PathToUtf8(plugins.GetDatabaseBackendLibrary().GetPath()); } #else result[PLUGINS_ENABLED] = false;
--- a/OrthancServer/Sources/ServerJobs/ArchiveJob.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Sources/ServerJobs/ArchiveJob.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -1114,11 +1114,11 @@ } } - void SetOutputFile(const std::string& path) + void SetOutputFile(const boost::filesystem::path& path) { if (zip_.get() == NULL) { - zip_.reset(new HierarchicalZipWriter(path.c_str())); + zip_.reset(new HierarchicalZipWriter(path)); zip_->SetZip64(commands_.IsZip64()); isStream_ = false; }
--- a/OrthancServer/Sources/ServerJobs/Operations/SystemCallOperation.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/SystemCallOperation.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -89,7 +89,7 @@ tmp->Write(dicom); - arguments.push_back(tmp->GetPath()); + arguments.push_back(SystemToolbox::PathToUtf8(tmp->GetPath())); break; }
--- a/OrthancServer/Sources/main.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/Sources/main.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -711,10 +711,10 @@ }; -static void PrintHelp(const char* path) +static void PrintHelp(const boost::filesystem::path& path) { std::cout - << "Usage: " << path << " [OPTION]... [CONFIGURATION]" << std::endl + << "Usage: " << SystemToolbox::PathToUtf8(path) << " [OPTION]... [CONFIGURATION]" << std::endl << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research." << std::endl << std::endl << "The \"CONFIGURATION\" argument can be a single file or a directory. In the " << std::endl @@ -776,10 +776,10 @@ } -static void PrintVersion(const char* path) +static void PrintVersion(const boost::filesystem::path &path) { std::cout - << path << " " << ORTHANC_VERSION << std::endl + << SystemToolbox::PathToUtf8(path) << " " << ORTHANC_VERSION << std::endl << "Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics Department, University Hospital of Liege (Belgium)" << std::endl << "Copyright (C) 2017-2023 Osimis S.A. (Belgium)" << std::endl << "Copyright (C) 2024-2025 Orthanc Team SRL (Belgium)" << std::endl @@ -801,10 +801,10 @@ } -static void PrintErrors(const char* path) +static void PrintErrors(const boost::filesystem::path& path) { std::cout - << path << " " << ORTHANC_VERSION << std::endl + << SystemToolbox::PathToUtf8(path) << " " << ORTHANC_VERSION << std::endl << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research." << std::endl << std::endl << "List of error codes that could be returned by Orthanc:" @@ -945,7 +945,7 @@ for (std::list<std::string>::const_iterator it = pathList.begin(); it != pathList.end(); ++it) { - std::string path; + boost::filesystem::path path; { OrthancConfiguration::ReaderLock lock; @@ -1150,7 +1150,7 @@ if (lock.GetConfiguration().GetBooleanParameter("SslEnabled", false)) { - std::string certificate = lock.GetConfiguration().InterpretStringParameterAsPath( + boost::filesystem::path certificate = lock.GetConfiguration().InterpretStringParameterAsPath( lock.GetConfiguration().GetStringParameter("SslCertificate", "certificate.pem")); httpServer.SetSslEnabled(true); httpServer.SetSslCertificate(certificate.c_str()); @@ -1199,10 +1199,10 @@ if (lock.GetConfiguration().GetBooleanParameter("SslVerifyPeers", false)) { - std::string trustedClientCertificates = lock.GetConfiguration().InterpretStringParameterAsPath( + boost::filesystem::path trustedClientCertificates = lock.GetConfiguration().InterpretStringParameterAsPath( lock.GetConfiguration().GetStringParameter("SslTrustedClientCertificates", "trustedCertificates.pem")); httpServer.SetSslVerifyPeers(true); - httpServer.SetSslTrustedClientCertificates(trustedClientCertificates.c_str()); + httpServer.SetSslTrustedClientCertificates(trustedClientCertificates); } else { @@ -1573,10 +1573,11 @@ // ServerContext, otherwise the possible Lua scripts will not be // able to properly issue HTTP/HTTPS queries - std::string httpsCaCertificates = lock.GetConfiguration().GetStringParameter("HttpsCACertificates", ""); - if (!httpsCaCertificates.empty()) + std::string httpsCaCertificatesStr = lock.GetConfiguration().GetStringParameter("HttpsCACertificates", ""); + boost::filesystem::path httpsCaCertificates; + if (!httpsCaCertificatesStr.empty()) { - httpsCaCertificates = lock.GetConfiguration().InterpretStringParameterAsPath(httpsCaCertificates); + httpsCaCertificates = lock.GetConfiguration().InterpretStringParameterAsPath(httpsCaCertificatesStr); } HttpClient::ConfigureSsl(lock.GetConfiguration().GetBooleanParameter("HttpsVerifyPeers", true), @@ -1769,8 +1770,7 @@ } -static bool ConfigurePlugins(int argc, - char* argv[], +static bool ConfigurePlugins(const std::vector<std::string> arguments, bool upgradeDatabase, bool loadJobsFromDatabase) { @@ -1785,7 +1785,7 @@ } OrthancPlugins plugins(databaseServerIdentifier); - plugins.SetCommandLineArguments(argc, argv); + plugins.SetCommandLineArguments(arguments); LoadPlugins(plugins); IDatabaseWrapper* database = NULL; @@ -1834,12 +1834,11 @@ } -static bool StartOrthanc(int argc, - char* argv[], +static bool StartOrthanc(const std::vector<std::string>& arguments, bool upgradeDatabase, bool loadJobsFromDatabase) { - return ConfigurePlugins(argc, argv, upgradeDatabase, loadJobsFromDatabase); + return ConfigurePlugins(arguments, upgradeDatabase, loadJobsFromDatabase); } @@ -1867,11 +1866,32 @@ } -int main(int argc, char* argv[]) +#if defined(_WIN32) && !defined(__MINGW32__) +// arguments are passed as UTF-16 on Windows +int wmain(int argc, wchar_t *argv[]) { -#if defined(_WIN32) || defined(__CYGWIN__) // Set Windows console output to UTF-8 (otherwise, strings are considered to be in UTF-16. For example, Cyrillic UTF-8 strings appear as garbage without that config) SetConsoleOutputCP(CP_UTF8); + + // Transform the UTF-16 arguments into UTF-8 arguments + std::vector<std::string> arguments; // UTF-8 arguments + + for (int i = 0; i < argc; i++) + { + std::wstring argument(argv[i]); + arguments.push_back(SystemToolbox::WStringToUtf8(argument)); + } + +#else +int main(int argc, char* argv[]) +{ + std::vector<std::string> arguments; // UTF-8 arguments + + // the arguments are assumed to be directly in UTF-8 + for (int i = 0; i < argc; i++) + { + arguments.push_back(argv[i]); + } #endif Logging::Initialize(); @@ -1880,16 +1900,15 @@ bool upgradeDatabase = false; bool loadJobsFromDatabase = true; - const char* configurationFile = NULL; - + boost::filesystem::path configurationFile; /** * Parse the command-line options. **/ - for (int i = 1; i < argc; i++) + for (size_t i = 1; i < arguments.size(); i++) { - std::string argument(argv[i]); + const std::string& argument = arguments[i]; if (argument.empty()) { @@ -1897,7 +1916,7 @@ } else if (argument[0] != '-') { - if (configurationFile != NULL) + if (!configurationFile.empty()) { LOG(ERROR) << "More than one configuration path were provided on the command line, aborting"; return -1; @@ -1907,23 +1926,28 @@ // Use the first argument that does not start with a "-" as // the configuration file - // TODO WHAT IS THE ENCODING? - configurationFile = argv[i]; + configurationFile = SystemToolbox::PathFromUtf8(argument); +// // TODO WHAT IS THE ENCODING? +//#if defined(_WIN32) +// //configurationFileUtf8Str = SystemToolbox::WStringToUtf8(SystemToolbox::WStringFromCharPtr(argv[i])); +//#else +// configurationFileUtf8Str = std::string(argv[i]); +//#endif } } else if (argument == "--errors") { - PrintErrors(argv[0]); + PrintErrors(SystemToolbox::PathFromUtf8(arguments[0])); return 0; } else if (argument == "--help") { - PrintHelp(argv[0]); + PrintHelp(SystemToolbox::PathFromUtf8(arguments[0])); return 0; } else if (argument == "--version") { - PrintVersion(argv[0]); + PrintVersion(SystemToolbox::PathFromUtf8(arguments[0])); return 0; } else if (argument == "--verbose") @@ -2175,7 +2199,7 @@ { OrthancInitialize(configurationFile); - bool restart = StartOrthanc(argc, argv, upgradeDatabase, loadJobsFromDatabase); + bool restart = StartOrthanc(arguments, upgradeDatabase, loadJobsFromDatabase); if (restart) { OrthancFinalize();
--- a/OrthancServer/UnitTestsSources/UnitTestsMain.cpp Tue Sep 09 14:26:51 2025 +0200 +++ b/OrthancServer/UnitTestsSources/UnitTestsMain.cpp Tue Sep 09 15:35:30 2025 +0200 @@ -47,6 +47,9 @@ #include <dcmtk/dcmdata/dcdeftag.h> +#if defined(_WIN32) || defined(__CYGWIN__) +#include <windows.h> +#endif using namespace Orthanc; @@ -515,11 +518,16 @@ int main(int argc, char **argv) { +#if defined(_WIN32) && !defined(__MINGW32__) + // Set Windows console output to UTF-8 (otherwise, strings are considered to be in UTF-16. For example, Cyrillic UTF-8 strings appear as garbage without that config) + SetConsoleOutputCP(CP_UTF8); +#endif + Logging::Initialize(); SetGlobalVerbosity(Verbosity_Verbose); Toolbox::DetectEndianness(); - SystemToolbox::MakeDirectory("UnitTestsResults"); - OrthancInitialize(); + SystemToolbox::MakeDirectory(SystemToolbox::PathFromUtf8("UnitTestsResults")); + OrthancInitialize(""); ::testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS();