Skip to main content

miniz_oxide/deflate/
core.rs

1//! Streaming compression functionality.
2
3use alloc::boxed::Box;
4#[cfg(target_arch = "wasm32")]
5use alloc::vec;
6use core::convert::TryInto;
7use core::{cmp, mem};
8
9use super::super::*;
10use super::deflate_flags::*;
11use super::CompressionLevel;
12use crate::deflate::buffer::{
13    update_hash, HashBuffers, LocalBuf, LZ_CODE_BUF_MASK, LZ_CODE_BUF_SIZE, LZ_DICT_FULL_SIZE,
14    LZ_HASH_BITS, LZ_HASH_SHIFT, LZ_HASH_SIZE, OUT_BUF_SIZE,
15};
16use crate::deflate::stored::compress_stored;
17use crate::deflate::zlib;
18use crate::shared::{update_adler32, HUFFMAN_LENGTH_ORDER, MZ_ADLER32_INIT};
19use crate::DataFormat;
20
21// Currently not bubbled up outside this module, so can fill in with more
22// context eventually if needed.
23type Result<T, E = Error> = core::result::Result<T, E>;
24pub(crate) struct Error {}
25
26pub(crate) const MAX_PROBES_MASK: u32 = 0xFFF;
27
28const MAX_SUPPORTED_HUFF_CODESIZE: usize = 15;
29
30// Length code for length values - 256.
31// We use an offset to help with bound check avoidance as we can mask values to 32
32// and it also saves some memory as we can use a u8 instead of a u16.
33// Conventiently our table is large enough that we can get away with using an
34// offset of 256 which results in very efficient code.
35const LEN_SYM: [u8; 256] = [
36    1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15,
37    15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19,
38    19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
39    21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23,
40    23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
41    24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
42    25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
43    26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27,
44    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
45    27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
46    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29,
47];
48
49const LEN_SYM_OFFSET: usize = 256;
50
51/// Number of extra bits for length values.
52#[rustfmt::skip]
53const LEN_EXTRA: [u8; 256] = [
54    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
55    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
56    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
57    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
58    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
59    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
60    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
61    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
62    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
63    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
64    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
65    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
66    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
67    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
68    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
69    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0
70];
71
72/// Distance codes for distances smaller than 512.
73#[rustfmt::skip]
74const SMALL_DIST_SYM: [u8; 512] = [
75     0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,
76     8,  8,  8,  8,  8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9,
77    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
78    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
79    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
80    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
81    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
82    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
83    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
84    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
85    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
86    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
87    15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
88    15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
89    15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
90    15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
91    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
92    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
93    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
94    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
95    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
96    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
97    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
98    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
99    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
100    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
101    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
102    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
103    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
104    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
105    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
106    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
107];
108
109// /// Number of extra bits for distances smaller than 512.
110/*#[rustfmt::skip]
111const SMALL_DIST_EXTRA: [u8; 512] = [
112    0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
113    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
114    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
115    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
116    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
117    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
118    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
119    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
120    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
121    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
122    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
123    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
124    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
125    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
126    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
127    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
128];*/
129
130/// Number of extra bits for distances smaller than 512.
131/// Reduced by 4 using bit shift
132#[rustfmt::skip]
133const SMALL_DIST_EXTRA: [u8; 128] = [
134    0, 1, 2, 2, 3, 3, 3, 3,
135    4, 4, 4, 4, 4, 4, 4, 4,
136    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
137    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
138    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
139    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
140];
141
142/// Base values to calculate distances above 512.
143#[rustfmt::skip]
144const LARGE_DIST_SYM: [u8; 128] = [
145     0,  0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
146    24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25,
147    26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
148    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
149    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
150    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
151    29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
152    29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
153];
154
155/// Number of extra bits distances above 512.
156#[rustfmt::skip]
157const LARGE_DIST_EXTRA: [u8; 128] = [
158     0,  0,  8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
159    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
160    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
161    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
162    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
163    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
164    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
165    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13
166];
167
168#[rustfmt::skip]
169const BITMASKS: [u32; 17] = [
170    0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
171    0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
172];
173
174/// The maximum number of checks for matches in the hash table the compressor will make for each
175/// compression level.
176pub(crate) const NUM_PROBES: [u16; 11] = [0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500];
177
178#[derive(Copy, Clone)]
179struct SymFreq {
180    key: u16,
181    sym_index: u16,
182}
183
184pub mod deflate_flags {
185    /// Whether to use a zlib wrapper.
186    pub const TDEFL_WRITE_ZLIB_HEADER: u32 = 0x0000_1000;
187    /// Should we compute the adler32 checksum.
188    pub const TDEFL_COMPUTE_ADLER32: u32 = 0x0000_2000;
189    /// Should we use greedy parsing (as opposed to lazy parsing where look ahead one or more
190    /// bytes to check for better matches.)
191    pub const TDEFL_GREEDY_PARSING_FLAG: u32 = 0x0000_4000;
192    /// Used in miniz to skip zero-initializing hash and dict. We don't do this here, so
193    /// this flag is ignored.
194    pub const TDEFL_NONDETERMINISTIC_PARSING_FLAG: u32 = 0x0000_8000;
195    /// Only look for matches with a distance of 0.
196    pub const TDEFL_RLE_MATCHES: u32 = 0x0001_0000;
197    /// Only use matches that are at least 6 bytes long.
198    pub const TDEFL_FILTER_MATCHES: u32 = 0x0002_0000;
199    /// Force the compressor to only output static blocks. (Blocks using the default huffman codes
200    /// specified in the deflate specification.)
201    pub const TDEFL_FORCE_ALL_STATIC_BLOCKS: u32 = 0x0004_0000;
202    /// Force the compressor to only output raw/uncompressed blocks.
203    pub const TDEFL_FORCE_ALL_RAW_BLOCKS: u32 = 0x0008_0000;
204}
205
206/// Strategy setting for compression.
207///
208/// The non-default settings offer some special-case compression variants.
209#[repr(i32)]
210#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
211#[non_exhaustive]
212pub enum CompressionStrategy {
213    /// Don't use any of the special strategies.
214    Default = 0,
215    /// Only use matches that are at least 5 bytes long.
216    Filtered = 1,
217    /// Don't look for matches, only huffman encode the literals.
218    /// (This is not optimally implemented at the moment and will not provide much of a speedup)
219    HuffmanOnly = 2,
220    /// Only look for matches with a distance of 1, i.e do run-length encoding only.
221    RLE = 3,
222    /// Only use static/fixed blocks. (Blocks using the default huffman codes
223    /// specified in the deflate specification.)
224    Fixed = 4,
225}
226
227impl From<CompressionStrategy> for i32 {
228    #[inline(always)]
229    fn from(value: CompressionStrategy) -> Self {
230        value as i32
231    }
232}
233
234/// A list of deflate flush types.
235#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
236#[non_exhaustive]
237pub enum TDEFLFlush {
238    /// Normal operation.
239    ///
240    /// Compress as much as there is space for, and then return waiting for more input.
241    None = 0,
242
243    /// Try to flush all the current data and output an empty fixed
244    /// block (10 bits) to synchonize the stream.
245    Partial = 1,
246
247    /// Try to flush all the current data and output an empty raw
248    /// block (3-10 bits + 32 bits) to synchonize the stream.
249    Sync = 2,
250
251    /// Same as [`Sync`][Self::Sync], but reset the dictionary so that the following data does not
252    /// depend on previous data.
253    Full = 3,
254
255    /// Try to flush everything and end the deflate stream.
256    ///
257    /// On success this will yield a [`TDEFLStatus::Done`] return status.
258    Finish = 4,
259
260    /// Try to flush all the current data and, if data is unaligned,
261    /// output an empty fixed block (10 bits) to synchonize the
262    /// stream.
263    PartialOpt = 5,
264
265    /// Try to flush all the current data and, if data is unaligned,
266    /// output an empty raw block (3-10 bits + 32 bits) to synchonize
267    /// the stream.
268    SyncOpt = 6,
269
270    /// Try to flush the current data but without any sync, which may
271    /// leave up to 7 bits of data not output.  You can use
272    /// `TDEFLFlush::PartialOpt` or `TDEFLFlush::SyncOpt` to add a
273    /// sync sequence on a future call if you later decide that you
274    /// have space downstream to forward that final byte.
275    NoSync = 7,
276}
277
278impl From<MZFlush> for TDEFLFlush {
279    fn from(flush: MZFlush) -> Self {
280        match flush {
281            MZFlush::None => TDEFLFlush::None,
282            MZFlush::Partial => TDEFLFlush::Partial,
283            MZFlush::Sync => TDEFLFlush::Sync,
284            MZFlush::Full => TDEFLFlush::Full,
285            MZFlush::Finish => TDEFLFlush::Finish,
286            _ => TDEFLFlush::None, // TODO: ??? What to do ???
287        }
288    }
289}
290
291impl TDEFLFlush {
292    pub const fn new(flush: i32) -> Result<Self, MZError> {
293        match flush {
294            0 => Ok(TDEFLFlush::None),
295            1 => Ok(TDEFLFlush::Partial),
296            2 => Ok(TDEFLFlush::Sync),
297            3 => Ok(TDEFLFlush::Full),
298            4 => Ok(TDEFLFlush::Finish),
299            5 => Ok(TDEFLFlush::PartialOpt),
300            6 => Ok(TDEFLFlush::SyncOpt),
301            7 => Ok(TDEFLFlush::NoSync),
302            _ => Err(MZError::Param),
303        }
304    }
305}
306
307/// Return status of compression.
308#[repr(i32)]
309#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
310pub enum TDEFLStatus {
311    /// Usage error.
312    ///
313    /// This indicates that either the [`CompressorOxide`] experienced a previous error, or the
314    /// stream has already been [`TDEFLFlush::Finish`]'d.
315    BadParam = -2,
316
317    /// Error putting data into output buffer.
318    ///
319    /// This usually indicates a too-small buffer.
320    PutBufFailed = -1,
321
322    /// Compression succeeded normally.
323    Okay = 0,
324
325    /// Compression succeeded and the deflate stream was ended.
326    ///
327    /// This is the result of calling compression with [`TDEFLFlush::Finish`].
328    Done = 1,
329}
330
331const MAX_HUFF_SYMBOLS: usize = 288;
332/// Size of hash chain for fast compression mode.
333const LEVEL1_HASH_SIZE_MASK: u32 = 4095;
334/// The number of huffman tables used by the compressor.
335/// Literal/length, Distances and Length of the huffman codes for the other two tables.
336const MAX_HUFF_TABLES: usize = 3;
337/// Literal/length codes
338const MAX_HUFF_SYMBOLS_0: usize = 288;
339/// Distance codes.
340const MAX_HUFF_SYMBOLS_1: usize = 32;
341/// Huffman length values.
342const MAX_HUFF_SYMBOLS_2: usize = 19;
343/// Size of the chained hash table.
344pub(crate) const LZ_DICT_SIZE: usize = 32_768;
345/// Mask used when stepping through the hash chains.
346pub(crate) const LZ_DICT_SIZE_MASK: usize = (LZ_DICT_SIZE as u32 - 1) as usize;
347/// The minimum length of a match.
348pub(crate) const MIN_MATCH_LEN: u8 = 3;
349/// The maximum length of a match.
350pub(crate) const MAX_MATCH_LEN: usize = 258;
351
352pub(crate) const DEFAULT_FLAGS: u32 = NUM_PROBES[4] as u32 | TDEFL_WRITE_ZLIB_HEADER;
353
354#[cfg(test)]
355#[inline]
356fn write_u16_le(val: u16, slice: &mut [u8], pos: usize) {
357    slice[pos] = val as u8;
358    slice[pos + 1] = (val >> 8) as u8;
359}
360
361// Read the two bytes starting at pos and interpret them as an u16.
362#[inline(always)]
363const fn read_u16_le<const N: usize>(slice: &[u8; N], pos: usize) -> u16 {
364    // The compiler is smart enough to optimize this into an unaligned load.
365    slice[pos] as u16 | ((slice[pos + 1] as u16) << 8)
366}
367
368/// Main compression struct.
369#[derive(Clone)]
370pub struct CompressorOxide {
371    pub(crate) lz: LZOxide,
372    pub(crate) params: ParamsOxide,
373    /// Put HuffmanOxide on the heap with default trick to avoid
374    /// excessive stack copies.
375    pub(crate) huff: Box<HuffmanOxide>,
376    pub(crate) dict: DictOxide,
377}
378
379const fn change_window_bits_from_format(window_bits: u8, data_format: DataFormat) -> i32 {
380    match data_format {
381        DataFormat::Zlib | DataFormat::ZLibIgnoreChecksum => window_bits as i32,
382        DataFormat::Raw => -(window_bits as i32),
383    }
384}
385
386/// Limit compression settings by window_bits as a simple way to implement smaller window sizes
387fn limit_level_by_window_bits(
388    window_bits: u8,
389    current_level: i32,
390    current_strategy: CompressionStrategy,
391) -> (i32, CompressionStrategy) {
392    if window_bits < 12 {
393        // If less than 12, use RLE (i.e window size of 1) unless huffman only or stored blocks are requested.
394        if current_strategy != CompressionStrategy::HuffmanOnly && current_level != 0 {
395            (1, CompressionStrategy::RLE)
396        } else {
397            (current_level, current_strategy)
398        }
399    // If less than 15 but 12 or more, use fast mode that uses a 4k window size.
400    } else if window_bits < MZ_DEFAULT_WINDOW_BITS as u8 {
401        (cmp::min(current_level, 1), current_strategy)
402    // If window bits is the full 15 just use the requested settings.
403    } else {
404        (current_level, current_strategy)
405    }
406}
407
408impl CompressorOxide {
409    /// Create a new `CompressorOxide` with the given flags.
410    ///
411    /// # Notes
412    /// This function may be changed to take different parameters in the future.
413    #[inline]
414    pub fn new(flags: u32) -> Self {
415        CompressorOxide {
416            lz: LZOxide::new(),
417            params: ParamsOxide::new(flags, MZ_DEFAULT_WINDOW_BITS as u8),
418            huff: Box::default(),
419            dict: DictOxide::new(flags),
420        }
421    }
422
423    /// Create a new `CompressorOxide` with the given flags.
424    ///
425    pub fn with_format_and_level(
426        data_format: DataFormat,
427        level: CompressionLevel,
428    ) -> CompressorOxide {
429        let flags = create_comp_flags_from_zip_params(
430            level as i32,
431            data_format.to_window_bits(),
432            CompressionStrategy::Default as i32,
433        );
434        CompressorOxide::new(flags)
435    }
436
437    /// Create a new 'CompressorOxide with the current format, level, strategy and window bits
438    ///
439    ///
440    /// Level will is limited to 10, and window bits is clamped to 15
441    pub fn with_params(
442        data_format: DataFormat,
443        level: u8,
444        strategy: CompressionStrategy,
445        window_bits: u8,
446    ) -> CompressorOxide {
447        let window_bits = cmp::min(window_bits, 15);
448        let level = cmp::min(level, 10);
449        let (level, strategy) = limit_level_by_window_bits(window_bits, level as i32, strategy);
450
451        let flags = create_comp_flags_from_zip_params(
452            level,
453            change_window_bits_from_format(window_bits, data_format),
454            strategy as i32,
455        );
456
457        CompressorOxide {
458            lz: LZOxide::new(),
459            params: ParamsOxide::new(flags, window_bits),
460            huff: Box::default(),
461            dict: DictOxide::new(flags),
462        }
463    }
464
465    /// Get the adler32 checksum of the currently encoded data.
466    pub const fn adler32(&self) -> u32 {
467        self.params.adler32
468    }
469
470    /// Get the return status of the previous [`compress`](fn.compress.html)
471    /// call with this compressor.
472    pub const fn prev_return_status(&self) -> TDEFLStatus {
473        self.params.prev_return_status
474    }
475
476    /// Get the raw compressor flags.
477    ///
478    /// # Notes
479    /// This function may be deprecated or changed in the future to use more rust-style flags.
480    pub const fn flags(&self) -> i32 {
481        self.params.flags as i32
482    }
483
484    /// Returns whether the compressor is wrapping the data in a zlib format or not.
485    pub const fn data_format(&self) -> DataFormat {
486        if (self.params.flags & TDEFL_WRITE_ZLIB_HEADER) != 0 {
487            DataFormat::Zlib
488        } else {
489            DataFormat::Raw
490        }
491    }
492
493    /// Reset the state of the compressor, keeping the same parameters.
494    ///
495    /// This avoids re-allocating data.
496    pub fn reset(&mut self) {
497        // LZ buf and huffman has no settings or dynamic memory
498        // that needs to be saved, so we simply replace them.
499        self.lz = LZOxide::new();
500        self.params.reset();
501        *self.huff = HuffmanOxide::default();
502        self.dict.reset();
503    }
504
505    /// Set the compression level of the compressor.
506    ///
507    /// Changing compression level after compression has started will likely result in failure.
508    /// # Notes
509    /// The compression strategy will be reset to the default one when this is called.
510    ///
511    /// If using the zlib wrapper, increasing the compression level
512    /// to one that requires a higher window_bits value
513    /// than the max set at initialization will fail and leave the
514    /// compressor at the current level.
515    pub fn set_compression_level(&mut self, level: CompressionLevel) {
516        let format = self.data_format();
517        self.set_format_and_level(format, level as u8);
518    }
519
520    /// Set the compression level of the compressor using an integer value.
521    ///
522    /// Changing compression level after compression has started will likely result in failure.
523    /// # Notes
524    /// The compression strategy will be reset to the default one when this is called.
525    ///
526    /// If using the zlib wrapper, increasing the compression level
527    /// to one that requires a higher window_bits value
528    /// than the max set at initialization will fail and leave the
529    /// compressor at the current level.
530    pub fn set_compression_level_raw(&mut self, level: u8) {
531        let format = self.data_format();
532        self.set_format_and_level(format, level);
533    }
534
535    /// Update the compression settings of the compressor.
536    ///
537    /// Changing the `DataFormat` after compression has started will result in
538    /// a corrupted stream.
539    ///
540    /// Changing compression level after compression has started will likely result in failure.
541    ///
542    /// # Notes
543    /// This function mainly intended for setting the initial settings after e.g creating with
544    /// `default` or after calling `CompressorOxide::reset()`, and behaviour may be changed
545    /// to disallow calling it after starting compression in the future.
546    ///
547    /// If using the zlib wrapper, increasing the compression level
548    /// to one that requires a higher window_bits value
549    /// than the max set at initialization will fail and leave the
550    /// compressor at the current level.
551    pub fn set_format_and_level(&mut self, data_format: DataFormat, level: u8) {
552        let flags = create_comp_flags_from_zip_params(
553            level.into(),
554            data_format.to_window_bits(),
555            CompressionStrategy::Default as i32,
556        );
557        if data_format == DataFormat::Zlib
558            && window_bits_from_flags(flags) > self.params.window_bits_max
559        {
560            return;
561        }
562        self.params.update_flags(flags);
563        self.dict.update_flags(flags);
564    }
565
566    /// Check the number of unwritten bits after the last flush.
567    /// After a `NoSync` flush it can be used to test whether the
568    /// stream is aligned with a byte boundary.
569    #[inline]
570    pub const fn unwritten_bit_count(&self) -> u32 {
571        self.params.saved_bits_in
572    }
573}
574
575impl Default for CompressorOxide {
576    /// Initialize the compressor with a level of 4, zlib wrapper and
577    /// the default strategy.
578    fn default() -> Self {
579        CompressorOxide {
580            lz: LZOxide::new(),
581            params: ParamsOxide::new(DEFAULT_FLAGS, MZ_DEFAULT_WINDOW_BITS as u8),
582            huff: Box::default(),
583            dict: DictOxide::new(DEFAULT_FLAGS),
584        }
585    }
586}
587
588/// Callback function and user used in `compress_to_output`.
589pub struct CallbackFunc<'a> {
590    pub put_buf_func: &'a mut dyn FnMut(&[u8]) -> bool,
591}
592
593impl CallbackFunc<'_> {
594    fn flush_output(
595        &mut self,
596        saved_output: SavedOutputBufferOxide,
597        params: &mut ParamsOxide,
598    ) -> i32 {
599        // TODO: As this could be unsafe since
600        // we can't verify the function pointer
601        // this whole function should maybe be unsafe as well.
602        let call_success = (self.put_buf_func)(&params.local_buf.b[0..saved_output.pos]);
603
604        if !call_success {
605            params.prev_return_status = TDEFLStatus::PutBufFailed;
606            return params.prev_return_status as i32;
607        }
608
609        params.flush_remaining as i32
610    }
611}
612
613struct CallbackBuf<'a> {
614    pub out_buf: &'a mut [u8],
615}
616
617impl CallbackBuf<'_> {
618    fn flush_output(
619        &mut self,
620        saved_output: SavedOutputBufferOxide,
621        params: &mut ParamsOxide,
622    ) -> i32 {
623        if saved_output.local {
624            let n = cmp::min(saved_output.pos, self.out_buf.len() - params.out_buf_ofs);
625            (self.out_buf[params.out_buf_ofs..params.out_buf_ofs + n])
626                .copy_from_slice(&params.local_buf.b[..n]);
627
628            params.out_buf_ofs += n;
629            if saved_output.pos != n {
630                params.flush_ofs = n as u32;
631                params.flush_remaining = (saved_output.pos - n) as u32;
632            }
633        } else {
634            params.out_buf_ofs += saved_output.pos;
635        }
636
637        params.flush_remaining as i32
638    }
639}
640
641enum CallbackOut<'a> {
642    Func(CallbackFunc<'a>),
643    Buf(CallbackBuf<'a>),
644}
645
646impl CallbackOut<'_> {
647    fn new_output_buffer<'b>(
648        &'b mut self,
649        local_buf: &'b mut [u8],
650        out_buf_ofs: usize,
651    ) -> OutputBufferOxide<'b> {
652        let is_local;
653        let buf_len = OUT_BUF_SIZE - 16;
654        let chosen_buffer = match *self {
655            CallbackOut::Buf(ref mut cb) if cb.out_buf.len() - out_buf_ofs >= OUT_BUF_SIZE => {
656                is_local = false;
657                &mut cb.out_buf[out_buf_ofs..out_buf_ofs + buf_len]
658            }
659            _ => {
660                is_local = true;
661                &mut local_buf[..buf_len]
662            }
663        };
664
665        OutputBufferOxide {
666            inner: chosen_buffer,
667            inner_pos: 0,
668            local: is_local,
669            bit_buffer: 0,
670            bits_in: 0,
671        }
672    }
673}
674
675pub(crate) struct CallbackOxide<'a> {
676    in_buf: Option<&'a [u8]>,
677    in_buf_size: Option<&'a mut usize>,
678    out_buf_size: Option<&'a mut usize>,
679    out: CallbackOut<'a>,
680}
681
682impl<'a> CallbackOxide<'a> {
683    fn new_callback_buf(in_buf: &'a [u8], out_buf: &'a mut [u8]) -> Self {
684        CallbackOxide {
685            in_buf: Some(in_buf),
686            in_buf_size: None,
687            out_buf_size: None,
688            out: CallbackOut::Buf(CallbackBuf { out_buf }),
689        }
690    }
691
692    fn new_callback_func(in_buf: &'a [u8], callback_func: CallbackFunc<'a>) -> Self {
693        CallbackOxide {
694            in_buf: Some(in_buf),
695            in_buf_size: None,
696            out_buf_size: None,
697            out: CallbackOut::Func(callback_func),
698        }
699    }
700
701    fn update_size(&mut self, in_size: Option<usize>, out_size: Option<usize>) {
702        if let (Some(in_size), Some(size)) = (in_size, self.in_buf_size.as_mut()) {
703            **size = in_size;
704        }
705
706        if let (Some(out_size), Some(size)) = (out_size, self.out_buf_size.as_mut()) {
707            **size = out_size
708        }
709    }
710
711    fn flush_output(
712        &mut self,
713        saved_output: SavedOutputBufferOxide,
714        params: &mut ParamsOxide,
715    ) -> i32 {
716        if saved_output.pos == 0 {
717            return params.flush_remaining as i32;
718        }
719
720        self.update_size(Some(params.src_pos), None);
721        match self.out {
722            CallbackOut::Func(ref mut cf) => cf.flush_output(saved_output, params),
723            CallbackOut::Buf(ref mut cb) => cb.flush_output(saved_output, params),
724        }
725    }
726
727    pub(crate) fn buf(&mut self) -> Option<&'a [u8]> {
728        self.in_buf
729    }
730}
731
732struct OutputBufferOxide<'a> {
733    pub inner: &'a mut [u8],
734    pub inner_pos: usize,
735    pub local: bool,
736
737    pub bit_buffer: u32,
738    pub bits_in: u32,
739}
740
741impl OutputBufferOxide<'_> {
742    /// Write bits to the bit buffer and flushes
743    /// the bit buffer so any whole bytes are output
744    /// to the underlying buffer.
745    fn put_bits(&mut self, bits: u32, len: u32) {
746        // TODO: Removing this assertion worsens performance
747        // Need to figure out why
748        assert!(bits <= ((1u32 << len) - 1u32));
749        self.bit_buffer |= bits << self.bits_in;
750        self.bits_in += len;
751
752        while self.bits_in >= 8 {
753            self.inner[self.inner_pos] = self.bit_buffer as u8;
754            self.inner_pos += 1;
755            self.bit_buffer >>= 8;
756            self.bits_in -= 8;
757        }
758    }
759
760    #[inline]
761    /// Write the provided bits to the bit buffer without flushing
762    /// anything. Does not check if there is actually space for it.
763    fn put_bits_no_flush(&mut self, bits: u32, len: u32) {
764        self.bit_buffer |= bits << self.bits_in;
765        self.bits_in += len;
766    }
767
768    const fn save(&self) -> SavedOutputBufferOxide {
769        SavedOutputBufferOxide {
770            pos: self.inner_pos,
771            bit_buffer: self.bit_buffer,
772            bits_in: self.bits_in,
773            local: self.local,
774        }
775    }
776
777    fn load(&mut self, saved: SavedOutputBufferOxide) {
778        self.inner_pos = saved.pos;
779        self.bit_buffer = saved.bit_buffer;
780        self.bits_in = saved.bits_in;
781        self.local = saved.local;
782    }
783
784    #[inline]
785    /// Pad the bit buffer to a whole byte with
786    /// zeroes and write that byte to the output buffer.
787    fn pad_to_bytes(&mut self) {
788        if self.bits_in != 0 {
789            let len = 8 - self.bits_in;
790            self.put_bits(0, len);
791        }
792    }
793
794    /// Test whether the output is currently on a byte boundary,
795    /// i.e. all current data has been output
796    #[inline]
797    const fn is_byte_aligned(&self) -> bool {
798        self.bits_in == 0
799    }
800
801    #[inline]
802    fn write_bytes(&mut self, bytes: &[u8]) {
803        debug_assert_eq!(self.bits_in, 0);
804        self.inner[self.inner_pos..self.inner_pos + bytes.len()].copy_from_slice(bytes);
805        self.inner_pos += bytes.len();
806    }
807}
808
809struct SavedOutputBufferOxide {
810    pub pos: usize,
811    pub bit_buffer: u32,
812    pub bits_in: u32,
813    pub local: bool,
814}
815
816struct BitBuffer {
817    pub bit_buffer: u64,
818    pub bits_in: u32,
819}
820
821impl BitBuffer {
822    fn put_fast(&mut self, bits: u64, len: u32) {
823        self.bit_buffer |= bits << self.bits_in;
824        self.bits_in += len;
825    }
826
827    fn flush(&mut self, output: &mut OutputBufferOxide) -> Result<()> {
828        let pos = output.inner_pos;
829        {
830            // isolation to please borrow checker
831            let inner = &mut output.inner[pos..pos + 8];
832            let bytes = u64::to_le_bytes(self.bit_buffer);
833            inner.copy_from_slice(&bytes);
834        }
835        match output.inner_pos.checked_add((self.bits_in >> 3) as usize) {
836            Some(n) if n <= output.inner.len() => output.inner_pos = n,
837            _ => return Err(Error {}),
838        }
839        self.bit_buffer >>= self.bits_in & !7;
840        self.bits_in &= 7;
841        Ok(())
842    }
843}
844
845/// A struct containing data about huffman codes and symbol frequencies.
846///
847/// NOTE: Only the literal/lengths have enough symbols to actually use
848/// the full array. It's unclear why it's defined like this in miniz,
849/// it could be for cache/alignment reasons.
850#[derive(Clone)]
851pub(crate) struct HuffmanOxide {
852    /// Number of occurrences of each symbol.
853    pub count: [[u16; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
854    /// The bits of the huffman code assigned to the symbol
855    pub codes: [[u16; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
856    /// The length of the huffman code assigned to the symbol.
857    pub code_sizes: [[u8; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
858}
859
860/// Tables used for literal/lengths in `HuffmanOxide`.
861const LITLEN_TABLE: usize = 0;
862/// Tables for distances.
863const DIST_TABLE: usize = 1;
864/// Tables for the run-length encoded huffman lengths for literals/lengths/distances.
865const HUFF_CODES_TABLE: usize = 2;
866
867/// Status of RLE encoding of huffman code lengths.
868struct Rle {
869    pub z_count: u32,
870    pub repeat_count: u16,
871    pub prev_code_size: u8,
872}
873
874impl Rle {
875    fn prev_code_size(
876        &mut self,
877        packed_code_sizes: &mut [u8],
878        packed_pos: &mut usize,
879        h: &mut HuffmanOxide,
880    ) -> Result<()> {
881        let mut write = |buf| write(buf, packed_code_sizes, packed_pos);
882        let counts = &mut h.count[HUFF_CODES_TABLE];
883        if self.repeat_count != 0 {
884            if self.repeat_count < 3 {
885                counts[self.prev_code_size as usize] =
886                    counts[self.prev_code_size as usize].wrapping_add(self.repeat_count);
887                let code = self.prev_code_size;
888                write(&[code, code, code][..self.repeat_count as usize])?;
889            } else {
890                counts[16] = counts[16].wrapping_add(1);
891                write(&[16, (self.repeat_count - 3) as u8][..])?;
892            }
893            self.repeat_count = 0;
894        }
895
896        Ok(())
897    }
898
899    fn zero_code_size(
900        &mut self,
901        packed_code_sizes: &mut [u8],
902        packed_pos: &mut usize,
903        h: &mut HuffmanOxide,
904    ) -> Result<()> {
905        let mut write = |buf| write(buf, packed_code_sizes, packed_pos);
906        let counts = &mut h.count[HUFF_CODES_TABLE];
907        if self.z_count != 0 {
908            if self.z_count < 3 {
909                counts[0] = counts[0].wrapping_add(self.z_count as u16);
910                write(&[0, 0, 0][..self.z_count as usize])?;
911            } else if self.z_count <= 10 {
912                counts[17] = counts[17].wrapping_add(1);
913                write(&[17, (self.z_count - 3) as u8][..])?;
914            } else {
915                counts[18] = counts[18].wrapping_add(1);
916                write(&[18, (self.z_count - 11) as u8][..])?;
917            }
918            self.z_count = 0;
919        }
920
921        Ok(())
922    }
923}
924
925fn write(src: &[u8], dst: &mut [u8], dst_pos: &mut usize) -> Result<()> {
926    match dst.get_mut(*dst_pos..*dst_pos + src.len()) {
927        Some(s) => s.copy_from_slice(src),
928        None => return Err(Error {}),
929    }
930    *dst_pos += src.len();
931    Ok(())
932}
933
934impl Default for HuffmanOxide {
935    fn default() -> Self {
936        HuffmanOxide {
937            count: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
938            codes: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
939            code_sizes: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
940        }
941    }
942}
943
944impl HuffmanOxide {
945    fn radix_sort_symbols<'a>(
946        symbols0: &'a mut [SymFreq],
947        symbols1: &'a mut [SymFreq],
948    ) -> &'a mut [SymFreq] {
949        let mut hist = [[0; 256]; 2];
950
951        for freq in symbols0.iter() {
952            hist[0][(freq.key & 0xFF) as usize] += 1;
953            hist[1][((freq.key >> 8) & 0xFF) as usize] += 1;
954        }
955
956        let mut n_passes = 2;
957        if symbols0.len() == hist[1][0] {
958            n_passes -= 1;
959        }
960
961        let mut current_symbols = symbols0;
962        let mut new_symbols = symbols1;
963
964        for (pass, hist_item) in hist.iter().enumerate().take(n_passes) {
965            let mut offsets = [0; 256];
966            let mut offset = 0;
967            for i in 0..256 {
968                offsets[i] = offset;
969                offset += hist_item[i];
970            }
971
972            for sym in current_symbols.iter() {
973                let j = ((sym.key >> (pass * 8)) & 0xFF) as usize;
974                new_symbols[offsets[j]] = *sym;
975                offsets[j] += 1;
976            }
977
978            mem::swap(&mut current_symbols, &mut new_symbols);
979        }
980
981        current_symbols
982    }
983
984    fn calculate_minimum_redundancy(symbols: &mut [SymFreq]) {
985        match symbols.len() {
986            0 => (),
987            1 => symbols[0].key = 1,
988            n => {
989                symbols[0].key += symbols[1].key;
990                let mut root = 0;
991                let mut leaf = 2;
992                for next in 1..n - 1 {
993                    if (leaf >= n) || (symbols[root].key < symbols[leaf].key) {
994                        symbols[next].key = symbols[root].key;
995                        symbols[root].key = next as u16;
996                        root += 1;
997                    } else {
998                        symbols[next].key = symbols[leaf].key;
999                        leaf += 1;
1000                    }
1001
1002                    if (leaf >= n) || (root < next && symbols[root].key < symbols[leaf].key) {
1003                        symbols[next].key = symbols[next].key.wrapping_add(symbols[root].key);
1004                        symbols[root].key = next as u16;
1005                        root += 1;
1006                    } else {
1007                        symbols[next].key = symbols[next].key.wrapping_add(symbols[leaf].key);
1008                        leaf += 1;
1009                    }
1010                }
1011
1012                symbols[n - 2].key = 0;
1013                for next in (0..n - 2).rev() {
1014                    symbols[next].key = symbols[symbols[next].key as usize].key + 1;
1015                }
1016
1017                let mut avbl = 1;
1018                let mut used = 0;
1019                let mut dpth = 0;
1020                let mut root = (n - 2) as i32;
1021                let mut next = (n - 1) as i32;
1022                while avbl > 0 {
1023                    while (root >= 0) && (symbols[root as usize].key == dpth) {
1024                        used += 1;
1025                        root -= 1;
1026                    }
1027                    while avbl > used {
1028                        symbols[next as usize].key = dpth;
1029                        next -= 1;
1030                        avbl -= 1;
1031                    }
1032                    avbl = 2 * used;
1033                    dpth += 1;
1034                    used = 0;
1035                }
1036            }
1037        }
1038    }
1039
1040    fn enforce_max_code_size(num_codes: &mut [i32], code_list_len: usize, max_code_size: usize) {
1041        if code_list_len <= 1 {
1042            return;
1043        }
1044
1045        num_codes[max_code_size] += num_codes[max_code_size + 1..].iter().sum::<i32>();
1046        let total = num_codes[1..=max_code_size]
1047            .iter()
1048            .rev()
1049            .enumerate()
1050            .fold(0u32, |total, (i, &x)| total + ((x as u32) << i));
1051
1052        for _ in (1 << max_code_size)..total {
1053            num_codes[max_code_size] -= 1;
1054            for i in (1..max_code_size).rev() {
1055                if num_codes[i] != 0 {
1056                    num_codes[i] -= 1;
1057                    num_codes[i + 1] += 2;
1058                    break;
1059                }
1060            }
1061        }
1062    }
1063
1064    fn optimize_table(
1065        &mut self,
1066        table_num: usize,
1067        table_len: usize,
1068        code_size_limit: usize,
1069        static_table: bool,
1070    ) {
1071        let mut num_codes = [0i32; 32 + 1];
1072        let mut next_code = [0u32; MAX_SUPPORTED_HUFF_CODESIZE + 1];
1073
1074        if static_table {
1075            for &code_size in &self.code_sizes[table_num][..table_len] {
1076                num_codes[code_size as usize] += 1;
1077            }
1078        } else {
1079            let mut symbols0 = [SymFreq {
1080                key: 0,
1081                sym_index: 0,
1082            }; MAX_HUFF_SYMBOLS];
1083            let mut symbols1 = [SymFreq {
1084                key: 0,
1085                sym_index: 0,
1086            }; MAX_HUFF_SYMBOLS];
1087
1088            let mut num_used_symbols = 0;
1089            for i in 0..table_len {
1090                if self.count[table_num][i] != 0 {
1091                    symbols0[num_used_symbols] = SymFreq {
1092                        key: self.count[table_num][i],
1093                        sym_index: i as u16,
1094                    };
1095                    num_used_symbols += 1;
1096                }
1097            }
1098
1099            let symbols = Self::radix_sort_symbols(
1100                &mut symbols0[..num_used_symbols],
1101                &mut symbols1[..num_used_symbols],
1102            );
1103            Self::calculate_minimum_redundancy(symbols);
1104
1105            for symbol in symbols.iter() {
1106                num_codes[symbol.key as usize] += 1;
1107            }
1108
1109            Self::enforce_max_code_size(&mut num_codes, num_used_symbols, code_size_limit);
1110
1111            self.code_sizes[table_num].fill(0);
1112            self.codes[table_num].fill(0);
1113
1114            let mut last = num_used_symbols;
1115            for (i, &num_item) in num_codes
1116                .iter()
1117                .enumerate()
1118                .take(code_size_limit + 1)
1119                .skip(1)
1120            {
1121                let first = last - num_item as usize;
1122                for symbol in &symbols[first..last] {
1123                    self.code_sizes[table_num][symbol.sym_index as usize] = i as u8;
1124                }
1125                last = first;
1126            }
1127        }
1128
1129        let mut j = 0;
1130        next_code[1] = 0;
1131        for i in 2..=code_size_limit {
1132            j = (j + num_codes[i - 1]) << 1;
1133            next_code[i] = j as u32;
1134        }
1135
1136        for (&code_size, huff_code) in self.code_sizes[table_num]
1137            .iter()
1138            .take(table_len)
1139            .zip(self.codes[table_num].iter_mut().take(table_len))
1140        {
1141            if code_size == 0 {
1142                continue;
1143            }
1144
1145            let code = next_code[code_size as usize];
1146
1147            next_code[code_size as usize] += 1;
1148
1149            let rev_code = (code as u16).reverse_bits() >> (16 - code_size);
1150
1151            *huff_code = rev_code;
1152        }
1153    }
1154
1155    fn start_static_block(&mut self, output: &mut OutputBufferOxide) {
1156        self.code_sizes[LITLEN_TABLE][0..144].fill(8);
1157        self.code_sizes[LITLEN_TABLE][144..256].fill(9);
1158        self.code_sizes[LITLEN_TABLE][256..280].fill(7);
1159        self.code_sizes[LITLEN_TABLE][280..288].fill(8);
1160
1161        self.code_sizes[DIST_TABLE][..32].fill(5);
1162
1163        self.optimize_table(LITLEN_TABLE, 288, 15, true);
1164        self.optimize_table(DIST_TABLE, 32, 15, true);
1165
1166        output.put_bits(0b01, 2)
1167    }
1168
1169    fn start_dynamic_block(&mut self, output: &mut OutputBufferOxide) -> Result<()> {
1170        // There will always be one, and only one end of block code.
1171        self.count[0][256] = 1;
1172
1173        self.optimize_table(0, MAX_HUFF_SYMBOLS_0, 15, false);
1174        self.optimize_table(1, MAX_HUFF_SYMBOLS_1, 15, false);
1175
1176        let num_lit_codes = 286
1177            - &self.code_sizes[0][257..286]
1178                .iter()
1179                .rev()
1180                .take_while(|&x| *x == 0)
1181                .count();
1182
1183        let num_dist_codes = 30
1184            - &self.code_sizes[1][1..30]
1185                .iter()
1186                .rev()
1187                .take_while(|&x| *x == 0)
1188                .count();
1189
1190        let mut code_sizes_to_pack = [0u8; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1];
1191        let mut packed_code_sizes = [0u8; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1];
1192
1193        let total_code_sizes_to_pack = num_lit_codes + num_dist_codes;
1194
1195        code_sizes_to_pack[..num_lit_codes].copy_from_slice(&self.code_sizes[0][..num_lit_codes]);
1196
1197        code_sizes_to_pack[num_lit_codes..total_code_sizes_to_pack]
1198            .copy_from_slice(&self.code_sizes[1][..num_dist_codes]);
1199
1200        let mut rle = Rle {
1201            z_count: 0,
1202            repeat_count: 0,
1203            prev_code_size: 0xFF,
1204        };
1205
1206        self.count[HUFF_CODES_TABLE][..MAX_HUFF_SYMBOLS_2].fill(0);
1207
1208        let mut packed_pos = 0;
1209        for &code_size in &code_sizes_to_pack[..total_code_sizes_to_pack] {
1210            if code_size == 0 {
1211                rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1212                rle.z_count += 1;
1213                if rle.z_count == 138 {
1214                    rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1215                }
1216            } else {
1217                rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1218                if code_size != rle.prev_code_size {
1219                    rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1220                    self.count[HUFF_CODES_TABLE][code_size as usize] =
1221                        self.count[HUFF_CODES_TABLE][code_size as usize].wrapping_add(1);
1222                    write(&[code_size], &mut packed_code_sizes, &mut packed_pos)?;
1223                } else {
1224                    rle.repeat_count += 1;
1225                    if rle.repeat_count == 6 {
1226                        rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1227                    }
1228                }
1229            }
1230            rle.prev_code_size = code_size;
1231        }
1232
1233        if rle.repeat_count != 0 {
1234            rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1235        } else {
1236            rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1237        }
1238
1239        self.optimize_table(2, MAX_HUFF_SYMBOLS_2, 7, false);
1240
1241        output.put_bits_no_flush(2, 2);
1242
1243        output.put_bits_no_flush((num_lit_codes - 257) as u32, 5);
1244        output.put_bits_no_flush((num_dist_codes - 1) as u32, 5);
1245
1246        let mut num_bit_lengths = 18
1247            - HUFFMAN_LENGTH_ORDER
1248                .iter()
1249                .rev()
1250                .take_while(|&swizzle| self.code_sizes[HUFF_CODES_TABLE][*swizzle as usize] == 0)
1251                .count();
1252
1253        num_bit_lengths = cmp::max(4, num_bit_lengths + 1);
1254        output.put_bits(num_bit_lengths as u32 - 4, 4);
1255        for &swizzle in &HUFFMAN_LENGTH_ORDER[..num_bit_lengths] {
1256            output.put_bits(
1257                u32::from(self.code_sizes[HUFF_CODES_TABLE][swizzle as usize]),
1258                3,
1259            );
1260        }
1261
1262        let mut packed_code_size_index = 0;
1263        while packed_code_size_index < packed_pos {
1264            let code = packed_code_sizes[packed_code_size_index] as usize;
1265            packed_code_size_index += 1;
1266            assert!(code < MAX_HUFF_SYMBOLS_2);
1267            output.put_bits(
1268                u32::from(self.codes[HUFF_CODES_TABLE][code]),
1269                u32::from(self.code_sizes[HUFF_CODES_TABLE][code]),
1270            );
1271            if code >= 16 {
1272                output.put_bits(
1273                    u32::from(packed_code_sizes[packed_code_size_index]),
1274                    [2, 3, 7][code - 16],
1275                );
1276                packed_code_size_index += 1;
1277            }
1278        }
1279
1280        Ok(())
1281    }
1282}
1283
1284#[derive(Clone)]
1285pub(crate) struct DictOxide {
1286    /// The maximum number of checks in the hash chain, for the initial,
1287    /// and the lazy match respectively.
1288    pub max_probes: [u32; 2],
1289    /// Buffer of input data.
1290    /// Padded with 1 byte to simplify matching code in `compress_fast`.
1291    pub b: HashBuffers,
1292
1293    pub code_buf_dict_pos: usize,
1294    pub lookahead_size: usize,
1295    pub lookahead_pos: usize,
1296    pub size: usize,
1297    loop_len: u8,
1298}
1299
1300const fn probes_from_flags(flags: u32) -> [u32; 2] {
1301    [
1302        1 + ((flags & 0xFFF) + 2) / 3,
1303        1 + (((flags & 0xFFF) >> 2) + 2) / 3,
1304    ]
1305}
1306
1307impl DictOxide {
1308    fn new(flags: u32) -> Self {
1309        DictOxide {
1310            max_probes: probes_from_flags(flags),
1311            b: HashBuffers::default(),
1312            code_buf_dict_pos: 0,
1313            lookahead_size: 0,
1314            lookahead_pos: 0,
1315            size: 0,
1316            loop_len: 32,
1317        }
1318    }
1319
1320    fn update_flags(&mut self, flags: u32) {
1321        self.max_probes = probes_from_flags(flags);
1322    }
1323
1324    fn reset(&mut self) {
1325        self.b.reset();
1326        self.code_buf_dict_pos = 0;
1327        self.lookahead_size = 0;
1328        self.lookahead_pos = 0;
1329        self.size = 0;
1330    }
1331
1332    /// Do an unaligned read of the data at `pos` in the dictionary and treat it as if it was of
1333    /// type T.
1334    #[inline]
1335    fn read_unaligned_u32(&self, pos: usize) -> u32 {
1336        // Masking the value here helps avoid bounds checks.
1337        let pos = pos & LZ_DICT_SIZE_MASK;
1338        let end = pos + 4;
1339        // Somehow this assertion makes things faster.
1340        // TODO: as of may 2024 this does not seem to make any difference
1341        // so consider removing.
1342        assert!(end < LZ_DICT_FULL_SIZE);
1343
1344        let bytes: [u8; 4] = self.b.dict[pos..end].try_into().unwrap();
1345        u32::from_le_bytes(bytes)
1346    }
1347
1348    /// Do an unaligned read of the data at `pos` in the dictionary and treat it as if it was of
1349    /// type T.
1350    #[inline]
1351    fn read_unaligned_u64(&self, pos: usize) -> u64 {
1352        // Help evade bounds/panic code check by masking the position value
1353        // This provides a small speedup at the cost of an instruction or two instead of
1354        // having to use unsafe.
1355        let pos = pos & LZ_DICT_SIZE_MASK;
1356        let bytes: [u8; 8] = self.b.dict[pos..pos + 8].try_into().unwrap();
1357        u64::from_le_bytes(bytes)
1358    }
1359
1360    /// Try to find a match for the data at lookahead_pos in the dictionary that is
1361    /// longer than `match_len`.
1362    /// Returns a tuple containing (match_distance, match_length). Will be equal to the input
1363    /// values if no better matches were found.
1364    fn find_match(
1365        &self,
1366        lookahead_pos: usize,
1367        max_dist: usize,
1368        max_match_len: u32,
1369        mut match_dist: u32,
1370        mut match_len: u32,
1371    ) -> (u32, u32) {
1372        // Clamp the match len and max_match_len to be valid. (It should be when this is called, but
1373        // do it for now just in case for safety reasons.)
1374        // This should normally end up as at worst conditional moves,
1375        // so it shouldn't slow us down much.
1376        // TODO: Statically verify these so we don't need to do this.
1377        let max_match_len = cmp::min(MAX_MATCH_LEN as u32, max_match_len);
1378        match_len = cmp::max(match_len, 1);
1379
1380        // If we already have a match of the full length don't bother searching for another one.
1381        if max_match_len <= match_len {
1382            return (match_dist, match_len);
1383        }
1384
1385        let pos = lookahead_pos & LZ_DICT_SIZE_MASK;
1386        let mut probe_pos = pos;
1387        // Number of probes into the hash chains.
1388        let mut num_probes_left = if match_len < 32 {
1389            self.max_probes[0]
1390        } else {
1391            self.max_probes[1]
1392        };
1393
1394        // Read the last byte of the current match, and the next one, used to compare matches.
1395        let mut c01: u16 = read_u16_le(&self.b.dict, pos + match_len as usize - 1);
1396        // Read the two bytes at the end position of the current match.
1397        let s01: u16 = read_u16_le(&self.b.dict, pos);
1398
1399        'outer: loop {
1400            let mut dist;
1401            'found: loop {
1402                num_probes_left -= 1;
1403                if num_probes_left == 0 {
1404                    // We have done as many probes in the hash chain as the current compression
1405                    // settings allow, so return the best match we found, if any.
1406                    return (match_dist, match_len);
1407                }
1408
1409                for _ in 0..3 {
1410                    let next_probe_pos = self.b.next[probe_pos] as usize;
1411
1412                    dist = (lookahead_pos - next_probe_pos) & 0xFFFF;
1413                    // Optimization: The last condition should never be hit but helps the compiler by avoiding
1414                    // doing the bounds check in the read_u16_le call and adding the extra instructions
1415                    // for branching to a panic after that and instead just adds the extra instruction here
1416                    // instead saving some instructions and thus improving performance a bit.
1417                    // May want to investigate whether we can avoid it entirely but as of now the compiler
1418                    // isn't able to deduce that match_len - 1 is bounded to [1-257]
1419                    // Disable clippy lint as it needs to be written in this specific way
1420                    // rather than MAX_MATCH_LEN to work
1421                    // because the compiler isn't super smart....
1422                    #[allow(clippy::int_plus_one)]
1423                    if next_probe_pos == 0
1424                        || dist > max_dist
1425                        || match_len as usize - 1 >= MAX_MATCH_LEN
1426                    {
1427                        // We reached the end of the hash chain, or the next value is further away
1428                        // than the maximum allowed distance, so return the best match we found, if
1429                        // any.
1430                        return (match_dist, match_len);
1431                    }
1432
1433                    // Mask the position value to get the position in the hash chain of the next
1434                    // position to match against.
1435                    probe_pos = next_probe_pos & LZ_DICT_SIZE_MASK;
1436
1437                    if read_u16_le(&self.b.dict, probe_pos + match_len as usize - 1) == c01 {
1438                        break 'found;
1439                    }
1440                }
1441            }
1442
1443            if dist == 0 {
1444                // We've looked through the whole match range, so return the best match we
1445                // found.
1446                return (match_dist, match_len);
1447            }
1448
1449            // Check if the two first bytes match.
1450            if read_u16_le(&self.b.dict, probe_pos) != s01 {
1451                continue;
1452            }
1453
1454            let mut p = pos + 2;
1455            let mut q = probe_pos + 2;
1456            // The first two bytes matched, so check the full length of the match.
1457            // TODO: This is a workaround for an upstream issue introduced after a LLVM upgrade in rust 1.82.
1458            // the compiler is too smart and ends up unrolling the loop which causes the performance to get worse
1459            // Using a variable instead of a constant here to prevent it seems to at least get back some of the performance loss.
1460            for _ in 0..self.loop_len as i32 {
1461                let p_data: u64 = self.read_unaligned_u64(p);
1462                let q_data: u64 = self.read_unaligned_u64(q);
1463                // Compare of 8 bytes at a time by using unaligned loads of 64-bit integers.
1464                let xor_data = p_data ^ q_data;
1465                if xor_data == 0 {
1466                    p += 8;
1467                    q += 8;
1468                } else {
1469                    // If not all of the last 8 bytes matched, check how may of them did.
1470                    let trailing = xor_data.trailing_zeros();
1471
1472                    let probe_len = p - pos + (trailing as usize >> 3);
1473                    if probe_len > match_len as usize {
1474                        match_dist = dist as u32;
1475                        match_len = cmp::min(max_match_len, probe_len as u32);
1476                        if match_len >= max_match_len {
1477                            // We found a match that had the maximum allowed length,
1478                            // so there is now point searching further.
1479                            return (match_dist, match_len);
1480                        }
1481                        // We found a better match, so save the last two bytes for further match
1482                        // comparisons.
1483                        // Optimization: use saturating_sub makes the compiler able to evade the bounds check
1484                        // at the cost of some extra instructions since it avoids any possibility of wraparound.
1485                        // need to see if we can find a better way to do this since this is still a bit costly.
1486                        c01 =
1487                            read_u16_le(&self.b.dict, (pos + match_len as usize).saturating_sub(1));
1488                    }
1489                    continue 'outer;
1490                }
1491            }
1492
1493            return (dist as u32, cmp::min(max_match_len, MAX_MATCH_LEN as u32));
1494        }
1495    }
1496}
1497
1498#[derive(Clone)]
1499pub(crate) struct ParamsOxide {
1500    pub flags: u32,
1501    pub greedy_parsing: bool,
1502    // If using a zlib header
1503    // we want to restrict changing
1504    // compression level higher than 1 if
1505    // has been 1 or lower since the header
1506    // will say the window size is lower than 32k.
1507    pub window_bits_max: u8,
1508    pub block_index: u32,
1509
1510    pub saved_match_dist: u32,
1511    pub saved_match_len: u32,
1512    pub saved_lit: u8,
1513
1514    pub flush: TDEFLFlush,
1515    pub flush_ofs: u32,
1516    pub flush_remaining: u32,
1517    pub finished: bool,
1518
1519    pub adler32: u32,
1520
1521    pub src_pos: usize,
1522
1523    pub out_buf_ofs: usize,
1524    pub prev_return_status: TDEFLStatus,
1525
1526    pub saved_bit_buffer: u32,
1527    pub saved_bits_in: u32,
1528
1529    pub local_buf: Box<LocalBuf>,
1530}
1531
1532impl ParamsOxide {
1533    fn new(flags: u32, window_bits: u8) -> Self {
1534        ParamsOxide {
1535            flags,
1536            greedy_parsing: flags & TDEFL_GREEDY_PARSING_FLAG != 0,
1537            window_bits_max: window_bits,
1538            block_index: 0,
1539            saved_match_dist: 0,
1540            saved_match_len: 0,
1541            saved_lit: 0,
1542            flush: TDEFLFlush::None,
1543            flush_ofs: 0,
1544            flush_remaining: 0,
1545            finished: false,
1546            adler32: MZ_ADLER32_INIT,
1547            src_pos: 0,
1548            out_buf_ofs: 0,
1549            prev_return_status: TDEFLStatus::Okay,
1550            saved_bit_buffer: 0,
1551            saved_bits_in: 0,
1552            local_buf: Box::default(),
1553        }
1554    }
1555
1556    fn update_flags(&mut self, flags: u32) {
1557        self.flags = flags;
1558        self.greedy_parsing = self.flags & TDEFL_GREEDY_PARSING_FLAG != 0;
1559    }
1560
1561    /// Reset state, saving settings.
1562    fn reset(&mut self) {
1563        self.block_index = 0;
1564        self.saved_match_len = 0;
1565        self.saved_match_dist = 0;
1566        self.saved_lit = 0;
1567        self.flush = TDEFLFlush::None;
1568        self.flush_ofs = 0;
1569        self.flush_remaining = 0;
1570        self.finished = false;
1571        self.adler32 = MZ_ADLER32_INIT;
1572        self.src_pos = 0;
1573        self.out_buf_ofs = 0;
1574        self.prev_return_status = TDEFLStatus::Okay;
1575        self.saved_bit_buffer = 0;
1576        self.saved_bits_in = 0;
1577        self.local_buf.b = [0; OUT_BUF_SIZE];
1578    }
1579}
1580
1581#[derive(Clone)]
1582pub(crate) struct LZOxide {
1583    #[cfg(target_arch = "wasm32")]
1584    pub codes: Box<[u8; LZ_CODE_BUF_SIZE]>,
1585    #[cfg(not(target_arch = "wasm32"))]
1586    pub codes: [u8; LZ_CODE_BUF_SIZE],
1587    pub code_position: usize,
1588    pub flag_position: usize,
1589
1590    pub total_bytes: u32,
1591    pub num_flags_left: u32,
1592}
1593
1594impl LZOxide {
1595    #[cfg(target_arch = "wasm32")]
1596    fn new() -> Self {
1597        LZOxide {
1598            codes: vec![0; LZ_CODE_BUF_SIZE]
1599                .into_boxed_slice()
1600                .try_into()
1601                .unwrap(),
1602            code_position: 1,
1603            flag_position: 0,
1604            total_bytes: 0,
1605            num_flags_left: 8,
1606        }
1607    }
1608
1609    #[cfg(not(target_arch = "wasm32"))]
1610    const fn new() -> Self {
1611        LZOxide {
1612            codes: [0; LZ_CODE_BUF_SIZE],
1613            code_position: 1,
1614            flag_position: 0,
1615            total_bytes: 0,
1616            num_flags_left: 8,
1617        }
1618    }
1619
1620    fn write_code(&mut self, val: u8) {
1621        // Perf - go via u16 to help evade bounds check
1622        // TODO: see if we can use u16 for flag_position in general.
1623        self.codes[usize::from(self.code_position as u16)] = val;
1624        self.code_position += 1;
1625    }
1626
1627    fn init_flag(&mut self) {
1628        if self.num_flags_left == 8 {
1629            *self.get_flag() = 0;
1630            self.code_position -= 1;
1631        } else {
1632            *self.get_flag() >>= self.num_flags_left;
1633        }
1634    }
1635
1636    fn get_flag(&mut self) -> &mut u8 {
1637        // Perf - go via u16 to help evade bounds check
1638        // TODO: see if we can use u16 for flag_position in general.
1639        &mut self.codes[usize::from(self.flag_position as u16)]
1640    }
1641
1642    fn plant_flag(&mut self) {
1643        self.flag_position = self.code_position;
1644        self.code_position += 1;
1645    }
1646
1647    fn consume_flag(&mut self) {
1648        self.num_flags_left -= 1;
1649        if self.num_flags_left == 0 {
1650            self.num_flags_left = 8;
1651            self.plant_flag();
1652        }
1653    }
1654}
1655
1656fn compress_lz_codes(
1657    huff: &HuffmanOxide,
1658    output: &mut OutputBufferOxide,
1659    lz_code_buf: &[u8; LZ_CODE_BUF_SIZE],
1660    lz_code_buf_used_len: usize,
1661) -> Result<bool> {
1662    let mut flags = 1;
1663    let mut bb = BitBuffer {
1664        bit_buffer: u64::from(output.bit_buffer),
1665        bits_in: output.bits_in,
1666    };
1667
1668    // Help out the compiler know this variable won't be larger than
1669    // the buffer length since the constants won't propagate through the function call.
1670    let lz_code_buf_used_len = cmp::min(lz_code_buf.len(), lz_code_buf_used_len);
1671
1672    let mut i: usize = 0;
1673    while i < lz_code_buf_used_len {
1674        if flags == 1 {
1675            flags = u32::from(lz_code_buf[i]) | 0x100;
1676            i += 1;
1677        }
1678
1679        // The lz code was a length code
1680        if flags & 1 == 1 {
1681            flags >>= 1;
1682
1683            let sym;
1684            let num_extra_bits;
1685
1686            let match_len = lz_code_buf[i & LZ_CODE_BUF_MASK] as usize;
1687
1688            let match_dist = lz_code_buf[(i + 1) & LZ_CODE_BUF_MASK] as u16
1689                | ((lz_code_buf[(i + 2) & LZ_CODE_BUF_MASK] as u16) << 8);
1690
1691            i += 3;
1692
1693            debug_assert!(huff.code_sizes[0][LEN_SYM[match_len] as usize + LEN_SYM_OFFSET] != 0);
1694            let len_sym = (LEN_SYM[match_len] & 31) as usize + LEN_SYM_OFFSET;
1695
1696            bb.put_fast(
1697                u64::from(huff.codes[0][len_sym]),
1698                u32::from(huff.code_sizes[0][len_sym]),
1699            );
1700            bb.put_fast(
1701                match_len as u64 & u64::from(BITMASKS[(LEN_EXTRA[match_len] & 7) as usize]),
1702                u32::from(LEN_EXTRA[match_len]),
1703            );
1704
1705            if match_dist < 512 {
1706                sym = SMALL_DIST_SYM[match_dist as usize] as usize;
1707                num_extra_bits = SMALL_DIST_EXTRA[(match_dist >> 2) as usize] as usize;
1708            } else {
1709                sym = LARGE_DIST_SYM[(match_dist >> 8) as usize] as usize;
1710                num_extra_bits = LARGE_DIST_EXTRA[(match_dist >> 8) as usize] as usize;
1711            }
1712
1713            debug_assert!(huff.code_sizes[1][sym] != 0);
1714            bb.put_fast(
1715                u64::from(huff.codes[1][sym]),
1716                u32::from(huff.code_sizes[1][sym]),
1717            );
1718            bb.put_fast(
1719                u64::from(match_dist) & u64::from(BITMASKS[num_extra_bits & 15]),
1720                num_extra_bits as u32,
1721            );
1722        } else {
1723            // The lz code was a literal
1724            for _ in 0..3 {
1725                flags >>= 1;
1726                let lit = lz_code_buf[i & LZ_CODE_BUF_MASK];
1727                i += 1;
1728
1729                debug_assert!(huff.code_sizes[0][lit as usize] != 0);
1730                bb.put_fast(
1731                    u64::from(huff.codes[0][lit as usize]),
1732                    u32::from(huff.code_sizes[0][lit as usize]),
1733                );
1734
1735                if flags & 1 == 1 || i >= lz_code_buf_used_len {
1736                    break;
1737                }
1738            }
1739        }
1740
1741        bb.flush(output)?;
1742    }
1743
1744    output.bits_in = 0;
1745    output.bit_buffer = 0;
1746    while bb.bits_in != 0 {
1747        let n = cmp::min(bb.bits_in, 16);
1748        output.put_bits(bb.bit_buffer as u32 & BITMASKS[n as usize], n);
1749        bb.bit_buffer >>= n;
1750        bb.bits_in -= n;
1751    }
1752
1753    // Output the end of block symbol.
1754    output.put_bits(
1755        u32::from(huff.codes[0][256]),
1756        u32::from(huff.code_sizes[0][256]),
1757    );
1758
1759    Ok(true)
1760}
1761
1762fn compress_block(
1763    huff: &mut HuffmanOxide,
1764    output: &mut OutputBufferOxide,
1765    lz: &LZOxide,
1766    static_block: bool,
1767) -> Result<bool> {
1768    if static_block {
1769        huff.start_static_block(output);
1770    } else {
1771        huff.start_dynamic_block(output)?;
1772    }
1773
1774    compress_lz_codes(huff, output, &lz.codes, lz.code_position)
1775}
1776
1777pub(crate) fn flush_block(
1778    d: &mut CompressorOxide,
1779    callback: &mut CallbackOxide,
1780    flush: TDEFLFlush,
1781) -> Result<i32> {
1782    let mut saved_buffer;
1783    {
1784        let mut output = callback
1785            .out
1786            .new_output_buffer(&mut d.params.local_buf.b, d.params.out_buf_ofs);
1787        output.bit_buffer = d.params.saved_bit_buffer;
1788        output.bits_in = d.params.saved_bits_in;
1789
1790        // If we are at the start of the stream, write the zlib header
1791        // if requested.  Note: Even if block-writing is skipped
1792        // below, `block_index` is still incremented, so this is done
1793        // only once
1794        if d.params.flags & TDEFL_WRITE_ZLIB_HEADER != 0 && d.params.block_index == 0 {
1795            let header = zlib::header_from_flags(d.params.flags, d.params.window_bits_max);
1796            output.put_bits_no_flush(header[0].into(), 8);
1797            output.put_bits(header[1].into(), 8);
1798        }
1799
1800        if d.lz.total_bytes > 0 || flush == TDEFLFlush::Finish {
1801            // TODO: Don't think this second condition should be here but need to verify.
1802            let use_raw_block = (d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0)
1803                && (d.dict.lookahead_pos - d.dict.code_buf_dict_pos) <= d.dict.size;
1804            debug_assert_eq!(
1805                use_raw_block,
1806                d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0
1807            );
1808
1809            debug_assert!(d.params.flush_remaining == 0);
1810            d.params.flush_ofs = 0;
1811            d.params.flush_remaining = 0;
1812
1813            d.lz.init_flag();
1814
1815            // Output the block header.
1816            output.put_bits((flush == TDEFLFlush::Finish) as u32, 1);
1817
1818            saved_buffer = output.save();
1819
1820            let comp_success = if !use_raw_block {
1821                let use_static = (d.params.flags & TDEFL_FORCE_ALL_STATIC_BLOCKS != 0)
1822                    || (d.lz.total_bytes < 48);
1823                compress_block(&mut d.huff, &mut output, &d.lz, use_static)?
1824            } else {
1825                false
1826            };
1827
1828            // If we failed to compress anything and the output would take up more space than the output
1829            // data, output a stored block instead, which has at most 5 bytes of overhead.
1830            // We only use some simple heuristics for now.
1831            // A stored block will have an overhead of at least 4 bytes containing the block length
1832            // but usually more due to the length parameters having to start at a byte boundary and thus
1833            // requiring up to 5 bytes of padding.
1834            // As a static block will have an overhead of at most 1 bit per byte
1835            // (as literals are either 8 or 9 bytes), a raw block will
1836            // never take up less space if the number of input bytes are less than 32.
1837            let expanded = (d.lz.total_bytes > 32)
1838                && (output.inner_pos - saved_buffer.pos + 1 >= (d.lz.total_bytes as usize))
1839                && (d.dict.lookahead_pos - d.dict.code_buf_dict_pos <= d.dict.size);
1840
1841            if use_raw_block || expanded {
1842                output.load(saved_buffer);
1843
1844                // Block header.
1845                output.put_bits(0, 2);
1846
1847                // Block length has to start on a byte boundary, so pad.
1848                output.pad_to_bytes();
1849
1850                // Block length and ones complement of block length.
1851                output.put_bits(d.lz.total_bytes & 0xFFFF, 16);
1852                output.put_bits(!d.lz.total_bytes & 0xFFFF, 16);
1853
1854                // Write the actual bytes.
1855                let start = d.dict.code_buf_dict_pos & LZ_DICT_SIZE_MASK;
1856                let end =
1857                    (d.dict.code_buf_dict_pos + d.lz.total_bytes as usize) & LZ_DICT_SIZE_MASK;
1858                let dict = &mut d.dict.b.dict;
1859                if start < end {
1860                    // The data does not wrap around.
1861                    output.write_bytes(&dict[start..end]);
1862                } else if d.lz.total_bytes > 0 {
1863                    // The data wraps around and the input was not 0 bytes.
1864                    output.write_bytes(&dict[start..LZ_DICT_SIZE]);
1865                    output.write_bytes(&dict[..end]);
1866                }
1867            } else if !comp_success {
1868                output.load(saved_buffer);
1869                compress_block(&mut d.huff, &mut output, &d.lz, true)?;
1870            }
1871        }
1872
1873        match flush {
1874            TDEFLFlush::Finish => {
1875                output.pad_to_bytes();
1876                if d.params.flags & TDEFL_WRITE_ZLIB_HEADER != 0 {
1877                    let mut adler = d.params.adler32;
1878                    for _ in 0..4 {
1879                        output.put_bits((adler >> 24) & 0xFF, 8);
1880                        adler <<= 8;
1881                    }
1882                }
1883            }
1884            TDEFLFlush::Partial => {
1885                output.put_bits(2, 10);
1886            }
1887            TDEFLFlush::PartialOpt => {
1888                if !output.is_byte_aligned() {
1889                    output.put_bits(2, 10);
1890                }
1891            }
1892            TDEFLFlush::Sync | TDEFLFlush::Full => {
1893                // Output an empty raw block.
1894                output.put_bits(0, 3);
1895                output.pad_to_bytes();
1896                output.put_bits(0, 16);
1897                output.put_bits(0xFFFF, 16);
1898            }
1899            TDEFLFlush::SyncOpt => {
1900                if !output.is_byte_aligned() {
1901                    output.put_bits(0, 3);
1902                    output.pad_to_bytes();
1903                    output.put_bits(0, 16);
1904                    output.put_bits(0xFFFF, 16);
1905                }
1906            }
1907            TDEFLFlush::None | TDEFLFlush::NoSync => (),
1908        }
1909
1910        d.huff.count[0][..MAX_HUFF_SYMBOLS_0].fill(0);
1911        d.huff.count[1][..MAX_HUFF_SYMBOLS_1].fill(0);
1912
1913        // Clear LZ buffer for the next block.
1914        d.lz.code_position = 1;
1915        d.lz.flag_position = 0;
1916        d.lz.num_flags_left = 8;
1917        d.dict.code_buf_dict_pos += d.lz.total_bytes as usize;
1918        d.lz.total_bytes = 0;
1919        d.params.block_index += 1;
1920
1921        saved_buffer = output.save();
1922
1923        d.params.saved_bit_buffer = saved_buffer.bit_buffer;
1924        d.params.saved_bits_in = saved_buffer.bits_in;
1925    }
1926
1927    Ok(callback.flush_output(saved_buffer, &mut d.params))
1928}
1929
1930pub(crate) fn record_literal(h: &mut HuffmanOxide, lz: &mut LZOxide, lit: u8) {
1931    lz.total_bytes += 1;
1932    lz.write_code(lit);
1933
1934    *lz.get_flag() >>= 1;
1935    lz.consume_flag();
1936
1937    h.count[0][lit as usize] += 1;
1938}
1939
1940fn record_match(h: &mut HuffmanOxide, lz: &mut LZOxide, match_len: u32, mut match_dist: u32) {
1941    debug_assert!(match_len >= MIN_MATCH_LEN.into());
1942    debug_assert!(match_dist >= 1);
1943    debug_assert!(match_dist as usize <= LZ_DICT_SIZE);
1944
1945    lz.total_bytes += match_len;
1946    match_dist -= 1;
1947    let match_len = (match_len - u32::from(MIN_MATCH_LEN)) as u8;
1948    lz.write_code(match_len);
1949    lz.write_code(match_dist as u8);
1950    lz.write_code((match_dist >> 8) as u8);
1951
1952    *lz.get_flag() >>= 1;
1953    *lz.get_flag() |= 0x80;
1954    lz.consume_flag();
1955
1956    let symbol = if match_dist < 512 {
1957        SMALL_DIST_SYM[match_dist as usize]
1958    } else {
1959        LARGE_DIST_SYM[((match_dist >> 8) & 127) as usize]
1960    } as usize;
1961    h.count[1][symbol] += 1;
1962    // Mask the values from LEN_SYM here as the compiler isn't quite smart enough to infer
1963    // that it only contains values smaller than 32.
1964    h.count[0][(LEN_SYM[match_len as usize] as usize & 31) + LEN_SYM_OFFSET] += 1;
1965}
1966
1967fn compress_normal(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool {
1968    let in_buf = match callback.in_buf {
1969        None => return true,
1970        Some(in_buf) => in_buf,
1971    };
1972
1973    let mut src_pos = d.params.src_pos;
1974    let mut lookahead_size = d.dict.lookahead_size;
1975    let mut lookahead_pos = d.dict.lookahead_pos;
1976    let mut saved_lit = d.params.saved_lit;
1977    let mut saved_match_dist = d.params.saved_match_dist;
1978    let mut saved_match_len = d.params.saved_match_len;
1979
1980    while src_pos < in_buf.len() || (d.params.flush != TDEFLFlush::None && lookahead_size != 0) {
1981        let in_buf_left = &in_buf[src_pos..];
1982        let num_bytes_to_process = cmp::min(in_buf_left.len(), MAX_MATCH_LEN - lookahead_size);
1983        let bytes_to_process = &in_buf_left[..num_bytes_to_process];
1984
1985        if lookahead_size + d.dict.size >= usize::from(MIN_MATCH_LEN) - 1
1986            && num_bytes_to_process > 0
1987        {
1988            let dictb = &mut d.dict.b;
1989
1990            let mut dst_pos = (lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK;
1991            let mut ins_pos = lookahead_pos + lookahead_size - 2;
1992            // Start the hash value from the first two bytes
1993            let mut hash = update_hash(
1994                u16::from(dictb.dict[ins_pos & LZ_DICT_SIZE_MASK]),
1995                dictb.dict[(ins_pos + 1) & LZ_DICT_SIZE_MASK],
1996            );
1997
1998            lookahead_size += num_bytes_to_process;
1999
2000            for &c in bytes_to_process {
2001                // Add byte to input buffer.
2002                dictb.dict[dst_pos] = c;
2003                if dst_pos < MAX_MATCH_LEN - 1 {
2004                    dictb.dict[LZ_DICT_SIZE + dst_pos] = c;
2005                }
2006
2007                // Generate hash from the current byte,
2008                hash = update_hash(hash, c);
2009                dictb.next[ins_pos & LZ_DICT_SIZE_MASK] = dictb.hash[hash as usize];
2010                // and insert it into the hash chain.
2011                dictb.hash[hash as usize] = ins_pos as u16;
2012                dst_pos = (dst_pos + 1) & LZ_DICT_SIZE_MASK;
2013                ins_pos += 1;
2014            }
2015
2016            src_pos += num_bytes_to_process;
2017        } else {
2018            let dictb = &mut d.dict.b;
2019            for &c in bytes_to_process {
2020                let dst_pos = (lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK;
2021                dictb.dict[dst_pos] = c;
2022                if dst_pos < MAX_MATCH_LEN - 1 {
2023                    dictb.dict[LZ_DICT_SIZE + dst_pos] = c;
2024                }
2025
2026                lookahead_size += 1;
2027                if lookahead_size + d.dict.size >= MIN_MATCH_LEN.into() {
2028                    let ins_pos = lookahead_pos + lookahead_size - 3;
2029                    let hash = ((u32::from(dictb.dict[ins_pos & LZ_DICT_SIZE_MASK])
2030                        << (LZ_HASH_SHIFT * 2))
2031                        ^ ((u32::from(dictb.dict[(ins_pos + 1) & LZ_DICT_SIZE_MASK])
2032                            << LZ_HASH_SHIFT)
2033                            ^ u32::from(c)))
2034                        & (LZ_HASH_SIZE as u32 - 1);
2035
2036                    dictb.next[ins_pos & LZ_DICT_SIZE_MASK] = dictb.hash[hash as usize];
2037                    dictb.hash[hash as usize] = ins_pos as u16;
2038                }
2039            }
2040
2041            src_pos += num_bytes_to_process;
2042        }
2043
2044        d.dict.size = cmp::min(LZ_DICT_SIZE - lookahead_size, d.dict.size);
2045        if d.params.flush == TDEFLFlush::None && lookahead_size < MAX_MATCH_LEN {
2046            break;
2047        }
2048
2049        let mut len_to_move = 1;
2050        let mut cur_match_dist = 0;
2051        let mut cur_match_len = if saved_match_len != 0 {
2052            saved_match_len
2053        } else {
2054            u32::from(MIN_MATCH_LEN) - 1
2055        };
2056        let cur_pos = lookahead_pos & LZ_DICT_SIZE_MASK;
2057        if d.params.flags & TDEFL_RLE_MATCHES != 0 {
2058            // If TDEFL_RLE_MATCHES is set, we only look for repeating sequences of the current byte.
2059            if d.dict.size != 0 {
2060                let c = d.dict.b.dict[(cur_pos.wrapping_sub(1)) & LZ_DICT_SIZE_MASK];
2061                cur_match_len = d.dict.b.dict[cur_pos..(cur_pos + lookahead_size)]
2062                    .iter()
2063                    .take_while(|&x| *x == c)
2064                    .count() as u32;
2065                if cur_match_len < MIN_MATCH_LEN.into() {
2066                    cur_match_len = 0
2067                } else {
2068                    cur_match_dist = 1
2069                }
2070            }
2071        } else {
2072            // Try to find a match for the bytes at the current position.
2073            let dist_len = d.dict.find_match(
2074                lookahead_pos,
2075                d.dict.size,
2076                lookahead_size as u32,
2077                cur_match_dist,
2078                cur_match_len,
2079            );
2080            cur_match_dist = dist_len.0;
2081            cur_match_len = dist_len.1;
2082        }
2083
2084        let far_and_small = cur_match_len == MIN_MATCH_LEN.into() && cur_match_dist >= 8 * 1024;
2085        let filter_small = d.params.flags & TDEFL_FILTER_MATCHES != 0 && cur_match_len <= 5;
2086        if far_and_small || filter_small || cur_pos == cur_match_dist as usize {
2087            cur_match_dist = 0;
2088            cur_match_len = 0;
2089        }
2090
2091        if saved_match_len != 0 {
2092            if cur_match_len > saved_match_len {
2093                record_literal(&mut d.huff, &mut d.lz, saved_lit);
2094                if cur_match_len >= 128 {
2095                    record_match(&mut d.huff, &mut d.lz, cur_match_len, cur_match_dist);
2096                    saved_match_len = 0;
2097                    len_to_move = cur_match_len as usize;
2098                } else {
2099                    saved_lit = d.dict.b.dict[cur_pos];
2100                    saved_match_dist = cur_match_dist;
2101                    saved_match_len = cur_match_len;
2102                }
2103            } else {
2104                record_match(&mut d.huff, &mut d.lz, saved_match_len, saved_match_dist);
2105                len_to_move = (saved_match_len - 1) as usize;
2106                saved_match_len = 0;
2107            }
2108        } else if cur_match_dist == 0 {
2109            record_literal(
2110                &mut d.huff,
2111                &mut d.lz,
2112                d.dict.b.dict[cmp::min(cur_pos, d.dict.b.dict.len() - 1)],
2113            );
2114        } else if d.params.greedy_parsing
2115            || (d.params.flags & TDEFL_RLE_MATCHES != 0)
2116            || cur_match_len >= 128
2117        {
2118            // If we are using lazy matching, check for matches at the next byte if the current
2119            // match was shorter than 128 bytes.
2120            record_match(&mut d.huff, &mut d.lz, cur_match_len, cur_match_dist);
2121            len_to_move = cur_match_len as usize;
2122        } else {
2123            saved_lit = d.dict.b.dict[cmp::min(cur_pos, d.dict.b.dict.len() - 1)];
2124            saved_match_dist = cur_match_dist;
2125            saved_match_len = cur_match_len;
2126        }
2127
2128        lookahead_pos += len_to_move;
2129        debug_assert!(lookahead_size >= len_to_move);
2130        lookahead_size -= len_to_move;
2131        d.dict.size = cmp::min(d.dict.size + len_to_move, LZ_DICT_SIZE);
2132
2133        let lz_buf_tight = d.lz.code_position > LZ_CODE_BUF_SIZE - 8;
2134        let fat = ((d.lz.code_position * 115) >> 7) >= d.lz.total_bytes as usize;
2135        let buf_fat = (d.lz.total_bytes > 31 * 1024) && fat;
2136
2137        if lz_buf_tight || buf_fat {
2138            d.params.src_pos = src_pos;
2139            // These values are used in flush_block, so we need to write them back here.
2140            d.dict.lookahead_size = lookahead_size;
2141            d.dict.lookahead_pos = lookahead_pos;
2142
2143            let n = flush_block(d, callback, TDEFLFlush::None)
2144                .unwrap_or(TDEFLStatus::PutBufFailed as i32);
2145            if n != 0 {
2146                d.params.saved_lit = saved_lit;
2147                d.params.saved_match_dist = saved_match_dist;
2148                d.params.saved_match_len = saved_match_len;
2149                return n > 0;
2150            }
2151        }
2152    }
2153
2154    d.params.src_pos = src_pos;
2155    d.dict.lookahead_size = lookahead_size;
2156    d.dict.lookahead_pos = lookahead_pos;
2157    d.params.saved_lit = saved_lit;
2158    d.params.saved_match_dist = saved_match_dist;
2159    d.params.saved_match_len = saved_match_len;
2160    true
2161}
2162
2163const COMP_FAST_LOOKAHEAD_SIZE: usize = 4096;
2164
2165fn compress_fast(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool {
2166    let mut src_pos = d.params.src_pos;
2167    let mut lookahead_size = d.dict.lookahead_size;
2168    let mut lookahead_pos = d.dict.lookahead_pos;
2169
2170    let mut cur_pos = lookahead_pos & LZ_DICT_SIZE_MASK;
2171    let in_buf = match callback.in_buf {
2172        None => return true,
2173        Some(in_buf) => in_buf,
2174    };
2175
2176    debug_assert!(d.lz.code_position < LZ_CODE_BUF_SIZE - 2);
2177
2178    while src_pos < in_buf.len() || (d.params.flush != TDEFLFlush::None && lookahead_size > 0) {
2179        let mut dst_pos = (lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK;
2180        let mut num_bytes_to_process = cmp::min(
2181            in_buf.len() - src_pos,
2182            COMP_FAST_LOOKAHEAD_SIZE - lookahead_size,
2183        );
2184        lookahead_size += num_bytes_to_process;
2185
2186        while num_bytes_to_process != 0 {
2187            let n = cmp::min(LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
2188            d.dict.b.dict[dst_pos..dst_pos + n].copy_from_slice(&in_buf[src_pos..src_pos + n]);
2189
2190            if dst_pos < MAX_MATCH_LEN - 1 {
2191                let m = cmp::min(n, MAX_MATCH_LEN - 1 - dst_pos);
2192                d.dict.b.dict[dst_pos + LZ_DICT_SIZE..dst_pos + LZ_DICT_SIZE + m]
2193                    .copy_from_slice(&in_buf[src_pos..src_pos + m]);
2194            }
2195
2196            src_pos += n;
2197            dst_pos = (dst_pos + n) & LZ_DICT_SIZE_MASK;
2198            num_bytes_to_process -= n;
2199        }
2200
2201        d.dict.size = cmp::min(LZ_DICT_SIZE - lookahead_size, d.dict.size);
2202        if d.params.flush == TDEFLFlush::None && lookahead_size < COMP_FAST_LOOKAHEAD_SIZE {
2203            break;
2204        }
2205
2206        while lookahead_size >= 4 {
2207            let mut cur_match_len = 1;
2208
2209            let first_trigram = d.dict.read_unaligned_u32(cur_pos) & 0xFF_FFFF;
2210
2211            let hash = (first_trigram ^ (first_trigram >> (24 - (LZ_HASH_BITS - 8))))
2212                & LEVEL1_HASH_SIZE_MASK;
2213
2214            let mut probe_pos = usize::from(d.dict.b.hash[hash as usize]);
2215            d.dict.b.hash[hash as usize] = lookahead_pos as u16;
2216
2217            let mut cur_match_dist = (lookahead_pos - probe_pos) as u16;
2218            if cur_match_dist as usize <= d.dict.size {
2219                probe_pos &= LZ_DICT_SIZE_MASK;
2220
2221                let trigram = d.dict.read_unaligned_u32(probe_pos) & 0xFF_FFFF;
2222
2223                if first_trigram == trigram {
2224                    // Trigram was tested, so we can start with "+ 3" displacement.
2225                    let mut p = cur_pos + 3;
2226                    let mut q = probe_pos + 3;
2227                    cur_match_len = (|| {
2228                        for _ in 0..32 {
2229                            let p_data: u64 = d.dict.read_unaligned_u64(p);
2230                            let q_data: u64 = d.dict.read_unaligned_u64(q);
2231                            let xor_data = p_data ^ q_data;
2232                            if xor_data == 0 {
2233                                p += 8;
2234                                q += 8;
2235                            } else {
2236                                let trailing = xor_data.trailing_zeros();
2237                                return p as u32 - cur_pos as u32 + (trailing >> 3);
2238                            }
2239                        }
2240
2241                        if cur_match_dist == 0 {
2242                            0
2243                        } else {
2244                            MAX_MATCH_LEN as u32
2245                        }
2246                    })();
2247
2248                    if cur_match_len < MIN_MATCH_LEN.into()
2249                        || (cur_match_len == MIN_MATCH_LEN.into() && cur_match_dist >= 8 * 1024)
2250                    {
2251                        let lit = first_trigram as u8;
2252                        cur_match_len = 1;
2253                        d.lz.write_code(lit);
2254                        *d.lz.get_flag() >>= 1;
2255                        d.huff.count[0][lit as usize] += 1;
2256                    } else {
2257                        // Limit the match to the length of the lookahead so we don't create a match
2258                        // that ends after the end of the input data.
2259                        cur_match_len = cmp::min(cur_match_len, lookahead_size as u32);
2260                        debug_assert!(cur_match_len >= MIN_MATCH_LEN.into());
2261                        debug_assert!(cur_match_len <= MAX_MATCH_LEN as u32);
2262                        debug_assert!(cur_match_dist >= 1);
2263                        debug_assert!(cur_match_dist as usize <= LZ_DICT_SIZE);
2264                        cur_match_dist -= 1;
2265
2266                        d.lz.write_code((cur_match_len - u32::from(MIN_MATCH_LEN)) as u8);
2267                        d.lz.write_code(cur_match_dist as u8);
2268                        d.lz.write_code((cur_match_dist >> 8) as u8);
2269
2270                        *d.lz.get_flag() >>= 1;
2271                        *d.lz.get_flag() |= 0x80;
2272                        if cur_match_dist < 512 {
2273                            d.huff.count[1][SMALL_DIST_SYM[cur_match_dist as usize] as usize] += 1;
2274                        } else {
2275                            d.huff.count[1]
2276                                [LARGE_DIST_SYM[(cur_match_dist >> 8) as usize] as usize] += 1;
2277                        }
2278
2279                        d.huff.count[0][(LEN_SYM
2280                            [(cur_match_len - u32::from(MIN_MATCH_LEN)) as usize & 255]
2281                            as usize
2282                            & 31)
2283                            + LEN_SYM_OFFSET] += 1;
2284                    }
2285                } else {
2286                    d.lz.write_code(first_trigram as u8);
2287                    *d.lz.get_flag() >>= 1;
2288                    d.huff.count[0][first_trigram as u8 as usize] += 1;
2289                }
2290
2291                d.lz.consume_flag();
2292                d.lz.total_bytes += cur_match_len;
2293                lookahead_pos += cur_match_len as usize;
2294                d.dict.size = cmp::min(d.dict.size + cur_match_len as usize, LZ_DICT_SIZE);
2295                cur_pos = (cur_pos + cur_match_len as usize) & LZ_DICT_SIZE_MASK;
2296                lookahead_size -= cur_match_len as usize;
2297
2298                if d.lz.code_position > LZ_CODE_BUF_SIZE - 8 {
2299                    // These values are used in flush_block, so we need to write them back here.
2300                    d.dict.lookahead_size = lookahead_size;
2301                    d.dict.lookahead_pos = lookahead_pos;
2302
2303                    let n = match flush_block(d, callback, TDEFLFlush::None) {
2304                        Err(_) => {
2305                            d.params.src_pos = src_pos;
2306                            d.params.prev_return_status = TDEFLStatus::PutBufFailed;
2307                            return false;
2308                        }
2309                        Ok(status) => status,
2310                    };
2311                    if n != 0 {
2312                        d.params.src_pos = src_pos;
2313                        return n > 0;
2314                    }
2315                    debug_assert!(d.lz.code_position < LZ_CODE_BUF_SIZE - 2);
2316
2317                    lookahead_size = d.dict.lookahead_size;
2318                    lookahead_pos = d.dict.lookahead_pos;
2319                }
2320            }
2321        }
2322
2323        while lookahead_size != 0 {
2324            let lit = d.dict.b.dict[cur_pos];
2325            d.lz.total_bytes += 1;
2326            d.lz.write_code(lit);
2327            *d.lz.get_flag() >>= 1;
2328            d.lz.consume_flag();
2329
2330            d.huff.count[0][lit as usize] += 1;
2331            lookahead_pos += 1;
2332            d.dict.size = cmp::min(d.dict.size + 1, LZ_DICT_SIZE);
2333            cur_pos = (cur_pos + 1) & LZ_DICT_SIZE_MASK;
2334            lookahead_size -= 1;
2335
2336            if d.lz.code_position > LZ_CODE_BUF_SIZE - 8 {
2337                // These values are used in flush_block, so we need to write them back here.
2338                d.dict.lookahead_size = lookahead_size;
2339                d.dict.lookahead_pos = lookahead_pos;
2340
2341                let n = match flush_block(d, callback, TDEFLFlush::None) {
2342                    Err(_) => {
2343                        d.params.prev_return_status = TDEFLStatus::PutBufFailed;
2344                        d.params.src_pos = src_pos;
2345                        return false;
2346                    }
2347                    Ok(status) => status,
2348                };
2349                if n != 0 {
2350                    d.params.src_pos = src_pos;
2351                    return n > 0;
2352                }
2353
2354                lookahead_size = d.dict.lookahead_size;
2355                lookahead_pos = d.dict.lookahead_pos;
2356            }
2357        }
2358    }
2359
2360    d.params.src_pos = src_pos;
2361    d.dict.lookahead_size = lookahead_size;
2362    d.dict.lookahead_pos = lookahead_pos;
2363    true
2364}
2365
2366fn flush_output_buffer(c: &mut CallbackOxide, p: &mut ParamsOxide) -> (TDEFLStatus, usize, usize) {
2367    let mut res = (TDEFLStatus::Okay, p.src_pos, 0);
2368    if let CallbackOut::Buf(ref mut cb) = c.out {
2369        let n = cmp::min(cb.out_buf.len() - p.out_buf_ofs, p.flush_remaining as usize);
2370        if n != 0 {
2371            cb.out_buf[p.out_buf_ofs..p.out_buf_ofs + n]
2372                .copy_from_slice(&p.local_buf.b[p.flush_ofs as usize..p.flush_ofs as usize + n]);
2373        }
2374        p.flush_ofs += n as u32;
2375        p.flush_remaining -= n as u32;
2376        p.out_buf_ofs += n;
2377        res.2 = p.out_buf_ofs;
2378    }
2379
2380    if p.finished && p.flush_remaining == 0 {
2381        res.0 = TDEFLStatus::Done
2382    }
2383    res
2384}
2385
2386/// Main compression function. Tries to compress as much as possible from `in_buf` and
2387/// puts compressed output into `out_buf`.
2388///
2389/// The value of `flush` determines if the compressor should attempt to flush all output
2390/// and alternatively try to finish the stream.
2391///
2392/// Use [`TDEFLFlush::Finish`] on the final call to signal that the stream is finishing.
2393///
2394/// Note that this function does not keep track of whether a flush marker has been output, so
2395/// if called using [`TDEFLFlush::Sync`], the caller needs to ensure there is enough space in the
2396/// output buffer if they want to avoid repeated flush markers.
2397/// See #105 for details.
2398///
2399/// # Returns
2400/// Returns a tuple containing the current status of the compressor, the current position
2401/// in the input buffer and the current position in the output buffer.
2402/// A result of [`TDEFLStatus::Done`] indicates that compression is finished, and further calls to this function will
2403/// result in [`TDEFLStatus::BadParam`].
2404/// See [`TDEFLStatus`] for other return values.
2405pub fn compress(
2406    d: &mut CompressorOxide,
2407    in_buf: &[u8],
2408    out_buf: &mut [u8],
2409    flush: TDEFLFlush,
2410) -> (TDEFLStatus, usize, usize) {
2411    compress_inner(
2412        d,
2413        &mut CallbackOxide::new_callback_buf(in_buf, out_buf),
2414        flush,
2415    )
2416}
2417
2418/// Main compression function. Callbacks output.
2419///
2420/// # Returns
2421/// Returns a tuple containing the current status of the compressor, the current position
2422/// in the input buffer.
2423///
2424/// The caller is responsible for ensuring the `CallbackFunc` struct will not cause undefined
2425/// behaviour.
2426pub fn compress_to_output(
2427    d: &mut CompressorOxide,
2428    in_buf: &[u8],
2429    flush: TDEFLFlush,
2430    mut callback_func: impl FnMut(&[u8]) -> bool,
2431) -> (TDEFLStatus, usize) {
2432    let res = compress_inner(
2433        d,
2434        &mut CallbackOxide::new_callback_func(
2435            in_buf,
2436            CallbackFunc {
2437                put_buf_func: &mut callback_func,
2438            },
2439        ),
2440        flush,
2441    );
2442
2443    (res.0, res.1)
2444}
2445
2446fn compress_inner(
2447    d: &mut CompressorOxide,
2448    callback: &mut CallbackOxide,
2449    flush: TDEFLFlush,
2450) -> (TDEFLStatus, usize, usize) {
2451    d.params.out_buf_ofs = 0;
2452    d.params.src_pos = 0;
2453
2454    let prev_ok = d.params.prev_return_status == TDEFLStatus::Okay;
2455    let flush_finish_once = d.params.flush != TDEFLFlush::Finish || flush == TDEFLFlush::Finish;
2456
2457    d.params.flush = flush;
2458    if !prev_ok || !flush_finish_once {
2459        d.params.prev_return_status = TDEFLStatus::BadParam;
2460        return (d.params.prev_return_status, 0, 0);
2461    }
2462
2463    if d.params.flush_remaining != 0 || d.params.finished {
2464        let res = flush_output_buffer(callback, &mut d.params);
2465        d.params.prev_return_status = res.0;
2466        return res;
2467    }
2468
2469    let one_probe = d.params.flags & MAX_PROBES_MASK == 1;
2470    let greedy = d.params.flags & TDEFL_GREEDY_PARSING_FLAG != 0;
2471    let filter_or_rle = d.params.flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS) != 0;
2472
2473    let raw = d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0;
2474
2475    let compress_success = if raw {
2476        compress_stored(d, callback)
2477    } else if one_probe && greedy && !filter_or_rle {
2478        compress_fast(d, callback)
2479    } else {
2480        compress_normal(d, callback)
2481    };
2482
2483    if !compress_success {
2484        return (
2485            d.params.prev_return_status,
2486            d.params.src_pos,
2487            d.params.out_buf_ofs,
2488        );
2489    }
2490
2491    if let Some(in_buf) = callback.in_buf {
2492        if d.params.flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32) != 0 {
2493            d.params.adler32 = update_adler32(d.params.adler32, &in_buf[..d.params.src_pos]);
2494        }
2495    }
2496
2497    let flush_none = d.params.flush == TDEFLFlush::None;
2498    let in_left = callback.in_buf.map_or(0, |buf| buf.len()) - d.params.src_pos;
2499    let remaining = in_left != 0 || d.params.flush_remaining != 0;
2500    if !flush_none && d.dict.lookahead_size == 0 && !remaining {
2501        let flush = d.params.flush;
2502        match flush_block(d, callback, flush) {
2503            Err(_) => {
2504                d.params.prev_return_status = TDEFLStatus::PutBufFailed;
2505                return (
2506                    d.params.prev_return_status,
2507                    d.params.src_pos,
2508                    d.params.out_buf_ofs,
2509                );
2510            }
2511            Ok(x) if x < 0 => {
2512                return (
2513                    d.params.prev_return_status,
2514                    d.params.src_pos,
2515                    d.params.out_buf_ofs,
2516                )
2517            }
2518            _ => {
2519                d.params.finished = d.params.flush == TDEFLFlush::Finish;
2520                if d.params.flush == TDEFLFlush::Full {
2521                    d.dict.b.hash.fill(0);
2522                    d.dict.b.next.fill(0);
2523                    d.dict.size = 0;
2524                }
2525            }
2526        }
2527    }
2528
2529    let res = flush_output_buffer(callback, &mut d.params);
2530    d.params.prev_return_status = res.0;
2531
2532    res
2533}
2534
2535/// Create a set of compression flags using parameters used by zlib and other compressors.
2536/// Mainly intended for use with transition from c libraries as it deals with raw integers.
2537///
2538/// # Parameters
2539/// `level` determines compression level. Clamped to maximum of 10. Negative values result in
2540/// `CompressionLevel::DefaultLevel`.
2541/// `window_bits`: Above 0, wraps the stream in a zlib wrapper, 0 or negative for a raw deflate
2542/// stream.
2543/// `strategy`: Sets the strategy if this conforms to any of the values in `CompressionStrategy`.
2544///
2545/// # Notes
2546/// This function may be removed or moved to the `miniz_oxide_c_api` in the future.
2547pub const fn create_comp_flags_from_zip_params(level: i32, window_bits: i32, strategy: i32) -> u32 {
2548    let num_probes = (if level >= 0 {
2549        // Manual min since cmp::min is not const.
2550        if level > 10 {
2551            10
2552        } else {
2553            level
2554        }
2555        //cmp::min(10, level)
2556    } else {
2557        CompressionLevel::DefaultLevel as i32
2558    }) as usize;
2559    let greedy = if level <= 3 {
2560        TDEFL_GREEDY_PARSING_FLAG
2561    } else {
2562        0
2563    };
2564    let mut comp_flags = NUM_PROBES[num_probes] as u32 | greedy;
2565
2566    if window_bits > 0 {
2567        comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
2568    }
2569
2570    if level == 0 {
2571        comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
2572    } else if strategy == CompressionStrategy::Filtered as i32 {
2573        comp_flags |= TDEFL_FILTER_MATCHES;
2574    } else if strategy == CompressionStrategy::HuffmanOnly as i32 {
2575        comp_flags &= !MAX_PROBES_MASK;
2576    } else if strategy == CompressionStrategy::Fixed as i32 {
2577        comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
2578    } else if strategy == CompressionStrategy::RLE as i32 {
2579        comp_flags |= TDEFL_RLE_MATCHES;
2580    }
2581
2582    comp_flags
2583}
2584
2585/// Check if the window is
2586const fn window_bits_from_flags(flags: u32) -> u8 {
2587    if (flags & TDEFL_FORCE_ALL_RAW_BLOCKS & TDEFL_RLE_MATCHES) != 0
2588        || (flags & MAX_PROBES_MASK) == 0
2589    {
2590        1
2591    } else if (flags & MAX_PROBES_MASK) == 1 {
2592        12
2593    } else {
2594        15
2595    }
2596}
2597
2598#[cfg(test)]
2599mod test {
2600    use super::{
2601        compress_to_output, create_comp_flags_from_zip_params, read_u16_le, write_u16_le,
2602        CompressionStrategy, CompressorOxide, TDEFLFlush, TDEFLStatus, DEFAULT_FLAGS,
2603        MZ_DEFAULT_WINDOW_BITS,
2604    };
2605    use crate::inflate::decompress_to_vec;
2606    use alloc::vec;
2607
2608    #[test]
2609    fn u16_to_slice() {
2610        let mut slice = [0, 0];
2611        write_u16_le(2000, &mut slice, 0);
2612        assert_eq!(slice, [208, 7]);
2613    }
2614
2615    #[test]
2616    fn u16_from_slice() {
2617        let slice = [208, 7];
2618        assert_eq!(read_u16_le(&slice, 0), 2000);
2619    }
2620
2621    #[test]
2622    fn compress_output() {
2623        assert_eq!(
2624            DEFAULT_FLAGS,
2625            create_comp_flags_from_zip_params(
2626                4,
2627                MZ_DEFAULT_WINDOW_BITS,
2628                CompressionStrategy::Default as i32
2629            )
2630        );
2631
2632        let slice = [
2633            1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 6, 1, 2, 3, 1, 2, 3, 2, 3, 1, 2, 3,
2634        ];
2635        let mut encoded = vec![];
2636        let flags = create_comp_flags_from_zip_params(6, 0, 0);
2637        let mut d = CompressorOxide::new(flags);
2638        let (status, in_consumed) =
2639            compress_to_output(&mut d, &slice, TDEFLFlush::Finish, |out: &[u8]| {
2640                encoded.extend_from_slice(out);
2641                true
2642            });
2643
2644        assert_eq!(status, TDEFLStatus::Done);
2645        assert_eq!(in_consumed, slice.len());
2646
2647        let decoded = decompress_to_vec(&encoded[..]).unwrap();
2648        assert_eq!(&decoded[..], &slice[..]);
2649    }
2650
2651    #[test]
2652    /// Check fast compress mode
2653    fn compress_fast() {
2654        let slice = [
2655            1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 6, 1, 2, 3, 1, 2, 3, 2, 3, 1, 2, 3,
2656        ];
2657        let mut encoded = vec![];
2658        let flags = create_comp_flags_from_zip_params(1, 0, 0);
2659        let mut d = CompressorOxide::new(flags);
2660        let (status, in_consumed) =
2661            compress_to_output(&mut d, &slice, TDEFLFlush::Finish, |out: &[u8]| {
2662                encoded.extend_from_slice(out);
2663                true
2664            });
2665
2666        assert_eq!(status, TDEFLStatus::Done);
2667        assert_eq!(in_consumed, slice.len());
2668
2669        // Needs to be altered if algorithm improves.
2670        assert_eq!(
2671            &encoded[..],
2672            [99, 100, 98, 102, 1, 98, 48, 98, 3, 147, 204, 76, 204, 140, 76, 204, 0]
2673        );
2674
2675        let decoded = decompress_to_vec(&encoded[..]).unwrap();
2676        assert_eq!(&decoded[..], &slice[..]);
2677    }
2678
2679    #[test]
2680    fn zlib_window_bits() {
2681        use super::TDEFL_RLE_MATCHES;
2682        use crate::deflate::CompressionLevel;
2683        use crate::inflate::stream::{inflate, InflateState};
2684        use crate::DataFormat;
2685        use alloc::boxed::Box;
2686        let slice = [
2687            1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 6, 1, 2, 3, 1, 2, 3, 2, 3, 1, 2, 3, 35, 22, 22, 2,
2688            6, 2, 6,
2689        ];
2690        let mut encoded = vec![];
2691
2692        // Create compressor with small window bits param
2693        let mut d = CompressorOxide::with_params(
2694            DataFormat::Zlib,
2695            CompressionLevel::DefaultCompression.into(),
2696            CompressionStrategy::Default,
2697            1,
2698        );
2699
2700        assert!((d.params.flags & TDEFL_RLE_MATCHES) != 0);
2701
2702        let (status, in_consumed) =
2703            compress_to_output(&mut d, &slice, TDEFLFlush::Finish, |out: &[u8]| {
2704                encoded.extend_from_slice(out);
2705                true
2706            });
2707
2708        assert_eq!(status, TDEFLStatus::Done);
2709        assert_eq!(in_consumed, slice.len());
2710
2711        let mut output = vec![0; slice.len()];
2712
2713        let mut decompressor = Box::new(InflateState::new(DataFormat::Zlib));
2714
2715        let mut out_slice = output.as_mut_slice();
2716        // Feed 1 byte at a time and no back buffer to test that RLE encoding has been used.
2717        for i in 0..encoded.len() {
2718            let result = inflate(
2719                &mut decompressor,
2720                &encoded[i..i + 1],
2721                out_slice,
2722                crate::MZFlush::None,
2723            );
2724            out_slice = &mut out_slice[result.bytes_written..];
2725        }
2726        let cmf = decompressor.decompressor().zlib_header().0;
2727        assert_eq!(cmf, 8);
2728        assert_eq!(output, slice)
2729    }
2730}