pub const TS_DECODE_ERROR: i32 = -1;
#[inline]
pub fn utf8_next(string: &[u8], offset: usize) -> (u32, i32) {
if offset >= string.len() {
return (0, -1);
}
let b0 = string[offset];
if b0 < 0x80 {
return (1, i32::from(b0));
}
let (expected_len, mut code_point) = if b0 < 0xC2 {
return (1, -1);
} else if b0 < 0xE0 {
(2, i32::from(b0 & 0x1F))
} else if b0 < 0xF0 {
(3, i32::from(b0 & 0x0F))
} else if b0 < 0xF5 {
(4, i32::from(b0 & 0x07))
} else {
return (1, -1);
};
let remaining = string.len() - offset;
if remaining < expected_len {
return (1, -1);
}
for i in 1..expected_len {
let b = string[offset + i];
if (b & 0xC0) != 0x80 {
return (1, -1);
}
code_point = (code_point << 6) | i32::from(b & 0x3F);
}
let bytes_consumed = match expected_len {
2 if code_point >= 0x80 => 2,
3 if code_point >= 0x800 && !(0xD800..=0xDFFF).contains(&code_point) => 3,
4 if (0x1_0000..=0x0010_FFFF).contains(&code_point) => 4,
_ => return (1, -1),
};
(bytes_consumed, code_point)
}
#[inline]
pub fn utf16le_next(string: &[u8], offset: usize) -> (u32, i32) {
if offset + 1 >= string.len() {
return (0, -1);
}
let c = u16::from_le_bytes([string[offset], string[offset + 1]]);
if !(0xD800..=0xDFFF).contains(&c) {
return (2, i32::from(c));
}
if (0xD800..=0xDBFF).contains(&c) {
if offset + 3 >= string.len() {
return (2, -1);
}
let c2 = u16::from_le_bytes([string[offset + 2], string[offset + 3]]);
if (0xDC00..=0xDFFF).contains(&c2) {
let code_point = 0x10000 + ((i32::from(c) - 0xD800) << 10) + (i32::from(c2) - 0xDC00);
return (4, code_point);
}
}
(2, -1)
}
#[inline]
pub fn utf16be_next(string: &[u8], offset: usize) -> (u32, i32) {
if offset + 1 >= string.len() {
return (0, -1);
}
let c = u16::from_be_bytes([string[offset], string[offset + 1]]);
if !(0xD800..=0xDFFF).contains(&c) {
return (2, i32::from(c));
}
if (0xD800..=0xDBFF).contains(&c) {
if offset + 3 >= string.len() {
return (2, -1);
}
let c2 = u16::from_be_bytes([string[offset + 2], string[offset + 3]]);
if (0xDC00..=0xDFFF).contains(&c2) {
let code_point = 0x10000 + ((i32::from(c) - 0xD800) << 10) + (i32::from(c2) - 0xDC00);
return (4, code_point);
}
}
(2, -1)
}
pub unsafe extern "C" fn ts_decode_utf8(
string: *const u8,
length: u32,
code_point: *mut i32,
) -> u32 {
if string.is_null() || length == 0 {
unsafe {
*code_point = -1;
}
return 0;
}
let slice = unsafe { core::slice::from_raw_parts(string, length as usize) };
let (consumed, cp) = utf8_next(slice, 0);
unsafe {
*code_point = cp;
}
consumed
}
pub unsafe extern "C" fn ts_decode_utf16_le(
string: *const u8,
length: u32,
code_point: *mut i32,
) -> u32 {
if string.is_null() || length < 2 {
unsafe {
*code_point = -1;
}
return 0;
}
let slice = unsafe { core::slice::from_raw_parts(string, length as usize) };
let (consumed, cp) = utf16le_next(slice, 0);
unsafe {
*code_point = cp;
}
consumed
}
pub unsafe extern "C" fn ts_decode_utf16_be(
string: *const u8,
length: u32,
code_point: *mut i32,
) -> u32 {
if string.is_null() || length < 2 {
unsafe {
*code_point = -1;
}
return 0;
}
let slice = unsafe { core::slice::from_raw_parts(string, length as usize) };
let (consumed, cp) = utf16be_next(slice, 0);
unsafe {
*code_point = cp;
}
consumed
}