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