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 "sal.hpp"
9#include "system.hpp"
10#include <assert.h>
11#include <stdint.h>
12#include <memory>
13#include <string>
14
15namespace stdex
16{
17 enum class charset_id : uint16_t {
18#ifdef _WIN32
19 default = CP_ACP,
20 utf8 = CP_UTF8,
21 utf16 = 1200 /*CP_WINUNICODE*/,
22#else
23 default = 0,
24#endif
25 };
26
37 inline void strcat(
38 _Inout_ std::wstring& dst,
39 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
40 _In_ charset_id charset = charset_id::default)
41 {
42 assert(src || !count_src);
43#ifdef _WIN32
44 assert(count_src < INT_MAX || count_src == SIZE_MAX);
45 constexpr DWORD dwFlags = MB_PRECOMPOSED;
46
47 // Try to convert to stack buffer first.
48 WCHAR szStackBuffer[1024/sizeof(WCHAR)];
49#pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpMultiByteStr parameter wrong?
50 int cch = MultiByteToWideChar(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer));
51 if (cch) {
52 // Append from stack.
53 dst.append(szStackBuffer, count_src != SIZE_MAX ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
54 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
55 // Query the required output size. Allocate buffer. Then convert again.
56 cch = MultiByteToWideChar(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), NULL, 0);
57 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
58 cch = MultiByteToWideChar(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szBuffer.get(), cch);
59 dst.append(szBuffer.get(), count_src != SIZE_MAX ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1);
60 }
61#else
62 throw std::exception("not implemented");
63#endif
64 }
65
66 inline _Deprecated_("Use stdex::strcat") void str2wstr(
67 _Inout_ std::wstring& dst,
68 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
69 _In_ charset_id charset = charset_id::default)
70 {
71 strcat(dst, src, count_src, charset);
72 }
73
83 inline void strcat(
84 _Inout_ std::wstring& dst,
85 _In_ const std::string& src,
86 _In_ charset_id charset = charset_id::default)
87 {
88 strcat(dst, src.data(), src.size(), charset);
89 }
90
91 inline _Deprecated_("Use stdex::strcat") void str2wstr(
92 _Inout_ std::wstring& dst,
93 _In_ const std::string& src,
94 _In_ charset_id charset = charset_id::default)
95 {
96 strcat(dst, src, charset);
97 }
98
109 inline void strcpy(
110 _Inout_ std::wstring& dst,
111 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
112 _In_ charset_id charset = charset_id::default)
113 {
114 dst.clear();
115 strcat(dst, src, count_src, charset);
116 }
117
127 inline void strcpy(
128 _Inout_ std::wstring& dst,
129 _In_ const std::string& src,
130 _In_ charset_id charset = charset_id::default)
131 {
132 strcpy(dst, src.data(), src.size(), charset);
133 }
134
143 inline std::wstring str2wstr(
144 _In_z_ const char* src,
145 _In_ charset_id charset = charset_id::default)
146 {
147 std::wstring dst;
148 strcat(dst, src, SIZE_MAX, charset);
149 return dst;
150 }
151
161 inline std::wstring str2wstr(
162 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
163 _In_ charset_id charset = charset_id::default)
164 {
165 std::wstring dst;
166 strcat(dst, src, count_src, charset);
167 return dst;
168 }
169
178 inline std::wstring str2wstr(
179 _In_ const std::string& src,
180 _In_ charset_id charset = charset_id::default)
181 {
182 return str2wstr(src.c_str(), src.size(), charset);
183 }
184
193 inline void strcat(
194 _Inout_ std::string& dst,
195 _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
196 _In_ charset_id charset = charset_id::default)
197 {
198 assert(src || !count_src);
199#ifdef _WIN32
200 assert(count_src < INT_MAX || count_src == SIZE_MAX);
201 constexpr DWORD dwFlags = 0;
202 constexpr LPCCH lpDefaultChar = NULL;
203
204 // Try to convert to stack buffer first.
205 CHAR szStackBuffer[1024/sizeof(CHAR)];
206#pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpWideCharStr parameter wrong?
207 int cch = WideCharToMultiByte(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, NULL);
208 if (cch) {
209 // Copy from stack. Be careful not to include zero terminator.
210 dst.append(szStackBuffer, count_src != SIZE_MAX ? strnlen(szStackBuffer, cch) : (size_t)cch - 1);
211 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
212 // Query the required output size. Allocate buffer. Then convert again.
213 cch = WideCharToMultiByte(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), NULL, 0, lpDefaultChar, NULL);
214 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
215 cch = WideCharToMultiByte(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szBuffer.get(), cch, lpDefaultChar, NULL);
216 dst.append(szBuffer.get(), count_src != SIZE_MAX ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1);
217 }
218#else
219 throw std::exception("not implemented");
220#endif
221 }
222
223 inline _Deprecated_("Use stdex::strcat") void wstr2str(
224 _Inout_ std::string& dst,
225 _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
226 _In_ charset_id charset = charset_id::default)
227 {
228 strcat(dst, src, count_src, charset);
229 }
230
238 inline void strcat(
239 _Inout_ std::string& dst,
240 _In_ const std::wstring& src,
241 _In_ charset_id charset = charset_id::default)
242 {
243 strcat(dst, src.c_str(), src.size(), charset);
244 }
245
246 inline _Deprecated_("Use stdex::strcat") void wstr2str(
247 _Inout_ std::string& dst,
248 _In_ const std::wstring& src,
249 _In_ charset_id charset = charset_id::default)
250 {
251 strcat(dst, src, charset);
252 }
253
262 inline void strcpy(
263 _Inout_ std::string& dst,
264 _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
265 _In_ charset_id charset = charset_id::default)
266 {
267 dst.clear();
268 strcat(dst, src, count_src, charset);
269 }
270
278 inline void strcpy(
279 _Inout_ std::string& dst,
280 _In_ const std::wstring& src,
281 _In_ charset_id charset = charset_id::default)
282 {
283 strcpy(dst, src.data(), src.size(), charset);
284 }
285
294 inline std::string wstr2str(
295 _In_z_ const wchar_t* src,
296 _In_ charset_id charset = charset_id::default)
297 {
298 std::string dst;
299 strcat(dst, src, SIZE_MAX, charset);
300 return dst;
301 }
302
312 inline std::string wstr2str(
313 _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
314 _In_ charset_id charset = charset_id::default)
315 {
316 std::string dst;
317 strcat(dst, src, count_src, charset);
318 return dst;
319 }
320
329 inline std::string wstr2str(
330 _In_ const std::wstring& src,
331 _In_ charset_id charset = charset_id::default)
332 {
333 return wstr2str(src.c_str(), src.size(), charset);
334 }
335}