23 enum class charset_id : uint16_t {
47 constexpr charset_id wchar_t_charset = charset_id::utf16;
49 constexpr charset_id wchar_t_charset = charset_id::utf32;
55 template <
typename T_from,
typename T_to>
59 charset_id m_from, m_to;
67 m_from_wincp = to_encoding(from);
68 m_to_wincp = to_encoding(to);
70 m_handle = iconv_open(to_encoding(to), to_encoding(from));
71 if (m_handle == (iconv_t)-1)
72 throw std::runtime_error(
"iconv_open failed");
79 iconv_close(m_handle);
83 inline charset_id from_encoding()
const {
return m_from; }
84 inline charset_id to_encoding()
const {
return m_to; }
93 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>>
95 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to> &dst,
96 _In_reads_or_z_opt_(count_src)
const T_from* src, _In_
size_t count_src)
98 assert(src || !count_src);
99 count_src = stdex::strnlen(src, count_src);
100 if (!count_src) _Unlikely_
104 constexpr DWORD dwFlagsMBWC = MB_PRECOMPOSED;
105 constexpr DWORD dwFlagsWCMB = 0;
106 constexpr LPCCH lpDefaultChar = NULL;
108 _Analysis_assume_(src);
109 if (m_from_wincp == m_to_wincp) _Unlikely_{
110 dst.append(
reinterpret_cast<const T_to*
>(src), count_src);
114 if _Constexpr_ (
sizeof(T_from) ==
sizeof(
char) &&
sizeof(T_to) ==
sizeof(
wchar_t)) {
115 assert(count_src < INT_MAX || count_src == SIZE_MAX);
118 WCHAR szStackBuffer[1024 /
sizeof(WCHAR)];
119#pragma warning(suppress: 6387)
120 int cch = MultiByteToWideChar(
static_cast<UINT
>(m_from_wincp), dwFlagsMBWC,
reinterpret_cast<LPCCH
>(src),
static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer));
123 dst.append(
reinterpret_cast<const T_to*
>(szStackBuffer), count_src != SIZE_MAX ? wcsnlen(szStackBuffer, cch) :
static_cast<size_t>(cch) - 1);
126 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
128 cch = MultiByteToWideChar(
static_cast<UINT
>(m_from_wincp), dwFlagsMBWC,
reinterpret_cast<LPCCH
>(src),
static_cast<int>(count_src), NULL, 0);
129 std::unique_ptr<WCHAR[]> szBuffer(
new WCHAR[cch]);
130 cch = MultiByteToWideChar(
static_cast<UINT
>(m_from_wincp), dwFlagsMBWC,
reinterpret_cast<LPCCH
>(src),
static_cast<int>(count_src), szBuffer.get(), cch);
131 dst.append(
reinterpret_cast<const T_to*
>(szBuffer.get()), count_src != SIZE_MAX ? wcsnlen(szBuffer.get(), cch) :
static_cast<size_t>(cch) - 1);
134 throw std::runtime_error(
"MultiByteToWideChar failed");
137 if _Constexpr_ (
sizeof(T_from) ==
sizeof(
wchar_t) &&
sizeof(T_to) ==
sizeof(
char)) {
138 assert(count_src < INT_MAX || count_src == SIZE_MAX);
141 CHAR szStackBuffer[1024 /
sizeof(CHAR)];
142#pragma warning(suppress: 6387)
143 int cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB,
reinterpret_cast<LPCWCH
>(src),
static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, NULL);
146 dst.append(
reinterpret_cast<const T_to*
>(szStackBuffer), count_src != SIZE_MAX ? strnlen(szStackBuffer, cch) :
static_cast<size_t>(cch) - 1);
149 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
151 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB,
reinterpret_cast<LPCWCH
>(src),
static_cast<int>(count_src), NULL, 0, lpDefaultChar, NULL);
152 std::unique_ptr<CHAR[]> szBuffer(
new CHAR[cch]);
153 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB,
reinterpret_cast<LPCWCH
>(src),
static_cast<int>(count_src), szBuffer.get(), cch, lpDefaultChar, NULL);
154 dst.append(
reinterpret_cast<const T_to*
>(szBuffer.get()), count_src != SIZE_MAX ? strnlen(szBuffer.get(), cch) :
static_cast<size_t>(cch) - 1);
157 throw std::runtime_error(
"WideCharToMultiByte failed");
160 if _Constexpr_ (
sizeof(T_from) ==
sizeof(
char) &&
sizeof(T_to) ==
sizeof(
char)) {
161 assert(count_src < INT_MAX || count_src == SIZE_MAX);
164 WCHAR szStackBufferMBWC[512 /
sizeof(WCHAR)];
165#pragma warning(suppress: 6387)
166 int cch = MultiByteToWideChar(
static_cast<UINT
>(m_from_wincp), dwFlagsMBWC,
reinterpret_cast<LPCCH
>(src),
static_cast<int>(count_src), szStackBufferMBWC, _countof(szStackBufferMBWC));
169 size_t count_inter = count_src != SIZE_MAX ? wcsnlen(szStackBufferMBWC, cch) :
static_cast<size_t>(cch) - 1;
170 assert(count_inter < INT_MAX);
173 CHAR szStackBufferWCMB[512 /
sizeof(CHAR)];
174#pragma warning(suppress: 6387)
175 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC,
static_cast<int>(count_inter), szStackBufferWCMB, _countof(szStackBufferWCMB), lpDefaultChar, NULL);
178 dst.append(
reinterpret_cast<const T_to*
>(szStackBufferWCMB), strnlen(szStackBufferWCMB, cch));
181 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
183 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC,
static_cast<int>(count_inter), NULL, 0, lpDefaultChar, NULL);
184 std::unique_ptr<CHAR[]> szBufferWCMB(
new CHAR[cch]);
185 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC,
static_cast<int>(count_inter), szBufferWCMB.get(), cch, lpDefaultChar, NULL);
186 dst.append(
reinterpret_cast<const T_to*
>(szBufferWCMB.get()), strnlen(szBufferWCMB.get(), cch));
189 throw std::runtime_error(
"WideCharToMultiByte failed");
191 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
193 cch = MultiByteToWideChar(
static_cast<UINT
>(m_from_wincp), dwFlagsMBWC,
reinterpret_cast<LPCCH
>(src),
static_cast<int>(count_src), NULL, 0);
194 std::unique_ptr<WCHAR[]> szBufferMBWC(
new WCHAR[cch]);
195 cch = MultiByteToWideChar(
static_cast<UINT
>(m_from_wincp), dwFlagsMBWC,
reinterpret_cast<LPCCH
>(src),
static_cast<int>(count_src), szBufferMBWC.get(), cch);
196 size_t count_inter = count_src != SIZE_MAX ? wcsnlen(szBufferMBWC.get(), cch) :
static_cast<size_t>(cch) - 1;
199 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB, szBufferMBWC.get(),
static_cast<int>(count_inter), NULL, 0, lpDefaultChar, NULL);
200 std::unique_ptr<CHAR[]> szBufferWCMB(
new CHAR[cch]);
201 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB, szBufferMBWC.get(),
static_cast<int>(count_inter), szBufferWCMB.get(), cch, lpDefaultChar, NULL);
202 dst.append(
reinterpret_cast<const T_to*
>(szBufferWCMB.get()), strnlen(szBufferWCMB.get(), cch));
205 throw std::runtime_error(
"MultiByteToWideChar failed");
208 dst.reserve(dst.size() + count_src);
209 T_to buf[1024 /
sizeof(T_to)];
210 size_t src_size = stdex::mul(
sizeof(T_from), count_src);
212 T_to* output = &buf[0];
213 size_t output_size =
sizeof(buf);
215 iconv(m_handle,
const_cast<char**
>(
reinterpret_cast<const char**
>(&src)), &src_size,
reinterpret_cast<char**
>(&output), &output_size);
216 dst.append(buf,
reinterpret_cast<T_to*
>(
reinterpret_cast<char*
>(buf) +
sizeof(buf) - output_size));
221 throw std::runtime_error(
"iconv failed");
232 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>>
234 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
235 _In_z_
const T_from* src)
237 strcat(dst, src, SIZE_MAX);
246 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>,
class _Traits_from = std::
char_traits<T_from>,
class _Alloc_from = std::allocator<T_from>>
248 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
249 _In_
const std::basic_string<T_from, _Traits_from, _Alloc_from>& src)
251 strcat(dst, src.data(), src.size());
261 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>>
263 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
264 _In_reads_or_z_opt_(count_src)
const T_from* src, _In_
size_t count_src)
267 strcat(dst, src, count_src);
276 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>>
278 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
279 _In_z_
const T_from* src)
281 strcpy(dst, src, SIZE_MAX);
290 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>,
class _Traits_from = std::
char_traits<T_from>,
class _Alloc_from = std::allocator<T_from>>
292 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
293 _In_
const std::basic_string<T_from, _Traits_from, _Alloc_from>& src)
295 strcpy(dst, src.data(), src.size());
304 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>>
305 inline std::basic_string<T_to, _Traits_to, _Alloc_to>
convert(_In_reads_or_z_opt_(count_src)
const T_from* src, _In_
size_t count_src)
307 std::basic_string<T_to, _Traits_to, _Alloc_to> dst;
308 strcat(dst, src, count_src);
317 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>>
318 inline std::basic_string<T_to, _Traits_to, _Alloc_to>
convert(_In_z_
const T_from* src)
328 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>,
class _Traits_from = std::
char_traits<T_from>,
class _Alloc_from = std::allocator<T_from>>
329 inline std::basic_string<T_to, _Traits_to, _Alloc_to>
convert(_In_
const std::basic_string<T_from, _Traits_from, _Alloc_from>& src)
331 return convert(src.data(), src.size());
337 iconv(m_handle, NULL, NULL, NULL, NULL);
341 static charset_id system_charset()
344 return static_cast<charset_id
>(GetACP());
346 const char* lctype = nl_langinfo(CODESET);
347 if (strcmp(lctype,
"UTF-8") == 0)
return charset_id::utf8;
348 if (strcmp(lctype,
"UTF-16") == 0)
return charset_id::utf16;
349#if BYTE_ORDER == BIG_ENDIAN
350 if (strcmp(lctype,
"UTF-16BE") == 0)
return charset_id::utf16;
352 if (strcmp(lctype,
"UTF-16LE") == 0)
return charset_id::utf16;
354 if (strcmp(lctype,
"UTF-32") == 0)
return charset_id::utf32;
355#if BYTE_ORDER == BIG_ENDIAN
356 if (strcmp(lctype,
"UTF-32BE") == 0)
return charset_id::utf32;
358 if (strcmp(lctype,
"UTF-32LE") == 0)
return charset_id::utf32;
360 if (strcmp(lctype,
"CP1250") == 0)
return charset_id::windows1250;
361 if (strcmp(lctype,
"CP1251") == 0)
return charset_id::windows1251;
362 if (strcmp(lctype,
"CP1252") == 0)
return charset_id::windows1252;
363 return charset_id::system;
369 static UINT to_encoding(_In_ charset_id charset)
372 charset == charset_id::system ? GetACP() :
373 charset == charset_id::oem ? GetOEMCP() :
374 static_cast<UINT>(charset);
378 UINT m_from_wincp, m_to_wincp;
381 static const char* to_encoding(_In_ charset_id charset)
383 static const char*
const encodings[
static_cast<std::underlying_type_t<charset_id>
>(charset_id::_max)] = {
386#if BYTE_ORDER == BIG_ENDIAN
398 charset == charset_id::system ? nl_langinfo(CODESET) :
399 encodings[static_cast<std::underlying_type_t<charset_id>>(charset)];
418 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
421 _Inout_ std::wstring& dst,
422 _In_reads_or_z_opt_(count_src)
const char* src, _In_
size_t count_src,
423 _In_ charset_id charset = charset_id::system)
425 charset_encoder<char, wchar_t>(charset, wchar_t_charset).strcat(dst, src, count_src);
428 _Deprecated_(
"Use stdex::strcat")
429 inline
void str2wstr(
430 _Inout_ std::wstring& dst,
431 _In_reads_or_z_opt_(count_src) const
char* src, _In_
size_t count_src,
432 _In_ charset_id charset = charset_id::system)
434 strcat(dst, src, count_src, charset);
447 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
450 _Inout_ std::wstring& dst,
451 _In_
const std::string& src,
452 _In_ charset_id charset = charset_id::system)
454 strcat(dst, src.data(), src.size(), charset);
457 _Deprecated_(
"Use stdex::strcat")
458 inline
void str2wstr(
459 _Inout_ std::wstring& dst,
460 _In_ const std::
string& src,
461 _In_ charset_id charset = charset_id::system)
463 strcat(dst, src, charset);
477 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
480 _Inout_ std::wstring& dst,
481 _In_reads_or_z_opt_(count_src)
const char* src, _In_
size_t count_src,
482 _In_ charset_id charset = charset_id::system)
485 strcat(dst, src, count_src, charset);
498 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
501 _Inout_ std::wstring& dst,
502 _In_
const std::string& src,
503 _In_ charset_id charset = charset_id::system)
505 strcpy(dst, src.data(), src.size(), charset);
519 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
521 inline std::wstring str2wstr(
522 _In_z_
const char* src,
523 _In_ charset_id charset = charset_id::system)
526 strcat(dst, src, SIZE_MAX, charset);
542 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
544 inline std::wstring str2wstr(
545 _In_reads_or_z_opt_(count_src)
const char* src, _In_
size_t count_src,
546 _In_ charset_id charset = charset_id::system)
549 strcat(dst, src, count_src, charset);
564 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
566 inline std::wstring str2wstr(
567 _In_
const std::string& src,
568 _In_ charset_id charset = charset_id::system)
570 return str2wstr(src.c_str(), src.size(), charset);
584 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
587 _Inout_ std::string& dst,
588 _In_reads_or_z_opt_(count_src)
const wchar_t* src, _In_
size_t count_src,
589 _In_ charset_id charset = charset_id::system)
591 charset_encoder<wchar_t, char>(wchar_t_charset, charset).strcat(dst, src, count_src);
594 _Deprecated_(
"Use stdex::strcat")
595 inline
void wstr2str(
596 _Inout_ std::
string& dst,
597 _In_reads_or_z_opt_(count_src) const
wchar_t* src, _In_
size_t count_src,
598 _In_ charset_id charset = charset_id::system)
600 strcat(dst, src, count_src, charset);
613 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
616 _Inout_ std::string& dst,
617 _In_
const std::wstring& src,
618 _In_ charset_id charset = charset_id::system)
620 strcat(dst, src.c_str(), src.size(), charset);
623 _Deprecated_(
"Use stdex::strcat")
624 inline
void wstr2str(
625 _Inout_ std::
string& dst,
626 _In_ const std::wstring& src,
627 _In_ charset_id charset = charset_id::system)
629 strcat(dst, src, charset);
643 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
646 _Inout_ std::string& dst,
647 _In_reads_or_z_opt_(count_src)
const wchar_t* src, _In_
size_t count_src,
648 _In_ charset_id charset = charset_id::system)
651 strcat(dst, src, count_src, charset);
664 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
667 _Inout_ std::string& dst,
668 _In_
const std::wstring& src,
669 _In_ charset_id charset = charset_id::system)
671 strcpy(dst, src.data(), src.size(), charset);
685 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
687 inline std::string wstr2str(
688 _In_z_
const wchar_t* src,
689 _In_ charset_id charset = charset_id::system)
692 strcat(dst, src, SIZE_MAX, charset);
708 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
710 inline std::string wstr2str(
711 _In_reads_or_z_opt_(count_src)
const wchar_t* src, _In_
size_t count_src,
712 _In_ charset_id charset = charset_id::system)
715 strcat(dst, src, count_src, charset);
730 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
732 inline std::string wstr2str(
733 _In_
const std::wstring& src,
734 _In_ charset_id charset = charset_id::system)
736 return wstr2str(src.c_str(), src.size(), charset);
Encoding converter context.
Definition unicode.hpp:57
void strcpy(std::basic_string< T_to, _Traits_to, _Alloc_to > &dst, const std::basic_string< T_from, _Traits_from, _Alloc_from > &src)
Convert string.
Definition unicode.hpp:291
std::basic_string< T_to, _Traits_to, _Alloc_to > convert(const std::basic_string< T_from, _Traits_from, _Alloc_from > &src)
Return converted string.
Definition unicode.hpp:329
std::basic_string< T_to, _Traits_to, _Alloc_to > convert(const T_from *src)
Return converted string.
Definition unicode.hpp:318
void strcat(std::basic_string< T_to, _Traits_to, _Alloc_to > &dst, const std::basic_string< T_from, _Traits_from, _Alloc_from > &src)
Convert string and append to string.
Definition unicode.hpp:247
void strcpy(std::basic_string< T_to, _Traits_to, _Alloc_to > &dst, const T_from *src)
Convert string.
Definition unicode.hpp:277
void strcat(std::basic_string< T_to, _Traits_to, _Alloc_to > &dst, _In_reads_or_z_opt_(count_src) const T_from *src, size_t count_src)
Convert string and append to string.
Definition unicode.hpp:94
void strcat(std::basic_string< T_to, _Traits_to, _Alloc_to > &dst, const T_from *src)
Convert string and append to string.
Definition unicode.hpp:233
void strcpy(std::basic_string< T_to, _Traits_to, _Alloc_to > &dst, _In_reads_or_z_opt_(count_src) const T_from *src, size_t count_src)
Convert string.
Definition unicode.hpp:262
std::basic_string< T_to, _Traits_to, _Alloc_to > convert(_In_reads_or_z_opt_(count_src) const T_from *src, size_t count_src)
Return converted string.
Definition unicode.hpp:305