libz_rs_sys/
lib.rs

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