Skip to content

Commit e83fcef

Browse files
folkertdevrnijveld
authored andcommitted
fix bug in the quick algorithm (Z_BEST_SPEED) where a block was closed where it should not be
1 parent 85bc778 commit e83fcef

File tree

3 files changed

+107
-5
lines changed

3 files changed

+107
-5
lines changed

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

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,3 +1344,105 @@ mod coverage {
13441344
});
13451345
}
13461346
}
1347+
1348+
#[test]
1349+
fn deflate_chunked_input_all_levels() {
1350+
use std::io::{Read, Write};
1351+
use std::mem::MaybeUninit;
1352+
1353+
assert_eq_rs_ng!({
1354+
// translated from zpipe.c
1355+
fn def<R: Read, W: Write, const CHUNK: usize>(
1356+
source: &mut R,
1357+
dest: &mut W,
1358+
level: i32,
1359+
) -> i32 {
1360+
let mut strm = MaybeUninit::zeroed();
1361+
1362+
let mut in_buf = [0u8; CHUNK];
1363+
let mut out_buf = [0u8; CHUNK];
1364+
1365+
let mut ret;
1366+
1367+
ret = unsafe {
1368+
deflateInit_(
1369+
strm.as_mut_ptr(),
1370+
level,
1371+
zlibVersion(),
1372+
core::mem::size_of::<z_stream>() as _,
1373+
)
1374+
};
1375+
if ret != Z_OK {
1376+
return ret;
1377+
}
1378+
1379+
let strm = unsafe { strm.assume_init_mut() };
1380+
1381+
loop {
1382+
strm.avail_in = match source.read(&mut in_buf) {
1383+
Ok(0) => 0,
1384+
Ok(n) => n as u32,
1385+
Err(_) => {
1386+
unsafe { deflateEnd(strm) };
1387+
return Z_ERRNO;
1388+
}
1389+
};
1390+
strm.next_in = in_buf.as_mut_ptr();
1391+
1392+
let flush = if strm.avail_in == 0 {
1393+
Z_FINISH
1394+
} else {
1395+
Z_NO_FLUSH
1396+
};
1397+
1398+
loop {
1399+
strm.avail_out = CHUNK as u32;
1400+
strm.next_out = out_buf.as_mut_ptr();
1401+
1402+
ret = unsafe { deflate(strm, flush) };
1403+
assert_ne!(ret, Z_STREAM_ERROR);
1404+
1405+
let have = CHUNK - strm.avail_out as usize;
1406+
if dest.write_all(&out_buf[..have]).is_err() {
1407+
unsafe { deflateEnd(strm) };
1408+
return Z_ERRNO;
1409+
}
1410+
1411+
if strm.avail_out != 0 {
1412+
break;
1413+
}
1414+
}
1415+
1416+
if flush == Z_FINISH {
1417+
break;
1418+
}
1419+
}
1420+
1421+
assert_eq!(ret, Z_STREAM_END);
1422+
1423+
unsafe { deflateEnd(strm) };
1424+
1425+
Z_OK
1426+
}
1427+
1428+
fn run<const CHUNK: usize>(level: i32) -> Vec<u8> {
1429+
let input: Vec<_> = (0..4096).map(|x| x as u8).collect();
1430+
let mut output = Vec::new();
1431+
1432+
def::<_, _, CHUNK>(&mut input.as_slice(), &mut output, level);
1433+
1434+
output
1435+
}
1436+
1437+
let mut outputs = Vec::new();
1438+
1439+
for level in -1..=9 {
1440+
outputs.push((level, 4, run::<{ 4 }>(level)));
1441+
outputs.push((level, 1 << 10, run::<{ 1 << 10 }>(level)));
1442+
outputs.push((level, 1 << 12, run::<{ 1 << 12 }>(level)));
1443+
outputs.push((level, 1 << 14, run::<{ 1 << 14 }>(level)));
1444+
}
1445+
1446+
outputs
1447+
});
1448+
}

zlib-rs/src/deflate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,7 @@ impl<'a> BitWriter<'a> {
10301030

10311031
#[cfg(feature = "ZLIB_DEBUG")]
10321032
if let Some(c) = char::from_u32(c as u32) {
1033-
if c.is_ascii() && !c.is_whitespace() {
1033+
if isgraph(c as u8) {
10341034
trace!(" '{}' ", c);
10351035
}
10361036
}

zlib-rs/src/deflate/algorithm/quick.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ pub fn deflate_quick(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockSt
2222
}
2323

2424
macro_rules! quick_end_block {
25-
() => {
25+
($last:expr) => {
2626
if state.block_open > 0 {
2727
state
2828
.bit_writer
29-
.emit_end_block_and_align(&StaticTreeDesc::L.static_tree, last);
29+
.emit_end_block_and_align(&StaticTreeDesc::L.static_tree, $last);
3030
state.block_open = 0;
3131
state.block_start = state.strstart as isize;
3232
flush_pending(stream);
@@ -46,7 +46,7 @@ pub fn deflate_quick(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockSt
4646

4747
if last && state.block_open != 2 {
4848
/* Emit end of previous block */
49-
quick_end_block!();
49+
quick_end_block!(false);
5050
/* Emit start of last block */
5151
quick_start_block!();
5252
} else if state.block_open == 0 && state.lookahead > 0 {
@@ -135,7 +135,7 @@ pub fn deflate_quick(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockSt
135135

136136
state.insert = Ord::min(state.strstart, STD_MIN_MATCH - 1);
137137

138-
quick_end_block!();
138+
quick_end_block!(last);
139139

140140
if last {
141141
BlockState::FinishDone

0 commit comments

Comments
 (0)