diff --git a/include/spdlog/common.h b/include/spdlog/common.h index ae9f0fa4..2f23e9e4 100644 --- a/include/spdlog/common.h +++ b/include/spdlog/common.h @@ -26,11 +26,6 @@ #include #endif //_WIN32 -#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) -#include -#include -#endif - #ifdef SPDLOG_COMPILED_LIB #undef SPDLOG_HEADER_ONLY #define SPDLOG_INLINE @@ -80,11 +75,6 @@ class sink; #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) using filename_t = std::wstring; #define SPDLOG_FILENAME_T(s) L##s -inline std::string filename_to_str(const filename_t &filename) -{ - std::wstring_convert, wchar_t> c; - return c.to_bytes(filename); -} #else using filename_t = std::string; #define SPDLOG_FILENAME_T(s) s @@ -97,10 +87,13 @@ using err_handler = std::function; // string_view type - either std::string_view or fmt::string_view (pre c++17) #if defined(FMT_USE_STD_STRING_VIEW) -using string_view_t = std::string_view; +template +using basic_string_view_t = std::basic_string_view; #else -using string_view_t = fmt::string_view; +template +using basic_string_view_t = fmt::basic_string_view; #endif +using string_view_t = basic_string_view_t; #if defined(SPDLOG_NO_ATOMIC_LEVELS) using level_t = details::null_atomic_int; diff --git a/include/spdlog/details/os-inl.h b/include/spdlog/details/os-inl.h index e0809d9b..0675436b 100644 --- a/include/spdlog/details/os-inl.h +++ b/include/spdlog/details/os-inl.h @@ -36,6 +36,10 @@ #include #endif +#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES) +#include +#endif + #else // unix #include @@ -342,13 +346,14 @@ SPDLOG_INLINE void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) -SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) SPDLOG_NOEXCEPT +SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) { - std::wstring_convert, wchar_t> c; - return c.to_bytes(filename); + fmt::memory_buffer buf; + wstr_to_utf8buf(filename, buf); + return fmt::to_string(buf); } #else -SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) SPDLOG_NOEXCEPT +SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) { return filename; } @@ -398,28 +403,42 @@ SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT #endif } -#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) && defined(_WIN32) -SPDLOG_INLINE void wbuf_to_utf8buf(const fmt::wmemory_buffer &wbuf, fmt::memory_buffer &target) +#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) +SPDLOG_INLINE void wstr_to_utf8buf(basic_string_view_t wstr, fmt::memory_buffer &target) { - int wbuf_size = static_cast(wbuf.size()); - if (wbuf_size == 0) + if (wstr.size() > static_cast(std::numeric_limits::max())) { + throw spdlog::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; } - auto result_size = ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, NULL, 0, NULL, NULL); + int result_size = static_cast(target.capacity()); + if ((wstr_size + 1) * 2 > result_size) + { + result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL); + } if (result_size > 0) { target.resize(result_size); - ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, &target.data()[0], result_size, NULL, NULL); - } - else - { - throw spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); + 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::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); } -#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT) && _WIN32 +#endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) } // namespace os } // namespace details diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index 4afe0cb9..27694494 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -68,7 +68,7 @@ size_t thread_id() SPDLOG_NOEXCEPT; // See https://github.com/gabime/spdlog/issues/609 void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT; -std::string filename_to_str(const filename_t &filename) SPDLOG_NOEXCEPT; +std::string filename_to_str(const filename_t &filename); int pid() SPDLOG_NOEXCEPT; @@ -80,8 +80,8 @@ bool is_color_terminal() SPDLOG_NOEXCEPT; // Source: https://github.com/agauniyal/rang/ bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; -#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) && defined(_WIN32) -void wbuf_to_utf8buf(const fmt::wmemory_buffer &wbuf, fmt::memory_buffer &target); +#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) +void wstr_to_utf8buf(basic_string_view_t wstr, fmt::memory_buffer &target); #endif } // namespace os diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index bc627c4b..1d831362 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -243,8 +243,10 @@ public: // format to wmemory_buffer and convert to utf8 fmt::wmemory_buffer wbuf; fmt::format_to(wbuf, fmt, args...); + fmt::memory_buffer buf; - details::os::wbuf_to_utf8buf(wbuf, buf); + details::os::wstr_to_utf8buf(basic_string_view_t(wbuf.data(), wbuf.size()), buf); + details::log_msg log_msg(source, name_, lvl, string_view_t(buf.data(), buf.size())); sink_it_(log_msg); }