aboutsummaryrefslogtreecommitdiff
path: root/vendor/miniz_oxide/src/inflate/stream.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/miniz_oxide/src/inflate/stream.rs')
-rw-r--r--vendor/miniz_oxide/src/inflate/stream.rs418
1 files changed, 0 insertions, 418 deletions
diff --git a/vendor/miniz_oxide/src/inflate/stream.rs b/vendor/miniz_oxide/src/inflate/stream.rs
deleted file mode 100644
index ee681b6..0000000
--- a/vendor/miniz_oxide/src/inflate/stream.rs
+++ /dev/null
@@ -1,418 +0,0 @@
-//! Extra streaming decompression functionality.
-//!
-//! As of now this is mainly intended for use to build a higher-level wrapper.
-#[cfg(feature = "with-alloc")]
-use crate::alloc::boxed::Box;
-use core::{cmp, mem};
-
-use crate::inflate::core::{decompress, inflate_flags, DecompressorOxide, TINFL_LZ_DICT_SIZE};
-use crate::inflate::TINFLStatus;
-use crate::{DataFormat, MZError, MZFlush, MZResult, MZStatus, StreamResult};
-
-/// Tag that determines reset policy of [InflateState](struct.InflateState.html)
-pub trait ResetPolicy {
- /// Performs reset
- fn reset(&self, state: &mut InflateState);
-}
-
-/// Resets state, without performing expensive ops (e.g. zeroing buffer)
-///
-/// Note that not zeroing buffer can lead to security issues when dealing with untrusted input.
-pub struct MinReset;
-
-impl ResetPolicy for MinReset {
- fn reset(&self, state: &mut InflateState) {
- state.decompressor().init();
- state.dict_ofs = 0;
- state.dict_avail = 0;
- state.first_call = true;
- state.has_flushed = false;
- state.last_status = TINFLStatus::NeedsMoreInput;
- }
-}
-
-/// Resets state and zero memory, continuing to use the same data format.
-pub struct ZeroReset;
-
-impl ResetPolicy for ZeroReset {
- #[inline]
- fn reset(&self, state: &mut InflateState) {
- MinReset.reset(state);
- state.dict = [0; TINFL_LZ_DICT_SIZE];
- }
-}
-
-/// Full reset of the state, including zeroing memory.
-///
-/// Requires to provide new data format.
-pub struct FullReset(pub DataFormat);
-
-impl ResetPolicy for FullReset {
- #[inline]
- fn reset(&self, state: &mut InflateState) {
- ZeroReset.reset(state);
- state.data_format = self.0;
- }
-}
-
-/// A struct that compbines a decompressor with extra data for streaming decompression.
-///
-pub struct InflateState {
- /// Inner decompressor struct
- decomp: DecompressorOxide,
-
- /// Buffer of input bytes for matches.
- /// TODO: Could probably do this a bit cleaner with some
- /// Cursor-like class.
- /// We may also look into whether we need to keep a buffer here, or just one in the
- /// decompressor struct.
- dict: [u8; TINFL_LZ_DICT_SIZE],
- /// Where in the buffer are we currently at?
- dict_ofs: usize,
- /// How many bytes of data to be flushed is there currently in the buffer?
- dict_avail: usize,
-
- first_call: bool,
- has_flushed: bool,
-
- /// Whether the input data is wrapped in a zlib header and checksum.
- /// TODO: This should be stored in the decompressor.
- data_format: DataFormat,
- last_status: TINFLStatus,
-}
-
-impl Default for InflateState {
- fn default() -> Self {
- InflateState {
- decomp: DecompressorOxide::default(),
- dict: [0; TINFL_LZ_DICT_SIZE],
- dict_ofs: 0,
- dict_avail: 0,
- first_call: true,
- has_flushed: false,
- data_format: DataFormat::Raw,
- last_status: TINFLStatus::NeedsMoreInput,
- }
- }
-}
-impl InflateState {
- /// Create a new state.
- ///
- /// Note that this struct is quite large due to internal buffers, and as such storing it on
- /// the stack is not recommended.
- ///
- /// # Parameters
- /// `data_format`: Determines whether the compressed data is assumed to wrapped with zlib
- /// metadata.
- pub fn new(data_format: DataFormat) -> InflateState {
- InflateState {
- data_format,
- ..Default::default()
- }
- }
-
- /// Create a new state on the heap.
- ///
- /// # Parameters
- /// `data_format`: Determines whether the compressed data is assumed to wrapped with zlib
- /// metadata.
- #[cfg(feature = "with-alloc")]
- pub fn new_boxed(data_format: DataFormat) -> Box<InflateState> {
- let mut b: Box<InflateState> = Box::default();
- b.data_format = data_format;
- b
- }
-
- /// Access the innner decompressor.
- pub fn decompressor(&mut self) -> &mut DecompressorOxide {
- &mut self.decomp
- }
-
- /// Return the status of the last call to `inflate` with this `InflateState`.
- pub const fn last_status(&self) -> TINFLStatus {
- self.last_status
- }
-
- /// Create a new state using miniz/zlib style window bits parameter.
- ///
- /// The decompressor does not support different window sizes. As such,
- /// any positive (>0) value will set the zlib header flag, while a negative one
- /// will not.
- #[cfg(feature = "with-alloc")]
- pub fn new_boxed_with_window_bits(window_bits: i32) -> Box<InflateState> {
- let mut b: Box<InflateState> = Box::default();
- b.data_format = DataFormat::from_window_bits(window_bits);
- b
- }
-
- #[inline]
- /// Reset the decompressor without re-allocating memory, using the given
- /// data format.
- pub fn reset(&mut self, data_format: DataFormat) {
- self.reset_as(FullReset(data_format));
- }
-
- #[inline]
- /// Resets the state according to specified policy.
- pub fn reset_as<T: ResetPolicy>(&mut self, policy: T) {
- policy.reset(self)
- }
-}
-
-/// Try to decompress from `input` to `output` with the given [`InflateState`]
-///
-/// # `flush`
-///
-/// Generally, the various [`MZFlush`] flags have meaning only on the compression side. They can be
-/// supplied here, but the only one that has any semantic meaning is [`MZFlush::Finish`], which is a
-/// signal that the stream is expected to finish, and failing to do so is an error. It isn't
-/// necessary to specify it when the stream ends; you'll still get returned a
-/// [`MZStatus::StreamEnd`] anyway. Other values either have no effect or cause errors. It's
-/// likely that you'll almost always just want to use [`MZFlush::None`].
-///
-/// # Errors
-///
-/// Returns [`MZError::Buf`] if the size of the `output` slice is empty or no progress was made due
-/// to lack of expected input data, or if called with [`MZFlush::Finish`] and input wasn't all
-/// consumed.
-///
-/// Returns [`MZError::Data`] if this or a a previous call failed with an error return from
-/// [`TINFLStatus`]; probably indicates corrupted data.
-///
-/// Returns [`MZError::Stream`] when called with [`MZFlush::Full`] (meaningless on
-/// decompression), or when called without [`MZFlush::Finish`] after an earlier call with
-/// [`MZFlush::Finish`] has been made.
-pub fn inflate(
- state: &mut InflateState,
- input: &[u8],
- output: &mut [u8],
- flush: MZFlush,
-) -> StreamResult {
- let mut bytes_consumed = 0;
- let mut bytes_written = 0;
- let mut next_in = input;
- let mut next_out = output;
-
- if flush == MZFlush::Full {
- return StreamResult::error(MZError::Stream);
- }
-
- let mut decomp_flags = if state.data_format == DataFormat::Zlib {
- inflate_flags::TINFL_FLAG_COMPUTE_ADLER32
- } else {
- inflate_flags::TINFL_FLAG_IGNORE_ADLER32
- };
-
- if (state.data_format == DataFormat::Zlib)
- | (state.data_format == DataFormat::ZLibIgnoreChecksum)
- {
- decomp_flags |= inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER;
- }
-
- let first_call = state.first_call;
- state.first_call = false;
- if (state.last_status as i32) < 0 {
- return StreamResult::error(MZError::Data);
- }
-
- if state.has_flushed && (flush != MZFlush::Finish) {
- return StreamResult::error(MZError::Stream);
- }
- state.has_flushed |= flush == MZFlush::Finish;
-
- if (flush == MZFlush::Finish) && first_call {
- decomp_flags |= inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
-
- let status = decompress(&mut state.decomp, next_in, next_out, 0, decomp_flags);
- let in_bytes = status.1;
- let out_bytes = status.2;
- let status = status.0;
-
- state.last_status = status;
-
- bytes_consumed += in_bytes;
- bytes_written += out_bytes;
-
- let ret_status = {
- if (status as i32) < 0 {
- Err(MZError::Data)
- } else if status != TINFLStatus::Done {
- state.last_status = TINFLStatus::Failed;
- Err(MZError::Buf)
- } else {
- Ok(MZStatus::StreamEnd)
- }
- };
- return StreamResult {
- bytes_consumed,
- bytes_written,
- status: ret_status,
- };
- }
-
- if flush != MZFlush::Finish {
- decomp_flags |= inflate_flags::TINFL_FLAG_HAS_MORE_INPUT;
- }
-
- if state.dict_avail != 0 {
- bytes_written += push_dict_out(state, &mut next_out);
- return StreamResult {
- bytes_consumed,
- bytes_written,
- status: Ok(
- if (state.last_status == TINFLStatus::Done) && (state.dict_avail == 0) {
- MZStatus::StreamEnd
- } else {
- MZStatus::Ok
- },
- ),
- };
- }
-
- let status = inflate_loop(
- state,
- &mut next_in,
- &mut next_out,
- &mut bytes_consumed,
- &mut bytes_written,
- decomp_flags,
- flush,
- );
- StreamResult {
- bytes_consumed,
- bytes_written,
- status,
- }
-}
-
-fn inflate_loop(
- state: &mut InflateState,
- next_in: &mut &[u8],
- next_out: &mut &mut [u8],
- total_in: &mut usize,
- total_out: &mut usize,
- decomp_flags: u32,
- flush: MZFlush,
-) -> MZResult {
- let orig_in_len = next_in.len();
- loop {
- let status = decompress(
- &mut state.decomp,
- *next_in,
- &mut state.dict,
- state.dict_ofs,
- decomp_flags,
- );
-
- let in_bytes = status.1;
- let out_bytes = status.2;
- let status = status.0;
-
- state.last_status = status;
-
- *next_in = &next_in[in_bytes..];
- *total_in += in_bytes;
-
- state.dict_avail = out_bytes;
- *total_out += push_dict_out(state, next_out);
-
- // The stream was corrupted, and decompression failed.
- if (status as i32) < 0 {
- return Err(MZError::Data);
- }
-
- // The decompressor has flushed all it's data and is waiting for more input, but
- // there was no more input provided.
- if (status == TINFLStatus::NeedsMoreInput) && orig_in_len == 0 {
- return Err(MZError::Buf);
- }
-
- if flush == MZFlush::Finish {
- if status == TINFLStatus::Done {
- // There is not enough space in the output buffer to flush the remaining
- // decompressed data in the internal buffer.
- return if state.dict_avail != 0 {
- Err(MZError::Buf)
- } else {
- Ok(MZStatus::StreamEnd)
- };
- // No more space in the output buffer, but we're not done.
- } else if next_out.is_empty() {
- return Err(MZError::Buf);
- }
- } else {
- // We're not expected to finish, so it's fine if we can't flush everything yet.
- let empty_buf = next_in.is_empty() || next_out.is_empty();
- if (status == TINFLStatus::Done) || empty_buf || (state.dict_avail != 0) {
- return if (status == TINFLStatus::Done) && (state.dict_avail == 0) {
- // No more data left, we're done.
- Ok(MZStatus::StreamEnd)
- } else {
- // Ok for now, still waiting for more input data or output space.
- Ok(MZStatus::Ok)
- };
- }
- }
- }
-}
-
-fn push_dict_out(state: &mut InflateState, next_out: &mut &mut [u8]) -> usize {
- let n = cmp::min(state.dict_avail as usize, next_out.len());
- (next_out[..n]).copy_from_slice(&state.dict[state.dict_ofs..state.dict_ofs + n]);
- *next_out = &mut mem::take(next_out)[n..];
- state.dict_avail -= n;
- state.dict_ofs = (state.dict_ofs + (n)) & (TINFL_LZ_DICT_SIZE - 1);
- n
-}
-
-#[cfg(test)]
-mod test {
- use super::{inflate, InflateState};
- use crate::{DataFormat, MZFlush, MZStatus};
- use alloc::vec;
-
- #[test]
- fn test_state() {
- let encoded = [
- 120u8, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4,
- 19,
- ];
- let mut out = vec![0; 50];
- let mut state = InflateState::new_boxed(DataFormat::Zlib);
- let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish);
- let status = res.status.expect("Failed to decompress!");
- assert_eq!(status, MZStatus::StreamEnd);
- assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]);
- assert_eq!(res.bytes_consumed, encoded.len());
-
- state.reset_as(super::ZeroReset);
- out.iter_mut().map(|x| *x = 0).count();
- let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish);
- let status = res.status.expect("Failed to decompress!");
- assert_eq!(status, MZStatus::StreamEnd);
- assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]);
- assert_eq!(res.bytes_consumed, encoded.len());
-
- state.reset_as(super::MinReset);
- out.iter_mut().map(|x| *x = 0).count();
- let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish);
- let status = res.status.expect("Failed to decompress!");
- assert_eq!(status, MZStatus::StreamEnd);
- assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]);
- assert_eq!(res.bytes_consumed, encoded.len());
- assert_eq!(state.decompressor().adler32(), Some(459605011));
-
- // Test state when not computing adler.
- state = InflateState::new_boxed(DataFormat::ZLibIgnoreChecksum);
- out.iter_mut().map(|x| *x = 0).count();
- let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish);
- let status = res.status.expect("Failed to decompress!");
- assert_eq!(status, MZStatus::StreamEnd);
- assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]);
- assert_eq!(res.bytes_consumed, encoded.len());
- // Not computed, so should be Some(1)
- assert_eq!(state.decompressor().adler32(), Some(1));
- // Should still have the checksum read from the header file.
- assert_eq!(state.decompressor().adler32_header(), Some(459605011))
- }
-}