20 std::runtime_error error(
const char*
function, DWORD code) {
21 std::ostringstream oss;
22 oss <<
"Function " <<
function <<
" failed with error code " << code;
23 return std::runtime_error{oss.str()};
26 bool size_t_to_int(std::size_t src, int32_t& dest) {
27 if (src >
static_cast<uint32_t
>(INT32_MAX))
29 dest =
static_cast<int32_t
>(src);
33 bool int_to_size_t(int32_t src, std::size_t& dest) {
34 if (src < 0 ||
static_cast<uint32_t
>(src) > SIZE_MAX)
36 dest =
static_cast<std::size_t
>(src);
40 int32_t convert_input_bytes_to_bytes(std::size_t nb) {
43 if (!size_t_to_int(nb, real_nb)) {
44 std::ostringstream oss;
45 oss <<
"Input buffer is too large at " << nb <<
" bytes";
46 throw std::runtime_error{oss.str()};
52 int32_t convert_input_bytes_to_chars(std::size_t nb) {
53 if (nb %
sizeof(WCHAR) != 0) {
54 std::ostringstream oss;
55 oss <<
"Buffer size invalid at " << nb <<
" bytes";
56 throw std::runtime_error{oss.str()};
59 const std::size_t nch = nb /
sizeof(WCHAR);
62 if (!size_t_to_int(nch, real_nch)) {
63 std::ostringstream oss;
64 oss <<
"Input buffer is too large at " << nch <<
" characters";
65 throw std::runtime_error{oss.str()};
71 template <
typename CharT>
72 std::vector<CharT> output_buffer(int32_t size) {
73 std::size_t real_size = 0;
75 if (!int_to_size_t(size, real_size)) {
76 std::ostringstream oss;
77 oss <<
"Buffer size invalid at " << size <<
" bytes";
78 throw std::runtime_error{oss.str()};
81 std::vector<CharT> buffer;
82 buffer.resize(real_size);
86 template <
typename CharT>
87 void verify_output(
const std::vector<CharT>& expected, int32_t _actual_size) {
88 std::size_t actual_size = 0;
90 if (!int_to_size_t(_actual_size, actual_size) || expected.size() != actual_size) {
91 std::ostringstream oss;
92 oss <<
"Expected output length " << expected.size() <<
", got " << _actual_size;
93 throw std::runtime_error{oss.str()};
99 std::wstring
widen(
const std::string& src) {
100 return widen(src.c_str(), src.size());
103 std::wstring
widen(
const void* src, std::size_t in_nb) {
104 const DWORD flags = MB_ERR_INVALID_CHARS;
106 const auto in_data =
reinterpret_cast<const char*
>(src);
107 const auto real_in_nb = convert_input_bytes_to_bytes(in_nb);
109 auto out_nch = ::MultiByteToWideChar(CP_UTF8, flags, in_data, real_in_nb, NULL, 0);
112 throw error(
"MultiByteToWideChar", GetLastError());
115 static_assert(
sizeof(
wchar_t) ==
sizeof(WCHAR),
"wchar_t != WCHAR");
116 auto out = output_buffer<wchar_t>(out_nch);
118 out_nch = ::MultiByteToWideChar(CP_UTF8, flags, in_data, real_in_nb, out.data(), out_nch);
121 throw error(
"MultiByteToWideChar", GetLastError());
124 verify_output(out, out_nch);
125 return {out.data(), out.size()};
128 std::string
narrow(
const std::wstring& src) {
129 static_assert(
sizeof(
wchar_t) ==
sizeof(WCHAR),
"wchar_t != WCHAR");
130 return narrow(src.c_str(), src.size() *
sizeof(std::wstring::value_type));
133 std::string
narrow(
const std::u16string& src) {
134 return narrow(src.c_str(), src.size() *
sizeof(std::u16string::value_type));
137 std::string
narrow(
const void* src, std::size_t in_nb) {
138 const DWORD flags = WC_ERR_INVALID_CHARS;
140 const auto in_data =
reinterpret_cast<const wchar_t*
>(src);
141 const auto in_nch = convert_input_bytes_to_chars(in_nb);
143 auto out_nb = ::WideCharToMultiByte(CP_UTF8, flags, in_data, in_nch, NULL, 0, NULL, NULL);
146 throw error(
"WideCharToMultiByte", GetLastError());
149 auto out = output_buffer<char>(out_nb);
151 out_nb = ::WideCharToMultiByte(CP_UTF8, flags, in_data, in_nch, out.data(), out_nb, NULL, NULL);
154 throw error(
"WideCharToMultiByte", GetLastError());
157 verify_output(out, out_nb);
158 return {out.data(), out.size()};
UTF-8 <-> UTF-16 conversion functions.
std::wstring widen(const std::string &)
std::string narrow(const std::wstring &)