|
1 | 1 | #pragma once |
2 | 2 |
|
3 | | -#include <tchar.h> |
| 3 | +#include <Windows.h> |
4 | 4 |
|
5 | 5 | #include <type_traits> |
6 | 6 | #include <string> |
7 | 7 | #include <locale> |
8 | 8 | #include <codecvt> |
9 | 9 | #include <cstring> |
| 10 | +#include <stdexcept> |
| 11 | +#include <cstddef> |
10 | 12 |
|
11 | 13 | #include "libipc/utility/concept.h" |
12 | 14 | #include "libipc/platform/detail.h" |
@@ -34,34 +36,68 @@ using IsSameChar = ipc::require<is_same_char<T, S>::value, R>; |
34 | 36 | //////////////////////////////////////////////////////////////// |
35 | 37 |
|
36 | 38 | template <typename T = TCHAR> |
37 | | -constexpr auto to_tchar(ipc::string && str) -> IsSameChar<T, ipc::string, ipc::string &&> { |
38 | | - return std::move(str); |
| 39 | +constexpr auto to_tchar(ipc::string &&str) -> IsSameChar<T, ipc::string, ipc::string &&> { |
| 40 | + return std::move(str); // noconv |
39 | 41 | } |
40 | 42 |
|
| 43 | +/** |
| 44 | + * codecvt_utf8_utf16/std::wstring_convert is deprecated |
| 45 | + * @see https://codingtidbit.com/2020/02/09/c17-codecvt_utf8-is-deprecated/ |
| 46 | + * https://stackoverflow.com/questions/42946335/deprecated-header-codecvt-replacement |
| 47 | + * https://en.cppreference.com/w/cpp/locale/codecvt/in |
| 48 | + * https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar |
| 49 | +*/ |
41 | 50 | template <typename T = TCHAR> |
42 | | -constexpr auto to_tchar(ipc::string && str) -> IsSameChar<T, ipc::wstring> { |
43 | | - return std::wstring_convert< |
44 | | - std::codecvt_utf8_utf16<wchar_t>, |
45 | | - wchar_t, |
46 | | - ipc::mem::allocator<wchar_t>, |
47 | | - ipc::mem::allocator<char> |
48 | | - >{}.from_bytes(std::move(str)); |
49 | | -} |
50 | | - |
51 | | -template <typename T> |
52 | | -inline auto to_tchar(T* dst, char const * src, std::size_t size) -> IsSameChar<T, char, void> { |
53 | | - std::memcpy(dst, src, size); |
54 | | -} |
55 | | - |
56 | | -template <typename T> |
57 | | -inline auto to_tchar(T* dst, char const * src, std::size_t size) -> IsSameChar<T, wchar_t, void> { |
58 | | - auto wstr = std::wstring_convert< |
59 | | - std::codecvt_utf8_utf16<wchar_t>, |
60 | | - wchar_t, |
61 | | - ipc::mem::allocator<wchar_t>, |
62 | | - ipc::mem::allocator<char> |
63 | | - >{}.from_bytes(src, src + size); |
64 | | - std::memcpy(dst, wstr.data(), (ipc::detail::min)(wstr.size(), size)); |
| 51 | +auto to_tchar(ipc::string &&external) -> IsSameChar<T, ipc::wstring> { |
| 52 | + if (external.empty()) { |
| 53 | + return {}; // noconv |
| 54 | + } |
| 55 | +#if 0 // backup |
| 56 | + auto &fcodecvt = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(std::locale()); |
| 57 | + std::mbstate_t mb {}; |
| 58 | + ipc::wstring internal(external.size(), '\0'); |
| 59 | + char const *first = &external[0], *last = &external[external.size()]; |
| 60 | + std::size_t len = 0; |
| 61 | + while (first != last) { |
| 62 | + wchar_t *start = &internal[len], *end = &internal[internal.size()], *to_next; |
| 63 | + auto ret = fcodecvt.in(mb, first, last, first, |
| 64 | + start, end , to_next); |
| 65 | + switch (ret) { |
| 66 | + // no conversion, just copy code values |
| 67 | + case std::codecvt_base::noconv: |
| 68 | + internal.resize(len); |
| 69 | + for (; first != last; ++first) { |
| 70 | + internal.push_back((wchar_t)(unsigned char)*first); |
| 71 | + } |
| 72 | + break; |
| 73 | + // conversion completed |
| 74 | + case std::codecvt_base::ok: |
| 75 | + len += static_cast<size_t>(to_next - start); |
| 76 | + internal.resize(len); |
| 77 | + break; |
| 78 | + // not enough space in the output buffer or unexpected end of source buffer |
| 79 | + case std::codecvt_base::partial: |
| 80 | + if (to_next <= start) { |
| 81 | + throw std::range_error{"[to_tchar] bad conversion"}; |
| 82 | + } |
| 83 | + len += static_cast<size_t>(to_next - start); |
| 84 | + internal.resize(internal.size() + external.size()); |
| 85 | + break; |
| 86 | + // encountered a character that could not be converted |
| 87 | + default: // error |
| 88 | + throw std::range_error{"[to_tchar] bad conversion"}; |
| 89 | + } |
| 90 | + } |
| 91 | +#else |
| 92 | + // CP_ACP: The system default Windows ANSI code page. |
| 93 | + int size_needed = ::MultiByteToWideChar(CP_ACP, 0, &external[0], (int)external.size(), NULL, 0); |
| 94 | + if (size_needed <= 0) { |
| 95 | + return {}; |
| 96 | + } |
| 97 | + ipc::wstring internal(size_needed, L'\0'); |
| 98 | + ::MultiByteToWideChar(CP_ACP, 0, &external[0], (int)external.size(), &internal[0], size_needed); |
| 99 | +#endif |
| 100 | + return internal; |
65 | 101 | } |
66 | 102 |
|
67 | 103 | } // namespace detail |
|
0 commit comments