use crate::bit_reverse::reverse_bits;
use crate::lzvalue::StoredLength;
use std::fmt;
pub const NUM_LENGTH_CODES: usize = 29;
pub const NUM_DISTANCE_CODES: usize = 30;
pub const NUM_LITERALS_AND_LENGTHS: usize = 286;
pub const MAX_CODE_LENGTH: usize = 15;
pub const MIN_MATCH: u16 = 3;
pub const MAX_MATCH: u16 = 258;
pub const MIN_DISTANCE: u16 = 1;
pub const MAX_DISTANCE: u16 = 32768;
pub const END_OF_BLOCK_POSITION: usize = 256;
pub static FIXED_CODE_LENGTHS: [u8; NUM_LITERALS_AND_LENGTHS + 2] = [
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8,
];
const LENGTH_EXTRA_BITS_LENGTH: [u8; NUM_LENGTH_CODES] = [
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0,
];
const LENGTH_CODE: [u8; 256] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14,
14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18,
18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28,
];
const BASE_LENGTH: [u8; NUM_LENGTH_CODES] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128,
160, 192, 224, 255,
];
pub const LENGTH_BITS_START: u16 = 257;
pub const FIXED_CODE_LENGTHS_DISTANCE: [u8; NUM_DISTANCE_CODES + 2] = [5; NUM_DISTANCE_CODES + 2];
const DISTANCE_CODES: [u8; 512] = [
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21,
22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
];
#[cfg(test)]
const DISTANCE_EXTRA_BITS: [u8; NUM_DISTANCE_CODES] = [
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13,
13,
];
const DISTANCE_BASE: [u16; NUM_DISTANCE_CODES] = [
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536,
2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576,
];
pub fn num_extra_bits_for_length_code(code: u8) -> u8 {
LENGTH_EXTRA_BITS_LENGTH[code as usize]
}
pub fn num_extra_bits_for_distance_code(code: u8) -> u8 {
let mut c = code >> 1;
c -= (c != 0) as u8;
c
}
#[derive(Copy, Clone)]
struct ExtraBits {
pub code_number: u16,
pub num_bits: u8,
pub value: u16,
}
pub fn get_length_code(length: u16) -> usize {
usize::from(LENGTH_CODE[(length.wrapping_sub(MIN_MATCH)) as u8 as usize])
+ LENGTH_BITS_START as usize
}
fn get_length_code_and_extra_bits(length: StoredLength) -> ExtraBits {
let n = LENGTH_CODE[length.stored_length() as usize];
let base = BASE_LENGTH[n as usize];
let num_bits = num_extra_bits_for_length_code(n);
ExtraBits {
code_number: u16::from(n) + LENGTH_BITS_START,
num_bits,
value: (length.stored_length() - base).into(),
}
}
pub fn get_distance_code(distance: u16) -> u8 {
let distance = distance as usize;
match distance {
1..=256 => DISTANCE_CODES[distance - 1],
257..=32768 => DISTANCE_CODES[256 + ((distance - 1) >> 7)],
_ => 0,
}
}
fn get_distance_code_and_extra_bits(distance: u16) -> ExtraBits {
let distance_code = get_distance_code(distance);
let extra = num_extra_bits_for_distance_code(distance_code);
let base = DISTANCE_BASE[distance_code as usize] + 1;
ExtraBits {
code_number: distance_code.into(),
num_bits: extra,
value: distance - base,
}
}
#[derive(Copy, Clone, Default)]
pub struct HuffmanCode {
pub code: u16,
pub length: u8,
}
impl fmt::Debug for HuffmanCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"HuffmanCode {{ code: {:b}, length: {}}}",
self.code, self.length
)
}
}
impl HuffmanCode {
#[inline]
fn new(code: u16, length: u8) -> HuffmanCode {
HuffmanCode { code, length }
}
}
#[cfg(test)]
pub struct LengthAndDistanceBits {
pub length_code: HuffmanCode,
pub length_extra_bits: HuffmanCode,
pub distance_code: HuffmanCode,
pub distance_extra_bits: HuffmanCode,
}
fn build_length_count_table(table: &[u8], len_counts: &mut [u16; 16]) -> (usize, usize) {
let max_length = (*table.iter().max().expect("BUG! Empty lengths!")).into();
assert!(max_length <= MAX_CODE_LENGTH);
let mut max_length_pos = 0;
for (n, &length) in table.iter().enumerate() {
if length > 0 {
len_counts[usize::from(length)] += 1;
max_length_pos = n;
}
}
(max_length, max_length_pos)
}
pub fn create_codes_in_place(code_table: &mut [u16], length_table: &[u8]) {
let mut len_counts = [0; 16];
let (max_length, max_length_pos) = build_length_count_table(length_table, &mut len_counts);
let lengths = len_counts;
let mut code = 0u16;
let mut next_code = Vec::with_capacity(length_table.len());
next_code.push(code);
for bits in 1..=max_length {
code = (code + lengths[bits - 1]) << 1;
next_code.push(code);
}
for n in 0..=max_length_pos {
let length = usize::from(length_table[n]);
if length != 0 {
code_table[n] = reverse_bits(next_code[length], length as u8);
next_code[length] = next_code[length].wrapping_add(1);
}
}
}
pub struct HuffmanTable {
codes: [u16; 288],
code_lengths: [u8; 288],
distance_codes: [u16; 32],
distance_code_lengths: [u8; 32],
}
impl HuffmanTable {
pub fn empty() -> HuffmanTable {
HuffmanTable {
codes: [0; 288],
code_lengths: [0; 288],
distance_codes: [0; 32],
distance_code_lengths: [0; 32],
}
}
#[cfg(test)]
pub fn from_length_tables(
literals_and_lengths: &[u8; 288],
distances: &[u8; 32],
) -> HuffmanTable {
let mut table = HuffmanTable {
codes: [0; 288],
code_lengths: *literals_and_lengths,
distance_codes: [0; 32],
distance_code_lengths: *distances,
};
table.update_from_lengths();
table
}
#[inline]
pub fn get_lengths(&self) -> (&[u8; 288], &[u8; 32]) {
(&self.code_lengths, &self.distance_code_lengths)
}
#[inline]
pub fn get_lengths_mut(&mut self) -> (&mut [u8; 288], &mut [u8; 32]) {
(&mut self.code_lengths, &mut self.distance_code_lengths)
}
pub fn update_from_lengths(&mut self) {
create_codes_in_place(self.codes.as_mut(), &self.code_lengths[..]);
create_codes_in_place(
self.distance_codes.as_mut(),
&self.distance_code_lengths[..],
);
}
pub fn set_to_fixed(&mut self) {
self.code_lengths = FIXED_CODE_LENGTHS;
self.distance_code_lengths = FIXED_CODE_LENGTHS_DISTANCE;
self.update_from_lengths();
}
#[cfg(test)]
pub fn fixed_table() -> HuffmanTable {
HuffmanTable::from_length_tables(&FIXED_CODE_LENGTHS, &FIXED_CODE_LENGTHS_DISTANCE)
}
#[inline]
fn get_ll_huff(&self, value: usize) -> HuffmanCode {
HuffmanCode::new(self.codes[value], self.code_lengths[value])
}
#[inline]
pub fn get_literal(&self, value: u8) -> HuffmanCode {
let index = usize::from(value);
HuffmanCode::new(self.codes[index], self.code_lengths[index])
}
#[inline]
pub fn get_end_of_block(&self) -> HuffmanCode {
self.get_ll_huff(END_OF_BLOCK_POSITION)
}
#[inline]
pub fn get_length_huffman(&self, length: StoredLength) -> (HuffmanCode, HuffmanCode) {
let length_data = get_length_code_and_extra_bits(length);
let length_huffman_code = self.get_ll_huff(length_data.code_number as usize);
(
length_huffman_code,
HuffmanCode {
code: length_data.value,
length: length_data.num_bits,
},
)
}
#[inline]
pub fn get_distance_huffman(&self, distance: u16) -> (HuffmanCode, HuffmanCode) {
debug_assert!(distance >= MIN_DISTANCE && distance <= MAX_DISTANCE);
let distance_data = get_distance_code_and_extra_bits(distance);
let distance_huffman_code = self.distance_codes[distance_data.code_number as usize];
let distance_huffman_length =
self.distance_code_lengths[distance_data.code_number as usize];
(
HuffmanCode {
code: distance_huffman_code,
length: distance_huffman_length,
},
HuffmanCode {
code: distance_data.value,
length: distance_data.num_bits,
},
)
}
#[cfg(test)]
pub fn get_length_distance_code(&self, length: u16, distance: u16) -> LengthAndDistanceBits {
assert!(length >= MIN_MATCH && length < MAX_DISTANCE);
let l_codes = self.get_length_huffman(StoredLength::from_actual_length(length));
let d_codes = self.get_distance_huffman(distance);
LengthAndDistanceBits {
length_code: l_codes.0,
length_extra_bits: l_codes.1,
distance_code: d_codes.0,
distance_extra_bits: d_codes.1,
}
}
}
#[cfg(test)]
mod test {
use super::*;
use super::{
build_length_count_table, get_distance_code_and_extra_bits, get_length_code_and_extra_bits,
};
use crate::lzvalue::StoredLength;
fn l(length: u16) -> StoredLength {
StoredLength::from_actual_length(length)
}
#[test]
fn test_get_length_code() {
let extra_bits = get_length_code_and_extra_bits(l(4));
assert_eq!(extra_bits.code_number, 258);
assert_eq!(extra_bits.num_bits, 0);
assert_eq!(extra_bits.value, 0);
let extra_bits = get_length_code_and_extra_bits(l(165));
assert_eq!(extra_bits.code_number, 282);
assert_eq!(extra_bits.num_bits, 5);
assert_eq!(extra_bits.value, 2);
let extra_bits = get_length_code_and_extra_bits(l(257));
assert_eq!(extra_bits.code_number, 284);
assert_eq!(extra_bits.num_bits, 5);
assert_eq!(extra_bits.value, 30);
let extra_bits = get_length_code_and_extra_bits(l(258));
assert_eq!(extra_bits.code_number, 285);
assert_eq!(extra_bits.num_bits, 0);
}
#[test]
fn test_distance_code() {
assert_eq!(get_distance_code(1), 0);
assert_eq!(get_distance_code(0), 0);
assert_eq!(get_distance_code(50000), 0);
assert_eq!(get_distance_code(6146), 25);
assert_eq!(get_distance_code(256), 15);
assert_eq!(get_distance_code(4733), 24);
assert_eq!(get_distance_code(257), 16);
}
#[test]
fn test_distance_extra_bits() {
let extra = get_distance_code_and_extra_bits(527);
assert_eq!(extra.value, 0b1110);
assert_eq!(extra.code_number, 18);
assert_eq!(extra.num_bits, 8);
let extra = get_distance_code_and_extra_bits(256);
assert_eq!(extra.code_number, 15);
assert_eq!(extra.num_bits, 6);
let extra = get_distance_code_and_extra_bits(4733);
assert_eq!(extra.code_number, 24);
assert_eq!(extra.num_bits, 11);
}
#[test]
fn test_length_table_fixed() {
let _ = build_length_count_table(&FIXED_CODE_LENGTHS, &mut [0; 16]);
}
#[test]
#[should_panic]
fn test_length_table_max_length() {
let table = [16u8; 288];
build_length_count_table(&table, &mut [0; 16]);
}
#[test]
#[should_panic]
fn test_empty_table() {
let table = [];
build_length_count_table(&table, &mut [0; 16]);
}
#[test]
fn make_table_fixed() {
let table = HuffmanTable::fixed_table();
assert_eq!(table.codes[0], 0b00001100);
assert_eq!(table.codes[143], 0b11111101);
assert_eq!(table.codes[144], 0b000010011);
assert_eq!(table.codes[255], 0b111111111);
assert_eq!(table.codes[256], 0b0000000);
assert_eq!(table.codes[279], 0b1110100);
assert_eq!(table.codes[280], 0b00000011);
assert_eq!(table.codes[287], 0b11100011);
assert_eq!(table.distance_codes[0], 0);
assert_eq!(table.distance_codes[5], 20);
let ld = table.get_length_distance_code(4, 5);
assert_eq!(ld.length_code.code, 0b00100000);
assert_eq!(ld.distance_code.code, 0b00100);
assert_eq!(ld.distance_extra_bits.length, 1);
assert_eq!(ld.distance_extra_bits.code, 0);
}
#[test]
fn extra_bits_distance() {
use std::mem::size_of;
for i in 0..NUM_DISTANCE_CODES {
assert_eq!(
num_extra_bits_for_distance_code(i as u8),
DISTANCE_EXTRA_BITS[i]
);
}
println!("Size of huffmanCode struct: {}", size_of::<HuffmanCode>());
}
}