From e8a5ee327d0b5cfb7216f56b1017eefbd58ae3c5 Mon Sep 17 00:00:00 2001 From: Jean-Francois Dockes Date: Wed, 30 Sep 2020 12:31:51 +0100 Subject: [PATCH] Windows wide path conversions: don't use SYSPATH outside pathut.cpp --- src/utils/pathut.cpp | 33 +++++++++++++++++++++++++++++++++ src/utils/pathut.h | 12 ++++-------- src/utils/readfile.cpp | 15 ++++++++++++--- src/windows/execmd_w.cpp | 4 ++-- 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/utils/pathut.cpp b/src/utils/pathut.cpp index 82cf7afd..b0df3f53 100644 --- a/src/utils/pathut.cpp +++ b/src/utils/pathut.cpp @@ -78,6 +78,7 @@ #include #endif // _MSC_VER + #ifdef _WIN32 #ifndef _MSC_VER @@ -134,6 +135,10 @@ #define RMDIR _wrmdir #define CHDIR _wchdir +#define SYSPATH(PATH, SPATH) wchar_t PATH ## _buf[2048]; \ + utf8towchar(PATH, PATH ## _buf, 2048); \ + wchar_t *SPATH = PATH ## _buf; + #define ftruncate _chsize_s #ifdef _MSC_VER @@ -172,6 +177,9 @@ #define RMDIR ::rmdir #define CHDIR ::chdir +#define SYSPATH(PATH, SPATH) const char *SPATH = PATH.c_str() + + #endif /* !_WIN32 */ using namespace std; @@ -256,6 +264,31 @@ bool utf8towchar(const std::string& in, wchar_t *out, size_t obytescap) return true; } +std::unique_ptr utf8towchar(const std::string& in) +{ + // Note that as we supply in.size(), mbtowch computes the size + // without a terminating 0 (and won't write in the second call of + // course). We take this into account by allocating one more and + // terminating the output. + int wcharcnt = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, in.c_str(), in.size(), nullptr, 0); + if (wcharcnt <= 0) { + LOGERR("utf8towchar: conversion error for [" << in << "]\n"); + return std::unique_ptr(); + } + auto buf = unique_ptr(new wchar_t[wcharcnt+1]); + + wcharcnt = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, in.c_str(), in.size(), + buf.get(), wcharcnt); + if (wcharcnt <= 0) { + LOGERR("utf8towchar: conversion error for [" << in << "]\n"); + return std::unique_ptr(); + } + buf.get()[wcharcnt] = 0; + return buf; +} + /// Convert \ separators to / void path_slashize(string& s) { diff --git a/src/utils/pathut.h b/src/utils/pathut.h index ab1f33dc..f969d0d6 100644 --- a/src/utils/pathut.h +++ b/src/utils/pathut.h @@ -123,14 +123,10 @@ extern int path_fileprops(const std::string path, struct PathStat *stp, extern std::string path_PATHsep(); #ifdef _WIN32 -extern bool wchartoutf8(const wchar_t *in, std::string& out, size_t len = 0); -extern std::string wchartoutf8(const wchar_t *in, size_t len = 0); -extern bool utf8towchar(const std::string& in, wchar_t *out, size_t obytescap); -#define SYSPATH(PATH, SPATH) wchar_t PATH ## _buf[2048]; \ - utf8towchar(PATH, PATH ## _buf, 2048); \ - wchar_t *SPATH = PATH ## _buf; -#else -#define SYSPATH(PATH, SPATH) const char *SPATH = PATH.c_str() +bool wchartoutf8(const wchar_t *in, std::string& out, size_t len = 0); +std::string wchartoutf8(const wchar_t *in, size_t len = 0); +bool utf8towchar(const std::string& in, wchar_t *out, size_t obytescap); +std::unique_ptr utf8towchar(const std::string& in); #endif /// Directory reading interface. UTF-8 on Windows. diff --git a/src/utils/readfile.cpp b/src/utils/readfile.cpp index 1cc1dac9..0ad5c2a9 100644 --- a/src/utils/readfile.cpp +++ b/src/utils/readfile.cpp @@ -32,7 +32,6 @@ #include "safefcntl.h" #include "safesysstat.h" #include "safeunistd.h" -#include "transcode.h" #define OPEN _wopen #else @@ -333,7 +332,12 @@ public: // If we have a file name, open it, else use stdin. if (!m_fn.empty()) { - SYSPATH(m_fn, realpath); +#ifdef _WIN32 + auto buf = utf8towchar(m_fn); + auto realpath = buf.get(); +#else + auto realpath = m_fn.c_str(); +#endif fd = OPEN(realpath, O_RDONLY | O_BINARY); if (fd < 0 || fstat(fd, &st) < 0) { catstrerror(m_reason, "open/stat", errno); @@ -440,7 +444,12 @@ public: if (m_fn.empty()) { ret1 = mz_zip_reader_init_mem(&zip, m_data, m_cnt, 0); } else { - SYSPATH(m_fn, realpath); +#ifdef _WIN32 + auto buf = utf8towchar(m_fn); + auto realpath = buf.get(); +#else + auto realpath = m_fn.c_str(); +#endif ret1 = mz_zip_reader_init_file(&zip, realpath, 0); } if (!ret1) { diff --git a/src/windows/execmd_w.cpp b/src/windows/execmd_w.cpp index dd6711a7..c7412866 100644 --- a/src/windows/execmd_w.cpp +++ b/src/windows/execmd_w.cpp @@ -793,9 +793,9 @@ int ExecCmd::startExec(const string &cmd, const vector& args, int flags = CREATE_NEW_PROCESS_GROUP | CREATE_UNICODE_ENVIRONMENT; // Create the child process. LOGDEB("ExecCmd:startExec: cmdline [" << cmdline << "]\n"); - SYSPATH(cmdline, wcmdline); + auto wcmdline = utf8towchar(cmdline); bSuccess = CreateProcessW(NULL, // app name - wcmdline, // command line + wcmdline.get(), // command line NULL, // process security attributes NULL, // primary thread security attrs TRUE, // handles are inherited