use std::io;
pub struct Rle90Reader<R: io::Read> {
inner: R,
count: u8,
last_byte: u8,
uncompressed_size: u64,
produced_bytes: u64,
}
impl<R: io::Read> Rle90Reader<R> {
pub fn new(inner: R, uncompressed_size: u64) -> Self {
Self {
inner,
count: 0,
last_byte: 0,
uncompressed_size,
produced_bytes: 0,
}
}
#[inline]
fn read_next_byte(&mut self) -> io::Result<Option<u8>> {
if self.produced_bytes >= self.uncompressed_size {
return Ok(None);
}
if self.count > 0 {
self.count -= 1;
self.produced_bytes += 1;
return Ok(Some(self.last_byte));
}
match self.inner.read_byte()? {
None => Ok(None),
Some(0x90u8) => match self.inner.read_byte()? {
None => Err(io::Error::other("Unexpected end of file after escape code")),
Some(0) => {
self.last_byte = 0x90;
self.produced_bytes += 1;
Ok(Some(self.last_byte))
}
Some(1) => Err(io::Error::other("Invalid repeat count")),
Some(c) => {
self.count = c - 2;
self.produced_bytes += 1;
Ok(Some(self.last_byte))
}
},
Some(b) => {
self.last_byte = b;
self.produced_bytes += 1;
Ok(Some(self.last_byte))
}
}
}
}
impl<R: io::Read> io::Read for Rle90Reader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
for (idx, byte) in buf.iter_mut().enumerate() {
match self.read_next_byte() {
Err(e) => return Err(e),
Ok(None) => return Ok(idx),
Ok(Some(b)) => *byte = b,
}
}
Ok(buf.len())
}
}
impl<R: io::Read> io::Seek for Rle90Reader<R> {
fn seek(&mut self, _: io::SeekFrom) -> io::Result<u64> {
todo!();
}
#[inline]
fn stream_position(&mut self) -> io::Result<u64> {
Ok(self.produced_bytes)
}
#[inline]
fn stream_len(&mut self) -> io::Result<u64> {
Ok(self.uncompressed_size)
}
}
trait ReadByte {
fn read_byte(&mut self) -> io::Result<Option<u8>>;
}
impl<R: io::Read> ReadByte for R {
#[inline]
fn read_byte(&mut self) -> io::Result<Option<u8>> {
let mut buf = [0u8];
match self.read(&mut buf) {
Ok(0) => Ok(None),
Ok(_) => Ok(Some(buf[0])),
Err(err) => Err(err),
}
}
}