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