Skip to content

Commit df8bca2

Browse files
committed
codecvt_utf8_utf16/std::wstring_convert is deprecated
1 parent 8dadafa commit df8bca2

File tree

2 files changed

+90
-26
lines changed

2 files changed

+90
-26
lines changed

src/libipc/platform/to_tchar.h

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#pragma once
22

3-
#include <tchar.h>
3+
#include <Windows.h>
44

55
#include <type_traits>
66
#include <string>
77
#include <locale>
88
#include <codecvt>
99
#include <cstring>
10+
#include <stdexcept>
11+
#include <cstddef>
1012

1113
#include "libipc/utility/concept.h"
1214
#include "libipc/platform/detail.h"
@@ -34,34 +36,68 @@ using IsSameChar = ipc::require<is_same_char<T, S>::value, R>;
3436
////////////////////////////////////////////////////////////////
3537

3638
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
3941
}
4042

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+
*/
4150
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;
65101
}
66102

67103
} // namespace detail

test/test_platform.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || \
3+
defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \
4+
defined(WINCE) || defined(_WIN32_WCE)
5+
6+
#include <locale>
7+
#include <iostream>
8+
9+
#include "test.h"
10+
11+
#include "libipc/platform/to_tchar.h"
12+
13+
TEST(Platform, to_tchar) {
14+
char const *utf8 = "hello world, 低挫�こんにちは";
15+
wchar_t const *wstr = L"hello world, 低挫�こんにちは";
16+
{
17+
ipc::string str = ipc::detail::to_tchar<char>(utf8);
18+
EXPECT_STREQ(str.c_str(), utf8);
19+
}
20+
{
21+
ipc::wstring wtr = ipc::detail::to_tchar<wchar_t>(utf8);
22+
//std::wcout.imbue(std::locale());
23+
//std::wcout << wtr << "\n";
24+
EXPECT_STREQ(wtr.c_str(), wstr);
25+
}
26+
}
27+
28+
#endif/*WIN*/

0 commit comments

Comments
 (0)