| |
| |
| |
| |
| |
| |
| #include <psxtypes/psxtypes.h> |
| #include <ntapi/nt_status.h> |
| #include <ntapi/nt_unicode.h> |
| #include "ntapi_impl.h" |
| |
| |
| static int32_t __fastcall __utf16_to_utf8_handler_1byte_or_null_termination(nt_utf16_callback_args * args) |
| { |
| |
| |
| |
| |
| |
| uint8_t * dst; |
| |
| if (args->dst >= args->dst_cap) |
| return NT_STATUS_BUFFER_TOO_SMALL; |
| |
| dst = (uint8_t *)args->dst; |
| *dst = *(uint8_t *)(args->src); |
| |
| |
| args->src++; |
| args->dst = (void *)((uintptr_t)(args->dst) + 1); |
| |
| |
| args->bytes_written++; |
| |
| return NT_STATUS_SUCCESS; |
| } |
| |
| |
| static int32_t __fastcall __utf16_to_utf8_handler_2bytes(nt_utf16_callback_args * args) |
| { |
| |
| |
| |
| |
| |
| const wchar16_t * src; |
| uint8_t * dst; |
| |
| wchar16_t wx; |
| wchar16_t wy; |
| |
| if ((uintptr_t)(args->dst) + 1 >= (uintptr_t)(args->dst_cap)) |
| return NT_STATUS_BUFFER_TOO_SMALL; |
| |
| src = args->src; |
| dst = (uint8_t *)args->dst; |
| |
| wy = *src; |
| wy >>= 6; |
| |
| wx = *src; |
| wx <<= 10; |
| wx >>= 10; |
| |
| |
| *dst = (char)(0xC0 | wy); |
| dst++; |
| |
| |
| *dst = (char)(0x80 | wx); |
| |
| |
| args->src++; |
| args->dst = (void *)((uintptr_t)(args->dst) + 2); |
| |
| |
| args->bytes_written += 2; |
| |
| return NT_STATUS_SUCCESS; |
| } |
| |
| |
| static int32_t __fastcall __utf16_to_utf8_handler_3bytes(nt_utf16_callback_args * args) |
| { |
| |
| |
| |
| |
| |
| const wchar16_t * src; |
| uint8_t * dst; |
| |
| wchar16_t wx; |
| wchar16_t wy; |
| wchar16_t wz; |
| |
| if ((uintptr_t)(args->dst) + 2 >= (uintptr_t)(args->dst_cap)) |
| return NT_STATUS_BUFFER_TOO_SMALL; |
| |
| src = args->src; |
| dst = (uint8_t *)args->dst; |
| |
| wz = *src; |
| wz >>= 12; |
| |
| wy = *src; |
| wy <<= 4; |
| wy >>= 10; |
| |
| wx = *src; |
| wx <<= 10; |
| wx >>= 10; |
| |
| |
| *dst = (char)(0xE0 | wz); |
| dst++; |
| |
| |
| *dst = (char)(0x80 | wy); |
| dst++; |
| |
| |
| *dst = (char)(0x80 | wx); |
| |
| |
| args->src++; |
| args->dst = (void *)((uintptr_t)(args->dst) + 3); |
| |
| |
| args->bytes_written += 3; |
| |
| return NT_STATUS_SUCCESS; |
| } |
| |
| |
| static int32_t __fastcall __utf16_to_utf8_handler_4bytes(nt_utf16_callback_args * args) |
| { |
| |
| |
| |
| |
| |
| const wchar16_t * src; |
| uint8_t * dst; |
| |
| wchar16_t wx; |
| wchar16_t wz; |
| |
| wchar16_t wy_low; |
| wchar16_t wy_high; |
| wchar16_t ww; |
| wchar16_t uuuuu; |
| wchar16_t u_low; |
| wchar16_t u_high; |
| |
| if ((uintptr_t)(args->dst) + 3 >= (uintptr_t)(args->dst_cap)) |
| return NT_STATUS_BUFFER_TOO_SMALL; |
| |
| src = args->src; |
| dst = (uint8_t *)args->dst; |
| |
| |
| wy_high = *src; |
| wy_high <<= 14; |
| wy_high >>= 10; |
| |
| wz = *src; |
| wz <<= 10; |
| wz >>= 12; |
| |
| ww = *src; |
| ww <<= 6; |
| ww >>= 12; |
| |
| |
| src++; |
| |
| |
| wx = *src; |
| wx <<= 10; |
| wx >>= 10; |
| |
| wy_low = *src; |
| wy_low <<= 6; |
| wy_low >>= 12; |
| |
| |
| uuuuu = ww + 1; |
| u_low = uuuuu; |
| u_low >>= 2; |
| |
| u_high = uuuuu; |
| u_high <<= 14; |
| u_high >>= 10; |
| |
| |
| *dst = (char)(0xF0 | u_low); |
| dst++; |
| |
| |
| *dst = (char)(0x80 | u_high | wz); |
| dst++; |
| |
| |
| *dst = (char)(0x80 | wy_low | wy_high); |
| dst++; |
| |
| |
| *dst = (char)(0x80 | wx); |
| |
| |
| args->src += 2; |
| args->dst = (void *)((uintptr_t)(args->dst) + 4); |
| |
| |
| args->bytes_written += 4; |
| |
| return NT_STATUS_SUCCESS; |
| } |
| |
| |
| static int32_t __fastcall __update_stream_leftover_info_utf16( |
| __in_out nt_unicode_conversion_params_utf16_to_utf8 * params) |
| { |
| int32_t status; |
| ptrdiff_t offset; |
| wchar16_t * wlead; |
| |
| offset = (uintptr_t)params->src + (uintptr_t)params->src_size_in_bytes - (uintptr_t)params->addr_failed; |
| wlead = (wchar16_t *)params->addr_failed; |
| |
| |
| if ((offset == 2) && (*wlead >= 0xD800) && (*wlead < 0xDC00)) { |
| |
| params->leftover_count = 2; |
| params->leftover_bytes = *wlead; |
| params->leftover_bytes <<= 16; |
| status = NT_STATUS_SUCCESS; |
| } else { |
| params->leftover_count = 0; |
| params->leftover_bytes = 0; |
| status = NT_STATUS_ILLEGAL_CHARACTER; |
| } |
| |
| return status; |
| } |
| |
| |
| int32_t __stdcall __ntapi_uc_convert_unicode_stream_utf16_to_utf8( |
| __in_out nt_unicode_conversion_params_utf16_to_utf8 * params) |
| { |
| int32_t status; |
| nt_utf16_callback_args args; |
| ntapi_uc_utf16_callback_fn * callback_fn[5]; |
| |
| callback_fn[0] = (ntapi_uc_utf16_callback_fn *)__utf16_to_utf8_handler_1byte_or_null_termination; |
| callback_fn[1] = (ntapi_uc_utf16_callback_fn *)__utf16_to_utf8_handler_1byte_or_null_termination; |
| callback_fn[2] = (ntapi_uc_utf16_callback_fn *)__utf16_to_utf8_handler_2bytes; |
| callback_fn[3] = (ntapi_uc_utf16_callback_fn *)__utf16_to_utf8_handler_3bytes; |
| callback_fn[4] = (ntapi_uc_utf16_callback_fn *)__utf16_to_utf8_handler_4bytes; |
| |
| args.src = params->src; |
| args.dst = params->dst; |
| args.dst_cap = (void *)((uintptr_t)(params->dst) + (params->dst_size_in_bytes)); |
| args.bytes_written = params->bytes_written; |
| |
| status = __ntapi_uc_validate_unicode_stream_utf16( |
| params->src, |
| params->src_size_in_bytes, |
| ¶ms->code_points, |
| ¶ms->addr_failed, |
| callback_fn, |
| &args); |
| |
| params->bytes_written = args.bytes_written; |
| |
| switch (status) { |
| case NT_STATUS_SUCCESS: |
| params->addr_failed = 0; |
| params->leftover_bytes = 0; |
| params->leftover_count = 0; |
| return status; |
| |
| case NT_STATUS_BUFFER_TOO_SMALL: |
| params->addr_failed = args.src; |
| params->leftover_bytes = 0; |
| params->leftover_count = 0; |
| return status; |
| |
| default: |
| status = __update_stream_leftover_info_utf16(params); |
| } |
| |
| |
| params->leftover_bytes <<= (8 * (sizeof(uintptr_t) - sizeof(uint32_t))); |
| |
| return status; |
| } |
| |
| |
| int32_t __stdcall __ntapi_uc_convert_unicode_stream_utf16_to_utf32( |
| __in_out nt_unicode_conversion_params_utf16_to_utf32 * params) |
| { |
| (void)params; |
| return NT_STATUS_SUCCESS; |
| } |