Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Derive Clone for InflateState to allow random-access reads #157

Merged
merged 1 commit into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions miniz_oxide/src/inflate/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use self::output_buffer::OutputBuffer;
pub const TINFL_LZ_DICT_SIZE: usize = 32_768;

/// A struct containing huffman code lengths and the huffman code tree used by the decompressor.
#[derive(Clone)]
struct HuffmanTable {
/// Length of the code at each index.
pub code_size: [u8; MAX_HUFF_SYMBOLS_0],
Expand Down Expand Up @@ -166,6 +167,7 @@ type BitBuffer = u32;

/// Main decompression struct.
///
#[derive(Clone)]
pub struct DecompressorOxide {
/// Current state of the decompressor.
state: core::State,
Expand Down
64 changes: 64 additions & 0 deletions miniz_oxide/src/inflate/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ impl ResetPolicy for FullReset {

/// A struct that compbines a decompressor with extra data for streaming decompression.
///
#[derive(Clone)]
pub struct InflateState {
/// Inner decompressor struct
decomp: DecompressorOxide,
Expand Down Expand Up @@ -420,4 +421,67 @@ mod test {
// Should still have the checksum read from the header file.
assert_eq!(state.decompressor().adler32_header(), Some(459605011))
}

#[test]
fn test_partial_continue() {
let encoded = [
120u8, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4,
19,
];

// Feed input bytes one at a time to the decompressor
let mut out = vec![0; 50];
let mut state = InflateState::new_boxed(DataFormat::Zlib);
let mut part_in = 0;
let mut part_out = 0;
for i in 1..=encoded.len() {
let res = inflate(&mut state, &encoded[part_in..i], &mut out[part_out..], MZFlush::None);
let status = res.status.expect("Failed to decompress!");
if i == encoded.len() {
assert_eq!(status, MZStatus::StreamEnd);
} else {
assert_eq!(status, MZStatus::Ok);
}
part_out += res.bytes_written as usize;
part_in += res.bytes_consumed;
}

assert_eq!(out[..part_out as usize], b"Hello, zlib!"[..]);
assert_eq!(part_in, encoded.len());
assert_eq!(state.decompressor().adler32(), Some(459605011));
}


// Inflate part of a stream and clone the inflate state.
// Discard the original state and resume the stream from the clone.
#[test]
fn test_rewind_and_resume() {
let encoded = [
120u8, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4,
19,
];
let decoded = b"Hello, zlib!";

// Feed partial input bytes to the decompressor
let mut out = vec![0; 50];
let mut state = InflateState::new_boxed(DataFormat::Zlib);
let res1 = inflate(&mut state, &encoded[..10], &mut out, MZFlush::None);
let status = res1.status.expect("Failed to decompress!");
assert_eq!(status, MZStatus::Ok);

// Clone the state and discard the original
let mut resume = state.clone();
drop(state);

// Resume the stream using the cloned state
let res2 = inflate(&mut resume, &encoded[res1.bytes_consumed..], &mut out[res1.bytes_written..], MZFlush::Finish);
let status = res2.status.expect("Failed to decompress!");
assert_eq!(status, MZStatus::StreamEnd);

assert_eq!(res1.bytes_consumed + res2.bytes_consumed, encoded.len());
assert_eq!(res1.bytes_written + res2.bytes_written, decoded.len());
assert_eq!(&out[..res1.bytes_written + res2.bytes_written as usize], decoded);
assert_eq!(resume.decompressor().adler32(), Some(459605011));
}

}
Loading