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}