mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
codecvt_utf8_utf16/std::wstring_convert is deprecated
This commit is contained in:
parent
8dadafab9a
commit
df8bca22c3
@ -1,12 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <tchar.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
#include "libipc/utility/concept.h"
|
#include "libipc/utility/concept.h"
|
||||||
#include "libipc/platform/detail.h"
|
#include "libipc/platform/detail.h"
|
||||||
@ -34,34 +36,68 @@ using IsSameChar = ipc::require<is_same_char<T, S>::value, R>;
|
|||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template <typename T = TCHAR>
|
template <typename T = TCHAR>
|
||||||
constexpr auto to_tchar(ipc::string && str) -> IsSameChar<T, ipc::string, ipc::string &&> {
|
constexpr auto to_tchar(ipc::string &&str) -> IsSameChar<T, ipc::string, ipc::string &&> {
|
||||||
return std::move(str);
|
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 <typename T = TCHAR>
|
template <typename T = TCHAR>
|
||||||
constexpr auto to_tchar(ipc::string && str) -> IsSameChar<T, ipc::wstring> {
|
auto to_tchar(ipc::string &&external) -> IsSameChar<T, ipc::wstring> {
|
||||||
return std::wstring_convert<
|
if (external.empty()) {
|
||||||
std::codecvt_utf8_utf16<wchar_t>,
|
return {}; // noconv
|
||||||
wchar_t,
|
}
|
||||||
ipc::mem::allocator<wchar_t>,
|
#if 0 // backup
|
||||||
ipc::mem::allocator<char>
|
auto &fcodecvt = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(std::locale());
|
||||||
>{}.from_bytes(std::move(str));
|
std::mbstate_t mb {};
|
||||||
}
|
ipc::wstring internal(external.size(), '\0');
|
||||||
|
char const *first = &external[0], *last = &external[external.size()];
|
||||||
template <typename T>
|
std::size_t len = 0;
|
||||||
inline auto to_tchar(T* dst, char const * src, std::size_t size) -> IsSameChar<T, char, void> {
|
while (first != last) {
|
||||||
std::memcpy(dst, src, size);
|
wchar_t *start = &internal[len], *end = &internal[internal.size()], *to_next;
|
||||||
}
|
auto ret = fcodecvt.in(mb, first, last, first,
|
||||||
|
start, end , to_next);
|
||||||
template <typename T>
|
switch (ret) {
|
||||||
inline auto to_tchar(T* dst, char const * src, std::size_t size) -> IsSameChar<T, wchar_t, void> {
|
// no conversion, just copy code values
|
||||||
auto wstr = std::wstring_convert<
|
case std::codecvt_base::noconv:
|
||||||
std::codecvt_utf8_utf16<wchar_t>,
|
internal.resize(len);
|
||||||
wchar_t,
|
for (; first != last; ++first) {
|
||||||
ipc::mem::allocator<wchar_t>,
|
internal.push_back((wchar_t)(unsigned char)*first);
|
||||||
ipc::mem::allocator<char>
|
}
|
||||||
>{}.from_bytes(src, src + size);
|
break;
|
||||||
std::memcpy(dst, wstr.data(), (ipc::detail::min)(wstr.size(), size));
|
// conversion completed
|
||||||
|
case std::codecvt_base::ok:
|
||||||
|
len += static_cast<size_t>(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<size_t>(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
|
} // namespace detail
|
||||||
|
|||||||
28
test/test_platform.cpp
Normal file
28
test/test_platform.cpp
Normal file
@ -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 <locale>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
#include "libipc/platform/to_tchar.h"
|
||||||
|
|
||||||
|
TEST(Platform, to_tchar) {
|
||||||
|
char const *utf8 = "hello world, 低挫<E4BD8E>こんにちは";
|
||||||
|
wchar_t const *wstr = L"hello world, 低挫<E4BD8E>こんにちは";
|
||||||
|
{
|
||||||
|
ipc::string str = ipc::detail::to_tchar<char>(utf8);
|
||||||
|
EXPECT_STREQ(str.c_str(), utf8);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ipc::wstring wtr = ipc::detail::to_tchar<wchar_t>(utf8);
|
||||||
|
//std::wcout.imbue(std::locale());
|
||||||
|
//std::wcout << wtr << "\n";
|
||||||
|
EXPECT_STREQ(wtr.c_str(), wstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif/*WIN*/
|
||||||
Loading…
x
Reference in New Issue
Block a user