#[cfg(feature = "zlib")]
mod zlib;
use std::{
fmt::Display,
io::{Read, Seek, SeekFrom, Write},
};
use crate::{
error::{Error, Result},
file::BasicFileEntry,
read::BlockSize,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum CompressionType {
None,
Zlib,
Lzma,
}
impl CompressionType {
pub(crate) fn decompress<R, W, F>(
self,
reader: &mut R,
writer: &mut W,
entry: &F,
block_size: BlockSize,
block_sizes: &[u32],
) -> Result<()>
where
R: Read + Seek,
W: Write,
F: BasicFileEntry,
{
reader.seek(SeekFrom::Start(
u64::try_from(entry.offset()).map_err(|_| Error::AddressTooSmall)?,
))?;
match self {
Self::None => {
let mut bytes = reader
.take(u64::try_from(entry.output_size()).map_err(|_| Error::AddressTooSmall)?);
std::io::copy(&mut bytes, writer)?;
Ok(())
}
#[cfg(feature = "zlib")]
Self::Zlib => zlib::decompress(reader, writer, entry, block_size, block_sizes),
#[cfg(feature = "lzma")]
Self::Lzma => todo!(),
#[cfg(not(all(feature = "lzma", feature = "zlib")))]
unsupported => Err(Error::UnsupportedCompression(unsupported.to_string())),
}
}
}
impl Display for CompressionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::None => "none",
Self::Zlib => "zlib",
Self::Lzma => "lzma",
})
}
}
impl TryFrom<u32> for CompressionType {
type Error = Error;
fn try_from(value: u32) -> Result<Self> {
match &value.to_be_bytes() {
[0, 0, 0, 0] => Ok(Self::None),
b"zlib" => Ok(Self::Zlib),
b"lzma" => Ok(Self::Lzma),
unsupported => Err(Error::UnsupportedCompression(
String::from_utf8_lossy(unsupported).into_owned(),
)),
}
}
}