diff --git a/src/libipc/platform/to_tchar.h b/src/libipc/platform/to_tchar.h index df67b2d..d9a1fb6 100755 --- a/src/libipc/platform/to_tchar.h +++ b/src/libipc/platform/to_tchar.h @@ -1,12 +1,14 @@ #pragma once -#include +#include #include #include #include #include #include +#include +#include #include "libipc/utility/concept.h" #include "libipc/platform/detail.h" @@ -34,34 +36,68 @@ using IsSameChar = ipc::require::value, R>; //////////////////////////////////////////////////////////////// template -constexpr auto to_tchar(ipc::string && str) -> IsSameChar { - return std::move(str); +constexpr auto to_tchar(ipc::string &&str) -> IsSameChar { + return std::move(str); // noconv } +/** + * codecvt_utf8_utf16/std::wstring_convert is deprecated + * @see https://codingtidbit.com/2020/02/09/c17-codecvt_utf8-is-deprecated/ + * https://stackoverflow.com/questions/42946335/deprecated-header-codecvt-replacement + * https://en.cppreference.com/w/cpp/locale/codecvt/in + * https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar +*/ template -constexpr auto to_tchar(ipc::string && str) -> IsSameChar { - return std::wstring_convert< - std::codecvt_utf8_utf16, - wchar_t, - ipc::mem::allocator, - ipc::mem::allocator - >{}.from_bytes(std::move(str)); -} - -template -inline auto to_tchar(T* dst, char const * src, std::size_t size) -> IsSameChar { - std::memcpy(dst, src, size); -} - -template -inline auto to_tchar(T* dst, char const * src, std::size_t size) -> IsSameChar { - auto wstr = std::wstring_convert< - std::codecvt_utf8_utf16, - wchar_t, - ipc::mem::allocator, - ipc::mem::allocator - >{}.from_bytes(src, src + size); - std::memcpy(dst, wstr.data(), (ipc::detail::min)(wstr.size(), size)); +auto to_tchar(ipc::string &&external) -> IsSameChar { + if (external.empty()) { + return {}; // noconv + } +#if 0 // backup + auto &fcodecvt = std::use_facet>(std::locale()); + std::mbstate_t mb {}; + ipc::wstring internal(external.size(), '\0'); + char const *first = &external[0], *last = &external[external.size()]; + std::size_t len = 0; + while (first != last) { + wchar_t *start = &internal[len], *end = &internal[internal.size()], *to_next; + auto ret = fcodecvt.in(mb, first, last, first, + start, end , to_next); + switch (ret) { + // no conversion, just copy code values + case std::codecvt_base::noconv: + internal.resize(len); + for (; first != last; ++first) { + internal.push_back((wchar_t)(unsigned char)*first); + } + break; + // conversion completed + case std::codecvt_base::ok: + len += static_cast(to_next - start); + internal.resize(len); + break; + // not enough space in the output buffer or unexpected end of source buffer + case std::codecvt_base::partial: + if (to_next <= start) { + throw std::range_error{"[to_tchar] bad conversion"}; + } + len += static_cast(to_next - start); + internal.resize(internal.size() + external.size()); + break; + // encountered a character that could not be converted + default: // error + throw std::range_error{"[to_tchar] bad conversion"}; + } + } +#else + // CP_ACP: The system default Windows ANSI code page. + int size_needed = ::MultiByteToWideChar(CP_ACP, 0, &external[0], (int)external.size(), NULL, 0); + if (size_needed <= 0) { + return {}; + } + ipc::wstring internal(size_needed, L'\0'); + ::MultiByteToWideChar(CP_ACP, 0, &external[0], (int)external.size(), &internal[0], size_needed); +#endif + return internal; } } // namespace detail diff --git a/test/test_platform.cpp b/test/test_platform.cpp new file mode 100644 index 0000000..e5a6400 --- /dev/null +++ b/test/test_platform.cpp @@ -0,0 +1,28 @@ + +#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || \ + defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \ + defined(WINCE) || defined(_WIN32_WCE) + +#include +#include + +#include "test.h" + +#include "libipc/platform/to_tchar.h" + +TEST(Platform, to_tchar) { + char const *utf8 = "hello world, ÄãºÃ£¬¤³¤ó¤Ë¤Á¤Ï"; + wchar_t const *wstr = L"hello world, ÄãºÃ£¬¤³¤ó¤Ë¤Á¤Ï"; + { + ipc::string str = ipc::detail::to_tchar(utf8); + EXPECT_STREQ(str.c_str(), utf8); + } + { + ipc::wstring wtr = ipc::detail::to_tchar(utf8); + //std::wcout.imbue(std::locale()); + //std::wcout << wtr << "\n"; + EXPECT_STREQ(wtr.c_str(), wstr); + } +} + +#endif/*WIN*/