use ffi::Error;
use std::mem;
use std::rc::Rc;
pub(crate) struct HuffmanTree {
pub maxbitlen: usize,
pub numcodes: usize,
pub tree2d: Vec<u32>,
pub tree1d: Vec<u32>,
pub lengths: Vec<u32>,
}
impl HuffmanTree {
pub fn new(numcodes: usize, lengths: Vec<u32>, maxbitlen: usize) -> Self {
Self {
numcodes,
lengths,
maxbitlen,
tree2d: Vec::new(),
tree1d: Vec::new(),
}
}
pub fn code(&self, index: u32) -> u32 {
self.tree1d[index as usize]
}
pub fn length(&self, index: u32) -> u32 {
self.lengths[index as usize]
}
#[inline]
pub fn decode_symbol(&self, inp: &[u8], bp: &mut usize) -> Option<u32> {
let inbitlength = inp.len() * 8;
let mut treepos = 0;
loop {
if *bp >= inbitlength {
return None;
}
let ct = self.tree2d[(treepos << 1) + (((inp[*bp >> 3]) >> (*bp & 7)) & 1u8) as usize];
(*bp) += 1;
if (ct as usize) < self.numcodes {
return Some(ct);
} else {
treepos = ct as usize - self.numcodes;
}
if treepos >= self.numcodes {
return None;
}
}
}
fn new_2d_tree(tree: &mut HuffmanTree) -> Result<(), Error> {
let mut nodefilled = 0;
let mut treepos = 0;
tree.tree2d = vec![32767; tree.numcodes as usize * 2];
for n in 0..tree.numcodes as usize {
for i in 0..tree.lengths[n] as isize {
let bit = ((tree.tree1d[n] >> (tree.lengths[n] as isize - i - 1)) & 1) as usize;
if treepos > 2147483647 || treepos + 2 > tree.numcodes {
return Err(Error(55));
}
if tree.tree2d[2 * treepos + bit as usize] == 32767 {
if i + 1 == tree.lengths[n] as isize {
tree.tree2d[2 * treepos + bit] = n as u32;
treepos = 0;
} else {
nodefilled += 1;
tree.tree2d[2 * treepos + bit] = (nodefilled + tree.numcodes) as u32;
treepos = nodefilled;
};
} else {
let pos = tree.tree2d[2 * treepos + bit] as usize;
if pos < tree.numcodes {
return Err(Error(55));
}
treepos = pos - tree.numcodes;
};
}
}
for n in 0..(tree.numcodes * 2) {
if tree.tree2d[n] == 32767 {
tree.tree2d[n] = 0;
}
}
Ok(())
}
fn from_lengths2(tree: &mut HuffmanTree) -> Result<(), Error> {
let mut blcount: Vec<u32> = vec![0; tree.maxbitlen + 1];
let mut nextcode: Vec<u32> = vec![0; tree.maxbitlen + 1];
tree.tree1d = vec![0; tree.numcodes];
for bits in 0..tree.numcodes {
blcount[tree.lengths[bits] as usize] += 1;
}
for bits in 0..tree.maxbitlen {
nextcode[bits+1] = (nextcode[bits] + blcount[bits]) << 1;
}
for n in 0..tree.numcodes {
if tree.lengths[n] != 0 {
tree.tree1d[n] = nextcode[tree.lengths[n as usize] as usize];
nextcode[tree.lengths[n as usize] as usize] += 1;
}
}
Self::new_2d_tree(tree)
}
pub fn from_lengths(bitlen: &[u32], maxbitlen: usize) -> Result<Self, Error> {
let mut tree = Self::new(bitlen.len(), bitlen.to_owned(), maxbitlen);
Self::from_lengths2(&mut tree)?;
Ok(tree)
}
pub fn from_frequencies(frequencies: &[u32], mincodes: usize, maxbitlen: u32) -> Result<Self, Error> {
let mut numcodes = frequencies.len();
while frequencies[numcodes - 1] == 0 && numcodes > mincodes {
numcodes -= 1;
}
let mut tree = Self::new(numcodes, huffman_code_lengths(frequencies, maxbitlen)?, maxbitlen as usize);
Self::from_lengths2(&mut tree)?;
Ok(tree)
}
}
#[derive(Clone)]
struct BPMNode {
pub weight: i32,
pub index: u32,
pub tail: Option<Rc<BPMNode>>,
}
struct BPMLists {
pub chains0: Vec<Rc<BPMNode>>,
pub chains1: Vec<Rc<BPMNode>>,
}
pub(crate) fn huffman_code_lengths(frequencies: &[u32], maxbitlen: u32) -> Result<Vec<u32>, Error> {
let numcodes = frequencies.len();
if numcodes == 0 {
return Err(Error(80));
}
if (1 << maxbitlen) < numcodes {
return Err(Error(80));
}
let mut leaves = vec![];
for i in 0..numcodes {
if frequencies[i] > 0 {
leaves.push(BPMNode {
weight: frequencies[i] as i32,
index: i as u32,
tail: None,
});
};
}
let mut lengths = vec![0; numcodes];
if leaves.is_empty() {
lengths[0] = 1;
lengths[1] = 1;
} else if leaves.len() == 1 {
lengths[leaves[0].index as usize] = 1;
lengths[(if leaves[0].index == 0 { 1 } else { 0 })] = 1;
} else {
let listsize = maxbitlen;
leaves.sort_by_key(|a| a.weight);
let mut lists = BPMLists {
chains0: vec![BPMNode::new(leaves[0].weight, 1, None); listsize as usize],
chains1: vec![BPMNode::new(leaves[1].weight, 2, None); listsize as usize],
};
for i in 2..(2 * leaves.len() - 2) {
boundary_pm(&mut lists, &leaves, maxbitlen as usize - 1, i);
}
let mut next_node = Some(&lists.chains1[maxbitlen as usize - 1]);
while let Some(node) = next_node {
for leaf in &leaves[0..node.index as usize] {
lengths[leaf.index as usize] += 1;
}
next_node = node.tail.as_ref();
}
}
Ok(lengths)
}
impl BPMNode {
fn new(weight: i32, index: u32, tail: Option<Rc<BPMNode>>) -> Rc<Self> {
Rc::new(BPMNode {
weight,
index,
tail,
})
}
}
fn boundary_pm(lists: &mut BPMLists, leaves: &[BPMNode], c: usize, num: usize) {
let lastindex = lists.chains1[c].index as usize;
if c == 0 {
if lastindex >= leaves.len() {
return;
}
mem::swap(&mut lists.chains0[0], &mut lists.chains1[0]); lists.chains1[0] = BPMNode::new(leaves[lastindex].weight, lastindex as u32 + 1, None);
} else {
let sum = lists.chains0[c - 1].weight + lists.chains1[c - 1].weight;
if lastindex < leaves.len() && sum > leaves[lastindex].weight {
let w = leaves[lastindex].weight;
let t = lists.chains1[c].tail.clone();
mem::swap(&mut lists.chains0[c], &mut lists.chains1[c]);
lists.chains1[c] = BPMNode::new(w, lastindex as u32 + 1, t);
return;
}
let t = Rc::clone(&lists.chains1[c - 1]);
mem::swap(&mut lists.chains0[c], &mut lists.chains1[c]);
lists.chains1[c] = BPMNode::new(sum, lastindex as u32, Some(t));
if num + 1 < (2 * leaves.len() - 2) {
boundary_pm(lists, leaves, c - 1, num);
boundary_pm(lists, leaves, c - 1, num);
};
};
}