|
|
dd89bb |
/********************************************************/
|
|
|
dd89bb |
/* ntapi: Native API core library */
|
|
|
64e606 |
/* Copyright (C) 2013--2021 SysDeer Technologies, LLC */
|
|
|
dd89bb |
/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
|
|
|
dd89bb |
/********************************************************/
|
|
|
dd89bb |
|
|
|
dd89bb |
#include <psxtypes/psxtypes.h>
|
|
|
dd89bb |
#include <ntapi/nt_status.h>
|
|
|
dd89bb |
#include <ntapi/nt_unicode.h>
|
|
|
766a63 |
#include "ntapi_impl.h"
|
|
|
dd89bb |
|
|
|
dd89bb |
/**
|
|
|
dd89bb |
* unofficial bit distribution table for comprehension purposes only
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* scalar nickname utf-16 utf-8[0] utf-8[1] utf-8[2] utf-8[3]
|
|
|
dd89bb |
* ------ -------- -------- -------- -------- -------- --------
|
|
|
dd89bb |
* 00000000 7x 00000000 0xxxxxxx
|
|
|
dd89bb |
* 0xxxxxxx 0xxxxxxx
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* 00000yyy 5y6x 00000yyy 110yyyyy 10xxxxxx
|
|
|
dd89bb |
* yyxxxxxx yyxxxxxx
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* zzzzyyyy 4z6y6x zzzzyyyy 1110zzzz 10yyyyyy 10xxxxxx
|
|
|
dd89bb |
* yyxxxxxx yyxxxxxx
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* 000uuuuu 5u4z6y6x 110110ww 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
|
|
|
dd89bb |
* zzzzyyyy wwzzzzyy
|
|
|
dd89bb |
* yyxxxxxx 110111yy
|
|
|
dd89bb |
* yyxxxxxx (where wwww = uuuuu - 1)
|
|
|
dd89bb |
*
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* validation of utf-8
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* from to utf-8[0] utf-8[1] utf-8[2] utf-8[3]
|
|
|
dd89bb |
* ------ ------ -------- -------- -------- --------
|
|
|
dd89bb |
* 0x0000 0x007F 00..7F
|
|
|
dd89bb |
* 0x0080 0x07FF C2..DF 80..BF
|
|
|
dd89bb |
* 0x0800 0x0FFF E0 A0..BF 80..BF
|
|
|
dd89bb |
* 0x1000 0xCFFF E1..EC 80..BF 80..BF
|
|
|
dd89bb |
* 0xD000 0xD7FF ED 80..9F 80..BF
|
|
|
dd89bb |
* 0xE000 0xFFFF EE..EF 80..BF 80..BF
|
|
|
dd89bb |
* 0x10000 0x3FFFF F0 90..BF 80..BF 80..BF
|
|
|
dd89bb |
* 0x40000 0xFFFFF F1..F3 80..BF 80..BF 80..BF
|
|
|
dd89bb |
* 0x100000 0x10FFFF F4 80..8F 80..BF 80..BF
|
|
|
dd89bb |
*
|
|
|
dd89bb |
**/
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
#define __AVAILABLE_CODE_POINTS 0x110000
|
|
|
dd89bb |
|
|
|
dd89bb |
int __stdcall __ntapi_uc_get_code_point_byte_count_utf8(uint32_t code_point)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
/* try clearing 7x bits */
|
|
|
dd89bb |
if ((code_point >> 7) == 0)
|
|
|
dd89bb |
return 1;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try clearing 5y + 6x bits */
|
|
|
dd89bb |
else if ((code_point >> 11) == 0)
|
|
|
dd89bb |
return 2;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try clearing 4z +6y + 6x bits */
|
|
|
dd89bb |
else if ((code_point >> 16) == 0)
|
|
|
dd89bb |
return 3;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try clearing 5u + 4z + 6y + 6x bits */
|
|
|
dd89bb |
else if ((code_point >> 21) == 0)
|
|
|
dd89bb |
return 4;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* __AVAILABLE_CODE_POINTS exceeded */
|
|
|
dd89bb |
else
|
|
|
dd89bb |
return 0;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
int __stdcall __ntapi_uc_get_code_point_byte_count_utf16(uint32_t code_point)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
/* try clearing 4z +6y + 6x bits */
|
|
|
dd89bb |
if ((code_point >> 16) == 0)
|
|
|
dd89bb |
return 2;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try clearing 5u + 4z + 6y + 6x bits */
|
|
|
dd89bb |
else if ((code_point >> 21) == 0)
|
|
|
dd89bb |
return 4;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* __AVAILABLE_CODE_POINTS exceeded */
|
|
|
dd89bb |
else
|
|
|
dd89bb |
return 0;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
/**
|
|
|
dd89bb |
* following is a straight-forward implementation
|
|
|
dd89bb |
* of unicode conversion and validation (see also:
|
|
|
dd89bb |
* Table 3-7 of the Unicode Standard, version 6.2).
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* the use of callbacks allows the validation
|
|
|
dd89bb |
* functions to be the basis of our utf-8 conversion
|
|
|
dd89bb |
* functions on the one hand, and the posix path arg
|
|
|
dd89bb |
* normalization routine on the other.
|
|
|
dd89bb |
**/
|
|
|
dd89bb |
|
|
|
dd89bb |
static int32_t __fastcall __default_callback_fn_utf8(nt_utf8_callback_args * args)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
args->src += args->byte_count;
|
|
|
dd89bb |
return NT_STATUS_SUCCESS;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
int32_t __stdcall __ntapi_uc_validate_unicode_stream_utf8(
|
|
|
dd89bb |
__in const unsigned char * ch,
|
|
|
dd89bb |
__in size_t size_in_bytes __optional,
|
|
|
dd89bb |
__out size_t * code_points __optional,
|
|
|
0e7864 |
__out const unsigned char ** addr_failed __optional,
|
|
|
dd89bb |
__in ntapi_uc_utf8_callback_fn ** callback_fn __optional,
|
|
|
dd89bb |
__in nt_utf8_callback_args * callback_args __optional)
|
|
|
dd89bb |
{
|
|
|
099813 |
int32_t status;
|
|
|
dd89bb |
const unsigned char * utf8;
|
|
|
dd89bb |
unsigned char * ch_boundary;
|
|
|
dd89bb |
unsigned char byte_count;
|
|
|
dd89bb |
size_t _code_points;
|
|
|
dd89bb |
|
|
|
dd89bb |
ntapi_uc_utf8_callback_fn * _callback_fn[5];
|
|
|
dd89bb |
nt_utf8_callback_args _callback_args;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (!callback_fn) {
|
|
|
dd89bb |
_callback_fn[0] = __default_callback_fn_utf8;
|
|
|
dd89bb |
_callback_fn[1] = __default_callback_fn_utf8;
|
|
|
dd89bb |
_callback_fn[2] = __default_callback_fn_utf8;
|
|
|
dd89bb |
_callback_fn[3] = __default_callback_fn_utf8;
|
|
|
dd89bb |
_callback_fn[4] = __default_callback_fn_utf8;
|
|
|
dd89bb |
callback_fn = (ntapi_uc_utf8_callback_fn **)&_callback_fn;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
if (!callback_args) {
|
|
|
dd89bb |
callback_args = &_callback_args;
|
|
|
dd89bb |
callback_args->src = (unsigned char *)0;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
if (callback_args->src)
|
|
|
dd89bb |
ch = callback_args->src;
|
|
|
dd89bb |
else
|
|
|
dd89bb |
callback_args->src = ch;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (size_in_bytes)
|
|
|
dd89bb |
ch_boundary = (unsigned char *)((uintptr_t)ch + size_in_bytes);
|
|
|
dd89bb |
else
|
|
|
dd89bb |
ch_boundary = (unsigned char *)(~0);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (!code_points)
|
|
|
dd89bb |
code_points = &_code_points;
|
|
|
dd89bb |
|
|
|
dd89bb |
while ((ch < ch_boundary) && (*ch)) {
|
|
|
dd89bb |
utf8 = ch;
|
|
|
dd89bb |
byte_count = 0;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try one byte */
|
|
|
dd89bb |
if (utf8[0] <= 0x7F)
|
|
|
dd89bb |
byte_count = 1;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try two bytes */
|
|
|
dd89bb |
else if ((++ch < ch_boundary)
|
|
|
dd89bb |
&& (utf8[0] >= 0xC2) && (utf8[0] <= 0xDF)
|
|
|
dd89bb |
&& (utf8[1] >= 0x80) && (utf8[1] <= 0xBF))
|
|
|
dd89bb |
byte_count = 2;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try three bytes */
|
|
|
dd89bb |
else if ((++ch < ch_boundary)
|
|
|
dd89bb |
&& (utf8[0] == 0xE0)
|
|
|
dd89bb |
&& (utf8[1] >= 0xA0) && (utf8[1] <= 0xBF)
|
|
|
dd89bb |
&& (utf8[2] >= 0x80) && (utf8[2] <= 0xBF))
|
|
|
dd89bb |
byte_count = 3;
|
|
|
dd89bb |
|
|
|
dd89bb |
else if (
|
|
|
dd89bb |
(utf8[0] >= 0xE1) && (utf8[0] <= 0xEC)
|
|
|
dd89bb |
&& (utf8[1] >= 0x80) && (utf8[1] <= 0xBF)
|
|
|
dd89bb |
&& (utf8[2] >= 0x80) && (utf8[2] <= 0xBF))
|
|
|
dd89bb |
byte_count = 3;
|
|
|
dd89bb |
|
|
|
dd89bb |
else if (
|
|
|
dd89bb |
(utf8[0] == 0xED)
|
|
|
dd89bb |
&& (utf8[1] >= 0x80) && (utf8[1] <= 0x9F)
|
|
|
dd89bb |
&& (utf8[2] >= 0x80) && (utf8[2] <= 0xBF))
|
|
|
dd89bb |
byte_count = 3;
|
|
|
dd89bb |
|
|
|
dd89bb |
else if (
|
|
|
dd89bb |
(utf8[0] >= 0xEE) && (utf8[0] <= 0xEF)
|
|
|
dd89bb |
&& (utf8[1] >= 0x80) && (utf8[1] <= 0xBF)
|
|
|
dd89bb |
&& (utf8[2] >= 0x80) && (utf8[2] <= 0xBF))
|
|
|
dd89bb |
byte_count = 3;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try four bytes */
|
|
|
dd89bb |
else if ((++ch < ch_boundary)
|
|
|
dd89bb |
&& (utf8[0] == 0xF0)
|
|
|
dd89bb |
&& (utf8[1] >= 0x90) && (utf8[1] <= 0xBF)
|
|
|
dd89bb |
&& (utf8[2] >= 0x80) && (utf8[2] <= 0xBF)
|
|
|
dd89bb |
&& (utf8[3] >= 0x80) && (utf8[3] <= 0xBF))
|
|
|
dd89bb |
byte_count = 4;
|
|
|
dd89bb |
|
|
|
dd89bb |
else if (
|
|
|
dd89bb |
(utf8[0] >= 0xF1) && (utf8[0] <= 0xF3)
|
|
|
dd89bb |
&& (utf8[1] >= 0x80) && (utf8[1] <= 0xBF)
|
|
|
dd89bb |
&& (utf8[2] >= 0x80) && (utf8[2] <= 0xBF)
|
|
|
dd89bb |
&& (utf8[3] >= 0x80) && (utf8[3] <= 0xBF))
|
|
|
dd89bb |
byte_count = 4;
|
|
|
dd89bb |
|
|
|
dd89bb |
else if (
|
|
|
dd89bb |
(utf8[0] == 0xF4)
|
|
|
dd89bb |
&& (utf8[1] >= 0x80) && (utf8[1] <= 0x8F)
|
|
|
dd89bb |
&& (utf8[2] >= 0x80) && (utf8[2] <= 0xBF)
|
|
|
dd89bb |
&& (utf8[3] >= 0x80) && (utf8[3] <= 0xBF))
|
|
|
dd89bb |
byte_count = 4;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (byte_count) {
|
|
|
dd89bb |
(*code_points)++;
|
|
|
dd89bb |
callback_args->byte_count = byte_count;
|
|
|
099813 |
|
|
|
099813 |
if ((status = callback_fn[byte_count](callback_args)))
|
|
|
099813 |
return status;
|
|
|
dd89bb |
} else {
|
|
|
dd89bb |
if (addr_failed)
|
|
|
dd89bb |
*addr_failed = (void *)utf8;
|
|
|
dd89bb |
return NT_STATUS_ILLEGAL_CHARACTER;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* advance, transcode if needed */
|
|
|
dd89bb |
ch = callback_args->src;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
e2e674 |
if ((ch < ch_boundary) && (*ch == 0)) {
|
|
|
e2e674 |
callback_args->byte_count = 1;
|
|
|
099813 |
return callback_fn[0](callback_args);
|
|
|
e2e674 |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
return NT_STATUS_SUCCESS;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
static int32_t __fastcall __default_callback_fn_utf16(nt_utf16_callback_args * args)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
if (args->byte_count == 4)
|
|
|
dd89bb |
args->src += 2;
|
|
|
dd89bb |
else
|
|
|
dd89bb |
args->src++;
|
|
|
dd89bb |
|
|
|
dd89bb |
return NT_STATUS_SUCCESS;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
int32_t __stdcall __ntapi_uc_validate_unicode_stream_utf16(
|
|
|
dd89bb |
__in const wchar16_t * wch,
|
|
|
dd89bb |
__in size_t size_in_bytes __optional,
|
|
|
dd89bb |
__out size_t * code_points __optional,
|
|
|
0e7864 |
__out const wchar16_t ** addr_failed __optional,
|
|
|
dd89bb |
__in ntapi_uc_utf16_callback_fn ** callback_fn __optional,
|
|
|
dd89bb |
__in nt_utf16_callback_args * callback_args __optional)
|
|
|
dd89bb |
{
|
|
|
7845d0 |
int32_t status;
|
|
|
dd89bb |
const wchar16_t * wch_trail;
|
|
|
dd89bb |
wchar16_t * wch_boundary;
|
|
|
dd89bb |
unsigned char byte_count;
|
|
|
dd89bb |
size_t _code_points;
|
|
|
dd89bb |
|
|
|
dd89bb |
ntapi_uc_utf16_callback_fn * _callback_fn[5];
|
|
|
dd89bb |
nt_utf16_callback_args _callback_args;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (!callback_fn) {
|
|
|
dd89bb |
_callback_fn[0] = __default_callback_fn_utf16;
|
|
|
dd89bb |
_callback_fn[1] = __default_callback_fn_utf16;
|
|
|
dd89bb |
_callback_fn[2] = __default_callback_fn_utf16;
|
|
|
dd89bb |
_callback_fn[3] = __default_callback_fn_utf16;
|
|
|
dd89bb |
_callback_fn[4] = __default_callback_fn_utf16;
|
|
|
dd89bb |
callback_fn = (ntapi_uc_utf16_callback_fn **)&_callback_fn;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
if (!callback_args) {
|
|
|
dd89bb |
callback_args = &_callback_args;
|
|
|
dd89bb |
callback_args->src = (wchar16_t *)0;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
if (callback_args->src)
|
|
|
dd89bb |
wch = callback_args->src;
|
|
|
dd89bb |
else
|
|
|
dd89bb |
callback_args->src = wch;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (size_in_bytes)
|
|
|
dd89bb |
wch_boundary = (wchar16_t *)((uintptr_t)wch + size_in_bytes);
|
|
|
dd89bb |
else
|
|
|
dd89bb |
wch_boundary = (wchar16_t *)(~0);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (!code_points)
|
|
|
dd89bb |
code_points = &_code_points;
|
|
|
dd89bb |
|
|
|
dd89bb |
while ((wch < wch_boundary) && (*wch)) {
|
|
|
dd89bb |
byte_count = 0;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try one byte */
|
|
|
dd89bb |
if (*wch <= 0x7F)
|
|
|
dd89bb |
byte_count = 1;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try two bytes */
|
|
|
dd89bb |
else if (*wch <= 0x7FF)
|
|
|
dd89bb |
byte_count = 2;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try three bytes */
|
|
|
dd89bb |
else if ((*wch < 0xD800) || (*wch >= 0xE000))
|
|
|
dd89bb |
byte_count = 3;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try four bytes */
|
|
|
dd89bb |
else if ((*wch >= 0xD800) && (*wch < 0xDC00)) {
|
|
|
dd89bb |
wch_trail = wch + 1;
|
|
|
dd89bb |
|
|
|
dd89bb |
if ((wch_trail < wch_boundary)
|
|
|
dd89bb |
&& (*wch_trail >= 0xDC00)
|
|
|
dd89bb |
&& (*wch_trail < 0xE000))
|
|
|
dd89bb |
byte_count = 4;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
if (byte_count) {
|
|
|
dd89bb |
(*code_points)++;
|
|
|
dd89bb |
callback_args->byte_count = byte_count;
|
|
|
7845d0 |
|
|
|
7845d0 |
if ((status = callback_fn[byte_count](callback_args)))
|
|
|
7845d0 |
return status;
|
|
|
dd89bb |
} else {
|
|
|
dd89bb |
if (addr_failed)
|
|
|
dd89bb |
*addr_failed = (void *)wch;
|
|
|
dd89bb |
return NT_STATUS_ILLEGAL_CHARACTER;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* advance, transcode as needed */
|
|
|
dd89bb |
wch = callback_args->src;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
e2e674 |
if ((wch < wch_boundary) && (*wch == 0)) {
|
|
|
e2e674 |
callback_args->byte_count = 1;
|
|
|
7845d0 |
return callback_fn[0](callback_args);
|
|
|
e2e674 |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
return NT_STATUS_SUCCESS;
|
|
|
dd89bb |
}
|