Files
RedBear-OS/src/header/wchar/utf8.rs
T
2025-02-08 14:05:37 -03:00

109 lines
3.2 KiB
Rust

//UTF implementation parts for wchar.h.
//Partially ported from the Sortix libc
use core::{char, slice, str, usize};
use crate::{
header::errno,
platform::{self, types::*},
};
use super::mbstate_t;
// Based on
// https://github.com/rust-lang/rust/blob/f24ce9b/library/core/src/str/validations.rs#L232-L257,
// because apparently somebody removed the `pub use` statement from `core::str`.
// https://tools.ietf.org/html/rfc3629
static UTF8_CHAR_WIDTH: [u8; 256] = [
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, // 0x1F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, // 0x3F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, // 0x5F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, // 0x7F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, // 0x9F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, // 0xBF
0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, // 0xDF
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF
4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF
];
// Given a first byte, determines how many bytes are in this UTF-8 character.
#[inline]
fn utf8_char_width(b: u8) -> usize {
UTF8_CHAR_WIDTH[usize::from(b)].into()
}
//It's guaranteed that we don't have any nullpointers here
pub unsafe fn mbrtowc(pwc: *mut wchar_t, s: *const c_char, n: usize, ps: *mut mbstate_t) -> usize {
let size = utf8_char_width(*s as u8);
if size > n {
platform::ERRNO.set(errno::EILSEQ);
return -2isize as usize;
}
if size == 0 {
platform::ERRNO.set(errno::EILSEQ);
return -1isize as usize;
}
let slice = slice::from_raw_parts(s as *const u8, size);
let decoded = str::from_utf8(slice);
if decoded.is_err() {
platform::ERRNO.set(errno::EILSEQ);
return -1isize as usize;
}
let wc = decoded.unwrap();
let result: wchar_t = wc.chars().next().unwrap() as wchar_t;
if !pwc.is_null() {
*pwc = result;
}
if result != 0 {
size
} else {
0
}
}
//It's guaranteed that we don't have any nullpointers here
pub unsafe fn wcrtomb(s: *mut c_char, wc: wchar_t, ps: *mut mbstate_t) -> usize {
let dc = char::from_u32(wc as u32);
if dc.is_none() {
platform::ERRNO.set(errno::EILSEQ);
return -1isize as usize;
}
let c = dc.unwrap();
let size = c.len_utf8();
let slice = slice::from_raw_parts_mut(s as *mut u8, size);
c.encode_utf8(slice);
size
}
/// Gets the encoded length of a character. It is used to recognize wide characters
pub fn get_char_encoded_length(first_byte: u8) -> Option<usize> {
if first_byte >> 7 == 0 {
Some(1)
} else if first_byte >> 5 == 6 {
Some(2)
} else if first_byte >> 4 == 0xe {
Some(3)
} else if first_byte >> 3 == 0x1e {
Some(4)
} else {
None
}
}