Skip to content

Commit b9ba7a6

Browse files
committed
expose uncompress2
1 parent 680841c commit b9ba7a6

File tree

4 files changed

+77
-9
lines changed

4 files changed

+77
-9
lines changed

libz-rs-sys/src/lib.rs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -478,25 +478,71 @@ pub unsafe extern "C-unwind" fn uncompress(
478478
dest: *mut u8,
479479
destLen: *mut c_ulong,
480480
source: *const u8,
481-
sourceLen: c_ulong,
481+
mut sourceLen: c_ulong,
482+
) -> c_int {
483+
uncompress2(dest, destLen, source, &mut sourceLen)
484+
}
485+
486+
/// Inflates `source` into `dest` like [`uncompress`], and writes the final inflated size into `destLen` and the number
487+
/// of source bytes consumed into `sourceLen`.
488+
///
489+
/// Upon entry, `destLen` is the total size of the destination buffer, which must be large enough to hold the entire
490+
/// uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and
491+
/// transmitted to the decompressor by some mechanism outside the scope of this compression library.)
492+
/// Upon exit, `destLen` is the actual size of the uncompressed data.
493+
///
494+
/// # Returns
495+
///
496+
/// * [`Z_OK`] if success
497+
/// * [`Z_MEM_ERROR`] if there was not enough memory
498+
/// * [`Z_BUF_ERROR`] if there was not enough room in the output buffer
499+
/// * [`Z_DATA_ERROR`] if the input data was corrupted or incomplete
500+
///
501+
/// In the case where there is not enough room, [`uncompress2`] will fill the output buffer with the uncompressed data up to that point.
502+
///
503+
/// # Safety
504+
///
505+
/// The caller must guarantee that
506+
///
507+
/// * Either
508+
/// - `destLen` is `NULL`
509+
/// - `destLen` satisfies the requirements of `&mut *destLen`
510+
/// * Either
511+
/// - `dest` is `NULL`
512+
/// - `dest` and `*destLen` satisfy the requirements of [`core::slice::from_raw_parts_mut::<MaybeUninit<u8>>`]
513+
/// * Either
514+
/// - `source` is `NULL`
515+
/// - `source` and `sourceLen` satisfy the requirements of [`core::slice::from_raw_parts::<u8>`]
516+
/// * `sourceLen` satisfies the requirements of `&mut *sourceLen`
517+
#[cfg_attr(feature = "export-symbols", export_name = prefix!(uncompress2))]
518+
pub unsafe extern "C" fn uncompress2(
519+
dest: *mut u8,
520+
destLen: *mut c_ulong,
521+
source: *const u8,
522+
sourceLen: *mut c_ulong,
482523
) -> c_int {
483524
// stock zlib will just dereference a NULL pointer: that's UB.
484525
// Hence us returning an error value is compatible
485526
let Some(destLen) = (unsafe { destLen.as_mut() }) else {
486527
return ReturnCode::StreamError as _;
487528
};
488529

530+
let Some(sourceLen) = (unsafe { sourceLen.as_mut() }) else {
531+
return ReturnCode::StreamError as _;
532+
};
533+
489534
let Some(output) = (unsafe { slice_from_raw_parts_uninit_mut(dest, *destLen as usize) }) else {
490535
return ReturnCode::StreamError as _;
491536
};
492537

493-
let Some(input) = (unsafe { slice_from_raw_parts(source, sourceLen as usize) }) else {
538+
let Some(input) = (unsafe { slice_from_raw_parts(source, *sourceLen as usize) }) else {
494539
return ReturnCode::StreamError as _;
495540
};
496541

497542
let config = InflateConfig::default();
498-
let (output, err) = zlib_rs::inflate::uncompress(output, input, config);
543+
let (consumed, output, err) = zlib_rs::inflate::uncompress2(output, input, config);
499544

545+
*sourceLen -= consumed as c_ulong;
500546
*destLen = output.len() as c_ulong;
501547

502548
err as c_int

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,23 +1069,27 @@ fn hello_world_uncompressed() {
10691069
fn copy_direct_from_next_in_to_next_out() {
10701070
assert_eq_rs_ng!({
10711071
let input = [120, 1, 1, 2, 0, 253, 255, 6, 10, 0, 24, 0, 17];
1072+
let output = [6u8, 10];
10721073
let mut dest_vec = vec![0u8; 1 << 16];
10731074

10741075
let mut dest_len = dest_vec.len() as c_ulong;
10751076
let dest = dest_vec.as_mut_ptr();
10761077

10771078
let source = input.as_ptr();
1078-
let source_len = input.len() as _;
1079+
let mut source_len = input.len() as c_ulong;
10791080

1080-
let err = unsafe { uncompress(dest, &mut dest_len, source, source_len) };
1081+
let err = unsafe { uncompress2(dest, &mut dest_len, source, &mut source_len) };
10811082

10821083
if err != 0 {
10831084
panic!("error {:?}", ReturnCode::from(err));
10841085
}
10851086

1087+
assert_eq!(dest_len as usize, output.len());
1088+
assert_eq!(source_len as usize, input.len());
1089+
10861090
dest_vec.truncate(dest_len as usize);
10871091

1088-
assert_eq!(String::from_utf8(dest_vec).unwrap(), "\u{6}\n");
1092+
assert_eq!(dest_vec, output);
10891093
});
10901094
}
10911095

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ macro_rules! assert_eq_rs_ng {
4545
dictLength: *mut core::ffi::c_uint,
4646
) -> core::ffi::c_int;
4747

48+
#[allow(unused)]
49+
fn uncompress2(
50+
dest: *mut u8,
51+
destLen: *mut core::ffi::c_ulong,
52+
source: *const u8,
53+
sourceLen: *mut core::ffi::c_ulong,
54+
) -> core::ffi::c_int;
55+
4856
#[allow(unused)]
4957
fn crc32_z(
5058
crc: core::ffi::c_ulong,

zlib-rs/src/inflate.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,15 @@ pub fn uncompress<'a>(
172172
input: &[u8],
173173
config: InflateConfig,
174174
) -> (&'a mut [u8], ReturnCode) {
175+
let (_consumed, output, ret) = uncompress2(output, input, config);
176+
(output, ret)
177+
}
178+
179+
pub fn uncompress2<'a>(
180+
output: &'a mut [MaybeUninit<u8>],
181+
input: &[u8],
182+
config: InflateConfig,
183+
) -> (u64, &'a mut [u8], ReturnCode) {
175184
let mut dest_len_ptr = output.len() as z_checksum;
176185

177186
// for detection of incomplete stream when *destLen == 0
@@ -204,14 +213,14 @@ pub fn uncompress<'a>(
204213

205214
let err = init(&mut stream, config);
206215
if err != ReturnCode::Ok {
207-
return (&mut [], err);
216+
return (0, &mut [], err);
208217
}
209218

210219
stream.next_out = dest;
211220
stream.avail_out = 0;
212221

213222
let Some(stream) = (unsafe { InflateStream::from_stream_mut(&mut stream) }) else {
214-
return (&mut [], ReturnCode::StreamError);
223+
return (0, &mut [], ReturnCode::StreamError);
215224
};
216225

217226
let err = loop {
@@ -232,6 +241,7 @@ pub fn uncompress<'a>(
232241
}
233242
};
234243

244+
let consumed = len + u64::from(stream.avail_in);
235245
if !output.is_empty() {
236246
dest_len_ptr = stream.total_out;
237247
} else if stream.total_out != 0 && err == ReturnCode::BufError {
@@ -254,7 +264,7 @@ pub fn uncompress<'a>(
254264
core::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut u8, dest_len_ptr as usize)
255265
};
256266

257-
(output_slice, ret)
267+
(consumed, output_slice, ret)
258268
}
259269

260270
#[derive(Debug, Clone, Copy)]

0 commit comments

Comments
 (0)