use crate::preflate_error::{err_exit_code, ExitCode, Result};
use std::vec;
use super::bit_reader::ReadBits;
pub fn calc_huffman_codes(code_lengths: &[u8]) -> Result<Vec<u16>> {
let mut result: Vec<u16> = vec![0; code_lengths.len()];
let mut maxbits = 0;
let mut bl_count: [u16; 32] = [0; 32];
for cbit in code_lengths {
bl_count[*cbit as usize] += 1;
if *cbit > maxbits {
maxbits = *cbit;
}
}
let mut code: u16 = 0;
bl_count[0] = 0;
let mut next_code: [u16; 32] = [0; 32];
for bits in 1..=maxbits {
code = (code + bl_count[bits as usize - 1]) << 1;
next_code[bits as usize] = code;
}
for n in 0..code_lengths.len() {
let len = code_lengths[n];
if len != 0 {
let mut code = next_code[len as usize];
let mut rev_code = 0;
for _ in 0..len {
rev_code = (rev_code << 1) | (code & 1);
code >>= 1;
}
result[n] = rev_code;
next_code[len as usize] += 1;
}
}
Ok(result)
}
fn is_valid_huffman_code_lengths(code_lengths: &[u8]) -> bool {
if code_lengths.is_empty() {
return false;
}
const MAX_CODE_LENGTH: usize = 16;
let mut length_count = [0; MAX_CODE_LENGTH];
for &length in code_lengths.iter() {
if length as usize >= MAX_CODE_LENGTH {
return false;
}
length_count[length as usize] += 1;
}
let mut internal_nodes = 2;
for i in 1..length_count.len() {
internal_nodes -= length_count[i];
if internal_nodes < 0 {
return false;
}
internal_nodes *= 2;
}
internal_nodes == 0
}
pub fn calculate_huffman_code_tree(code_lengths: &[u8]) -> Result<Vec<i32>> {
if !is_valid_huffman_code_lengths(code_lengths) {
return err_exit_code(ExitCode::InvalidDeflate, "Invalid Huffman code lengths");
}
let mut c_codes: i32 = 0;
let mut c_bits_largest = 0;
for &c_bits in code_lengths {
if c_bits != 0 {
c_codes += 1;
}
if c_bits > c_bits_largest {
c_bits_largest = c_bits;
}
}
let mut rg_huff_nodes: Vec<i32> = vec![0; ((c_codes - 1) * 2) as usize];
let mut i_huff_nodes: i32 = 0;
let mut i_huff_nodes_previous_level: i32 = 0;
for c_bits_cur in (1..=c_bits_largest).rev() {
let i_huff_nodes_start = i_huff_nodes;
for j in 0..code_lengths.len() {
if code_lengths[j] == c_bits_cur {
rg_huff_nodes[i_huff_nodes as usize] = -1 - j as i32; i_huff_nodes += 1;
}
}
for j in (i_huff_nodes_previous_level..i_huff_nodes_start).step_by(2) {
rg_huff_nodes[i_huff_nodes as usize] = j;
i_huff_nodes += 1;
}
i_huff_nodes_previous_level = i_huff_nodes_start;
}
Ok(rg_huff_nodes)
}
pub fn decode_symbol<R: ReadBits>(bit_reader: &mut R, huffman_tree: &[i32]) -> Result<u16> {
let mut i_node_cur: i32 = huffman_tree.len() as i32 - 2;
loop {
i_node_cur = huffman_tree[(bit_reader.get(1)? as i32 + i_node_cur) as usize];
if i_node_cur < 0 {
return Ok((0 - (i_node_cur + 1)) as u16);
}
}
}
#[cfg(test)]
struct SingleCode {
pub code: u32,
}
#[cfg(test)]
impl ReadBits for SingleCode {
fn get(&mut self, cbits: u32) -> std::io::Result<u32> {
let result = self.code & ((1 << cbits) - 1);
self.code >>= cbits;
Ok(result)
}
}
#[cfg(test)]
fn roundtrip(frequencies: &[u16], huffcalc: super::huffman_calc::HufftreeBitCalc) {
use super::huffman_calc::calc_bit_lengths;
let code_lengths = calc_bit_lengths(huffcalc, frequencies, 7);
let codes = calc_huffman_codes(&code_lengths).unwrap();
let huffman_tree = calculate_huffman_code_tree(&code_lengths).unwrap();
for i in 0..code_lengths.len() {
if code_lengths[i] != 0 {
let mut code = SingleCode {
code: codes[i].into(),
};
let symbol = decode_symbol(&mut code, &huffman_tree).unwrap();
assert_eq!(i, symbol as usize);
}
}
}
#[test]
fn roundtrip_huffman_code() {
roundtrip(
&[1, 0, 2, 3, 5, 8, 13, 0],
super::huffman_calc::HufftreeBitCalc::Miniz,
);
roundtrip(
&[1, 0, 2, 3, 5, 8, 13, 0],
super::huffman_calc::HufftreeBitCalc::Zlib,
);
roundtrip(
&[1, 0, 2, 3, 5, 1008, 113, 1, 1, 1, 100, 10000],
super::huffman_calc::HufftreeBitCalc::Zlib,
);
}