1use alloc::boxed::Box;
4use core::convert::TryInto;
5use core::{cmp, mem};
6
7use super::super::*;
8use super::deflate_flags::*;
9use super::CompressionLevel;
10use crate::deflate::buffer::{
11    update_hash, HashBuffers, LocalBuf, LZ_CODE_BUF_MASK, LZ_CODE_BUF_SIZE, LZ_DICT_FULL_SIZE,
12    LZ_HASH_BITS, LZ_HASH_SHIFT, LZ_HASH_SIZE, OUT_BUF_SIZE,
13};
14use crate::deflate::stored::compress_stored;
15use crate::deflate::zlib;
16use crate::shared::{update_adler32, HUFFMAN_LENGTH_ORDER, MZ_ADLER32_INIT};
17use crate::DataFormat;
18
19type Result<T, E = Error> = core::result::Result<T, E>;
22pub(crate) struct Error {}
23
24pub(crate) const MAX_PROBES_MASK: u32 = 0xFFF;
25
26const MAX_SUPPORTED_HUFF_CODESIZE: usize = 15;
27
28const LEN_SYM: [u8; 256] = [
34    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,
35    15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19,
36    19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
37    21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23,
38    23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
39    24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
40    25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
41    26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27,
42    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
43    27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
44    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29,
45];
46
47const LEN_SYM_OFFSET: usize = 256;
48
49#[rustfmt::skip]
51const LEN_EXTRA: [u8; 256] = [
52    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
53    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
54    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
55    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
56    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
57    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
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    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
61    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
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, 0
68];
69
70#[rustfmt::skip]
72const SMALL_DIST_SYM: [u8; 512] = [
73     0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,
74     8,  8,  8,  8,  8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9,
75    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
76    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
77    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
78    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
79    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
80    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
81    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
82    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
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    15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
86    15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
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    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
90    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
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    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
98    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
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];
106
107#[rustfmt::skip]
109const SMALL_DIST_EXTRA: [u8; 512] = [
110    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,
111    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,
112    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,
113    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,
114    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,
115    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,
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    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,
119    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,
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];
127
128#[rustfmt::skip]
130const LARGE_DIST_SYM: [u8; 128] = [
131     0,  0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
132    24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25,
133    26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
134    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
135    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
136    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
137    29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
138    29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
139];
140
141#[rustfmt::skip]
143const LARGE_DIST_EXTRA: [u8; 128] = [
144     0,  0,  8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
145    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
146    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
147    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
148    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
149    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
150    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
151    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13
152];
153
154#[rustfmt::skip]
155const BITMASKS: [u32; 17] = [
156    0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
157    0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
158];
159
160pub(crate) const NUM_PROBES: [u16; 11] = [0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500];
163
164#[derive(Copy, Clone)]
165struct SymFreq {
166    key: u16,
167    sym_index: u16,
168}
169
170pub mod deflate_flags {
171    pub const TDEFL_WRITE_ZLIB_HEADER: u32 = 0x0000_1000;
173    pub const TDEFL_COMPUTE_ADLER32: u32 = 0x0000_2000;
175    pub const TDEFL_GREEDY_PARSING_FLAG: u32 = 0x0000_4000;
178    pub const TDEFL_NONDETERMINISTIC_PARSING_FLAG: u32 = 0x0000_8000;
181    pub const TDEFL_RLE_MATCHES: u32 = 0x0001_0000;
183    pub const TDEFL_FILTER_MATCHES: u32 = 0x0002_0000;
185    pub const TDEFL_FORCE_ALL_STATIC_BLOCKS: u32 = 0x0004_0000;
188    pub const TDEFL_FORCE_ALL_RAW_BLOCKS: u32 = 0x0008_0000;
190}
191
192#[repr(i32)]
196#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
197pub enum CompressionStrategy {
198    Default = 0,
200    Filtered = 1,
202    HuffmanOnly = 2,
204    RLE = 3,
206    Fixed = 4,
209}
210
211impl From<CompressionStrategy> for i32 {
212    #[inline(always)]
213    fn from(value: CompressionStrategy) -> Self {
214        value as i32
215    }
216}
217
218#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
220pub enum TDEFLFlush {
221    None = 0,
225
226    Sync = 2,
228
229    Full = 3,
232
233    Finish = 4,
237}
238
239impl From<MZFlush> for TDEFLFlush {
240    fn from(flush: MZFlush) -> Self {
241        match flush {
242            MZFlush::None => TDEFLFlush::None,
243            MZFlush::Sync => TDEFLFlush::Sync,
244            MZFlush::Full => TDEFLFlush::Full,
245            MZFlush::Finish => TDEFLFlush::Finish,
246            _ => TDEFLFlush::None, }
248    }
249}
250
251impl TDEFLFlush {
252    pub const fn new(flush: i32) -> Result<Self, MZError> {
253        match flush {
254            0 => Ok(TDEFLFlush::None),
255            2 => Ok(TDEFLFlush::Sync),
256            3 => Ok(TDEFLFlush::Full),
257            4 => Ok(TDEFLFlush::Finish),
258            _ => Err(MZError::Param),
259        }
260    }
261}
262
263#[repr(i32)]
265#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
266pub enum TDEFLStatus {
267    BadParam = -2,
272
273    PutBufFailed = -1,
277
278    Okay = 0,
280
281    Done = 1,
285}
286
287const MAX_HUFF_SYMBOLS: usize = 288;
288const LEVEL1_HASH_SIZE_MASK: u32 = 4095;
290const MAX_HUFF_TABLES: usize = 3;
293const MAX_HUFF_SYMBOLS_0: usize = 288;
295const MAX_HUFF_SYMBOLS_1: usize = 32;
297const MAX_HUFF_SYMBOLS_2: usize = 19;
299pub(crate) const LZ_DICT_SIZE: usize = 32_768;
301pub(crate) const LZ_DICT_SIZE_MASK: usize = (LZ_DICT_SIZE as u32 - 1) as usize;
303pub(crate) const MIN_MATCH_LEN: u8 = 3;
305pub(crate) const MAX_MATCH_LEN: usize = 258;
307
308pub(crate) const DEFAULT_FLAGS: u32 = NUM_PROBES[4] as u32 | TDEFL_WRITE_ZLIB_HEADER;
309
310#[cfg(test)]
311#[inline]
312fn write_u16_le(val: u16, slice: &mut [u8], pos: usize) {
313    slice[pos] = val as u8;
314    slice[pos + 1] = (val >> 8) as u8;
315}
316
317#[inline(always)]
319const fn read_u16_le<const N: usize>(slice: &[u8; N], pos: usize) -> u16 {
320    slice[pos] as u16 | ((slice[pos + 1] as u16) << 8)
322}
323
324pub struct CompressorOxide {
326    pub(crate) lz: LZOxide,
327    pub(crate) params: ParamsOxide,
328    pub(crate) huff: Box<HuffmanOxide>,
331    pub(crate) dict: DictOxide,
332}
333
334impl CompressorOxide {
335    pub fn new(flags: u32) -> Self {
340        CompressorOxide {
341            lz: LZOxide::new(),
342            params: ParamsOxide::new(flags),
343            huff: Box::default(),
344            dict: DictOxide::new(flags),
345        }
346    }
347
348    pub const fn adler32(&self) -> u32 {
350        self.params.adler32
351    }
352
353    pub const fn prev_return_status(&self) -> TDEFLStatus {
356        self.params.prev_return_status
357    }
358
359    pub const fn flags(&self) -> i32 {
364        self.params.flags as i32
365    }
366
367    pub const fn data_format(&self) -> DataFormat {
369        if (self.params.flags & TDEFL_WRITE_ZLIB_HEADER) != 0 {
370            DataFormat::Zlib
371        } else {
372            DataFormat::Raw
373        }
374    }
375
376    pub fn reset(&mut self) {
380        self.lz = LZOxide::new();
383        self.params.reset();
384        *self.huff = HuffmanOxide::default();
385        self.dict.reset();
386    }
387
388    pub fn set_compression_level(&mut self, level: CompressionLevel) {
394        let format = self.data_format();
395        self.set_format_and_level(format, level as u8);
396    }
397
398    pub fn set_compression_level_raw(&mut self, level: u8) {
404        let format = self.data_format();
405        self.set_format_and_level(format, level);
406    }
407
408    pub fn set_format_and_level(&mut self, data_format: DataFormat, level: u8) {
418        let flags = create_comp_flags_from_zip_params(
419            level.into(),
420            data_format.to_window_bits(),
421            CompressionStrategy::Default as i32,
422        );
423        self.params.update_flags(flags);
424        self.dict.update_flags(flags);
425    }
426}
427
428impl Default for CompressorOxide {
429    fn default() -> Self {
432        CompressorOxide {
433            lz: LZOxide::new(),
434            params: ParamsOxide::new(DEFAULT_FLAGS),
435            huff: Box::default(),
436            dict: DictOxide::new(DEFAULT_FLAGS),
437        }
438    }
439}
440
441pub struct CallbackFunc<'a> {
443    pub put_buf_func: &'a mut dyn FnMut(&[u8]) -> bool,
444}
445
446impl CallbackFunc<'_> {
447    fn flush_output(
448        &mut self,
449        saved_output: SavedOutputBufferOxide,
450        params: &mut ParamsOxide,
451    ) -> i32 {
452        let call_success = (self.put_buf_func)(¶ms.local_buf.b[0..saved_output.pos]);
456
457        if !call_success {
458            params.prev_return_status = TDEFLStatus::PutBufFailed;
459            return params.prev_return_status as i32;
460        }
461
462        params.flush_remaining as i32
463    }
464}
465
466struct CallbackBuf<'a> {
467    pub out_buf: &'a mut [u8],
468}
469
470impl CallbackBuf<'_> {
471    fn flush_output(
472        &mut self,
473        saved_output: SavedOutputBufferOxide,
474        params: &mut ParamsOxide,
475    ) -> i32 {
476        if saved_output.local {
477            let n = cmp::min(saved_output.pos, self.out_buf.len() - params.out_buf_ofs);
478            (self.out_buf[params.out_buf_ofs..params.out_buf_ofs + n])
479                .copy_from_slice(¶ms.local_buf.b[..n]);
480
481            params.out_buf_ofs += n;
482            if saved_output.pos != n {
483                params.flush_ofs = n as u32;
484                params.flush_remaining = (saved_output.pos - n) as u32;
485            }
486        } else {
487            params.out_buf_ofs += saved_output.pos;
488        }
489
490        params.flush_remaining as i32
491    }
492}
493
494enum CallbackOut<'a> {
495    Func(CallbackFunc<'a>),
496    Buf(CallbackBuf<'a>),
497}
498
499impl CallbackOut<'_> {
500    fn new_output_buffer<'b>(
501        &'b mut self,
502        local_buf: &'b mut [u8],
503        out_buf_ofs: usize,
504    ) -> OutputBufferOxide<'b> {
505        let is_local;
506        let buf_len = OUT_BUF_SIZE - 16;
507        let chosen_buffer = match *self {
508            CallbackOut::Buf(ref mut cb) if cb.out_buf.len() - out_buf_ofs >= OUT_BUF_SIZE => {
509                is_local = false;
510                &mut cb.out_buf[out_buf_ofs..out_buf_ofs + buf_len]
511            }
512            _ => {
513                is_local = true;
514                &mut local_buf[..buf_len]
515            }
516        };
517
518        OutputBufferOxide {
519            inner: chosen_buffer,
520            inner_pos: 0,
521            local: is_local,
522            bit_buffer: 0,
523            bits_in: 0,
524        }
525    }
526}
527
528pub(crate) struct CallbackOxide<'a> {
529    in_buf: Option<&'a [u8]>,
530    in_buf_size: Option<&'a mut usize>,
531    out_buf_size: Option<&'a mut usize>,
532    out: CallbackOut<'a>,
533}
534
535impl<'a> CallbackOxide<'a> {
536    fn new_callback_buf(in_buf: &'a [u8], out_buf: &'a mut [u8]) -> Self {
537        CallbackOxide {
538            in_buf: Some(in_buf),
539            in_buf_size: None,
540            out_buf_size: None,
541            out: CallbackOut::Buf(CallbackBuf { out_buf }),
542        }
543    }
544
545    fn new_callback_func(in_buf: &'a [u8], callback_func: CallbackFunc<'a>) -> Self {
546        CallbackOxide {
547            in_buf: Some(in_buf),
548            in_buf_size: None,
549            out_buf_size: None,
550            out: CallbackOut::Func(callback_func),
551        }
552    }
553
554    fn update_size(&mut self, in_size: Option<usize>, out_size: Option<usize>) {
555        if let (Some(in_size), Some(size)) = (in_size, self.in_buf_size.as_mut()) {
556            **size = in_size;
557        }
558
559        if let (Some(out_size), Some(size)) = (out_size, self.out_buf_size.as_mut()) {
560            **size = out_size
561        }
562    }
563
564    fn flush_output(
565        &mut self,
566        saved_output: SavedOutputBufferOxide,
567        params: &mut ParamsOxide,
568    ) -> i32 {
569        if saved_output.pos == 0 {
570            return params.flush_remaining as i32;
571        }
572
573        self.update_size(Some(params.src_pos), None);
574        match self.out {
575            CallbackOut::Func(ref mut cf) => cf.flush_output(saved_output, params),
576            CallbackOut::Buf(ref mut cb) => cb.flush_output(saved_output, params),
577        }
578    }
579
580    pub(crate) fn buf(&mut self) -> Option<&'a [u8]> {
581        self.in_buf
582    }
583}
584
585struct OutputBufferOxide<'a> {
586    pub inner: &'a mut [u8],
587    pub inner_pos: usize,
588    pub local: bool,
589
590    pub bit_buffer: u32,
591    pub bits_in: u32,
592}
593
594impl OutputBufferOxide<'_> {
595    fn put_bits(&mut self, bits: u32, len: u32) {
599        assert!(bits <= ((1u32 << len) - 1u32));
602        self.bit_buffer |= bits << self.bits_in;
603        self.bits_in += len;
604
605        while self.bits_in >= 8 {
606            self.inner[self.inner_pos] = self.bit_buffer as u8;
607            self.inner_pos += 1;
608            self.bit_buffer >>= 8;
609            self.bits_in -= 8;
610        }
611    }
612
613    #[inline]
614    fn put_bits_no_flush(&mut self, bits: u32, len: u32) {
617        self.bit_buffer |= bits << self.bits_in;
618        self.bits_in += len;
619    }
620
621    const fn save(&self) -> SavedOutputBufferOxide {
622        SavedOutputBufferOxide {
623            pos: self.inner_pos,
624            bit_buffer: self.bit_buffer,
625            bits_in: self.bits_in,
626            local: self.local,
627        }
628    }
629
630    fn load(&mut self, saved: SavedOutputBufferOxide) {
631        self.inner_pos = saved.pos;
632        self.bit_buffer = saved.bit_buffer;
633        self.bits_in = saved.bits_in;
634        self.local = saved.local;
635    }
636
637    #[inline]
638    fn pad_to_bytes(&mut self) {
641        if self.bits_in != 0 {
642            let len = 8 - self.bits_in;
643            self.put_bits(0, len);
644        }
645    }
646
647    #[inline]
648    fn write_bytes(&mut self, bytes: &[u8]) {
649        debug_assert_eq!(self.bits_in, 0);
650        self.inner[self.inner_pos..self.inner_pos + bytes.len()].copy_from_slice(bytes);
651        self.inner_pos += bytes.len();
652    }
653}
654
655struct SavedOutputBufferOxide {
656    pub pos: usize,
657    pub bit_buffer: u32,
658    pub bits_in: u32,
659    pub local: bool,
660}
661
662struct BitBuffer {
663    pub bit_buffer: u64,
664    pub bits_in: u32,
665}
666
667impl BitBuffer {
668    fn put_fast(&mut self, bits: u64, len: u32) {
669        self.bit_buffer |= bits << self.bits_in;
670        self.bits_in += len;
671    }
672
673    fn flush(&mut self, output: &mut OutputBufferOxide) -> Result<()> {
674        let pos = output.inner_pos;
675        {
676            let inner = &mut output.inner[pos..pos + 8];
678            let bytes = u64::to_le_bytes(self.bit_buffer);
679            inner.copy_from_slice(&bytes);
680        }
681        match output.inner_pos.checked_add((self.bits_in >> 3) as usize) {
682            Some(n) if n <= output.inner.len() => output.inner_pos = n,
683            _ => return Err(Error {}),
684        }
685        self.bit_buffer >>= self.bits_in & !7;
686        self.bits_in &= 7;
687        Ok(())
688    }
689}
690
691pub(crate) struct HuffmanOxide {
697    pub count: [[u16; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
699    pub codes: [[u16; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
701    pub code_sizes: [[u8; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
703}
704
705const LITLEN_TABLE: usize = 0;
707const DIST_TABLE: usize = 1;
709const HUFF_CODES_TABLE: usize = 2;
711
712struct Rle {
714    pub z_count: u32,
715    pub repeat_count: u16,
716    pub prev_code_size: u8,
717}
718
719impl Rle {
720    fn prev_code_size(
721        &mut self,
722        packed_code_sizes: &mut [u8],
723        packed_pos: &mut usize,
724        h: &mut HuffmanOxide,
725    ) -> Result<()> {
726        let mut write = |buf| write(buf, packed_code_sizes, packed_pos);
727        let counts = &mut h.count[HUFF_CODES_TABLE];
728        if self.repeat_count != 0 {
729            if self.repeat_count < 3 {
730                counts[self.prev_code_size as usize] =
731                    counts[self.prev_code_size as usize].wrapping_add(self.repeat_count);
732                let code = self.prev_code_size;
733                write(&[code, code, code][..self.repeat_count as usize])?;
734            } else {
735                counts[16] = counts[16].wrapping_add(1);
736                write(&[16, (self.repeat_count - 3) as u8][..])?;
737            }
738            self.repeat_count = 0;
739        }
740
741        Ok(())
742    }
743
744    fn zero_code_size(
745        &mut self,
746        packed_code_sizes: &mut [u8],
747        packed_pos: &mut usize,
748        h: &mut HuffmanOxide,
749    ) -> Result<()> {
750        let mut write = |buf| write(buf, packed_code_sizes, packed_pos);
751        let counts = &mut h.count[HUFF_CODES_TABLE];
752        if self.z_count != 0 {
753            if self.z_count < 3 {
754                counts[0] = counts[0].wrapping_add(self.z_count as u16);
755                write(&[0, 0, 0][..self.z_count as usize])?;
756            } else if self.z_count <= 10 {
757                counts[17] = counts[17].wrapping_add(1);
758                write(&[17, (self.z_count - 3) as u8][..])?;
759            } else {
760                counts[18] = counts[18].wrapping_add(1);
761                write(&[18, (self.z_count - 11) as u8][..])?;
762            }
763            self.z_count = 0;
764        }
765
766        Ok(())
767    }
768}
769
770fn write(src: &[u8], dst: &mut [u8], dst_pos: &mut usize) -> Result<()> {
771    match dst.get_mut(*dst_pos..*dst_pos + src.len()) {
772        Some(s) => s.copy_from_slice(src),
773        None => return Err(Error {}),
774    }
775    *dst_pos += src.len();
776    Ok(())
777}
778
779impl Default for HuffmanOxide {
780    fn default() -> Self {
781        HuffmanOxide {
782            count: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
783            codes: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
784            code_sizes: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
785        }
786    }
787}
788
789impl HuffmanOxide {
790    fn radix_sort_symbols<'a>(
791        symbols0: &'a mut [SymFreq],
792        symbols1: &'a mut [SymFreq],
793    ) -> &'a mut [SymFreq] {
794        let mut hist = [[0; 256]; 2];
795
796        for freq in symbols0.iter() {
797            hist[0][(freq.key & 0xFF) as usize] += 1;
798            hist[1][((freq.key >> 8) & 0xFF) as usize] += 1;
799        }
800
801        let mut n_passes = 2;
802        if symbols0.len() == hist[1][0] {
803            n_passes -= 1;
804        }
805
806        let mut current_symbols = symbols0;
807        let mut new_symbols = symbols1;
808
809        for (pass, hist_item) in hist.iter().enumerate().take(n_passes) {
810            let mut offsets = [0; 256];
811            let mut offset = 0;
812            for i in 0..256 {
813                offsets[i] = offset;
814                offset += hist_item[i];
815            }
816
817            for sym in current_symbols.iter() {
818                let j = ((sym.key >> (pass * 8)) & 0xFF) as usize;
819                new_symbols[offsets[j]] = *sym;
820                offsets[j] += 1;
821            }
822
823            mem::swap(&mut current_symbols, &mut new_symbols);
824        }
825
826        current_symbols
827    }
828
829    fn calculate_minimum_redundancy(symbols: &mut [SymFreq]) {
830        match symbols.len() {
831            0 => (),
832            1 => symbols[0].key = 1,
833            n => {
834                symbols[0].key += symbols[1].key;
835                let mut root = 0;
836                let mut leaf = 2;
837                for next in 1..n - 1 {
838                    if (leaf >= n) || (symbols[root].key < symbols[leaf].key) {
839                        symbols[next].key = symbols[root].key;
840                        symbols[root].key = next as u16;
841                        root += 1;
842                    } else {
843                        symbols[next].key = symbols[leaf].key;
844                        leaf += 1;
845                    }
846
847                    if (leaf >= n) || (root < next && symbols[root].key < symbols[leaf].key) {
848                        symbols[next].key = symbols[next].key.wrapping_add(symbols[root].key);
849                        symbols[root].key = next as u16;
850                        root += 1;
851                    } else {
852                        symbols[next].key = symbols[next].key.wrapping_add(symbols[leaf].key);
853                        leaf += 1;
854                    }
855                }
856
857                symbols[n - 2].key = 0;
858                for next in (0..n - 2).rev() {
859                    symbols[next].key = symbols[symbols[next].key as usize].key + 1;
860                }
861
862                let mut avbl = 1;
863                let mut used = 0;
864                let mut dpth = 0;
865                let mut root = (n - 2) as i32;
866                let mut next = (n - 1) as i32;
867                while avbl > 0 {
868                    while (root >= 0) && (symbols[root as usize].key == dpth) {
869                        used += 1;
870                        root -= 1;
871                    }
872                    while avbl > used {
873                        symbols[next as usize].key = dpth;
874                        next -= 1;
875                        avbl -= 1;
876                    }
877                    avbl = 2 * used;
878                    dpth += 1;
879                    used = 0;
880                }
881            }
882        }
883    }
884
885    fn enforce_max_code_size(num_codes: &mut [i32], code_list_len: usize, max_code_size: usize) {
886        if code_list_len <= 1 {
887            return;
888        }
889
890        num_codes[max_code_size] += num_codes[max_code_size + 1..].iter().sum::<i32>();
891        let total = num_codes[1..=max_code_size]
892            .iter()
893            .rev()
894            .enumerate()
895            .fold(0u32, |total, (i, &x)| total + ((x as u32) << i));
896
897        for _ in (1 << max_code_size)..total {
898            num_codes[max_code_size] -= 1;
899            for i in (1..max_code_size).rev() {
900                if num_codes[i] != 0 {
901                    num_codes[i] -= 1;
902                    num_codes[i + 1] += 2;
903                    break;
904                }
905            }
906        }
907    }
908
909    fn optimize_table(
910        &mut self,
911        table_num: usize,
912        table_len: usize,
913        code_size_limit: usize,
914        static_table: bool,
915    ) {
916        let mut num_codes = [0i32; 32 + 1];
917        let mut next_code = [0u32; MAX_SUPPORTED_HUFF_CODESIZE + 1];
918
919        if static_table {
920            for &code_size in &self.code_sizes[table_num][..table_len] {
921                num_codes[code_size as usize] += 1;
922            }
923        } else {
924            let mut symbols0 = [SymFreq {
925                key: 0,
926                sym_index: 0,
927            }; MAX_HUFF_SYMBOLS];
928            let mut symbols1 = [SymFreq {
929                key: 0,
930                sym_index: 0,
931            }; MAX_HUFF_SYMBOLS];
932
933            let mut num_used_symbols = 0;
934            for i in 0..table_len {
935                if self.count[table_num][i] != 0 {
936                    symbols0[num_used_symbols] = SymFreq {
937                        key: self.count[table_num][i],
938                        sym_index: i as u16,
939                    };
940                    num_used_symbols += 1;
941                }
942            }
943
944            let symbols = Self::radix_sort_symbols(
945                &mut symbols0[..num_used_symbols],
946                &mut symbols1[..num_used_symbols],
947            );
948            Self::calculate_minimum_redundancy(symbols);
949
950            for symbol in symbols.iter() {
951                num_codes[symbol.key as usize] += 1;
952            }
953
954            Self::enforce_max_code_size(&mut num_codes, num_used_symbols, code_size_limit);
955
956            self.code_sizes[table_num].fill(0);
957            self.codes[table_num].fill(0);
958
959            let mut last = num_used_symbols;
960            for (i, &num_item) in num_codes
961                .iter()
962                .enumerate()
963                .take(code_size_limit + 1)
964                .skip(1)
965            {
966                let first = last - num_item as usize;
967                for symbol in &symbols[first..last] {
968                    self.code_sizes[table_num][symbol.sym_index as usize] = i as u8;
969                }
970                last = first;
971            }
972        }
973
974        let mut j = 0;
975        next_code[1] = 0;
976        for i in 2..=code_size_limit {
977            j = (j + num_codes[i - 1]) << 1;
978            next_code[i] = j as u32;
979        }
980
981        for (&code_size, huff_code) in self.code_sizes[table_num]
982            .iter()
983            .take(table_len)
984            .zip(self.codes[table_num].iter_mut().take(table_len))
985        {
986            if code_size == 0 {
987                continue;
988            }
989
990            let code = next_code[code_size as usize];
991
992            next_code[code_size as usize] += 1;
993
994            let rev_code = (code as u16).reverse_bits() >> (16 - code_size);
995
996            *huff_code = rev_code;
997        }
998    }
999
1000    fn start_static_block(&mut self, output: &mut OutputBufferOxide) {
1001        self.code_sizes[LITLEN_TABLE][0..144].fill(8);
1002        self.code_sizes[LITLEN_TABLE][144..256].fill(9);
1003        self.code_sizes[LITLEN_TABLE][256..280].fill(7);
1004        self.code_sizes[LITLEN_TABLE][280..288].fill(8);
1005
1006        self.code_sizes[DIST_TABLE][..32].fill(5);
1007
1008        self.optimize_table(LITLEN_TABLE, 288, 15, true);
1009        self.optimize_table(DIST_TABLE, 32, 15, true);
1010
1011        output.put_bits(0b01, 2)
1012    }
1013
1014    fn start_dynamic_block(&mut self, output: &mut OutputBufferOxide) -> Result<()> {
1015        self.count[0][256] = 1;
1017
1018        self.optimize_table(0, MAX_HUFF_SYMBOLS_0, 15, false);
1019        self.optimize_table(1, MAX_HUFF_SYMBOLS_1, 15, false);
1020
1021        let num_lit_codes = 286
1022            - &self.code_sizes[0][257..286]
1023                .iter()
1024                .rev()
1025                .take_while(|&x| *x == 0)
1026                .count();
1027
1028        let num_dist_codes = 30
1029            - &self.code_sizes[1][1..30]
1030                .iter()
1031                .rev()
1032                .take_while(|&x| *x == 0)
1033                .count();
1034
1035        let mut code_sizes_to_pack = [0u8; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1];
1036        let mut packed_code_sizes = [0u8; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1];
1037
1038        let total_code_sizes_to_pack = num_lit_codes + num_dist_codes;
1039
1040        code_sizes_to_pack[..num_lit_codes].copy_from_slice(&self.code_sizes[0][..num_lit_codes]);
1041
1042        code_sizes_to_pack[num_lit_codes..total_code_sizes_to_pack]
1043            .copy_from_slice(&self.code_sizes[1][..num_dist_codes]);
1044
1045        let mut rle = Rle {
1046            z_count: 0,
1047            repeat_count: 0,
1048            prev_code_size: 0xFF,
1049        };
1050
1051        self.count[HUFF_CODES_TABLE][..MAX_HUFF_SYMBOLS_2].fill(0);
1052
1053        let mut packed_pos = 0;
1054        for &code_size in &code_sizes_to_pack[..total_code_sizes_to_pack] {
1055            if code_size == 0 {
1056                rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1057                rle.z_count += 1;
1058                if rle.z_count == 138 {
1059                    rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1060                }
1061            } else {
1062                rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1063                if code_size != rle.prev_code_size {
1064                    rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1065                    self.count[HUFF_CODES_TABLE][code_size as usize] =
1066                        self.count[HUFF_CODES_TABLE][code_size as usize].wrapping_add(1);
1067                    write(&[code_size], &mut packed_code_sizes, &mut packed_pos)?;
1068                } else {
1069                    rle.repeat_count += 1;
1070                    if rle.repeat_count == 6 {
1071                        rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1072                    }
1073                }
1074            }
1075            rle.prev_code_size = code_size;
1076        }
1077
1078        if rle.repeat_count != 0 {
1079            rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1080        } else {
1081            rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1082        }
1083
1084        self.optimize_table(2, MAX_HUFF_SYMBOLS_2, 7, false);
1085
1086        output.put_bits_no_flush(2, 2);
1087
1088        output.put_bits_no_flush((num_lit_codes - 257) as u32, 5);
1089        output.put_bits_no_flush((num_dist_codes - 1) as u32, 5);
1090
1091        let mut num_bit_lengths = 18
1092            - HUFFMAN_LENGTH_ORDER
1093                .iter()
1094                .rev()
1095                .take_while(|&swizzle| self.code_sizes[HUFF_CODES_TABLE][*swizzle as usize] == 0)
1096                .count();
1097
1098        num_bit_lengths = cmp::max(4, num_bit_lengths + 1);
1099        output.put_bits(num_bit_lengths as u32 - 4, 4);
1100        for &swizzle in &HUFFMAN_LENGTH_ORDER[..num_bit_lengths] {
1101            output.put_bits(
1102                u32::from(self.code_sizes[HUFF_CODES_TABLE][swizzle as usize]),
1103                3,
1104            );
1105        }
1106
1107        let mut packed_code_size_index = 0;
1108        while packed_code_size_index < packed_pos {
1109            let code = packed_code_sizes[packed_code_size_index] as usize;
1110            packed_code_size_index += 1;
1111            assert!(code < MAX_HUFF_SYMBOLS_2);
1112            output.put_bits(
1113                u32::from(self.codes[HUFF_CODES_TABLE][code]),
1114                u32::from(self.code_sizes[HUFF_CODES_TABLE][code]),
1115            );
1116            if code >= 16 {
1117                output.put_bits(
1118                    u32::from(packed_code_sizes[packed_code_size_index]),
1119                    [2, 3, 7][code - 16],
1120                );
1121                packed_code_size_index += 1;
1122            }
1123        }
1124
1125        Ok(())
1126    }
1127}
1128
1129pub(crate) struct DictOxide {
1130    pub max_probes: [u32; 2],
1133    pub b: HashBuffers,
1136
1137    pub code_buf_dict_pos: usize,
1138    pub lookahead_size: usize,
1139    pub lookahead_pos: usize,
1140    pub size: usize,
1141    loop_len: u8,
1142}
1143
1144const fn probes_from_flags(flags: u32) -> [u32; 2] {
1145    [
1146        1 + ((flags & 0xFFF) + 2) / 3,
1147        1 + (((flags & 0xFFF) >> 2) + 2) / 3,
1148    ]
1149}
1150
1151impl DictOxide {
1152    fn new(flags: u32) -> Self {
1153        DictOxide {
1154            max_probes: probes_from_flags(flags),
1155            b: HashBuffers::default(),
1156            code_buf_dict_pos: 0,
1157            lookahead_size: 0,
1158            lookahead_pos: 0,
1159            size: 0,
1160            loop_len: 32,
1161        }
1162    }
1163
1164    fn update_flags(&mut self, flags: u32) {
1165        self.max_probes = probes_from_flags(flags);
1166    }
1167
1168    fn reset(&mut self) {
1169        self.b.reset();
1170        self.code_buf_dict_pos = 0;
1171        self.lookahead_size = 0;
1172        self.lookahead_pos = 0;
1173        self.size = 0;
1174    }
1175
1176    #[inline]
1179    fn read_unaligned_u32(&self, pos: usize) -> u32 {
1180        let pos = pos & LZ_DICT_SIZE_MASK;
1182        let end = pos + 4;
1183        assert!(end < LZ_DICT_FULL_SIZE);
1187
1188        let bytes: [u8; 4] = self.b.dict[pos..end].try_into().unwrap();
1189        u32::from_le_bytes(bytes)
1190    }
1191
1192    #[inline]
1195    fn read_unaligned_u64(&self, pos: usize) -> u64 {
1196        let pos = pos & LZ_DICT_SIZE_MASK;
1200        let bytes: [u8; 8] = self.b.dict[pos..pos + 8].try_into().unwrap();
1201        u64::from_le_bytes(bytes)
1202    }
1203
1204    fn find_match(
1209        &self,
1210        lookahead_pos: usize,
1211        max_dist: usize,
1212        max_match_len: u32,
1213        mut match_dist: u32,
1214        mut match_len: u32,
1215    ) -> (u32, u32) {
1216        let max_match_len = cmp::min(MAX_MATCH_LEN as u32, max_match_len);
1222        match_len = cmp::max(match_len, 1);
1223
1224        if max_match_len <= match_len {
1226            return (match_dist, match_len);
1227        }
1228
1229        let pos = lookahead_pos & LZ_DICT_SIZE_MASK;
1230        let mut probe_pos = pos;
1231        let mut num_probes_left = if match_len < 32 {
1233            self.max_probes[0]
1234        } else {
1235            self.max_probes[1]
1236        };
1237
1238        let mut c01: u16 = read_u16_le(&self.b.dict, pos + match_len as usize - 1);
1240        let s01: u16 = read_u16_le(&self.b.dict, pos);
1242
1243        'outer: loop {
1244            let mut dist;
1245            'found: loop {
1246                num_probes_left -= 1;
1247                if num_probes_left == 0 {
1248                    return (match_dist, match_len);
1251                }
1252
1253                for _ in 0..3 {
1254                    let next_probe_pos = self.b.next[probe_pos] as usize;
1255
1256                    dist = (lookahead_pos - next_probe_pos) & 0xFFFF;
1257                    #[allow(clippy::int_plus_one)]
1267                    if next_probe_pos == 0
1268                        || dist > max_dist
1269                        || match_len as usize - 1 >= MAX_MATCH_LEN
1270                    {
1271                        return (match_dist, match_len);
1275                    }
1276
1277                    probe_pos = next_probe_pos & LZ_DICT_SIZE_MASK;
1280
1281                    if read_u16_le(&self.b.dict, probe_pos + match_len as usize - 1) == c01 {
1282                        break 'found;
1283                    }
1284                }
1285            }
1286
1287            if dist == 0 {
1288                return (match_dist, match_len);
1291            }
1292
1293            if read_u16_le(&self.b.dict, probe_pos) != s01 {
1295                continue;
1296            }
1297
1298            let mut p = pos + 2;
1299            let mut q = probe_pos + 2;
1300            for _ in 0..self.loop_len as i32 {
1305                let p_data: u64 = self.read_unaligned_u64(p);
1306                let q_data: u64 = self.read_unaligned_u64(q);
1307                let xor_data = p_data ^ q_data;
1309                if xor_data == 0 {
1310                    p += 8;
1311                    q += 8;
1312                } else {
1313                    let trailing = xor_data.trailing_zeros();
1315
1316                    let probe_len = p - pos + (trailing as usize >> 3);
1317                    if probe_len > match_len as usize {
1318                        match_dist = dist as u32;
1319                        match_len = cmp::min(max_match_len, probe_len as u32);
1320                        if match_len >= max_match_len {
1321                            return (match_dist, match_len);
1324                        }
1325                        c01 =
1331                            read_u16_le(&self.b.dict, (pos + match_len as usize).saturating_sub(1));
1332                    }
1333                    continue 'outer;
1334                }
1335            }
1336
1337            return (dist as u32, cmp::min(max_match_len, MAX_MATCH_LEN as u32));
1338        }
1339    }
1340}
1341
1342pub(crate) struct ParamsOxide {
1343    pub flags: u32,
1344    pub greedy_parsing: bool,
1345    pub block_index: u32,
1346
1347    pub saved_match_dist: u32,
1348    pub saved_match_len: u32,
1349    pub saved_lit: u8,
1350
1351    pub flush: TDEFLFlush,
1352    pub flush_ofs: u32,
1353    pub flush_remaining: u32,
1354    pub finished: bool,
1355
1356    pub adler32: u32,
1357
1358    pub src_pos: usize,
1359
1360    pub out_buf_ofs: usize,
1361    pub prev_return_status: TDEFLStatus,
1362
1363    pub saved_bit_buffer: u32,
1364    pub saved_bits_in: u32,
1365
1366    pub local_buf: Box<LocalBuf>,
1367}
1368
1369impl ParamsOxide {
1370    fn new(flags: u32) -> Self {
1371        ParamsOxide {
1372            flags,
1373            greedy_parsing: flags & TDEFL_GREEDY_PARSING_FLAG != 0,
1374            block_index: 0,
1375            saved_match_dist: 0,
1376            saved_match_len: 0,
1377            saved_lit: 0,
1378            flush: TDEFLFlush::None,
1379            flush_ofs: 0,
1380            flush_remaining: 0,
1381            finished: false,
1382            adler32: MZ_ADLER32_INIT,
1383            src_pos: 0,
1384            out_buf_ofs: 0,
1385            prev_return_status: TDEFLStatus::Okay,
1386            saved_bit_buffer: 0,
1387            saved_bits_in: 0,
1388            local_buf: Box::default(),
1389        }
1390    }
1391
1392    fn update_flags(&mut self, flags: u32) {
1393        self.flags = flags;
1394        self.greedy_parsing = self.flags & TDEFL_GREEDY_PARSING_FLAG != 0;
1395    }
1396
1397    fn reset(&mut self) {
1399        self.block_index = 0;
1400        self.saved_match_len = 0;
1401        self.saved_match_dist = 0;
1402        self.saved_lit = 0;
1403        self.flush = TDEFLFlush::None;
1404        self.flush_ofs = 0;
1405        self.flush_remaining = 0;
1406        self.finished = false;
1407        self.adler32 = MZ_ADLER32_INIT;
1408        self.src_pos = 0;
1409        self.out_buf_ofs = 0;
1410        self.prev_return_status = TDEFLStatus::Okay;
1411        self.saved_bit_buffer = 0;
1412        self.saved_bits_in = 0;
1413        self.local_buf.b = [0; OUT_BUF_SIZE];
1414    }
1415}
1416
1417pub(crate) struct LZOxide {
1418    pub codes: [u8; LZ_CODE_BUF_SIZE],
1419    pub code_position: usize,
1420    pub flag_position: usize,
1421
1422    pub total_bytes: u32,
1424    pub num_flags_left: u32,
1425}
1426
1427impl LZOxide {
1428    const fn new() -> Self {
1429        LZOxide {
1430            codes: [0; LZ_CODE_BUF_SIZE],
1431            code_position: 1,
1432            flag_position: 0,
1433            total_bytes: 0,
1434            num_flags_left: 8,
1435        }
1436    }
1437
1438    fn write_code(&mut self, val: u8) {
1439        self.codes[usize::from(self.code_position as u16)] = val;
1442        self.code_position += 1;
1443    }
1444
1445    fn init_flag(&mut self) {
1446        if self.num_flags_left == 8 {
1447            *self.get_flag() = 0;
1448            self.code_position -= 1;
1449        } else {
1450            *self.get_flag() >>= self.num_flags_left;
1451        }
1452    }
1453
1454    fn get_flag(&mut self) -> &mut u8 {
1455        &mut self.codes[usize::from(self.flag_position as u16)]
1458    }
1459
1460    fn plant_flag(&mut self) {
1461        self.flag_position = self.code_position;
1462        self.code_position += 1;
1463    }
1464
1465    fn consume_flag(&mut self) {
1466        self.num_flags_left -= 1;
1467        if self.num_flags_left == 0 {
1468            self.num_flags_left = 8;
1469            self.plant_flag();
1470        }
1471    }
1472}
1473
1474fn compress_lz_codes(
1475    huff: &HuffmanOxide,
1476    output: &mut OutputBufferOxide,
1477    lz_code_buf: &[u8; LZ_CODE_BUF_SIZE],
1478    lz_code_buf_used_len: usize,
1479) -> Result<bool> {
1480    let mut flags = 1;
1481    let mut bb = BitBuffer {
1482        bit_buffer: u64::from(output.bit_buffer),
1483        bits_in: output.bits_in,
1484    };
1485
1486    let lz_code_buf_used_len = cmp::min(lz_code_buf.len(), lz_code_buf_used_len);
1489
1490    let mut i: usize = 0;
1491    while i < lz_code_buf_used_len {
1492        if flags == 1 {
1493            flags = u32::from(lz_code_buf[i]) | 0x100;
1494            i += 1;
1495        }
1496
1497        if flags & 1 == 1 {
1499            flags >>= 1;
1500
1501            let sym;
1502            let num_extra_bits;
1503
1504            let match_len = lz_code_buf[i & LZ_CODE_BUF_MASK] as usize;
1505
1506            let match_dist = lz_code_buf[(i + 1) & LZ_CODE_BUF_MASK] as u16
1507                | ((lz_code_buf[(i + 2) & LZ_CODE_BUF_MASK] as u16) << 8);
1508
1509            i += 3;
1510
1511            debug_assert!(huff.code_sizes[0][LEN_SYM[match_len] as usize + LEN_SYM_OFFSET] != 0);
1512            let len_sym = (LEN_SYM[match_len] & 31) as usize + LEN_SYM_OFFSET;
1513
1514            bb.put_fast(
1515                u64::from(huff.codes[0][len_sym]),
1516                u32::from(huff.code_sizes[0][len_sym]),
1517            );
1518            bb.put_fast(
1519                match_len as u64 & u64::from(BITMASKS[(LEN_EXTRA[match_len] & 7) as usize]),
1520                u32::from(LEN_EXTRA[match_len]),
1521            );
1522
1523            if match_dist < 512 {
1524                sym = SMALL_DIST_SYM[match_dist as usize] as usize;
1525                num_extra_bits = SMALL_DIST_EXTRA[match_dist as usize] as usize;
1526            } else {
1527                sym = LARGE_DIST_SYM[(match_dist >> 8) as usize] as usize;
1528                num_extra_bits = LARGE_DIST_EXTRA[(match_dist >> 8) as usize] as usize;
1529            }
1530
1531            debug_assert!(huff.code_sizes[1][sym] != 0);
1532            bb.put_fast(
1533                u64::from(huff.codes[1][sym]),
1534                u32::from(huff.code_sizes[1][sym]),
1535            );
1536            bb.put_fast(
1537                u64::from(match_dist) & u64::from(BITMASKS[num_extra_bits & 15]),
1538                num_extra_bits as u32,
1539            );
1540        } else {
1541            for _ in 0..3 {
1543                flags >>= 1;
1544                let lit = lz_code_buf[i & LZ_CODE_BUF_MASK];
1545                i += 1;
1546
1547                debug_assert!(huff.code_sizes[0][lit as usize] != 0);
1548                bb.put_fast(
1549                    u64::from(huff.codes[0][lit as usize]),
1550                    u32::from(huff.code_sizes[0][lit as usize]),
1551                );
1552
1553                if flags & 1 == 1 || i >= lz_code_buf_used_len {
1554                    break;
1555                }
1556            }
1557        }
1558
1559        bb.flush(output)?;
1560    }
1561
1562    output.bits_in = 0;
1563    output.bit_buffer = 0;
1564    while bb.bits_in != 0 {
1565        let n = cmp::min(bb.bits_in, 16);
1566        output.put_bits(bb.bit_buffer as u32 & BITMASKS[n as usize], n);
1567        bb.bit_buffer >>= n;
1568        bb.bits_in -= n;
1569    }
1570
1571    output.put_bits(
1573        u32::from(huff.codes[0][256]),
1574        u32::from(huff.code_sizes[0][256]),
1575    );
1576
1577    Ok(true)
1578}
1579
1580fn compress_block(
1581    huff: &mut HuffmanOxide,
1582    output: &mut OutputBufferOxide,
1583    lz: &LZOxide,
1584    static_block: bool,
1585) -> Result<bool> {
1586    if static_block {
1587        huff.start_static_block(output);
1588    } else {
1589        huff.start_dynamic_block(output)?;
1590    }
1591
1592    compress_lz_codes(huff, output, &lz.codes, lz.code_position)
1593}
1594
1595pub(crate) fn flush_block(
1596    d: &mut CompressorOxide,
1597    callback: &mut CallbackOxide,
1598    flush: TDEFLFlush,
1599) -> Result<i32> {
1600    let mut saved_buffer;
1601    {
1602        let mut output = callback
1603            .out
1604            .new_output_buffer(&mut d.params.local_buf.b, d.params.out_buf_ofs);
1605        output.bit_buffer = d.params.saved_bit_buffer;
1606        output.bits_in = d.params.saved_bits_in;
1607
1608        let use_raw_block = (d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0)
1610            && (d.dict.lookahead_pos - d.dict.code_buf_dict_pos) <= d.dict.size;
1611        debug_assert_eq!(
1612            use_raw_block,
1613            d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0
1614        );
1615
1616        assert!(d.params.flush_remaining == 0);
1617        d.params.flush_ofs = 0;
1618        d.params.flush_remaining = 0;
1619
1620        d.lz.init_flag();
1621
1622        if d.params.flags & TDEFL_WRITE_ZLIB_HEADER != 0 && d.params.block_index == 0 {
1624            let header = zlib::header_from_flags(d.params.flags);
1625            output.put_bits_no_flush(header[0].into(), 8);
1626            output.put_bits(header[1].into(), 8);
1627        }
1628
1629        output.put_bits((flush == TDEFLFlush::Finish) as u32, 1);
1631
1632        saved_buffer = output.save();
1633
1634        let comp_success = if !use_raw_block {
1635            let use_static =
1636                (d.params.flags & TDEFL_FORCE_ALL_STATIC_BLOCKS != 0) || (d.lz.total_bytes < 48);
1637            compress_block(&mut d.huff, &mut output, &d.lz, use_static)?
1638        } else {
1639            false
1640        };
1641
1642        let expanded = (d.lz.total_bytes > 32)
1652            && (output.inner_pos - saved_buffer.pos + 1 >= (d.lz.total_bytes as usize))
1653            && (d.dict.lookahead_pos - d.dict.code_buf_dict_pos <= d.dict.size);
1654
1655        if use_raw_block || expanded {
1656            output.load(saved_buffer);
1657
1658            output.put_bits(0, 2);
1660
1661            output.pad_to_bytes();
1663
1664            output.put_bits(d.lz.total_bytes & 0xFFFF, 16);
1666            output.put_bits(!d.lz.total_bytes & 0xFFFF, 16);
1667
1668            let start = d.dict.code_buf_dict_pos & LZ_DICT_SIZE_MASK;
1670            let end = (d.dict.code_buf_dict_pos + d.lz.total_bytes as usize) & LZ_DICT_SIZE_MASK;
1671            let dict = &mut d.dict.b.dict;
1672            if start < end {
1673                output.write_bytes(&dict[start..end]);
1675            } else if d.lz.total_bytes > 0 {
1676                output.write_bytes(&dict[start..LZ_DICT_SIZE]);
1678                output.write_bytes(&dict[..end]);
1679            }
1680        } else if !comp_success {
1681            output.load(saved_buffer);
1682            compress_block(&mut d.huff, &mut output, &d.lz, true)?;
1683        }
1684
1685        if flush != TDEFLFlush::None {
1686            if flush == TDEFLFlush::Finish {
1687                output.pad_to_bytes();
1688                if d.params.flags & TDEFL_WRITE_ZLIB_HEADER != 0 {
1689                    let mut adler = d.params.adler32;
1690                    for _ in 0..4 {
1691                        output.put_bits((adler >> 24) & 0xFF, 8);
1692                        adler <<= 8;
1693                    }
1694                }
1695            } else {
1696                output.put_bits(0, 3);
1699                output.pad_to_bytes();
1700                output.put_bits(0, 16);
1701                output.put_bits(0xFFFF, 16);
1702            }
1703        }
1704
1705        d.huff.count[0][..MAX_HUFF_SYMBOLS_0].fill(0);
1706        d.huff.count[1][..MAX_HUFF_SYMBOLS_1].fill(0);
1707
1708        d.lz.code_position = 1;
1710        d.lz.flag_position = 0;
1711        d.lz.num_flags_left = 8;
1712        d.dict.code_buf_dict_pos += d.lz.total_bytes as usize;
1713        d.lz.total_bytes = 0;
1714        d.params.block_index += 1;
1715
1716        saved_buffer = output.save();
1717
1718        d.params.saved_bit_buffer = saved_buffer.bit_buffer;
1719        d.params.saved_bits_in = saved_buffer.bits_in;
1720    }
1721
1722    Ok(callback.flush_output(saved_buffer, &mut d.params))
1723}
1724
1725pub(crate) fn record_literal(h: &mut HuffmanOxide, lz: &mut LZOxide, lit: u8) {
1726    lz.total_bytes += 1;
1727    lz.write_code(lit);
1728
1729    *lz.get_flag() >>= 1;
1730    lz.consume_flag();
1731
1732    h.count[0][lit as usize] += 1;
1733}
1734
1735fn record_match(h: &mut HuffmanOxide, lz: &mut LZOxide, match_len: u32, mut match_dist: u32) {
1736    debug_assert!(match_len >= MIN_MATCH_LEN.into());
1737    debug_assert!(match_dist >= 1);
1738    debug_assert!(match_dist as usize <= LZ_DICT_SIZE);
1739
1740    lz.total_bytes += match_len;
1741    match_dist -= 1;
1742    let match_len = (match_len - u32::from(MIN_MATCH_LEN)) as u8;
1743    lz.write_code(match_len);
1744    lz.write_code(match_dist as u8);
1745    lz.write_code((match_dist >> 8) as u8);
1746
1747    *lz.get_flag() >>= 1;
1748    *lz.get_flag() |= 0x80;
1749    lz.consume_flag();
1750
1751    let symbol = if match_dist < 512 {
1752        SMALL_DIST_SYM[match_dist as usize]
1753    } else {
1754        LARGE_DIST_SYM[((match_dist >> 8) & 127) as usize]
1755    } as usize;
1756    h.count[1][symbol] += 1;
1757    h.count[0][(LEN_SYM[match_len as usize] as usize & 31) + LEN_SYM_OFFSET] += 1;
1760}
1761
1762fn compress_normal(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool {
1763    let in_buf = match callback.in_buf {
1764        None => return true,
1765        Some(in_buf) => in_buf,
1766    };
1767
1768    let mut src_pos = d.params.src_pos;
1769    let mut lookahead_size = d.dict.lookahead_size;
1770    let mut lookahead_pos = d.dict.lookahead_pos;
1771    let mut saved_lit = d.params.saved_lit;
1772    let mut saved_match_dist = d.params.saved_match_dist;
1773    let mut saved_match_len = d.params.saved_match_len;
1774
1775    while src_pos < in_buf.len() || (d.params.flush != TDEFLFlush::None && lookahead_size != 0) {
1776        let src_buf_left = in_buf.len() - src_pos;
1777        let num_bytes_to_process = cmp::min(src_buf_left, MAX_MATCH_LEN - lookahead_size);
1778
1779        if lookahead_size + d.dict.size >= usize::from(MIN_MATCH_LEN) - 1
1780            && num_bytes_to_process > 0
1781        {
1782            let dictb = &mut d.dict.b;
1783
1784            let mut dst_pos = (lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK;
1785            let mut ins_pos = lookahead_pos + lookahead_size - 2;
1786            let mut hash = update_hash(
1788                u16::from(dictb.dict[ins_pos & LZ_DICT_SIZE_MASK]),
1789                dictb.dict[(ins_pos + 1) & LZ_DICT_SIZE_MASK],
1790            );
1791
1792            lookahead_size += num_bytes_to_process;
1793
1794            for &c in &in_buf[src_pos..src_pos + num_bytes_to_process] {
1795                dictb.dict[dst_pos] = c;
1797                if dst_pos < MAX_MATCH_LEN - 1 {
1798                    dictb.dict[LZ_DICT_SIZE + dst_pos] = c;
1799                }
1800
1801                hash = update_hash(hash, c);
1803                dictb.next[ins_pos & LZ_DICT_SIZE_MASK] = dictb.hash[hash as usize];
1804                dictb.hash[hash as usize] = ins_pos as u16;
1806                dst_pos = (dst_pos + 1) & LZ_DICT_SIZE_MASK;
1807                ins_pos += 1;
1808            }
1809
1810            src_pos += num_bytes_to_process;
1811        } else {
1812            let dictb = &mut d.dict.b;
1813            for &c in &in_buf[src_pos..src_pos + num_bytes_to_process] {
1814                let dst_pos = (lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK;
1815                dictb.dict[dst_pos] = c;
1816                if dst_pos < MAX_MATCH_LEN - 1 {
1817                    dictb.dict[LZ_DICT_SIZE + dst_pos] = c;
1818                }
1819
1820                lookahead_size += 1;
1821                if lookahead_size + d.dict.size >= MIN_MATCH_LEN.into() {
1822                    let ins_pos = lookahead_pos + lookahead_size - 3;
1823                    let hash = ((u32::from(dictb.dict[ins_pos & LZ_DICT_SIZE_MASK])
1824                        << (LZ_HASH_SHIFT * 2))
1825                        ^ ((u32::from(dictb.dict[(ins_pos + 1) & LZ_DICT_SIZE_MASK])
1826                            << LZ_HASH_SHIFT)
1827                            ^ u32::from(c)))
1828                        & (LZ_HASH_SIZE as u32 - 1);
1829
1830                    dictb.next[ins_pos & LZ_DICT_SIZE_MASK] = dictb.hash[hash as usize];
1831                    dictb.hash[hash as usize] = ins_pos as u16;
1832                }
1833            }
1834
1835            src_pos += num_bytes_to_process;
1836        }
1837
1838        d.dict.size = cmp::min(LZ_DICT_SIZE - lookahead_size, d.dict.size);
1839        if d.params.flush == TDEFLFlush::None && lookahead_size < MAX_MATCH_LEN {
1840            break;
1841        }
1842
1843        let mut len_to_move = 1;
1844        let mut cur_match_dist = 0;
1845        let mut cur_match_len = if saved_match_len != 0 {
1846            saved_match_len
1847        } else {
1848            u32::from(MIN_MATCH_LEN) - 1
1849        };
1850        let cur_pos = lookahead_pos & LZ_DICT_SIZE_MASK;
1851        if d.params.flags & TDEFL_RLE_MATCHES != 0 {
1852            if d.dict.size != 0 {
1854                let c = d.dict.b.dict[(cur_pos.wrapping_sub(1)) & LZ_DICT_SIZE_MASK];
1855                cur_match_len = d.dict.b.dict[cur_pos..(cur_pos + lookahead_size)]
1856                    .iter()
1857                    .take_while(|&x| *x == c)
1858                    .count() as u32;
1859                if cur_match_len < MIN_MATCH_LEN.into() {
1860                    cur_match_len = 0
1861                } else {
1862                    cur_match_dist = 1
1863                }
1864            }
1865        } else {
1866            let dist_len = d.dict.find_match(
1868                lookahead_pos,
1869                d.dict.size,
1870                lookahead_size as u32,
1871                cur_match_dist,
1872                cur_match_len,
1873            );
1874            cur_match_dist = dist_len.0;
1875            cur_match_len = dist_len.1;
1876        }
1877
1878        let far_and_small = cur_match_len == MIN_MATCH_LEN.into() && cur_match_dist >= 8 * 1024;
1879        let filter_small = d.params.flags & TDEFL_FILTER_MATCHES != 0 && cur_match_len <= 5;
1880        if far_and_small || filter_small || cur_pos == cur_match_dist as usize {
1881            cur_match_dist = 0;
1882            cur_match_len = 0;
1883        }
1884
1885        if saved_match_len != 0 {
1886            if cur_match_len > saved_match_len {
1887                record_literal(&mut d.huff, &mut d.lz, saved_lit);
1888                if cur_match_len >= 128 {
1889                    record_match(&mut d.huff, &mut d.lz, cur_match_len, cur_match_dist);
1890                    saved_match_len = 0;
1891                    len_to_move = cur_match_len as usize;
1892                } else {
1893                    saved_lit = d.dict.b.dict[cur_pos];
1894                    saved_match_dist = cur_match_dist;
1895                    saved_match_len = cur_match_len;
1896                }
1897            } else {
1898                record_match(&mut d.huff, &mut d.lz, saved_match_len, saved_match_dist);
1899                len_to_move = (saved_match_len - 1) as usize;
1900                saved_match_len = 0;
1901            }
1902        } else if cur_match_dist == 0 {
1903            record_literal(
1904                &mut d.huff,
1905                &mut d.lz,
1906                d.dict.b.dict[cmp::min(cur_pos, d.dict.b.dict.len() - 1)],
1907            );
1908        } else if d.params.greedy_parsing
1909            || (d.params.flags & TDEFL_RLE_MATCHES != 0)
1910            || cur_match_len >= 128
1911        {
1912            record_match(&mut d.huff, &mut d.lz, cur_match_len, cur_match_dist);
1915            len_to_move = cur_match_len as usize;
1916        } else {
1917            saved_lit = d.dict.b.dict[cmp::min(cur_pos, d.dict.b.dict.len() - 1)];
1918            saved_match_dist = cur_match_dist;
1919            saved_match_len = cur_match_len;
1920        }
1921
1922        lookahead_pos += len_to_move;
1923        assert!(lookahead_size >= len_to_move);
1924        lookahead_size -= len_to_move;
1925        d.dict.size = cmp::min(d.dict.size + len_to_move, LZ_DICT_SIZE);
1926
1927        let lz_buf_tight = d.lz.code_position > LZ_CODE_BUF_SIZE - 8;
1928        let fat = ((d.lz.code_position * 115) >> 7) >= d.lz.total_bytes as usize;
1929        let buf_fat = (d.lz.total_bytes > 31 * 1024) && fat;
1930
1931        if lz_buf_tight || buf_fat {
1932            d.params.src_pos = src_pos;
1933            d.dict.lookahead_size = lookahead_size;
1935            d.dict.lookahead_pos = lookahead_pos;
1936
1937            let n = flush_block(d, callback, TDEFLFlush::None)
1938                .unwrap_or(TDEFLStatus::PutBufFailed as i32);
1939            if n != 0 {
1940                d.params.saved_lit = saved_lit;
1941                d.params.saved_match_dist = saved_match_dist;
1942                d.params.saved_match_len = saved_match_len;
1943                return n > 0;
1944            }
1945        }
1946    }
1947
1948    d.params.src_pos = src_pos;
1949    d.dict.lookahead_size = lookahead_size;
1950    d.dict.lookahead_pos = lookahead_pos;
1951    d.params.saved_lit = saved_lit;
1952    d.params.saved_match_dist = saved_match_dist;
1953    d.params.saved_match_len = saved_match_len;
1954    true
1955}
1956
1957const COMP_FAST_LOOKAHEAD_SIZE: usize = 4096;
1958
1959fn compress_fast(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool {
1960    let mut src_pos = d.params.src_pos;
1961    let mut lookahead_size = d.dict.lookahead_size;
1962    let mut lookahead_pos = d.dict.lookahead_pos;
1963
1964    let mut cur_pos = lookahead_pos & LZ_DICT_SIZE_MASK;
1965    let in_buf = match callback.in_buf {
1966        None => return true,
1967        Some(in_buf) => in_buf,
1968    };
1969
1970    debug_assert!(d.lz.code_position < LZ_CODE_BUF_SIZE - 2);
1971
1972    while src_pos < in_buf.len() || (d.params.flush != TDEFLFlush::None && lookahead_size > 0) {
1973        let mut dst_pos = (lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK;
1974        let mut num_bytes_to_process = cmp::min(
1975            in_buf.len() - src_pos,
1976            COMP_FAST_LOOKAHEAD_SIZE - lookahead_size,
1977        );
1978        lookahead_size += num_bytes_to_process;
1979
1980        while num_bytes_to_process != 0 {
1981            let n = cmp::min(LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
1982            d.dict.b.dict[dst_pos..dst_pos + n].copy_from_slice(&in_buf[src_pos..src_pos + n]);
1983
1984            if dst_pos < MAX_MATCH_LEN - 1 {
1985                let m = cmp::min(n, MAX_MATCH_LEN - 1 - dst_pos);
1986                d.dict.b.dict[dst_pos + LZ_DICT_SIZE..dst_pos + LZ_DICT_SIZE + m]
1987                    .copy_from_slice(&in_buf[src_pos..src_pos + m]);
1988            }
1989
1990            src_pos += n;
1991            dst_pos = (dst_pos + n) & LZ_DICT_SIZE_MASK;
1992            num_bytes_to_process -= n;
1993        }
1994
1995        d.dict.size = cmp::min(LZ_DICT_SIZE - lookahead_size, d.dict.size);
1996        if d.params.flush == TDEFLFlush::None && lookahead_size < COMP_FAST_LOOKAHEAD_SIZE {
1997            break;
1998        }
1999
2000        while lookahead_size >= 4 {
2001            let mut cur_match_len = 1;
2002
2003            let first_trigram = d.dict.read_unaligned_u32(cur_pos) & 0xFF_FFFF;
2004
2005            let hash = (first_trigram ^ (first_trigram >> (24 - (LZ_HASH_BITS - 8))))
2006                & LEVEL1_HASH_SIZE_MASK;
2007
2008            let mut probe_pos = usize::from(d.dict.b.hash[hash as usize]);
2009            d.dict.b.hash[hash as usize] = lookahead_pos as u16;
2010
2011            let mut cur_match_dist = (lookahead_pos - probe_pos) as u16;
2012            if cur_match_dist as usize <= d.dict.size {
2013                probe_pos &= LZ_DICT_SIZE_MASK;
2014
2015                let trigram = d.dict.read_unaligned_u32(probe_pos) & 0xFF_FFFF;
2016
2017                if first_trigram == trigram {
2018                    let mut p = cur_pos + 3;
2020                    let mut q = probe_pos + 3;
2021                    cur_match_len = (|| {
2022                        for _ in 0..32 {
2023                            let p_data: u64 = d.dict.read_unaligned_u64(p);
2024                            let q_data: u64 = d.dict.read_unaligned_u64(q);
2025                            let xor_data = p_data ^ q_data;
2026                            if xor_data == 0 {
2027                                p += 8;
2028                                q += 8;
2029                            } else {
2030                                let trailing = xor_data.trailing_zeros();
2031                                return p as u32 - cur_pos as u32 + (trailing >> 3);
2032                            }
2033                        }
2034
2035                        if cur_match_dist == 0 {
2036                            0
2037                        } else {
2038                            MAX_MATCH_LEN as u32
2039                        }
2040                    })();
2041
2042                    if cur_match_len < MIN_MATCH_LEN.into()
2043                        || (cur_match_len == MIN_MATCH_LEN.into() && cur_match_dist >= 8 * 1024)
2044                    {
2045                        let lit = first_trigram as u8;
2046                        cur_match_len = 1;
2047                        d.lz.write_code(lit);
2048                        *d.lz.get_flag() >>= 1;
2049                        d.huff.count[0][lit as usize] += 1;
2050                    } else {
2051                        cur_match_len = cmp::min(cur_match_len, lookahead_size as u32);
2054                        debug_assert!(cur_match_len >= MIN_MATCH_LEN.into());
2055                        debug_assert!(cur_match_len <= MAX_MATCH_LEN as u32);
2056                        debug_assert!(cur_match_dist >= 1);
2057                        debug_assert!(cur_match_dist as usize <= LZ_DICT_SIZE);
2058                        cur_match_dist -= 1;
2059
2060                        d.lz.write_code((cur_match_len - u32::from(MIN_MATCH_LEN)) as u8);
2061                        d.lz.write_code(cur_match_dist as u8);
2062                        d.lz.write_code((cur_match_dist >> 8) as u8);
2063
2064                        *d.lz.get_flag() >>= 1;
2065                        *d.lz.get_flag() |= 0x80;
2066                        if cur_match_dist < 512 {
2067                            d.huff.count[1][SMALL_DIST_SYM[cur_match_dist as usize] as usize] += 1;
2068                        } else {
2069                            d.huff.count[1]
2070                                [LARGE_DIST_SYM[(cur_match_dist >> 8) as usize] as usize] += 1;
2071                        }
2072
2073                        d.huff.count[0][(LEN_SYM
2074                            [(cur_match_len - u32::from(MIN_MATCH_LEN)) as usize & 255]
2075                            as usize
2076                            & 31)
2077                            + LEN_SYM_OFFSET] += 1;
2078                    }
2079                } else {
2080                    d.lz.write_code(first_trigram as u8);
2081                    *d.lz.get_flag() >>= 1;
2082                    d.huff.count[0][first_trigram as u8 as usize] += 1;
2083                }
2084
2085                d.lz.consume_flag();
2086                d.lz.total_bytes += cur_match_len;
2087                lookahead_pos += cur_match_len as usize;
2088                d.dict.size = cmp::min(d.dict.size + cur_match_len as usize, LZ_DICT_SIZE);
2089                cur_pos = (cur_pos + cur_match_len as usize) & LZ_DICT_SIZE_MASK;
2090                lookahead_size -= cur_match_len as usize;
2091
2092                if d.lz.code_position > LZ_CODE_BUF_SIZE - 8 {
2093                    d.dict.lookahead_size = lookahead_size;
2095                    d.dict.lookahead_pos = lookahead_pos;
2096
2097                    let n = match flush_block(d, callback, TDEFLFlush::None) {
2098                        Err(_) => {
2099                            d.params.src_pos = src_pos;
2100                            d.params.prev_return_status = TDEFLStatus::PutBufFailed;
2101                            return false;
2102                        }
2103                        Ok(status) => status,
2104                    };
2105                    if n != 0 {
2106                        d.params.src_pos = src_pos;
2107                        return n > 0;
2108                    }
2109                    debug_assert!(d.lz.code_position < LZ_CODE_BUF_SIZE - 2);
2110
2111                    lookahead_size = d.dict.lookahead_size;
2112                    lookahead_pos = d.dict.lookahead_pos;
2113                }
2114            }
2115        }
2116
2117        while lookahead_size != 0 {
2118            let lit = d.dict.b.dict[cur_pos];
2119            d.lz.total_bytes += 1;
2120            d.lz.write_code(lit);
2121            *d.lz.get_flag() >>= 1;
2122            d.lz.consume_flag();
2123
2124            d.huff.count[0][lit as usize] += 1;
2125            lookahead_pos += 1;
2126            d.dict.size = cmp::min(d.dict.size + 1, LZ_DICT_SIZE);
2127            cur_pos = (cur_pos + 1) & LZ_DICT_SIZE_MASK;
2128            lookahead_size -= 1;
2129
2130            if d.lz.code_position > LZ_CODE_BUF_SIZE - 8 {
2131                d.dict.lookahead_size = lookahead_size;
2133                d.dict.lookahead_pos = lookahead_pos;
2134
2135                let n = match flush_block(d, callback, TDEFLFlush::None) {
2136                    Err(_) => {
2137                        d.params.prev_return_status = TDEFLStatus::PutBufFailed;
2138                        d.params.src_pos = src_pos;
2139                        return false;
2140                    }
2141                    Ok(status) => status,
2142                };
2143                if n != 0 {
2144                    d.params.src_pos = src_pos;
2145                    return n > 0;
2146                }
2147
2148                lookahead_size = d.dict.lookahead_size;
2149                lookahead_pos = d.dict.lookahead_pos;
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    true
2158}
2159
2160fn flush_output_buffer(c: &mut CallbackOxide, p: &mut ParamsOxide) -> (TDEFLStatus, usize, usize) {
2161    let mut res = (TDEFLStatus::Okay, p.src_pos, 0);
2162    if let CallbackOut::Buf(ref mut cb) = c.out {
2163        let n = cmp::min(cb.out_buf.len() - p.out_buf_ofs, p.flush_remaining as usize);
2164        if n != 0 {
2165            cb.out_buf[p.out_buf_ofs..p.out_buf_ofs + n]
2166                .copy_from_slice(&p.local_buf.b[p.flush_ofs as usize..p.flush_ofs as usize + n]);
2167        }
2168        p.flush_ofs += n as u32;
2169        p.flush_remaining -= n as u32;
2170        p.out_buf_ofs += n;
2171        res.2 = p.out_buf_ofs;
2172    }
2173
2174    if p.finished && p.flush_remaining == 0 {
2175        res.0 = TDEFLStatus::Done
2176    }
2177    res
2178}
2179
2180pub fn compress(
2197    d: &mut CompressorOxide,
2198    in_buf: &[u8],
2199    out_buf: &mut [u8],
2200    flush: TDEFLFlush,
2201) -> (TDEFLStatus, usize, usize) {
2202    compress_inner(
2203        d,
2204        &mut CallbackOxide::new_callback_buf(in_buf, out_buf),
2205        flush,
2206    )
2207}
2208
2209pub fn compress_to_output(
2218    d: &mut CompressorOxide,
2219    in_buf: &[u8],
2220    flush: TDEFLFlush,
2221    mut callback_func: impl FnMut(&[u8]) -> bool,
2222) -> (TDEFLStatus, usize) {
2223    let res = compress_inner(
2224        d,
2225        &mut CallbackOxide::new_callback_func(
2226            in_buf,
2227            CallbackFunc {
2228                put_buf_func: &mut callback_func,
2229            },
2230        ),
2231        flush,
2232    );
2233
2234    (res.0, res.1)
2235}
2236
2237fn compress_inner(
2238    d: &mut CompressorOxide,
2239    callback: &mut CallbackOxide,
2240    flush: TDEFLFlush,
2241) -> (TDEFLStatus, usize, usize) {
2242    d.params.out_buf_ofs = 0;
2243    d.params.src_pos = 0;
2244
2245    let prev_ok = d.params.prev_return_status == TDEFLStatus::Okay;
2246    let flush_finish_once = d.params.flush != TDEFLFlush::Finish || flush == TDEFLFlush::Finish;
2247
2248    d.params.flush = flush;
2249    if !prev_ok || !flush_finish_once {
2250        d.params.prev_return_status = TDEFLStatus::BadParam;
2251        return (d.params.prev_return_status, 0, 0);
2252    }
2253
2254    if d.params.flush_remaining != 0 || d.params.finished {
2255        let res = flush_output_buffer(callback, &mut d.params);
2256        d.params.prev_return_status = res.0;
2257        return res;
2258    }
2259
2260    let one_probe = d.params.flags & MAX_PROBES_MASK == 1;
2261    let greedy = d.params.flags & TDEFL_GREEDY_PARSING_FLAG != 0;
2262    let filter_or_rle = d.params.flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS) != 0;
2263
2264    let raw = d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0;
2265
2266    let compress_success = if raw {
2267        compress_stored(d, callback)
2268    } else if one_probe && greedy && !filter_or_rle {
2269        compress_fast(d, callback)
2270    } else {
2271        compress_normal(d, callback)
2272    };
2273
2274    if !compress_success {
2275        return (
2276            d.params.prev_return_status,
2277            d.params.src_pos,
2278            d.params.out_buf_ofs,
2279        );
2280    }
2281
2282    if let Some(in_buf) = callback.in_buf {
2283        if d.params.flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32) != 0 {
2284            d.params.adler32 = update_adler32(d.params.adler32, &in_buf[..d.params.src_pos]);
2285        }
2286    }
2287
2288    let flush_none = d.params.flush == TDEFLFlush::None;
2289    let in_left = callback.in_buf.map_or(0, |buf| buf.len()) - d.params.src_pos;
2290    let remaining = in_left != 0 || d.params.flush_remaining != 0;
2291    if !flush_none && d.dict.lookahead_size == 0 && !remaining {
2292        let flush = d.params.flush;
2293        match flush_block(d, callback, flush) {
2294            Err(_) => {
2295                d.params.prev_return_status = TDEFLStatus::PutBufFailed;
2296                return (
2297                    d.params.prev_return_status,
2298                    d.params.src_pos,
2299                    d.params.out_buf_ofs,
2300                );
2301            }
2302            Ok(x) if x < 0 => {
2303                return (
2304                    d.params.prev_return_status,
2305                    d.params.src_pos,
2306                    d.params.out_buf_ofs,
2307                )
2308            }
2309            _ => {
2310                d.params.finished = d.params.flush == TDEFLFlush::Finish;
2311                if d.params.flush == TDEFLFlush::Full {
2312                    d.dict.b.hash.fill(0);
2313                    d.dict.b.next.fill(0);
2314                    d.dict.size = 0;
2315                }
2316            }
2317        }
2318    }
2319
2320    let res = flush_output_buffer(callback, &mut d.params);
2321    d.params.prev_return_status = res.0;
2322
2323    res
2324}
2325
2326pub fn create_comp_flags_from_zip_params(level: i32, window_bits: i32, strategy: i32) -> u32 {
2339    let num_probes = (if level >= 0 {
2340        cmp::min(10, level)
2341    } else {
2342        CompressionLevel::DefaultLevel as i32
2343    }) as usize;
2344    let greedy = if level <= 3 {
2345        TDEFL_GREEDY_PARSING_FLAG
2346    } else {
2347        0
2348    };
2349    let mut comp_flags = u32::from(NUM_PROBES[num_probes]) | greedy;
2350
2351    if window_bits > 0 {
2352        comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
2353    }
2354
2355    if level == 0 {
2356        comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
2357    } else if strategy == CompressionStrategy::Filtered as i32 {
2358        comp_flags |= TDEFL_FILTER_MATCHES;
2359    } else if strategy == CompressionStrategy::HuffmanOnly as i32 {
2360        comp_flags &= !MAX_PROBES_MASK;
2361    } else if strategy == CompressionStrategy::Fixed as i32 {
2362        comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
2363    } else if strategy == CompressionStrategy::RLE as i32 {
2364        comp_flags |= TDEFL_RLE_MATCHES;
2365    }
2366
2367    comp_flags
2368}
2369
2370#[cfg(test)]
2371mod test {
2372    use super::{
2373        compress_to_output, create_comp_flags_from_zip_params, read_u16_le, write_u16_le,
2374        CompressionStrategy, CompressorOxide, TDEFLFlush, TDEFLStatus, DEFAULT_FLAGS,
2375        MZ_DEFAULT_WINDOW_BITS,
2376    };
2377    use crate::inflate::decompress_to_vec;
2378    use alloc::vec;
2379
2380    #[test]
2381    fn u16_to_slice() {
2382        let mut slice = [0, 0];
2383        write_u16_le(2000, &mut slice, 0);
2384        assert_eq!(slice, [208, 7]);
2385    }
2386
2387    #[test]
2388    fn u16_from_slice() {
2389        let slice = [208, 7];
2390        assert_eq!(read_u16_le(&slice, 0), 2000);
2391    }
2392
2393    #[test]
2394    fn compress_output() {
2395        assert_eq!(
2396            DEFAULT_FLAGS,
2397            create_comp_flags_from_zip_params(
2398                4,
2399                MZ_DEFAULT_WINDOW_BITS,
2400                CompressionStrategy::Default as i32
2401            )
2402        );
2403
2404        let slice = [
2405            1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 6, 1, 2, 3, 1, 2, 3, 2, 3, 1, 2, 3,
2406        ];
2407        let mut encoded = vec![];
2408        let flags = create_comp_flags_from_zip_params(6, 0, 0);
2409        let mut d = CompressorOxide::new(flags);
2410        let (status, in_consumed) =
2411            compress_to_output(&mut d, &slice, TDEFLFlush::Finish, |out: &[u8]| {
2412                encoded.extend_from_slice(out);
2413                true
2414            });
2415
2416        assert_eq!(status, TDEFLStatus::Done);
2417        assert_eq!(in_consumed, slice.len());
2418
2419        let decoded = decompress_to_vec(&encoded[..]).unwrap();
2420        assert_eq!(&decoded[..], &slice[..]);
2421    }
2422
2423    #[test]
2424    fn compress_fast() {
2426        let slice = [
2427            1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 6, 1, 2, 3, 1, 2, 3, 2, 3, 1, 2, 3,
2428        ];
2429        let mut encoded = vec![];
2430        let flags = create_comp_flags_from_zip_params(1, 0, 0);
2431        let mut d = CompressorOxide::new(flags);
2432        let (status, in_consumed) =
2433            compress_to_output(&mut d, &slice, TDEFLFlush::Finish, |out: &[u8]| {
2434                encoded.extend_from_slice(out);
2435                true
2436            });
2437
2438        assert_eq!(status, TDEFLStatus::Done);
2439        assert_eq!(in_consumed, slice.len());
2440
2441        assert_eq!(
2443            &encoded[..],
2444            [99, 100, 98, 102, 1, 98, 48, 98, 3, 147, 204, 76, 204, 140, 76, 204, 0]
2445        );
2446
2447        let decoded = decompress_to_vec(&encoded[..]).unwrap();
2448        assert_eq!(&decoded[..], &slice[..]);
2449    }
2450
2451    #[test]
2452    fn zlib_window_bits() {
2453        use crate::inflate::stream::{inflate, InflateState};
2454        use crate::DataFormat;
2455        use alloc::boxed::Box;
2456        let slice = [
2457            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,
2458            6, 2, 6,
2459        ];
2460        let mut encoded = vec![];
2461        let flags = create_comp_flags_from_zip_params(2, 1, CompressionStrategy::RLE.into());
2462        let mut d = CompressorOxide::new(flags);
2463        let (status, in_consumed) =
2464            compress_to_output(&mut d, &slice, TDEFLFlush::Finish, |out: &[u8]| {
2465                encoded.extend_from_slice(out);
2466                true
2467            });
2468
2469        assert_eq!(status, TDEFLStatus::Done);
2470        assert_eq!(in_consumed, slice.len());
2471
2472        let mut output = vec![0; slice.len()];
2473
2474        let mut decompressor = Box::new(InflateState::new(DataFormat::Zlib));
2475
2476        let mut out_slice = output.as_mut_slice();
2477        for i in 0..encoded.len() {
2479            let result = inflate(
2480                &mut decompressor,
2481                &encoded[i..i + 1],
2482                out_slice,
2483                crate::MZFlush::None,
2484            );
2485            out_slice = &mut out_slice[result.bytes_written..];
2486        }
2487        let cmf = decompressor.decompressor().zlib_header().0;
2488        assert_eq!(cmf, 8);
2489        assert_eq!(output, slice)
2490    }
2491}