use std::io::{self, Read, Seek};
use bitstream_io::{BigEndian, BitRead, BitReader};
use super::huffman_decoder::HuffmanDecoder;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Invalid huffman tree")]
InvalidTree,
#[error(transparent)]
Io(#[from] io::Error),
}
pub struct HuffmanReader<R: Read + Seek> {
inner: bitstream_io::BitReader<R, BigEndian>,
uncompressed_size: u64,
offset: u64,
tree: HuffmanDecoder,
}
impl<R: Read + Seek> HuffmanReader<R> {
pub fn try_from(inner: R, uncompressed_size: u64) -> Result<Self, Error> {
let mut inner = bitstream_io::BitReader::new(inner);
let tree = Self::read_hufftree(&mut inner)?;
Ok(Self {
inner,
uncompressed_size,
offset: 0,
tree,
})
}
fn read_hufftree(
reader: &mut bitstream_io::BitReader<R, BigEndian>,
) -> Result<HuffmanDecoder, Error> {
let mut tree = HuffmanDecoder::new();
Self::read_hufftree_node(reader, &mut tree, 0)?;
tree.make_table(false);
Ok(tree)
}
#[inline]
fn read_hufftree_node(
reader: &mut BitReader<R, BigEndian>,
tree: &mut HuffmanDecoder,
node: i32,
) -> Result<(), Error> {
match reader.read_bit()? {
true => {
let value: u8 = reader.read_var(8)?;
tree.set_leaf_value(node, value as i32);
}
false => {
let left = tree.new_node();
Self::read_hufftree_node(reader, tree, left)?;
let right = tree.new_node();
Self::read_hufftree_node(reader, tree, right)?;
tree.set_branch(node, false, left);
tree.set_branch(node, true, right);
}
}
Ok(())
}
pub fn into_inner(self) -> R {
self.inner.into_reader()
}
}
impl<R: io::Read + io::Seek> io::Read for HuffmanReader<R> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
for (idx, byte) in buf.iter_mut().enumerate() {
if self.stream_position()? >= self.stream_len()? {
return Ok(idx);
}
match self.tree.next_symbol(&mut self.inner) {
Ok(value) => {
*byte = value as u8;
self.offset += 1;
}
Err(e) => return Err(e),
}
}
Ok(buf.len())
}
}
impl<R: io::Read + io::Seek> io::Seek for HuffmanReader<R> {
fn seek(&mut self, _: io::SeekFrom) -> io::Result<u64> {
todo!()
}
#[inline]
fn stream_len(&mut self) -> io::Result<u64> {
Ok(self.uncompressed_size)
}
#[inline]
fn stream_position(&mut self) -> io::Result<u64> {
Ok(self.offset)
}
}