23 enum class charset_id : uint16_t {
46 constexpr charset_id wchar_t_charset = charset_id::utf16;
48 constexpr charset_id wchar_t_charset = charset_id::utf32;
54 template <
typename T_from,
typename T_to>
58 charset_id m_from, m_to;
66 m_from_wincp = to_encoding(from);
67 m_to_wincp = to_encoding(to);
69 m_handle = iconv_open(to_encoding(to), to_encoding(from));
70 if (m_handle == (iconv_t)-1)
71 throw std::runtime_error(
"iconv_open failed");
78 iconv_close(m_handle);
82 inline charset_id from_encoding()
const {
return m_from; }
83 inline charset_id to_encoding()
const {
return m_to; }
92 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>>
94 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to> &dst,
95 _In_reads_or_z_opt_(count_src)
const T_from* src, _In_
size_t count_src)
97 assert(src || !count_src);
98 count_src = stdex::strnlen(src, count_src);
99 if (!count_src) _Unlikely_
103 constexpr DWORD dwFlagsMBWC = MB_PRECOMPOSED;
104 constexpr DWORD dwFlagsWCMB = 0;
105 constexpr LPCCH lpDefaultChar = NULL;
107 _Analysis_assume_(src);
108 if (m_from_wincp == m_to_wincp) _Unlikely_{
109 dst.append(
reinterpret_cast<const T_to*
>(src), count_src);
113 if _Constexpr_ (
sizeof(T_from) ==
sizeof(
char) &&
sizeof(T_to) ==
sizeof(
wchar_t)) {
114 assert(count_src < INT_MAX || count_src == SIZE_MAX);
117 WCHAR szStackBuffer[1024 /
sizeof(WCHAR)];
118#pragma warning(suppress: 6387)
119 int cch = MultiByteToWideChar(
static_cast<UINT
>(m_from_wincp), dwFlagsMBWC,
reinterpret_cast<LPCCH
>(src),
static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer));
122 dst.append(
reinterpret_cast<const T_to*
>(szStackBuffer), count_src != SIZE_MAX ? wcsnlen(szStackBuffer, cch) :
static_cast<size_t>(cch) - 1);
125 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
127 cch = MultiByteToWideChar(
static_cast<UINT
>(m_from_wincp), dwFlagsMBWC,
reinterpret_cast<LPCCH
>(src),
static_cast<int>(count_src), NULL, 0);
128 std::unique_ptr<WCHAR[]> szBuffer(
new WCHAR[cch]);
129 cch = MultiByteToWideChar(
static_cast<UINT
>(m_from_wincp), dwFlagsMBWC,
reinterpret_cast<LPCCH
>(src),
static_cast<int>(count_src), szBuffer.get(), cch);
130 dst.append(
reinterpret_cast<const T_to*
>(szBuffer.get()), count_src != SIZE_MAX ? wcsnlen(szBuffer.get(), cch) :
static_cast<size_t>(cch) - 1);
133 throw std::runtime_error(
"MultiByteToWideChar failed");
136 if _Constexpr_ (
sizeof(T_from) ==
sizeof(
wchar_t) &&
sizeof(T_to) ==
sizeof(
char)) {
137 assert(count_src < INT_MAX || count_src == SIZE_MAX);
140 CHAR szStackBuffer[1024 /
sizeof(CHAR)];
141#pragma warning(suppress: 6387)
142 int cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB,
reinterpret_cast<LPCWCH
>(src),
static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, NULL);
145 dst.append(
reinterpret_cast<const T_to*
>(szStackBuffer), count_src != SIZE_MAX ? strnlen(szStackBuffer, cch) :
static_cast<size_t>(cch) - 1);
148 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
150 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB,
reinterpret_cast<LPCWCH
>(src),
static_cast<int>(count_src), NULL, 0, lpDefaultChar, NULL);
151 std::unique_ptr<CHAR[]> szBuffer(
new CHAR[cch]);
152 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB,
reinterpret_cast<LPCWCH
>(src),
static_cast<int>(count_src), szBuffer.get(), cch, lpDefaultChar, NULL);
153 dst.append(
reinterpret_cast<const T_to*
>(szBuffer.get()), count_src != SIZE_MAX ? strnlen(szBuffer.get(), cch) :
static_cast<size_t>(cch) - 1);
156 throw std::runtime_error(
"WideCharToMultiByte failed");
159 if _Constexpr_ (
sizeof(T_from) ==
sizeof(
char) &&
sizeof(T_to) ==
sizeof(
char)) {
160 assert(count_src < INT_MAX || count_src == SIZE_MAX);
163 WCHAR szStackBufferMBWC[512 /
sizeof(WCHAR)];
164#pragma warning(suppress: 6387)
165 int cch = MultiByteToWideChar(
static_cast<UINT
>(m_from_wincp), dwFlagsMBWC,
reinterpret_cast<LPCCH
>(src),
static_cast<int>(count_src), szStackBufferMBWC, _countof(szStackBufferMBWC));
168 size_t count_inter = count_src != SIZE_MAX ? wcsnlen(szStackBufferMBWC, cch) :
static_cast<size_t>(cch) - 1;
169 assert(count_inter < INT_MAX);
172 CHAR szStackBufferWCMB[512 /
sizeof(CHAR)];
173#pragma warning(suppress: 6387)
174 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC,
static_cast<int>(count_inter), szStackBufferWCMB, _countof(szStackBufferWCMB), lpDefaultChar, NULL);
177 dst.append(
reinterpret_cast<const T_to*
>(szStackBufferWCMB), strnlen(szStackBufferWCMB, cch));
180 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
182 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC,
static_cast<int>(count_inter), NULL, 0, lpDefaultChar, NULL);
183 std::unique_ptr<CHAR[]> szBufferWCMB(
new CHAR[cch]);
184 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC,
static_cast<int>(count_inter), szBufferWCMB.get(), cch, lpDefaultChar, NULL);
185 dst.append(
reinterpret_cast<const T_to*
>(szBufferWCMB.get()), strnlen(szBufferWCMB.get(), cch));
188 throw std::runtime_error(
"WideCharToMultiByte failed");
190 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
192 cch = MultiByteToWideChar(
static_cast<UINT
>(m_from_wincp), dwFlagsMBWC,
reinterpret_cast<LPCCH
>(src),
static_cast<int>(count_src), NULL, 0);
193 std::unique_ptr<WCHAR[]> szBufferMBWC(
new WCHAR[cch]);
194 cch = MultiByteToWideChar(
static_cast<UINT
>(m_from_wincp), dwFlagsMBWC,
reinterpret_cast<LPCCH
>(src),
static_cast<int>(count_src), szBufferMBWC.get(), cch);
195 size_t count_inter = count_src != SIZE_MAX ? wcsnlen(szBufferMBWC.get(), cch) :
static_cast<size_t>(cch) - 1;
198 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB, szBufferMBWC.get(),
static_cast<int>(count_inter), NULL, 0, lpDefaultChar, NULL);
199 std::unique_ptr<CHAR[]> szBufferWCMB(
new CHAR[cch]);
200 cch = WideCharToMultiByte(
static_cast<UINT
>(m_to_wincp), dwFlagsWCMB, szBufferMBWC.get(),
static_cast<int>(count_inter), szBufferWCMB.get(), cch, lpDefaultChar, NULL);
201 dst.append(
reinterpret_cast<const T_to*
>(szBufferWCMB.get()), strnlen(szBufferWCMB.get(), cch));
204 throw std::runtime_error(
"MultiByteToWideChar failed");
207 dst.reserve(dst.size() + count_src);
208 T_to buf[1024 /
sizeof(T_to)];
209 size_t src_size = stdex::mul(
sizeof(T_from), count_src);
211 T_to* output = &buf[0];
212 size_t output_size =
sizeof(buf);
214 iconv(m_handle,
const_cast<char**
>(
reinterpret_cast<const char**
>(&src)), &src_size,
reinterpret_cast<char**
>(&output), &output_size);
215 dst.append(buf,
reinterpret_cast<T_to*
>(
reinterpret_cast<char*
>(buf) +
sizeof(buf) - output_size));
220 throw std::runtime_error(
"iconv failed");
231 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>>
233 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
234 _In_z_
const T_from* src)
236 strcat(dst, src, SIZE_MAX);
245 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>>
247 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
248 _In_
const std::basic_string<T_from, _Traits_from, _Alloc_from>& src)
250 strcat(dst, src.data(), src.size());
260 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>>
262 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
263 _In_reads_or_z_opt_(count_src)
const T_from* src, _In_
size_t count_src)
266 strcat(dst, src, count_src);
275 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>>
277 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
278 _In_z_
const T_from* src)
280 strcpy(dst, src, SIZE_MAX);
289 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>>
291 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
292 _In_
const std::basic_string<T_from, _Traits_from, _Alloc_from>& src)
294 strcpy(dst, src.data(), src.size());
303 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>>
304 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)
306 std::basic_string<T_to, _Traits_to, _Alloc_to> dst;
307 strcat(dst, src, count_src);
316 template <
class _Traits_to = std::
char_traits<T_to>,
class _Alloc_to = std::allocator<T_to>>
317 inline std::basic_string<T_to, _Traits_to, _Alloc_to>
convert(_In_z_
const T_from* src)
327 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>>
328 inline std::basic_string<T_to, _Traits_to, _Alloc_to>
convert(_In_
const std::basic_string<T_from, _Traits_from, _Alloc_from>& src)
330 return convert(src.data(), src.size());
336 iconv(m_handle, NULL, NULL, NULL, NULL);
340 static charset_id system_charset()
343 return static_cast<charset_id
>(GetACP());
345 const char* lctype = nl_langinfo(CODESET);
346 if (strcmp(lctype,
"UTF-8") == 0)
return charset_id::utf8;
347 if (strcmp(lctype,
"UTF-16") == 0)
return charset_id::utf16;
348#if BYTE_ORDER == BIG_ENDIAN
349 if (strcmp(lctype,
"UTF-16BE") == 0)
return charset_id::utf16;
351 if (strcmp(lctype,
"UTF-16LE") == 0)
return charset_id::utf16;
353 if (strcmp(lctype,
"UTF-32") == 0)
return charset_id::utf32;
354#if BYTE_ORDER == BIG_ENDIAN
355 if (strcmp(lctype,
"UTF-32BE") == 0)
return charset_id::utf32;
357 if (strcmp(lctype,
"UTF-32LE") == 0)
return charset_id::utf32;
359 if (strcmp(lctype,
"CP1250") == 0)
return charset_id::windows1250;
360 if (strcmp(lctype,
"CP1251") == 0)
return charset_id::windows1251;
361 if (strcmp(lctype,
"CP1252") == 0)
return charset_id::windows1252;
362 return charset_id::system;
368 static UINT to_encoding(_In_ charset_id charset)
371 charset == charset_id::system ? GetACP() :
372 charset == charset_id::oem ? GetOEMCP() :
373 static_cast<UINT>(charset);
377 UINT m_from_wincp, m_to_wincp;
380 static const char* to_encoding(_In_ charset_id charset)
382 static const char*
const encodings[
static_cast<std::underlying_type_t<charset_id>
>(charset_id::_max)] = {
385#if BYTE_ORDER == BIG_ENDIAN
397 charset == charset_id::system ? nl_langinfo(CODESET) :
398 encodings[static_cast<std::underlying_type_t<charset_id>>(charset)];
417 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
420 _Inout_ std::wstring& dst,
421 _In_reads_or_z_opt_(count_src)
const char* src, _In_
size_t count_src,
422 _In_ charset_id charset = charset_id::system)
424 charset_encoder<char, wchar_t>(charset, wchar_t_charset).strcat(dst, src, count_src);
427 _Deprecated_(
"Use stdex::strcat")
428 inline
void str2wstr(
429 _Inout_ std::wstring& dst,
430 _In_reads_or_z_opt_(count_src) const
char* src, _In_
size_t count_src,
431 _In_ charset_id charset = charset_id::system)
433 strcat(dst, src, count_src, charset);
446 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
449 _Inout_ std::wstring& dst,
450 _In_
const std::string& src,
451 _In_ charset_id charset = charset_id::system)
453 strcat(dst, src.data(), src.size(), charset);
456 _Deprecated_(
"Use stdex::strcat")
457 inline
void str2wstr(
458 _Inout_ std::wstring& dst,
459 _In_ const std::
string& src,
460 _In_ charset_id charset = charset_id::system)
462 strcat(dst, src, charset);
476 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
479 _Inout_ std::wstring& dst,
480 _In_reads_or_z_opt_(count_src)
const char* src, _In_
size_t count_src,
481 _In_ charset_id charset = charset_id::system)
484 strcat(dst, src, count_src, charset);
497 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
500 _Inout_ std::wstring& dst,
501 _In_
const std::string& src,
502 _In_ charset_id charset = charset_id::system)
504 strcpy(dst, src.data(), src.size(), charset);
518 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
520 inline std::wstring str2wstr(
521 _In_z_
const char* src,
522 _In_ charset_id charset = charset_id::system)
525 strcat(dst, src, SIZE_MAX, charset);
541 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
543 inline std::wstring str2wstr(
544 _In_reads_or_z_opt_(count_src)
const char* src, _In_
size_t count_src,
545 _In_ charset_id charset = charset_id::system)
548 strcat(dst, src, count_src, charset);
563 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
565 inline std::wstring str2wstr(
566 _In_
const std::string& src,
567 _In_ charset_id charset = charset_id::system)
569 return str2wstr(src.c_str(), src.size(), charset);
583 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
586 _Inout_ std::string& dst,
587 _In_reads_or_z_opt_(count_src)
const wchar_t* src, _In_
size_t count_src,
588 _In_ charset_id charset = charset_id::system)
590 charset_encoder<wchar_t, char>(wchar_t_charset, charset).strcat(dst, src, count_src);
593 _Deprecated_(
"Use stdex::strcat")
594 inline
void wstr2str(
595 _Inout_ std::
string& dst,
596 _In_reads_or_z_opt_(count_src) const
wchar_t* src, _In_
size_t count_src,
597 _In_ charset_id charset = charset_id::system)
599 strcat(dst, src, count_src, charset);
612 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
615 _Inout_ std::string& dst,
616 _In_
const std::wstring& src,
617 _In_ charset_id charset = charset_id::system)
619 strcat(dst, src.c_str(), src.size(), charset);
622 _Deprecated_(
"Use stdex::strcat")
623 inline
void wstr2str(
624 _Inout_ std::
string& dst,
625 _In_ const std::wstring& src,
626 _In_ charset_id charset = charset_id::system)
628 strcat(dst, src, charset);
642 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
645 _Inout_ std::string& dst,
646 _In_reads_or_z_opt_(count_src)
const wchar_t* src, _In_
size_t count_src,
647 _In_ charset_id charset = charset_id::system)
650 strcat(dst, src, count_src, charset);
663 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
666 _Inout_ std::string& dst,
667 _In_
const std::wstring& src,
668 _In_ charset_id charset = charset_id::system)
670 strcpy(dst, src.data(), src.size(), charset);
684 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
686 inline std::string wstr2str(
687 _In_z_
const wchar_t* src,
688 _In_ charset_id charset = charset_id::system)
691 strcat(dst, src, SIZE_MAX, charset);
707 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
709 inline std::string wstr2str(
710 _In_reads_or_z_opt_(count_src)
const wchar_t* src, _In_
size_t count_src,
711 _In_ charset_id charset = charset_id::system)
714 strcat(dst, src, count_src, charset);
729 _Deprecated_(
"For better performance, consider a reusable charset_encoder")
731 inline std::string wstr2str(
732 _In_
const std::wstring& src,
733 _In_ charset_id charset = charset_id::system)
735 return wstr2str(src.c_str(), src.size(), charset);
Encoding converter context.
Definition unicode.hpp:56
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:290
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:328
std::basic_string< T_to, _Traits_to, _Alloc_to > convert(const T_from *src)
Return converted string.
Definition unicode.hpp:317
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:246
void strcpy(std::basic_string< T_to, _Traits_to, _Alloc_to > &dst, const T_from *src)
Convert string.
Definition unicode.hpp:276
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:93
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:232
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:261
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:304