StringUtil: Add wide string<->utf8 conversion for Windows

This commit is contained in:
Connor McLaughlin 2020-07-31 16:02:32 +10:00
parent ebf9f3b2e2
commit 3edb8e113e
3 changed files with 56 additions and 19 deletions

View file

@ -1,7 +1,12 @@
#include "string_util.h" #include "string_util.h"
#include <cctype> #include <cctype>
#include <codecvt>
#include <cstdio> #include <cstdio>
#ifdef WIN32
#include "windows_headers.h"
#endif
namespace StringUtil { namespace StringUtil {
std::string StdStringFromFormat(const char* format, ...) 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; return len;
} }
#ifdef WIN32
std::wstring UTF8StringToWideString(const std::string_view& str)
{
int wlen = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
if (wlen <= 0)
return {};
std::wstring ret;
ret.resize(wlen);
if (MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(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<int>(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<int>(str.length()), ret.data(), mblen, nullptr, nullptr) <
0)
return {};
return ret;
}
#endif
} // namespace StringUtil } // namespace StringUtil

View file

@ -53,7 +53,7 @@ static inline int Strncasecmp(const char* s1, const char* s2, std::size_t n)
/// Wrapper arond std::from_chars /// Wrapper arond std::from_chars
template<typename T> template<typename T>
inline std::optional<T> FromChars(std::string_view str) inline std::optional<T> FromChars(const std::string_view& str)
{ {
T value; T value;
@ -74,7 +74,7 @@ inline std::optional<T> FromChars(std::string_view str)
/// Explicit override for booleans /// Explicit override for booleans
template<> template<>
inline std::optional<bool> FromChars(std::string_view str) inline std::optional<bool> FromChars(const std::string_view& str)
{ {
if (Strncasecmp("true", str.data(), str.length()) == 0 || Strncasecmp("yes", str.data(), str.length()) == 0 || 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) Strncasecmp("on", str.data(), str.length()) == 0 || Strncasecmp("1", str.data(), str.length()) == 0)
@ -94,7 +94,7 @@ inline std::optional<bool> FromChars(std::string_view str)
#ifndef _MSC_VER #ifndef _MSC_VER
/// from_chars doesn't seem to work with floats on gcc /// from_chars doesn't seem to work with floats on gcc
template<> template<>
inline std::optional<float> FromChars(std::string_view str) inline std::optional<float> FromChars(const std::string_view& str)
{ {
float value; float value;
std::string temp(str); std::string temp(str);
@ -108,9 +108,19 @@ inline std::optional<float> FromChars(std::string_view str)
#endif #endif
/// starts_with from C++20 /// 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); 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 } // namespace StringUtil

View file

@ -626,23 +626,12 @@ void CommonHostInterface::SetUserDirectory()
PWSTR documents_directory; PWSTR documents_directory;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory))) if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory)))
{ {
const size_t documents_directory_len = std::wcslen(documents_directory); const std::string documents_directory_str(StringUtil::WideStringToUTF8String(documents_directory));
int documents_directory_u8len = WideCharToMultiByte( if (!documents_directory_str.empty())
CP_UTF8, 0, documents_directory, static_cast<int>(documents_directory_len), nullptr, 0, nullptr, nullptr);
if (documents_directory_u8len > 0)
{ {
std::string documents_directory_str;
documents_directory_str.resize(documents_directory_u8len);
documents_directory_u8len = WideCharToMultiByte(
CP_UTF8, 0, documents_directory, static_cast<int>(documents_directory_len), documents_directory_str.data(),
static_cast<int>(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(), m_user_directory = StringUtil::StdStringFromFormat("%s%c%s", documents_directory_str.c_str(),
FS_OSPATH_SEPERATOR_CHARACTER, "DuckStation"); FS_OSPATH_SEPERATOR_CHARACTER, "DuckStation");
} }
}
CoTaskMemFree(documents_directory); CoTaskMemFree(documents_directory);
} }
#elif __linux__ #elif __linux__