use super::{copy_match, push_window, Corrupt, Decompressor};
use crate::bitreader::BitReader;
const MASK: u16 = 0xff;
impl Decompressor {
pub(super) fn unpack_quick(&mut self, packed: &[u8], out: &mut [u8]) -> Result<(), Corrupt> {
let mut bits = BitReader::new(packed);
let mut pos = 0;
while pos < out.len() {
if bits.read(1) != 0 {
let byte = bits.read(8) as u8;
push_window(&mut self.window[..], &mut self.quick_pos, MASK, byte);
out[pos] = byte;
pos += 1;
} else {
let length = bits.read(2) + 2;
let distance = bits.read(8);
copy_match(
&mut self.window[..],
&mut self.quick_pos,
MASK,
distance,
length,
out,
&mut pos,
)?;
}
}
self.quick_pos = self.quick_pos.wrapping_add(5) & MASK;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::Decompressor;
use alloc::vec;
#[derive(Default)]
struct BitWriter {
out: alloc::vec::Vec<u8>,
acc: u32,
nbits: u32,
}
impl BitWriter {
fn put(&mut self, value: u32, n: u32) {
self.acc = (self.acc << n) | (value & ((1 << n) - 1));
self.nbits += n;
while self.nbits >= 8 {
self.nbits -= 8;
self.out.push((self.acc >> self.nbits) as u8);
}
}
fn finish(mut self) -> alloc::vec::Vec<u8> {
if self.nbits > 0 {
self.out.push((self.acc << (8 - self.nbits)) as u8);
}
self.out
}
}
#[test]
fn round_trips_literals_and_a_match() {
let mut w = BitWriter::default();
for byte in [b'A', b'B'] {
w.put(1, 1);
w.put(u32::from(byte), 8);
}
w.put(0, 1); w.put(3 - 2, 2); w.put(2 - 1, 8); let packed = w.finish();
let mut d = Decompressor::new();
let mut out = vec![0u8; 5];
d.unpack_quick(&packed, &mut out).unwrap();
assert_eq!(&out, b"ABABA");
}
}