Skip to content

Commit

Permalink
add deflateParams
Browse files Browse the repository at this point in the history
  • Loading branch information
folkertdev committed Feb 22, 2024
1 parent 9ad250b commit c31bb52
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 1 deletion.
11 changes: 11 additions & 0 deletions libz-rs-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,17 @@ pub unsafe extern "C" fn deflateEnd(strm: *mut z_stream) -> i32 {
}
}

pub unsafe extern "C" fn deflateParams(strm: z_streamp, level: c_int, strategy: c_int) -> c_int {
let Ok(strategy) = Strategy::try_from(strategy) else {
return ReturnCode::StreamError as _;
};

match DeflateStream::from_stream_mut(strm) {
Some(stream) => zlib_rs::deflate::params(stream, level, strategy) as _,
None => ReturnCode::StreamError as _,
}
}

pub unsafe extern "C" fn deflateInit_(
strm: z_streamp,
level: c_int,
Expand Down
117 changes: 116 additions & 1 deletion libz-rs-sys/src/tests/deflate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use libz_rs_sys::{
deflate, deflateEnd, deflateInit2_, inflate, inflateEnd, inflateInit2_, Z_DEFLATED, Z_FILTERED,
Z_NO_FLUSH,
};
use zlib_rs::{deflate::DeflateConfig, Flush, ReturnCode};
use zlib_rs::{
deflate::{DeflateConfig, Strategy},
Flush, ReturnCode,
};

const VERSION: *const c_char = "2.3.0\0".as_ptr() as *const c_char;
const STREAM_SIZE: c_int = std::mem::size_of::<libz_rs_sys::z_stream>() as c_int;
Expand Down Expand Up @@ -613,3 +616,115 @@ fn test_compress_bound() {
rs_bound == ng_bound as _
}
}

#[test]
fn test_compress_param() {
let mut output_rs = [0; 1024];
let mut output_ng = [0; 1024];

let config = DeflateConfig::new(2);

let input =
"Scheduling and executing async tasks is a job handled by an async runtime, such as\0";

let n_rs = unsafe {
let mut strm = MaybeUninit::zeroed();

// first validate the config
let err = libz_rs_sys::deflateInit2_(
strm.as_mut_ptr(),
config.level,
config.method as i32,
config.window_bits,
config.mem_level,
config.strategy as i32,
VERSION,
STREAM_SIZE,
);
assert_eq!(err, 0);

let stream = strm.assume_init_mut();

stream.next_out = output_rs.as_mut_ptr();
stream.avail_out = output_rs.len() as _;

let offset = input.len() / 2;

stream.next_in = input.as_ptr() as *mut u8;
stream.avail_in = offset as _;

let err = libz_rs_sys::deflate(stream, Flush::NoFlush as i32);
assert_eq!(err, 0);

let err = libz_rs_sys::deflateParams(stream, 8, Strategy::Rle as i32);
assert_eq!(err, 0);

assert_eq!(stream.next_in as usize - input.as_ptr() as usize, offset);

stream.avail_in = (input.len() - offset) as _;

let err = libz_rs_sys::deflate(stream, Flush::Finish as i32);
assert_eq!(err, ReturnCode::StreamEnd as i32);

let err = libz_rs_sys::deflateEnd(stream);
assert_eq!(err, 0);

stream.total_out as usize
};

let n_ng = unsafe {
let mut strm = MaybeUninit::zeroed();

let err = libz_ng_sys::deflateParams(strm.as_mut_ptr(), 8, Strategy::Rle as i32);
assert_eq!(err, ReturnCode::StreamError as i32);

// first validate the config
let err = libz_ng_sys::deflateInit2_(
strm.as_mut_ptr(),
config.level,
config.method as i32,
config.window_bits,
config.mem_level,
config.strategy as i32,
VERSION,
STREAM_SIZE,
);
assert_eq!(err, 0);

let err = libz_ng_sys::deflateParams(strm.as_mut_ptr(), -1, 100);
assert_eq!(err, ReturnCode::StreamError as i32);

let err = libz_ng_sys::deflateParams(strm.as_mut_ptr(), 100, Strategy::Rle as i32);
assert_eq!(err, ReturnCode::StreamError as i32);

let stream = strm.assume_init_mut();

stream.next_out = output_ng.as_mut_ptr();
stream.avail_out = output_ng.len() as _;

let offset = input.len() / 2;

stream.next_in = input.as_ptr() as *mut u8;
stream.avail_in = offset as _;

let err = libz_ng_sys::deflate(stream, Flush::NoFlush as i32);
assert_eq!(err, 0);

let err = libz_ng_sys::deflateParams(stream, 8, Strategy::Rle as i32);
assert_eq!(err, 0);

assert_eq!(stream.next_in as usize - input.as_ptr() as usize, offset);

stream.avail_in = (input.len() - offset) as _;

let err = libz_ng_sys::deflate(stream, Flush::Finish as i32);
assert_eq!(err, ReturnCode::StreamEnd as i32);

let err = libz_ng_sys::deflateEnd(stream);
assert_eq!(err, 0);

stream.total_out
};

assert_eq!(&output_rs[..n_rs], &output_ng[..n_ng]);
}
55 changes: 55 additions & 0 deletions zlib-rs/src/deflate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,61 @@ pub fn init(stream: &mut z_stream, config: DeflateConfig) -> ReturnCode {
reset(stream)
}

pub fn params(stream: &mut DeflateStream, level: i32, strategy: Strategy) -> ReturnCode {
let level = if level == crate::c_api::Z_DEFAULT_COMPRESSION {
6
} else {
level
};

if !(0..=9).contains(&level) {
return ReturnCode::StreamError;
}

let level = level as i8;

let func = CONFIGURATION_TABLE[stream.state.level as usize].func;

let state = &mut stream.state;

if (strategy != state.strategy || func != CONFIGURATION_TABLE[level as usize].func)
&& state.last_flush != -2
{
// Flush the last buffer.
let err = deflate(stream, Flush::Block);
if err == ReturnCode::StreamError {
return err;
}

let state = &mut stream.state;

if stream.avail_in != 0
|| ((state.strstart as isize - state.block_start) + state.lookahead as isize) != 0
{
return ReturnCode::BufError;
}
}

let state = &mut stream.state;

if state.level != level {
if state.level == 0 && state.matches != 0 {
if state.matches == 1 {
self::slide_hash::slide_hash(state);
} else {
state.head.fill(0);
}
state.matches = 0;
}

lm_set_level(state, level);
}

state.strategy = strategy;

ReturnCode::Ok
}

pub fn end(stream: &mut DeflateStream) -> ReturnCode {
let status = stream.state.status;

Expand Down

0 comments on commit c31bb52

Please sign in to comment.