Skip to main content

libz_rs_sys/
lib.rs

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