Skip to main content

zlib_rs/
lib.rs

1#![doc = core::include_str!("../README.md")]
2#![cfg_attr(not(any(test, feature = "rust-allocator")), no_std)]
3#![cfg_attr(
4    all(any(miri, feature = "lsx"), target_arch = "loongarch64"),
5    feature(stdarch_loongarch)
6)]
7
8#[cfg(any(feature = "rust-allocator", feature = "c-allocator"))]
9extern crate alloc;
10
11pub mod adler32;
12pub mod crc32;
13
14cfg_select! {
15    feature = "__internal-api" => {
16        pub mod allocate;
17        pub mod c_api;
18        pub mod deflate;
19        pub mod inflate;
20
21        pub const MIN_WBITS: i32 = 8; // 256b LZ77 window
22        pub const MAX_WBITS: i32 = 15; // 32kb LZ77 window
23    }
24    _ => {
25        pub(crate) mod allocate;
26        pub(crate) mod c_api;
27        pub(crate) mod deflate;
28        pub(crate) mod inflate;
29
30        pub(crate) const MIN_WBITS: i32 = 8; // 256b LZ77 window
31        pub(crate) const MAX_WBITS: i32 = 15; // 32kb LZ77 window
32    }
33}
34
35mod cpu_features;
36mod stable;
37mod weak_slice;
38
39pub use stable::{Deflate, DeflateError, Inflate, InflateError, Status};
40
41pub use deflate::{DeflateConfig, Method, Strategy};
42pub use inflate::InflateConfig;
43
44pub use deflate::{compress_bound, compress_slice};
45pub use inflate::decompress_slice;
46
47macro_rules! traceln {
48    ($($arg:tt)*) => {
49        #[cfg(feature = "ZLIB_DEBUG")]
50        {
51            eprintln!($($arg)*)
52        }
53    };
54}
55pub(crate) use traceln;
56
57macro_rules! trace {
58    ($($arg:tt)*) => {
59        #[cfg(feature = "ZLIB_DEBUG")]
60        {
61            eprint!($($arg)*)
62        }
63    };
64}
65pub(crate) use trace;
66
67macro_rules! cfg_select {
68    ({ $($tt:tt)* }) => {{
69        $crate::cfg_select! { $($tt)* }
70    }};
71    (_ => { $($output:tt)* }) => {
72        $($output)*
73    };
74    (
75        $cfg:meta => $output:tt
76        $($( $rest:tt )+)?
77    ) => {
78        #[cfg($cfg)]
79        $crate::cfg_select! { _ => $output }
80        $(
81            #[cfg(not($cfg))]
82            $crate::cfg_select! { $($rest)+ }
83        )?
84    }
85}
86use cfg_select;
87
88/// Maximum size of the dynamic table.  The maximum number of code structures is
89/// 1924, which is the sum of 1332 for literal/length codes and 592 for distance
90/// codes.  These values were found by exhaustive searches using the program
91/// examples/enough.c found in the zlib distributions.  The arguments to that
92/// program are the number of symbols, the initial root table size, and the
93/// maximum bit length of a code.  "enough 286 10 15" for literal/length codes
94/// returns 1332, and "enough 30 9 15" for distance codes returns 592.
95/// The initial root table size (10 or 9) is found in the fifth argument of the
96/// inflate_table() calls in inflate.c and infback.c.  If the root table size is
97/// changed, then these maximum sizes would be need to be recalculated and
98/// updated.
99#[allow(unused)]
100pub(crate) const ENOUGH: usize = ENOUGH_LENS + ENOUGH_DISTS;
101pub(crate) const ENOUGH_LENS: usize = 1332;
102pub(crate) const ENOUGH_DISTS: usize = 592;
103
104/// initial adler-32 hash value
105pub(crate) const ADLER32_INITIAL_VALUE: usize = 1;
106/// initial crc-32 hash value
107pub(crate) const CRC32_INITIAL_VALUE: u32 = 0;
108
109pub(crate) const DEF_WBITS: i32 = MAX_WBITS;
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
112#[cfg_attr(feature = "__internal-fuzz", derive(arbitrary::Arbitrary))]
113pub enum DeflateFlush {
114    #[default]
115    /// if flush is set to `NoFlush`, that allows deflate to decide how much data
116    /// to accumulate before producing output, in order to maximize compression.
117    NoFlush = 0,
118
119    /// If flush is set to `PartialFlush`, all pending output is flushed to the
120    /// output buffer, but the output is not aligned to a byte boundary.  All of the
121    /// input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
122    /// This completes the current deflate block and follows it with an empty fixed
123    /// codes block that is 10 bits long.  This assures that enough bytes are output
124    /// in order for the decompressor to finish the block before the empty fixed
125    /// codes block.
126    PartialFlush = 1,
127
128    /// If the parameter flush is set to `SyncFlush`, all pending output is
129    /// flushed to the output buffer and the output is aligned on a byte boundary, so
130    /// that the decompressor can get all input data available so far.  (In
131    /// particular avail_in is zero after the call if enough output space has been
132    /// provided before the call.) Flushing may degrade compression for some
133    /// compression algorithms and so it should be used only when necessary.  This
134    /// completes the current deflate block and follows it with an empty stored block
135    /// that is three bits plus filler bits to the next byte, followed by four bytes
136    /// (00 00 ff ff).
137    SyncFlush = 2,
138
139    /// If flush is set to `FullFlush`, all output is flushed as with
140    /// Z_SYNC_FLUSH, and the compression state is reset so that decompression can
141    /// restart from this point if previous compressed data has been damaged or if
142    /// random access is desired.  Using `FullFlush` too often can seriously degrade
143    /// compression.
144    FullFlush = 3,
145
146    /// If the parameter flush is set to `Finish`, pending input is processed,
147    /// pending output is flushed and deflate returns with `StreamEnd` if there was
148    /// enough output space.  If deflate returns with `Ok` or `BufError`, this
149    /// function must be called again with `Finish` and more output space (updated
150    /// avail_out) but no more input data, until it returns with `StreamEnd` or an
151    /// error.  After deflate has returned `StreamEnd`, the only possible operations
152    /// on the stream are deflateReset or deflateEnd.
153    ///
154    /// `Finish` can be used in the first deflate call after deflateInit if all the
155    /// compression is to be done in a single step.  In order to complete in one
156    /// call, avail_out must be at least the value returned by deflateBound (see
157    /// below).  Then deflate is guaranteed to return `StreamEnd`.  If not enough
158    /// output space is provided, deflate will not return `StreamEnd`, and it must
159    /// be called again as described above.
160    Finish = 4,
161
162    /// If flush is set to `Block`, a deflate block is completed and emitted, as
163    /// for `SyncFlush`, but the output is not aligned on a byte boundary, and up to
164    /// seven bits of the current block are held to be written as the next byte after
165    /// the next deflate block is completed.  In this case, the decompressor may not
166    /// be provided enough bits at this point in order to complete decompression of
167    /// the data provided so far to the compressor.  It may need to wait for the next
168    /// block to be emitted.  This is for advanced applications that need to control
169    /// the emission of deflate blocks.
170    Block = 5,
171}
172
173impl TryFrom<i32> for DeflateFlush {
174    type Error = ();
175
176    fn try_from(value: i32) -> Result<Self, Self::Error> {
177        match value {
178            0 => Ok(Self::NoFlush),
179            1 => Ok(Self::PartialFlush),
180            2 => Ok(Self::SyncFlush),
181            3 => Ok(Self::FullFlush),
182            4 => Ok(Self::Finish),
183            5 => Ok(Self::Block),
184            _ => Err(()),
185        }
186    }
187}
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
190pub enum InflateFlush {
191    #[default]
192    NoFlush = 0,
193    SyncFlush = 2,
194    Finish = 4,
195    Block = 5,
196    Trees = 6,
197}
198
199impl TryFrom<i32> for InflateFlush {
200    type Error = ();
201
202    fn try_from(value: i32) -> Result<Self, Self::Error> {
203        match value {
204            0 => Ok(Self::NoFlush),
205            2 => Ok(Self::SyncFlush),
206            4 => Ok(Self::Finish),
207            5 => Ok(Self::Block),
208            6 => Ok(Self::Trees),
209            _ => Err(()),
210        }
211    }
212}
213
214#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
215pub(crate) struct Code {
216    /// operation, extra bits, table bits
217    pub op: u8,
218    /// bits in this part of the code
219    pub bits: u8,
220    /// offset in table or code value
221    pub val: u16,
222}
223
224#[derive(Debug, Copy, Clone, PartialEq, Eq)]
225#[repr(i32)]
226pub enum ReturnCode {
227    Ok = 0,
228    StreamEnd = 1,
229    NeedDict = 2,
230    ErrNo = -1,
231    StreamError = -2,
232    DataError = -3,
233    MemError = -4,
234    BufError = -5,
235    VersionError = -6,
236}
237
238impl From<i32> for ReturnCode {
239    fn from(value: i32) -> Self {
240        match Self::try_from_c_int(value) {
241            Some(value) => value,
242            None => panic!("invalid return code {value}"),
243        }
244    }
245}
246
247impl ReturnCode {
248    fn error_message_str(self) -> &'static str {
249        self.error_message_str_with_null().trim_end_matches('\0')
250    }
251
252    const fn error_message_str_with_null(self) -> &'static str {
253        match self {
254            ReturnCode::Ok => "\0",
255            ReturnCode::StreamEnd => "stream end\0",
256            ReturnCode::NeedDict => "need dictionary\0",
257            ReturnCode::ErrNo => "file error\0",
258            ReturnCode::StreamError => "stream error\0",
259            ReturnCode::DataError => "data error\0",
260            ReturnCode::MemError => "insufficient memory\0",
261            ReturnCode::BufError => "buffer error\0",
262            ReturnCode::VersionError => "incompatible version\0",
263        }
264    }
265
266    pub const fn error_message(self) -> *const core::ffi::c_char {
267        let msg = self.error_message_str_with_null();
268        msg.as_ptr().cast::<core::ffi::c_char>()
269    }
270
271    pub const fn try_from_c_int(err: core::ffi::c_int) -> Option<Self> {
272        match err {
273            0 => Some(Self::Ok),
274            1 => Some(Self::StreamEnd),
275            2 => Some(Self::NeedDict),
276            -1 => Some(Self::ErrNo),
277            -2 => Some(Self::StreamError),
278            -3 => Some(Self::DataError),
279            -4 => Some(Self::MemError),
280            -5 => Some(Self::BufError),
281            -6 => Some(Self::VersionError),
282            _ => None,
283        }
284    }
285}