Skip to content

Commit b75f68c

Browse files
committed
track and expose the number of codes used
1 parent d0559d8 commit b75f68c

11 files changed

+98
-13
lines changed

libz-rs-sys/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -908,8 +908,11 @@ pub unsafe extern "C-unwind" fn inflateResetKeep(strm: *mut z_stream) -> c_int {
908908
/// - `buf` is `NULL`
909909
/// - `buf` and `len` satisfy the requirements of [`core::slice::from_raw_parts`]
910910
#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateCodesUsed))]
911-
pub unsafe extern "C-unwind" fn inflateCodesUsed(_strm: *mut z_stream) -> c_ulong {
912-
todo!()
911+
pub unsafe extern "C-unwind" fn inflateCodesUsed(strm: *mut z_stream) -> c_ulong {
912+
match InflateStream::from_stream_mut(strm) {
913+
Some(stream) => zlib_rs::inflate::codes_used(stream) as c_ulong,
914+
None => c_ulong::MAX,
915+
}
913916
}
914917

915918
/// Compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full.

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

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2209,3 +2209,73 @@ fn blow_up_the_stack_2() {
22092209
let (_, err) = uncompress_slice(&mut output_rs, INPUT, config);
22102210
assert_eq!(err, ReturnCode::DataError);
22112211
}
2212+
2213+
#[test]
2214+
fn codes_used() {
2215+
// -1 is returned on NULL
2216+
assert_eq_rs_ng!({ inflateCodesUsed(core::ptr::null_mut()) });
2217+
assert_eq!(
2218+
unsafe { libz_rs_sys::inflateCodesUsed(core::ptr::null_mut()) },
2219+
c_ulong::MAX
2220+
);
2221+
2222+
let inputs = &[
2223+
include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-0.gz")
2224+
.as_slice(),
2225+
include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-9.gz")
2226+
.as_slice(),
2227+
include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-filtered-9.gz")
2228+
.as_slice(),
2229+
include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-fixed-9.gz")
2230+
.as_slice(),
2231+
include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-huffman-9.gz")
2232+
.as_slice(),
2233+
include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-rle-9.gz")
2234+
.as_slice(),
2235+
];
2236+
2237+
for input in inputs {
2238+
assert_eq_rs_ng!({
2239+
let mut output: Vec<u8> = vec![0u8; 1 << 15];
2240+
let mut codes_used = Vec::new();
2241+
2242+
let mut stream = MaybeUninit::<z_stream>::zeroed();
2243+
2244+
let err = unsafe {
2245+
inflateInit2_(
2246+
stream.as_mut_ptr(),
2247+
16 + 15,
2248+
zlibVersion(),
2249+
core::mem::size_of::<z_stream>() as c_int,
2250+
)
2251+
};
2252+
assert_eq!(ReturnCode::from(err), ReturnCode::Ok);
2253+
2254+
let stream = unsafe { stream.assume_init_mut() };
2255+
codes_used.push(inflateCodesUsed(stream));
2256+
2257+
stream.next_out = output.as_mut_ptr();
2258+
stream.avail_out = output.len() as _;
2259+
2260+
for chunk in input.chunks(16) {
2261+
stream.next_in = chunk.as_ptr().cast_mut();
2262+
stream.avail_in = chunk.len() as _;
2263+
2264+
let err = unsafe { inflate(stream, InflateFlush::NoFlush as _) };
2265+
codes_used.push(inflateCodesUsed(stream));
2266+
2267+
if err == ReturnCode::StreamEnd as i32 {
2268+
break;
2269+
}
2270+
2271+
assert_eq!(err, ReturnCode::Ok as i32);
2272+
}
2273+
2274+
let err = inflateEnd(stream);
2275+
assert_eq!(ReturnCode::from(err), ReturnCode::Ok);
2276+
2277+
output.truncate(stream.total_out as usize);
2278+
(output, codes_used)
2279+
});
2280+
}
2281+
}

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
#[cfg(test)]
22
mod deflate;
33
pub mod end_to_end;
4+
#[cfg(test)]
5+
#[cfg(feature = "gz")]
6+
mod gz;
47
mod helpers;
58
#[cfg(test)]
69
mod inflate;
710
#[cfg(test)]
811
mod zlib_ng_cve;
9-
#[cfg(test)]
10-
#[cfg(feature = "gz")]
11-
mod gz;
1212

1313
#[cfg(test)]
1414
#[macro_export]
@@ -21,6 +21,12 @@ macro_rules! assert_eq_rs_ng {
2121
let _ng = unsafe {
2222
use libz_sys::*;
2323

24+
// this function is not exposed by `libz_sys`
25+
extern "C" {
26+
#[allow(unused)]
27+
fn inflateCodesUsed(strm: *mut z_stream) -> core::ffi::c_ulong;
28+
}
29+
2430
$tt
2531
};
2632

zlib-rs/src/inflate.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,7 +1587,7 @@ impl State<'_> {
15871587
self.have += 1;
15881588
}
15891589

1590-
let InflateTable::Success(root) = inflate_table(
1590+
let InflateTable::Success { root, used } = inflate_table(
15911591
CodeType::Codes,
15921592
&self.lens,
15931593
19,
@@ -1599,6 +1599,7 @@ impl State<'_> {
15991599
break 'label self.bad("invalid code lengths set\0");
16001600
};
16011601

1602+
self.next = used;
16021603
self.len_table.codes = Codes::Codes;
16031604
self.len_table.bits = root;
16041605

@@ -1685,7 +1686,7 @@ impl State<'_> {
16851686

16861687
// build code tables
16871688

1688-
let InflateTable::Success(root) = inflate_table(
1689+
let InflateTable::Success { root, used } = inflate_table(
16891690
CodeType::Lens,
16901691
&self.lens,
16911692
self.nlen,
@@ -1699,8 +1700,9 @@ impl State<'_> {
16991700

17001701
self.len_table.codes = Codes::Len;
17011702
self.len_table.bits = root;
1703+
self.next = used;
17021704

1703-
let InflateTable::Success(root) = inflate_table(
1705+
let InflateTable::Success { root, used } = inflate_table(
17041706
CodeType::Dists,
17051707
&self.lens[self.nlen..],
17061708
self.ndist,
@@ -1714,6 +1716,7 @@ impl State<'_> {
17141716

17151717
self.dist_table.bits = root;
17161718
self.dist_table.codes = Codes::Dist;
1719+
self.next += used;
17171720

17181721
mode = Mode::Len_;
17191722

@@ -2215,6 +2218,10 @@ pub fn reset_keep(stream: &mut InflateStream) -> ReturnCode {
22152218
ReturnCode::Ok
22162219
}
22172220

2221+
pub fn codes_used(stream: &InflateStream) -> usize {
2222+
stream.state.next
2223+
}
2224+
22182225
pub unsafe fn inflate(stream: &mut InflateStream, flush: InflateFlush) -> ReturnCode {
22192226
if stream.next_out.is_null() || (stream.next_in.is_null() && stream.avail_in != 0) {
22202227
return ReturnCode::StreamError as _;

0 commit comments

Comments
 (0)