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
204 changes: 102 additions & 102 deletions libz-rs-sys-cdylib/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -522,64 +522,64 @@ static void test_dict_deflate(unsigned char *compr, size_t comprLen) {
CHECK_ERR(err, "deflateEnd");
}

// /* ===========================================================================
// * Test inflate() with a preset dictionary
// */
// static void test_dict_inflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) {
// int err;
// uint8_t check_dictionary[MAX_DICTIONARY_SIZE];
// uint32_t check_dictionary_len = 0;
// PREFIX3(stream) d_stream; /* decompression stream */
//
// strcpy((char*)uncompr, "garbage garbage garbage");
//
// d_stream.zalloc = zalloc;
// d_stream.zfree = zfree;
// d_stream.opaque = (void *)0;
// d_stream.adler = 0;
// d_stream.next_in = compr;
// d_stream.avail_in = (unsigned int)comprLen;
//
// err = PREFIX(inflateInit)(&d_stream);
// CHECK_ERR(err, "inflateInit");
//
// d_stream.next_out = uncompr;
// d_stream.avail_out = (unsigned int)uncomprLen;
//
// for (;;) {
// err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH);
// if (err == Z_STREAM_END) break;
// if (err == Z_NEED_DICT) {
// if (d_stream.adler != dictId)
// error("unexpected dictionary");
// err = PREFIX(inflateSetDictionary)(&d_stream, (const unsigned char*)dictionary,
// (int)sizeof(dictionary));
// }
// CHECK_ERR(err, "inflate with dict");
// }
//
// err = PREFIX(inflateGetDictionary)(&d_stream, NULL, &check_dictionary_len);
// CHECK_ERR(err, "inflateGetDictionary");
// #ifndef S390_DFLTCC_INFLATE
// if (check_dictionary_len < sizeof(dictionary))
// error("bad dictionary length\n");
// #endif
//
// err = PREFIX(inflateGetDictionary)(&d_stream, check_dictionary, &check_dictionary_len);
// CHECK_ERR(err, "inflateGetDictionary");
// #ifndef S390_DFLTCC_INFLATE
// if (memcmp(dictionary, check_dictionary, sizeof(dictionary)) != 0)
// error("bad dictionary\n");
// #endif
//
// err = PREFIX(inflateEnd)(&d_stream);
// CHECK_ERR(err, "inflateEnd");
//
// if (strncmp((char*)uncompr, hello, sizeof(hello)))
// error("bad inflate with dict\n");
// else
// printf("inflate with dictionary: %s\n", (char *)uncompr);
// }
/* ===========================================================================
* Test inflate() with a preset dictionary
*/
static void test_dict_inflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) {
int err;
uint8_t check_dictionary[MAX_DICTIONARY_SIZE];
uint32_t check_dictionary_len = 0;
PREFIX3(stream) d_stream; /* decompression stream */

strcpy((char*)uncompr, "garbage garbage garbage");

d_stream.zalloc = zalloc;
d_stream.zfree = zfree;
d_stream.opaque = (void *)0;
d_stream.adler = 0;
d_stream.next_in = compr;
d_stream.avail_in = (unsigned int)comprLen;

err = PREFIX(inflateInit)(&d_stream);
CHECK_ERR(err, "inflateInit");

d_stream.next_out = uncompr;
d_stream.avail_out = (unsigned int)uncomprLen;

for (;;) {
err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH);
if (err == Z_STREAM_END) break;
if (err == Z_NEED_DICT) {
if (d_stream.adler != dictId)
error("unexpected dictionary");
err = PREFIX(inflateSetDictionary)(&d_stream, (const unsigned char*)dictionary,
(int)sizeof(dictionary));
}
CHECK_ERR(err, "inflate with dict");
}

err = PREFIX(inflateGetDictionary)(&d_stream, NULL, &check_dictionary_len);
CHECK_ERR(err, "inflateGetDictionary");
#ifndef S390_DFLTCC_INFLATE
if (check_dictionary_len < sizeof(dictionary))
error("bad dictionary length\n");
#endif

err = PREFIX(inflateGetDictionary)(&d_stream, check_dictionary, &check_dictionary_len);
CHECK_ERR(err, "inflateGetDictionary");
#ifndef S390_DFLTCC_INFLATE
if (memcmp(dictionary, check_dictionary, sizeof(dictionary)) != 0)
error("bad dictionary\n");
#endif

err = PREFIX(inflateEnd)(&d_stream);
CHECK_ERR(err, "inflateEnd");

if (strncmp((char*)uncompr, hello, sizeof(hello)))
error("bad inflate with dict\n");
else
printf("inflate with dictionary: %s\n", (char *)uncompr);
}

/* ===========================================================================
* Test deflateBound() with small buffers
Expand Down Expand Up @@ -670,48 +670,48 @@ static void test_deflate_copy(unsigned char *compr, size_t comprLen) {
CHECK_ERR(err, "deflateEnd copy");
}

// /* ===========================================================================
// * Test deflateGetDictionary() with small buffers
// */
// static void test_deflate_get_dict(unsigned char *compr, size_t comprLen) {
// PREFIX3(stream) c_stream; /* compression stream */
// int err;
// unsigned char *dictNew = NULL;
// unsigned int *dictLen;
//
// c_stream.zalloc = zalloc;
// c_stream.zfree = zfree;
// c_stream.opaque = (voidpf)0;
//
// err = PREFIX(deflateInit)(&c_stream, Z_BEST_COMPRESSION);
// CHECK_ERR(err, "deflateInit");
//
// c_stream.next_out = compr;
// c_stream.avail_out = (uInt)comprLen;
//
// c_stream.next_in = (z_const unsigned char *)hello;
// c_stream.avail_in = (unsigned int)strlen(hello)+1;
//
// err = PREFIX(deflate)(&c_stream, Z_FINISH);
//
// if (err != Z_STREAM_END)
// error("deflate should report Z_STREAM_END\n");
//
// dictNew = calloc(256, 1);
// dictLen = (unsigned int *)calloc(4, 1);
// err = PREFIX(deflateGetDictionary)(&c_stream, dictNew, dictLen);
//
// CHECK_ERR(err, "deflateGetDictionary");
// if (err == Z_OK) {
// printf("deflateGetDictionary(): %s\n", dictNew);
// }
//
// err = PREFIX(deflateEnd)(&c_stream);
// CHECK_ERR(err, "deflateEnd");
//
// free(dictNew);
// free(dictLen);
// }
/* ===========================================================================
* Test deflateGetDictionary() with small buffers
*/
static void test_deflate_get_dict(unsigned char *compr, size_t comprLen) {
PREFIX3(stream) c_stream; /* compression stream */
int err;
unsigned char *dictNew = NULL;
unsigned int *dictLen;

c_stream.zalloc = zalloc;
c_stream.zfree = zfree;
c_stream.opaque = (voidpf)0;

err = PREFIX(deflateInit)(&c_stream, Z_BEST_COMPRESSION);
CHECK_ERR(err, "deflateInit");

c_stream.next_out = compr;
c_stream.avail_out = (uInt)comprLen;

c_stream.next_in = (z_const unsigned char *)hello;
c_stream.avail_in = (unsigned int)strlen(hello)+1;

err = PREFIX(deflate)(&c_stream, Z_FINISH);

if (err != Z_STREAM_END)
error("deflate should report Z_STREAM_END\n");

dictNew = calloc(256, 1);
dictLen = (unsigned int *)calloc(4, 1);
err = PREFIX(deflateGetDictionary)(&c_stream, dictNew, dictLen);

CHECK_ERR(err, "deflateGetDictionary");
if (err == Z_OK) {
printf("deflateGetDictionary(): %s\n", dictNew);
}

err = PREFIX(deflateEnd)(&c_stream);
CHECK_ERR(err, "deflateEnd");

free(dictNew);
free(dictLen);
}

/* ===========================================================================
* Test deflatePending() with small buffers
Expand Down Expand Up @@ -1015,11 +1015,11 @@ int main(int argc, char *argv[]) {
comprLen = uncomprLen;

test_dict_deflate(compr, comprLen);
// test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
test_dict_inflate(compr, comprLen, uncompr, uncomprLen);

test_deflate_bound();
test_deflate_copy(compr, comprLen);
//// test_deflate_get_dict(compr, comprLen);
test_deflate_get_dict(compr, comprLen);
test_deflate_set_header(compr, comprLen);
test_deflate_tune(compr, comprLen);
test_deflate_pending(compr, comprLen);
Expand Down
83 changes: 83 additions & 0 deletions libz-rs-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1785,6 +1785,89 @@ pub const extern "C" fn zlibCompileFlags() -> c_ulong {
flags
}

/// Returns the sliding dictionary being maintained by inflate.
///
/// `dictLength` is set to the number of bytes in the dictionary, and that many bytes are copied
/// to `dictionary`. `dictionary` must have enough space, where `32768` bytes is
/// always enough. If [`inflateGetDictionary`] is called with `dictionary` equal to
/// `NULL`, then only the dictionary length is returned, and nothing is copied.
/// Similarly, if `dictLength` is `NULL`, then it is not set.
///
/// # Returns
///
/// * [`Z_OK`] if success
/// * [`Z_STREAM_ERROR`] if the stream state is inconsistent
///
/// # Safety
///
/// - `dictionary` must `NULL` or writable for the dictionary length (`32768` is always enough)
/// - `dictLength` must `NULL` or satisfy the requirements of [`pointer::as_mut`]
///
/// [`pointer::as_mut`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.as_mut
#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateGetDictionary))]
pub unsafe extern "C-unwind" fn inflateGetDictionary(
strm: *const z_stream,
dictionary: *mut c_uchar,
dictLength: *mut c_uint,
) -> c_int {
let Some(stream) = InflateStream::from_stream_ref(strm) else {
return ReturnCode::StreamError as c_int;
};

let whave = zlib_rs::inflate::get_dictionary(stream, dictionary);

if let Some(dictLength) = unsafe { dictLength.as_mut() } {
*dictLength = whave as c_uint;
}

ReturnCode::Ok as _
}

/// Returns the sliding dictionary being maintained by deflate.
///
/// `dictLength` is set to the number of bytes in the dictionary, and that many bytes are copied
/// to `dictionary`. `dictionary` must have enough space, where `32768` bytes is
/// always enough. If [`deflateGetDictionary`] is called with `dictionary` equal to
/// `NULL`, then only the dictionary length is returned, and nothing is copied.
/// Similarly, if `dictLength` is `NULL`, then it is not set.
///
/// [`deflateGetDictionary`] may return a length less than the window size, even
/// when more than the window size in input has been provided. It may return up
/// to 258 bytes less in that case, due to how zlib's implementation of deflate
/// manages the sliding window and lookahead for matches, where matches can be
/// up to 258 bytes long. If the application needs the last window-size bytes of
/// input, then that would need to be saved by the application outside of zlib.
///
/// # Returns
///
/// * [`Z_OK`] if success
/// * [`Z_STREAM_ERROR`] if the stream state is inconsistent
///
/// # Safety
///
/// - `dictionary` must `NULL` or writable for the dictionary length (`32768` is always enough)
/// - `dictLength` must `NULL` or satisfy the requirements of [`pointer::as_mut`]
///
/// [`pointer::as_mut`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.as_mut
#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateGetDictionary))]
pub unsafe extern "C-unwind" fn deflateGetDictionary(
strm: *const z_stream,
dictionary: *mut c_uchar,
dictLength: *mut c_uint,
) -> c_int {
let Some(stream) = DeflateStream::from_stream_ref(strm) else {
return ReturnCode::StreamError as c_int;
};

let len = zlib_rs::deflate::get_dictionary(stream, dictionary);

if let Some(dictLength) = unsafe { dictLength.as_mut() } {
*dictLength = len as c_uint;
}

ReturnCode::Ok as _
}

/// # Safety
///
/// Either
Expand Down
48 changes: 47 additions & 1 deletion test-libz-rs-sys/src/deflate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{ffi::CString, mem::MaybeUninit};
// we use the libz_sys but configure zlib-ng in zlib compat mode
use libz_sys as libz_ng_sys;

use core::ffi::{c_char, c_int, c_ulong, CStr};
use core::ffi::{c_char, c_int, c_uint, c_ulong, CStr};

use libz_rs_sys::{
deflate, deflateEnd, deflateInit2_, inflate, inflateEnd, inflateInit2_, Z_DEFLATED, Z_FILTERED,
Expand Down Expand Up @@ -2424,3 +2424,49 @@ fn crc32_hash_calc_uninitialized_memory() {
dest
});
}

#[test]
fn test_deflate_get_dict() {
assert_eq_rs_ng!({
let mut compr = [0u8; 1024];

let mut strm = MaybeUninit::zeroed();

let ret = unsafe {
deflateInit_(
strm.as_mut_ptr(),
Z_BEST_COMPRESSION,
zlibVersion(),
core::mem::size_of::<z_stream>() as _,
)
};

let c_stream = unsafe { strm.assume_init_mut() };

assert_eq!(ReturnCode::from(ret), ReturnCode::Ok);

c_stream.avail_out = compr.len() as _;
c_stream.next_out = compr.as_mut_ptr();

let mut hello = *b"hello, hello!\0";

c_stream.avail_in = hello.len() as _;
c_stream.next_in = hello.as_mut_ptr();

let ret = unsafe { deflate(c_stream, Z_FINISH) };
assert_eq!(ReturnCode::from(ret), ReturnCode::StreamEnd);

let mut dict_new = vec![0; 256];
let mut dict_len = dict_new.len() as c_uint;

let ret = unsafe { deflateGetDictionary(c_stream, dict_new.as_mut_ptr(), &mut dict_len) };
assert_eq!(ReturnCode::from(ret), ReturnCode::Ok);

let dictionary = unsafe { CStr::from_ptr(dict_new.as_ptr().cast()) }.to_owned();

let ret = unsafe { deflateEnd(c_stream) };
assert_eq!(ReturnCode::from(ret), ReturnCode::Ok);

dictionary
});
}
Loading