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 };
21
32 inline void str2wstr(
33 _Inout_ std::wstring& dst,
34 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
35 _In_ charset_id charset = charset_id::default)
36 {
37 assert(src || !count_src);
38#ifdef _WIN32
39 assert(count_src < INT_MAX || count_src == SIZE_MAX);
40 constexpr DWORD dwFlags = MB_PRECOMPOSED;
41
42 // Try to convert to stack buffer first.
43 WCHAR szStackBuffer[1024/sizeof(WCHAR)];
44 int cch = MultiByteToWideChar(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer));
45 if (cch) {
46 // Append from stack.
47 dst.append(szStackBuffer, count_src != SIZE_MAX ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
48 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
49 // Query the required output size. Allocate buffer. Then convert again.
50 cch = MultiByteToWideChar(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), NULL, 0);
51 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
52 cch = MultiByteToWideChar(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szBuffer.get(), cch);
53 dst.append(szBuffer.get(), count_src != SIZE_MAX ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1);
54 }
55#else
56 throw std::exception("not implemented");
57#endif
58 }
59
69 inline void str2wstr(
70 _Inout_ std::wstring& dst,
71 _In_ const std::string& src,
72 _In_ charset_id charset = charset_id::default)
73 {
74 str2wstr(dst, src.data(), src.size(), charset);
75 }
76
86 inline std::wstring str2wstr(
87 _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
88 _In_ charset_id charset = charset_id::default)
89 {
90 std::wstring dst;
91 str2wstr(dst, src, count_src, charset);
92 return dst;
93 }
94
103 inline std::wstring str2wstr(
104 _In_ const std::string& src,
105 _In_ charset_id charset = charset_id::default)
106 {
107 return str2wstr(src.c_str(), src.size(), charset);
108 }
109
118 inline void wstr2str(
119 _Inout_ std::string& dst,
120 _In_reads_or_z_opt_(count_src) const wchar_t* src,
121 _In_ size_t count_src,
122 _In_ charset_id charset = charset_id::default)
123 {
124 assert(src || !count_src);
125#ifdef _WIN32
126 assert(count_src < INT_MAX || count_src == SIZE_MAX);
127 constexpr DWORD dwFlags = 0;
128 constexpr LPCCH lpDefaultChar = NULL;
129
130 // Try to convert to stack buffer first.
131 CHAR szStackBuffer[1024/sizeof(CHAR)];
132 int cch = WideCharToMultiByte(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, NULL);
133 if (cch) {
134 // Copy from stack. Be careful not to include zero terminator.
135 dst.append(szStackBuffer, count_src != SIZE_MAX ? strnlen(szStackBuffer, cch) : (size_t)cch - 1);
136 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
137 // Query the required output size. Allocate buffer. Then convert again.
138 cch = WideCharToMultiByte(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), NULL, 0, lpDefaultChar, NULL);
139 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
140 cch = WideCharToMultiByte(static_cast<UINT>(charset), dwFlags, src, static_cast<int>(count_src), szBuffer.get(), cch, lpDefaultChar, NULL);
141 dst.append(szBuffer.get(), count_src != SIZE_MAX ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1);
142 }
143#else
144 throw std::exception("not implemented");
145#endif
146 }
147
155 inline void wstr2str(
156 _Inout_ std::string& dst,
157 _In_ const std::wstring& src,
158 _In_ charset_id charset = charset_id::default)
159 {
160 wstr2str(dst, src.c_str(), src.size(), charset);
161 }
162
172 inline std::string wstr2str(
173 _In_reads_or_z_opt_(count_src) const wchar_t* src,
174 _In_ size_t count_src,
175 _In_ charset_id charset = charset_id::default)
176 {
177 std::string dst;
178 wstr2str(dst, src, count_src, charset);
179 return dst;
180 }
181
190 inline std::string wstr2str(
191 _In_ const std::wstring& src,
192 _In_ charset_id charset = charset_id::default)
193 {
194 return wstr2str(src.c_str(), src.size(), charset);
195 }
196}