compact-pro 0.2.0

Read compressed files created by Compact Pro
Documentation
use crate::{lzh::LzhReader, rle::RleReader, Error};
use std::{io, rc::Rc};

#[derive(Debug, Default, Copy, Clone)]
pub(crate) enum CompressionMethod {
    #[default]
    Rle,
    Lzh,
}

#[derive(Debug, Default, Copy, Clone)]
pub(crate) struct StreamDescription {
    pub(crate) method: CompressionMethod,
    pub(crate) _compressed_len: usize,
    pub(crate) uncompressed_len: usize,
    pub(crate) offset: u64,
}

pub enum EntryReader<'a, R: io::Read + std::io::Seek> {
    RleReader(RleReader<&'a mut R>),
    LzhReader(LzhReader<'a, R>),
}

impl<'a, R: io::Read + std::io::Seek> EntryReader<'a, R> {
    pub(crate) fn try_new(reader: &'a mut Rc<R>, spec: StreamDescription) -> Result<Self, Error> {
        let StreamDescription {
            method,
            uncompressed_len,
            offset,
            ..
        } = spec;
        // TODO: document safety considerations
        let reader = unsafe { Rc::get_mut_unchecked(reader) };

        reader.seek(io::SeekFrom::Start(offset))?;

        Ok(match method {
            CompressionMethod::Rle => Self::RleReader(RleReader::new(reader, uncompressed_len)),
            CompressionMethod::Lzh => {
                Self::LzhReader(LzhReader::try_new(reader, uncompressed_len)?)
            }
        })
    }
}

impl<R: io::Read + std::io::Seek> std::io::Read for EntryReader<'_, R> {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match self {
            EntryReader::RleReader(reader) => reader.read(buf),
            EntryReader::LzhReader(reader) => reader.read(buf),
        }
    }
}