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 <assert.h>
13#include <stdint.h>
14#ifndef _WIN32
15#include <iconv.h>
16#include <langinfo.h>
17#endif
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 utf8 = CP_UTF8,
28 utf16 = 1200 /*CP_WINUNICODE*/,
29 windows1250 = 1250,
30 windows1251 = 1251,
31 windows1252 = 1252,
32#else
33 system = 0,
34 utf8,
35 utf16,
36 utf32,
37 windows1250,
38 windows1251,
39 windows1252,
40
41 _max
42#endif
43 };
44
45#ifdef _WIN32
46 constexpr charset_id wchar_t_charset = charset_id::utf16;
47#else
48 constexpr charset_id wchar_t_charset = charset_id::utf32;
49#endif
50
54 template <typename T_from, typename T_to>
56 {
57 protected:
58 charset_id m_from, m_to;
59
60 public:
61 charset_encoder(_In_ charset_id from, _In_ charset_id to) :
62 m_from(from),
63 m_to(to)
64 {
65#ifdef _WIN32
66 m_from_wincp = to_encoding(from);
67 m_to_wincp = to_encoding(to);
68#else
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");
72#endif
73 }
74
75#ifndef _WIN32
77 {
78 iconv_close(m_handle);
79 }
80#endif
81
82 inline charset_id from_encoding() const { return m_from; }
83 inline charset_id to_encoding() const { return m_to; }
84
92 template <class _Traits_to = std::char_traits<T_to>, class _Alloc_to = std::allocator<T_to>>
93 void strcat(
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)
96 {
97 assert(src || !count_src);
98 count_src = stdex::strnlen(src, count_src);
99 if (!count_src) _Unlikely_
100 return;
101
102#ifdef _WIN32
103 constexpr DWORD dwFlagsMBWC = MB_PRECOMPOSED;
104 constexpr DWORD dwFlagsWCMB = 0;
105 constexpr LPCCH lpDefaultChar = NULL;
106
107 _Analysis_assume_(src);
108 if (m_from_wincp == m_to_wincp) _Unlikely_{
109 dst.append(reinterpret_cast<const T_to*>(src), count_src);
110 return;
111 }
112
113 if _Constexpr_ (sizeof(T_from) == sizeof(char) && sizeof(T_to) == sizeof(wchar_t)) {
114 assert(count_src < INT_MAX || count_src == SIZE_MAX);
115
116 // Try to convert to stack buffer first.
117 WCHAR szStackBuffer[1024 / sizeof(WCHAR)];
118#pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpMultiByteStr parameter wrong?
119 int cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), dwFlagsMBWC, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer));
120 if (cch) {
121 // Append from stack.
122 dst.append(reinterpret_cast<const T_to*>(szStackBuffer), count_src != SIZE_MAX ? wcsnlen(szStackBuffer, cch) : static_cast<size_t>(cch) - 1);
123 return;
124 }
125 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
126 // Query the required output size. Allocate buffer. Then convert again.
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);
131 return;
132 }
133 throw std::runtime_error("MultiByteToWideChar failed");
134 }
135
136 if _Constexpr_ (sizeof(T_from) == sizeof(wchar_t) && sizeof(T_to) == sizeof(char)) {
137 assert(count_src < INT_MAX || count_src == SIZE_MAX);
138
139 // Try to convert to stack buffer first.
140 CHAR szStackBuffer[1024 / sizeof(CHAR)];
141#pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpWideCharStr parameter wrong?
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);
143 if (cch) {
144 // Copy from stack. Be careful not to include zero terminator.
145 dst.append(reinterpret_cast<const T_to*>(szStackBuffer), count_src != SIZE_MAX ? strnlen(szStackBuffer, cch) : static_cast<size_t>(cch) - 1);
146 return;
147 }
148 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
149 // Query the required output size. Allocate buffer. Then convert again.
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);
154 return;
155 }
156 throw std::runtime_error("WideCharToMultiByte failed");
157 }
158
159 if _Constexpr_ (sizeof(T_from) == sizeof(char) && sizeof(T_to) == sizeof(char)) {
160 assert(count_src < INT_MAX || count_src == SIZE_MAX);
161
162 // Try to convert to stack buffer first.
163 WCHAR szStackBufferMBWC[512 / sizeof(WCHAR)];
164#pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpMultiByteStr parameter wrong?
165 int cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), dwFlagsMBWC, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), szStackBufferMBWC, _countof(szStackBufferMBWC));
166 if (cch) {
167 // Append from stack.
168 size_t count_inter = count_src != SIZE_MAX ? wcsnlen(szStackBufferMBWC, cch) : static_cast<size_t>(cch) - 1;
169 assert(count_inter < INT_MAX);
170
171 // Try to convert to stack buffer first.
172 CHAR szStackBufferWCMB[512 / sizeof(CHAR)];
173#pragma warning(suppress: 6387) // Testing indicates szStackBufferMBWC may be NULL when count_inter is also 0. Is SAL of the lpWideCharStr parameter wrong?
174 cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC, static_cast<int>(count_inter), szStackBufferWCMB, _countof(szStackBufferWCMB), lpDefaultChar, NULL);
175 if (cch) {
176 // Copy from stack. Be careful not to include zero terminator.
177 dst.append(reinterpret_cast<const T_to*>(szStackBufferWCMB), strnlen(szStackBufferWCMB, cch));
178 return;
179 }
180 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
181 // Query the required output size. Allocate buffer. Then convert again.
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));
186 return;
187 }
188 throw std::runtime_error("WideCharToMultiByte failed");
189 }
190 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
191 // Query the required output size. Allocate buffer. Then convert again.
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;
196
197 // Query the required output size. Allocate buffer. Then convert again.
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));
202 return;
203 }
204 throw std::runtime_error("MultiByteToWideChar failed");
205 }
206#else
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);
210 for (;;) {
211 T_to* output = &buf[0];
212 size_t output_size = sizeof(buf);
213 errno = 0;
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));
216 if (!errno)
217 break;
218 if (errno == E2BIG)
219 continue;
220 throw std::runtime_error("iconv failed");
221 }
222#endif
223 }
224
231 template <class _Traits_to = std::char_traits<T_to>, class _Alloc_to = std::allocator<T_to>>
232 inline void strcat(
233 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
234 _In_z_ const T_from* src)
235 {
236 strcat(dst, src, SIZE_MAX);
237 }
238
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>>
246 inline void strcat(
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)
249 {
250 strcat(dst, src.data(), src.size());
251 }
252
260 template <class _Traits_to = std::char_traits<T_to>, class _Alloc_to = std::allocator<T_to>>
261 inline void strcpy(
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)
264 {
265 dst.clear();
266 strcat(dst, src, count_src);
267 }
268
275 template <class _Traits_to = std::char_traits<T_to>, class _Alloc_to = std::allocator<T_to>>
276 inline void strcpy(
277 _Inout_ std::basic_string<T_to, _Traits_to, _Alloc_to>& dst,
278 _In_z_ const T_from* src)
279 {
280 strcpy(dst, src, SIZE_MAX);
281 }
282
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>>
290 inline void strcpy(
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)
293 {
294 strcpy(dst, src.data(), src.size());
295 }
296
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)
305 {
306 std::basic_string<T_to, _Traits_to, _Alloc_to> dst;
307 strcat(dst, src, count_src);
308 return dst;
309 }
310
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)
318 {
319 return convert(src, SIZE_MAX);
320 }
321
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)
329 {
330 return convert(src.data(), src.size());
331 }
332
333 inline void clear()
334 {
335#ifndef _WIN32
336 iconv(m_handle, NULL, NULL, NULL, NULL);
337#endif
338 }
339
340 static charset_id system_charset()
341 {
342#ifdef _WIN32
343 return static_cast<charset_id>(GetACP());
344#else
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;
350#else
351 if (strcmp(lctype, "UTF-16LE") == 0) return charset_id::utf16;
352#endif
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;
356#else
357 if (strcmp(lctype, "UTF-32LE") == 0) return charset_id::utf32;
358#endif
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;
363#endif
364 }
365
366#ifdef _WIN32
367 protected:
368 static UINT to_encoding(_In_ charset_id charset)
369 {
370 return
371 charset == charset_id::system ? GetACP() :
372 charset == charset_id::oem ? GetOEMCP() :
373 static_cast<UINT>(charset);
374 }
375
376 protected:
377 UINT m_from_wincp, m_to_wincp;
378#else
379 protected:
380 static const char* to_encoding(_In_ charset_id charset)
381 {
382 static const char* const encodings[static_cast<std::underlying_type_t<charset_id>>(charset_id::_max)] = {
383 "", // system
384 "UTF-8", // utf8
385#if BYTE_ORDER == BIG_ENDIAN
386 "UTF-16BE", // utf16
387 "UTF-32BE", // utf32
388#else
389 "UTF-16LE", // utf16
390 "UTF-32LE", // utf32
391#endif
392 "CP1250", // windows1250
393 "CP1251", // windows1251
394 "CP1252", // windows1252
395 };
396 return
397 charset == charset_id::system ? nl_langinfo(CODESET) :
398 encodings[static_cast<std::underlying_type_t<charset_id>>(charset)];
399 }
400
401 protected:
402 iconv_t m_handle;
403#endif
404 };
405
416#ifndef _WIN32
417 _Deprecated_("For better performance, consider a reusable charset_encoder")
418#endif
419 inline void strcat(
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)
423 {
424 charset_encoder<char, wchar_t>(charset, wchar_t_charset).strcat(dst, src, count_src);
425 }
426
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)
432 {
433 strcat(dst, src, count_src, charset);
434 }
435
445#ifndef _WIN32
446 _Deprecated_("For better performance, consider a reusable charset_encoder")
447#endif
448 inline void strcat(
449 _Inout_ std::wstring& dst,
450 _In_ const std::string& src,
451 _In_ charset_id charset = charset_id::system)
452 {
453 strcat(dst, src.data(), src.size(), charset);
454 }
455
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)
461 {
462 strcat(dst, src, charset);
463 }
464
475#ifndef _WIN32
476 _Deprecated_("For better performance, consider a reusable charset_encoder")
477#endif
478 inline void strcpy(
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)
482 {
483 dst.clear();
484 strcat(dst, src, count_src, charset);
485 }
486
496#ifndef _WIN32
497 _Deprecated_("For better performance, consider a reusable charset_encoder")
498#endif
499 inline void strcpy(
500 _Inout_ std::wstring& dst,
501 _In_ const std::string& src,
502 _In_ charset_id charset = charset_id::system)
503 {
504 strcpy(dst, src.data(), src.size(), charset);
505 }
506
517#ifndef _WIN32
518 _Deprecated_("For better performance, consider a reusable charset_encoder")
519#endif
520 inline std::wstring str2wstr(
521 _In_z_ const char* src,
522 _In_ charset_id charset = charset_id::system)
523 {
524 std::wstring dst;
525 strcat(dst, src, SIZE_MAX, charset);
526 return dst;
527 }
528
540#ifndef _WIN32
541 _Deprecated_("For better performance, consider a reusable charset_encoder")
542#endif
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)
546 {
547 std::wstring dst;
548 strcat(dst, src, count_src, charset);
549 return dst;
550 }
551
562#ifndef _WIN32
563 _Deprecated_("For better performance, consider a reusable charset_encoder")
564#endif
565 inline std::wstring str2wstr(
566 _In_ const std::string& src,
567 _In_ charset_id charset = charset_id::system)
568 {
569 return str2wstr(src.c_str(), src.size(), charset);
570 }
571
582#ifndef _WIN32
583 _Deprecated_("For better performance, consider a reusable charset_encoder")
584#endif
585 inline void strcat(
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)
589 {
590 charset_encoder<wchar_t, char>(wchar_t_charset, charset).strcat(dst, src, count_src);
591 }
592
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)
598 {
599 strcat(dst, src, count_src, charset);
600 }
601
611#ifndef _WIN32
612 _Deprecated_("For better performance, consider a reusable charset_encoder")
613#endif
614 inline void strcat(
615 _Inout_ std::string& dst,
616 _In_ const std::wstring& src,
617 _In_ charset_id charset = charset_id::system)
618 {
619 strcat(dst, src.c_str(), src.size(), charset);
620 }
621
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)
627 {
628 strcat(dst, src, charset);
629 }
630
641#ifndef _WIN32
642 _Deprecated_("For better performance, consider a reusable charset_encoder")
643#endif
644 inline void strcpy(
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)
648 {
649 dst.clear();
650 strcat(dst, src, count_src, charset);
651 }
652
662#ifndef _WIN32
663 _Deprecated_("For better performance, consider a reusable charset_encoder")
664#endif
665 inline void strcpy(
666 _Inout_ std::string& dst,
667 _In_ const std::wstring& src,
668 _In_ charset_id charset = charset_id::system)
669 {
670 strcpy(dst, src.data(), src.size(), charset);
671 }
672
683#ifndef _WIN32
684 _Deprecated_("For better performance, consider a reusable charset_encoder")
685#endif
686 inline std::string wstr2str(
687 _In_z_ const wchar_t* src,
688 _In_ charset_id charset = charset_id::system)
689 {
690 std::string dst;
691 strcat(dst, src, SIZE_MAX, charset);
692 return dst;
693 }
694
706#ifndef _WIN32
707 _Deprecated_("For better performance, consider a reusable charset_encoder")
708#endif
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)
712 {
713 std::string dst;
714 strcat(dst, src, count_src, charset);
715 return dst;
716 }
717
728#ifndef _WIN32
729 _Deprecated_("For better performance, consider a reusable charset_encoder")
730#endif
731 inline std::string wstr2str(
732 _In_ const std::wstring& src,
733 _In_ charset_id charset = charset_id::system)
734 {
735 return wstr2str(src.c_str(), src.size(), charset);
736 }
737}
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