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