use std::io::Read;
use crate::error::{ArchiveError, Result};
pub struct BitStream<R: Read> {
#[allow(dead_code)]
reader: R,
buffer: Vec<u32>,
pos: usize,
len: usize,
}
impl<R: Read> BitStream<R> {
pub fn new(mut reader: R, size: usize) -> Self {
let mut data = vec![0u8; size];
let _ = reader.read(&mut data);
let mut buffer = Vec::with_capacity(size.div_ceil(4));
for chunk in data.chunks(4) {
let mut bytes = [0u8; 4];
bytes[..chunk.len()].copy_from_slice(chunk);
buffer.push(u32::from_le_bytes(bytes));
}
let len = buffer.len() * 32;
Self { reader, buffer, pos: 0, len }
}
fn get_bits(value: u32, start: usize, length: usize) -> u32 {
if length == 0 {
return 0;
}
let mask = ((0xFFFFFFFFu64 << (32 - length)) & 0xFFFFFFFF) >> start;
((value as u64 & mask) >> (32 - length - start)) as u32
}
pub fn peek_bits(&mut self, n: u8) -> Result<u32> {
if n == 0 {
return Ok(0);
}
let bits = n as usize;
if self.pos + bits > self.len + 31 {
return Err(ArchiveError::decompression_failed("bitstream", "unexpected end of data"));
}
while self.pos + bits > self.buffer.len() * 32 {
self.buffer.push(0);
}
let word_idx = self.pos / 32;
let bit_idx = self.pos % 32;
let peeked = bits.min(32 - bit_idx);
let mut res = Self::get_bits(self.buffer[word_idx], bit_idx, peeked) as u64;
let mut total_peeked = peeked;
while bits - total_peeked >= 32 {
res <<= 32;
res += self.buffer[(self.pos + total_peeked) / 32] as u64;
total_peeked += 32;
}
if bits > total_peeked {
let remaining = bits - total_peeked;
res <<= remaining;
res += Self::get_bits(self.buffer[(self.pos + total_peeked) / 32], 0, remaining) as u64;
}
Ok(res as u32)
}
pub fn skip_bits(&mut self, n: u8) -> Result<()> {
self.pos += n as usize;
Ok(())
}
pub fn read_bits(&mut self, n: u8) -> Result<u32> {
let value = self.peek_bits(n)?;
self.skip_bits(n)?;
Ok(value)
}
pub fn read_known_width_uint(&mut self, bits: u8) -> Result<u32> {
if bits < 2 {
return Ok(bits as u32);
}
let actual_bits = bits - 1;
let value = self.read_bits(actual_bits)?;
Ok(value + (1 << actual_bits))
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_python_compatibility() {
let data = b"01234567";
let mut bs = BitStream::new(Cursor::new(data.to_vec()), 8);
let result = bs.peek_bits(31).unwrap();
println!("peek_bits(31) = {} (expected 429463704)", result);
assert_eq!(result, 429463704);
let result = bs.read_bits(31).unwrap();
assert_eq!(result, 429463704);
bs.skip_bits(3).unwrap();
let result = bs.read_bits(5).unwrap();
println!("read_bits(5) = {} (expected 27)", result);
assert_eq!(result, 27);
}
}