From 86a42e1e4379120db7d6dcddaead86b82505b0dd Mon Sep 17 00:00:00 2001 From: Denis Zibarev <9913878+dz-fsd@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:27:26 +0800 Subject: [PATCH] Problem: Using non-ascii characters in unix domain socket path doesn't work on Windows Solution: Convert utf-8 socket paths to utf-16 file names when using filesystem calls to delete files and directories as Windows doesn't have any filesystem calls that take utf-8 path. rmdir_utf8() and unlink_utf8() static functions were created which substitute rmdir() and unlink() when building on Windows. --- src/ip.cpp | 4 ++-- src/ipc_listener.cpp | 4 ++-- src/windows.hpp | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/ip.cpp b/src/ip.cpp index 98804e8c..5016da5b 100644 --- a/src/ip.cpp +++ b/src/ip.cpp @@ -27,8 +27,8 @@ #include -#define rmdir _rmdir -#define unlink _unlink +#define rmdir rmdir_utf8 +#define unlink unlink_utf8 #endif #if defined ZMQ_HAVE_OPENVMS || defined ZMQ_HAVE_VXWORKS diff --git a/src/ipc_listener.cpp b/src/ipc_listener.cpp index 50126040..586bd764 100644 --- a/src/ipc_listener.cpp +++ b/src/ipc_listener.cpp @@ -25,8 +25,8 @@ #include #include -#define rmdir _rmdir -#define unlink _unlink +#define rmdir rmdir_utf8 +#define unlink unlink_utf8 #else #include diff --git a/src/windows.hpp b/src/windows.hpp index 9a4e96d5..3ecec4c6 100644 --- a/src/windows.hpp +++ b/src/windows.hpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #if !defined __MINGW32__ #include @@ -64,6 +66,43 @@ static inline int poll (struct pollfd *pfd, unsigned long nfds, int timeout) #define AI_NUMERICSERV 0x0400 #endif +// Need unlink() and rmdir() functions that take utf-8 encoded file path. +static inline std::wstring utf8_to_utf16 (const char *utf8_string) +{ + std::wstring retVal; + + if (utf8_string && *utf8_string) { + const int utf16_length = ::MultiByteToWideChar ( + CP_UTF8, MB_ERR_INVALID_CHARS, utf8_string, + -1, // assume the input string is null-terminated + NULL, 0); + + if (utf16_length > 0) { + retVal.resize (utf16_length); + + const int conversion_result = ::MultiByteToWideChar ( + CP_UTF8, MB_ERR_INVALID_CHARS, utf8_string, + -1, // assume the input string is null-terminated + &retVal[0], static_cast (retVal.size ())); + + if (conversion_result == 0) + retVal.clear (); + } + } + + return retVal; +} + +static inline int unlink_utf8 (const char *filename) +{ + return _wunlink (utf8_to_utf16 (filename).c_str ()); +} + +static inline int rmdir_utf8 (const char *filename) +{ + return _wrmdir (utf8_to_utf16 (filename).c_str ()); +} + // In MSVC prior to v14, snprintf is not available // The closest implementation is the _snprintf_s function #if defined(_MSC_VER) && _MSC_VER < 1900