use std::{
io::{self, Seek},
rc::Rc,
};
use sit_algos::huffman::HuffmanReader;
use sit_algos::huffman_fixed::HuffmanReader as HuffmanFixedReader;
use sit_algos::lmzw::LmzwReader;
use sit_algos::lz_huffman::LzHuffmanReader;
use sit_algos::lzah::LzahReader;
use sit_algos::lzw::LzwReader;
use sit_algos::none::NoneReader;
use sit_algos::rle90::Rle90Reader;
use sit_algos::{arsenic::ArsenicReader, installer::InstallerReader};
use crate::{Error, VerifyingEntryReader, structs::Algorithm};
pub(crate) enum EntryReader<'a, R: io::Read + io::Seek> {
None {
reader: NoneReader<&'a mut R>,
},
Rle {
reader: Rle90Reader<NoneReader<&'a mut R>>,
},
Lzw {
reader: Box<LzwReader<NoneReader<&'a mut R>>>,
},
Huffman {
reader: HuffmanReader<NoneReader<&'a mut R>>,
},
Lzah {
reader: Box<LzahReader<NoneReader<&'a mut R>>>,
},
HuffmanFixed {
reader: Box<HuffmanFixedReader<NoneReader<&'a mut R>>>,
},
Lmzw {
reader: Box<LmzwReader<NoneReader<&'a mut R>>>,
},
LzHuffman {
reader: Box<LzHuffmanReader<NoneReader<&'a mut R>>>,
},
Installer {
reader: Box<InstallerReader<NoneReader<&'a mut R>>>,
},
Arsenic {
reader: Box<ArsenicReader<'a, NoneReader<&'a mut R>>>,
},
}
impl<'a, R: io::Read + io::Seek> EntryReader<'a, R> {
pub(crate) fn try_from(
reader: &'a mut Rc<R>,
algo: Algorithm,
uncompressed_size: u64,
compressed_size: usize,
offset: u64,
) -> Result<Self, Error> {
unsafe { Rc::get_mut_unchecked(reader).seek(io::SeekFrom::Start(offset))? };
unsafe {
Ok(match algo {
Algorithm::None => EntryReader::None {
reader: NoneReader::with_length(
Rc::get_mut_unchecked(reader),
offset,
compressed_size as u64,
),
},
Algorithm::RLE => EntryReader::Rle {
reader: Rle90Reader::new(
NoneReader::with_length(
Rc::get_mut_unchecked(reader),
offset,
compressed_size as u64,
),
uncompressed_size,
),
},
Algorithm::LZW => EntryReader::Lzw {
reader: Box::new(LzwReader::new(
NoneReader::with_length(
Rc::get_mut_unchecked(reader),
offset,
compressed_size as u64,
),
uncompressed_size,
)),
},
Algorithm::Huffman => EntryReader::Huffman {
reader: HuffmanReader::try_from(
NoneReader::with_length(
Rc::get_mut_unchecked(reader),
offset,
compressed_size as u64,
),
uncompressed_size,
)?,
},
Algorithm::LZAH => EntryReader::Lzah {
reader: Box::new(LzahReader::new(
NoneReader::with_length(
Rc::get_mut_unchecked(reader),
offset,
compressed_size as u64,
),
uncompressed_size,
)),
},
Algorithm::HuffmanFixed => EntryReader::HuffmanFixed {
reader: Box::new(HuffmanFixedReader::try_from(
NoneReader::with_length(
Rc::get_mut_unchecked(reader),
offset,
compressed_size as u64,
),
uncompressed_size,
)?),
},
Algorithm::LZMW => EntryReader::Lmzw {
reader: Box::new(LmzwReader::new(
NoneReader::with_length(
Rc::get_mut_unchecked(reader),
offset,
compressed_size as u64,
),
uncompressed_size,
)),
},
Algorithm::LzHuffman => EntryReader::LzHuffman {
reader: Box::new(LzHuffmanReader::new(
NoneReader::with_length(
Rc::get_mut_unchecked(reader),
offset,
compressed_size as u64,
),
uncompressed_size,
)),
},
Algorithm::Installer => EntryReader::Installer {
reader: Box::new(InstallerReader::try_new(NoneReader::with_length(
Rc::get_mut_unchecked(reader),
offset,
compressed_size as u64,
))?),
},
Algorithm::Arsenic => EntryReader::Arsenic {
reader: Box::new(ArsenicReader::try_from(
NoneReader::with_length(
Rc::get_mut_unchecked(reader),
offset,
compressed_size as u64,
),
uncompressed_size,
)?),
},
Algorithm::Unknown(id) => {
return Err(Error::UnsupportedFeature(
crate::error::UnsupportedFeature::Algorithm(Algorithm::Unknown(id)),
));
}
})
}
}
pub fn verifying(self, checksum: u16) -> VerifyingEntryReader<'a, R> {
let is_arsenic = matches!(self, EntryReader::Arsenic { .. });
VerifyingEntryReader::new(self, checksum, is_arsenic)
}
pub(crate) fn ended(&mut self) -> Result<bool, io::Error> {
Ok(self.stream_position()? >= self.stream_len()?)
}
}
impl<'a, R: io::Read + io::Seek> io::Read for EntryReader<'a, R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
EntryReader::None { reader, .. } => reader.read(buf),
EntryReader::Rle { reader, .. } => reader.read(buf),
EntryReader::Lzw { reader, .. } => reader.read(buf),
EntryReader::Huffman { reader, .. } => reader.read(buf),
EntryReader::Lzah { reader, .. } => reader.read(buf),
EntryReader::HuffmanFixed { reader, .. } => reader.read(buf),
EntryReader::Lmzw { reader, .. } => reader.read(buf),
EntryReader::LzHuffman { reader, .. } => reader.read(buf),
EntryReader::Installer { reader } => reader.read(buf),
EntryReader::Arsenic { reader, .. } => reader.read(buf),
}
}
}
impl<'a, R: io::Read + io::Seek> io::Seek for EntryReader<'a, R> {
#[inline]
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
match self {
EntryReader::None { reader, .. } => reader.seek(pos),
EntryReader::Rle { reader, .. } => reader.seek(pos),
EntryReader::Lzw { reader, .. } => reader.seek(pos),
EntryReader::Huffman { reader, .. } => reader.seek(pos),
EntryReader::Lzah { reader, .. } => reader.seek(pos),
EntryReader::HuffmanFixed { reader, .. } => reader.seek(pos),
EntryReader::Lmzw { reader, .. } => reader.seek(pos),
EntryReader::LzHuffman { reader, .. } => reader.seek(pos),
EntryReader::Installer { reader } => reader.seek(pos),
EntryReader::Arsenic { reader, .. } => reader.seek(pos),
}
}
#[inline]
fn stream_position(&mut self) -> io::Result<u64> {
match self {
EntryReader::None { reader, .. } => reader.stream_position(),
EntryReader::Rle { reader, .. } => reader.stream_position(),
EntryReader::Lzw { reader, .. } => reader.stream_position(),
EntryReader::Huffman { reader, .. } => reader.stream_position(),
EntryReader::Lzah { reader, .. } => reader.stream_position(),
EntryReader::HuffmanFixed { reader, .. } => reader.stream_position(),
EntryReader::Lmzw { reader, .. } => reader.stream_position(),
EntryReader::LzHuffman { reader, .. } => reader.stream_position(),
EntryReader::Installer { reader, .. } => reader.stream_position(),
EntryReader::Arsenic { reader, .. } => reader.stream_position(),
}
}
#[inline]
fn stream_len(&mut self) -> io::Result<u64> {
match self {
EntryReader::None { reader, .. } => reader.stream_len(),
EntryReader::Rle { reader, .. } => reader.stream_len(),
EntryReader::Lzw { reader, .. } => reader.stream_len(),
EntryReader::Huffman { reader, .. } => reader.stream_len(),
EntryReader::Lzah { reader, .. } => reader.stream_len(),
EntryReader::HuffmanFixed { reader, .. } => reader.stream_len(),
EntryReader::Lmzw { reader, .. } => reader.stream_len(),
EntryReader::LzHuffman { reader, .. } => reader.stream_len(),
EntryReader::Installer { reader, .. } => reader.stream_len(),
EntryReader::Arsenic { reader, .. } => reader.stream_len(),
}
}
}