changeset 6294:470e2a8b42e0 default

merge
author Alain Mazy <am@orthanc.team>
date Tue, 02 Sep 2025 18:00:26 +0200
parents 26d5e7f09a13 (diff) 5377631f42a3 (current diff)
children 88aa865b6a54
files OrthancFramework/Sources/SystemToolbox.cpp OrthancFramework/Sources/SystemToolbox.h OrthancServer/Plugins/Engine/OrthancPlugins.cpp
diffstat 4 files changed, 110 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/SystemToolbox.cpp	Mon Sep 01 12:45:47 2025 +0200
+++ b/OrthancFramework/Sources/SystemToolbox.cpp	Tue Sep 02 18:00:26 2025 +0200
@@ -235,7 +235,7 @@
     try
     {
       boost::filesystem::ifstream f;
-      f.open(path, std::ifstream::in | std::ifstream::binary);
+      f.open(PathFromUtf8(path), std::ifstream::in | std::ifstream::binary);
       if (!f.good())
       {
         throw OrthancException(ErrorCode_InexistentFile,
@@ -289,7 +289,7 @@
     try
     {
       boost::filesystem::ifstream f;
-      f.open(path, std::ifstream::in | std::ifstream::binary);
+      f.open(PathFromUtf8(path), std::ifstream::in | std::ifstream::binary);
       if (!f.good())
       {
         throw OrthancException(ErrorCode_InexistentFile);
@@ -338,7 +338,7 @@
                                 const std::string& path,
                                 bool callFsync)
   {
-    WriteFile(content, size, boost::filesystem::path(path), callFsync);
+    WriteFile(content, size, PathFromUtf8(path), callFsync);
   }
 
   void SystemToolbox::WriteFile(const void *content, 
@@ -445,8 +445,12 @@
     }
   }
 
+  uint64_t SystemToolbox::GetFileSize(const std::string &path) 
+  {
+    return GetFileSize(PathFromUtf8(path));
+  }
 
-  uint64_t SystemToolbox::GetFileSize(const std::string& path)
+  uint64_t SystemToolbox::GetFileSize(const boost::filesystem::path& path)
   {
     try
     {
@@ -484,25 +488,35 @@
 
     context.Export(result);
   }
+  
+
+  void SystemToolbox::ComputeFileMD5(std::string& result, 
+                                     const std::string& path) 
+  { 
+    return ComputeFileMD5(result, PathFromUtf8(path));
+  }
 
 
   void SystemToolbox::ComputeFileMD5(std::string& result,
-                                     const std::string& path)
+                                     const boost::filesystem::path& path)
   {
     boost::filesystem::ifstream fileStream;
     fileStream.open(path, std::ifstream::in | std::ifstream::binary);
 
     if (!fileStream.good())
     {
-      throw OrthancException(ErrorCode_InexistentFile, "File not found: " + path);
+      throw OrthancException(ErrorCode_InexistentFile, "File not found: " + PathToUtf8(path));
     }
 
     ComputeStreamMD5(result, fileStream);
   }
 
+  bool SystemToolbox::CompareFilesMD5(const std::string &path1, const std::string &path2) 
+  { 
+    return CompareFilesMD5(PathFromUtf8(path1), PathFromUtf8(path2));
+  }
 
-  bool SystemToolbox::CompareFilesMD5(const std::string& path1,
-                                      const std::string& path2)
+  bool SystemToolbox::CompareFilesMD5(const boost::filesystem::path& path1, const boost::filesystem::path &path2)
   {
     if (GetFileSize(path1) != GetFileSize(path2))
     {
@@ -618,6 +632,57 @@
 #endif
 
 
+#ifdef _WIN32
+  std::wstring Utf8ToWString(const std::string &str)
+  {
+    if (str.empty())
+    {
+      return std::wstring();
+    }
+
+    int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int) str.size(), NULL, 0);
+
+    std::wstring wstr(sizeNeeded, 0);
+    MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int) str.size(), &wstr[0], sizeNeeded);
+
+    return wstr;
+  }
+
+  std::string WStringToUtf8(const std::wstring &wstr)
+  {
+    if (wstr.empty())
+    {
+      return std::string();
+    }
+
+    int sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int) wstr.size(), NULL, 0, NULL, NULL);
+
+    std::string str(sizeNeeded, 0);
+    WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int) wstr.size(), &str[0], sizeNeeded, NULL, NULL);
+
+    return str;
+  }
+
+#endif
+
+    boost::filesystem::path SystemToolbox::PathFromUtf8(const std::string &utf8)
+  {
+#ifdef _WIN32
+    return boost::filesystem::path(Utf8ToWString(utf8));
+#else
+    return boost::filesystem::path(utf8); // POSIX: std::string is UTF-8
+#endif
+  }
+
+  std::string SystemToolbox::PathToUtf8(const boost::filesystem::path &p)
+  {
+#ifdef _WIN32
+    return WStringToUtf8(p.wstring());
+#else
+    return p.string(); // POSIX: already UTF-8
+#endif
+  }
+
   std::string SystemToolbox::GetPathToExecutable()
   {
     boost::filesystem::path p(GetPathToExecutableInternal());
@@ -715,8 +780,8 @@
 
 
   bool SystemToolbox::IsRegularFile(const std::string& path)
-  {
-    return IsRegularFile(boost::filesystem::path(path));
+  { 
+    return IsRegularFile(PathFromUtf8(path));
   }
 
 
@@ -845,9 +910,15 @@
     return false;
   }
 
-  MimeType SystemToolbox::AutodetectMimeType(const std::string& path)
+  MimeType SystemToolbox::AutodetectMimeType(const std::string &path) 
+  { 
+    return AutodetectMimeType(PathFromUtf8(path));
+  }
+
+
+  MimeType SystemToolbox::AutodetectMimeType(const boost::filesystem::path& path)
   {
-    std::string extension = boost::filesystem::path(path).extension().string();
+    std::string extension = path.extension().string();
     Toolbox::ToLowerCase(extension);
 
     // http://en.wikipedia.org/wiki/Mime_types
@@ -1030,7 +1101,7 @@
     }
 
     boost::filesystem::ifstream f;
-    f.open(path, std::ifstream::in | std::ifstream::binary);
+    f.open(PathFromUtf8(path), std::ifstream::in | std::ifstream::binary);
     if (!f.good())
     {
       throw OrthancException(ErrorCode_InexistentFile,
--- a/OrthancFramework/Sources/SystemToolbox.h	Mon Sep 01 12:45:47 2025 +0200
+++ b/OrthancFramework/Sources/SystemToolbox.h	Tue Sep 02 18:00:26 2025 +0200
@@ -93,6 +93,8 @@
 
     static uint64_t GetFileSize(const std::string& path);
 
+    static uint64_t GetFileSize(const boost::filesystem::path &path);  // this variant is mandatory to handle non ASCII-only path on Windows
+
 #if ORTHANC_ENABLE_MD5 == 1
     static void ComputeStreamMD5(std::string& result,
                                  std::istream& stream);
@@ -100,9 +102,15 @@
     static void ComputeFileMD5(std::string& result,
                                const std::string& path);
 
+    static void ComputeFileMD5(std::string &result, 
+                               const boost::filesystem::path& path);  // this variant is mandatory to handle non ASCII-only path on Windows
+
     // returns true if file have the same MD5
     static bool CompareFilesMD5(const std::string& path1,
                                 const std::string& path2); 
+
+    static bool CompareFilesMD5(const boost::filesystem::path& path1, 
+                                const boost::filesystem::path& path2);  // this variant is mandatory to handle non ASCII-only path on Windows
 #endif
 
     static void MakeDirectory(const std::string& path);
@@ -125,6 +133,19 @@
     static FILE* OpenFile(const std::string& path,
                           FileMode mode);
 
+    static MimeType AutodetectMimeType(const char* path)  // used only in Unit Tests
+    { 
+      return AutodetectMimeType(std::string(path));
+    }
+
+    static MimeType AutodetectMimeType(const std::string &path);
+
+    static MimeType AutodetectMimeType(const boost::filesystem::path &path);
+
+    static boost::filesystem::path PathFromUtf8(const std::string &utf8);
+
+    static std::string PathToUtf8(const boost::filesystem::path &p);
+
     static std::string GetNowIsoString(bool utc);
 
     static void GetNowDicom(std::string& date,
@@ -137,8 +158,6 @@
 
     static bool IsContentCompressible(const std::string& contentType);
 
-    static MimeType AutodetectMimeType(const std::string& path);
-
     static void GetEnvironmentVariables(std::map<std::string, std::string>& env);
 
     static std::string InterpretRelativePath(const std::string& baseDirectory,
--- a/OrthancFramework/UnitTestsSources/FrameworkTests.cpp	Mon Sep 01 12:45:47 2025 +0200
+++ b/OrthancFramework/UnitTestsSources/FrameworkTests.cpp	Tue Sep 02 18:00:26 2025 +0200
@@ -369,6 +369,9 @@
   ASSERT_STREQ("model/obj", EnumerationToString(SystemToolbox::AutodetectMimeType(".obj")));
   ASSERT_STREQ("model/mtl", EnumerationToString(SystemToolbox::AutodetectMimeType(".mtl")));
   ASSERT_STREQ("model/stl", EnumerationToString(SystemToolbox::AutodetectMimeType(".stl")));
+
+  // test with utf8 strings
+  ASSERT_STREQ("model/stl", EnumerationToString(SystemToolbox::AutodetectMimeType("\xd0\x94.stl")));
 }
 #endif
 
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Mon Sep 01 12:45:47 2025 +0200
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Tue Sep 02 18:00:26 2025 +0200
@@ -267,7 +267,7 @@
         if (mimeType == NULL ||
             std::string(mimeType).empty())
         {
-          f->SetMimeType(SystemToolbox::AutodetectMimeType(displayName));
+          f->SetMimeType(SystemToolbox::AutodetectMimeType(std::string(displayName)));
         }
         else
         {
@@ -5233,7 +5233,7 @@
       {
         const _OrthancPluginWriteFile& p =
           *reinterpret_cast<const _OrthancPluginWriteFile*>(parameters);
-        SystemToolbox::WriteFile(p.data, p.size, boost::filesystem::path(p.path), true /* run fsync() */);
+        SystemToolbox::WriteFile(p.data, p.size, std::string(p.path), true /* run fsync() */);
         return true;
       }