use std::{fs, io};
use crate::{lookup_table, util::ReadByte, Error, SixBitDecoder};
pub struct SixBitRleReader<R> {
inner: R,
b6_decoder: SixBitDecoder,
rle_byte: u8,
rle_repetition: u8,
ended: bool,
pub(crate) data_start: u64,
pub(crate) position: u64,
}
impl<R> SixBitRleReader<R> {
pub(crate) fn new(inner: R, data_start: u64) -> Self {
Self {
inner,
b6_decoder: SixBitDecoder::default(),
ended: false,
position: 0,
data_start,
rle_byte: 0,
rle_repetition: 0,
}
}
pub(crate) fn into_inner(self) -> R {
self.inner
}
}
impl<R: io::Read> SixBitRleReader<R> {
#[inline]
fn produce_partial_byte(&mut self) -> io::Result<Option<u8>> {
loop {
match lookup_table::TABLE[self.inner.read_byte()? as usize] {
lookup_table::Entry::Ended => {
self.ended = true;
return Ok(None);
}
lookup_table::Entry::Invalid => return Err(Error::InvalidCharacter.into()),
lookup_table::Entry::Ignore => continue,
lookup_table::Entry::Valid(byte) => return Ok(Some(byte)),
}
}
}
#[inline]
fn produce_rle_instruction(&mut self) -> io::Result<Option<u8>> {
loop {
let Some(partial) = self.produce_partial_byte()? else {
return Ok(None);
};
match self.b6_decoder.next(partial) {
Some(byte) => return Ok(Some(byte)),
None => continue,
}
}
}
#[inline]
fn produce_byte(&mut self) -> io::Result<Option<u8>> {
if self.rle_repetition != 0 {
self.rle_repetition -= 1;
return Ok(Some(self.rle_byte));
}
let Some(current) = self.produce_rle_instruction()? else {
return Ok(None);
};
if current == 0x90 {
let Some(secondary) = self.produce_rle_instruction()? else {
return Err(Error::UnexpectedEof.into());
};
match secondary {
0 => self.rle_byte = 0x90,
1 => self.rle_repetition = 0,
count => self.rle_repetition = count - 2,
}
return Ok(Some(self.rle_byte));
}
self.rle_byte = current;
Ok(Some(current))
}
}
impl<R: io::Read + io::Seek> SixBitRleReader<R> {
pub(crate) fn reset(&mut self) -> io::Result<()> {
self.b6_decoder = SixBitDecoder::new();
self.rle_byte = 0;
self.rle_repetition = 0;
self.ended = false;
self.inner.seek(io::SeekFrom::Start(self.data_start))?;
self.position = 0;
Ok(())
}
}
impl<R: io::Read> io::Read for SixBitRleReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.ended {
return Ok(0);
}
for (idx, out) in buf.iter_mut().enumerate() {
let Some(byte) = self.produce_byte()? else {
self.position += idx as u64;
return Ok(idx);
};
*out = byte;
}
self.position += buf.len() as u64;
Ok(buf.len())
}
}
impl<R: io::Read + io::Seek> io::Seek for SixBitRleReader<R> {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
match pos {
io::SeekFrom::Start(0) => {
self.reset()?;
Ok(0)
}
io::SeekFrom::Start(x) => {
if x < self.position {
log::warn!(
"Performing expensive backwards seek from {} to {}",
self.position,
x
);
self.seek(io::SeekFrom::Start(0))?;
self.seek(io::SeekFrom::Current(x as i64))
} else if x > self.position {
self.seek(io::SeekFrom::Current(x as i64 - self.position as i64))
} else {
Ok(x)
}
}
io::SeekFrom::Current(val) if val >= 0 => {
let mut skipped_bytes = 0;
for _ in 0..val {
if (self.produce_byte()?).is_some() {
skipped_bytes += 1;
} else {
break;
}
}
self.position += skipped_bytes;
Ok(self.position)
}
mode => {
eprintln!("Unsupported seek {mode:?}");
Err(Error::UnsupportedSeek.into())
}
}
}
}
impl<R: Clone> Clone for SixBitRleReader<R> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
data_start: self.data_start,
b6_decoder: self.b6_decoder.clone(),
rle_byte: self.rle_byte,
rle_repetition: self.rle_repetition,
ended: self.ended,
position: self.position,
}
}
}
impl SixBitRleReader<fs::File> {
pub(crate) fn try_clone(&self) -> io::Result<Self> {
Ok(Self {
inner: self.inner.try_clone()?,
data_start: self.data_start,
b6_decoder: self.b6_decoder.clone(),
rle_byte: self.rle_byte,
rle_repetition: self.rle_repetition,
ended: self.ended,
position: self.position,
})
}
}