diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index 541acf0a..83dfac7f 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -75,6 +75,12 @@ SPDLOG_API bool is_color_terminal() noexcept; // Source: https://github.com/agauniyal/rang/ SPDLOG_API bool in_terminal(FILE *file) noexcept; +#if (defined _WIN32) + SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); + SPDLOG_API void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target); +#endif + + // Return directory name from given path or empty string // "abc/file" => "abc" // "abc/" => "abc" diff --git a/src/details/os_windows.cpp b/src/details/os_windows.cpp index 8fdcc569..e64e9082 100644 --- a/src/details/os_windows.cpp +++ b/src/details/os_windows.cpp @@ -167,6 +167,69 @@ bool is_color_terminal() noexcept { return true; } // Determine if the terminal attached bool in_terminal(FILE *file) noexcept { return ::_isatty(_fileno(file)) != 0; } + + +void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) { + if (wstr.size() > static_cast((std::numeric_limits::max)()) / 4 - 1) { + throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8"); + } + + int wstr_size = static_cast(wstr.size()); + if (wstr_size == 0) { + target.resize(0); + return; + } + + int result_size = static_cast(target.capacity()); + if ((wstr_size + 1) * 4 > result_size) { + result_size = + ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL); + } + + if (result_size > 0) { + target.resize(result_size); + result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), + result_size, NULL, NULL); + + if (result_size > 0) { + target.resize(result_size); + return; + } + } + + throw_spdlog_ex( + fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); +} + +void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) { + if (str.size() > static_cast((std::numeric_limits::max)()) - 1) { + throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16"); + } + + int str_size = static_cast(str.size()); + if (str_size == 0) { + target.resize(0); + return; + } + + // find the size to allocate for the result buffer + int result_size = + ::MultiByteToWideChar(CP_UTF8, 0, str.data(), str_size, NULL, 0); + + if (result_size > 0) { + target.resize(result_size); + result_size = ::MultiByteToWideChar(CP_UTF8, 0, str.data(), str_size, target.data(), + result_size); + if (result_size > 0) { + assert(result_size == target.size()); + return; + } + } + + throw_spdlog_ex( + fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError())); +} + // return true on success static bool mkdir_(const filename_t &path) { return ::_mkdir(path.c_str()) == 0;