use alloc::{Allocator, SliceWrapperMut}; #[cfg(feature = "std")] use std::io; #[cfg(feature = "std")] use std::io::{Error, ErrorKind, Read}; #[cfg(feature = "std")] pub use alloc_stdlib::StandardAlloc; use brotli_decompressor::CustomRead; #[cfg(feature = "std")] pub use brotli_decompressor::{IntoIoReader, IoReaderWrapper, IoWriterWrapper}; use super::backward_references::BrotliEncoderParams; use super::combined_alloc::BrotliAlloc; use super::encode::{ BrotliEncoderDestroyInstance, BrotliEncoderOperation, BrotliEncoderParameter, BrotliEncoderStateStruct, }; use super::interface; use crate::enc::combined_alloc::allocate; #[cfg(feature = "std")] pub struct CompressorReaderCustomAlloc, Alloc: BrotliAlloc>( CompressorReaderCustomIo, BufferType, Alloc>, ); #[cfg(feature = "std")] impl, Alloc: BrotliAlloc> CompressorReaderCustomAlloc { pub fn new(r: R, buffer: BufferType, alloc: Alloc, q: u32, lgwin: u32) -> Self { CompressorReaderCustomAlloc::(CompressorReaderCustomIo::< Error, IntoIoReader, BufferType, Alloc, >::new( IntoIoReader::(r), buffer, alloc, Error::new(ErrorKind::InvalidData, "Invalid Data"), q, lgwin, )) } pub fn get_ref(&self) -> &R { &self.0.get_ref().0 } pub fn into_inner(self) -> R { self.0.into_inner().0 } } #[cfg(feature = "std")] impl, Alloc: BrotliAlloc> Read for CompressorReaderCustomAlloc { fn read(&mut self, buf: &mut [u8]) -> Result { self.0.read(buf) } } #[cfg(feature = "std")] pub struct CompressorReader( CompressorReaderCustomAlloc< R, >::AllocatedMemory, StandardAlloc, >, ); #[cfg(feature = "std")] impl CompressorReader { pub fn new(r: R, buffer_size: usize, q: u32, lgwin: u32) -> Self { let mut alloc = StandardAlloc::default(); let buffer = allocate::( &mut alloc, if buffer_size == 0 { 4096 } else { buffer_size }, ); CompressorReader::(CompressorReaderCustomAlloc::new(r, buffer, alloc, q, lgwin)) } pub fn with_params(r: R, buffer_size: usize, params: &BrotliEncoderParams) -> Self { let mut reader = Self::new(r, buffer_size, params.quality as u32, params.lgwin as u32); (reader.0).0.state.0.params = params.clone(); reader } pub fn get_ref(&self) -> &R { self.0.get_ref() } pub fn into_inner(self) -> R { self.0.into_inner() } } #[cfg(feature = "std")] impl Read for CompressorReader { fn read(&mut self, buf: &mut [u8]) -> Result { self.0.read(buf) } } pub struct CompressorReaderCustomIo< ErrType, R: CustomRead, BufferType: SliceWrapperMut, Alloc: BrotliAlloc, > { input_buffer: BufferType, total_out: Option, input_offset: usize, input_len: usize, input: R, input_eof: bool, error_if_invalid_data: Option, state: StateWrapper, } struct StateWrapper(BrotliEncoderStateStruct); impl Drop for StateWrapper { fn drop(&mut self) { BrotliEncoderDestroyInstance(&mut self.0); } } impl, BufferType: SliceWrapperMut, Alloc: BrotliAlloc> CompressorReaderCustomIo { pub fn new( r: R, buffer: BufferType, alloc: Alloc, invalid_data_error_type: ErrType, q: u32, lgwin: u32, ) -> Self { let mut ret = CompressorReaderCustomIo { input_buffer: buffer, total_out: Some(0), input_offset: 0, input_len: 0, input_eof: false, input: r, state: StateWrapper(BrotliEncoderStateStruct::new(alloc)), error_if_invalid_data: Some(invalid_data_error_type), }; ret.state .0 .set_parameter(BrotliEncoderParameter::BROTLI_PARAM_QUALITY, q); ret.state .0 .set_parameter(BrotliEncoderParameter::BROTLI_PARAM_LGWIN, lgwin); ret } pub fn copy_to_front(&mut self) { let avail_in = self.input_len - self.input_offset; if self.input_offset == self.input_buffer.slice_mut().len() { self.input_offset = 0; self.input_len = 0; } else if self.input_offset + 256 > self.input_buffer.slice_mut().len() && avail_in < self.input_offset { let (first, second) = self .input_buffer .slice_mut() .split_at_mut(self.input_offset); first[0..avail_in].clone_from_slice(&second[0..avail_in]); self.input_len -= self.input_offset; self.input_offset = 0; } } pub fn into_inner(self) -> R { match self { CompressorReaderCustomIo { input_buffer: _ib, total_out: _to, input_offset: _io, input_len: _len, input, input_eof: _ieof, error_if_invalid_data: _eiid, state: _state, } => input, } } pub fn get_ref(&self) -> &R { &self.input } } impl, BufferType: SliceWrapperMut, Alloc: BrotliAlloc> CustomRead for CompressorReaderCustomIo { fn read(&mut self, buf: &mut [u8]) -> Result { let mut nop_callback = |_data: &mut interface::PredictionModeContextMap, _cmds: &mut [interface::StaticCommand], _mb: interface::InputPair, _mfv: &mut Alloc| (); let mut output_offset: usize = 0; let mut avail_out = buf.len(); let mut avail_in = self.input_len - self.input_offset; while output_offset == 0 { if self.input_len < self.input_buffer.slice_mut().len() && !self.input_eof { match self .input .read(&mut self.input_buffer.slice_mut()[self.input_len..]) { Err(e) => return Err(e), Ok(size) => { if size == 0 { self.input_eof = true; } else { self.input_len += size; avail_in = self.input_len - self.input_offset; } } } } let op: BrotliEncoderOperation; if avail_in == 0 { op = BrotliEncoderOperation::BROTLI_OPERATION_FINISH; } else { op = BrotliEncoderOperation::BROTLI_OPERATION_PROCESS; } let ret = self.state.0.compress_stream( op, &mut avail_in, self.input_buffer.slice_mut(), &mut self.input_offset, &mut avail_out, buf, &mut output_offset, &mut self.total_out, &mut nop_callback, ); if avail_in == 0 { self.copy_to_front(); } if !ret { return Err(self.error_if_invalid_data.take().unwrap()); } if self.state.0.is_finished() { break; } } Ok(output_offset) } }