Skip to content

Commit

Permalink
fix(deflate): fix bug causing 0 length stored block to be output inco…
Browse files Browse the repository at this point in the history
…rrectly causing corrupt stream
  • Loading branch information
oyvindln committed Feb 21, 2025
1 parent 4c38ff8 commit 3d62e6b
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 5 deletions.
8 changes: 5 additions & 3 deletions miniz_oxide/src/deflate/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1639,7 +1639,7 @@ pub(crate) fn flush_block(
// Block header.
output.put_bits(0, 2);

// Block length has to start on a byte boundary, s opad.
// Block length has to start on a byte boundary, so pad.
output.pad_to_bytes();

// Block length and ones complement of block length.
Expand All @@ -1651,8 +1651,10 @@ pub(crate) fn flush_block(
let end = (d.dict.code_buf_dict_pos + d.lz.total_bytes as usize) & LZ_DICT_SIZE_MASK;
let dict = &mut d.dict.b.dict;
if start < end {
// The data does not wrap around.
output.write_bytes(&dict[start..end]);
} else {
} else if d.lz.total_bytes > 0 {
// The data wraps around and the input was not 0 bytes.
output.write_bytes(&dict[start..LZ_DICT_SIZE]);
output.write_bytes(&dict[..end]);
}
Expand Down Expand Up @@ -1738,12 +1740,12 @@ fn record_match(h: &mut HuffmanOxide, lz: &mut LZOxide, mut match_len: u32, mut
}

fn compress_normal(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool {
let mut src_pos = d.params.src_pos;
let in_buf = match callback.in_buf {
None => return true,
Some(in_buf) => in_buf,
};

let mut src_pos = d.params.src_pos;
let mut lookahead_size = d.dict.lookahead_size;
let mut lookahead_pos = d.dict.lookahead_pos;
let mut saved_lit = d.params.saved_lit;
Expand Down
3 changes: 1 addition & 2 deletions miniz_oxide/src/deflate/stored.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::deflate::core::{
use core::cmp;

pub(crate) fn compress_stored(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool {
let mut src_pos = d.params.src_pos;
let in_buf = match callback.buf() {
None => return true,
Some(in_buf) => in_buf,
Expand All @@ -17,7 +16,7 @@ pub(crate) fn compress_stored(d: &mut CompressorOxide, callback: &mut CallbackOx
// but just do this here to avoid causing issues for now.
d.params.saved_match_len = 0;
let mut bytes_written = d.lz.total_bytes;

let mut src_pos = d.params.src_pos;
let mut lookahead_size = d.dict.lookahead_size;
let mut lookahead_pos = d.dict.lookahead_pos;

Expand Down
10 changes: 10 additions & 0 deletions miniz_oxide/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,16 @@ fn issue_161_index_out_of_range_apply_match() {
let _ = miniz_oxide::inflate::core::decompress(&mut decompressor, &content, &mut buf2, 0, 0);
}

#[test]
fn empty_stored() {
// Compress empty input using stored compression level
// There was a logic error casuing this to output zeroes
// from the empty data buffer instead of outputting an empty stored block.
let data = vec![];
let enc = compress_to_vec_zlib(&data, 0);
let _ = decompress_to_vec_zlib(&enc).unwrap();
}

/*
#[test]
fn partial_decompression_imap_issue_158() {
Expand Down

0 comments on commit 3d62e6b

Please sign in to comment.