Skip to content

Commit d7a4f13

Browse files
committed
✨ Fully automated luxury win32 communism code page conversions.
1 parent 06fa935 commit d7a4f13

File tree

4 files changed

+61
-22
lines changed

4 files changed

+61
-22
lines changed

include/ztd/cuneicode/mcstate.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,15 @@ typedef union cnc_mcstate_t {
162162
uint32_t __code_page;
163163
//////
164164
/// @brief Private, do not access.
165+
void* __code_page_info;
166+
//////
167+
/// @brief Private, do not access.
165168
union {
166-
ztd_wchar_t __wide_accumulator[(sizeof(ztd_mbstate_t) * 2 - sizeof(uint32_t))
169+
ztd_wchar_t __wide_accumulator[(sizeof(ztd_mbstate_t) * 2
170+
- (sizeof(uint32_t) + sizeof(void*)))
167171
/ sizeof(ztd_wchar_t)];
168-
char __narrow_accumulator[(sizeof(ztd_mbstate_t) * 2 - sizeof(uint32_t))
172+
char __narrow_accumulator[(sizeof(ztd_mbstate_t) * 2
173+
- (sizeof(uint32_t) + sizeof(void*)))
169174
/ sizeof(char)];
170175
};
171176
} __win32_code_page;

source/include/ztd/cuneicode/detail/core_mcharn.hpp

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -298,28 +298,30 @@ namespace cnc {
298298
? (*__p_maybe_dst_len > static_cast<size_t>(INT_MAX) ? INT_MAX
299299
: *__p_maybe_dst_len)
300300
: INT_MAX);
301+
CPINFOEXW* __p_info = (CPINFOEXW*)__p_state->__win32_code_page.__code_page_info;
301302
for (size_t __intermediate_input_read = 1;
302303
__intermediate_input_read <= __intermediate_size; ++__intermediate_input_read) {
303304
if (__intermediate_input_read > CNC_MWC_INPUT_MAX) {
304305
break;
305306
}
306307
const int __win32_err = ::WideCharToMultiByte(
307308
::ztd::__idk_detail::__windows::__code_page_active_thread,
308-
WC_ERR_INVALID_CHARS, __intermediate_output,
309+
__used_defaults.__flags, __intermediate_output,
309310
static_cast<int>(__intermediate_input_read), __win32_dst, __win32_dst_len,
310311
__used_defaults.__p_default_char, __used_defaults.__p_default_char_used);
311312
if (__win32_err == 0) {
312313
DWORD __last_win32_err = ::GetLastError();
313-
if (__last_win32_err == ERROR_NO_UNICODE_TRANSLATION
314-
|| __default_char_used) {
314+
if (__last_win32_err == ERROR_NO_UNICODE_TRANSLATION) {
315315
// loop around; we don't know if this is from a partial read (because
316-
// of our
317-
// artifical limitations) or because it's a genuine error. This is, of
318-
// course, the problem with these crappy 1990s/2000s APIs.
316+
// of ourartifical limitations) or because it's a genuine error. This
317+
// is, of course, the problem with these crappy 1990s/2000s APIs.
319318
continue;
320319
}
320+
else if (__default_char_used) {
321+
return cnc_mcerr_invalid_sequence;
322+
}
321323
else if (__last_win32_err == ERROR_INSUFFICIENT_BUFFER) {
322-
if (!_IsUnbounded) {
324+
if constexpr (!_IsUnbounded) {
323325
__p_src[0] = __initial_src;
324326
__p_src_len[0] = __initial_src_len;
325327
return cnc_mcerr_insufficient_output;
@@ -330,15 +332,10 @@ namespace cnc {
330332
}
331333
}
332334
else {
333-
if (__win32_err == 1) {
334-
// double-check if we were screwed over by the conversion: given
335-
// Win32's undocumented fuckups around this, the only way to know if
336-
// we actually failed is by checking if the single character we output
337-
// is equal to a replacement character, and if the replacement
338-
// character is NOT present in the original stream. The proper way to
339-
// do this is to call GetCPInfoExW and then using a comparison to the
340-
// MultiByte stream. But there's so many different things wrong with
341-
// it, and it's hard to know.
335+
if (::ztd::__idk_detail::__windows::
336+
__widechar_to_multibyte_conversion_failed(__intermediate_output,
337+
__intermediate_input_read, __win32_dst, __p_info)) {
338+
return cnc_mcerr_invalid_sequence;
342339
}
343340
// okay, it should be good
344341
if (!_IsUnbounded) {
@@ -1106,6 +1103,7 @@ namespace cnc {
11061103
const uint32_t __flags
11071104
= ::ztd::__idk_detail::__windows::__multibyte_to_widechar_flags(
11081105
ztd::__idk_detail::__windows::__code_page_active_thread);
1106+
CPINFOEXW* __p_info = (CPINFOEXW*)__p_state->__win32_code_page.__code_page_info;
11091107
for (; __input_read_size <= __initial_src_len; ++__input_read_size) {
11101108
if (__input_read_size > CNC_MC_INPUT_MAX) {
11111109
// can't do much else
@@ -1121,6 +1119,11 @@ namespace cnc {
11211119
continue;
11221120
}
11231121
else {
1122+
if (::ztd::__idk_detail::__windows::
1123+
__multibyte_to_widechar_conversion_failed(__input_read_size,
1124+
__initial_src, __p_intermediate_output, __p_info)) {
1125+
return cnc_mcerr_invalid_sequence;
1126+
}
11241127
__intermediate_size = static_cast<size_t>(__win32_err);
11251128
break;
11261129
}

source/ztd/cuneicode/mcstate.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ void cnc_mcstate_set_win32_code_page(cnc_mcstate_t* __state, uint32_t __win32_co
6666
}
6767
__state->__win32_code_page.__indicator = __mc_s_i_win32_code_page;
6868
__state->__win32_code_page.__code_page = __win32_code_page_id;
69+
CPINFOEXW* __codepage_info
70+
= static_cast<CPINFOEXW*>(__state->__win32_code_page.__code_page_info);
71+
if (::ztd::__idk_detail::__windows::__get_codepage_descirptor(
72+
__win32_code_page_id, &__codepage_info)) {
73+
__state->__win32_code_page.__code_page_info = static_cast<void*>(__codepage_info);
74+
}
6975
}
7076

7177
ZTD_USE(ZTD_C_LANGUAGE_LINKAGE)

source/ztd/cuneicode/windows_code_page.cpp

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ cnc_mcerr cnc_c32nrtomcn_windows_code_page(size_t* __p_maybe_dst_len, char** __p
8989
? INT_MAX
9090
: static_cast<int>(*__p_maybe_dst_len))
9191
: INT_MAX);
92+
CPINFOEXW* __p_info = (CPINFOEXW*)__p_state->__win32_code_page.__code_page_info;
9293
const int __win32_err = ::WideCharToMultiByte(static_cast<UINT>(__code_page_id),
9394
__used_defaults.__flags, __intermediate_output, static_cast<int>(__intermediate_size),
9495
__win32_dst, __win32_dst_len, __used_defaults.__p_default_char,
@@ -108,6 +109,12 @@ cnc_mcerr cnc_c32nrtomcn_windows_code_page(size_t* __p_maybe_dst_len, char** __p
108109
}
109110
}
110111
else {
112+
if (::ztd::__idk_detail::__windows::__widechar_to_multibyte_conversion_failed(
113+
__intermediate_output, __intermediate_size, __win32_dst, __p_info)) {
114+
__p_src[0] = __initial_src;
115+
__p_src_len[0] = __initial_src_len;
116+
return cnc_mcerr_invalid_sequence;
117+
}
111118
// okay, it should be good
112119
if (!__is_unbounded) {
113120
if (__p_maybe_dst_len[0] < static_cast<size_t>(__win32_err)) {
@@ -167,6 +174,7 @@ cnc_mcerr cnc_mcnrtoc32n_windows_code_page(size_t* __p_maybe_dst_len, ztd_char32
167174
const uint32_t __code_page_id = cnc_mcstate_get_win32_code_page(__p_state);
168175
const uint32_t __flags
169176
= ::ztd::__idk_detail::__windows::__multibyte_to_widechar_flags(__code_page_id);
177+
CPINFOEXW* __p_info = (CPINFOEXW*)__p_state->__win32_code_page.__code_page_info;
170178
for (; __input_read_size <= __initial_src_len; ++__input_read_size) {
171179
if (__input_read_size > CNC_MC_INPUT_MAX) {
172180
// can't do much else
@@ -180,6 +188,10 @@ cnc_mcerr cnc_mcnrtoc32n_windows_code_page(size_t* __p_maybe_dst_len, ztd_char32
180188
continue;
181189
}
182190
else {
191+
if (::ztd::__idk_detail::__windows::__multibyte_to_widechar_conversion_failed(
192+
__input_read_size, __initial_src, __p_intermediate_output, __p_info)) {
193+
return cnc_mcerr_invalid_sequence;
194+
}
183195
__intermediate_size = static_cast<size_t>(__win32_err);
184196
break;
185197
}
@@ -286,37 +298,45 @@ cnc_mcerr cnc_mwcnrtomcn_windows_code_page(size_t* __p_maybe_dst_len, char** __p
286298
const ztd_wchar_t* __initial_src = *__p_src;
287299
const size_t __initial_src_len = *__p_src_len;
288300
char __win32_blackhole_buffer[CNC_MC_MAX];
289-
char* __dst = __is_counting ? __win32_blackhole_buffer : *__p_maybe_dst;
301+
char* __win32_dst = __is_counting ? __win32_blackhole_buffer : *__p_maybe_dst;
290302
const size_t __dst_size
291303
= __is_unbounded ? ztdc_c_array_size(__win32_blackhole_buffer) : *__p_maybe_dst_len;
292304
const uint32_t __code_page_id = cnc_mcstate_get_win32_code_page(__p_state);
293305
BOOL __default_char_used = false;
294306
CHAR __default_char = '?';
295307
auto __used_defaults = ::ztd::__idk_detail::__windows::__widechar_to_multibyte_used_char(
296308
__code_page_id, &__default_char, &__default_char_used);
309+
CPINFOEXW* __p_info = (CPINFOEXW*)__p_state->__win32_code_page.__code_page_info;
297310
for (size_t __input_read_size = 1; __input_read_size <= __initial_src_len;
298311
++__input_read_size) {
299312
if (__input_read_size > CNC_MWC_INPUT_MAX) {
300313
break;
301314
}
302315
const int __win32_err = ::WideCharToMultiByte(static_cast<UINT>(__code_page_id),
303-
__used_defaults.__flags, __initial_src, static_cast<int>(__input_read_size), __dst,
304-
static_cast<int>(__dst_size), __used_defaults.__p_default_char,
316+
__used_defaults.__flags, __initial_src, static_cast<int>(__input_read_size),
317+
__win32_dst, static_cast<int>(__dst_size), __used_defaults.__p_default_char,
305318
__used_defaults.__p_default_char_used);
306319
if (__win32_err == 0) {
307320
DWORD __last_win32_err = ::GetLastError();
308-
if (__last_win32_err == ERROR_NO_UNICODE_TRANSLATION || __default_char_used) {
321+
if (__last_win32_err == ERROR_NO_UNICODE_TRANSLATION) {
309322
// loop around; we don't know if this is from a partial read (because of our
310323
// artifical limitations) or because it's a genuine error. This is, of course,
311324
// the problem with these crappy 1990s/2000s APIs.
312325
continue;
313326
}
327+
else if (__default_char_used) {
328+
return cnc_mcerr_invalid_sequence;
329+
}
314330
else if (!__is_unbounded && __last_win32_err == ERROR_INSUFFICIENT_BUFFER) {
315331
return cnc_mcerr_insufficient_output;
316332
}
317333
// if it's not one of those, then it's safe to loop around and do it again...
318334
}
319335
else {
336+
if (::ztd::__idk_detail::__windows::__widechar_to_multibyte_conversion_failed(
337+
__initial_src, __input_read_size, __win32_dst, __p_info)) {
338+
return cnc_mcerr_invalid_sequence;
339+
}
320340
if (!__is_unbounded) {
321341
if (__p_maybe_dst_len[0] < static_cast<size_t>(__win32_err)) {
322342
return cnc_mcerr_insufficient_output;
@@ -375,6 +395,7 @@ cnc_mcerr cnc_mcnrtomwcn_windows_code_page(size_t* __p_maybe_dst_len, ztd_wchar_
375395
const uint32_t __code_page_id = cnc_mcstate_get_win32_code_page(__p_state);
376396
uint32_t __flags
377397
= ::ztd::__idk_detail::__windows::__multibyte_to_widechar_flags(__code_page_id);
398+
CPINFOEXW* __p_info = (CPINFOEXW*)__p_state->__win32_code_page.__code_page_info;
378399
for (size_t __input_read_size = 1; __input_read_size <= __initial_src_len;
379400
++__input_read_size) {
380401
if (__input_read_size > CNC_MC_INPUT_MAX) {
@@ -391,6 +412,10 @@ cnc_mcerr cnc_mcnrtomwcn_windows_code_page(size_t* __p_maybe_dst_len, ztd_wchar_
391412
continue;
392413
}
393414
else {
415+
if (::ztd::__idk_detail::__windows::__multibyte_to_widechar_conversion_failed(
416+
__input_read_size, __initial_src, __dst, __p_info)) {
417+
return cnc_mcerr_invalid_sequence;
418+
}
394419
if (!__is_unbounded) {
395420
if (__p_maybe_dst_len[0] < static_cast<size_t>(__win32_err)) {
396421
return cnc_mcerr_insufficient_output;

0 commit comments

Comments
 (0)