use crate::{Error, Result};
#[derive(Default)]
pub(super) struct Bits {
value: u32,
pub(super) count: u8,
pub(super) total: u64,
}
impl Bits {
pub(super) fn read(&mut self, count: u8, input: &mut &[u8]) -> Result<Option<u32>> {
while self.count < count {
if !self.refill(input)? {
return Ok(None);
}
}
let value = self.value & ((1 << count) - 1);
self.value >>= count;
self.count -= count;
Ok(Some(value))
}
#[inline]
fn refill(&mut self, input: &mut &[u8]) -> Result<bool> {
let Some((&byte, remaining)) = input.split_first() else {
return Ok(false);
};
self.total = self.total.checked_add(1).ok_or(Error::LimitExceeded)?;
*input = remaining;
self.value |= u32::from(byte) << self.count;
self.count += 8;
Ok(true)
}
pub(super) fn align(&mut self) {
let padding = self.count % 8;
self.value >>= padding;
self.count -= padding;
}
}
pub(super) struct Huffman<const N: usize, const FAST: usize> {
counts: [u16; 16],
symbols: [u16; N],
max_bits: u8,
fast: [u16; FAST],
}
impl<const N: usize, const FAST: usize> Huffman<N, FAST> {
pub(super) fn new() -> Self {
Self {
counts: [0; 16],
symbols: [0; N],
max_bits: 0,
fast: [0; FAST],
}
}
pub(super) fn build(
&mut self,
lengths: &[u8],
allow_empty: bool,
allow_single: bool,
) -> Result<()> {
self.counts.fill(0);
self.max_bits = 0;
self.fast.fill(0);
for &length in lengths {
let count = self
.counts
.get_mut(usize::from(length))
.ok_or(Error::InvalidZlib)?;
*count += 1;
self.max_bits = self.max_bits.max(length);
}
if self.max_bits == 0 {
return if allow_empty {
Ok(())
} else {
Err(Error::InvalidZlib)
};
}
let mut left = 1_u32;
for &count in &self.counts[1..] {
left = (left * 2)
.checked_sub(u32::from(count))
.ok_or(Error::InvalidZlib)?;
}
if left != 0 && !(allow_single && self.max_bits == 1 && self.counts[1] == 1) {
return Err(Error::InvalidZlib);
}
let mut offsets = [0_usize; 16];
for length in 1..15 {
offsets[length + 1] = offsets[length] + usize::from(self.counts[length]);
}
for (symbol, &length) in lengths.iter().enumerate() {
if length != 0 {
let offset = &mut offsets[usize::from(length)];
self.symbols[*offset] = symbol as u16;
*offset += 1;
}
}
let (mut code, mut index) = (0_u16, 0_usize);
let fast_bits = self.max_bits.min(FAST.trailing_zeros() as u8);
for length in 1..=fast_bits {
let count = self.counts[usize::from(length)];
for offset in 0..count {
let prefix = usize::from((code + offset).reverse_bits() >> (16 - length));
let value = (u16::from(length) << 9) | self.symbols[index + usize::from(offset)];
for slot in (prefix..FAST).step_by(1 << length) {
self.fast[slot] = value;
}
}
index += usize::from(count);
code = code.wrapping_add(count).wrapping_mul(2);
}
Ok(())
}
}
pub(super) struct Symbol {
code: u32,
first: u32,
index: usize,
length: u8,
}
impl Default for Symbol {
fn default() -> Self {
Self {
code: 0,
first: 0,
index: 0,
length: 1,
}
}
}
impl Symbol {
pub(super) fn read<const N: usize, const FAST: usize>(
&mut self,
table: &Huffman<N, FAST>,
bits: &mut Bits,
input: &mut &[u8],
) -> Result<Option<u16>> {
if self.length == 1 && table.max_bits != 0 {
if bits.count == 0 && !bits.refill(input)? {
return Ok(None);
}
let value = table.fast[bits.value as usize & (FAST - 1)];
let length = (value >> 9) as u8;
if length != 0 && length <= bits.count {
bits.value >>= length;
bits.count -= length;
return Ok(Some(value & 511));
}
}
while self.length <= table.max_bits {
let Some(bit) = bits.read(1, input)? else {
return Ok(None);
};
self.code |= bit;
let count = u32::from(table.counts[usize::from(self.length)]);
let offset = self.code.wrapping_sub(self.first);
if offset < count {
let symbol = table.symbols[self.index + offset as usize];
*self = Self::default();
return Ok(Some(symbol));
}
self.index += count as usize;
self.first = (self.first + count) << 1;
self.code <<= 1;
self.length += 1;
}
Err(Error::InvalidZlib)
}
}