libz_rs_sys/
lib.rs

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