Skip to content

Commit 78460f8

Browse files
authored
Remove end_of_input argument to Decompressor::read (#59)
1 parent aa74a06 commit 78460f8

File tree

7 files changed

+43
-63
lines changed

7 files changed

+43
-63
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ categories = ["compression"]
2121
simd-adler32 = "0.3.4"
2222

2323
[dev-dependencies]
24-
miniz_oxide = "0.7.1"
24+
miniz_oxide = "0.8.9"
2525
rand = "0.8.5"
2626

2727
[lints.rust]

fuzz/fuzz_targets/inflate_bytewise.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ fuzz_target!(|input: (u8, Vec<u8>)| {
2828
&compressed[input_index..],
2929
&mut decompressed,
3030
output_position,
31-
true,
3231
)
3332
.expect("Decompression failed!");
3433

fuzz/fuzz_targets/inflate_bytewise2.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ fuzz_target!(|input: (u8, Vec<u8>)| {
2626
&compressed[input_index..input_index + 1],
2727
&mut decompressed,
2828
output_position,
29-
false,
3029
)
3130
.expect("Decompression failed!");
3231

fuzz/fuzz_targets/inflate_bytewise3.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ mod test_utils;
1111
use test_utils::decompress_by_chunks;
1212

1313
fuzz_target!(|input: &[u8]| {
14-
let r_whole = decompress_by_chunks(input, std::iter::repeat(input.len()), false);
15-
let r_bytewise = decompress_by_chunks(input, std::iter::repeat(1), false);
14+
let r_whole = decompress_by_chunks(input, std::iter::repeat(input.len()));
15+
let r_bytewise = decompress_by_chunks(input, std::iter::repeat(1));
1616
match (r_whole, r_bytewise) {
1717
(Ok(output_whole), Ok(output_bytewise)) => assert_eq!(output_whole, output_bytewise),
1818
(Err(_e1), Err(_e2)) => (),

fuzz/fuzz_targets/inflate_split.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fuzz_target!(|input: (Vec<u8>, Vec<u8>)| {
1919
while !decoder.is_done() && input_index < input.0.len() {
2020
// println!("input_index: {} {}", input_index, input.0.len());
2121
let (consumed, produced) =
22-
decoder.read(&input.0[input_index..], &mut output, output_index, false)?;
22+
decoder.read(&input.0[input_index..], &mut output, output_index)?;
2323
input_index += consumed;
2424
output_index += produced;
2525
if output_index == output.len() {
@@ -32,8 +32,12 @@ fuzz_target!(|input: (Vec<u8>, Vec<u8>)| {
3232
&input.1[input_index - input.0.len()..],
3333
&mut output,
3434
output_index,
35-
true,
3635
)?;
36+
37+
if !decoder.is_done() && consumed == 0 && produced == 0 {
38+
return Err(fdeflate::DecompressionError::InsufficientInput);
39+
}
40+
3741
input_index += consumed;
3842
output_index += produced;
3943
output.resize(output_index + 32 * 1024, 0);

src/decompress.rs

Lines changed: 33 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ impl Decompressor {
160160
/// Returns the number of bytes read from `input` and the number of bytes written to `output`,
161161
/// or an error if the deflate stream is not valid. `input` is the compressed data. `output` is
162162
/// the buffer to write the decompressed data to, starting at index `output_position`.
163-
/// `end_of_input` indicates whether more data may be available in the future.
164163
///
165164
/// The contents of `output` after `output_position` are ignored. However, this function may
166165
/// write additional data to `output` past what is indicated by the return value.
@@ -170,6 +169,10 @@ impl Decompressor {
170169
/// - The output is full but there are more bytes to output.
171170
/// - The deflate stream is complete (and `is_done` will return true).
172171
///
172+
/// To detect whether the zlib stream was truncated before the final checksum, call the
173+
/// `is_done` method after all input data has been consumed and no more data is written. If it returns false, then the
174+
/// stream was truncated.
175+
///
173176
/// # Panics
174177
///
175178
/// This function will panic if `output_position` is out of bounds.
@@ -178,7 +181,6 @@ impl Decompressor {
178181
input: &[u8],
179182
output: &mut [u8],
180183
output_position: usize,
181-
end_of_input: bool,
182184
) -> Result<(usize, usize), DecompressionError> {
183185
if let State::Done = self.state {
184186
return Ok((0, 0));
@@ -330,12 +332,8 @@ impl Decompressor {
330332
self.checksum.write(&output[output_position..output_index]);
331333
}
332334

333-
if self.state == State::Done || !end_of_input || output_index == output.len() {
334-
let input_left = remaining_input.len();
335-
Ok((input.len() - input_left, output_index - output_position))
336-
} else {
337-
Err(DecompressionError::InsufficientInput)
338-
}
335+
let input_left = remaining_input.len();
336+
Ok((input.len() - input_left, output_index - output_position))
339337
}
340338

341339
/// Returns true if the decompressor has finished decompressing the input.
@@ -1118,25 +1116,31 @@ pub fn decompress_to_vec_bounded(
11181116
let mut output = vec![0; 1024.min(maxlen)];
11191117
let mut input_index = 0;
11201118
let mut output_index = 0;
1119+
11211120
loop {
11221121
let (consumed, produced) =
1123-
decoder.read(&input[input_index..], &mut output, output_index, true)?;
1122+
decoder.read(&input[input_index..], &mut output, output_index)?;
11241123
input_index += consumed;
11251124
output_index += produced;
1126-
if decoder.is_done() || output_index == maxlen {
1125+
1126+
if decoder.is_done() {
11271127
break;
1128+
} else if output_index == maxlen {
1129+
return Err(BoundedDecompressionError::OutputTooLarge {
1130+
partial_output: output,
1131+
});
1132+
} else if output_index == output.len() {
1133+
output.resize((output_index + 32 * 1024).min(maxlen), 0);
1134+
continue;
1135+
} else if input_index == input.len() {
1136+
return Err(DecompressionError::InsufficientInput.into());
1137+
} else {
1138+
unreachable!("Read() call violated post-condition");
11281139
}
1129-
output.resize((output_index + 32 * 1024).min(maxlen), 0);
11301140
}
1131-
output.resize(output_index, 0);
11321141

1133-
if decoder.is_done() {
1134-
Ok(output)
1135-
} else {
1136-
Err(BoundedDecompressionError::OutputTooLarge {
1137-
partial_output: output,
1138-
})
1139-
}
1142+
output.resize(output_index, 0);
1143+
Ok(output)
11401144
}
11411145

11421146
#[cfg(test)]
@@ -1269,7 +1273,7 @@ mod tests {
12691273
decompressor.ignore_adler32();
12701274
let mut decompressed = vec![0; 1024];
12711275
let decompressed_len = decompressor
1272-
.read(&compressed, &mut decompressed, 0, true)
1276+
.read(&compressed, &mut decompressed, 0)
12731277
.unwrap()
12741278
.1;
12751279
assert_eq!(&decompressed[..decompressed_len], b"Hello world!");
@@ -1283,12 +1287,7 @@ mod tests {
12831287
let mut decompressor = Decompressor::new();
12841288
let mut decompressed = vec![0; 1024];
12851289
let (input_consumed, output_written) = decompressor
1286-
.read(
1287-
&compressed[..compressed.len() - 1],
1288-
&mut decompressed,
1289-
0,
1290-
false,
1291-
)
1290+
.read(&compressed[..compressed.len() - 1], &mut decompressed, 0)
12921291
.unwrap();
12931292
assert_eq!(output_written, input.len());
12941293
assert_eq!(input_consumed, compressed.len() - 1);
@@ -1298,7 +1297,6 @@ mod tests {
12981297
&compressed[input_consumed..],
12991298
&mut decompressed[..output_written],
13001299
output_written,
1301-
true,
13021300
)
13031301
.unwrap();
13041302
assert!(decompressor.is_done());
@@ -1318,18 +1316,12 @@ mod tests {
13181316
compressed.splice(2..2, [0u8, 0, 0, 0xff, 0xff].into_iter());
13191317
}
13201318

1321-
// Ensure that the full input is decompressed, regardless of whether
1322-
// `end_of_input` is set.
1323-
for end_of_input in [true, false] {
1324-
let mut decompressor = Decompressor::new();
1325-
let (input_consumed, output_written) = decompressor
1326-
.read(&compressed, &mut [], 0, end_of_input)
1327-
.unwrap();
1328-
1329-
assert!(decompressor.is_done());
1330-
assert_eq!(input_consumed, compressed.len());
1331-
assert_eq!(output_written, 0);
1332-
}
1319+
let mut decompressor = Decompressor::new();
1320+
let (input_consumed, output_written) = decompressor.read(&compressed, &mut [], 0).unwrap();
1321+
1322+
assert!(decompressor.is_done());
1323+
assert_eq!(input_consumed, compressed.len());
1324+
assert_eq!(output_written, 0);
13331325
}
13341326

13351327
mod test_utils;
@@ -1339,8 +1331,8 @@ mod tests {
13391331
fn verify_no_sensitivity_to_input_chunking(
13401332
input: &[u8],
13411333
) -> Result<Vec<u8>, TestDecompressionError> {
1342-
let r_whole = decompress_by_chunks(input, vec![input.len()], false);
1343-
let r_bytewise = decompress_by_chunks(input, std::iter::repeat(1), false);
1334+
let r_whole = decompress_by_chunks(input, vec![input.len()]);
1335+
let r_bytewise = decompress_by_chunks(input, std::iter::repeat(1));
13441336
assert_eq!(r_whole, r_bytewise);
13451337
r_whole // Returning an arbitrary result, since this is equal to `r_bytewise`.
13461338
}

src/decompress/tests/test_utils.rs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,12 @@ impl From<TestErrorKind> for TestDecompressionError {
4141
/// But `chunks` can also be used to replicate arbitrary chunking patterns (such as may be
4242
/// used by some fuzzing-based repros from the `png` crate).
4343
///
44-
/// `early_eof` is used to the last `end_of_input` argument of `Decompressor::read` calls.
45-
/// When `early_eof` is `false`, then `end_of_input` is `false` until the whole input is
46-
/// consumed (and then is `Decompressor::is_done` is still false, then `Decompressor::read`
47-
/// is called one or more times with empty input slice and `end_of_input` set to true).
48-
/// When `early_eof` is `true` then `end_of_input` is set to `true` as soon as the slice
49-
/// fed to `Decompressor::read` "reaches" the end of the whole input.
50-
///
5144
/// Unlike the `png` crate, this testing helper uses a big, fixed-size output buffer.
5245
/// (i.e. there is no simulation of `ZlibStream.compact_out_buffer_if_needed` from the `png`
5346
/// crate).
5447
pub fn decompress_by_chunks(
5548
input: &[u8],
5649
chunks: impl IntoIterator<Item = usize>,
57-
early_eof: bool,
5850
) -> Result<Vec<u8>, TestDecompressionError> {
5951
let mut chunks = chunks.into_iter();
6052

@@ -80,14 +72,8 @@ pub fn decompress_by_chunks(
8072
let start = in_pos;
8173
let end = std::cmp::min(start + chunk_size, input.len());
8274

83-
let eof = if early_eof {
84-
end == input.len()
85-
} else {
86-
start == input.len()
87-
};
88-
8975
let (in_consumed, out_written) =
90-
d.read(&input[start..end], out_buf.as_mut_slice(), out_pos, eof)?;
76+
d.read(&input[start..end], out_buf.as_mut_slice(), out_pos)?;
9177

9278
in_pos += in_consumed;
9379
out_pos += out_written;

0 commit comments

Comments
 (0)