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