use alloc::vec::Vec;
pub const FAST_LOOKUP_BITS: u32 = 10;
const FAST_LOOKUP_SIZE: usize = 1 << FAST_LOOKUP_BITS;
const MAX_INTERNAL_CODE_SIZE: usize = 31;
#[derive(Clone, Default)]
pub struct HuffmanDecodingTable {
pub code_sizes: Vec<u8>,
pub lookup: Vec<i32>,
pub tree: Vec<i16>,
}
impl HuffmanDecodingTable {
pub fn new() -> Self {
Self::default()
}
pub fn clear(&mut self) {
self.code_sizes.clear();
self.lookup.clear();
self.tree.clear();
}
pub fn is_valid(&self) -> bool {
!self.code_sizes.is_empty()
}
pub fn init(&mut self, total_syms: usize, code_sizes: &[u8]) -> bool {
self.clear();
if total_syms == 0 {
return true;
}
self.code_sizes = code_sizes[..total_syms].to_vec();
self.lookup = vec![0i32; FAST_LOOKUP_SIZE];
self.tree = vec![0i16; total_syms * 2];
let mut syms_using_codesize = [0u32; MAX_INTERNAL_CODE_SIZE + 1];
for &cs in &code_sizes[..total_syms] {
if cs as usize > MAX_INTERNAL_CODE_SIZE {
return false;
}
syms_using_codesize[cs as usize] += 1;
}
let mut next_code = [0u32; MAX_INTERNAL_CODE_SIZE + 2];
let mut used_syms = 0u32;
let mut total = 0u32;
for i in 1..MAX_INTERNAL_CODE_SIZE {
used_syms += syms_using_codesize[i];
total = total.wrapping_add(syms_using_codesize[i]) << 1;
next_code[i + 1] = total;
}
if ((1u32 << MAX_INTERNAL_CODE_SIZE) != total) && (used_syms != 1) {
return false;
}
let mut tree_next: i32 = -1;
for (sym_index, &cs) in code_sizes[..total_syms].iter().enumerate() {
let code_size = cs as u32;
if code_size == 0 {
continue;
}
let mut cur_code = next_code[code_size as usize];
next_code[code_size as usize] += 1;
let mut rev_code = 0u32;
for _ in 0..code_size {
rev_code = (rev_code << 1) | (cur_code & 1);
cur_code >>= 1;
}
if code_size <= FAST_LOOKUP_BITS {
let k = ((code_size << 16) | sym_index as u32) as i32;
let mut rc = rev_code;
while (rc as usize) < FAST_LOOKUP_SIZE {
if self.lookup[rc as usize] != 0 {
return false;
}
self.lookup[rc as usize] = k;
rc += 1 << code_size;
}
continue;
}
let idx0 = (rev_code & (FAST_LOOKUP_SIZE as u32 - 1)) as usize;
let mut tree_cur = self.lookup[idx0];
if tree_cur == 0 {
self.lookup[idx0] = tree_next;
tree_cur = tree_next;
tree_next -= 2;
}
if tree_cur >= 0 {
return false;
}
let mut rc = rev_code >> (FAST_LOOKUP_BITS - 1);
let mut j = code_size as i32;
while j > FAST_LOOKUP_BITS as i32 + 1 {
rc >>= 1;
tree_cur -= (rc & 1) as i32;
let idx = -tree_cur - 1;
if idx < 0 {
return false;
}
let idx = idx as usize;
if idx >= self.tree.len() {
self.tree.resize(idx + 1, 0);
}
if self.tree[idx] == 0 {
self.tree[idx] = tree_next as i16;
tree_cur = tree_next;
tree_next -= 2;
} else {
tree_cur = self.tree[idx] as i32;
if tree_cur >= 0 {
return false;
}
}
j -= 1;
}
rc >>= 1;
tree_cur -= (rc & 1) as i32;
let idx = -tree_cur - 1;
if idx < 0 {
return false;
}
let idx = idx as usize;
if idx >= self.tree.len() {
self.tree.resize(idx + 1, 0);
}
if self.tree[idx] != 0 {
return false;
}
self.tree[idx] = sym_index as i16;
}
true
}
}