libz_rs_sys/lib.rs
1#![allow(non_camel_case_types)]
2#![allow(non_snake_case)]
3#![cfg_attr(not(feature = "std"), no_std)]
4#![doc = include_str!("../README.md")]
5
6//! # Safety
7//!
8//! Most of the functions in this module are `unsafe fn`s, meaning that their behavior may be
9//! undefined if certain assumptions are broken by the caller. In most cases, documentation
10//! in this module refers to the safety assumptions of standard library functions.
11//!
12//! In most cases, pointers must be either `NULL` or satisfy the requirements of `&*ptr` or `&mut
13//! *ptr`. This requirement maps to the requirements of [`pointer::as_ref`] and [`pointer::as_mut`]
14//! for immutable and mutable pointers respectively.
15//!
16//! For pointer and length pairs, describing some sequence of elements in memory, the requirements
17//! of [`core::slice::from_raw_parts`] or [`core::slice::from_raw_parts_mut`] apply. In some cases,
18//! the element type `T` is converted into `MaybeUninit<T>`, meaning that while the slice must be
19//! valid, the elements in the slice can be uninitialized. Using uninitialized buffers for output
20//! is more performant.
21//!
22//! Finally, some functions accept a string argument, which must either be `NULL` or satisfy the
23//! requirements of [`core::ffi::CStr::from_ptr`].
24//!
25//! [`pointer::as_ref`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.as_ref
26//! [`pointer::as_mut`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.as_mut
27
28use core::mem::MaybeUninit;
29
30use core::ffi::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void};
31
32use zlib_rs::{
33 deflate::{DeflateConfig, DeflateStream, Method, Strategy},
34 inflate::{InflateConfig, InflateStream},
35 DeflateFlush, InflateFlush, ReturnCode,
36};
37
38pub use zlib_rs::c_api::*;
39
40#[cfg(feature = "custom-prefix")]
41macro_rules! prefix {
42 ($name:expr) => {
43 concat!(env!("LIBZ_RS_SYS_PREFIX"), stringify!($name))
44 };
45}
46
47// NOTE: once we reach 1.0.0, the macro used for the `semver-prefix` feature should no longer include the
48// minor version in the name. The name is meant to be unique between semver-compatible versions!
49const _PRE_ONE_DOT_O: () = assert!(env!("CARGO_PKG_VERSION_MAJOR").as_bytes()[0] == b'0');
50
51#[cfg(feature = "semver-prefix")]
52macro_rules! prefix {
53 ($name:expr) => {
54 concat!(
55 "LIBZ_RS_SYS_v",
56 env!("CARGO_PKG_VERSION_MAJOR"),
57 "_",
58 env!("CARGO_PKG_VERSION_MINOR"),
59 "_x_",
60 stringify!($name)
61 )
62 };
63}
64
65#[cfg(all(
66 not(feature = "custom-prefix"),
67 not(feature = "semver-prefix"),
68 not(any(test, feature = "testing-prefix"))
69))]
70macro_rules! prefix {
71 ($name:expr) => {
72 stringify!($name)
73 };
74}
75
76#[cfg(all(
77 not(feature = "custom-prefix"),
78 not(feature = "semver-prefix"),
79 any(test, feature = "testing-prefix")
80))]
81macro_rules! prefix {
82 ($name:expr) => {
83 concat!("LIBZ_RS_SYS_TEST_", stringify!($name))
84 };
85}
86
87pub(crate) use prefix;
88
89#[cfg(all(feature = "rust-allocator", feature = "c-allocator"))]
90const _: () =
91 compile_error!("Only one of `rust-allocator` and `c-allocator` can be enabled at a time");
92
93// In spirit this type is `libc::off_t`, but it would be our only libc dependency, and so we
94// hardcode the type here. This should be correct on most operating systems. If we ever run into
95// issues with it, we can either special-case or add a feature flag to force a particular width
96#[cfg(not(target_arch = "wasm32"))]
97pub type z_off_t = c_long;
98
99#[cfg(target_arch = "wasm32")]
100pub type z_off_t = i64;
101
102/// Calculates the [crc32](https://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks#CRC-32_algorithm) checksum
103/// of a sequence of bytes.
104///
105/// When the pointer argument is `NULL`, the initial checksum value is returned.
106///
107/// # Safety
108///
109/// The caller must guarantee that either:
110///
111/// - `buf` is `NULL`
112/// - `buf` and `len` satisfy the requirements of [`core::slice::from_raw_parts`]
113///
114/// # Example
115///
116/// ```
117/// use libz_rs_sys::crc32;
118///
119/// unsafe {
120/// assert_eq!(crc32(0, core::ptr::null(), 0), 0);
121/// assert_eq!(crc32(1, core::ptr::null(), 32), 0);
122///
123/// let input = [1,2,3];
124/// assert_eq!(crc32(0, input.as_ptr(), input.len() as _), 1438416925);
125/// }
126/// ```
127#[cfg_attr(feature = "export-symbols", export_name = prefix!(crc32))]
128pub unsafe extern "C-unwind" fn crc32(crc: c_ulong, buf: *const Bytef, len: uInt) -> c_ulong {
129 match unsafe { slice_from_raw_parts(buf, len as usize) } {
130 Some(buf) => zlib_rs::crc32(crc as u32, buf) as c_ulong,
131 None => 0,
132 }
133}
134
135/// Combines the checksum of two slices into one.
136///
137/// The combined value is equivalent to calculating the checksum of the whole input.
138///
139/// This function can be used when input arrives in chunks, or when different threads
140/// calculate the checksum of different sections of the input.
141///
142/// # Example
143///
144/// ```
145/// use libz_rs_sys::{crc32, crc32_combine};
146///
147/// let input = [1, 2, 3, 4, 5, 6, 7, 8];
148/// let lo = &input[..4];
149/// let hi = &input[4..];
150///
151/// unsafe {
152/// let full = crc32(0, input.as_ptr(), input.len() as _);
153///
154/// let crc1 = crc32(0, lo.as_ptr(), lo.len() as _);
155/// let crc2 = crc32(0, hi.as_ptr(), hi.len() as _);
156///
157/// let combined = crc32_combine(crc1, crc2, hi.len() as _);
158///
159/// assert_eq!(full, combined);
160/// }
161/// ```
162#[cfg_attr(feature = "export-symbols", export_name = prefix!(crc32_combine))]
163pub extern "C-unwind" fn crc32_combine(crc1: c_ulong, crc2: c_ulong, len2: z_off_t) -> c_ulong {
164 zlib_rs::crc32_combine(crc1 as u32, crc2 as u32, len2 as u64) as c_ulong
165}
166
167/// Calculates the [adler32](https://en.wikipedia.org/wiki/Adler-32) checksum
168/// of a sequence of bytes.
169///
170/// When the pointer argument is `NULL`, the initial checksum value is returned.
171///
172/// # Safety
173///
174/// The caller must guarantee that either:
175///
176/// - `buf` is `NULL`
177/// - `buf` and `len` satisfy the requirements of [`core::slice::from_raw_parts`]
178///
179/// # Example
180///
181/// ```
182/// use libz_rs_sys::adler32;
183///
184/// unsafe {
185/// assert_eq!(adler32(0, core::ptr::null(), 0), 1);
186/// assert_eq!(adler32(1, core::ptr::null(), 32), 1);
187///
188/// let input = [1,2,3];
189/// assert_eq!(adler32(0, input.as_ptr(), input.len() as _), 655366);
190/// }
191/// ```
192#[cfg_attr(feature = "export-symbols", export_name = prefix!(adler32))]
193pub unsafe extern "C-unwind" fn adler32(adler: c_ulong, buf: *const Bytef, len: uInt) -> c_ulong {
194 match unsafe { slice_from_raw_parts(buf, len as usize) } {
195 Some(buf) => zlib_rs::adler32(adler as u32, buf) as c_ulong,
196 None => 1,
197 }
198}
199
200/// Combines the checksum of two slices into one.
201///
202/// The combined value is equivalent to calculating the checksum of the whole input.
203///
204/// This function can be used when input arrives in chunks, or when different threads
205/// calculate the checksum of different sections of the input.
206///
207/// # Example
208///
209/// ```
210/// use libz_rs_sys::{adler32, adler32_combine};
211///
212/// let input = [1, 2, 3, 4, 5, 6, 7, 8];
213/// let lo = &input[..4];
214/// let hi = &input[4..];
215///
216/// unsafe {
217/// let full = adler32(1, input.as_ptr(), input.len() as _);
218///
219/// let adler1 = adler32(1, lo.as_ptr(), lo.len() as _);
220/// let adler2 = adler32(1, hi.as_ptr(), hi.len() as _);
221///
222/// let combined = adler32_combine(adler1, adler2, hi.len() as _);
223///
224/// assert_eq!(full, combined);
225/// }
226/// ```
227#[cfg_attr(feature = "export-symbols", export_name = prefix!(adler32_combine))]
228pub extern "C-unwind" fn adler32_combine(
229 adler1: c_ulong,
230 adler2: c_ulong,
231 len2: z_off_t,
232) -> c_ulong {
233 match u64::try_from(len2) {
234 Ok(len2) => zlib_rs::adler32_combine(adler1 as u32, adler2 as u32, len2) as c_ulong,
235 Err(_) => {
236 // for negative len, return invalid adler32 as a clue for debugging
237 0xFFFF_FFFF
238 }
239 }
240}
241
242/// Inflates `source` into `dest`, and writes the final inflated size into `destLen`.
243///
244/// Upon entry, `destLen` is the total size of the destination buffer, which must be large enough to hold the entire
245/// uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and
246/// transmitted to the decompressor by some mechanism outside the scope of this compression library.)
247/// Upon exit, `destLen` is the actual size of the uncompressed data.
248///
249/// # Returns
250///
251/// * [`Z_OK`] if success
252/// * [`Z_MEM_ERROR`] if there was not enough memory
253/// * [`Z_BUF_ERROR`] if there was not enough room in the output buffer
254/// * [`Z_DATA_ERROR`] if the input data was corrupted or incomplete
255///
256/// In the case where there is not enough room, [`uncompress`] will fill the output buffer with the uncompressed data up to that point.
257///
258/// # Safety
259///
260/// The caller must guarantee that
261///
262/// * Either
263/// - `destLen` is `NULL`
264/// - `destLen` satisfies the requirements of `&mut *destLen`
265/// * Either
266/// - `dest` is `NULL`
267/// - `dest` and `*destLen` satisfy the requirements of [`core::slice::from_raw_parts_mut::<MaybeUninit<u8>>`]
268/// * Either
269/// - `source` is `NULL`
270/// - `source` and `sourceLen` satisfy the requirements of [`core::slice::from_raw_parts::<u8>`]
271///
272/// # Example
273///
274/// ```
275/// use libz_rs_sys::{Z_OK, uncompress};
276///
277/// let source = [120, 156, 115, 75, 45, 42, 202, 44, 6, 0, 8, 6, 2, 108];
278///
279/// let mut dest = vec![0u8; 100];
280/// let mut dest_len = dest.len() as _;
281///
282/// let err = unsafe {
283/// uncompress(
284/// dest.as_mut_ptr(),
285/// &mut dest_len,
286/// source.as_ptr(),
287/// source.len() as _,
288/// )
289/// };
290///
291/// assert_eq!(err, Z_OK);
292/// assert_eq!(dest_len, 6);
293///
294/// dest.truncate(dest_len as usize);
295/// assert_eq!(dest, b"Ferris");
296/// ```
297#[cfg_attr(feature = "export-symbols", export_name = prefix!(uncompress))]
298pub unsafe extern "C-unwind" fn uncompress(
299 dest: *mut u8,
300 destLen: *mut c_ulong,
301 source: *const u8,
302 sourceLen: c_ulong,
303) -> c_int {
304 // stock zlib will just dereference a NULL pointer: that's UB.
305 // Hence us returning an error value is compatible
306 let Some(destLen) = (unsafe { destLen.as_mut() }) else {
307 return ReturnCode::StreamError as _;
308 };
309
310 let Some(output) = (unsafe { slice_from_raw_parts_uninit_mut(dest, *destLen as usize) }) else {
311 return ReturnCode::StreamError as _;
312 };
313
314 let Some(input) = (unsafe { slice_from_raw_parts(source, sourceLen as usize) }) else {
315 return ReturnCode::StreamError as _;
316 };
317
318 let config = InflateConfig::default();
319 let (output, err) = zlib_rs::inflate::uncompress(output, input, config);
320
321 *destLen = output.len() as c_ulong;
322
323 err as c_int
324}
325
326/// Decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full.
327///
328/// # Returns
329///
330/// - [`Z_OK`] if success
331/// - [`Z_STREAM_END`] if the end of the compressed data has been reached and all uncompressed output has been produced
332/// - [`Z_NEED_DICT`] if a preset dictionary is needed at this point
333/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
334/// - [`Z_DATA_ERROR`] if the input data was corrupted
335/// - [`Z_MEM_ERROR`] if there was not enough memory
336/// - [`Z_BUF_ERROR`] if no progress was possible or if there was not enough room in the output buffer when [`Z_FINISH`] is used
337///
338/// Note that [`Z_BUF_ERROR`] is not fatal, and [`inflate`] can be called again with more input and more output space to continue decompressing.
339/// If [`Z_DATA_ERROR`] is returned, the application may then call [`inflateSync`] to look for a good compression block if a partial recovery of the data is to be attempted.
340///
341/// # Safety
342///
343/// * Either
344/// - `strm` is `NULL`
345/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
346/// * Either
347/// - `strm.next_out` is `NULL`
348/// - `strm.next_out` and `strm.avail_out` satisfy the requirements of [`core::slice::from_raw_parts_mut::<MaybeUninit<u8>>`]
349/// * Either
350/// - `strm.next_in` is `NULL`
351/// - `strm.next_in` and `strm.avail_in` satisfy the requirements of [`core::slice::from_raw_parts::<u8>`]
352#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflate))]
353pub unsafe extern "C-unwind" fn inflate(strm: *mut z_stream, flush: i32) -> i32 {
354 if let Some(stream) = InflateStream::from_stream_mut(strm) {
355 let flush = InflateFlush::try_from(flush).unwrap_or_default();
356 zlib_rs::inflate::inflate(stream, flush) as _
357 } else {
358 ReturnCode::StreamError as _
359 }
360}
361
362/// Deallocates all dynamically allocated data structures for this stream.
363///
364/// This function discards any unprocessed input and does not flush any pending output.
365///
366/// # Returns
367///
368/// - [`Z_OK`] if success
369/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
370///
371/// # Safety
372///
373/// * Either
374/// - `strm` is `NULL`
375/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
376#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateEnd))]
377pub unsafe extern "C-unwind" fn inflateEnd(strm: *mut z_stream) -> i32 {
378 match InflateStream::from_stream_mut(strm) {
379 Some(stream) => {
380 zlib_rs::inflate::end(stream);
381 ReturnCode::Ok as _
382 }
383 None => ReturnCode::StreamError as _,
384 }
385}
386
387/// Initializes the state for decompression
388///
389/// # Returns
390///
391/// - [`Z_OK`] if success
392/// - [`Z_MEM_ERROR`] if there was not enough memory
393/// - [`Z_VERSION_ERROR`] if the zlib library version is incompatible with the version assumed by the caller
394/// - [`Z_STREAM_ERROR`] if a parameter is invalid, such as a null pointer to the structure
395///
396/// # Safety
397///
398/// The caller must guarantee that
399///
400/// * Either
401/// - `strm` is `NULL`
402/// - `strm` satisfies the requirements of `&mut *strm`
403/// * Either
404/// - `version` is NULL
405/// - `version` satisfies the requirements of [`core::ffi::CStr::from_ptr`]
406/// * If `strm` is not `NULL`, the following fields contain valid values
407/// - `zalloc`
408/// - `zfree`
409/// - `opaque`
410#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateBackInit_))]
411pub unsafe extern "C-unwind" fn inflateBackInit_(
412 _strm: z_streamp,
413 _windowBits: c_int,
414 _window: *mut c_uchar,
415 _version: *const c_char,
416 _stream_size: c_int,
417) -> c_int {
418 todo!("inflateBack is not implemented yet")
419}
420
421/// Decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full.
422///
423/// ## Safety
424///
425/// The caller must guarantee that
426///
427/// * Either
428/// - `strm` is `NULL`
429/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateBackInit_`]
430#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateBack))]
431pub unsafe extern "C-unwind" fn inflateBack(
432 _strm: z_streamp,
433 _in: in_func,
434 _in_desc: *mut c_void,
435 _out: out_func,
436 _out_desc: *mut c_void,
437) -> c_int {
438 todo!("inflateBack is not implemented yet")
439}
440
441/// Deallocates all dynamically allocated data structures for this stream.
442///
443/// This function discards any unprocessed input and does not flush any pending output.
444///
445/// ## Returns
446///
447/// - [`Z_OK`] if success
448/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
449///
450/// ## Safety
451///
452/// The caller must guarantee that
453///
454/// * Either
455/// - `strm` is `NULL`
456/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateBackInit_`]
457#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateBackEnd))]
458pub unsafe extern "C-unwind" fn inflateBackEnd(_strm: z_streamp) -> c_int {
459 todo!("inflateBack is not implemented yet")
460}
461
462/// Sets the destination stream as a complete copy of the source stream.
463///
464/// This function can be useful when randomly accessing a large stream.
465/// The first pass through the stream can periodically record the inflate state,
466/// allowing restarting inflate at those points when randomly accessing the stream.
467///
468/// # Returns
469///
470/// - [`Z_OK`] if success
471/// - [`Z_MEM_ERROR`] if there was not enough memory
472/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent (such as zalloc being NULL)
473///
474/// The `msg` field is left unchanged in both source and destination.
475///
476/// # Safety
477///
478/// The caller must guarantee that
479///
480/// * Either
481/// - `dest` is `NULL`
482/// - `dest` satisfies the requirements of `&mut *(dest as *mut MaybeUninit<z_stream>)`
483/// * Either
484/// - `source` is `NULL`
485/// - `source` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
486#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateCopy))]
487pub unsafe extern "C-unwind" fn inflateCopy(dest: *mut z_stream, source: *const z_stream) -> i32 {
488 let Some(dest) = (unsafe { dest.cast::<MaybeUninit<InflateStream>>().as_mut() }) else {
489 return ReturnCode::StreamError as _;
490 };
491
492 let Some(source) = (unsafe { InflateStream::from_stream_ref(source) }) else {
493 return ReturnCode::StreamError as _;
494 };
495
496 zlib_rs::inflate::copy(dest, source) as _
497}
498
499/// Gives information about the current location of the input stream.
500///
501/// This function marks locations in the input data for random access, which may be at bit positions, and notes those cases where the output of a code may span boundaries of random access blocks. The current location in the input stream can be determined from `avail_in` and `data_type` as noted in the description for the [`Z_BLOCK`] flush parameter for [`inflate`].
502///
503/// A code is being processed if [`inflate`] is waiting for more input to complete decoding of the code, or if it has completed decoding but is waiting for more output space to write the literal or match data.
504///
505/// # Returns
506///
507/// This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the return value down 16 bits.
508///
509/// - If the upper value is `-1` and the lower value is zero, then [`inflate`] is currently decoding information outside of a block.
510/// - If the upper value is `-1` and the lower value is non-zero, then [`inflate`] is in the middle of a stored block, with the lower value equaling the number of bytes from the input remaining to copy.
511/// - If the upper value is not `-1`, then it is the number of bits back from the current bit position in the input of the code (literal or length/distance pair) currently being processed. In that case the lower value is the number of bytes already emitted for that code.
512/// - `-65536` if the provided source stream state was inconsistent.
513///
514/// # Safety
515///
516/// The caller must guarantee that
517///
518/// * Either
519/// - `strm` is `NULL`
520/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
521#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateMark))]
522pub unsafe extern "C-unwind" fn inflateMark(strm: *const z_stream) -> c_long {
523 if let Some(stream) = InflateStream::from_stream_ref(strm) {
524 zlib_rs::inflate::mark(stream)
525 } else {
526 -65536
527 }
528}
529
530/// Skips invalid compressed data until
531///
532/// Skip invalid compressed data until a possible full flush point (see the description of deflate with [`Z_FULL_FLUSH`]) can be found,
533/// or until all available input is skipped. No output is provided.
534///
535/// [`inflateSync`] searches for a `00 00 FF FF` pattern in the compressed data.
536/// All full flush points have this pattern, but not all occurrences of this pattern are full flush points.
537///
538/// # Returns
539///
540/// - [`Z_OK`] if a possible full flush point has been found
541/// - [`Z_BUF_ERROR`] if no more input was provided
542/// - [`Z_DATA_ERROR`] if no flush point has been found
543/// - [`Z_STREAM_ERROR`] if the stream structure was inconsistent
544///
545/// In the success case, the application may save the current value of `total_in` which indicates where valid compressed data was found.
546/// In the error case, the application may repeatedly call [`inflateSync`], providing more input each time, until success or end of the input data.
547///
548/// # Safety
549///
550/// The caller must guarantee that
551///
552/// * Either
553/// - `strm` is `NULL`
554/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
555#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateSync))]
556pub unsafe extern "C-unwind" fn inflateSync(strm: *mut z_stream) -> i32 {
557 if let Some(stream) = InflateStream::from_stream_mut(strm) {
558 zlib_rs::inflate::sync(stream) as _
559 } else {
560 ReturnCode::StreamError as _
561 }
562}
563
564#[doc(hidden)]
565/// # Safety
566///
567/// The caller must guarantee that
568///
569/// * Either
570/// - `strm` is `NULL`
571/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
572#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateSyncPoint))]
573pub unsafe extern "C-unwind" fn inflateSyncPoint(strm: *mut z_stream) -> i32 {
574 if let Some(stream) = InflateStream::from_stream_mut(strm) {
575 zlib_rs::inflate::sync_point(stream) as i32
576 } else {
577 ReturnCode::StreamError as _
578 }
579}
580
581/// Initializes the state for decompression
582///
583/// A call to [`inflateInit_`] is equivalent to [`inflateInit2_`] where `windowBits` is 15.
584///
585/// # Returns
586///
587/// - [`Z_OK`] if success
588/// - [`Z_MEM_ERROR`] if there was not enough memory
589/// - [`Z_VERSION_ERROR`] if the zlib library version is incompatible with the version assumed by the caller
590/// - [`Z_STREAM_ERROR`] if a parameter is invalid, such as a null pointer to the structure
591///
592/// # Safety
593///
594/// The caller must guarantee that
595///
596/// * Either
597/// - `strm` is `NULL`
598/// - `strm` satisfies the requirements of `&mut *strm`
599/// * Either
600/// - `version` is NULL
601/// - `version` satisfies the requirements of [`core::ffi::CStr::from_ptr`]
602/// * If `strm` is not `NULL`, the following fields contain valid values
603/// - `zalloc`
604/// - `zfree`
605/// - `opaque`
606#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateInit_))]
607pub unsafe extern "C-unwind" fn inflateInit_(
608 strm: z_streamp,
609 version: *const c_char,
610 stream_size: c_int,
611) -> c_int {
612 let config = InflateConfig::default();
613 unsafe { inflateInit2_(strm, config.window_bits, version, stream_size) }
614}
615
616/// Initializes the state for decompression
617///
618/// # Returns
619///
620/// - [`Z_OK`] if success
621/// - [`Z_MEM_ERROR`] if there was not enough memory
622/// - [`Z_VERSION_ERROR`] if the zlib library version is incompatible with the version assumed by the caller
623/// - [`Z_STREAM_ERROR`] if a parameter is invalid, such as a null pointer to the structure
624///
625/// # Safety
626///
627/// The caller must guarantee that
628///
629/// * Either
630/// - `strm` is `NULL`
631/// - `strm` satisfies the requirements of `&mut *strm`
632/// * Either
633/// - `version` is NULL
634/// - `version` satisfies the requirements of [`core::ffi::CStr::from_ptr`]
635/// * If `strm` is not `NULL`, the following fields contain valid values
636/// - `zalloc`
637/// - `zfree`
638/// - `opaque`
639#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateInit2_))]
640pub unsafe extern "C-unwind" fn inflateInit2_(
641 strm: z_streamp,
642 windowBits: c_int,
643 version: *const c_char,
644 stream_size: c_int,
645) -> c_int {
646 if !is_version_compatible(version, stream_size) {
647 ReturnCode::VersionError as _
648 } else {
649 inflateInit2(strm, windowBits)
650 }
651}
652
653/// Helper that implements the actual initialization logic
654///
655/// # Safety
656///
657/// The caller must guarantee that
658///
659/// * Either
660/// - `strm` is `NULL`
661/// - `strm` satisfies the requirements of `&mut *strm`
662/// * If `strm` is not `NULL`, the following fields contain valid values
663/// - `zalloc`
664/// - `zfree`
665/// - `opaque`
666unsafe extern "C-unwind" fn inflateInit2(strm: z_streamp, windowBits: c_int) -> c_int {
667 let Some(strm) = (unsafe { strm.as_mut() }) else {
668 return ReturnCode::StreamError as _;
669 };
670
671 let config = InflateConfig {
672 window_bits: windowBits,
673 };
674
675 zlib_rs::inflate::init(strm, config) as _
676}
677
678/// Inserts bits in the inflate input stream.
679///
680/// The intent is that this function is used to start inflating at a bit position in the middle of a byte.
681/// The provided bits will be used before any bytes are used from next_in.
682/// This function should only be used with raw inflate, and should be used before the first [`inflate`] call after [`inflateInit2_`] or [`inflateReset`].
683/// bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the input.
684///
685/// If bits is negative, then the input stream bit buffer is emptied. Then [`inflatePrime`] can be called again to put bits in the buffer.
686/// This is used to clear out bits leftover after feeding inflate a block description prior to feeding inflate codes.
687///
688/// # Returns
689///
690/// - [`Z_OK`] if success
691/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent
692///
693/// # Safety
694///
695/// The caller must guarantee that
696///
697/// * Either
698/// - `strm` is `NULL`
699/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
700#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflatePrime))]
701pub unsafe extern "C-unwind" fn inflatePrime(strm: *mut z_stream, bits: i32, value: i32) -> i32 {
702 if let Some(stream) = InflateStream::from_stream_mut(strm) {
703 zlib_rs::inflate::prime(stream, bits, value) as _
704 } else {
705 ReturnCode::StreamError as _
706 }
707}
708
709/// Equivalent to [`inflateEnd`] followed by [`inflateInit_`], but does not free and reallocate the internal decompression state.
710///
711/// The stream will keep attributes that may have been set by [`inflateInit2_`].
712/// The stream's `total_in`, `total_out`, `adler`, and `msg` fields are initialized.
713///
714/// # Returns
715///
716/// - [`Z_OK`] if success
717/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent
718///
719/// # Safety
720///
721/// The caller must guarantee that
722///
723/// * Either
724/// - `strm` is `NULL`
725/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
726#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateReset))]
727pub unsafe extern "C-unwind" fn inflateReset(strm: *mut z_stream) -> i32 {
728 if let Some(stream) = InflateStream::from_stream_mut(strm) {
729 zlib_rs::inflate::reset(stream) as _
730 } else {
731 ReturnCode::StreamError as _
732 }
733}
734
735/// This function is the same as [`inflateReset`], but it also permits changing the wrap and window size requests.
736///
737/// The `windowBits` parameter is interpreted the same as it is for [`inflateInit2_`].
738/// If the window size is changed, then the memory allocated for the window is freed, and the window will be reallocated by [`inflate`] if needed.
739///
740/// # Returns
741///
742/// - [`Z_OK`] if success
743/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent, or if the `windowBits`
744/// parameter is invalid
745///
746/// # Safety
747///
748/// The caller must guarantee that
749///
750/// * Either
751/// - `strm` is `NULL`
752/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
753#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateReset2))]
754pub unsafe extern "C-unwind" fn inflateReset2(strm: *mut z_stream, windowBits: c_int) -> i32 {
755 if let Some(stream) = InflateStream::from_stream_mut(strm) {
756 let config = InflateConfig {
757 window_bits: windowBits,
758 };
759 zlib_rs::inflate::reset_with_config(stream, config) as _
760 } else {
761 ReturnCode::StreamError as _
762 }
763}
764
765/// Initializes the decompression dictionary from the given uncompressed byte sequence.
766///
767/// This function must be called immediately after a call of [`inflate`], if that call returned [`Z_NEED_DICT`].
768/// The dictionary chosen by the compressor can be determined from the Adler-32 value returned by that call of inflate.
769/// The compressor and decompressor must use exactly the same dictionary (see [`deflateSetDictionary`]).
770/// For raw inflate, this function can be called at any time to set the dictionary.
771/// If the provided dictionary is smaller than the window and there is already data in the window, then the provided dictionary will amend what's there.
772/// The application must insure that the same dictionary that was used for compression is provided.
773///
774/// [`inflateSetDictionary`] does not perform any decompression: this will be done by subsequent calls of [`inflate`].
775///
776/// # Returns
777///
778/// - [`Z_OK`] if success
779/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent or `dictionary` is `NULL`
780/// - [`Z_DATA_ERROR`] if the given dictionary doesn't match the expected one (i.e. it has an incorrect Adler-32 value).
781///
782/// # Safety
783///
784/// The caller must guarantee that
785///
786/// * Either
787/// - `strm` is `NULL`
788/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
789/// * Either
790/// - `dictionary` is `NULL`
791/// - `dictionary` and `dictLength` satisfy the requirements of [`core::slice::from_raw_parts_mut::<u8>`]
792#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateSetDictionary))]
793pub unsafe extern "C-unwind" fn inflateSetDictionary(
794 strm: *mut z_stream,
795 dictionary: *const u8,
796 dictLength: c_uint,
797) -> c_int {
798 let Some(stream) = InflateStream::from_stream_mut(strm) else {
799 return ReturnCode::StreamError as _;
800 };
801
802 let dict = match dictLength {
803 0 => &[],
804 _ => unsafe { slice_from_raw_parts(dictionary, dictLength as usize) }.unwrap_or(&[]),
805 };
806
807 zlib_rs::inflate::set_dictionary(stream, dict) as _
808}
809
810/// Requests that gzip header information be stored in the provided [`gz_header`] structure.
811///
812/// The [`inflateGetHeader`] function may be called after [`inflateInit2_`] or [`inflateReset`], and before the first call of [`inflate`].
813/// As [`inflate`] processes the gzip stream, `head.done` is zero until the header is completed, at which time `head.done` is set to one.
814/// If a zlib stream is being decoded, then `head.done` is set to `-1` to indicate that there will be no gzip header information forthcoming.
815/// Note that [`Z_BLOCK`] can be used to force [`inflate`] to return immediately after header processing is complete and before any actual data is decompressed.
816///
817/// - The `text`, `time`, `xflags`, and `os` fields are filled in with the gzip header contents.
818/// - `hcrc` is set to true if there is a header CRC. (The header CRC was valid if done is set to one.)
819/// - If `extra` is not `NULL`, then `extra_max` contains the maximum number of bytes to write to extra.
820/// Once `done` is `true`, `extra_len` contains the actual extra field length,
821/// and `extra` contains the extra field, or that field truncated if `extra_max` is less than `extra_len`.
822/// - If `name` is not `NULL`, then up to `name_max` characters are written there, terminated with a zero unless the length is greater than `name_max`.
823/// - If `comment` is not `NULL`, then up to `comm_max` characters are written there, terminated with a zero unless the length is greater than `comm_max`.
824///
825/// When any of `extra`, `name`, or `comment` are not `NULL` and the respective field is not present in the header, then that field is set to `NULL` to signal its absence.
826/// This allows the use of [`deflateSetHeader`] with the returned structure to duplicate the header. However if those fields are set to allocated memory,
827/// then the application will need to save those pointers elsewhere so that they can be eventually freed.
828///
829/// If [`inflateGetHeader`] is not used, then the header information is simply discarded. The header is always checked for validity, including the header CRC if present.
830/// [`inflateReset`] will reset the process to discard the header information.
831/// The application would need to call [`inflateGetHeader`] again to retrieve the header from the next gzip stream.
832///
833/// # Returns
834///
835/// - [`Z_OK`] if success
836/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent (such as zalloc being NULL)
837///
838/// # Safety
839///
840/// * Either
841/// - `strm` is `NULL`
842/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
843/// * Either
844/// - `head` is `NULL`
845/// - `head` satisfies the requirements of `&mut *head`
846/// * If `head` is not `NULL`:
847/// - if `head.extra` is not NULL, it must be writable for at least `head.extra_max` bytes
848/// - if `head.name` is not NULL, it must be writable for at least `head.name_max` bytes
849/// - if `head.comment` is not NULL, it must be writable for at least `head.comm_max` bytes
850#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateGetHeader))]
851pub unsafe extern "C-unwind" fn inflateGetHeader(strm: z_streamp, head: gz_headerp) -> c_int {
852 let Some(stream) = (unsafe { InflateStream::from_stream_mut(strm) }) else {
853 return ReturnCode::StreamError as _;
854 };
855
856 // SAFETY: the caller guarantees the safety of `&mut *`
857 let header = unsafe { head.as_mut() };
858
859 zlib_rs::inflate::get_header(stream, header) as i32
860}
861
862#[doc(hidden)]
863/// # Safety
864///
865/// The caller must guarantee that
866///
867/// * Either
868/// - `strm` is `NULL`
869/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
870#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateUndermine))]
871pub unsafe extern "C-unwind" fn inflateUndermine(strm: *mut z_stream, subvert: i32) -> c_int {
872 if let Some(stream) = InflateStream::from_stream_mut(strm) {
873 zlib_rs::inflate::undermine(stream, subvert) as i32
874 } else {
875 ReturnCode::StreamError as _
876 }
877}
878
879#[doc(hidden)]
880/// ## Safety
881///
882/// * Either
883/// - `strm` is `NULL`
884/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
885#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateResetKeep))]
886pub unsafe extern "C-unwind" fn inflateResetKeep(strm: *mut z_stream) -> c_int {
887 if let Some(stream) = InflateStream::from_stream_mut(strm) {
888 zlib_rs::inflate::reset_keep(stream) as _
889 } else {
890 ReturnCode::StreamError as _
891 }
892}
893
894// undocumented but exposed function
895#[doc(hidden)]
896/// Returns the number of codes used
897///
898/// # Safety
899///
900/// The caller must guarantee that either:
901///
902/// - `buf` is `NULL`
903/// - `buf` and `len` satisfy the requirements of [`core::slice::from_raw_parts`]
904#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateCodesUsed))]
905pub unsafe extern "C-unwind" fn inflateCodesUsed(strm: *mut z_stream) -> c_ulong {
906 match InflateStream::from_stream_mut(strm) {
907 Some(stream) => zlib_rs::inflate::codes_used(stream) as c_ulong,
908 None => c_ulong::MAX,
909 }
910}
911
912/// Compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full.
913///
914/// # Returns
915///
916/// - [`Z_OK`] if success
917/// - [`Z_STREAM_END`] if the end of the compressed data has been reached and all uncompressed output has been produced
918/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
919/// - [`Z_BUF_ERROR`] if no progress was possible or if there was not enough room in the output buffer when [`Z_FINISH`] is used
920///
921/// Note that [`Z_BUF_ERROR`] is not fatal, and [`deflate`] can be called again with more input and more output space to continue decompressing.
922///
923/// # Safety
924///
925/// * Either
926/// - `strm` is `NULL`
927/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
928/// * Either
929/// - `strm.next_out` is `NULL`
930/// - `strm.next_out` and `strm.avail_out` satisfy the requirements of [`core::slice::from_raw_parts_mut::<MaybeUninit<u8>>`]
931/// * Either
932/// - `strm.next_in` is `NULL`
933/// - `strm.next_in` and `strm.avail_in` satisfy the requirements of [`core::slice::from_raw_parts::<u8>`]
934#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflate))]
935pub unsafe extern "C-unwind" fn deflate(strm: *mut z_stream, flush: i32) -> c_int {
936 if let Some(stream) = DeflateStream::from_stream_mut(strm) {
937 match DeflateFlush::try_from(flush) {
938 Ok(flush) => zlib_rs::deflate::deflate(stream, flush) as _,
939 Err(()) => ReturnCode::StreamError as _,
940 }
941 } else {
942 ReturnCode::StreamError as _
943 }
944}
945
946/// Provides gzip header information for when a gzip stream is requested by [`deflateInit2_`].
947///
948/// [`deflateSetHeader`] may be called after [`deflateInit2_`] or [`deflateReset`]) and before the first call of [`deflate`]. The header's `text`, `time`, `os`, `extra`, `name`, and `comment` fields in the provided [`gz_header`] structure are written to the gzip header (xflag is ignored — the extra flags are set according to the compression level).
949///
950/// The caller must assure that, if not `NULL`, `name` and `comment` are terminated with a zero byte, and that if `extra` is not NULL, that `extra_len` bytes are available there.
951/// If `hcrc` is true, a gzip header crc is included.
952///
953/// If [`deflateSetHeader`] is not used, the default gzip header has text false, the time set to zero, and os set to the current operating system, with no extra, name, or comment fields. The gzip header is returned to the default state by [`deflateReset`].
954///
955/// # Returns
956///
957/// - [`Z_OK`] if success
958/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
959///
960/// # Safety
961///
962/// * Either
963/// - `strm` is `NULL`
964/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
965/// * Either
966/// - `head` is `NULL`
967/// - `head` satisfies the requirements of `&mut *head` and satisfies the following:
968/// - `head.extra` is `NULL` or is readable for at least `head.extra_len` bytes
969/// - `head.name` is `NULL` or satisfies the requirements of [`core::ffi::CStr::from_ptr`]
970/// - `head.comment` is `NULL` or satisfies the requirements of [`core::ffi::CStr::from_ptr`]
971#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateSetHeader))]
972pub unsafe extern "C-unwind" fn deflateSetHeader(strm: *mut z_stream, head: gz_headerp) -> c_int {
973 let Some(stream) = (unsafe { DeflateStream::from_stream_mut(strm) }) else {
974 return ReturnCode::StreamError as _;
975 };
976
977 let header = unsafe { head.as_mut() };
978
979 zlib_rs::deflate::set_header(stream, header) as _
980}
981
982/// Returns an upper bound on the compressed size after deflation of `sourceLen` bytes.
983///
984/// This function must be called after [`deflateInit_`] or [`deflateInit2_`].
985/// This would be used to allocate an output buffer for deflation in a single pass, and so would be called before [`deflate`].
986/// If that first [`deflate`] call is provided the `sourceLen` input bytes, an output buffer allocated to the size returned by [`deflateBound`],
987/// and the flush value [`Z_FINISH`], then [`deflate`] is guaranteed to return [`Z_STREAM_END`].
988///
989/// Note that it is possible for the compressed size to be larger than the value returned by [`deflateBound`]
990/// if flush options other than [`Z_FINISH`] or [`Z_NO_FLUSH`] are used.
991///
992/// ## Safety
993///
994/// * Either
995/// - `strm` is `NULL`
996/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
997#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateBound))]
998pub unsafe extern "C-unwind" fn deflateBound(strm: *mut z_stream, sourceLen: c_ulong) -> c_ulong {
999 zlib_rs::deflate::bound(DeflateStream::from_stream_mut(strm), sourceLen as usize) as c_ulong
1000}
1001
1002/// Compresses `source` into `dest`, and writes the final deflated size into `destLen`.
1003///
1004///`sourceLen` is the byte length of the source buffer.
1005/// Upon entry, `destLen` is the total size of the destination buffer,
1006/// which must be at least the value returned by [`compressBound`]`(sourceLen)`.
1007/// Upon exit, `destLen` is the actual size of the compressed data.
1008///
1009/// A call to [`compress`] is equivalent to [`compress2`] with a level parameter of [`Z_DEFAULT_COMPRESSION`].
1010///
1011/// # Returns
1012///
1013/// * [`Z_OK`] if success
1014/// * [`Z_MEM_ERROR`] if there was not enough memory
1015/// * [`Z_BUF_ERROR`] if there was not enough room in the output buffer
1016///
1017/// # Safety
1018///
1019/// The caller must guarantee that
1020///
1021/// * The `destLen` pointer satisfies the requirements of [`core::ptr::read`]
1022/// * Either
1023/// - `dest` is `NULL`
1024/// - `dest` and `*destLen` satisfy the requirements of [`core::slice::from_raw_parts_mut::<MaybeUninit<u8>>`]
1025/// * Either
1026/// - `source` is `NULL`
1027/// - `source` and `sourceLen` satisfy the requirements of [`core::slice::from_raw_parts`]
1028///
1029/// # Example
1030///
1031/// ```
1032/// use libz_rs_sys::{Z_OK, compress};
1033///
1034/// let source = b"Ferris";
1035///
1036/// let mut dest = vec![0u8; 100];
1037/// let mut dest_len = dest.len() as _;
1038///
1039/// let err = unsafe {
1040/// compress(
1041/// dest.as_mut_ptr(),
1042/// &mut dest_len,
1043/// source.as_ptr(),
1044/// source.len() as _,
1045/// )
1046/// };
1047///
1048/// assert_eq!(err, Z_OK);
1049/// assert_eq!(dest_len, 14);
1050///
1051/// dest.truncate(dest_len as usize);
1052/// assert_eq!(dest, [120, 156, 115, 75, 45, 42, 202, 44, 6, 0, 8, 6, 2, 108]);
1053/// ```
1054#[cfg_attr(feature = "export-symbols", export_name = prefix!(compress))]
1055pub unsafe extern "C-unwind" fn compress(
1056 dest: *mut Bytef,
1057 destLen: *mut c_ulong,
1058 source: *const Bytef,
1059 sourceLen: c_ulong,
1060) -> c_int {
1061 compress2(
1062 dest,
1063 destLen,
1064 source,
1065 sourceLen,
1066 DeflateConfig::default().level,
1067 )
1068}
1069
1070/// Compresses `source` into `dest`, and writes the final deflated size into `destLen`.
1071///
1072/// The level parameter has the same meaning as in [`deflateInit_`].
1073/// `sourceLen` is the byte length of the source buffer.
1074/// Upon entry, `destLen` is the total size of the destination buffer,
1075/// which must be at least the value returned by [`compressBound`]`(sourceLen)`.
1076/// Upon exit, `destLen` is the actual size of the compressed data.
1077///
1078/// # Returns
1079///
1080/// * [`Z_OK`] if success
1081/// * [`Z_MEM_ERROR`] if there was not enough memory
1082/// * [`Z_BUF_ERROR`] if there was not enough room in the output buffer
1083///
1084/// # Safety
1085///
1086/// The caller must guarantee that
1087///
1088/// * Either
1089/// - `destLen` is `NULL`
1090/// - `destLen` satisfies the requirements of `&mut *destLen`
1091/// * Either
1092/// - `dest` is `NULL`
1093/// - `dest` and `*destLen` satisfy the requirements of [`core::slice::from_raw_parts_mut::<MaybeUninit<u8>>`]
1094/// * Either
1095/// - `source` is `NULL`
1096/// - `source` and `sourceLen` satisfy the requirements of [`core::slice::from_raw_parts`]
1097#[cfg_attr(feature = "export-symbols", export_name = prefix!(compress2))]
1098pub unsafe extern "C-unwind" fn compress2(
1099 dest: *mut Bytef,
1100 destLen: *mut c_ulong,
1101 source: *const Bytef,
1102 sourceLen: c_ulong,
1103 level: c_int,
1104) -> c_int {
1105 // stock zlib will just dereference a NULL pointer: that's UB.
1106 // Hence us returning an error value is compatible
1107 let Some(destLen) = (unsafe { destLen.as_mut() }) else {
1108 return ReturnCode::StreamError as _;
1109 };
1110
1111 let Some(output) = (unsafe { slice_from_raw_parts_uninit_mut(dest, *destLen as usize) }) else {
1112 return ReturnCode::StreamError as _;
1113 };
1114
1115 let Some(input) = (unsafe { slice_from_raw_parts(source, sourceLen as usize) }) else {
1116 return ReturnCode::StreamError as _;
1117 };
1118
1119 let config = DeflateConfig::new(level);
1120 let (output, err) = zlib_rs::deflate::compress(output, input, config);
1121
1122 *destLen = output.len() as c_ulong;
1123
1124 err as c_int
1125}
1126
1127/// Returns an upper bound on the compressed size after [`compress`] or [`compress2`] on `sourceLen` bytes.
1128///
1129/// Can be used before a [`compress`] or [`compress2`] call to allocate the destination buffer.
1130#[cfg_attr(feature = "export-symbols", export_name = prefix!(compressBound))]
1131pub extern "C-unwind" fn compressBound(sourceLen: c_ulong) -> c_ulong {
1132 zlib_rs::deflate::compress_bound(sourceLen as usize) as c_ulong
1133}
1134
1135/// Deallocates all dynamically allocated data structures for this stream.
1136///
1137/// This function discards any unprocessed input and does not flush any pending output.
1138///
1139/// # Returns
1140///
1141/// - [`Z_OK`] if success
1142/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
1143/// - [`Z_DATA_ERROR`] if the stream was freed prematurely (some input or output was discarded)
1144///
1145/// In the error case, `strm.msg` may be set but then points to a static string (which must not be deallocated).
1146///
1147/// # Safety
1148///
1149/// * Either
1150/// - `strm` is `NULL`
1151/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1152#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateEnd))]
1153pub unsafe extern "C-unwind" fn deflateEnd(strm: *mut z_stream) -> i32 {
1154 match DeflateStream::from_stream_mut(strm) {
1155 Some(stream) => match zlib_rs::deflate::end(stream) {
1156 Ok(_) => ReturnCode::Ok as _,
1157 Err(_) => ReturnCode::DataError as _,
1158 },
1159 None => ReturnCode::StreamError as _,
1160 }
1161}
1162
1163/// This function is equivalent to [`deflateEnd`] followed by [`deflateInit_`], but does not free and reallocate the internal compression state.
1164///
1165/// This function will leave the compression level and any other attributes that may have been set unchanged.
1166/// The stream's `total_in`, `total_out`, `adler`, and `msg` fields are initialized.
1167///
1168/// ## Returns
1169///
1170/// - [`Z_OK`] if success
1171/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
1172///
1173/// ## Safety
1174///
1175/// The caller must guarantee that
1176///
1177/// * Either
1178/// - `strm` is `NULL`
1179/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1180#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateReset))]
1181pub unsafe extern "C-unwind" fn deflateReset(strm: *mut z_stream) -> i32 {
1182 match DeflateStream::from_stream_mut(strm) {
1183 Some(stream) => zlib_rs::deflate::reset(stream) as _,
1184 None => ReturnCode::StreamError as _,
1185 }
1186}
1187
1188/// Dynamically update the compression level and compression strategy.
1189///
1190/// This can be used to switch between compression and straight copy of the input data,
1191/// or to switch to a different kind of input data requiring a different strategy.
1192///
1193/// The interpretation of level and strategy is as in [`deflateInit2_`].
1194///
1195/// # Returns
1196///
1197/// - [`Z_OK`] if success
1198/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent or if a parameter was invalid
1199/// - [`Z_BUF_ERROR`] if there was not enough output space to complete the compression of the available input data before a change in the strategy or approach.
1200///
1201/// Note that in the case of a [`Z_BUF_ERROR`], the parameters are not changed.
1202/// A return value of [`Z_BUF_ERROR`] is not fatal, in which case [`deflateParams`] can be retried with more output space.
1203///
1204/// # Safety
1205///
1206/// The caller must guarantee that
1207///
1208/// * Either
1209/// - `strm` is `NULL`
1210/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1211#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateParams))]
1212pub unsafe extern "C-unwind" fn deflateParams(
1213 strm: z_streamp,
1214 level: c_int,
1215 strategy: c_int,
1216) -> c_int {
1217 let Ok(strategy) = Strategy::try_from(strategy) else {
1218 return ReturnCode::StreamError as _;
1219 };
1220
1221 match DeflateStream::from_stream_mut(strm) {
1222 Some(stream) => zlib_rs::deflate::params(stream, level, strategy) as _,
1223 None => ReturnCode::StreamError as _,
1224 }
1225}
1226
1227/// Initializes the compression dictionary from the given byte sequence without producing any compressed output.
1228///
1229/// This function may be called after [`deflateInit_`], [`deflateInit2_`] or [`deflateReset`]) and before the first call of [`deflate`].
1230///
1231/// # Returns
1232///
1233/// - [`Z_OK`] if success
1234/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
1235///
1236/// # Safety
1237///
1238/// The caller must guarantee that
1239///
1240/// * Either
1241/// - `strm` is `NULL`
1242/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1243/// * Either
1244/// - `dictionary` is `NULL`
1245/// - `dictionary` and `dictLength` satisfy the requirements of [`core::slice::from_raw_parts_mut::<u8>`]
1246#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateSetDictionary))]
1247pub unsafe extern "C-unwind" fn deflateSetDictionary(
1248 strm: z_streamp,
1249 dictionary: *const Bytef,
1250 dictLength: uInt,
1251) -> c_int {
1252 let Some(dictionary) = (unsafe { slice_from_raw_parts(dictionary, dictLength as usize) })
1253 else {
1254 return ReturnCode::StreamError as _;
1255 };
1256
1257 match DeflateStream::from_stream_mut(strm) {
1258 Some(stream) => zlib_rs::deflate::set_dictionary(stream, dictionary) as _,
1259 None => ReturnCode::StreamError as _,
1260 }
1261}
1262
1263/// Inserts bits in the deflate output stream.
1264///
1265/// The intent is that this function is used to start off the deflate output with the bits leftover from a previous deflate stream when appending to it.
1266/// As such, this function can only be used for raw deflate, and must be used before the first [`deflate`] call after a [`deflateInit2_`] or [`deflateReset`].
1267/// bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the output.
1268///
1269/// # Returns
1270///
1271/// - [`Z_OK`] if success
1272/// - [`Z_BUF_ERROR`] if there was not enough room in the internal buffer to insert the bits
1273/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent
1274///
1275/// # Safety
1276///
1277/// The caller must guarantee that
1278///
1279/// * Either
1280/// - `strm` is `NULL`
1281/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1282#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflatePrime))]
1283pub unsafe extern "C-unwind" fn deflatePrime(strm: z_streamp, bits: c_int, value: c_int) -> c_int {
1284 match DeflateStream::from_stream_mut(strm) {
1285 Some(stream) => zlib_rs::deflate::prime(stream, bits, value) as _,
1286 None => ReturnCode::StreamError as _,
1287 }
1288}
1289
1290/// Returns the number of bytes and bits of output that have been generated, but not yet provided in the available output.
1291///
1292/// The bytes not provided would be due to the available output space having being consumed.
1293/// The number of bits of output not provided are between `0` and `7`, where they await more bits to join them in order to fill out a full byte.
1294/// If pending or bits are `NULL`, then those values are not set.
1295///
1296/// # Returns
1297///
1298/// - [`Z_OK`] if success
1299/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent
1300///
1301/// # Safety
1302///
1303/// The caller must guarantee that
1304///
1305/// * Either
1306/// - `strm` is `NULL`
1307/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1308/// * Either
1309/// - `pending` is `NULL`
1310/// - `pending` satisfies the requirements of [`core::ptr::write::<c_int>`]
1311/// * Either
1312/// - `bits` is `NULL`
1313/// - `bits` satisfies the requirements of [`core::ptr::write::<c_int>`]
1314#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflatePending))]
1315pub unsafe extern "C-unwind" fn deflatePending(
1316 strm: z_streamp,
1317 pending: *mut c_uint,
1318 bits: *mut c_int,
1319) -> c_int {
1320 let Some(stream) = (unsafe { DeflateStream::from_stream_mut(strm) }) else {
1321 return ReturnCode::StreamError as _;
1322 };
1323
1324 let (current_pending, current_bits) = stream.pending();
1325
1326 if let Some(pending) = unsafe { pending.as_mut() } {
1327 *pending = current_pending as c_uint;
1328 }
1329
1330 if let Some(bits) = unsafe { bits.as_mut() } {
1331 *bits = current_bits as c_int;
1332 }
1333
1334 ReturnCode::Ok as _
1335}
1336
1337/// Sets the destination stream as a complete copy of the source stream.
1338///
1339/// This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter.
1340/// The streams that will be discarded should then be freed by calling [`deflateEnd`].
1341/// Note that [`deflateCopy`] duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory.
1342///
1343/// # Returns
1344///
1345/// - [`Z_OK`] if success
1346/// - [`Z_MEM_ERROR`] if there was not enough memory
1347/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent (such as zalloc being NULL)
1348///
1349/// The `msg` field is left unchanged in both source and destination.
1350///
1351/// # Safety
1352///
1353/// The caller must guarantee that
1354///
1355/// * Either
1356/// - `dest` is `NULL`
1357/// - `dest` satisfies the requirements of `&mut *(dest as *mut MaybeUninit<z_stream>)`
1358/// * Either
1359/// - `source` is `NULL`
1360/// - `source` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1361#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateCopy))]
1362pub unsafe extern "C-unwind" fn deflateCopy(dest: z_streamp, source: z_streamp) -> c_int {
1363 let Some(dest) = (unsafe { dest.cast::<MaybeUninit<DeflateStream>>().as_mut() }) else {
1364 return ReturnCode::StreamError as _;
1365 };
1366
1367 let Some(source) = (unsafe { DeflateStream::from_stream_mut(source) }) else {
1368 return ReturnCode::StreamError as _;
1369 };
1370
1371 zlib_rs::deflate::copy(dest, source) as _
1372}
1373
1374/// Initializes the state for compression
1375///
1376/// The stream's `zalloc`, `zfree` and `opaque` fields must be initialized before by the caller.
1377/// If `zalloc` and `zfree` are set to `NULL`, [`deflateInit_`] updates them to use default allocation functions.
1378/// The `total_in`, `total_out`, `adler`, and `msg` fields are initialized.
1379///
1380/// The compression level must be [`Z_DEFAULT_COMPRESSION`], or between `0` and `9`:
1381///
1382/// - level `0` gives no compression at all (the input data is simply copied a block at a time)
1383/// - level `1` gives best speed
1384/// - level `9` gives best compression
1385/// - [`Z_DEFAULT_COMPRESSION`] requests a default compromise between speed and compression (currently equivalent to level `6`).
1386///
1387/// A call to [`deflateInit_`] is equivalent to [`deflateInit2_`] where:
1388///
1389/// - `method` is `8` (deflate)
1390/// - `windowBits` is `15`
1391/// - `memLevel` is `8`
1392/// - `strategy` is `0` (default)
1393///
1394/// # Returns
1395///
1396/// - [`Z_OK`] if success
1397/// - [`Z_MEM_ERROR`] if there was not enough memory
1398/// - [`Z_VERSION_ERROR`] if the zlib library version is incompatible with the version assumed by the caller
1399/// - [`Z_STREAM_ERROR`] if a parameter is invalid, such as a null pointer to the structure
1400///
1401/// # Safety
1402///
1403/// The caller must guarantee that
1404///
1405/// * Either
1406/// - `strm` is `NULL`
1407/// - `strm` satisfies the requirements of `&mut *strm`
1408/// * Either
1409/// - `version` is NULL
1410/// - `version` satisfies the requirements of [`core::ffi::CStr::from_ptr`]
1411/// * If `strm` is not `NULL`, the following fields contain valid values
1412/// - `zalloc`
1413/// - `zfree`
1414/// - `opaque`
1415///
1416/// # Example
1417///
1418/// ```
1419/// use core::mem::MaybeUninit;
1420/// use libz_rs_sys::{z_stream, deflateInit_, zlibVersion, Z_OK};
1421///
1422/// // the zalloc and zfree fields are initialized as zero/NULL.
1423/// // `deflateInit_` will set a default allocation and deallocation function.
1424/// let mut strm = MaybeUninit::zeroed();
1425///
1426/// let err = unsafe {
1427/// deflateInit_(
1428/// strm.as_mut_ptr(),
1429/// 6,
1430/// zlibVersion(),
1431/// core::mem::size_of::<z_stream>() as _,
1432/// )
1433/// };
1434/// assert_eq!(err, Z_OK);
1435///
1436/// // the stream is now fully initialized. Prefer `assume_init_mut` over
1437/// // `assume_init` so the stream does not get moved.
1438/// let strm = unsafe { strm.assume_init_mut() };
1439/// ```
1440#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateInit_))]
1441pub unsafe extern "C-unwind" fn deflateInit_(
1442 strm: z_streamp,
1443 level: c_int,
1444 version: *const c_char,
1445 stream_size: c_int,
1446) -> c_int {
1447 let config = DeflateConfig::new(level);
1448
1449 unsafe {
1450 deflateInit2_(
1451 strm,
1452 level,
1453 config.method as c_int,
1454 config.window_bits,
1455 config.mem_level,
1456 config.strategy as c_int,
1457 version,
1458 stream_size,
1459 )
1460 }
1461}
1462
1463/// Initializes the state for compression
1464///
1465/// The stream's `zalloc`, `zfree` and `opaque` fields must be initialized before by the caller.
1466/// If `zalloc` and `zfree` are set to `NULL`, [`deflateInit_`] updates them to use default allocation functions.
1467/// The `total_in`, `total_out`, `adler`, and `msg` fields are initialized.
1468///
1469/// The compression level must be [`Z_DEFAULT_COMPRESSION`], or between `0` and `9`:
1470///
1471/// - level `0` gives no compression at all (the input data is simply copied a block at a time)
1472/// - level `1` gives best speed
1473/// - level `9` gives best compression
1474/// - [`Z_DEFAULT_COMPRESSION`] requests a default compromise between speed and compression (currently equivalent to level `6`).
1475///
1476/// # Returns
1477///
1478/// - [`Z_OK`] if success
1479/// - [`Z_MEM_ERROR`] if there was not enough memory
1480/// - [`Z_VERSION_ERROR`] if the zlib library version is incompatible with the version assumed by the caller
1481/// - [`Z_STREAM_ERROR`] if a parameter is invalid, such as a null pointer to the structure
1482///
1483/// # Safety
1484///
1485/// The caller must guarantee that
1486///
1487/// * Either
1488/// - `strm` is `NULL`
1489/// - `strm` satisfies the requirements of `&mut *strm`
1490/// * Either
1491/// - `version` is NULL
1492/// - `version` satisfies the requirements of [`core::ffi::CStr::from_ptr`]
1493/// * If `strm` is not `NULL`, the following fields contain valid values
1494/// - `zalloc`
1495/// - `zfree`
1496/// - `opaque`
1497///
1498/// # Example
1499///
1500/// ```
1501/// use core::mem::MaybeUninit;
1502/// use libz_rs_sys::{z_stream, deflateInit2_, zlibVersion, Z_OK};
1503///
1504/// // the zalloc and zfree fields are initialized as zero/NULL.
1505/// // `deflateInit_` will set a default allocation and deallocation function.
1506/// let mut strm = MaybeUninit::zeroed();
1507///
1508/// let err = unsafe {
1509/// deflateInit2_(
1510/// strm.as_mut_ptr(),
1511/// 6,
1512/// 8,
1513/// 15,
1514/// 8,
1515/// 0,
1516/// zlibVersion(),
1517/// core::mem::size_of::<z_stream>() as _,
1518/// )
1519/// };
1520/// assert_eq!(err, Z_OK);
1521///
1522/// // the stream is now fully initialized. Prefer `assume_init_mut` over
1523/// // `assume_init` so the stream does not get moved.
1524/// let strm = unsafe { strm.assume_init_mut() };
1525/// ```
1526#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateInit2_))]
1527pub unsafe extern "C-unwind" fn deflateInit2_(
1528 strm: z_streamp,
1529 level: c_int,
1530 method: c_int,
1531 windowBits: c_int,
1532 memLevel: c_int,
1533 strategy: c_int,
1534 version: *const c_char,
1535 stream_size: c_int,
1536) -> c_int {
1537 if !is_version_compatible(version, stream_size) {
1538 return ReturnCode::VersionError as _;
1539 }
1540
1541 let Some(strm) = (unsafe { strm.as_mut() }) else {
1542 return ReturnCode::StreamError as _;
1543 };
1544
1545 let Ok(method) = Method::try_from(method) else {
1546 return ReturnCode::StreamError as _;
1547 };
1548
1549 let Ok(strategy) = Strategy::try_from(strategy) else {
1550 return ReturnCode::StreamError as _;
1551 };
1552
1553 let config = DeflateConfig {
1554 level,
1555 method,
1556 window_bits: windowBits,
1557 mem_level: memLevel,
1558 strategy,
1559 };
1560
1561 zlib_rs::deflate::init(strm, config) as _
1562}
1563
1564/// Fine tune deflate's internal compression parameters.
1565///
1566/// This should only be used by someone who understands the algorithm used by zlib's deflate for searching
1567/// for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out
1568/// the last compressed bit for their specific input data. Read the `deflate.rs` source code for the meaning
1569/// of the `max_lazy`, `good_length`, `nice_length`, and `max_chain` parameters.
1570///
1571/// ## Returns
1572///
1573/// - [`Z_OK`] if success
1574/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
1575///
1576/// # Safety
1577///
1578/// The caller must guarantee that
1579///
1580/// * Either
1581/// - `strm` is `NULL`
1582/// - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1583#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateTune))]
1584pub unsafe extern "C-unwind" fn deflateTune(
1585 strm: z_streamp,
1586 good_length: c_int,
1587 max_lazy: c_int,
1588 nice_length: c_int,
1589 max_chain: c_int,
1590) -> c_int {
1591 let Some(stream) = (unsafe { DeflateStream::from_stream_mut(strm) }) else {
1592 return ReturnCode::StreamError as _;
1593 };
1594
1595 zlib_rs::deflate::tune(
1596 stream,
1597 good_length as usize,
1598 max_lazy as usize,
1599 nice_length as usize,
1600 max_chain as usize,
1601 ) as _
1602}
1603
1604/// Get the error message for an error. This could be the value returned by e.g. [`compress`] or
1605/// [`inflate`].
1606///
1607/// The return value is a pointer to a NULL-terminated sequence of bytes
1608///
1609/// ## Example
1610///
1611/// ```
1612/// use libz_rs_sys::*;
1613/// use core::ffi::{c_char, CStr};
1614///
1615/// fn cstr<'a>(ptr: *const c_char) -> &'a [u8] {
1616/// // SAFETY: we trust the input
1617/// unsafe { CStr::from_ptr(ptr) }.to_bytes()
1618/// }
1619///
1620/// // defined error values give a short message
1621/// assert_eq!(cstr(zError(Z_NEED_DICT)), b"need dictionary");
1622/// assert_eq!(cstr(zError(Z_NEED_DICT)), b"need dictionary");
1623/// assert_eq!(cstr(zError(Z_STREAM_END)), b"stream end");
1624/// assert_eq!(cstr(zError(Z_OK)), b"");
1625/// assert_eq!(cstr(zError(Z_ERRNO)), b"file error");
1626/// assert_eq!(cstr(zError(Z_STREAM_ERROR)), b"stream error");
1627/// assert_eq!(cstr(zError(Z_DATA_ERROR)), b"data error");
1628/// assert_eq!(cstr(zError(Z_MEM_ERROR)), b"insufficient memory");
1629/// assert_eq!(cstr(zError(Z_BUF_ERROR)), b"buffer error");
1630/// assert_eq!(cstr(zError(Z_VERSION_ERROR)), b"incompatible version");
1631///
1632/// // other inputs return an empty string
1633/// assert_eq!(cstr(zError(1234)), b"");
1634/// ```
1635#[cfg_attr(feature = "export-symbols", export_name = prefix!(zError))]
1636pub const extern "C" fn zError(err: c_int) -> *const c_char {
1637 match ReturnCode::try_from_c_int(err) {
1638 Some(return_code) => return_code.error_message(),
1639 None => [0 as c_char].as_ptr(),
1640 }
1641}
1642
1643macro_rules! libz_rs_sys_version {
1644 () => {
1645 concat!("1.3.0-zlib-rs-", env!("CARGO_PKG_VERSION"), "\0")
1646 };
1647}
1648
1649// the first part of this version specifies the zlib that we're compatible with (in terms of
1650// supported functions). In practice in most cases only the major version is checked, unless
1651// specific functions that were added later are used.
1652const LIBZ_RS_SYS_VERSION: &str = concat!(libz_rs_sys_version!(), "\0");
1653
1654unsafe fn is_version_compatible(version: *const c_char, stream_size: i32) -> bool {
1655 let Some(expected_major_version) = (unsafe { version.as_ref() }) else {
1656 return false;
1657 };
1658
1659 if *expected_major_version as u8 != LIBZ_RS_SYS_VERSION.as_bytes()[0] {
1660 return false;
1661 }
1662
1663 core::mem::size_of::<z_stream>() as i32 == stream_size
1664}
1665
1666/// The version of the zlib library.
1667///
1668/// Its value is a pointer to a NULL-terminated sequence of bytes.
1669///
1670/// The version string for this release is `
1671#[doc = libz_rs_sys_version!()]
1672/// `:
1673///
1674/// - The first component is the version of stock zlib that this release is compatible with
1675/// - The final component is the zlib-rs version used to build this release.
1676#[cfg_attr(feature = "export-symbols", export_name = prefix!(zlibVersion))]
1677pub const extern "C" fn zlibVersion() -> *const c_char {
1678 LIBZ_RS_SYS_VERSION.as_ptr().cast::<c_char>()
1679}
1680
1681/// Return flags indicating compile-time options.
1682///
1683/// Type sizes, two bits each, `0b00` = 16 bits, `0b01` = 32, `0b10` = 64, `0b11` = other:
1684///
1685/// | bits | description |
1686/// | -- | -- |
1687/// | `0..=1` | size of [`uInt`] |
1688/// | `2..=3` | size of [`uLong`] |
1689/// | `4..=5` | size of [`voidpf`] (pointer) |
1690/// | `6..=7` | size of [`z_off_t`] |
1691///
1692/// Compiler, assembler, and debug options:
1693///
1694/// | bits | flag | description |
1695/// | -- | -- | -- |
1696/// | `8` | `ZLIB_DEBUG` | debug prints are enabled |
1697/// | `9` | `ASMV` or `ASMINF` | use ASM code |
1698/// | `10` | `ZLIB_WINAPI` | exported functions use the WINAPI calling convention |
1699/// | `11` | | reserved |
1700///
1701/// One-time table building (smaller code, but not thread-safe if true):
1702///
1703/// | bits | flag | description |
1704/// | -- | -- | -- |
1705/// | `12` | `BUILDFIXED` | build static block decoding tables when needed |
1706/// | `13` | `DYNAMIC_CRC_TABLE` | build CRC calculation tables when needed |
1707/// | `14` | | reserved |
1708/// | `15` | | reserved |
1709///
1710/// Library content (indicates missing functionality):
1711///
1712/// | bits | flag | description |
1713/// | -- | -- | -- |
1714/// | `16` | `NO_GZCOMPRESS` | `gz*` functions cannot compress (to avoid linking deflate code when not needed) |
1715/// | `17` | `NO_GZIP` | deflate can't write gzip streams, and inflate can't detect and decode gzip streams (to avoid linking crc code) |
1716/// | `18` | | reserved |
1717/// | `19` | | reserved |
1718///
1719/// Operation variations (changes in library functionality):
1720///
1721/// | bits | flag | description |
1722/// | -- | -- | -- |
1723/// | `20` | `PKZIP_BUG_WORKAROUND` | slightly more permissive inflate |
1724/// | `21` | `FASTEST` | deflate algorithm with only one, lowest compression level |
1725/// | `22` | | reserved |
1726/// | `23` | | reserved |
1727///
1728/// The sprintf variant used by `gzprintf` (zero is best):
1729///
1730/// | bits | value | description |
1731/// | -- | -- | -- |
1732/// | `24` | 0 = vs*, 1 = s* | 1 means limited to 20 arguments after the format |
1733/// | `25` | 0 = *nprintf, 1 = *printf | 1 means `gzprintf` not secure! |
1734/// | `26` | 0 = returns value, 1 = void | 1 means inferred string length returned |
1735///
1736/// Remainder:
1737///
1738/// The remaining bits `27..=31` are 0 (reserved).
1739#[cfg_attr(feature = "export-symbols", export_name = prefix!(zlibCompileFlags))]
1740pub const extern "C" fn zlibCompileFlags() -> c_ulong {
1741 let mut flags = 0;
1742
1743 const fn encode_size<T>() -> c_ulong {
1744 match core::mem::size_of::<T>() {
1745 2 => 0b00,
1746 4 => 0b01,
1747 8 => 0b10,
1748 _ => 0b11,
1749 }
1750 }
1751
1752 flags |= encode_size::<uInt>();
1753 flags |= encode_size::<uLong>() << 2;
1754 flags |= encode_size::<voidpf>() << 4;
1755 flags |= encode_size::<z_off_t>() << 6;
1756
1757 macro_rules! set_bit {
1758 ($i:expr, $v:expr) => {
1759 flags |= (($v as uLong) << $i);
1760 };
1761 }
1762
1763 // Compiler, assembler, debug:
1764 set_bit!(8, false); // ZLIB_DEBUG
1765 set_bit!(9, false); // ASMV || ASMINF
1766 set_bit!(10, false); // ZLIB_WINAPI
1767
1768 // One-time table building:
1769 set_bit!(12, false); // BUILDFIXED
1770 set_bit!(13, false); // DYNAMIC_CRC_TABLE
1771
1772 // Library content (indicates missing functionality):
1773 set_bit!(16, false); // NO_GZCOMPRESS
1774 set_bit!(17, false); // NO_GZIP
1775
1776 // Operation variations (changes in library functionality):
1777 set_bit!(20, false); // PKZIP_BUG_WORKAROUND
1778 set_bit!(21, false); // FASTEST
1779
1780 // The sprintf variant used by gzprintf (we assume a modern libc):
1781 set_bit!(24, false);
1782 set_bit!(25, false);
1783 set_bit!(26, false);
1784
1785 flags
1786}
1787
1788/// Returns the sliding dictionary being maintained by inflate.
1789///
1790/// `dictLength` is set to the number of bytes in the dictionary, and that many bytes are copied
1791/// to `dictionary`. `dictionary` must have enough space, where `32768` bytes is
1792/// always enough. If [`inflateGetDictionary`] is called with `dictionary` equal to
1793/// `NULL`, then only the dictionary length is returned, and nothing is copied.
1794/// Similarly, if `dictLength` is `NULL`, then it is not set.
1795///
1796/// # Returns
1797///
1798/// * [`Z_OK`] if success
1799/// * [`Z_STREAM_ERROR`] if the stream state is inconsistent
1800///
1801/// # Safety
1802///
1803/// - `dictionary` must `NULL` or writable for the dictionary length (`32768` is always enough)
1804/// - `dictLength` must `NULL` or satisfy the requirements of [`pointer::as_mut`]
1805///
1806/// [`pointer::as_mut`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.as_mut
1807#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateGetDictionary))]
1808pub unsafe extern "C-unwind" fn inflateGetDictionary(
1809 strm: *const z_stream,
1810 dictionary: *mut c_uchar,
1811 dictLength: *mut c_uint,
1812) -> c_int {
1813 let Some(stream) = InflateStream::from_stream_ref(strm) else {
1814 return ReturnCode::StreamError as c_int;
1815 };
1816
1817 let whave = zlib_rs::inflate::get_dictionary(stream, dictionary);
1818
1819 if let Some(dictLength) = unsafe { dictLength.as_mut() } {
1820 *dictLength = whave as c_uint;
1821 }
1822
1823 ReturnCode::Ok as _
1824}
1825
1826/// Returns the sliding dictionary being maintained by deflate.
1827///
1828/// `dictLength` is set to the number of bytes in the dictionary, and that many bytes are copied
1829/// to `dictionary`. `dictionary` must have enough space, where `32768` bytes is
1830/// always enough. If [`deflateGetDictionary`] is called with `dictionary` equal to
1831/// `NULL`, then only the dictionary length is returned, and nothing is copied.
1832/// Similarly, if `dictLength` is `NULL`, then it is not set.
1833///
1834/// [`deflateGetDictionary`] may return a length less than the window size, even
1835/// when more than the window size in input has been provided. It may return up
1836/// to 258 bytes less in that case, due to how zlib's implementation of deflate
1837/// manages the sliding window and lookahead for matches, where matches can be
1838/// up to 258 bytes long. If the application needs the last window-size bytes of
1839/// input, then that would need to be saved by the application outside of zlib.
1840///
1841/// # Returns
1842///
1843/// * [`Z_OK`] if success
1844/// * [`Z_STREAM_ERROR`] if the stream state is inconsistent
1845///
1846/// # Safety
1847///
1848/// - `dictionary` must `NULL` or writable for the dictionary length (`32768` is always enough)
1849/// - `dictLength` must `NULL` or satisfy the requirements of [`pointer::as_mut`]
1850///
1851/// [`pointer::as_mut`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.as_mut
1852#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateGetDictionary))]
1853pub unsafe extern "C-unwind" fn deflateGetDictionary(
1854 strm: *const z_stream,
1855 dictionary: *mut c_uchar,
1856 dictLength: *mut c_uint,
1857) -> c_int {
1858 let Some(stream) = DeflateStream::from_stream_ref(strm) else {
1859 return ReturnCode::StreamError as c_int;
1860 };
1861
1862 let len = zlib_rs::deflate::get_dictionary(stream, dictionary);
1863
1864 if let Some(dictLength) = unsafe { dictLength.as_mut() } {
1865 *dictLength = len as c_uint;
1866 }
1867
1868 ReturnCode::Ok as _
1869}
1870
1871/// # Safety
1872///
1873/// Either
1874///
1875/// - `ptr` is `NULL`
1876/// - `ptr` and `len` satisfy the requirements of [`core::slice::from_raw_parts`]
1877unsafe fn slice_from_raw_parts<'a, T>(ptr: *const T, len: usize) -> Option<&'a [T]> {
1878 if ptr.is_null() {
1879 None
1880 } else {
1881 Some(unsafe { core::slice::from_raw_parts(ptr, len) })
1882 }
1883}
1884
1885/// # Safety
1886///
1887/// Either
1888///
1889/// - `ptr` is `NULL`
1890/// - `ptr` and `len` satisfy the requirements of [`core::slice::from_raw_parts_mut`]
1891unsafe fn slice_from_raw_parts_uninit_mut<'a, T>(
1892 ptr: *mut T,
1893 len: usize,
1894) -> Option<&'a mut [MaybeUninit<T>]> {
1895 if ptr.is_null() {
1896 None
1897 } else {
1898 Some(unsafe { core::slice::from_raw_parts_mut(ptr.cast::<MaybeUninit<T>>(), len) })
1899 }
1900}