Skip to content

Commit 8d53c8d

Browse files
committed
✨ windows code page type storage
1 parent 6220b12 commit 8d53c8d

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed

include/ztd/idk/detail/windows.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,30 @@ namespace ztd {
229229
return MB_ERR_INVALID_CHARS;
230230
}
231231

232+
ZTD_USE(ZTD_C_LANGUAGE_LINKAGE)
233+
ZTD_USE(ZTD_IDK_API_LINKAGE)
234+
bool __get_codepage_descirptor(uint32_t __codepage_id, CPINFOEXW** __pp_codepage_info)
235+
ZTD_USE(ZTD_NOEXCEPT_IF_CXX);
236+
237+
// double-check if we were screwed over by the conversion: given
238+
// Win32's undocumented fuckups around this, the only way to know if
239+
// we actually failed is by checking if the single character we output
240+
// is equal to a replacement character, and if the replacement
241+
// character is NOT present in the original stream. The proper way to
242+
// do this is to call GetCPInfoExW and then using a comparison to the
243+
// MultiByte stream. But there's so many different things wrong with
244+
// it, and it's hard to know.
245+
246+
ZTD_USE(ZTD_C_LANGUAGE_LINKAGE)
247+
ZTD_USE(ZTD_IDK_API_LINKAGE)
248+
bool __widechar_to_multibyte_conversion_failed(const WCHAR* __input, size_t __output_size,
249+
const CHAR* __output, CPINFOEXW* __p_codepage_info) ZTD_USE(ZTD_NOEXCEPT_IF_CXX);
250+
251+
ZTD_USE(ZTD_C_LANGUAGE_LINKAGE)
252+
ZTD_USE(ZTD_IDK_API_LINKAGE)
253+
bool __multibyte_to_widechar_conversion_failed(size_t __input_size, const CHAR* __input,
254+
const WCHAR* __output, CPINFOEXW* __p_codepage_info) ZTD_USE(ZTD_NOEXCEPT_IF_CXX);
255+
232256
}} // namespace __idk_detail::__windows
233257
ZTD_IDK_INLINE_ABI_NAMESPACE_CLOSE_I_
234258
} // namespace ztd

include/ztd/idk/thread_local.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@
3838
#if ZTD_IS_ON(ZTD_CXX)
3939
#define ztd_thread_local thread_local
4040
#else
41+
#if __STDC_VERSION__ >= 202311L
42+
#define ztd_thread_local thread_local
43+
#else
4144
#define ztd_thread_local _Thread_local
4245
#endif
46+
#endif
4347

4448
#endif

source/ztd/idk/detail/windows.cpp

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// =============================================================================
2+
//
3+
// ztd.idk
4+
// Copyright © JeanHeyd "ThePhD" Meneide and Shepherd's Oasis, LLC
5+
// Contact: [email protected]
6+
//
7+
// Commercial License Usage
8+
// Licensees holding valid commercial ztd.idk licenses may use this file in
9+
// accordance with the commercial license agreement provided with the
10+
// Software or, alternatively, in accordance with the terms contained in
11+
// a written agreement between you and Shepherd's Oasis, LLC.
12+
// For licensing terms and conditions see your agreement. For
13+
// further information contact [email protected].
14+
//
15+
// Apache License Version 2 Usage
16+
// Alternatively, this file may be used under the terms of Apache License
17+
// Version 2.0 (the "License") for non-commercial use; you may not use this
18+
// file except in compliance with the License. You may obtain a copy of the
19+
// License at
20+
//
21+
// https://www.apache.org/licenses/LICENSE-2.0
22+
//
23+
// Unless required by applicable law or agreed to in writing, software
24+
// distributed under the License is distributed on an "AS IS" BASIS,
25+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26+
// See the License for the specific language governing permissions and
27+
// limitations under the License.
28+
//
29+
// ============================================================================ //
30+
31+
#include <ztd/idk/version.h>
32+
#include <ztd/idk/version.hpp>
33+
34+
#include <ztd/idk/thread_local.h>
35+
#include <ztd/idk/detail/windows.hpp>
36+
37+
#include <map>
38+
#include <memory>
39+
40+
#if ZTD_IS_ON(ZTD_PLATFORM_WINDOWS)
41+
42+
namespace ztd {
43+
ZTD_IDK_INLINE_ABI_NAMESPACE_OPEN_I_
44+
namespace __idk_detail { namespace __windows {
45+
46+
ztd_thread_local ::std::map<uint32_t, ::std::unique_ptr<CPINFOEXW>> __codepage_descriptors;
47+
48+
ZTD_USE(ZTD_C_LANGUAGE_LINKAGE)
49+
ZTD_USE(ZTD_IDK_API_LINKAGE)
50+
bool __get_codepage_descirptor(uint32_t __codepage_id, CPINFOEXW** __pp_codepage_info)
51+
ZTD_USE(ZTD_NOEXCEPT_IF_CXX) {
52+
if (__pp_codepage_info == nullptr) {
53+
return false;
54+
}
55+
if (__codepage_id == CP_ACP || __codepage_id == CP_THREAD_ACP) {
56+
__codepage_id = static_cast<uint32_t>(GetACP());
57+
}
58+
else if (__codepage_id == CP_OEMCP) {
59+
__codepage_id = static_cast<uint32_t>(GetOEMCP());
60+
}
61+
auto __it = __codepage_descriptors.find(__codepage_id);
62+
if (__it == __codepage_descriptors.cend()) {
63+
CPINFOEXW __info = {};
64+
if (GetCPInfoExW(static_cast<UINT>(__codepage_id), 0, &__info) == 0) {
65+
// somehow failed: we can't use this
66+
*__pp_codepage_info = nullptr;
67+
return false;
68+
}
69+
__it = __codepage_descriptors.insert(::std::move(__it),
70+
::std::pair<uint32_t, ::std::unique_ptr<CPINFOEXW>>(
71+
__codepage_id, ::std::make_unique<CPINFOEXW>(__info)));
72+
}
73+
*__pp_codepage_info = __it->second.get();
74+
return true;
75+
}
76+
77+
ZTD_USE(ZTD_C_LANGUAGE_LINKAGE)
78+
ZTD_USE(ZTD_IDK_API_LINKAGE)
79+
bool __widechar_to_multibyte_conversion_failed(const WCHAR* __input, size_t __output_size,
80+
const CHAR* __output, CPINFOEXW* __p_codepage_info) ZTD_USE(ZTD_NOEXCEPT_IF_CXX) {
81+
if (!__p_codepage_info) {
82+
return false;
83+
}
84+
if (__output[0] != __p_codepage_info->DefaultChar[0]) {
85+
return false;
86+
}
87+
if (__p_codepage_info->DefaultChar[1] == '\0') {
88+
// if there isn't a second char then we're done here: it's been equal both for the wide and the
89+
// not-wide.
90+
return true;
91+
}
92+
if (__output_size < 2u || __p_codepage_info->DefaultChar[1] != __output[1]) {
93+
return false;
94+
}
95+
if (__input[0] != __p_codepage_info->UnicodeDefaultChar) {
96+
return false;
97+
}
98+
// if all things are equal, then there was, in fact, a failure
99+
return true;
100+
}
101+
102+
ZTD_USE(ZTD_C_LANGUAGE_LINKAGE)
103+
ZTD_USE(ZTD_IDK_API_LINKAGE)
104+
bool __multibyte_to_widechar_conversion_failed(size_t __input_size, const CHAR* __input,
105+
const WCHAR* __output, CPINFOEXW* __p_codepage_info) ZTD_USE(ZTD_NOEXCEPT_IF_CXX) {
106+
if (!__p_codepage_info) {
107+
return false;
108+
}
109+
if (__output[0] != __p_codepage_info->UnicodeDefaultChar || __output[0] != '?') {
110+
// The output does not have the replacement character!
111+
return false;
112+
}
113+
// Okay: the output has a replaced character. It's time to check if the input already had the (original)
114+
// replacement character.
115+
if (__input[0] == __p_codepage_info->DefaultChar[0]) {
116+
// if the input is equal to the default character, then we can't be sure.
117+
if (__p_codepage_info->DefaultChar[1] == '\0') {
118+
// This is the maximum length so it definitely can't be sure.
119+
return false;
120+
}
121+
if (__input_size > 1u && __p_codepage_info->DefaultChar[1] == __input[1]) {
122+
// okay, so we have 2 characters and they're both equal: we cannot be sure.
123+
return false;
124+
}
125+
}
126+
// the input does not contain the same characters, and the output IS the default character:
127+
// that seems like a replacement! Which means the conversion DID fail.
128+
return true;
129+
}
130+
131+
}} // namespace __idk_detail::__windows
132+
ZTD_IDK_INLINE_ABI_NAMESPACE_CLOSE_I_
133+
} // namespace ztd
134+
135+
#endif

0 commit comments

Comments
 (0)