#[cfg(test)]
mod tests;
use super::{ArtifactError, read_reader};
use std::fmt;
#[derive(Debug)]
pub enum GzipError {
InputLimit {
actual: usize,
limit: usize,
},
Decode(ArtifactError),
TrailingData,
}
impl fmt::Display for GzipError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InputLimit { actual, limit } => {
write!(f, "compressed input has {actual} bytes, exceeding {limit}")
}
Self::Decode(_) => f.write_str("bounded gzip decoding failed"),
Self::TrailingData => f.write_str("bytes follow the single gzip member"),
}
}
}
impl std::error::Error for GzipError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Decode(source) => Some(source),
_ => None,
}
}
}
pub fn decode_gzip(
bytes: &[u8],
max_compressed_bytes: usize,
max_decoded_bytes: usize,
) -> Result<Vec<u8>, GzipError> {
if bytes.len() > max_compressed_bytes {
return Err(GzipError::InputLimit {
actual: bytes.len(),
limit: max_compressed_bytes,
});
}
let mut decoder = flate2::bufread::GzDecoder::new(bytes);
let payload = read_reader(&mut decoder, max_decoded_bytes).map_err(GzipError::Decode)?;
if !decoder.into_inner().is_empty() {
return Err(GzipError::TrailingData);
}
Ok(payload)
}