From 3edb8e113e72b8eedd741e92dff63f5167ff5adb Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Fri, 31 Jul 2020 16:02:32 +1000 Subject: [PATCH] StringUtil: Add wide string<->utf8 conversion for Windows --- src/common/string_util.cpp | 38 +++++++++++++++++++ src/common/string_util.h | 18 +++++++-- src/frontend-common/common_host_interface.cpp | 19 ++-------- 3 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 5787d2b64..a9863bde7 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -1,7 +1,12 @@ #include "string_util.h" #include +#include #include +#ifdef WIN32 +#include "windows_headers.h" +#endif + namespace StringUtil { std::string StdStringFromFormat(const char* format, ...) @@ -158,4 +163,37 @@ std::size_t Strlcpy(char* dst, const std::string_view& src, std::size_t size) return len; } +#ifdef WIN32 + +std::wstring UTF8StringToWideString(const std::string_view& str) +{ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.length()), nullptr, 0); + if (wlen <= 0) + return {}; + + std::wstring ret; + ret.resize(wlen); + if (MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.length()), ret.data(), wlen) <= 0) + return {}; + + return ret; +} + +std::string WideStringToUTF8String(const std::wstring_view& str) +{ + int mblen = WideCharToMultiByte(CP_UTF8, 0, str.data(), static_cast(str.length()), nullptr, 0, nullptr, nullptr); + if (mblen <= 0) + return {}; + + std::string ret; + ret.resize(mblen); + if (WideCharToMultiByte(CP_UTF8, 0, str.data(), static_cast(str.length()), ret.data(), mblen, nullptr, nullptr) < + 0) + return {}; + + return ret; +} + +#endif + } // namespace StringUtil diff --git a/src/common/string_util.h b/src/common/string_util.h index ea69931d4..d2058e644 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h @@ -53,7 +53,7 @@ static inline int Strncasecmp(const char* s1, const char* s2, std::size_t n) /// Wrapper arond std::from_chars template -inline std::optional FromChars(std::string_view str) +inline std::optional FromChars(const std::string_view& str) { T value; @@ -74,7 +74,7 @@ inline std::optional FromChars(std::string_view str) /// Explicit override for booleans template<> -inline std::optional FromChars(std::string_view str) +inline std::optional FromChars(const std::string_view& str) { if (Strncasecmp("true", str.data(), str.length()) == 0 || Strncasecmp("yes", str.data(), str.length()) == 0 || Strncasecmp("on", str.data(), str.length()) == 0 || Strncasecmp("1", str.data(), str.length()) == 0) @@ -94,7 +94,7 @@ inline std::optional FromChars(std::string_view str) #ifndef _MSC_VER /// from_chars doesn't seem to work with floats on gcc template<> -inline std::optional FromChars(std::string_view str) +inline std::optional FromChars(const std::string_view& str) { float value; std::string temp(str); @@ -108,9 +108,19 @@ inline std::optional FromChars(std::string_view str) #endif /// starts_with from C++20 -ALWAYS_INLINE static bool StartsWith(std::string_view str, const char* prefix) +ALWAYS_INLINE static bool StartsWith(const std::string_view& str, const char* prefix) { return (str.compare(0, std::strlen(prefix), prefix) == 0); } +#ifdef WIN32 + +/// Converts the specified UTF-8 string to a wide string. +std::wstring UTF8StringToWideString(const std::string_view& str); + +/// Converts the specified wide string to a UTF-8 string. +std::string WideStringToUTF8String(const std::wstring_view& str); + +#endif + } // namespace StringUtil diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp index 14049a2e6..16b7fbcc6 100644 --- a/src/frontend-common/common_host_interface.cpp +++ b/src/frontend-common/common_host_interface.cpp @@ -626,22 +626,11 @@ void CommonHostInterface::SetUserDirectory() PWSTR documents_directory; if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory))) { - const size_t documents_directory_len = std::wcslen(documents_directory); - int documents_directory_u8len = WideCharToMultiByte( - CP_UTF8, 0, documents_directory, static_cast(documents_directory_len), nullptr, 0, nullptr, nullptr); - if (documents_directory_u8len > 0) + const std::string documents_directory_str(StringUtil::WideStringToUTF8String(documents_directory)); + if (!documents_directory_str.empty()) { - std::string documents_directory_str; - documents_directory_str.resize(documents_directory_u8len); - documents_directory_u8len = WideCharToMultiByte( - CP_UTF8, 0, documents_directory, static_cast(documents_directory_len), documents_directory_str.data(), - static_cast(documents_directory_str.size()), 0, nullptr); - if (documents_directory_u8len > 0) - { - documents_directory_str.resize(documents_directory_u8len); - m_user_directory = StringUtil::StdStringFromFormat("%s%c%s", documents_directory_str.c_str(), - FS_OSPATH_SEPERATOR_CHARACTER, "DuckStation"); - } + m_user_directory = StringUtil::StdStringFromFormat("%s%c%s", documents_directory_str.c_str(), + FS_OSPATH_SEPERATOR_CHARACTER, "DuckStation"); } CoTaskMemFree(documents_directory); }