use super::{stream::FormatErrorInner, unfiltering_buffer::UnfilteringBuffer, DecodingError};
use fdeflate::Decompressor;
pub struct UnfilterBuf<'data> {
pub(crate) buffer: &'data mut Vec<u8>,
pub(crate) filled: &'data mut usize,
pub(crate) available: &'data mut usize,
}
#[derive(Default, Clone, Copy)]
pub struct UnfilterRegion {
pub available: usize,
pub filled: usize,
}
pub(super) struct ZlibStream {
state: Box<fdeflate::Decompressor>,
started: bool,
ignore_adler32: bool,
}
impl ZlibStream {
const LOOKBACK_SIZE: usize = 32768;
pub(crate) fn new() -> Self {
ZlibStream {
state: Box::new(Decompressor::new()),
started: false,
ignore_adler32: true,
}
}
pub(crate) fn reset(&mut self) {
self.started = false;
*self.state = Decompressor::new();
}
pub(crate) fn set_ignore_adler32(&mut self, flag: bool) -> bool {
if !self.started {
self.ignore_adler32 = flag;
true
} else {
false
}
}
pub(crate) fn ignore_adler32(&self) -> bool {
self.ignore_adler32
}
pub(crate) fn decompress(
&mut self,
data: &[u8],
image_data: &mut UnfilterBuf<'_>,
) -> Result<usize, DecodingError> {
if self.state.is_done() {
return Ok(data.len());
}
if !self.started && self.ignore_adler32 {
self.state.ignore_adler32();
}
let (buffer, filled) = image_data.borrow_mut();
let output_limit = (filled + UnfilteringBuffer::GROWTH_BYTES).min(buffer.len());
let (in_consumed, out_consumed) = self
.state
.read(data, &mut buffer[..output_limit], filled, false)
.map_err(|err| {
DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into())
})?;
self.started = true;
let filled = filled + out_consumed;
image_data.filled(filled);
if self.state.is_done() {
image_data.commit(filled);
} else {
image_data.commit(filled.saturating_sub(Self::LOOKBACK_SIZE));
}
Ok(in_consumed)
}
pub(crate) fn finish_compressed_chunks(
&mut self,
image_data: &mut UnfilterBuf<'_>,
) -> Result<(), DecodingError> {
if !self.started {
return Ok(());
}
if self.state.is_done() {
return Ok(());
}
let (_, mut filled) = image_data.borrow_mut();
while !self.state.is_done() {
let (buffer, _) = image_data.borrow_mut();
let (_in_consumed, out_consumed) =
self.state.read(&[], buffer, filled, true).map_err(|err| {
DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into())
})?;
filled += out_consumed;
if !self.state.is_done() {
image_data.flush_allocate();
}
}
image_data.filled(filled);
image_data.commit(filled);
Ok(())
}
}
impl UnfilterRegion {
pub fn as_buf<'data>(&'data mut self, buffer: &'data mut Vec<u8>) -> UnfilterBuf<'data> {
UnfilterBuf {
buffer,
filled: &mut self.filled,
available: &mut self.available,
}
}
}
impl UnfilterBuf<'_> {
pub(crate) fn borrow_mut(&mut self) -> (&mut [u8], usize) {
(self.buffer, *self.filled)
}
pub(crate) fn filled(&mut self, filled: usize) {
*self.filled = filled;
}
pub(crate) fn commit(&mut self, howmany: usize) {
*self.available = howmany;
}
pub(crate) fn flush_allocate(&mut self) {
let len = self.buffer.len() + 32 * 1024;
self.buffer.resize(len, 0);
}
}