use alloc::vec::Vec;
use crate::{
Error, ErrorKind, Level, Limits, Progress,
deflate::{Deflater, Flush, Inflater},
gzip, zlib,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Format {
Raw,
Zlib,
Gzip,
}
impl Format {
#[must_use]
pub fn detect(data: &[u8]) -> Option<Format> {
match data {
[0x1F, 0x8B, ..] => Some(Format::Gzip),
[cmf, flg, ..] if zlib::header_ok(*cmf, *flg) => Some(Format::Zlib),
_ => None,
}
}
}
pub fn decompress(data: &[u8]) -> Result<Vec<u8>, Error> {
decompress_with(data, Limits::new())
}
pub fn decompress_with(data: &[u8], limits: Limits) -> Result<Vec<u8>, Error> {
match Format::detect(data) {
Some(Format::Gzip) => gzip::decompress_with(data, limits),
Some(Format::Zlib) => zlib::decompress_with(data, limits),
_ => Err(Error::new(ErrorKind::InvalidHeader, 0)),
}
}
#[derive(Debug)]
enum Inner<R, Z, G> {
Raw(R),
Zlib(Z),
Gzip(G),
}
#[derive(Debug)]
pub struct Decoder(Inner<Inflater, zlib::Decoder, gzip::Decoder>);
impl Decoder {
#[must_use]
pub fn new(format: Format) -> Self {
Self(match format {
Format::Raw => Inner::Raw(Inflater::new()),
Format::Zlib => Inner::Zlib(zlib::Decoder::new()),
Format::Gzip => Inner::Gzip(gzip::Decoder::new()),
})
}
#[must_use]
pub fn with_limits(self, limits: Limits) -> Self {
Self(match self.0 {
Inner::Raw(d) => Inner::Raw(d.with_limits(limits)),
Inner::Zlib(d) => Inner::Zlib(d.with_limits(limits)),
Inner::Gzip(d) => Inner::Gzip(d.with_limits(limits)),
})
}
#[must_use]
pub fn format(&self) -> Format {
match self.0 {
Inner::Raw(_) => Format::Raw,
Inner::Zlib(_) => Format::Zlib,
Inner::Gzip(_) => Format::Gzip,
}
}
pub fn decompress(&mut self, input: &[u8], output: &mut [u8]) -> Result<Progress, Error> {
match &mut self.0 {
Inner::Raw(d) => d.decompress(input, output),
Inner::Zlib(d) => d.decompress(input, output),
Inner::Gzip(d) => d.decompress(input, output),
}
}
pub fn finish(&mut self, input: &[u8], output: &mut [u8]) -> Result<Progress, Error> {
match &mut self.0 {
Inner::Raw(d) => d.finish(input, output),
Inner::Zlib(d) => d.finish(input, output),
Inner::Gzip(d) => d.finish(input, output),
}
}
pub fn decompress_vec(&mut self, input: &[u8], out: &mut Vec<u8>) -> Result<Progress, Error> {
match &mut self.0 {
Inner::Raw(d) => d.decompress_vec(input, out),
Inner::Zlib(d) => d.decompress_vec(input, out),
Inner::Gzip(d) => d.decompress_vec(input, out),
}
}
pub fn finish_vec(&mut self, input: &[u8], out: &mut Vec<u8>) -> Result<Progress, Error> {
match &mut self.0 {
Inner::Raw(d) => d.finish_vec(input, out),
Inner::Zlib(d) => d.finish_vec(input, out),
Inner::Gzip(d) => d.finish_vec(input, out),
}
}
#[must_use]
pub fn is_done(&self) -> bool {
match &self.0 {
Inner::Raw(d) => d.is_done(),
Inner::Zlib(d) => d.is_done(),
Inner::Gzip(d) => d.is_done(),
}
}
#[must_use]
pub fn total_in(&self) -> u64 {
match &self.0 {
Inner::Raw(d) => d.total_in(),
Inner::Zlib(d) => d.total_in(),
Inner::Gzip(d) => d.total_in(),
}
}
#[must_use]
pub fn total_out(&self) -> u64 {
match &self.0 {
Inner::Raw(d) => d.total_out(),
Inner::Zlib(d) => d.total_out(),
Inner::Gzip(d) => d.total_out(),
}
}
pub fn reset(&mut self) {
match &mut self.0 {
Inner::Raw(d) => d.reset(),
Inner::Zlib(d) => d.reset(),
Inner::Gzip(d) => d.reset(),
}
}
}
#[derive(Debug)]
pub struct Encoder(Inner<Deflater, zlib::Encoder, gzip::Encoder>);
impl Encoder {
#[must_use]
pub fn new(format: Format, level: Level) -> Self {
Self(match format {
Format::Raw => Inner::Raw(Deflater::new(level)),
Format::Zlib => Inner::Zlib(zlib::Encoder::new(level)),
Format::Gzip => Inner::Gzip(gzip::Encoder::new(level)),
})
}
#[must_use]
pub fn format(&self) -> Format {
match self.0 {
Inner::Raw(_) => Format::Raw,
Inner::Zlib(_) => Format::Zlib,
Inner::Gzip(_) => Format::Gzip,
}
}
pub fn compress(
&mut self,
input: &[u8],
output: &mut [u8],
flush: Flush,
) -> Result<Progress, Error> {
match &mut self.0 {
Inner::Raw(e) => e.compress(input, output, flush),
Inner::Zlib(e) => e.compress(input, output, flush),
Inner::Gzip(e) => e.compress(input, output, flush),
}
}
pub fn compress_vec(
&mut self,
input: &[u8],
out: &mut Vec<u8>,
flush: Flush,
) -> Result<Progress, Error> {
match &mut self.0 {
Inner::Raw(e) => e.compress_vec(input, out, flush),
Inner::Zlib(e) => e.compress_vec(input, out, flush),
Inner::Gzip(e) => e.compress_vec(input, out, flush),
}
}
pub fn reset(&mut self) {
match &mut self.0 {
Inner::Raw(e) => e.reset(),
Inner::Zlib(e) => e.reset(),
Inner::Gzip(e) => e.reset(),
}
}
}