Skip to content

Commit 32f9dd2

Browse files
committed
add copy continue test
1 parent 4c4df4a commit 32f9dd2

File tree

1 file changed

+118
-1
lines changed

1 file changed

+118
-1
lines changed

test-libz-rs-sys/src/inflate.rs

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,6 @@ fn inf(input: &[u8], _what: &str, step: usize, win: i32, len: usize, err: c_int)
349349

350350
if matches!(ret, Z_NEED_DICT) {
351351
let ret = unsafe { inflateSetDictionary(&mut stream, input.as_ptr(), 1) };
352-
println!("{ret:?}");
353352
assert_eq!(ret, Z_DATA_ERROR);
354353

355354
unsafe { set_mode_dict(&mut stream) }
@@ -2705,3 +2704,121 @@ fn cover_back() {
27052704
assert_eq!(ret, Z_OK);
27062705
}
27072706
}
2707+
2708+
#[test]
2709+
fn inflate_copy_after_half_input() {
2710+
let input = include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-9.gz");
2711+
2712+
let _ = assert_eq_rs_ng!({
2713+
let mut stream = MaybeUninit::<z_stream>::zeroed();
2714+
let ret = unsafe {
2715+
inflateInit2_(
2716+
stream.as_mut_ptr(),
2717+
16 + 15,
2718+
zlibVersion(),
2719+
core::mem::size_of::<z_stream>() as i32,
2720+
)
2721+
};
2722+
let stream = stream.assume_init_mut();
2723+
assert_eq!(ret, Z_OK);
2724+
2725+
let mut out = vec![0u8; 16 * 1024];
2726+
2727+
// First, decompress only the first half of the compressed input.
2728+
let half = input.len() / 2;
2729+
2730+
stream.next_in = input.as_ptr() as *mut _;
2731+
stream.avail_in = half as _;
2732+
stream.next_out = out.as_mut_ptr();
2733+
stream.avail_out = out.len() as _;
2734+
2735+
loop {
2736+
let ret = unsafe { inflate(stream, InflateFlush::NoFlush as _) };
2737+
2738+
assert!(
2739+
matches!(ret, Z_OK | Z_BUF_ERROR | Z_STREAM_END),
2740+
"unexpected inflate return: {}",
2741+
ret
2742+
);
2743+
2744+
if matches!(ret, Z_STREAM_END) {
2745+
unreachable!("we only provide half of the input")
2746+
}
2747+
2748+
if stream.avail_in == 0 {
2749+
break;
2750+
}
2751+
2752+
if stream.avail_out == 0 {
2753+
unreachable!("there is enough output space")
2754+
}
2755+
}
2756+
2757+
// At this point, we’ve decompressed part (or possibly all) of the stream.
2758+
let prefix_len = stream.total_out as usize;
2759+
2760+
// Make a copy of the inflate state *after* half the input has been processed.
2761+
let mut copy = MaybeUninit::<z_stream>::zeroed();
2762+
let ret = unsafe { inflateCopy(copy.as_mut_ptr(), stream) };
2763+
let copy = copy.assume_init_mut();
2764+
assert_eq!(ret, Z_OK);
2765+
2766+
// Prepare a separate output buffer for the copy, and copy the already-produced prefix
2767+
let mut out_copy = vec![0u8; 16 * 1024];
2768+
out_copy[..prefix_len].copy_from_slice(&out[..prefix_len]);
2769+
2770+
// The original stream already has next_out pointing at out[prefix_len].
2771+
// For the copy, we need to point it at the corresponding location in out_copy.
2772+
copy.next_out = unsafe { out_copy.as_mut_ptr().add(prefix_len) };
2773+
copy.avail_out = (out_copy.len() - prefix_len) as _;
2774+
2775+
// Now feed the *remainder* of the compressed input to both streams.
2776+
let remaining = input.len() - half;
2777+
if remaining > 0 {
2778+
stream.next_in = unsafe { input.as_ptr().add(half) as *mut _ };
2779+
stream.avail_in = remaining as _;
2780+
2781+
copy.next_in = stream.next_in;
2782+
copy.avail_in = stream.avail_in;
2783+
}
2784+
2785+
// Decompress the remainder in lockstep on both the original and the copy.
2786+
loop {
2787+
let ret1 = unsafe { inflate(stream, InflateFlush::NoFlush as _) };
2788+
let ret2 = unsafe { inflate(copy, InflateFlush::NoFlush as _) };
2789+
2790+
// Both streams should behave identically
2791+
assert_eq!(ret1, ret2);
2792+
assert!(
2793+
matches!(ret1, Z_OK | Z_BUF_ERROR | Z_STREAM_END),
2794+
"unexpected inflate return: {ret}",
2795+
);
2796+
2797+
// Their accounting should remain in sync at all times
2798+
assert_eq!(stream.total_out, copy.total_out);
2799+
assert_eq!(stream.total_in, copy.total_in);
2800+
2801+
if matches!(ret1, Z_STREAM_END) {
2802+
break;
2803+
}
2804+
2805+
// If we somehow run out of input or output space, bail
2806+
if stream.avail_in == 0 && copy.avail_in == 0 {
2807+
break;
2808+
}
2809+
if stream.avail_out == 0 || copy.avail_out == 0 {
2810+
break;
2811+
}
2812+
}
2813+
2814+
assert_eq!(unsafe { inflateEnd(stream) }, Z_OK);
2815+
assert_eq!(unsafe { inflateEnd(copy) }, Z_OK);
2816+
2817+
let total = stream.total_out as usize;
2818+
assert_eq!(total, copy.total_out as usize);
2819+
2820+
assert_eq!(&out[..total], &out_copy[..total]);
2821+
2822+
out[..total].to_vec()
2823+
});
2824+
}

0 commit comments

Comments
 (0)