sit-algos 0.3.0

Implementation of decompression algorithms used by StuffIt Expander and related applications
Documentation
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),
        }
    }
}