Skip to content

Commit 1f95a16

Browse files
authored
Introduce reset policy to control InflateState::reset (#91)
* Introduce reset policy to control InflateState::reset * Update comments per request
1 parent f8c25f3 commit 1f95a16

File tree

1 file changed

+65
-9
lines changed

1 file changed

+65
-9
lines changed

miniz_oxide/src/inflate/stream.rs

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,52 @@ use crate::inflate::core::{decompress, inflate_flags, DecompressorOxide, TINFL_L
88
use crate::inflate::TINFLStatus;
99
use crate::{DataFormat, MZError, MZFlush, MZResult, MZStatus, StreamResult};
1010

11+
/// Tag that determines reset policy of [InflateState](struct.InflateState.html)
12+
pub trait ResetPolicy {
13+
/// Performs reset
14+
fn reset(&self, state: &mut InflateState);
15+
}
16+
17+
/// Resets state, without performing expensive ops (e.g. zeroing buffer)
18+
///
19+
/// Note that not zeroing buffer can lead to security issues when dealing with untrusted input.
20+
pub struct MinReset;
21+
22+
impl ResetPolicy for MinReset {
23+
fn reset(&self, state: &mut InflateState) {
24+
state.decompressor().init();
25+
state.dict_ofs = 0;
26+
state.dict_avail = 0;
27+
state.first_call = true;
28+
state.has_flushed = false;
29+
state.last_status = TINFLStatus::NeedsMoreInput;
30+
}
31+
}
32+
33+
/// Resets state and zero memory, continuing to use the same data format.
34+
pub struct ZeroReset;
35+
36+
impl ResetPolicy for ZeroReset {
37+
#[inline]
38+
fn reset(&self, state: &mut InflateState) {
39+
MinReset.reset(state);
40+
state.dict = [0; TINFL_LZ_DICT_SIZE];
41+
}
42+
}
43+
44+
/// Full reset of the state, including zeroing memory.
45+
///
46+
/// Requires to provide new data format.
47+
pub struct FullReset(DataFormat);
48+
49+
impl ResetPolicy for FullReset {
50+
#[inline]
51+
fn reset(&self, state: &mut InflateState) {
52+
ZeroReset.reset(state);
53+
state.data_format = self.0;
54+
}
55+
}
56+
1157
/// A struct that compbines a decompressor with extra data for streaming decompression.
1258
///
1359
pub struct InflateState {
@@ -95,17 +141,17 @@ impl InflateState {
95141
b
96142
}
97143

144+
#[inline]
98145
/// Reset the decompressor without re-allocating memory, using the given
99146
/// data format.
100147
pub fn reset(&mut self, data_format: DataFormat) {
101-
self.decompressor().init();
102-
self.dict = [0; TINFL_LZ_DICT_SIZE];
103-
self.dict_ofs = 0;
104-
self.dict_avail = 0;
105-
self.first_call = true;
106-
self.has_flushed = false;
107-
self.data_format = data_format;
108-
self.last_status = TINFLStatus::NeedsMoreInput;
148+
self.reset_as(FullReset(data_format));
149+
}
150+
151+
#[inline]
152+
/// Resets the state according to specified policy.
153+
pub fn reset_as<T: ResetPolicy>(&mut self, policy: T) {
154+
policy.reset(self)
109155
}
110156
}
111157

@@ -314,7 +360,17 @@ mod test {
314360
assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]);
315361
assert_eq!(res.bytes_consumed, encoded.len());
316362

317-
state.reset(DataFormat::Zlib);
363+
state.reset_as(super::ZeroReset);
364+
out.iter_mut().map(|x| *x = 0).count();
365+
let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish);
366+
let status = res.status.expect("Failed to decompress!");
367+
assert_eq!(status, MZStatus::StreamEnd);
368+
assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]);
369+
assert_eq!(res.bytes_consumed, encoded.len());
370+
371+
state.reset_as(super::MinReset);
372+
out.iter_mut().map(|x| *x = 0).count();
373+
let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish);
318374
let status = res.status.expect("Failed to decompress!");
319375
assert_eq!(status, MZStatus::StreamEnd);
320376
assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]);

0 commit comments

Comments
 (0)