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 <assert.h>
10#ifdef _WIN32
11#include <windows.h>
12#endif
13#include <memory>
14#include <string>
15
16namespace stdex
17{
18 enum class charset_id {
19 default = 0,
20#ifdef _WIN32
21 utf8 = CP_UTF8,
22#endif
23 };
24
35 inline void str2wstr(
36 _Inout_ std::wstring& dst,
37 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
38 _In_ charset_id charset = charset_id::default)
39 {
40 assert(src || !count_src);
41#ifdef _WIN32
42 assert(count_src < INT_MAX || count_src == SIZE_MAX);
43 constexpr DWORD dwFlags = MB_PRECOMPOSED;
44
45 // Try to convert to stack buffer first.
46 WCHAR szStackBuffer[1024/sizeof(WCHAR)];
47 int cch = MultiByteToWideChar(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer));
48 if (cch) {
49 // Append from stack.
50 dst.append(szStackBuffer, count_src != SIZE_MAX ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
51 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
52 // Query the required output size. Allocate buffer. Then convert again.
53 cch = MultiByteToWideChar(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), NULL, 0);
54 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
55 cch = MultiByteToWideChar(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szBuffer.get(), cch);
56 dst.append(szBuffer.get(), count_src != SIZE_MAX ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1);
57 }
58#else
59 throw std::exception("not implemented");
60#endif
61 }
62
72 inline void str2wstr(
73 _Inout_ std::wstring& dst,
74 _In_ const std::string& src,
75 _In_ charset_id charset = charset_id::default)
76 {
77 str2wstr(dst, src.data(), src.size(), charset);
78 }
79
89 inline std::wstring str2wstr(
90 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
91 _In_ charset_id charset = charset_id::default)
92 {
93 std::wstring dst;
94 str2wstr(dst, src, count_src, charset);
95 return dst;
96 }
97
106 inline std::wstring str2wstr(
107 _In_ const std::string& src,
108 _In_ charset_id charset = charset_id::default)
109 {
110 return str2wstr(src.c_str(), src.size(), charset);
111 }
112
121 inline void wstr2str(
122 _Inout_ std::string& dst,
123 _In_reads_or_z_opt_(count_src) const wchar_t* src,
124 _In_ size_t count_src,
125 _In_ charset_id charset = charset_id::default)
126 {
127 assert(src || !count_src);
128#ifdef _WIN32
129 assert(count_src < INT_MAX || count_src == SIZE_MAX);
130 constexpr DWORD dwFlags = 0;
131 constexpr LPCCH lpDefaultChar = NULL;
132
133 // Try to convert to stack buffer first.
134 CHAR szStackBuffer[1024/sizeof(CHAR)];
135 int cch = WideCharToMultiByte(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, NULL);
136 if (cch) {
137 // Copy from stack. Be careful not to include zero terminator.
138 dst.append(szStackBuffer, count_src != SIZE_MAX ? strnlen(szStackBuffer, cch) : (size_t)cch - 1);
139 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
140 // Query the required output size. Allocate buffer. Then convert again.
141 cch = WideCharToMultiByte(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), NULL, 0, lpDefaultChar, NULL);
142 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
143 cch = WideCharToMultiByte(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szBuffer.get(), cch, lpDefaultChar, NULL);
144 dst.append(szBuffer.get(), count_src != SIZE_MAX ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1);
145 }
146#else
147 throw std::exception("not implemented");
148#endif
149 }
150
158 inline void wstr2str(
159 _Inout_ std::string& dst,
160 _In_ const std::wstring& src,
161 _In_ charset_id charset = charset_id::default)
162 {
163 wstr2str(dst, src.c_str(), src.size(), charset);
164 }
165
175 inline std::string wstr2str(
176 _In_reads_or_z_opt_(count_src) const wchar_t* src,
177 _In_ size_t count_src,
178 _In_ charset_id charset = charset_id::default)
179 {
180 std::string dst;
181 wstr2str(dst, src, count_src, charset);
182 return dst;
183 }
184
193 inline std::string wstr2str(
194 _In_ const std::wstring& src,
195 _In_ charset_id charset = charset_id::default)
196 {
197 return wstr2str(src.c_str(), src.size(), charset);
198 }
199}