use oxideav_core::bits::BitReader;
use oxideav_core::{Error, Result};
pub struct Hcb {
pub len: &'static [u8],
pub cw: &'static [u32],
pub dim: u8,
pub cb_mod: u32,
pub cb_mod2: u32,
pub cb_mod3: u32,
pub cb_off: i32,
pub unsigned: bool,
}
pub fn huff_decode(br: &mut BitReader<'_>, lens: &[u8], cws: &[u32]) -> Result<u32> {
debug_assert_eq!(lens.len(), cws.len());
let mut code: u32 = 0;
let mut width: u8 = 0;
while width < 32 {
let b = br.read_u32(1)?;
code = (code << 1) | b;
width += 1;
for (i, &l) in lens.iter().enumerate() {
if l == width && cws[i] == code {
return Ok(i as u32);
}
}
}
Err(Error::invalid("ac4: no matching Huffman codeword"))
}
include!("huffman_tables.rs");
pub fn asf_hcb(cb_idx: u32) -> Option<&'static Hcb> {
match cb_idx {
1 => Some(&HCB1),
2 => Some(&HCB2),
3 => Some(&HCB3),
4 => Some(&HCB4),
5 => Some(&HCB5),
6 => Some(&HCB6),
7 => Some(&HCB7),
8 => Some(&HCB8),
9 => Some(&HCB9),
10 => Some(&HCB10),
11 => Some(&HCB11),
_ => None,
}
}
pub fn split_qspec(hcb: &Hcb, mut cb_idx: u32, out: &mut [i32]) {
if hcb.dim == 4 {
debug_assert!(out.len() >= 4);
let q1 = (cb_idx / hcb.cb_mod3) as i32 - hcb.cb_off;
cb_idx -= (q1 + hcb.cb_off) as u32 * hcb.cb_mod3;
let q2 = (cb_idx / hcb.cb_mod2) as i32 - hcb.cb_off;
cb_idx -= (q2 + hcb.cb_off) as u32 * hcb.cb_mod2;
let q3 = (cb_idx / hcb.cb_mod) as i32 - hcb.cb_off;
cb_idx -= (q3 + hcb.cb_off) as u32 * hcb.cb_mod;
let q4 = cb_idx as i32 - hcb.cb_off;
out[0] = q1;
out[1] = q2;
out[2] = q3;
out[3] = q4;
} else {
debug_assert!(out.len() >= 2);
let q1 = (cb_idx / hcb.cb_mod) as i32 - hcb.cb_off;
cb_idx -= (q1 + hcb.cb_off) as u32 * hcb.cb_mod;
let q2 = cb_idx as i32 - hcb.cb_off;
out[0] = q1;
out[1] = q2;
}
}
pub fn ext_decode(br: &mut BitReader<'_>) -> Result<u32> {
let mut n_ext: u32 = 0;
loop {
let b = br.read_u32(1)?;
if b == 0 {
break;
}
n_ext += 1;
}
let bits = n_ext + 4;
let ext_val = br.read_u32(bits)?;
Ok((1u32 << (n_ext + 4)) + ext_val)
}
#[cfg(test)]
mod tests {
use super::*;
use oxideav_core::bits::BitWriter;
#[test]
fn scalefac_roundtrip_index_60() {
let mut bw = BitWriter::new();
bw.write_u32(HCB_SCALEFAC_CW[60], HCB_SCALEFAC_LEN[60] as u32);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let idx = huff_decode(&mut br, HCB_SCALEFAC_LEN, HCB_SCALEFAC_CW).unwrap();
assert_eq!(idx, 60);
}
#[test]
fn snf_short_codeword() {
let mut bw = BitWriter::new();
bw.write_u32(HCB_SNF_CW[13], HCB_SNF_LEN[13] as u32);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let idx = huff_decode(&mut br, HCB_SNF_LEN, HCB_SNF_CW).unwrap();
assert_eq!(idx, 13);
}
#[test]
fn hcb1_known_entry() {
let mut bw = BitWriter::new();
bw.write_u32(HCB1.cw[40], HCB1.len[40] as u32);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
let idx = huff_decode(&mut br, HCB1.len, HCB1.cw).unwrap();
assert_eq!(idx, 40);
}
#[test]
fn split_qspec_dim2_unsigned() {
let mut out = [0i32; 4];
split_qspec(&HCB5, 40, &mut out);
assert_eq!(out[0], 0);
assert_eq!(out[1], 0);
}
#[test]
fn split_qspec_dim4_signed() {
let mut out = [0i32; 4];
split_qspec(&HCB1, 40, &mut out);
assert_eq!(out, [0, 0, 0, 0]);
}
#[test]
fn ext_decode_n0_v0() {
let mut bw = BitWriter::new();
bw.write_u32(0, 1); bw.write_u32(0, 4); bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
assert_eq!(ext_decode(&mut br).unwrap(), 16);
}
#[test]
fn ext_decode_n1_v5() {
let mut bw = BitWriter::new();
bw.write_u32(1, 1);
bw.write_u32(0, 1);
bw.write_u32(5, 5);
bw.align_to_byte();
let bytes = bw.finish();
let mut br = BitReader::new(&bytes);
assert_eq!(ext_decode(&mut br).unwrap(), 37);
}
}