Skip to content
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
105 changes: 105 additions & 0 deletions test-libz-rs-sys/examples/gix-blame.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use libz_sys as libz_ng_sys;

fn iter_files() -> impl Iterator<Item = &'static [u8]> {
static DATA: &[u8] = include_bytes!("../src/test-data/gix-blame-readme.bin");

let mut cursor = DATA;

std::iter::from_fn(move || {
let [a, b, c, d, rest @ ..] = cursor else {
return None;
};

let length = u32::from_le_bytes([*a, *b, *c, *d]) as usize;

let (input, rest) = rest.split_at(length);

cursor = rest;

Some(input)
})
}

fn main() {
match std::env::args().nth(1).unwrap().as_str() {
"ng" => {
for _ in 0..100 {
decompress_files_ng(iter_files());
}
}
"rs" => {
for _ in 0..100 {
decompress_files_rs(iter_files());
}
}
other => panic!("invalid variant: {other}"),
}
}

fn decompress_files_rs<'a>(inputs: impl Iterator<Item = &'a [u8]>) {
use libz_rs_sys::*;

let mut outbuf = vec![0u8; 1 << 20];

unsafe {
let mut stream = std::mem::MaybeUninit::zeroed();
let ret = inflateInit2_(
stream.as_mut_ptr(),
15, // windowBits = 15 (default)
zlibVersion(),
std::mem::size_of::<z_stream>() as i32,
);
assert_eq!(ret, Z_OK);
let stream = stream.assume_init_mut();

for input in inputs {
stream.next_in = input.as_ptr() as *mut u8;
stream.avail_in = input.len() as u32;
stream.next_out = outbuf.as_mut_ptr();
stream.avail_out = outbuf.len() as u32;

let ret = inflate(stream, Z_NO_FLUSH);
assert!(ret == Z_STREAM_END || ret == Z_OK);

// Reset stream for next input
let ret = inflateReset(stream);
assert_eq!(ret, Z_OK);
}

inflateEnd(stream);
}
}

fn decompress_files_ng<'a>(inputs: impl Iterator<Item = &'a [u8]>) {
use libz_ng_sys::*;

let mut outbuf = vec![0u8; 1 << 20];

unsafe {
let mut stream = std::mem::MaybeUninit::zeroed();
let ret = inflateInit2_(
stream.as_mut_ptr(),
15, // windowBits = 15 (default)
zlibVersion(),
std::mem::size_of::<z_stream>() as i32,
);
assert_eq!(ret, Z_OK);
let stream = stream.assume_init_mut();

for input in inputs {
stream.next_in = input.as_ptr() as *mut u8;
stream.avail_in = input.len() as u32;
stream.next_out = outbuf.as_mut_ptr();
stream.avail_out = outbuf.len() as u32;

let _ret = inflate(stream, Z_FINISH);
// assert!(ret == Z_STREAM_END || ret == Z_OK,);

// Reset stream for next input
let ret = inflateReset(stream);
assert_eq!(ret, Z_OK);
}

inflateEnd(stream);
}
}
Binary file not shown.
67 changes: 25 additions & 42 deletions zlib-rs/src/inflate/inftrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,6 @@ pub(crate) enum CodeType {

const MAX_BITS: usize = 15;

fn min_max<const N: usize>(count: [u16; N]) -> (usize, usize) {
let mut max = MAX_BITS;
while max >= 1 {
if count[max] != 0 {
break;
}
max -= 1;
}

let mut min = 1;
while min < max {
if count[min] != 0 {
break;
}
min += 1;
}

(min, max)
}

/// Length codes 257..285 base
const LBASE: [u16; 31] = [
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131,
Expand Down Expand Up @@ -70,16 +50,15 @@ pub(crate) fn inflate_table(
// number of codes of each length
let mut count = [0u16; MAX_BITS + 1];

for len in lens[0..codes].iter().copied() {
count[len as usize] += 1;
let (mut min, mut max) = (MAX_BITS, 0);
for &len in &lens[0..codes] {
if len > 0 {
count[len as usize] += 1;
max = Ord::max(max, usize::from(len));
min = Ord::min(min, usize::from(len));
}
}

let mut root = bits;

let (min, max) = min_max(count);
root = Ord::min(root, max);
root = Ord::max(root, min);

if max == 0 {
// no symbols to code at all
let code = Code {
Expand All @@ -94,17 +73,16 @@ pub(crate) fn inflate_table(
return InflateTable::Success { root: 1, used: 2 };
}

// NOTE: if max != 0, then min has been set to a value <= max.
let root = bits.clamp(min, max);

/* check for an over-subscribed or incomplete set of lengths */
let mut left = 1i32;
let mut len = 1;
while len <= MAX_BITS {
left <<= 1;
left -= count[len] as i32;
if left < 0 {
// over-subscribed
return InflateTable::InvalidCode;
}
len += 1;
let mut left = 1u32;
for &sym in &count[1..] {
left = match (left << 1).checked_sub(u32::from(sym)) {
None => return InflateTable::InvalidCode, // over-subscribed
Some(v) => v,
};
}

if left > 0 && (matches!(codetype, CodeType::Codes) || max != 1) {
Expand Down Expand Up @@ -181,11 +159,16 @@ pub(crate) fn inflate_table(

// replicate for those indices with low len bits equal to huff
let incr = 1 << (len - drop_);
let min = 1 << curr; // also has the name 'fill' in the C code
let mut fill = 1 << curr;
let min = fill;

let base = &mut table[next + (huff >> drop_)..];
for fill in (0..min).step_by(incr) {
base[fill] = here;
loop {
fill -= incr;
table[next + (huff >> drop_) + fill] = here;

if fill == 0 {
break;
}
}

// backwards increment the len-bit code huff
Expand Down