libz_rs_sys/
lib.rs

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