use alloc::vec;
use alloc::vec::Vec;
use super::bits::Reverse;
use crate::decompressor::core::data::corrupt;
use crate::decompressor::error::DecodeError;
const BYTE_MAX_LOG: u32 = 12;
const WIDE_MAX_LOG: u32 = 20;
#[derive(Debug)]
pub(super) struct Table {
log: u32,
cells: Vec<u32>,
}
impl Table {
fn new(weights: &[u8], max_log: u32) -> Result<Self, DecodeError> {
let mut sum = 0u64;
let mut present = 0usize;
let mut counts = [0usize; WIDE_MAX_LOG as usize + 1];
for &weight in weights {
if u32::from(weight) > max_log {
return Err(corrupt());
}
sum += (1u64 << weight) >> 1;
counts[usize::from(weight)] += 1;
present += usize::from(weight != 0);
}
if present < 2 || !sum.is_power_of_two() {
return Err(corrupt());
}
let log = sum.trailing_zeros();
if log > max_log {
return Err(corrupt());
}
let mut start = [0usize; WIDE_MAX_LOG as usize + 2];
for weight in 1..=log as usize {
start[weight + 1] = start[weight] + (counts[weight] << (weight - 1));
}
let mut cells = vec![0u32; 1usize << log];
for (symbol, &weight) in weights.iter().enumerate() {
if weight == 0 {
continue;
}
let weight = usize::from(weight);
let length = 1usize << (weight - 1);
let first = start[weight];
start[weight] += length;
let bits = log + 1 - weight as u32;
cells
.get_mut(first..first + length)
.ok_or_else(corrupt)?
.fill((bits << 16) | symbol as u32);
}
Ok(Self { log, cells })
}
pub(super) fn bytes(weights: &[u8]) -> Result<Self, DecodeError> {
if weights.len() < 2 || weights.len() > 256 {
return Err(corrupt());
}
Self::new(weights, BYTE_MAX_LOG)
}
pub(super) fn wide(weights: &[u8]) -> Result<Self, DecodeError> {
if weights.len() < 2 || weights.len() > 65536 {
return Err(corrupt());
}
Self::new(weights, WIDE_MAX_LOG)
}
fn stream<const WIDE: bool>(
&self,
src: &[u8],
count: usize,
exact: bool,
out: &mut Vec<u8>,
) -> Result<(), DecodeError> {
let mut bits = Reverse::new(src)?;
for _ in 0..count {
let cell = self.cells[bits.peek(self.log) as usize];
bits.skip(cell >> 16);
if WIDE {
out.extend_from_slice(&(cell as u16).to_le_bytes());
} else {
out.push(cell as u8);
}
}
if bits.remaining() < 0 || (exact && bits.remaining() != 0) {
return Err(corrupt());
}
Ok(())
}
pub(super) fn single(
&self,
src: &[u8],
count: usize,
out: &mut Vec<u8>,
) -> Result<(), DecodeError> {
self.stream::<false>(src, count, true, out)
}
pub(super) fn quad(
&self,
src: &[u8],
count: usize,
out: &mut Vec<u8>,
) -> Result<(), DecodeError> {
if src.len() < 10 {
return Err(corrupt());
}
let length = |at: usize| usize::from(u16::from_le_bytes([src[at], src[at + 1]]));
let (first, second, third) = (length(0), length(2), length(4));
let body = &src[6..];
let fourth = body
.len()
.checked_sub(first + second + third)
.ok_or_else(corrupt)?;
let segment = count.div_ceil(4);
if segment * 3 > count {
return Err(corrupt());
}
let mut rest = body;
for (index, size) in [first, second, third, fourth].into_iter().enumerate() {
let (part, tail) = rest.split_at(size);
rest = tail;
let symbols = if index < 3 {
segment
} else {
count - 3 * segment
};
self.stream::<false>(part, symbols, true, out)?;
}
Ok(())
}
fn wide_block<'a>(
&self,
src: &'a [u8],
room: usize,
out: &mut Vec<u8>,
) -> Result<(&'a [u8], usize), DecodeError> {
let (head, rest) = src.split_first_chunk::<8>().ok_or_else(corrupt)?;
let count = u32::from_le_bytes([head[0], head[1], head[2], head[3]]) as usize;
let size = u32::from_le_bytes([head[4], head[5], head[6], head[7]]) as usize;
if size > rest.len() || count > room {
return Err(corrupt());
}
let (payload, rest) = rest.split_at(size);
self.stream::<true>(payload, count, false, out)?;
Ok((rest, count))
}
pub(super) fn wide_blocks(
&self,
mut src: &[u8],
count: usize,
x4: bool,
out: &mut Vec<u8>,
) -> Result<(), DecodeError> {
let mut decoded = 0usize;
for _ in 0..if x4 { 4 } else { 1 } {
let (rest, block) = self.wide_block(src, count - decoded, out)?;
src = rest;
decoded += block;
}
if decoded != count || !src.is_empty() {
return Err(corrupt());
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
const WEIGHTS: [u8; 3] = [3, 2, 2];
#[test]
fn canonical_codes_follow_ascending_weight_then_symbol() {
let table = Table::bytes(&WEIGHTS).unwrap();
assert_eq!(table.log, 3);
let symbols: Vec<u8> = table.cells.iter().map(|&cell| cell as u8).collect();
let lengths: Vec<u32> = table.cells.iter().map(|&cell| cell >> 16).collect();
assert_eq!(symbols, [1, 1, 2, 2, 0, 0, 0, 0]);
assert_eq!(lengths, [2, 2, 2, 2, 1, 1, 1, 1]);
}
#[test]
fn weights_are_validated() {
for bad in [
&[1u8][..],
&[1, 0][..],
&[13, 12][..],
&[1, 1, 1][..],
&[0, 0][..],
&[12, 12, 12][..],
] {
assert_eq!(Table::bytes(bad).unwrap_err(), corrupt());
}
assert!(Table::bytes(&[1, 1]).is_ok());
assert!(Table::bytes(&[0; 257]).is_err());
assert_eq!(Table::wide(&[20, 20, 0, 1]).unwrap_err(), corrupt());
assert!(Table::wide(&[0; 65537]).is_err());
assert!(Table::wide(&[21, 21]).is_err());
assert_eq!(Table::wide(&[20, 20]).unwrap().log, 20);
}
fn pack(codes: &[(u32, u32)]) -> Vec<u8> {
let mut acc = 0u64;
let mut nbits = 0;
for &(value, width) in codes {
acc |= u64::from(value) << nbits;
nbits += width;
}
acc |= 1 << nbits;
nbits += 1;
acc.to_le_bytes()[..(nbits as usize).div_ceil(8)].to_vec()
}
#[test]
fn single_streams_must_end_exactly() {
let table = Table::bytes(&WEIGHTS).unwrap();
let reversed = pack(&[(0b01, 2), (0b00, 2), (0b1, 1)]);
let mut out = Vec::new();
table.single(&reversed, 3, &mut out).unwrap();
assert_eq!(out, [0, 1, 2]);
out.clear();
assert!(table.single(&reversed, 2, &mut out).is_err());
assert!(table.single(&reversed, 4, &mut out).is_err());
assert!(table.single(&[], 1, &mut out).is_err());
}
#[test]
fn quad_streams_split_the_output_in_quarters() {
let table = Table::bytes(&WEIGHTS).unwrap();
let one = pack(&[(0b1, 1)]);
let mut framed = Vec::new();
for _ in 0..3 {
framed.extend_from_slice(&(one.len() as u16).to_le_bytes());
}
for _ in 0..4 {
framed.extend_from_slice(&one);
}
let mut out = Vec::new();
table.quad(&framed, 4, &mut out).unwrap();
assert_eq!(out, [0, 0, 0, 0]);
out.clear();
assert!(table.quad(&framed, 2, &mut out).is_err());
let mut bad = framed.clone();
bad[0] = 0xff;
assert!(table.quad(&bad, 4, &mut out).is_err());
assert!(table.quad(&framed[..9], 4, &mut out).is_err());
}
#[test]
fn wide_blocks_decode_sixteen_bit_symbols() {
let table = Table::wide(&[1, 1]).unwrap();
let bits = pack(&[(1, 1), (0, 1), (1, 1)]);
let mut block = Vec::new();
block.extend_from_slice(&3u32.to_le_bytes());
block.extend_from_slice(&(bits.len() as u32).to_le_bytes());
block.extend_from_slice(&bits);
let mut out = Vec::new();
table.wide_blocks(&block, 3, false, &mut out).unwrap();
assert_eq!(out, [1, 0, 0, 0, 1, 0]);
let mut quad = block.clone();
for _ in 0..3 {
quad.extend_from_slice(&0u32.to_le_bytes());
quad.extend_from_slice(&1u32.to_le_bytes());
quad.push(1);
}
out.clear();
table.wide_blocks(&quad, 3, true, &mut out).unwrap();
assert_eq!(out.len(), 6);
assert!(table.wide_blocks(&block, 4, false, &mut out).is_err());
assert!(table.wide_blocks(&block, 2, false, &mut out).is_err());
let mut trailing = block.clone();
trailing.push(0);
assert!(table.wide_blocks(&trailing, 3, false, &mut out).is_err());
assert!(table.wide_blocks(&block[..7], 3, false, &mut out).is_err());
assert!(table.wide_blocks(&block[..8], 3, false, &mut out).is_err());
let mut starved = Vec::new();
starved.extend_from_slice(&9u32.to_le_bytes());
starved.extend_from_slice(&1u32.to_le_bytes());
starved.push(0b11);
assert!(table.wide_blocks(&starved, 9, false, &mut out).is_err());
}
}