stdex
Additional custom or not Standard C++ covered algorithms
Loading...
Searching...
No Matches
unicode.hpp
1/*
2 SPDX-License-Identifier: MIT
3 Copyright © 2023 Amebis
4*/
5
6#pragma once
7
8#include "compat.hpp"
9#include "endian.hpp"
10#include "math.hpp"
11#include <stdint.h>
12#ifndef _WIN32
13#include <iconv.h>
14#include <langinfo.h>
15#endif
16#include <map>
17#include <memory>
18#include <string>
19
20namespace stdex
21{
22 enum class charset_id : uint16_t {
23#ifdef _WIN32
24 system = CP_ACP,
25 oem = CP_OEMCP,
26 utf7 = CP_UTF7,
27 utf8 = CP_UTF8,
28 utf16 = 1200 /*CP_WINUNICODE*/,
29 utf32 = 12000,
30 windows1250 = 1250,
31 windows1251 = 1251,
32 windows1252 = 1252,
33#else
34 system = 0,
35 utf7,
36 utf8,
37 utf16,
38 utf32,
39 windows1250,
40 windows1251,
41 windows1252,
42
43 _max
44#endif
45 };
46
47#ifdef _WIN32
48 constexpr charset_id wchar_t_charset = charset_id::utf16;
49#ifdef _UNICODE
50 constexpr charset_id system_charset = charset_id::utf16;
51#else
52 constexpr charset_id system_charset = charset_id::system;
53#endif
54#else
55 constexpr charset_id wchar_t_charset = charset_id::utf32;
56 constexpr charset_id system_charset = charset_id::system;
57#endif
58
62 template <typename T_from, typename T_to>
64 {
65 protected:
66 charset_id m_from, m_to;
67
68 public:
69 charset_encoder(_In_ charset_id from, _In_ charset_id to) :
70 m_from(from),
71 m_to(to)
72 {
73#ifdef _WIN32
74 m_from_wincp = to_encoding(from);
75 m_to_wincp = to_encoding(to);
76#else
77 m_handle = iconv_open(to_encoding(to), to_encoding(from));
78 if (m_handle == (iconv_t)-1)
79 throw std::system_error(errno, std::system_category(), "iconv_open failed");
80#endif
81 }
82
83#ifndef _WIN32
85 {
86 iconv_close(m_handle);
87 }
88#endif
89
90 inline charset_id from_encoding() const { return m_from; }
91 inline charset_id to_encoding() const { return m_to; }
92
100 template <class _Traits_to = std::char_traits<T_to>, class _Alloc_to = std::allocator<T_to>>
101 void strcat(
102 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to> &dst,
103 _In_reads_or_z_opt_(count_src) const T_from* src, _In_ size_t count_src)
104 {
105 _Assume_(src || !count_src);
106 count_src = stdex::strnlen(src, count_src);
107 if (!count_src) _Unlikely_
108 return;
109
110#ifdef _WIN32
111 constexpr DWORD dwFlagsMBWC = MB_PRECOMPOSED;
112 constexpr DWORD dwFlagsWCMB = 0;
113 constexpr LPCCH lpDefaultChar = NULL;
114
115 _Assume_(src);
116 if (m_from_wincp == m_to_wincp) _Unlikely_{
117 dst.append(reinterpret_cast<const T_to*>(src), count_src);
118 return;
119 }
120
121#pragma warning(suppress: 4127)
122 if _Constexpr_ (sizeof(T_from) == sizeof(char) && sizeof(T_to) == sizeof(wchar_t)) {
123 _Assume_(count_src < INT_MAX || count_src == SIZE_MAX);
124
125 // Try to convert to stack buffer first.
126 WCHAR szStackBuffer[1024 / sizeof(WCHAR)];
127#pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpMultiByteStr parameter wrong?
128 int cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), dwFlagsMBWC, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer));
129 if (cch) {
130 // Append from stack.
131 dst.append(reinterpret_cast<const T_to*>(szStackBuffer), count_src != SIZE_MAX ? wcsnlen(szStackBuffer, cch) : static_cast<size_t>(cch) - 1);
132 return;
133 }
134 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
135 // Query the required output size. Allocate buffer. Then convert again.
136 cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), dwFlagsMBWC, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), NULL, 0);
137 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
138 cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), dwFlagsMBWC, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), szBuffer.get(), cch);
139 dst.append(reinterpret_cast<const T_to*>(szBuffer.get()), count_src != SIZE_MAX ? wcsnlen(szBuffer.get(), cch) : static_cast<size_t>(cch) - 1);
140 return;
141 }
142 throw std::system_error(GetLastError(), std::system_category(), "MultiByteToWideChar failed");
143 }
144
145#pragma warning(suppress: 4127)
146 if _Constexpr_ (sizeof(T_from) == sizeof(wchar_t) && sizeof(T_to) == sizeof(char)) {
147 _Assume_(count_src < INT_MAX || count_src == SIZE_MAX);
148
149 // Try to convert to stack buffer first.
150 CHAR szStackBuffer[1024 / sizeof(CHAR)];
151#pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpWideCharStr parameter wrong?
152 int cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, reinterpret_cast<LPCWCH>(src), static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, NULL);
153 if (cch) {
154 // Copy from stack. Be careful not to include zero terminator.
155 dst.append(reinterpret_cast<const T_to*>(szStackBuffer), count_src != SIZE_MAX ? strnlen(szStackBuffer, cch) : static_cast<size_t>(cch) - 1);
156 return;
157 }
158 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
159 // Query the required output size. Allocate buffer. Then convert again.
160 cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, reinterpret_cast<LPCWCH>(src), static_cast<int>(count_src), NULL, 0, lpDefaultChar, NULL);
161 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
162 cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, reinterpret_cast<LPCWCH>(src), static_cast<int>(count_src), szBuffer.get(), cch, lpDefaultChar, NULL);
163 dst.append(reinterpret_cast<const T_to*>(szBuffer.get()), count_src != SIZE_MAX ? strnlen(szBuffer.get(), cch) : static_cast<size_t>(cch) - 1);
164 return;
165 }
166 throw std::system_error(GetLastError(), std::system_category(), "WideCharToMultiByte failed");
167 }
168
169#pragma warning(suppress: 4127)
170 if _Constexpr_ (sizeof(T_from) == sizeof(char) && sizeof(T_to) == sizeof(char)) {
171 _Assume_(count_src < INT_MAX || count_src == SIZE_MAX);
172
173 // Try to convert to stack buffer first.
174 WCHAR szStackBufferMBWC[512 / sizeof(WCHAR)];
175#pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpMultiByteStr parameter wrong?
176 int cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), dwFlagsMBWC, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), szStackBufferMBWC, _countof(szStackBufferMBWC));
177 if (cch) {
178 // Append from stack.
179 size_t count_inter = count_src != SIZE_MAX ? wcsnlen(szStackBufferMBWC, cch) : static_cast<size_t>(cch) - 1;
180 _Assume_(count_inter < INT_MAX);
181
182 // Try to convert to stack buffer first.
183 CHAR szStackBufferWCMB[512 / sizeof(CHAR)];
184#pragma warning(suppress: 6387) // Testing indicates szStackBufferMBWC may be NULL when count_inter is also 0. Is SAL of the lpWideCharStr parameter wrong?
185 cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC, static_cast<int>(count_inter), szStackBufferWCMB, _countof(szStackBufferWCMB), lpDefaultChar, NULL);
186 if (cch) {
187 // Copy from stack. Be careful not to include zero terminator.
188 dst.append(reinterpret_cast<const T_to*>(szStackBufferWCMB), strnlen(szStackBufferWCMB, cch));
189 return;
190 }
191 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
192 // Query the required output size. Allocate buffer. Then convert again.
193 cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC, static_cast<int>(count_inter), NULL, 0, lpDefaultChar, NULL);
194 std::unique_ptr<CHAR[]> szBufferWCMB(new CHAR[cch]);
195 cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC, static_cast<int>(count_inter), szBufferWCMB.get(), cch, lpDefaultChar, NULL);
196 dst.append(reinterpret_cast<const T_to*>(szBufferWCMB.get()), strnlen(szBufferWCMB.get(), cch));
197 return;
198 }
199 throw std::system_error(GetLastError(), std::system_category(), "WideCharToMultiByte failed");
200 }
201 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
202 // Query the required output size. Allocate buffer. Then convert again.
203 cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), dwFlagsMBWC, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), NULL, 0);
204 std::unique_ptr<WCHAR[]> szBufferMBWC(new WCHAR[cch]);
205 cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), dwFlagsMBWC, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), szBufferMBWC.get(), cch);
206 size_t count_inter = count_src != SIZE_MAX ? wcsnlen(szBufferMBWC.get(), cch) : static_cast<size_t>(cch) - 1;
207
208 // Query the required output size. Allocate buffer. Then convert again.
209 cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, szBufferMBWC.get(), static_cast<int>(count_inter), NULL, 0, lpDefaultChar, NULL);
210 std::unique_ptr<CHAR[]> szBufferWCMB(new CHAR[cch]);
211 cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, szBufferMBWC.get(), static_cast<int>(count_inter), szBufferWCMB.get(), cch, lpDefaultChar, NULL);
212 dst.append(reinterpret_cast<const T_to*>(szBufferWCMB.get()), strnlen(szBufferWCMB.get(), cch));
213 return;
214 }
215 throw std::system_error(GetLastError(), std::system_category(), "MultiByteToWideChar failed");
216 }
217#else
218 dst.reserve(dst.size() + count_src);
219 T_to buf[1024 / sizeof(T_to)];
220 size_t src_size = stdex::mul(sizeof(T_from), count_src);
221 for (;;) {
222 T_to* output = &buf[0];
223 size_t output_size = sizeof(buf);
224 errno = 0;
225 iconv(m_handle, const_cast<char**>(reinterpret_cast<const char**>(&src)), &src_size, reinterpret_cast<char**>(&output), &output_size);
226 dst.append(buf, reinterpret_cast<T_to*>(reinterpret_cast<char*>(buf) + sizeof(buf) - output_size));
227 if (!errno)
228 break;
229 if (errno == E2BIG)
230 continue;
231 throw std::system_error(errno, std::system_category(), "iconv failed");
232 }
233#endif
234 }
235
242 template <class _Traits_to = std::char_traits<T_to>, class _Alloc_to = std::allocator<T_to>>
243 inline void strcat(
244 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
245 _In_z_ const T_from* src)
246 {
247 strcat(dst, src, SIZE_MAX);
248 }
249
256 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>>
257 inline void strcat(
258 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
259 _In_ const std::basic_string<T_from, _Traits_from, _Alloc_from>& src)
260 {
261 strcat(dst, src.data(), src.size());
262 }
263
271 template <class _Traits_to = std::char_traits<T_to>, class _Alloc_to = std::allocator<T_to>>
272 inline void strcpy(
273 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
274 _In_reads_or_z_opt_(count_src) const T_from* src, _In_ size_t count_src)
275 {
276 dst.clear();
277 strcat(dst, src, count_src);
278 }
279
286 template <class _Traits_to = std::char_traits<T_to>, class _Alloc_to = std::allocator<T_to>>
287 inline void strcpy(
288 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
289 _In_z_ const T_from* src)
290 {
291 strcpy(dst, src, SIZE_MAX);
292 }
293
300 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>>
301 inline void strcpy(
302 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
303 _In_ const std::basic_string<T_from, _Traits_from, _Alloc_from>& src)
304 {
305 strcpy(dst, src.data(), src.size());
306 }
307
314 template <class _Traits_to = std::char_traits<T_to>, class _Alloc_to = std::allocator<T_to>>
315 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)
316 {
317 std::basic_string<T_to, _Traits_to, _Alloc_to> dst;
318 strcat(dst, src, count_src);
319 return dst;
320 }
321
327 template <class _Traits_to = std::char_traits<T_to>, class _Alloc_to = std::allocator<T_to>>
328 inline std::basic_string<T_to, _Traits_to, _Alloc_to> convert(_In_z_ const T_from* src)
329 {
330 return convert(src, SIZE_MAX);
331 }
332
338 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>>
339 inline std::basic_string<T_to, _Traits_to, _Alloc_to> convert(_In_ const std::basic_string<T_from, _Traits_from, _Alloc_from>& src)
340 {
341 return convert(src.data(), src.size());
342 }
343
344 inline void clear()
345 {
346#ifndef _WIN32
347 iconv(m_handle, NULL, NULL, NULL, NULL);
348#endif
349 }
350
351 static charset_id system_charset()
352 {
353#ifdef _WIN32
354 return static_cast<charset_id>(GetACP());
355#else
356 static const std::map<const char*, charset_id> charsets = {
357 { "UNICODE-1-1-UTF-7", charset_id::utf7 },
358 { "UTF-7", charset_id::utf7 },
359 { "CSUNICODE11UTF7", charset_id::utf7 },
360
361 { "UTF-8", charset_id::utf8 },
362 { "UTF8", charset_id::utf8 },
363
364 { "UTF-16", charset_id::utf16 },
365#if BYTE_ORDER == BIG_ENDIAN
366 { "UTF-16BE", charset_id::utf16 },
367#else
368 { "UTF-16LE", charset_id::utf16 },
369#endif
370
371 { "UTF-32", charset_id::utf32 },
372#if BYTE_ORDER == BIG_ENDIAN
373 { "UTF-32BE", charset_id::utf32 },
374#else
375 { "UTF-32LE", charset_id::utf32 },
376#endif
377
378 { "CP1250", charset_id::windows1250 },
379 { "MS-EE", charset_id::windows1250 },
380 { "WINDOWS-1250", charset_id::windows1250 },
381
382 { "CP1251", charset_id::windows1251 },
383 { "MS-CYRL", charset_id::windows1251 },
384 { "WINDOWS-1251", charset_id::windows1251 },
385
386 { "CP1252", charset_id::windows1252 },
387 { "MS-ANSI", charset_id::windows1252 },
388 { "WINDOWS-1252", charset_id::windows1252 },
389 };
390 const char* lctype = nl_langinfo(CODESET);
391 if (auto el = charsets.find(lctype); el != charsets.end())
392 return el->second;
393 return charset_id::system;
394#endif
395 }
396
397#ifdef _WIN32
398 protected:
399 static UINT to_encoding(_In_ charset_id charset)
400 {
401 return
402 charset == charset_id::system ? GetACP() :
403 charset == charset_id::oem ? GetOEMCP() :
404 static_cast<UINT>(charset);
405 }
406
407 protected:
408 UINT m_from_wincp, m_to_wincp;
409#else
410 protected:
411 static const char* to_encoding(_In_ charset_id charset)
412 {
413 static const char* const encodings[static_cast<std::underlying_type_t<charset_id>>(charset_id::_max)] = {
414 "", // system
415 "UTF-7", // utf7
416 "UTF-8", // utf8
417#if BYTE_ORDER == BIG_ENDIAN
418 "UTF-16BE", // utf16
419 "UTF-32BE", // utf32
420#else
421 "UTF-16LE", // utf16
422 "UTF-32LE", // utf32
423#endif
424 "CP1250", // windows1250
425 "CP1251", // windows1251
426 "CP1252", // windows1252
427 };
428 return
429 charset == charset_id::system ? nl_langinfo(CODESET) :
430 encodings[static_cast<std::underlying_type_t<charset_id>>(charset)];
431 }
432
433 protected:
434 iconv_t m_handle;
435#endif
436 };
437
448#ifndef _WIN32
449 _Deprecated_("For better performance, consider a reusable charset_encoder")
450#endif
451 inline void strcat(
452 _Inout_ std::wstring& dst,
453 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
454 _In_ charset_id charset = charset_id::system)
455 {
456 charset_encoder<char, wchar_t>(charset, wchar_t_charset).strcat(dst, src, count_src);
457 }
458
459 _Deprecated_("Use stdex::strcat")
460 inline void str2wstr(
461 _Inout_ std::wstring& dst,
462 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
463 _In_ charset_id charset = charset_id::system)
464 {
465 strcat(dst, src, count_src, charset);
466 }
467
477#ifndef _WIN32
478 _Deprecated_("For better performance, consider a reusable charset_encoder")
479#endif
480 inline void strcat(
481 _Inout_ std::wstring& dst,
482 _In_ const std::string& src,
483 _In_ charset_id charset = charset_id::system)
484 {
485 strcat(dst, src.data(), src.size(), charset);
486 }
487
488 _Deprecated_("Use stdex::strcat")
489 inline void str2wstr(
490 _Inout_ std::wstring& dst,
491 _In_ const std::string& src,
492 _In_ charset_id charset = charset_id::system)
493 {
494 strcat(dst, src, charset);
495 }
496
507#ifndef _WIN32
508 _Deprecated_("For better performance, consider a reusable charset_encoder")
509#endif
510 inline void strcpy(
511 _Inout_ std::wstring& dst,
512 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
513 _In_ charset_id charset = charset_id::system)
514 {
515 dst.clear();
516 strcat(dst, src, count_src, charset);
517 }
518
528#ifndef _WIN32
529 _Deprecated_("For better performance, consider a reusable charset_encoder")
530#endif
531 inline void strcpy(
532 _Inout_ std::wstring& dst,
533 _In_ const std::string& src,
534 _In_ charset_id charset = charset_id::system)
535 {
536 strcpy(dst, src.data(), src.size(), charset);
537 }
538
549#ifndef _WIN32
550 _Deprecated_("For better performance, consider a reusable charset_encoder")
551#endif
552 inline std::wstring str2wstr(
553 _In_z_ const char* src,
554 _In_ charset_id charset = charset_id::system)
555 {
556 std::wstring dst;
557 strcat(dst, src, SIZE_MAX, charset);
558 return dst;
559 }
560
572#ifndef _WIN32
573 _Deprecated_("For better performance, consider a reusable charset_encoder")
574#endif
575 inline std::wstring str2wstr(
576 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
577 _In_ charset_id charset = charset_id::system)
578 {
579 std::wstring dst;
580 strcat(dst, src, count_src, charset);
581 return dst;
582 }
583
594#ifndef _WIN32
595 _Deprecated_("For better performance, consider a reusable charset_encoder")
596#endif
597 inline std::wstring str2wstr(
598 _In_ const std::string& src,
599 _In_ charset_id charset = charset_id::system)
600 {
601 return str2wstr(src.c_str(), src.size(), charset);
602 }
603
614#ifndef _WIN32
615 _Deprecated_("For better performance, consider a reusable charset_encoder")
616#endif
617 inline void strcat(
618 _Inout_ std::string& dst,
619 _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
620 _In_ charset_id charset = charset_id::system)
621 {
622 charset_encoder<wchar_t, char>(wchar_t_charset, charset).strcat(dst, src, count_src);
623 }
624
625 _Deprecated_("Use stdex::strcat")
626 inline void wstr2str(
627 _Inout_ std::string& dst,
628 _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
629 _In_ charset_id charset = charset_id::system)
630 {
631 strcat(dst, src, count_src, charset);
632 }
633
643#ifndef _WIN32
644 _Deprecated_("For better performance, consider a reusable charset_encoder")
645#endif
646 inline void strcat(
647 _Inout_ std::string& dst,
648 _In_ const std::wstring& src,
649 _In_ charset_id charset = charset_id::system)
650 {
651 strcat(dst, src.c_str(), src.size(), charset);
652 }
653
654 _Deprecated_("Use stdex::strcat")
655 inline void wstr2str(
656 _Inout_ std::string& dst,
657 _In_ const std::wstring& src,
658 _In_ charset_id charset = charset_id::system)
659 {
660 strcat(dst, src, charset);
661 }
662
673#ifndef _WIN32
674 _Deprecated_("For better performance, consider a reusable charset_encoder")
675#endif
676 inline void strcpy(
677 _Inout_ std::string& dst,
678 _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
679 _In_ charset_id charset = charset_id::system)
680 {
681 dst.clear();
682 strcat(dst, src, count_src, charset);
683 }
684
694#ifndef _WIN32
695 _Deprecated_("For better performance, consider a reusable charset_encoder")
696#endif
697 inline void strcpy(
698 _Inout_ std::string& dst,
699 _In_ const std::wstring& src,
700 _In_ charset_id charset = charset_id::system)
701 {
702 strcpy(dst, src.data(), src.size(), charset);
703 }
704
715#ifndef _WIN32
716 _Deprecated_("For better performance, consider a reusable charset_encoder")
717#endif
718 inline std::string wstr2str(
719 _In_z_ const wchar_t* src,
720 _In_ charset_id charset = charset_id::system)
721 {
722 std::string dst;
723 strcat(dst, src, SIZE_MAX, charset);
724 return dst;
725 }
726
738#ifndef _WIN32
739 _Deprecated_("For better performance, consider a reusable charset_encoder")
740#endif
741 inline std::string wstr2str(
742 _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
743 _In_ charset_id charset = charset_id::system)
744 {
745 std::string dst;
746 strcat(dst, src, count_src, charset);
747 return dst;
748 }
749
760#ifndef _WIN32
761 _Deprecated_("For better performance, consider a reusable charset_encoder")
762#endif
763 inline std::string wstr2str(
764 _In_ const std::wstring& src,
765 _In_ charset_id charset = charset_id::system)
766 {
767 return wstr2str(src.c_str(), src.size(), charset);
768 }
769}
Encoding converter context.
Definition unicode.hpp:64
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:301
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:339
std::basic_string< T_to, _Traits_to, _Alloc_to > convert(const T_from *src)
Return converted string.
Definition unicode.hpp:328
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:257
void strcpy(std::basic_string< T_to, _Traits_to, _Alloc_to > &dst, const T_from *src)
Convert string.
Definition unicode.hpp:287
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:101
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:243
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:272
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:315