use core::num::NonZeroU16;
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
use crate::error::LhaResult;
use crate::stub_io::Read;
use crate::decode::Decoder;
use crate::ringbuf::*;
use crate::bitstream::*;
mod dyntree;
use dyntree::*;
const RING_BUFFER_SIZE: usize = 4096;
#[derive(Debug)]
pub struct Lh1Decoder<R> {
bit_reader: BitStream<R>,
command_tree: Box<DynHuffTree>,
copy_progress: Option<(u16, NonZeroU16)>,
ringbuf: Box<RingArrayBuf<RING_BUFFER_SIZE>>,
}
impl<R: Read> Lh1Decoder<R> {
pub fn new(rd: R) -> Lh1Decoder<R> {
let bit_reader = BitStream::new(rd);
let ringbuf = Default::default();
let command_tree = Box::new(DynHuffTree::new());
Lh1Decoder {
bit_reader,
ringbuf,
command_tree,
copy_progress: None
}
}
#[inline]
fn read_command(&mut self) -> LhaResult<u16, R> {
self.command_tree.read_entry(&mut self.bit_reader)
}
#[inline]
fn read_offset(&mut self) -> LhaResult<u16, R> {
let bits9 = self.bit_reader.read_bits(9)?;
let (mut offset, bits) = decode_offset(bits9);
offset |= self.bit_reader.read_bits::<u16>(bits)?;
Ok(offset)
}
fn copy_from_history<'a, I: Iterator<Item=&'a mut u8> + ExactSizeIterator>(
&mut self,
target: I,
offset: usize,
count: usize
) -> LhaResult<(), R>
{
let history_iter = self.ringbuf.iter_from_offset(offset);
let count_after = count - target.len().min(count);
for (t, s) in target.zip(history_iter).take(count) {
*t = s;
}
self.copy_progress = NonZeroU16::new(count_after as u16)
.map(|count| (offset as u16, count));
Ok(())
}
}
impl<R: Read> Decoder<R> for Lh1Decoder<R> where R::Error: core::fmt::Debug {
type Error = R::Error;
fn into_inner(self) -> R {
self.bit_reader.into_inner()
}
fn fill_buffer(&mut self, buf: &mut[u8]) -> LhaResult<(), R> {
let buflen = buf.len();
let mut target = buf.iter_mut();
if let Some((offset, count)) = self.copy_progress {
self.copy_from_history(&mut target,
offset as usize,
count.get() as usize)?;
}
while let Some(dst) = target.next() {
match self.read_command()? {
code @ 0..=0xff => {
let value = code as u8;
*dst = value;
self.ringbuf.push(value);
}
count => {
let offset = self.read_offset()?;
let index = buflen - target.len() - 1;
target = buf[index..].iter_mut();
self.copy_from_history(&mut target,
offset as usize,
(count - 0x100 + 3).into())?;
}
}
}
Ok(())
}
}
#[inline(always)]
fn decode_offset(bits9: u16) -> (u16, u32) {
match bits9 & 0b111100000 {
0b000000000..=0b000111111 => (bits9, 0),
0b001000000..=0b010011111 => ((bits9 - 0b000100000) << 1, 1),
0b010100000..=0b100011111 => ((bits9 - 0b001100000) << 2, 2),
0b100100000..=0b101111111 => ((bits9 - 0b011000000) << 3, 3),
0b110000000..=0b111011111 => ((bits9 - 0b100100000) << 4, 4),
0b111100000..=0b111111111 => ((bits9 - 0b110000000) << 5, 5),
_ => unreachable!()
}
}
#[cfg(feature = "std")]
#[cfg(test)]
mod tests {
use super::*;
use std::io;
use std::fs;
#[test]
fn lhav1_works() {
println!("Lh1Decoder<Empty> {}", core::mem::size_of::<Lh1Decoder<io::Empty>>());
println!("Lh1Decoder<File> {}", core::mem::size_of::<Lh1Decoder<fs::File>>());
println!("DynHuffTree {}", core::mem::size_of::<DynHuffTree>());
}
}