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    todo!("inflateBack is not implemented yet")
574}
575
576/// Decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full.
577///
578/// ## Safety
579///
580/// The caller must guarantee that
581///
582/// * Either
583///     - `strm` is `NULL`
584///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateBackInit_`]
585#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateBack))]
586pub unsafe extern "C-unwind" fn inflateBack(
587    _strm: z_streamp,
588    _in: in_func,
589    _in_desc: *mut c_void,
590    _out: out_func,
591    _out_desc: *mut c_void,
592) -> c_int {
593    todo!("inflateBack is not implemented yet")
594}
595
596/// Deallocates all dynamically allocated data structures for this stream.
597///
598/// This function discards any unprocessed input and does not flush any pending output.
599///
600/// ## Returns
601///
602/// - [`Z_OK`] if success
603/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
604///
605/// ## Safety
606///
607/// The caller must guarantee that
608///
609/// * Either
610///     - `strm` is `NULL`
611///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateBackInit_`]
612#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateBackEnd))]
613pub unsafe extern "C-unwind" fn inflateBackEnd(_strm: z_streamp) -> c_int {
614    todo!("inflateBack is not implemented yet")
615}
616
617/// Sets the destination stream as a complete copy of the source stream.
618///
619/// This function can be useful when randomly accessing a large stream.
620/// The first pass through the stream can periodically record the inflate state,
621/// allowing restarting inflate at those points when randomly accessing the stream.
622///
623/// # Returns
624///
625/// - [`Z_OK`] if success
626/// - [`Z_MEM_ERROR`] if there was not enough memory
627/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent (such as zalloc being NULL)
628///
629/// The `msg` field is left unchanged in both source and destination.
630///
631/// # Safety
632///
633/// The caller must guarantee that
634///
635/// * Either
636///     - `dest` is `NULL`
637///     - `dest` satisfies the requirements of `&mut *(dest as *mut MaybeUninit<z_stream>)`
638/// * Either
639///     - `source` is `NULL`
640///     - `source` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
641#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateCopy))]
642pub unsafe extern "C-unwind" fn inflateCopy(dest: *mut z_stream, source: *const z_stream) -> i32 {
643    let Some(dest) = (unsafe { dest.cast::<MaybeUninit<InflateStream>>().as_mut() }) else {
644        return ReturnCode::StreamError as _;
645    };
646
647    let Some(source) = (unsafe { InflateStream::from_stream_ref(source) }) else {
648        return ReturnCode::StreamError as _;
649    };
650
651    zlib_rs::inflate::copy(dest, source) as _
652}
653
654/// Gives information about the current location of the input stream.
655///
656/// 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`].
657///
658/// 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.
659///
660/// # Returns
661///
662/// 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.
663///
664/// - If the upper value is `-1` and the lower value is zero, then [`inflate`] is currently decoding information outside of a block.
665/// - 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.
666/// - 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.
667/// - `-65536` if the provided source stream state was inconsistent.
668///
669/// # Safety
670///
671/// The caller must guarantee that
672///
673/// * Either
674///     - `strm` is `NULL`
675///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
676#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateMark))]
677pub unsafe extern "C-unwind" fn inflateMark(strm: *const z_stream) -> c_long {
678    if let Some(stream) = InflateStream::from_stream_ref(strm) {
679        zlib_rs::inflate::mark(stream)
680    } else {
681        -65536
682    }
683}
684
685/// Skips invalid compressed data until
686///
687/// Skip invalid compressed data until a possible full flush point (see the description of deflate with [`Z_FULL_FLUSH`]) can be found,
688/// or until all available input is skipped. No output is provided.
689///
690/// [`inflateSync`] searches for a `00 00 FF FF` pattern in the compressed data.
691/// All full flush points have this pattern, but not all occurrences of this pattern are full flush points.
692///
693/// # Returns
694///
695/// - [`Z_OK`] if a possible full flush point has been found
696/// - [`Z_BUF_ERROR`] if no more input was provided
697/// - [`Z_DATA_ERROR`] if no flush point has been found
698/// - [`Z_STREAM_ERROR`] if the stream structure was inconsistent
699///
700/// In the success case, the application may save the current value of `total_in` which indicates where valid compressed data was found.
701/// In the error case, the application may repeatedly call [`inflateSync`], providing more input each time, until success or end of the input data.
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!(inflateSync))]
711pub unsafe extern "C-unwind" fn inflateSync(strm: *mut z_stream) -> i32 {
712    if let Some(stream) = InflateStream::from_stream_mut(strm) {
713        zlib_rs::inflate::sync(stream) as _
714    } else {
715        ReturnCode::StreamError as _
716    }
717}
718
719#[doc(hidden)]
720/// # Safety
721///
722/// The caller must guarantee that
723///
724/// * Either
725///     - `strm` is `NULL`
726///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
727#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateSyncPoint))]
728pub unsafe extern "C-unwind" fn inflateSyncPoint(strm: *mut z_stream) -> i32 {
729    if let Some(stream) = InflateStream::from_stream_mut(strm) {
730        zlib_rs::inflate::sync_point(stream) as i32
731    } else {
732        ReturnCode::StreamError as _
733    }
734}
735
736/// Initializes the state for decompression
737///
738/// A call to [`inflateInit_`] is equivalent to [`inflateInit2_`] where `windowBits` is 15.
739///
740/// # Returns
741///
742/// - [`Z_OK`] if success
743/// - [`Z_MEM_ERROR`] if there was not enough memory
744/// - [`Z_VERSION_ERROR`] if the zlib library version is incompatible with the version assumed by the caller
745/// - [`Z_STREAM_ERROR`] if a parameter is invalid, such as a null pointer to the structure
746///
747/// # Safety
748///
749/// The caller must guarantee that
750///
751/// * Either
752///     - `strm` is `NULL`
753///     - `strm` satisfies the requirements of `&mut *strm`
754/// * Either
755///     - `version` is NULL
756///     - `version` satisfies the requirements of [`core::ffi::CStr::from_ptr`]
757/// * If `strm` is not `NULL`, the following fields contain valid values
758///     - `zalloc`
759///     - `zfree`
760///     - `opaque`
761#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateInit_))]
762pub unsafe extern "C-unwind" fn inflateInit_(
763    strm: z_streamp,
764    version: *const c_char,
765    stream_size: c_int,
766) -> c_int {
767    let config = InflateConfig::default();
768    unsafe { inflateInit2_(strm, config.window_bits, version, stream_size) }
769}
770
771/// Initializes the state for decompression
772///
773/// # Returns
774///
775/// - [`Z_OK`] if success
776/// - [`Z_MEM_ERROR`] if there was not enough memory
777/// - [`Z_VERSION_ERROR`] if the zlib library version is incompatible with the version assumed by the caller
778/// - [`Z_STREAM_ERROR`] if a parameter is invalid, such as a null pointer to the structure
779///
780/// # Safety
781///
782/// The caller must guarantee that
783///
784/// * Either
785///     - `strm` is `NULL`
786///     - `strm` satisfies the requirements of `&mut *strm`
787/// * Either
788///     - `version` is NULL
789///     - `version` satisfies the requirements of [`core::ffi::CStr::from_ptr`]
790/// * If `strm` is not `NULL`, the following fields contain valid values
791///     - `zalloc`
792///     - `zfree`
793///     - `opaque`
794#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateInit2_))]
795pub unsafe extern "C-unwind" fn inflateInit2_(
796    strm: z_streamp,
797    windowBits: c_int,
798    version: *const c_char,
799    stream_size: c_int,
800) -> c_int {
801    if !is_version_compatible(version, stream_size) {
802        ReturnCode::VersionError as _
803    } else {
804        inflateInit2(strm, windowBits)
805    }
806}
807
808/// Helper that implements the actual initialization logic
809///
810/// # Safety
811///
812/// The caller must guarantee that
813///
814/// * Either
815///     - `strm` is `NULL`
816///     - `strm` satisfies the requirements of `&mut *strm`
817/// * If `strm` is not `NULL`, the following fields contain valid values
818///     - `zalloc`
819///     - `zfree`
820///     - `opaque`
821unsafe extern "C-unwind" fn inflateInit2(strm: z_streamp, windowBits: c_int) -> c_int {
822    let Some(strm) = (unsafe { strm.as_mut() }) else {
823        return ReturnCode::StreamError as _;
824    };
825
826    let config = InflateConfig {
827        window_bits: windowBits,
828    };
829
830    zlib_rs::inflate::init(strm, config) as _
831}
832
833/// Inserts bits in the inflate input stream.
834///
835/// The intent is that this function is used to start inflating at a bit position in the middle of a byte.
836/// The provided bits will be used before any bytes are used from next_in.
837/// This function should only be used with raw inflate, and should be used before the first [`inflate`] call after [`inflateInit2_`] or [`inflateReset`].
838/// 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.
839///
840/// If bits is negative, then the input stream bit buffer is emptied. Then [`inflatePrime`] can be called again to put bits in the buffer.
841/// This is used to clear out bits leftover after feeding inflate a block description prior to feeding inflate codes.
842///
843/// # Returns
844///
845/// - [`Z_OK`] if success
846/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent
847///
848/// # Safety
849///
850/// The caller must guarantee that
851///
852/// * Either
853///     - `strm` is `NULL`
854///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
855#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflatePrime))]
856pub unsafe extern "C-unwind" fn inflatePrime(strm: *mut z_stream, bits: i32, value: i32) -> i32 {
857    if let Some(stream) = InflateStream::from_stream_mut(strm) {
858        zlib_rs::inflate::prime(stream, bits, value) as _
859    } else {
860        ReturnCode::StreamError as _
861    }
862}
863
864/// Equivalent to [`inflateEnd`] followed by [`inflateInit_`], but does not free and reallocate the internal decompression state.
865///
866/// The stream will keep attributes that may have been set by [`inflateInit2_`].
867/// The stream's `total_in`, `total_out`, `adler`, and `msg` fields are initialized.
868///
869/// # Returns
870///
871/// - [`Z_OK`] if success
872/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent
873///
874/// # Safety
875///
876/// The caller must guarantee that
877///
878/// * Either
879///     - `strm` is `NULL`
880///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
881#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateReset))]
882pub unsafe extern "C-unwind" fn inflateReset(strm: *mut z_stream) -> i32 {
883    if let Some(stream) = InflateStream::from_stream_mut(strm) {
884        zlib_rs::inflate::reset(stream) as _
885    } else {
886        ReturnCode::StreamError as _
887    }
888}
889
890/// This function is the same as [`inflateReset`], but it also permits changing the wrap and window size requests.
891///
892/// The `windowBits` parameter is interpreted the same as it is for [`inflateInit2_`].
893/// 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.
894///
895/// # Returns
896///
897/// - [`Z_OK`] if success
898/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent, or if the `windowBits`
899///   parameter is invalid
900///
901/// # Safety
902///
903/// The caller must guarantee that
904///
905/// * Either
906///     - `strm` is `NULL`
907///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
908#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateReset2))]
909pub unsafe extern "C-unwind" fn inflateReset2(strm: *mut z_stream, windowBits: c_int) -> i32 {
910    if let Some(stream) = InflateStream::from_stream_mut(strm) {
911        let config = InflateConfig {
912            window_bits: windowBits,
913        };
914        zlib_rs::inflate::reset_with_config(stream, config) as _
915    } else {
916        ReturnCode::StreamError as _
917    }
918}
919
920/// Initializes the decompression dictionary from the given uncompressed byte sequence.
921///
922/// This function must be called immediately after a call of [`inflate`], if that call returned [`Z_NEED_DICT`].
923/// The dictionary chosen by the compressor can be determined from the Adler-32 value returned by that call of inflate.
924/// The compressor and decompressor must use exactly the same dictionary (see [`deflateSetDictionary`]).
925/// For raw inflate, this function can be called at any time to set the dictionary.
926/// 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.
927/// The application must insure that the same dictionary that was used for compression is provided.
928///
929/// [`inflateSetDictionary`] does not perform any decompression: this will be done by subsequent calls of [`inflate`].
930///
931/// # Returns
932///
933/// - [`Z_OK`] if success
934/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent or `dictionary` is `NULL`
935/// - [`Z_DATA_ERROR`] if the given dictionary doesn't match the expected one (i.e. it has an incorrect Adler-32 value).
936///
937/// # Safety
938///
939/// The caller must guarantee that
940///
941/// * Either
942///     - `strm` is `NULL`
943///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
944/// * Either
945///     - `dictionary` is `NULL`
946///     - `dictionary` and `dictLength` satisfy the requirements of [`core::slice::from_raw_parts_mut::<u8>`]
947#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateSetDictionary))]
948pub unsafe extern "C-unwind" fn inflateSetDictionary(
949    strm: *mut z_stream,
950    dictionary: *const u8,
951    dictLength: c_uint,
952) -> c_int {
953    let Some(stream) = InflateStream::from_stream_mut(strm) else {
954        return ReturnCode::StreamError as _;
955    };
956
957    let dict = match dictLength {
958        0 => &[],
959        _ => unsafe { slice_from_raw_parts(dictionary, dictLength as usize) }.unwrap_or(&[]),
960    };
961
962    zlib_rs::inflate::set_dictionary(stream, dict) as _
963}
964
965/// Requests that gzip header information be stored in the provided [`gz_header`] structure.
966///
967/// The [`inflateGetHeader`] function may be called after [`inflateInit2_`] or [`inflateReset`], and before the first call of [`inflate`].
968/// As [`inflate`] processes the gzip stream, `head.done` is zero until the header is completed, at which time `head.done` is set to one.
969/// 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.
970/// 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.
971///
972/// - The `text`, `time`, `xflags`, and `os` fields are filled in with the gzip header contents.
973/// - `hcrc` is set to true if there is a header CRC. (The header CRC was valid if done is set to one.)
974/// - If `extra` is not `NULL`, then `extra_max` contains the maximum number of bytes to write to extra.
975///   Once `done` is `true`, `extra_len` contains the actual extra field length,
976///   and `extra` contains the extra field, or that field truncated if `extra_max` is less than `extra_len`.
977/// - 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`.
978/// - 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`.
979///
980/// 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.
981/// This allows the use of [`deflateSetHeader`] with the returned structure to duplicate the header. However if those fields are set to allocated memory,
982/// then the application will need to save those pointers elsewhere so that they can be eventually freed.
983///
984/// 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.
985/// [`inflateReset`] will reset the process to discard the header information.
986/// The application would need to call [`inflateGetHeader`] again to retrieve the header from the next gzip stream.
987///
988/// # Returns
989///
990/// - [`Z_OK`] if success
991/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent (such as zalloc being NULL)
992///
993/// # Safety
994///
995/// * Either
996///     - `strm` is `NULL`
997///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
998/// * Either
999///     - `head` is `NULL`
1000///     - `head` satisfies the requirements of `&mut *head`
1001/// * If `head` is not `NULL`:
1002///     - if `head.extra` is not NULL, it must be writable for at least `head.extra_max` bytes
1003///     - if `head.name` is not NULL, it must be writable for at least `head.name_max` bytes
1004///     - if `head.comment` is not NULL, it must be writable for at least `head.comm_max` bytes
1005#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateGetHeader))]
1006pub unsafe extern "C-unwind" fn inflateGetHeader(strm: z_streamp, head: gz_headerp) -> c_int {
1007    let Some(stream) = (unsafe { InflateStream::from_stream_mut(strm) }) else {
1008        return ReturnCode::StreamError as _;
1009    };
1010
1011    // SAFETY: the caller guarantees the safety of `&mut *`
1012    let header = unsafe { head.as_mut() };
1013
1014    zlib_rs::inflate::get_header(stream, header) as i32
1015}
1016
1017#[doc(hidden)]
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!(inflateUndermine))]
1026pub unsafe extern "C-unwind" fn inflateUndermine(strm: *mut z_stream, subvert: i32) -> c_int {
1027    if let Some(stream) = InflateStream::from_stream_mut(strm) {
1028        zlib_rs::inflate::undermine(stream, subvert) as i32
1029    } else {
1030        ReturnCode::StreamError as _
1031    }
1032}
1033
1034#[doc(hidden)]
1035/// ## Safety
1036///
1037/// * Either
1038///     - `strm` is `NULL`
1039///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`inflateInit_`] or similar
1040#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateResetKeep))]
1041pub unsafe extern "C-unwind" fn inflateResetKeep(strm: *mut z_stream) -> c_int {
1042    if let Some(stream) = InflateStream::from_stream_mut(strm) {
1043        zlib_rs::inflate::reset_keep(stream) as _
1044    } else {
1045        ReturnCode::StreamError as _
1046    }
1047}
1048
1049// undocumented but exposed function
1050#[doc(hidden)]
1051/// Returns the number of codes used
1052///
1053/// # Safety
1054///
1055/// The caller must guarantee that either:
1056///
1057/// - `buf` is `NULL`
1058/// - `buf` and `len` satisfy the requirements of [`core::slice::from_raw_parts`]
1059#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateCodesUsed))]
1060pub unsafe extern "C-unwind" fn inflateCodesUsed(strm: *mut z_stream) -> c_ulong {
1061    match InflateStream::from_stream_mut(strm) {
1062        Some(stream) => zlib_rs::inflate::codes_used(stream) as c_ulong,
1063        None => c_ulong::MAX,
1064    }
1065}
1066
1067/// Compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full.
1068///
1069/// # Returns
1070///
1071/// - [`Z_OK`] if success
1072/// - [`Z_STREAM_END`] if the end of the compressed data has been reached and all uncompressed output has been produced
1073/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
1074/// - [`Z_BUF_ERROR`] if no progress was possible or if there was not enough room in the output buffer when [`Z_FINISH`] is used
1075///
1076/// Note that [`Z_BUF_ERROR`] is not fatal, and [`deflate`] can be called again with more input and more output space to continue decompressing.
1077///
1078/// # Safety
1079///
1080/// * Either
1081///     - `strm` is `NULL`
1082///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1083/// * Either
1084///     - `strm.next_out` is `NULL`
1085///     - `strm.next_out` and `strm.avail_out` satisfy the requirements of [`core::slice::from_raw_parts_mut::<MaybeUninit<u8>>`]
1086/// * Either
1087///     - `strm.next_in` is `NULL`
1088///     - `strm.next_in` and `strm.avail_in` satisfy the requirements of [`core::slice::from_raw_parts::<u8>`]
1089#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflate))]
1090pub unsafe extern "C-unwind" fn deflate(strm: *mut z_stream, flush: i32) -> c_int {
1091    if let Some(stream) = DeflateStream::from_stream_mut(strm) {
1092        match DeflateFlush::try_from(flush) {
1093            Ok(flush) => zlib_rs::deflate::deflate(stream, flush) as _,
1094            Err(()) => ReturnCode::StreamError as _,
1095        }
1096    } else {
1097        ReturnCode::StreamError as _
1098    }
1099}
1100
1101/// Provides gzip header information for when a gzip stream is requested by [`deflateInit2_`].
1102///
1103/// [`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).
1104///
1105/// 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.
1106/// If `hcrc` is true, a gzip header crc is included.
1107///
1108/// 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`].
1109///
1110/// # Returns
1111///
1112/// - [`Z_OK`] if success
1113/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
1114///
1115/// # Safety
1116///
1117/// * Either
1118///     - `strm` is `NULL`
1119///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1120/// * Either
1121///     - `head` is `NULL`
1122///     - `head` satisfies the requirements of `&mut *head` and satisfies the following:
1123///         - `head.extra` is `NULL` or is readable for at least `head.extra_len` bytes
1124///         - `head.name` is `NULL` or satisfies the requirements of [`core::ffi::CStr::from_ptr`]
1125///         - `head.comment` is `NULL` or satisfies the requirements of [`core::ffi::CStr::from_ptr`]
1126#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateSetHeader))]
1127pub unsafe extern "C-unwind" fn deflateSetHeader(strm: *mut z_stream, head: gz_headerp) -> c_int {
1128    let Some(stream) = (unsafe { DeflateStream::from_stream_mut(strm) }) else {
1129        return ReturnCode::StreamError as _;
1130    };
1131
1132    let header = unsafe { head.as_mut() };
1133
1134    zlib_rs::deflate::set_header(stream, header) as _
1135}
1136
1137/// Returns an upper bound on the compressed size after deflation of `sourceLen` bytes.
1138///
1139/// This function must be called after [`deflateInit_`] or [`deflateInit2_`].
1140/// This would be used to allocate an output buffer for deflation in a single pass, and so would be called before [`deflate`].
1141/// If that first [`deflate`] call is provided the `sourceLen` input bytes, an output buffer allocated to the size returned by [`deflateBound`],
1142/// and the flush value [`Z_FINISH`], then [`deflate`] is guaranteed to return [`Z_STREAM_END`].
1143///
1144/// Note that it is possible for the compressed size to be larger than the value returned by [`deflateBound`]
1145/// if flush options other than [`Z_FINISH`] or [`Z_NO_FLUSH`] are used.
1146///
1147/// ## Safety
1148///
1149/// * Either
1150///     - `strm` is `NULL`
1151///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1152#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateBound))]
1153pub unsafe extern "C-unwind" fn deflateBound(strm: *mut z_stream, sourceLen: c_ulong) -> c_ulong {
1154    zlib_rs::deflate::bound(DeflateStream::from_stream_mut(strm), sourceLen as usize) as c_ulong
1155}
1156
1157/// Compresses `source` into `dest`, and writes the final deflated size into `destLen`.
1158///
1159///`sourceLen` is the byte length of the source buffer.
1160/// Upon entry, `destLen` is the total size of the destination buffer,
1161/// which must be at least the value returned by [`compressBound`]`(sourceLen)`.
1162/// Upon exit, `destLen` is the actual size of the compressed data.
1163///
1164/// A call to [`compress`] is equivalent to [`compress2`] with a level parameter of [`Z_DEFAULT_COMPRESSION`].
1165///
1166/// # Returns
1167///
1168/// * [`Z_OK`] if success
1169/// * [`Z_MEM_ERROR`] if there was not enough memory
1170/// * [`Z_BUF_ERROR`] if there was not enough room in the output buffer
1171///
1172/// # Safety
1173///
1174/// The caller must guarantee that
1175///
1176/// * The `destLen` pointer satisfies the requirements of [`core::ptr::read`]
1177/// * Either
1178///     - `dest` is `NULL`
1179///     - `dest` and `*destLen` satisfy the requirements of [`core::slice::from_raw_parts_mut::<MaybeUninit<u8>>`]
1180/// * Either
1181///     - `source` is `NULL`
1182///     - `source` and `sourceLen` satisfy the requirements of [`core::slice::from_raw_parts`]
1183///
1184/// # Example
1185///
1186/// ```
1187/// use libz_rs_sys::{Z_OK, compress};
1188///
1189/// let source = b"Ferris";
1190///
1191/// let mut dest = vec![0u8; 100];
1192/// let mut dest_len = dest.len() as _;
1193///
1194/// let err = unsafe {
1195///     compress(
1196///         dest.as_mut_ptr(),
1197///         &mut dest_len,
1198///         source.as_ptr(),
1199///         source.len() as _,
1200///     )
1201/// };
1202///
1203/// assert_eq!(err, Z_OK);
1204/// assert_eq!(dest_len, 14);
1205///
1206/// dest.truncate(dest_len as usize);
1207/// assert_eq!(dest, [120, 156, 115, 75, 45, 42, 202, 44, 6, 0, 8, 6, 2, 108]);
1208/// ```
1209#[cfg_attr(feature = "export-symbols", export_name = prefix!(compress))]
1210pub unsafe extern "C-unwind" fn compress(
1211    dest: *mut Bytef,
1212    destLen: *mut c_ulong,
1213    source: *const Bytef,
1214    sourceLen: c_ulong,
1215) -> c_int {
1216    compress2(
1217        dest,
1218        destLen,
1219        source,
1220        sourceLen,
1221        DeflateConfig::default().level,
1222    )
1223}
1224
1225/// Compresses `source` into `dest`, and writes the final deflated size into `destLen`.
1226///
1227/// The level parameter has the same meaning as in [`deflateInit_`].
1228/// `sourceLen` is the byte length of the source buffer.
1229/// Upon entry, `destLen` is the total size of the destination buffer,
1230/// which must be at least the value returned by [`compressBound`]`(sourceLen)`.
1231/// Upon exit, `destLen` is the actual size of the compressed data.
1232///
1233/// # Returns
1234///
1235/// * [`Z_OK`] if success
1236/// * [`Z_MEM_ERROR`] if there was not enough memory
1237/// * [`Z_BUF_ERROR`] if there was not enough room in the output buffer
1238///
1239/// # Safety
1240///
1241/// The caller must guarantee that
1242///
1243/// * Either
1244///     - `destLen` is `NULL`
1245///     - `destLen` satisfies the requirements of `&mut *destLen`
1246/// * Either
1247///     - `dest` is `NULL`
1248///     - `dest` and `*destLen` satisfy the requirements of [`core::slice::from_raw_parts_mut::<MaybeUninit<u8>>`]
1249/// * Either
1250///     - `source` is `NULL`
1251///     - `source` and `sourceLen` satisfy the requirements of [`core::slice::from_raw_parts`]
1252#[cfg_attr(feature = "export-symbols", export_name = prefix!(compress2))]
1253pub unsafe extern "C-unwind" fn compress2(
1254    dest: *mut Bytef,
1255    destLen: *mut c_ulong,
1256    source: *const Bytef,
1257    sourceLen: c_ulong,
1258    level: c_int,
1259) -> c_int {
1260    // stock zlib will just dereference a NULL pointer: that's UB.
1261    // Hence us returning an error value is compatible
1262    let Some(destLen) = (unsafe { destLen.as_mut() }) else {
1263        return ReturnCode::StreamError as _;
1264    };
1265
1266    let Some(output) = (unsafe { slice_from_raw_parts_uninit_mut(dest, *destLen as usize) }) else {
1267        return ReturnCode::StreamError as _;
1268    };
1269
1270    let Some(input) = (unsafe { slice_from_raw_parts(source, sourceLen as usize) }) else {
1271        return ReturnCode::StreamError as _;
1272    };
1273
1274    let config = DeflateConfig::new(level);
1275    let (output, err) = zlib_rs::deflate::compress(output, input, config);
1276
1277    *destLen = output.len() as c_ulong;
1278
1279    err as c_int
1280}
1281
1282/// Returns an upper bound on the compressed size after [`compress`] or [`compress2`] on `sourceLen` bytes.
1283///
1284/// Can be used before a [`compress`] or [`compress2`] call to allocate the destination buffer.
1285#[cfg_attr(feature = "export-symbols", export_name = prefix!(compressBound))]
1286pub extern "C-unwind" fn compressBound(sourceLen: c_ulong) -> c_ulong {
1287    zlib_rs::deflate::compress_bound(sourceLen as usize) as c_ulong
1288}
1289
1290/// Deallocates all dynamically allocated data structures for this stream.
1291///
1292/// This function discards any unprocessed input and does not flush any pending output.
1293///
1294/// # Returns
1295///
1296/// - [`Z_OK`] if success
1297/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
1298/// - [`Z_DATA_ERROR`] if the stream was freed prematurely (some input or output was discarded)
1299///
1300/// In the error case, `strm.msg` may be set but then points to a static string (which must not be deallocated).
1301///
1302/// # Safety
1303///
1304/// * Either
1305///     - `strm` is `NULL`
1306///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1307#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateEnd))]
1308pub unsafe extern "C-unwind" fn deflateEnd(strm: *mut z_stream) -> i32 {
1309    match DeflateStream::from_stream_mut(strm) {
1310        Some(stream) => match zlib_rs::deflate::end(stream) {
1311            Ok(_) => ReturnCode::Ok as _,
1312            Err(_) => ReturnCode::DataError as _,
1313        },
1314        None => ReturnCode::StreamError as _,
1315    }
1316}
1317
1318/// This function is equivalent to [`deflateEnd`] followed by [`deflateInit_`], but does not free and reallocate the internal compression state.
1319///
1320/// This function will leave the compression level and any other attributes that may have been set unchanged.
1321/// The stream's `total_in`, `total_out`, `adler`, and `msg` fields are initialized.
1322///
1323/// ## Returns
1324///
1325/// - [`Z_OK`] if success
1326/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
1327///
1328/// ## Safety
1329///
1330/// The caller must guarantee that
1331///
1332/// * Either
1333///     - `strm` is `NULL`
1334///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1335#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateReset))]
1336pub unsafe extern "C-unwind" fn deflateReset(strm: *mut z_stream) -> i32 {
1337    match DeflateStream::from_stream_mut(strm) {
1338        Some(stream) => zlib_rs::deflate::reset(stream) as _,
1339        None => ReturnCode::StreamError as _,
1340    }
1341}
1342
1343/// Dynamically update the compression level and compression strategy.
1344///
1345/// This can be used to switch between compression and straight copy of the input data,
1346/// or to switch to a different kind of input data requiring a different strategy.
1347///
1348/// The interpretation of level and strategy is as in [`deflateInit2_`].
1349///
1350/// # Returns
1351///
1352/// - [`Z_OK`] if success
1353/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent or if a parameter was invalid
1354/// - [`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.
1355///
1356/// Note that in the case of a [`Z_BUF_ERROR`], the parameters are not changed.
1357/// A return value of [`Z_BUF_ERROR`] is not fatal, in which case [`deflateParams`] can be retried with more output space.
1358///
1359/// # Safety
1360///
1361/// The caller must guarantee that
1362///
1363/// * Either
1364///     - `strm` is `NULL`
1365///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1366#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateParams))]
1367pub unsafe extern "C-unwind" fn deflateParams(
1368    strm: z_streamp,
1369    level: c_int,
1370    strategy: c_int,
1371) -> c_int {
1372    let Ok(strategy) = Strategy::try_from(strategy) else {
1373        return ReturnCode::StreamError as _;
1374    };
1375
1376    match DeflateStream::from_stream_mut(strm) {
1377        Some(stream) => zlib_rs::deflate::params(stream, level, strategy) as _,
1378        None => ReturnCode::StreamError as _,
1379    }
1380}
1381
1382/// Initializes the compression dictionary from the given byte sequence without producing any compressed output.
1383///
1384/// This function may be called after [`deflateInit_`], [`deflateInit2_`] or [`deflateReset`]) and before the first call of [`deflate`].
1385///
1386/// # Returns
1387///
1388/// - [`Z_OK`] if success
1389/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
1390///
1391/// # Safety
1392///
1393/// The caller must guarantee that
1394///
1395/// * Either
1396///     - `strm` is `NULL`
1397///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1398/// * Either
1399///     - `dictionary` is `NULL`
1400///     - `dictionary` and `dictLength` satisfy the requirements of [`core::slice::from_raw_parts_mut::<u8>`]
1401#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateSetDictionary))]
1402pub unsafe extern "C-unwind" fn deflateSetDictionary(
1403    strm: z_streamp,
1404    dictionary: *const Bytef,
1405    dictLength: uInt,
1406) -> c_int {
1407    let Some(dictionary) = (unsafe { slice_from_raw_parts(dictionary, dictLength as usize) })
1408    else {
1409        return ReturnCode::StreamError as _;
1410    };
1411
1412    match DeflateStream::from_stream_mut(strm) {
1413        Some(stream) => zlib_rs::deflate::set_dictionary(stream, dictionary) as _,
1414        None => ReturnCode::StreamError as _,
1415    }
1416}
1417
1418/// Inserts bits in the deflate output stream.
1419///
1420/// 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.
1421/// 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`].
1422/// 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.
1423///
1424/// # Returns
1425///
1426/// - [`Z_OK`] if success
1427/// - [`Z_BUF_ERROR`] if there was not enough room in the internal buffer to insert the bits
1428/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent
1429///
1430/// # Safety
1431///
1432/// The caller must guarantee that
1433///
1434/// * Either
1435///     - `strm` is `NULL`
1436///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1437#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflatePrime))]
1438pub unsafe extern "C-unwind" fn deflatePrime(strm: z_streamp, bits: c_int, value: c_int) -> c_int {
1439    match DeflateStream::from_stream_mut(strm) {
1440        Some(stream) => zlib_rs::deflate::prime(stream, bits, value) as _,
1441        None => ReturnCode::StreamError as _,
1442    }
1443}
1444
1445/// Returns the number of bytes and bits of output that have been generated, but not yet provided in the available output.
1446///
1447/// The bytes not provided would be due to the available output space having being consumed.
1448/// 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.
1449/// If pending or bits are `NULL`, then those values are not set.
1450///
1451/// # Returns
1452///
1453/// - [`Z_OK`] if success
1454/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent
1455///
1456/// # Safety
1457///
1458/// The caller must guarantee that
1459///
1460/// * Either
1461///     - `strm` is `NULL`
1462///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1463/// * Either
1464///     - `pending` is `NULL`
1465///     - `pending` satisfies the requirements of [`core::ptr::write::<c_int>`]
1466/// * Either
1467///     - `bits` is `NULL`
1468///     - `bits` satisfies the requirements of [`core::ptr::write::<c_int>`]
1469#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflatePending))]
1470pub unsafe extern "C-unwind" fn deflatePending(
1471    strm: z_streamp,
1472    pending: *mut c_uint,
1473    bits: *mut c_int,
1474) -> c_int {
1475    let Some(stream) = (unsafe { DeflateStream::from_stream_mut(strm) }) else {
1476        return ReturnCode::StreamError as _;
1477    };
1478
1479    let (current_pending, current_bits) = stream.pending();
1480
1481    if let Some(pending) = unsafe { pending.as_mut() } {
1482        *pending = current_pending as c_uint;
1483    }
1484
1485    if let Some(bits) = unsafe { bits.as_mut() } {
1486        *bits = current_bits as c_int;
1487    }
1488
1489    ReturnCode::Ok as _
1490}
1491
1492/// Sets the destination stream as a complete copy of the source stream.
1493///
1494/// 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.
1495/// The streams that will be discarded should then be freed by calling [`deflateEnd`].
1496/// Note that [`deflateCopy`] duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory.
1497///
1498/// # Returns
1499///
1500/// - [`Z_OK`] if success
1501/// - [`Z_MEM_ERROR`] if there was not enough memory
1502/// - [`Z_STREAM_ERROR`] if the source stream state was inconsistent (such as zalloc being NULL)
1503///
1504/// The `msg` field is left unchanged in both source and destination.
1505///
1506/// # Safety
1507///
1508/// The caller must guarantee that
1509///
1510/// * Either
1511///     - `dest` is `NULL`
1512///     - `dest` satisfies the requirements of `&mut *(dest as *mut MaybeUninit<z_stream>)`
1513/// * Either
1514///     - `source` is `NULL`
1515///     - `source` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1516#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateCopy))]
1517pub unsafe extern "C-unwind" fn deflateCopy(dest: z_streamp, source: z_streamp) -> c_int {
1518    let Some(dest) = (unsafe { dest.cast::<MaybeUninit<DeflateStream>>().as_mut() }) else {
1519        return ReturnCode::StreamError as _;
1520    };
1521
1522    let Some(source) = (unsafe { DeflateStream::from_stream_mut(source) }) else {
1523        return ReturnCode::StreamError as _;
1524    };
1525
1526    zlib_rs::deflate::copy(dest, source) as _
1527}
1528
1529/// Initializes the state for compression
1530///
1531///  The stream's `zalloc`, `zfree` and `opaque` fields must be initialized before by the caller.
1532///  If `zalloc` and `zfree` are set to `NULL`, [`deflateInit_`] updates them to use default allocation functions.
1533///  The `total_in`, `total_out`, `adler`, and `msg` fields are initialized.
1534///
1535/// The compression level must be [`Z_DEFAULT_COMPRESSION`], or between `0` and `9`:
1536///
1537/// - level `0` gives no compression at all (the input data is simply copied a block at a time)
1538/// - level `1` gives best speed
1539/// - level `9` gives best compression
1540/// - [`Z_DEFAULT_COMPRESSION`] requests a default compromise between speed and compression (currently equivalent to level `6`).
1541///
1542/// A call to [`deflateInit_`] is equivalent to [`deflateInit2_`] where:
1543///
1544/// - `method` is `8` (deflate)
1545/// - `windowBits` is `15`
1546/// - `memLevel` is `8`
1547/// - `strategy` is `0` (default)
1548///
1549/// # Returns
1550///
1551/// - [`Z_OK`] if success
1552/// - [`Z_MEM_ERROR`] if there was not enough memory
1553/// - [`Z_VERSION_ERROR`] if the zlib library version is incompatible with the version assumed by the caller
1554/// - [`Z_STREAM_ERROR`] if a parameter is invalid, such as a null pointer to the structure
1555///
1556/// # Safety
1557///
1558/// The caller must guarantee that
1559///
1560/// * Either
1561///     - `strm` is `NULL`
1562///     - `strm` satisfies the requirements of `&mut *strm`
1563/// * Either
1564///     - `version` is NULL
1565///     - `version` satisfies the requirements of [`core::ffi::CStr::from_ptr`]
1566/// * If `strm` is not `NULL`, the following fields contain valid values
1567///     - `zalloc`
1568///     - `zfree`
1569///     - `opaque`
1570///
1571/// # Example
1572///
1573/// ```
1574/// use core::mem::MaybeUninit;
1575/// use libz_rs_sys::{z_stream, deflateInit_, zlibVersion, Z_OK};
1576///
1577/// // the zalloc and zfree fields are initialized as zero/NULL.
1578/// // `deflateInit_` will set a default allocation  and deallocation function.
1579/// let mut strm = MaybeUninit::zeroed();
1580///
1581/// let err = unsafe {
1582///     deflateInit_(
1583///         strm.as_mut_ptr(),
1584///         6,
1585///         zlibVersion(),
1586///         core::mem::size_of::<z_stream>() as _,
1587///     )
1588/// };
1589/// assert_eq!(err, Z_OK);
1590///
1591/// // the stream is now fully initialized. Prefer `assume_init_mut` over
1592/// // `assume_init` so the stream does not get moved.
1593/// let strm = unsafe { strm.assume_init_mut() };
1594/// ```
1595#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateInit_))]
1596pub unsafe extern "C-unwind" fn deflateInit_(
1597    strm: z_streamp,
1598    level: c_int,
1599    version: *const c_char,
1600    stream_size: c_int,
1601) -> c_int {
1602    let config = DeflateConfig::new(level);
1603
1604    unsafe {
1605        deflateInit2_(
1606            strm,
1607            level,
1608            config.method as c_int,
1609            config.window_bits,
1610            config.mem_level,
1611            config.strategy as c_int,
1612            version,
1613            stream_size,
1614        )
1615    }
1616}
1617
1618/// Initializes the state for compression
1619///
1620///  The stream's `zalloc`, `zfree` and `opaque` fields must be initialized before by the caller.
1621///  If `zalloc` and `zfree` are set to `NULL`, [`deflateInit_`] updates them to use default allocation functions.
1622///  The `total_in`, `total_out`, `adler`, and `msg` fields are initialized.
1623///
1624/// The compression level must be [`Z_DEFAULT_COMPRESSION`], or between `0` and `9`:
1625///
1626/// - level `0` gives no compression at all (the input data is simply copied a block at a time)
1627/// - level `1` gives best speed
1628/// - level `9` gives best compression
1629/// - [`Z_DEFAULT_COMPRESSION`] requests a default compromise between speed and compression (currently equivalent to level `6`).
1630///
1631/// # Returns
1632///
1633/// - [`Z_OK`] if success
1634/// - [`Z_MEM_ERROR`] if there was not enough memory
1635/// - [`Z_VERSION_ERROR`] if the zlib library version is incompatible with the version assumed by the caller
1636/// - [`Z_STREAM_ERROR`] if a parameter is invalid, such as a null pointer to the structure
1637///
1638/// # Safety
1639///
1640/// The caller must guarantee that
1641///
1642/// * Either
1643///     - `strm` is `NULL`
1644///     - `strm` satisfies the requirements of `&mut *strm`
1645/// * Either
1646///     - `version` is NULL
1647///     - `version` satisfies the requirements of [`core::ffi::CStr::from_ptr`]
1648/// * If `strm` is not `NULL`, the following fields contain valid values
1649///     - `zalloc`
1650///     - `zfree`
1651///     - `opaque`
1652///
1653/// # Example
1654///
1655/// ```
1656/// use core::mem::MaybeUninit;
1657/// use libz_rs_sys::{z_stream, deflateInit2_, zlibVersion, Z_OK};
1658///
1659/// // the zalloc and zfree fields are initialized as zero/NULL.
1660/// // `deflateInit_` will set a default allocation  and deallocation function.
1661/// let mut strm = MaybeUninit::zeroed();
1662///
1663/// let err = unsafe {
1664///     deflateInit2_(
1665///         strm.as_mut_ptr(),
1666///         6,
1667///         8,
1668///         15,
1669///         8,
1670///         0,
1671///         zlibVersion(),
1672///         core::mem::size_of::<z_stream>() as _,
1673///     )
1674/// };
1675/// assert_eq!(err, Z_OK);
1676///
1677/// // the stream is now fully initialized. Prefer `assume_init_mut` over
1678/// // `assume_init` so the stream does not get moved.
1679/// let strm = unsafe { strm.assume_init_mut() };
1680/// ```
1681#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateInit2_))]
1682pub unsafe extern "C-unwind" fn deflateInit2_(
1683    strm: z_streamp,
1684    level: c_int,
1685    method: c_int,
1686    windowBits: c_int,
1687    memLevel: c_int,
1688    strategy: c_int,
1689    version: *const c_char,
1690    stream_size: c_int,
1691) -> c_int {
1692    if !is_version_compatible(version, stream_size) {
1693        return ReturnCode::VersionError as _;
1694    }
1695
1696    let Some(strm) = (unsafe { strm.as_mut() }) else {
1697        return ReturnCode::StreamError as _;
1698    };
1699
1700    let Ok(method) = Method::try_from(method) else {
1701        return ReturnCode::StreamError as _;
1702    };
1703
1704    let Ok(strategy) = Strategy::try_from(strategy) else {
1705        return ReturnCode::StreamError as _;
1706    };
1707
1708    let config = DeflateConfig {
1709        level,
1710        method,
1711        window_bits: windowBits,
1712        mem_level: memLevel,
1713        strategy,
1714    };
1715
1716    zlib_rs::deflate::init(strm, config) as _
1717}
1718
1719/// Fine tune deflate's internal compression parameters.
1720///
1721/// This should only be used by someone who understands the algorithm used by zlib's deflate for searching
1722/// for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out
1723/// the last compressed bit for their specific input data. Read the `deflate.rs` source code for the meaning
1724/// of the `max_lazy`, `good_length`, `nice_length`, and `max_chain` parameters.
1725///
1726/// ## Returns
1727///
1728/// - [`Z_OK`] if success
1729/// - [`Z_STREAM_ERROR`] if the stream state was inconsistent
1730///
1731/// # Safety
1732///
1733/// The caller must guarantee that
1734///
1735/// * Either
1736///     - `strm` is `NULL`
1737///     - `strm` satisfies the requirements of `&mut *strm` and was initialized with [`deflateInit_`] or similar
1738#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateTune))]
1739pub unsafe extern "C-unwind" fn deflateTune(
1740    strm: z_streamp,
1741    good_length: c_int,
1742    max_lazy: c_int,
1743    nice_length: c_int,
1744    max_chain: c_int,
1745) -> c_int {
1746    let Some(stream) = (unsafe { DeflateStream::from_stream_mut(strm) }) else {
1747        return ReturnCode::StreamError as _;
1748    };
1749
1750    zlib_rs::deflate::tune(
1751        stream,
1752        good_length as usize,
1753        max_lazy as usize,
1754        nice_length as usize,
1755        max_chain as usize,
1756    ) as _
1757}
1758
1759/// Get the error message for an error. This could be the value returned by e.g. [`compress`] or
1760/// [`inflate`].
1761///
1762/// The return value is a pointer to a NULL-terminated sequence of bytes
1763///
1764/// ## Example
1765///
1766/// ```
1767/// use libz_rs_sys::*;
1768/// use core::ffi::{c_char, CStr};
1769///
1770/// fn cstr<'a>(ptr: *const c_char) -> &'a [u8] {
1771///     // SAFETY: we trust the input
1772///     unsafe { CStr::from_ptr(ptr) }.to_bytes()
1773/// }
1774///
1775/// // defined error values give a short message
1776/// assert_eq!(cstr(zError(Z_NEED_DICT)), b"need dictionary");
1777/// assert_eq!(cstr(zError(Z_NEED_DICT)), b"need dictionary");
1778/// assert_eq!(cstr(zError(Z_STREAM_END)), b"stream end");
1779/// assert_eq!(cstr(zError(Z_OK)), b"");
1780/// assert_eq!(cstr(zError(Z_ERRNO)), b"file error");
1781/// assert_eq!(cstr(zError(Z_STREAM_ERROR)), b"stream error");
1782/// assert_eq!(cstr(zError(Z_DATA_ERROR)), b"data error");
1783/// assert_eq!(cstr(zError(Z_MEM_ERROR)), b"insufficient memory");
1784/// assert_eq!(cstr(zError(Z_BUF_ERROR)), b"buffer error");
1785/// assert_eq!(cstr(zError(Z_VERSION_ERROR)), b"incompatible version");
1786///
1787/// // other inputs return an empty string
1788/// assert_eq!(cstr(zError(1234)), b"");
1789/// ```
1790#[cfg_attr(feature = "export-symbols", export_name = prefix!(zError))]
1791pub const extern "C" fn zError(err: c_int) -> *const c_char {
1792    match ReturnCode::try_from_c_int(err) {
1793        Some(return_code) => return_code.error_message(),
1794        None => [0 as c_char].as_ptr(),
1795    }
1796}
1797
1798macro_rules! libz_rs_sys_version {
1799    () => {
1800        concat!("1.3.0-zlib-rs-", env!("CARGO_PKG_VERSION"), "\0")
1801    };
1802}
1803
1804// the first part of this version specifies the zlib that we're compatible with (in terms of
1805// supported functions). In practice in most cases only the major version is checked, unless
1806// specific functions that were added later are used.
1807const LIBZ_RS_SYS_VERSION: &str = concat!(libz_rs_sys_version!(), "\0");
1808
1809unsafe fn is_version_compatible(version: *const c_char, stream_size: i32) -> bool {
1810    let Some(expected_major_version) = (unsafe { version.as_ref() }) else {
1811        return false;
1812    };
1813
1814    if *expected_major_version as u8 != LIBZ_RS_SYS_VERSION.as_bytes()[0] {
1815        return false;
1816    }
1817
1818    core::mem::size_of::<z_stream>() as i32 == stream_size
1819}
1820
1821/// The version of the zlib library.
1822///
1823/// Its value is a pointer to a NULL-terminated sequence of bytes.
1824///
1825/// The version string for this release is `
1826#[doc = libz_rs_sys_version!()]
1827/// `:
1828///
1829/// - The first component is the version of stock zlib that this release is compatible with
1830/// - The final component is the zlib-rs version used to build this release.
1831#[cfg_attr(feature = "export-symbols", export_name = prefix!(zlibVersion))]
1832pub const extern "C" fn zlibVersion() -> *const c_char {
1833    LIBZ_RS_SYS_VERSION.as_ptr().cast::<c_char>()
1834}
1835
1836/// Return flags indicating compile-time options.
1837///
1838/// Type sizes, two bits each, `0b00` = 16 bits, `0b01` = 32, `0b10` = 64, `0b11` = other:
1839///
1840/// | bits | description |
1841/// | -- | -- |
1842/// | `0..=1` | size of [`uInt`] |
1843/// | `2..=3` | size of [`uLong`] |
1844/// | `4..=5` | size of [`voidpf`] (pointer) |
1845/// | `6..=7` | size of [`z_off_t`] |
1846///
1847/// Compiler, assembler, and debug options:
1848///
1849/// | bits | flag | description |
1850/// | -- | -- | -- |
1851/// | `8`     | `ZLIB_DEBUG` | debug prints are enabled |
1852/// | `9`     | `ASMV` or `ASMINF` | use ASM code |
1853/// | `10`    | `ZLIB_WINAPI` | exported functions use the WINAPI calling convention |
1854/// | `11`    | | reserved |
1855///
1856/// One-time table building (smaller code, but not thread-safe if true):
1857///
1858/// | bits | flag | description |
1859/// | -- | -- | -- |
1860/// | `12` | `BUILDFIXED` | build static block decoding tables when needed |
1861/// | `13` | `DYNAMIC_CRC_TABLE` | build CRC calculation tables when needed |
1862/// | `14`    | | reserved |
1863/// | `15`    | | reserved |
1864///
1865/// Library content (indicates missing functionality):
1866///
1867/// | bits | flag | description |
1868/// | -- | -- | -- |
1869/// | `16` | `NO_GZCOMPRESS` | `gz*` functions cannot compress (to avoid linking deflate code when not needed) |
1870/// | `17` | `NO_GZIP` | deflate can't write gzip streams, and inflate can't detect and decode gzip streams (to avoid linking crc code) |
1871/// | `18`    | | reserved |
1872/// | `19`    | | reserved |
1873///
1874/// Operation variations (changes in library functionality):
1875///
1876/// | bits | flag | description |
1877/// | -- | -- | -- |
1878/// | `20` | `PKZIP_BUG_WORKAROUND` | slightly more permissive inflate |
1879/// | `21` | `FASTEST` | deflate algorithm with only one, lowest compression level |
1880/// | `22`    | | reserved |
1881/// | `23`    | | reserved |
1882///
1883/// The sprintf variant used by `gzprintf` (zero is best):
1884///
1885/// | bits | value | description |
1886/// | -- | -- | -- |
1887/// | `24` | 0 = vs*, 1 = s* | 1 means limited to 20 arguments after the format |
1888/// | `25` | 0 = *nprintf, 1 = *printf | 1 means `gzprintf` not secure! |
1889/// | `26` | 0 = returns value, 1 = void | 1 means inferred string length returned |
1890///
1891/// Remainder:
1892///
1893/// The remaining bits `27..=31` are 0 (reserved).
1894#[cfg_attr(feature = "export-symbols", export_name = prefix!(zlibCompileFlags))]
1895pub const extern "C" fn zlibCompileFlags() -> c_ulong {
1896    let mut flags = 0;
1897
1898    const fn encode_size<T>() -> c_ulong {
1899        match core::mem::size_of::<T>() {
1900            2 => 0b00,
1901            4 => 0b01,
1902            8 => 0b10,
1903            _ => 0b11,
1904        }
1905    }
1906
1907    flags |= encode_size::<uInt>();
1908    flags |= encode_size::<uLong>() << 2;
1909    flags |= encode_size::<voidpf>() << 4;
1910    flags |= encode_size::<z_off_t>() << 6;
1911
1912    macro_rules! set_bit {
1913        ($i:expr, $v:expr) => {
1914            flags |= (($v as uLong) << $i);
1915        };
1916    }
1917
1918    // Compiler, assembler, debug:
1919    set_bit!(8, false); // ZLIB_DEBUG
1920    set_bit!(9, false); // ASMV || ASMINF
1921    set_bit!(10, false); // ZLIB_WINAPI
1922
1923    // One-time table building:
1924    set_bit!(12, false); // BUILDFIXED
1925    set_bit!(13, false); // DYNAMIC_CRC_TABLE
1926
1927    // Library content (indicates missing functionality):
1928    set_bit!(16, false); // NO_GZCOMPRESS
1929    set_bit!(17, false); // NO_GZIP
1930
1931    // Operation variations (changes in library functionality):
1932    set_bit!(20, false); // PKZIP_BUG_WORKAROUND
1933    set_bit!(21, false); // FASTEST
1934
1935    // The sprintf variant used by gzprintf (we assume a modern libc):
1936    set_bit!(24, false);
1937    set_bit!(25, false);
1938    set_bit!(26, false);
1939
1940    flags
1941}
1942
1943/// Returns the sliding dictionary being maintained by inflate.  
1944///
1945/// `dictLength` is set to the number of bytes in the dictionary, and that many bytes are copied
1946/// to `dictionary`. `dictionary` must have enough space, where `32768` bytes is
1947/// always enough.  If [`inflateGetDictionary`] is called with `dictionary` equal to
1948/// `NULL`, then only the dictionary length is returned, and nothing is copied.
1949/// Similarly, if `dictLength` is `NULL`, then it is not set.
1950///
1951/// # Returns
1952///
1953/// * [`Z_OK`] if success
1954/// * [`Z_STREAM_ERROR`] if the stream state is inconsistent
1955///
1956/// # Safety
1957///
1958/// - `dictionary` must `NULL` or writable for the dictionary length (`32768` is always enough)
1959/// - `dictLength` must `NULL` or satisfy the requirements of [`pointer::as_mut`]
1960///
1961/// [`pointer::as_mut`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.as_mut
1962#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateGetDictionary))]
1963pub unsafe extern "C-unwind" fn inflateGetDictionary(
1964    strm: *const z_stream,
1965    dictionary: *mut c_uchar,
1966    dictLength: *mut c_uint,
1967) -> c_int {
1968    let Some(stream) = InflateStream::from_stream_ref(strm) else {
1969        return ReturnCode::StreamError as c_int;
1970    };
1971
1972    let whave = zlib_rs::inflate::get_dictionary(stream, dictionary);
1973
1974    if let Some(dictLength) = unsafe { dictLength.as_mut() } {
1975        *dictLength = whave as c_uint;
1976    }
1977
1978    ReturnCode::Ok as _
1979}
1980
1981/// Returns the sliding dictionary being maintained by deflate.  
1982///
1983/// `dictLength` is set to the number of bytes in the dictionary, and that many bytes are copied
1984/// to `dictionary`. `dictionary` must have enough space, where `32768` bytes is
1985/// always enough.  If [`deflateGetDictionary`] is called with `dictionary` equal to
1986/// `NULL`, then only the dictionary length is returned, and nothing is copied.
1987/// Similarly, if `dictLength` is `NULL`, then it is not set.
1988///
1989/// [`deflateGetDictionary`] may return a length less than the window size, even
1990/// when more than the window size in input has been provided. It may return up
1991/// to 258 bytes less in that case, due to how zlib's implementation of deflate
1992/// manages the sliding window and lookahead for matches, where matches can be
1993/// up to 258 bytes long. If the application needs the last window-size bytes of
1994/// input, then that would need to be saved by the application outside of zlib.
1995///
1996/// # Returns
1997///
1998/// * [`Z_OK`] if success
1999/// * [`Z_STREAM_ERROR`] if the stream state is inconsistent
2000///
2001/// # Safety
2002///
2003/// - `dictionary` must `NULL` or writable for the dictionary length (`32768` is always enough)
2004/// - `dictLength` must `NULL` or satisfy the requirements of [`pointer::as_mut`]
2005///
2006/// [`pointer::as_mut`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.as_mut
2007#[cfg_attr(feature = "export-symbols", export_name = prefix!(deflateGetDictionary))]
2008pub unsafe extern "C-unwind" fn deflateGetDictionary(
2009    strm: *const z_stream,
2010    dictionary: *mut c_uchar,
2011    dictLength: *mut c_uint,
2012) -> c_int {
2013    let Some(stream) = DeflateStream::from_stream_ref(strm) else {
2014        return ReturnCode::StreamError as c_int;
2015    };
2016
2017    let len = zlib_rs::deflate::get_dictionary(stream, dictionary);
2018
2019    if let Some(dictLength) = unsafe { dictLength.as_mut() } {
2020        *dictLength = len as c_uint;
2021    }
2022
2023    ReturnCode::Ok as _
2024}
2025
2026/// # Safety
2027///
2028/// Either
2029///
2030/// - `ptr` is `NULL`
2031/// - `ptr` and `len` satisfy the requirements of [`core::slice::from_raw_parts`]
2032unsafe fn slice_from_raw_parts<'a, T>(ptr: *const T, len: usize) -> Option<&'a [T]> {
2033    if ptr.is_null() {
2034        None
2035    } else {
2036        Some(unsafe { core::slice::from_raw_parts(ptr, len) })
2037    }
2038}
2039
2040/// # Safety
2041///
2042/// Either
2043///
2044/// - `ptr` is `NULL`
2045/// - `ptr` and `len` satisfy the requirements of [`core::slice::from_raw_parts_mut`]
2046unsafe fn slice_from_raw_parts_uninit_mut<'a, T>(
2047    ptr: *mut T,
2048    len: usize,
2049) -> Option<&'a mut [MaybeUninit<T>]> {
2050    if ptr.is_null() {
2051        None
2052    } else {
2053        Some(unsafe { core::slice::from_raw_parts_mut(ptr.cast::<MaybeUninit<T>>(), len) })
2054    }
2055}