pub const END_OF_STREAM: u32 = u32::MAX;
const LASTPOS_SIZE: usize = 64;
#[derive(Clone, Copy, Debug)]
pub struct DecodeError {
pub code: u32,
pub line: i32,
pub column: i32,
}
pub struct Stream {
data: Vec<u8>,
pos: usize,
pushed: Vec<u32>,
tabs: i32,
lastcols: [i32; LASTPOS_SIZE],
curlastpos: usize,
firstlastpos: usize,
pub curcol: i32,
pub curline: i32,
tab_size: u32,
keep_tabs: bool,
pub errors: Vec<DecodeError>,
}
impl Stream {
pub const fn new(data: Vec<u8>, tab_size: u32, keep_tabs: bool) -> Self {
Self {
data,
pos: 0,
pushed: Vec::new(),
tabs: 0,
lastcols: [0; LASTPOS_SIZE],
curlastpos: 0,
firstlastpos: 0,
curcol: 1,
curline: 1,
tab_size,
keep_tabs,
errors: Vec::new(),
}
}
pub fn skip_bom(&mut self) -> Result<(), &'static str> {
if self.data.starts_with(&[0xEF, 0xBB, 0xBF]) {
self.pos = 3;
return Ok(());
}
if self.data.starts_with(&[0xFE, 0xFF]) || self.data.starts_with(&[0xFF, 0xFE]) {
return Err("UTF-16 input (byte order mark found) is not supported");
}
Ok(())
}
const fn is_eof(&self) -> bool {
self.pos >= self.data.len()
}
fn read_byte(&mut self) -> u32 {
if self.pos >= self.data.len() {
return END_OF_STREAM;
}
let b = self.data[self.pos];
self.pos += 1;
u32::from(b)
}
const fn unget_byte(&mut self) {
self.pos -= 1;
}
const fn pop_last_pos(&mut self) {
self.curlastpos = (self.curlastpos + 1) % LASTPOS_SIZE;
if self.curlastpos == self.firstlastpos {
self.firstlastpos = (self.firstlastpos + 1) % LASTPOS_SIZE;
}
}
const fn save_last_pos(&mut self) {
self.pop_last_pos();
self.lastcols[self.curlastpos] = self.curcol;
}
const fn restore_last_pos(&mut self) {
if self.firstlastpos == self.curlastpos {
self.curcol = 0;
} else {
self.curcol = self.lastcols[self.curlastpos];
if self.curlastpos == 0 {
self.curlastpos = LASTPOS_SIZE;
}
self.curlastpos -= 1;
}
}
pub fn read_char(&mut self) -> u32 {
if !self.pushed.is_empty() {
return self.pop_char();
}
self.save_last_pos();
if self.tabs > 0 {
self.curcol += 1;
self.tabs -= 1;
return u32::from(b' ');
}
loop {
let mut c = self.read_char_from_stream();
if c == END_OF_STREAM {
return END_OF_STREAM;
}
if c == u32::from(b'\n') {
self.curcol = 1;
self.curline += 1;
return c;
}
if c == u32::from(b'\t') {
if !self.keep_tabs {
let tabsize = i32::try_from(self.tab_size).unwrap_or(i32::MAX);
self.tabs = if tabsize > 0 {
tabsize - ((self.curcol - 1) % tabsize) - 1
} else {
0
};
c = u32::from(b' ');
}
self.curcol += 1;
return c;
}
if c == u32::from(b'\r') {
let next = self.read_char_from_stream();
if next != u32::from(b'\n') {
self.unget_char(next);
}
self.curcol = 1;
self.curline += 1;
return u32::from(b'\n');
}
if c == 0x1b {
return c;
}
if c < 32 {
continue;
}
self.curcol += 1;
return c;
}
}
fn pop_char(&mut self) -> u32 {
let Some(c) = self.pushed.pop() else {
return END_OF_STREAM;
};
if c == u32::from(b'\n') {
self.curcol = 1;
self.curline += 1;
self.pop_last_pos();
return c;
}
self.curcol += 1;
self.pop_last_pos();
c
}
pub fn unget_char(&mut self, c: u32) {
if c == END_OF_STREAM {
return;
}
self.pushed.push(c);
if c == u32::from(b'\n') {
self.curline -= 1;
}
self.restore_last_pos();
}
pub const fn end_of_input(&self) -> bool {
self.pushed.is_empty() && self.is_eof()
}
fn read_char_from_stream(&mut self) -> u32 {
if self.is_eof() {
return END_OF_STREAM;
}
let first = self.read_byte();
let (code, valid) = self.decode_utf8(first);
if valid {
code
} else {
self.errors.push(DecodeError {
code,
line: self.curline,
column: self.curcol,
});
0xFFFD
}
}
fn decode_utf8(&mut self, first: u32) -> (u32, bool) {
let mut has_error = false;
let (mut n, mut bytes) = if first <= 0x7F {
(first, 1)
} else if (first & 0xE0) == 0xC0 {
(first & 31, 2)
} else if (first & 0xF0) == 0xE0 {
(first & 15, 3)
} else if (first & 0xF8) == 0xF0 {
(first & 7, 4)
} else if (first & 0xFC) == 0xF8 {
has_error = true;
(first & 3, 5)
} else if (first & 0xFE) == 0xFC {
has_error = true;
(first & 1, 6)
} else {
has_error = true;
(first, 1)
};
let mut buf = [0u32; 6];
let mut i = 0;
while i < bytes - 1 && !self.is_eof() {
let b = self.read_byte();
buf[i] = b;
if (b & 0xC0) != 0x80 {
has_error = true;
bytes = i + 1;
self.unget_byte();
break;
}
n = (n << 6) | (b & 0x3F);
i += 1;
}
if i < bytes - 1 && !has_error {
has_error = true;
bytes = i + 1;
}
if !has_error && (n == 0xFFFE || n == 0xFFFF) {
has_error = true;
}
if !has_error && n > 0x0010_FFFF {
has_error = true;
}
if !has_error {
has_error = !sequence_is_valid(first, &buf, bytes, n);
}
(n, !has_error)
}
}
const VALID_UTF8: &[(u32, u32, usize, [u8; 8])] = &[
(
0x0000,
0x007F,
1,
[0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
),
(
0x0080,
0x07FF,
2,
[0xC2, 0xDF, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00],
),
(
0x0800,
0x0FFF,
3,
[0xE0, 0xE0, 0xA0, 0xBF, 0x80, 0xBF, 0x00, 0x00],
),
(
0x1000,
0xFFFF,
3,
[0xE1, 0xEF, 0x80, 0xBF, 0x80, 0xBF, 0x00, 0x00],
),
(
0x10000,
0x3FFFF,
4,
[0xF0, 0xF0, 0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF],
),
(
0x40000,
0xFFFFF,
4,
[0xF1, 0xF3, 0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF],
),
(
0x0010_0000,
0x0010_FFFF,
4,
[0xF4, 0xF4, 0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF],
),
];
const OFFSETS: [usize; 5] = [0, 1, 2, 4, 7];
fn sequence_is_valid(first: u32, successors: &[u32; 6], bytes: usize, n: u32) -> bool {
if bytes == 0 || bytes > 4 {
return false;
}
let lo = OFFSETS[bytes - 1];
let hi = OFFSETS[bytes] - 1;
if n < VALID_UTF8[lo].0 || n > VALID_UTF8[hi].1 {
return false;
}
for entry in &VALID_UTF8[lo..=hi] {
let mut ok = false;
for k in 0..bytes {
let byte = if k == 0 { first } else { successors[k - 1] };
let low = u32::from(entry.3[k * 2]);
let high = u32::from(entry.3[k * 2 + 1]);
ok = byte >= low && byte <= high;
if !ok {
break;
}
}
if ok {
return true;
}
}
false
}