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