use crate::{Error, Result};
pub const PS_HUFF_MAX_CODE_LEN: u32 = 20;
pub const HUFF_IID_FINE_DF: [(u8, u32); 61] = [
(18, 0b011111111010110100), (18, 0b011111111010110101), (18, 0b011111110101110110), (18, 0b011111110101110111), (18, 0b011111110101110100), (18, 0b011111110101110101), (18, 0b011111111010001010), (18, 0b011111111010001011), (18, 0b011111111010001000), (17, 0b01111111010000000), (18, 0b011111111010110110), (17, 0b01111111010000010), (17, 0b01111111010111000), (16, 0b0111111101000010), (16, 0b0111111110101110), (15, 0b011111110101111), (14, 0b01111111010001), (14, 0b01111111101001), (13, 0b0111111101001), (12, 0b011111101010), (12, 0b011111111011), (11, 0b01111111011), (10, 0b0111111011), (10, 0b0111111111), (8, 0b01111100), (7, 0b0111100), (6, 0b011100), (5, 0b01100), (4, 0b0000), (3, 0b001), (1, 0b1), (3, 0b010), (4, 0b0001), (5, 0b01101), (6, 0b011101), (7, 0b0111101), (8, 0b01111101), (9, 0b011111100), (10, 0b0111111100), (11, 0b01111111100), (11, 0b01111110100), (12, 0b011111101011), (13, 0b0111111101010), (14, 0b01111111101010), (14, 0b01111111010110), (15, 0b011111111010000), (16, 0b0111111110101111), (16, 0b0111111101000011), (17, 0b01111111010111001), (17, 0b01111111010000011), (18, 0b011111111010110111), (17, 0b01111111010000001), (18, 0b011111111010001001), (18, 0b011111111010001110), (18, 0b011111111010001111), (18, 0b011111111010001100), (18, 0b011111111010001101), (18, 0b011111111010110010), (18, 0b011111111010110011), (18, 0b011111111010110000), (18, 0b011111111010110001), ];
pub const HUFF_IID_FINE_DT: [(u8, u32); 61] = [
(16, 0b0100111011010100), (16, 0b0100111011010101), (16, 0b0100111011001110), (16, 0b0100111011001111), (16, 0b0100111011001100), (16, 0b0100111011010110), (16, 0b0100111011011000), (16, 0b0100111101000110), (16, 0b0100111101100000), (15, 0b010011100011000), (15, 0b010011100011001), (15, 0b010011101100100), (15, 0b010011101100101), (15, 0b010011101101101), (15, 0b010011110110001), (14, 0b01001110110111), (14, 0b01001111010110), (13, 0b0100111000111), (13, 0b0100111101001), (13, 0b0100111101101), (12, 0b010011101110), (12, 0b010011110111), (11, 0b01001111000), (10, 0b0100111001), (9, 0b010011010), (9, 0b010011111), (7, 0b0100000), (6, 0b010001), (5, 0b01010), (3, 0b011), (1, 0b1), (2, 0b00), (5, 0b01011), (6, 0b010010), (7, 0b0100001), (8, 0b01001100), (9, 0b010011011), (10, 0b0100111010), (11, 0b01001111001), (11, 0b01001110000), (12, 0b010011101111), (12, 0b010011100010), (13, 0b0100111101010), (13, 0b0100111011000), (14, 0b01001111010111), (14, 0b01001111010000), (15, 0b010011110110010), (15, 0b010011110100010), (15, 0b010011100011010), (15, 0b010011100011011), (16, 0b0100111101100110), (16, 0b0100111101100111), (16, 0b0100111101100001), (16, 0b0100111101000111), (16, 0b0100111011011001), (16, 0b0100111011010111), (16, 0b0100111011001101), (16, 0b0100111011010010), (16, 0b0100111011010011), (16, 0b0100111011010000), (16, 0b0100111011010001), ];
pub const HUFF_IID_DF: [(u8, u32); 29] = [
(17, 0b11111111111111011), (17, 0b11111111111111100), (17, 0b11111111111111101), (17, 0b11111111111111010), (16, 0b1111111111111100), (15, 0b111111111111100), (13, 0b1111111111101), (10, 0b1111111110), (9, 0b111111110), (7, 0b1111110), (6, 0b111100), (5, 0b11101), (4, 0b1101), (3, 0b101), (1, 0b0), (3, 0b100), (4, 0b1100), (5, 0b11100), (6, 0b111101), (6, 0b111110), (8, 0b11111110), (11, 0b11111111110), (13, 0b1111111111100), (14, 0b11111111111100), (14, 0b11111111111101), (15, 0b111111111111101), (17, 0b11111111111111110), (18, 0b111111111111111110), (18, 0b111111111111111111), ];
pub const HUFF_IID_DT: [(u8, u32); 29] = [
(19, 0b1111111111111111001), (19, 0b1111111111111111010), (19, 0b1111111111111111011), (20, 0b11111111111111111000), (20, 0b11111111111111111001), (20, 0b11111111111111111010), (17, 0b11111111111111101), (15, 0b111111111111110), (12, 0b111111111110), (10, 0b1111111110), (8, 0b11111110), (6, 0b111110), (4, 0b1110), (2, 0b10), (1, 0b0), (3, 0b110), (5, 0b11110), (7, 0b1111110), (9, 0b111111110), (11, 0b11111111110), (13, 0b1111111111110), (14, 0b11111111111110), (17, 0b11111111111111100), (19, 0b1111111111111111000), (20, 0b11111111111111111011), (20, 0b11111111111111111100), (20, 0b11111111111111111101), (20, 0b11111111111111111110), (20, 0b11111111111111111111), ];
pub const HUFF_ICC_DF: [(u8, u32); 15] = [
(14, 0b11111111111111), (14, 0b11111111111110), (12, 0b111111111110), (10, 0b1111111110), (7, 0b1111110), (5, 0b11110), (3, 0b110), (1, 0b0), (2, 0b10), (4, 0b1110), (6, 0b111110), (8, 0b11111110), (9, 0b111111110), (11, 0b11111111110), (13, 0b1111111111110), ];
pub const HUFF_ICC_DT: [(u8, u32); 15] = [
(14, 0b11111111111110), (13, 0b1111111111110), (11, 0b11111111110), (9, 0b111111110), (7, 0b1111110), (5, 0b11110), (3, 0b110), (1, 0b0), (2, 0b10), (4, 0b1110), (6, 0b111110), (8, 0b11111110), (10, 0b1111111110), (12, 0b111111111110), (14, 0b11111111111111), ];
pub const HUFF_IPD_DF: [(u8, u32); 8] = [
(1, 0b1), (3, 0b000), (4, 0b0110), (4, 0b0100), (4, 0b0010), (4, 0b0011), (4, 0b0101), (4, 0b0111), ];
pub const HUFF_IPD_DT: [(u8, u32); 8] = [
(1, 0b1), (3, 0b010), (4, 0b0010), (5, 0b00011), (5, 0b00010), (4, 0b0000), (4, 0b0011), (3, 0b011), ];
pub const HUFF_OPD_DF: [(u8, u32); 8] = [
(1, 0b1), (3, 0b001), (4, 0b0110), (4, 0b0100), (5, 0b01111), (5, 0b01110), (4, 0b0101), (3, 0b000), ];
pub const HUFF_OPD_DT: [(u8, u32); 8] = [
(1, 0b1), (3, 0b010), (4, 0b0001), (5, 0b00111), (5, 0b00110), (4, 0b0000), (4, 0b0010), (3, 0b011), ];
pub fn ps_huff_dec(
reader: &mut oxideav_core::bits::BitReader<'_>,
table: &[(u8, u32)],
lav: i32,
) -> Result<i32> {
let mut codeword: u32 = 0;
let mut len: u32 = 0;
loop {
codeword = (codeword << 1) | reader.read_u32(1).map_err(|_| Error::PsDataInvalid)?;
len += 1;
for (idx, &(clen, ccode)) in table.iter().enumerate() {
if u32::from(clen) == len && ccode == codeword {
return Ok(idx as i32 - lav);
}
}
if len >= PS_HUFF_MAX_CODE_LEN {
return Err(Error::PsDataInvalid);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use oxideav_core::bits::{BitReader, BitWriter};
fn check_table(table: &[(u8, u32)]) {
let mut kraft_num: u64 = 0; for &(len, code) in table {
assert!(len >= 1 && u32::from(len) <= PS_HUFF_MAX_CODE_LEN);
assert!(
u64::from(code) < (1u64 << len),
"codeword 0x{code:08X} overflows its {len}-bit length"
);
kraft_num += 1u64 << (PS_HUFF_MAX_CODE_LEN - u32::from(len));
}
assert_eq!(
kraft_num,
1u64 << PS_HUFF_MAX_CODE_LEN,
"code is not complete"
);
for (a, &(la, ca)) in table.iter().enumerate() {
for (b, &(lb, cb)) in table.iter().enumerate() {
if a == b || lb < la {
continue;
}
assert!(cb >> (lb - la) != ca, "prefix conflict {a} vs {b}");
}
}
}
#[test]
fn all_tables_are_complete_prefix_codes() {
check_table(&HUFF_IID_FINE_DF);
check_table(&HUFF_IID_FINE_DT);
check_table(&HUFF_IID_DF);
check_table(&HUFF_IID_DT);
check_table(&HUFF_ICC_DF);
check_table(&HUFF_ICC_DT);
check_table(&HUFF_IPD_DF);
check_table(&HUFF_IPD_DT);
check_table(&HUFF_OPD_DF);
check_table(&HUFF_OPD_DT);
}
#[test]
fn every_codeword_decodes_to_its_index() {
let cases: [(&[(u8, u32)], i32); 10] = [
(&HUFF_IID_FINE_DF, 30),
(&HUFF_IID_FINE_DT, 30),
(&HUFF_IID_DF, 14),
(&HUFF_IID_DT, 14),
(&HUFF_ICC_DF, 7),
(&HUFF_ICC_DT, 7),
(&HUFF_IPD_DF, 0),
(&HUFF_IPD_DT, 0),
(&HUFF_OPD_DF, 0),
(&HUFF_OPD_DT, 0),
];
for (table, lav) in cases {
for (idx, &(len, code)) in table.iter().enumerate() {
let mut w = BitWriter::new();
w.write_u32(code, u32::from(len));
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let got = ps_huff_dec(&mut r, table, lav).unwrap();
assert_eq!(got, idx as i32 - lav);
assert_eq!(r.bit_position(), u64::from(len));
}
}
}
#[test]
fn zero_delta_anchors() {
assert_eq!(HUFF_IID_FINE_DF[30], (1, 0b1));
assert_eq!(HUFF_IID_DF[14], (1, 0b0));
assert_eq!(HUFF_ICC_DF[7], (1, 0b0));
assert_eq!(HUFF_IPD_DF[0], (1, 0b1));
assert_eq!(HUFF_OPD_DT[0], (1, 0b1));
}
#[test]
fn unmatched_bits_error() {
let bytes = [0xFFu8; 1];
let mut r = BitReader::new(&bytes);
assert!(matches!(
ps_huff_dec(&mut r, &HUFF_IID_DT, 14),
Err(Error::PsDataInvalid)
));
}
}