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 str2wstr(
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
75 inline void str2wstr(
76 _Inout_ std::wstring& dst,
77 _In_ const std::string& src,
78 _In_ charset_id charset = charset_id::default)
79 {
80 str2wstr(dst, src.data(), src.size(), charset);
81 }
82
92 inline std::wstring str2wstr(
93 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
94 _In_ charset_id charset = charset_id::default)
95 {
96 std::wstring dst;
97 str2wstr(dst, src, count_src, charset);
98 return dst;
99 }
100
109 inline std::wstring str2wstr(
110 _In_ const std::string& src,
111 _In_ charset_id charset = charset_id::default)
112 {
113 return str2wstr(src.c_str(), src.size(), charset);
114 }
115
124 inline void wstr2str(
125 _Inout_ std::string& dst,
126 _In_reads_or_z_opt_(count_src) const wchar_t* src,
127 _In_ size_t count_src,
128 _In_ charset_id charset = charset_id::default)
129 {
130 assert(src || !count_src);
131#ifdef _WIN32
132 assert(count_src < INT_MAX || count_src == SIZE_MAX);
133 constexpr DWORD dwFlags = 0;
134 constexpr LPCCH lpDefaultChar = NULL;
135
136 // Try to convert to stack buffer first.
137 CHAR szStackBuffer[1024/sizeof(CHAR)];
138#pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpWideCharStr parameter wrong?
139 int cch = WideCharToMultiByte(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, NULL);
140 if (cch) {
141 // Copy from stack. Be careful not to include zero terminator.
142 dst.append(szStackBuffer, count_src != SIZE_MAX ? strnlen(szStackBuffer, cch) : (size_t)cch - 1);
143 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
144 // Query the required output size. Allocate buffer. Then convert again.
145 cch = WideCharToMultiByte(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), NULL, 0, lpDefaultChar, NULL);
146 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
147 cch = WideCharToMultiByte(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szBuffer.get(), cch, lpDefaultChar, NULL);
148 dst.append(szBuffer.get(), count_src != SIZE_MAX ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1);
149 }
150#else
151 throw std::exception("not implemented");
152#endif
153 }
154
162 inline void wstr2str(
163 _Inout_ std::string& dst,
164 _In_ const std::wstring& src,
165 _In_ charset_id charset = charset_id::default)
166 {
167 wstr2str(dst, src.c_str(), src.size(), charset);
168 }
169
179 inline std::string wstr2str(
180 _In_reads_or_z_opt_(count_src) const wchar_t* src,
181 _In_ size_t count_src,
182 _In_ charset_id charset = charset_id::default)
183 {
184 std::string dst;
185 wstr2str(dst, src, count_src, charset);
186 return dst;
187 }
188
197 inline std::string wstr2str(
198 _In_ const std::wstring& src,
199 _In_ charset_id charset = charset_id::default)
200 {
201 return wstr2str(src.c_str(), src.size(), charset);
202 }
203}