use alloc::vec;
use alloc::vec::Vec;
use super::bits::Reverse;
use crate::decompressor::core::data::corrupt;
use crate::decompressor::error::DecodeError;
const MIN_LOG: u32 = 5;
const MAX_LOG: u32 = 12;
const ABSOLUTE_MAX_LOG: u32 = 15;
pub(super) const MAX_SYMBOLS: usize = 256;
#[derive(Copy, Clone, Debug, Default)]
struct Cell {
symbol: u8,
bits: u8,
next: u16,
}
#[derive(Debug)]
pub(super) struct Table {
log: u32,
cells: Vec<Cell>,
}
const fn high_bit(value: u32) -> u32 {
31 - value.leading_zeros()
}
impl Table {
pub(super) fn new(counts: &[i16]) -> Result<Self, DecodeError> {
if counts.len() < 2 || counts.len() > MAX_SYMBOLS {
return Err(corrupt());
}
let mut sum = 0u32;
for &count in counts {
if count < -1 {
return Err(corrupt());
}
sum += if count == -1 { 1 } else { count as u32 };
}
if sum == 0 || !sum.is_power_of_two() {
return Err(corrupt());
}
let log = high_bit(sum);
if !(MIN_LOG..=MAX_LOG).contains(&log) {
return Err(corrupt());
}
let size = 1usize << log;
let mask = size - 1;
let step = (size >> 1) + (size >> 3) + 3;
let mut cells = vec![Cell::default(); size];
let mut next = [0u32; MAX_SYMBOLS];
let mut high = size;
for (symbol, &count) in counts.iter().enumerate() {
if count == -1 {
high -= 1;
cells[high].symbol = symbol as u8;
next[symbol] = 1;
} else {
next[symbol] = count as u32;
}
}
let mut position = 0usize;
for (symbol, &count) in counts.iter().enumerate() {
for _ in 0..count.max(0) {
cells[position].symbol = symbol as u8;
position = (position + step) & mask;
while position >= high {
position = (position + step) & mask;
}
}
}
if position != 0 {
return Err(corrupt());
}
for cell in &mut cells {
let state = next[usize::from(cell.symbol)];
next[usize::from(cell.symbol)] += 1;
let bits = log - high_bit(state);
cell.bits = bits as u8;
cell.next = ((state << bits) - size as u32) as u16;
}
Ok(Self { log, cells })
}
}
pub(super) fn decode(
table: &Table,
src: &[u8],
states: usize,
count: usize,
out: &mut Vec<u8>,
) -> Result<(), DecodeError> {
let start = out.len();
let mut bits = Reverse::new(src)?;
let mut state = [0usize; 4];
for slot in &mut state[..states] {
*slot = bits.read(table.log) as usize;
}
let mut index = 0usize;
while bits.remaining() > 0 && out.len() - start < count {
let cell = table.cells[state[index]];
out.push(cell.symbol);
state[index] = usize::from(cell.next) + bits.read(u32::from(cell.bits)) as usize;
index = (index + 1) % states;
}
if bits.remaining() != 0 {
return Err(corrupt());
}
while out.len() - start < count {
let cell = table.cells[state[index]];
out.push(cell.symbol);
state[index] = usize::from(cell.next);
index = (index + 1) % states;
if cell.bits != 0 {
break;
}
}
if count - (out.len() - start) < states - 1 {
return Err(corrupt());
}
for _ in 1..states {
out.push(table.cells[state[index]].symbol);
index = (index + 1) % states;
}
if out.len() - start != count {
return Err(corrupt());
}
Ok(())
}
pub(super) fn read_ncount(src: &[u8]) -> Result<(Vec<i16>, usize), DecodeError> {
let bit_len = src.len() * 8;
let peek = |position: usize, n: u32| -> u32 {
let mut chunk = [0u8; 4];
let tail = src.get(position >> 3..).unwrap_or_default();
chunk[..tail.len().min(4)].copy_from_slice(&tail[..tail.len().min(4)]);
(u32::from_le_bytes(chunk) >> (position & 7)) & ((1u32 << n) - 1)
};
let log = peek(0, 4) + MIN_LOG;
if log > ABSOLUTE_MAX_LOG {
return Err(corrupt());
}
let mut position = 4usize;
let mut remaining = (1i32 << log) + 1;
let mut threshold = 1i32 << log;
let mut width = log + 1;
let mut counts = Vec::new();
let mut after_zero = false;
loop {
if after_zero {
loop {
let code = peek(position, 2) as usize;
position += 2;
counts.resize(counts.len() + code, 0);
if code != 3 {
break;
}
}
if counts.len() >= MAX_SYMBOLS {
return Err(corrupt());
}
}
let max = (2 * threshold - 1) - remaining;
let low = peek(position, width) as i32;
let mut count;
if (low & (threshold - 1)) < max {
count = low & (threshold - 1);
position += width as usize - 1;
} else {
count = low & (2 * threshold - 1);
if count >= threshold {
count -= max;
}
position += width as usize;
}
count -= 1;
remaining -= count.abs();
counts.push(count as i16);
after_zero = count == 0;
if remaining < threshold {
if remaining <= 1 {
break;
}
width = high_bit(remaining as u32) + 1;
threshold = 1 << (width - 1);
}
if counts.len() >= MAX_SYMBOLS {
break;
}
}
if remaining != 1 || counts.len() > MAX_SYMBOLS || position > bit_len {
return Err(corrupt());
}
Ok((counts, position.div_ceil(8)))
}
#[cfg(test)]
mod tests {
use super::*;
const COUNTS: [i16; 4] = [16, 8, 7, -1];
#[test]
fn tables_validate_their_counts() {
let table = Table::new(&COUNTS).unwrap();
assert_eq!(table.log, 5);
assert_eq!(table.cells.len(), 32);
assert_eq!(table.cells[31].symbol, 3);
assert_eq!((table.cells[31].bits, table.cells[31].next), (5, 0));
for bad in [
&[32][..],
&[16, 15][..],
&[-2, 33][..],
&[0, 0][..],
&[8, 8][..],
&[4096, 1][..],
] {
assert_eq!(Table::new(bad).unwrap_err(), corrupt());
}
assert_eq!(Table::new(&[0i16; 257]).unwrap_err(), corrupt());
assert!(Table::new(&[-1i16; 32]).is_ok());
assert!(Table::new(&[32, 0]).is_ok());
}
#[test]
fn a_table_that_never_needs_bits_leaves_no_room_to_flush() {
let table = Table::new(&[32, 0]).unwrap();
let mut out = Vec::new();
assert!(decode(&table, &[0, 0b100], 2, 5, &mut out).is_err());
assert_eq!(out, [0; 5]);
}
#[test]
fn streams_with_the_wrong_length_are_rejected() {
let table = Table::new(&[32, 0]).unwrap();
let mut out = Vec::new();
assert!(decode(&table, &[0, 0, 0b100], 2, 4, &mut out).is_err());
assert!(decode(&table, &[0b1], 2, 4, &mut out).is_err());
assert!(decode(&table, &[0], 2, 2, &mut out).is_err());
assert!(decode(&table, &[], 2, 2, &mut out).is_err());
assert!(decode(&table, &[0, 0b100], 2, 1, &mut out).is_err());
}
#[test]
fn count_headers_decode_hand_encoded_examples() {
assert_eq!(read_ncount(&[0xf0, 0x03]), Ok((vec![32], 2)));
assert_eq!(read_ncount(&[0; 64]), Ok((vec![-1; 32], 15)));
assert_eq!(read_ncount(&[0x10, 0x3f]), Ok((vec![16, 16], 2)));
assert_eq!(
read_ncount(&[0x10, 0xa3, 0x0f]),
Ok((vec![16, 0, 0, 16], 3))
);
}
#[test]
fn count_headers_reject_malformed_input() {
assert!(read_ncount(&[0x0f]).is_err());
assert!(read_ncount(&[]).is_err());
assert!(read_ncount(&[0xff; 64]).is_err());
assert!(read_ncount(&[0x10]).is_err());
let mut endless = vec![0x10, 0xfe];
endless.resize(120, 0xff);
assert!(read_ncount(&endless).is_err());
let mut many = vec![0x1f];
many.resize(200, 0x55);
assert!(read_ncount(&many).is_err());
}
}