1use alloc::boxed::Box;
4#[cfg(target_arch = "wasm32")]
5use alloc::vec;
6use core::convert::TryInto;
7use core::{cmp, mem};
8
9use super::super::*;
10use super::deflate_flags::*;
11use super::CompressionLevel;
12use crate::deflate::buffer::{
13 update_hash, HashBuffers, LocalBuf, LZ_CODE_BUF_MASK, LZ_CODE_BUF_SIZE, LZ_DICT_FULL_SIZE,
14 LZ_HASH_BITS, LZ_HASH_SHIFT, LZ_HASH_SIZE, OUT_BUF_SIZE,
15};
16use crate::deflate::stored::compress_stored;
17use crate::deflate::zlib;
18use crate::shared::{update_adler32, HUFFMAN_LENGTH_ORDER, MZ_ADLER32_INIT};
19use crate::DataFormat;
20
21type Result<T, E = Error> = core::result::Result<T, E>;
24pub(crate) struct Error {}
25
26pub(crate) const MAX_PROBES_MASK: u32 = 0xFFF;
27
28const MAX_SUPPORTED_HUFF_CODESIZE: usize = 15;
29
30const LEN_SYM: [u8; 256] = [
36 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15,
37 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19,
38 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
39 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23,
40 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
41 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
42 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
43 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27,
44 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
45 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
46 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29,
47];
48
49const LEN_SYM_OFFSET: usize = 256;
50
51#[rustfmt::skip]
53const LEN_EXTRA: [u8; 256] = [
54 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
55 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
56 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
57 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
58 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
59 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
60 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
61 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
62 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
63 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
64 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
65 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
66 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
67 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
68 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
69 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0
70];
71
72#[rustfmt::skip]
74const SMALL_DIST_SYM: [u8; 512] = [
75 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
76 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
77 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
78 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
79 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
80 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
81 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
82 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
83 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
84 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
85 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
86 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
87 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
88 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
89 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
90 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
91 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
92 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
93 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
94 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
95 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
96 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
97 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
98 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
99 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
100 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
101 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
102 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
103 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
104 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
105 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
106 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
107];
108
109#[rustfmt::skip]
133const SMALL_DIST_EXTRA: [u8; 128] = [
134 0, 1, 2, 2, 3, 3, 3, 3,
135 4, 4, 4, 4, 4, 4, 4, 4,
136 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
137 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
138 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
139 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
140];
141
142#[rustfmt::skip]
144const LARGE_DIST_SYM: [u8; 128] = [
145 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
146 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25,
147 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
148 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
149 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
150 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
151 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
152 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
153];
154
155#[rustfmt::skip]
157const LARGE_DIST_EXTRA: [u8; 128] = [
158 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
159 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
160 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
161 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
162 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
163 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
164 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
165 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13
166];
167
168#[rustfmt::skip]
169const BITMASKS: [u32; 17] = [
170 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
171 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
172];
173
174pub(crate) const NUM_PROBES: [u16; 11] = [0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500];
177
178#[derive(Copy, Clone)]
179struct SymFreq {
180 key: u16,
181 sym_index: u16,
182}
183
184pub mod deflate_flags {
185 pub const TDEFL_WRITE_ZLIB_HEADER: u32 = 0x0000_1000;
187 pub const TDEFL_COMPUTE_ADLER32: u32 = 0x0000_2000;
189 pub const TDEFL_GREEDY_PARSING_FLAG: u32 = 0x0000_4000;
192 pub const TDEFL_NONDETERMINISTIC_PARSING_FLAG: u32 = 0x0000_8000;
195 pub const TDEFL_RLE_MATCHES: u32 = 0x0001_0000;
197 pub const TDEFL_FILTER_MATCHES: u32 = 0x0002_0000;
199 pub const TDEFL_FORCE_ALL_STATIC_BLOCKS: u32 = 0x0004_0000;
202 pub const TDEFL_FORCE_ALL_RAW_BLOCKS: u32 = 0x0008_0000;
204}
205
206#[repr(i32)]
210#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
211#[non_exhaustive]
212pub enum CompressionStrategy {
213 Default = 0,
215 Filtered = 1,
217 HuffmanOnly = 2,
220 RLE = 3,
222 Fixed = 4,
225}
226
227impl From<CompressionStrategy> for i32 {
228 #[inline(always)]
229 fn from(value: CompressionStrategy) -> Self {
230 value as i32
231 }
232}
233
234#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
236#[non_exhaustive]
237pub enum TDEFLFlush {
238 None = 0,
242
243 Partial = 1,
246
247 Sync = 2,
250
251 Full = 3,
254
255 Finish = 4,
259
260 PartialOpt = 5,
264
265 SyncOpt = 6,
269
270 NoSync = 7,
276}
277
278impl From<MZFlush> for TDEFLFlush {
279 fn from(flush: MZFlush) -> Self {
280 match flush {
281 MZFlush::None => TDEFLFlush::None,
282 MZFlush::Partial => TDEFLFlush::Partial,
283 MZFlush::Sync => TDEFLFlush::Sync,
284 MZFlush::Full => TDEFLFlush::Full,
285 MZFlush::Finish => TDEFLFlush::Finish,
286 _ => TDEFLFlush::None, }
288 }
289}
290
291impl TDEFLFlush {
292 pub const fn new(flush: i32) -> Result<Self, MZError> {
293 match flush {
294 0 => Ok(TDEFLFlush::None),
295 1 => Ok(TDEFLFlush::Partial),
296 2 => Ok(TDEFLFlush::Sync),
297 3 => Ok(TDEFLFlush::Full),
298 4 => Ok(TDEFLFlush::Finish),
299 5 => Ok(TDEFLFlush::PartialOpt),
300 6 => Ok(TDEFLFlush::SyncOpt),
301 7 => Ok(TDEFLFlush::NoSync),
302 _ => Err(MZError::Param),
303 }
304 }
305}
306
307#[repr(i32)]
309#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
310pub enum TDEFLStatus {
311 BadParam = -2,
316
317 PutBufFailed = -1,
321
322 Okay = 0,
324
325 Done = 1,
329}
330
331const MAX_HUFF_SYMBOLS: usize = 288;
332const LEVEL1_HASH_SIZE_MASK: u32 = 4095;
334const MAX_HUFF_TABLES: usize = 3;
337const MAX_HUFF_SYMBOLS_0: usize = 288;
339const MAX_HUFF_SYMBOLS_1: usize = 32;
341const MAX_HUFF_SYMBOLS_2: usize = 19;
343pub(crate) const LZ_DICT_SIZE: usize = 32_768;
345pub(crate) const LZ_DICT_SIZE_MASK: usize = (LZ_DICT_SIZE as u32 - 1) as usize;
347pub(crate) const MIN_MATCH_LEN: u8 = 3;
349pub(crate) const MAX_MATCH_LEN: usize = 258;
351
352pub(crate) const DEFAULT_FLAGS: u32 = NUM_PROBES[4] as u32 | TDEFL_WRITE_ZLIB_HEADER;
353
354#[cfg(test)]
355#[inline]
356fn write_u16_le(val: u16, slice: &mut [u8], pos: usize) {
357 slice[pos] = val as u8;
358 slice[pos + 1] = (val >> 8) as u8;
359}
360
361#[inline(always)]
363const fn read_u16_le<const N: usize>(slice: &[u8; N], pos: usize) -> u16 {
364 slice[pos] as u16 | ((slice[pos + 1] as u16) << 8)
366}
367
368#[derive(Clone)]
370pub struct CompressorOxide {
371 pub(crate) lz: LZOxide,
372 pub(crate) params: ParamsOxide,
373 pub(crate) huff: Box<HuffmanOxide>,
376 pub(crate) dict: DictOxide,
377}
378
379const fn change_window_bits_from_format(window_bits: u8, data_format: DataFormat) -> i32 {
380 match data_format {
381 DataFormat::Zlib | DataFormat::ZLibIgnoreChecksum => window_bits as i32,
382 DataFormat::Raw => -(window_bits as i32),
383 }
384}
385
386fn limit_level_by_window_bits(
388 window_bits: u8,
389 current_level: i32,
390 current_strategy: CompressionStrategy,
391) -> (i32, CompressionStrategy) {
392 if window_bits < 12 {
393 if current_strategy != CompressionStrategy::HuffmanOnly && current_level != 0 {
395 (1, CompressionStrategy::RLE)
396 } else {
397 (current_level, current_strategy)
398 }
399 } else if window_bits < MZ_DEFAULT_WINDOW_BITS as u8 {
401 (cmp::min(current_level, 1), current_strategy)
402 } else {
404 (current_level, current_strategy)
405 }
406}
407
408impl CompressorOxide {
409 #[inline]
414 pub fn new(flags: u32) -> Self {
415 CompressorOxide {
416 lz: LZOxide::new(),
417 params: ParamsOxide::new(flags, MZ_DEFAULT_WINDOW_BITS as u8),
418 huff: Box::default(),
419 dict: DictOxide::new(flags),
420 }
421 }
422
423 pub fn with_format_and_level(
426 data_format: DataFormat,
427 level: CompressionLevel,
428 ) -> CompressorOxide {
429 let flags = create_comp_flags_from_zip_params(
430 level as i32,
431 data_format.to_window_bits(),
432 CompressionStrategy::Default as i32,
433 );
434 CompressorOxide::new(flags)
435 }
436
437 pub fn with_params(
442 data_format: DataFormat,
443 level: u8,
444 strategy: CompressionStrategy,
445 window_bits: u8,
446 ) -> CompressorOxide {
447 let window_bits = cmp::min(window_bits, 15);
448 let level = cmp::min(level, 10);
449 let (level, strategy) = limit_level_by_window_bits(window_bits, level as i32, strategy);
450
451 let flags = create_comp_flags_from_zip_params(
452 level,
453 change_window_bits_from_format(window_bits, data_format),
454 strategy as i32,
455 );
456
457 CompressorOxide {
458 lz: LZOxide::new(),
459 params: ParamsOxide::new(flags, window_bits),
460 huff: Box::default(),
461 dict: DictOxide::new(flags),
462 }
463 }
464
465 pub const fn adler32(&self) -> u32 {
467 self.params.adler32
468 }
469
470 pub const fn prev_return_status(&self) -> TDEFLStatus {
473 self.params.prev_return_status
474 }
475
476 pub const fn flags(&self) -> i32 {
481 self.params.flags as i32
482 }
483
484 pub const fn data_format(&self) -> DataFormat {
486 if (self.params.flags & TDEFL_WRITE_ZLIB_HEADER) != 0 {
487 DataFormat::Zlib
488 } else {
489 DataFormat::Raw
490 }
491 }
492
493 pub fn reset(&mut self) {
497 self.lz = LZOxide::new();
500 self.params.reset();
501 *self.huff = HuffmanOxide::default();
502 self.dict.reset();
503 }
504
505 pub fn set_compression_level(&mut self, level: CompressionLevel) {
516 let format = self.data_format();
517 self.set_format_and_level(format, level as u8);
518 }
519
520 pub fn set_compression_level_raw(&mut self, level: u8) {
531 let format = self.data_format();
532 self.set_format_and_level(format, level);
533 }
534
535 pub fn set_format_and_level(&mut self, data_format: DataFormat, level: u8) {
552 let flags = create_comp_flags_from_zip_params(
553 level.into(),
554 data_format.to_window_bits(),
555 CompressionStrategy::Default as i32,
556 );
557 if data_format == DataFormat::Zlib
558 && window_bits_from_flags(flags) > self.params.window_bits_max
559 {
560 return;
561 }
562 self.params.update_flags(flags);
563 self.dict.update_flags(flags);
564 }
565
566 #[inline]
570 pub const fn unwritten_bit_count(&self) -> u32 {
571 self.params.saved_bits_in
572 }
573}
574
575impl Default for CompressorOxide {
576 fn default() -> Self {
579 CompressorOxide {
580 lz: LZOxide::new(),
581 params: ParamsOxide::new(DEFAULT_FLAGS, MZ_DEFAULT_WINDOW_BITS as u8),
582 huff: Box::default(),
583 dict: DictOxide::new(DEFAULT_FLAGS),
584 }
585 }
586}
587
588pub struct CallbackFunc<'a> {
590 pub put_buf_func: &'a mut dyn FnMut(&[u8]) -> bool,
591}
592
593impl CallbackFunc<'_> {
594 fn flush_output(
595 &mut self,
596 saved_output: SavedOutputBufferOxide,
597 params: &mut ParamsOxide,
598 ) -> i32 {
599 let call_success = (self.put_buf_func)(¶ms.local_buf.b[0..saved_output.pos]);
603
604 if !call_success {
605 params.prev_return_status = TDEFLStatus::PutBufFailed;
606 return params.prev_return_status as i32;
607 }
608
609 params.flush_remaining as i32
610 }
611}
612
613struct CallbackBuf<'a> {
614 pub out_buf: &'a mut [u8],
615}
616
617impl CallbackBuf<'_> {
618 fn flush_output(
619 &mut self,
620 saved_output: SavedOutputBufferOxide,
621 params: &mut ParamsOxide,
622 ) -> i32 {
623 if saved_output.local {
624 let n = cmp::min(saved_output.pos, self.out_buf.len() - params.out_buf_ofs);
625 (self.out_buf[params.out_buf_ofs..params.out_buf_ofs + n])
626 .copy_from_slice(¶ms.local_buf.b[..n]);
627
628 params.out_buf_ofs += n;
629 if saved_output.pos != n {
630 params.flush_ofs = n as u32;
631 params.flush_remaining = (saved_output.pos - n) as u32;
632 }
633 } else {
634 params.out_buf_ofs += saved_output.pos;
635 }
636
637 params.flush_remaining as i32
638 }
639}
640
641enum CallbackOut<'a> {
642 Func(CallbackFunc<'a>),
643 Buf(CallbackBuf<'a>),
644}
645
646impl CallbackOut<'_> {
647 fn new_output_buffer<'b>(
648 &'b mut self,
649 local_buf: &'b mut [u8],
650 out_buf_ofs: usize,
651 ) -> OutputBufferOxide<'b> {
652 let is_local;
653 let buf_len = OUT_BUF_SIZE - 16;
654 let chosen_buffer = match *self {
655 CallbackOut::Buf(ref mut cb) if cb.out_buf.len() - out_buf_ofs >= OUT_BUF_SIZE => {
656 is_local = false;
657 &mut cb.out_buf[out_buf_ofs..out_buf_ofs + buf_len]
658 }
659 _ => {
660 is_local = true;
661 &mut local_buf[..buf_len]
662 }
663 };
664
665 OutputBufferOxide {
666 inner: chosen_buffer,
667 inner_pos: 0,
668 local: is_local,
669 bit_buffer: 0,
670 bits_in: 0,
671 }
672 }
673}
674
675pub(crate) struct CallbackOxide<'a> {
676 in_buf: Option<&'a [u8]>,
677 in_buf_size: Option<&'a mut usize>,
678 out_buf_size: Option<&'a mut usize>,
679 out: CallbackOut<'a>,
680}
681
682impl<'a> CallbackOxide<'a> {
683 fn new_callback_buf(in_buf: &'a [u8], out_buf: &'a mut [u8]) -> Self {
684 CallbackOxide {
685 in_buf: Some(in_buf),
686 in_buf_size: None,
687 out_buf_size: None,
688 out: CallbackOut::Buf(CallbackBuf { out_buf }),
689 }
690 }
691
692 fn new_callback_func(in_buf: &'a [u8], callback_func: CallbackFunc<'a>) -> Self {
693 CallbackOxide {
694 in_buf: Some(in_buf),
695 in_buf_size: None,
696 out_buf_size: None,
697 out: CallbackOut::Func(callback_func),
698 }
699 }
700
701 fn update_size(&mut self, in_size: Option<usize>, out_size: Option<usize>) {
702 if let (Some(in_size), Some(size)) = (in_size, self.in_buf_size.as_mut()) {
703 **size = in_size;
704 }
705
706 if let (Some(out_size), Some(size)) = (out_size, self.out_buf_size.as_mut()) {
707 **size = out_size
708 }
709 }
710
711 fn flush_output(
712 &mut self,
713 saved_output: SavedOutputBufferOxide,
714 params: &mut ParamsOxide,
715 ) -> i32 {
716 if saved_output.pos == 0 {
717 return params.flush_remaining as i32;
718 }
719
720 self.update_size(Some(params.src_pos), None);
721 match self.out {
722 CallbackOut::Func(ref mut cf) => cf.flush_output(saved_output, params),
723 CallbackOut::Buf(ref mut cb) => cb.flush_output(saved_output, params),
724 }
725 }
726
727 pub(crate) fn buf(&mut self) -> Option<&'a [u8]> {
728 self.in_buf
729 }
730}
731
732struct OutputBufferOxide<'a> {
733 pub inner: &'a mut [u8],
734 pub inner_pos: usize,
735 pub local: bool,
736
737 pub bit_buffer: u32,
738 pub bits_in: u32,
739}
740
741impl OutputBufferOxide<'_> {
742 fn put_bits(&mut self, bits: u32, len: u32) {
746 assert!(bits <= ((1u32 << len) - 1u32));
749 self.bit_buffer |= bits << self.bits_in;
750 self.bits_in += len;
751
752 while self.bits_in >= 8 {
753 self.inner[self.inner_pos] = self.bit_buffer as u8;
754 self.inner_pos += 1;
755 self.bit_buffer >>= 8;
756 self.bits_in -= 8;
757 }
758 }
759
760 #[inline]
761 fn put_bits_no_flush(&mut self, bits: u32, len: u32) {
764 self.bit_buffer |= bits << self.bits_in;
765 self.bits_in += len;
766 }
767
768 const fn save(&self) -> SavedOutputBufferOxide {
769 SavedOutputBufferOxide {
770 pos: self.inner_pos,
771 bit_buffer: self.bit_buffer,
772 bits_in: self.bits_in,
773 local: self.local,
774 }
775 }
776
777 fn load(&mut self, saved: SavedOutputBufferOxide) {
778 self.inner_pos = saved.pos;
779 self.bit_buffer = saved.bit_buffer;
780 self.bits_in = saved.bits_in;
781 self.local = saved.local;
782 }
783
784 #[inline]
785 fn pad_to_bytes(&mut self) {
788 if self.bits_in != 0 {
789 let len = 8 - self.bits_in;
790 self.put_bits(0, len);
791 }
792 }
793
794 #[inline]
797 const fn is_byte_aligned(&self) -> bool {
798 self.bits_in == 0
799 }
800
801 #[inline]
802 fn write_bytes(&mut self, bytes: &[u8]) {
803 debug_assert_eq!(self.bits_in, 0);
804 self.inner[self.inner_pos..self.inner_pos + bytes.len()].copy_from_slice(bytes);
805 self.inner_pos += bytes.len();
806 }
807}
808
809struct SavedOutputBufferOxide {
810 pub pos: usize,
811 pub bit_buffer: u32,
812 pub bits_in: u32,
813 pub local: bool,
814}
815
816struct BitBuffer {
817 pub bit_buffer: u64,
818 pub bits_in: u32,
819}
820
821impl BitBuffer {
822 fn put_fast(&mut self, bits: u64, len: u32) {
823 self.bit_buffer |= bits << self.bits_in;
824 self.bits_in += len;
825 }
826
827 fn flush(&mut self, output: &mut OutputBufferOxide) -> Result<()> {
828 let pos = output.inner_pos;
829 {
830 let inner = &mut output.inner[pos..pos + 8];
832 let bytes = u64::to_le_bytes(self.bit_buffer);
833 inner.copy_from_slice(&bytes);
834 }
835 match output.inner_pos.checked_add((self.bits_in >> 3) as usize) {
836 Some(n) if n <= output.inner.len() => output.inner_pos = n,
837 _ => return Err(Error {}),
838 }
839 self.bit_buffer >>= self.bits_in & !7;
840 self.bits_in &= 7;
841 Ok(())
842 }
843}
844
845#[derive(Clone)]
851pub(crate) struct HuffmanOxide {
852 pub count: [[u16; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
854 pub codes: [[u16; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
856 pub code_sizes: [[u8; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
858}
859
860const LITLEN_TABLE: usize = 0;
862const DIST_TABLE: usize = 1;
864const HUFF_CODES_TABLE: usize = 2;
866
867struct Rle {
869 pub z_count: u32,
870 pub repeat_count: u16,
871 pub prev_code_size: u8,
872}
873
874impl Rle {
875 fn prev_code_size(
876 &mut self,
877 packed_code_sizes: &mut [u8],
878 packed_pos: &mut usize,
879 h: &mut HuffmanOxide,
880 ) -> Result<()> {
881 let mut write = |buf| write(buf, packed_code_sizes, packed_pos);
882 let counts = &mut h.count[HUFF_CODES_TABLE];
883 if self.repeat_count != 0 {
884 if self.repeat_count < 3 {
885 counts[self.prev_code_size as usize] =
886 counts[self.prev_code_size as usize].wrapping_add(self.repeat_count);
887 let code = self.prev_code_size;
888 write(&[code, code, code][..self.repeat_count as usize])?;
889 } else {
890 counts[16] = counts[16].wrapping_add(1);
891 write(&[16, (self.repeat_count - 3) as u8][..])?;
892 }
893 self.repeat_count = 0;
894 }
895
896 Ok(())
897 }
898
899 fn zero_code_size(
900 &mut self,
901 packed_code_sizes: &mut [u8],
902 packed_pos: &mut usize,
903 h: &mut HuffmanOxide,
904 ) -> Result<()> {
905 let mut write = |buf| write(buf, packed_code_sizes, packed_pos);
906 let counts = &mut h.count[HUFF_CODES_TABLE];
907 if self.z_count != 0 {
908 if self.z_count < 3 {
909 counts[0] = counts[0].wrapping_add(self.z_count as u16);
910 write(&[0, 0, 0][..self.z_count as usize])?;
911 } else if self.z_count <= 10 {
912 counts[17] = counts[17].wrapping_add(1);
913 write(&[17, (self.z_count - 3) as u8][..])?;
914 } else {
915 counts[18] = counts[18].wrapping_add(1);
916 write(&[18, (self.z_count - 11) as u8][..])?;
917 }
918 self.z_count = 0;
919 }
920
921 Ok(())
922 }
923}
924
925fn write(src: &[u8], dst: &mut [u8], dst_pos: &mut usize) -> Result<()> {
926 match dst.get_mut(*dst_pos..*dst_pos + src.len()) {
927 Some(s) => s.copy_from_slice(src),
928 None => return Err(Error {}),
929 }
930 *dst_pos += src.len();
931 Ok(())
932}
933
934impl Default for HuffmanOxide {
935 fn default() -> Self {
936 HuffmanOxide {
937 count: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
938 codes: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
939 code_sizes: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
940 }
941 }
942}
943
944impl HuffmanOxide {
945 fn radix_sort_symbols<'a>(
946 symbols0: &'a mut [SymFreq],
947 symbols1: &'a mut [SymFreq],
948 ) -> &'a mut [SymFreq] {
949 let mut hist = [[0; 256]; 2];
950
951 for freq in symbols0.iter() {
952 hist[0][(freq.key & 0xFF) as usize] += 1;
953 hist[1][((freq.key >> 8) & 0xFF) as usize] += 1;
954 }
955
956 let mut n_passes = 2;
957 if symbols0.len() == hist[1][0] {
958 n_passes -= 1;
959 }
960
961 let mut current_symbols = symbols0;
962 let mut new_symbols = symbols1;
963
964 for (pass, hist_item) in hist.iter().enumerate().take(n_passes) {
965 let mut offsets = [0; 256];
966 let mut offset = 0;
967 for i in 0..256 {
968 offsets[i] = offset;
969 offset += hist_item[i];
970 }
971
972 for sym in current_symbols.iter() {
973 let j = ((sym.key >> (pass * 8)) & 0xFF) as usize;
974 new_symbols[offsets[j]] = *sym;
975 offsets[j] += 1;
976 }
977
978 mem::swap(&mut current_symbols, &mut new_symbols);
979 }
980
981 current_symbols
982 }
983
984 fn calculate_minimum_redundancy(symbols: &mut [SymFreq]) {
985 match symbols.len() {
986 0 => (),
987 1 => symbols[0].key = 1,
988 n => {
989 symbols[0].key += symbols[1].key;
990 let mut root = 0;
991 let mut leaf = 2;
992 for next in 1..n - 1 {
993 if (leaf >= n) || (symbols[root].key < symbols[leaf].key) {
994 symbols[next].key = symbols[root].key;
995 symbols[root].key = next as u16;
996 root += 1;
997 } else {
998 symbols[next].key = symbols[leaf].key;
999 leaf += 1;
1000 }
1001
1002 if (leaf >= n) || (root < next && symbols[root].key < symbols[leaf].key) {
1003 symbols[next].key = symbols[next].key.wrapping_add(symbols[root].key);
1004 symbols[root].key = next as u16;
1005 root += 1;
1006 } else {
1007 symbols[next].key = symbols[next].key.wrapping_add(symbols[leaf].key);
1008 leaf += 1;
1009 }
1010 }
1011
1012 symbols[n - 2].key = 0;
1013 for next in (0..n - 2).rev() {
1014 symbols[next].key = symbols[symbols[next].key as usize].key + 1;
1015 }
1016
1017 let mut avbl = 1;
1018 let mut used = 0;
1019 let mut dpth = 0;
1020 let mut root = (n - 2) as i32;
1021 let mut next = (n - 1) as i32;
1022 while avbl > 0 {
1023 while (root >= 0) && (symbols[root as usize].key == dpth) {
1024 used += 1;
1025 root -= 1;
1026 }
1027 while avbl > used {
1028 symbols[next as usize].key = dpth;
1029 next -= 1;
1030 avbl -= 1;
1031 }
1032 avbl = 2 * used;
1033 dpth += 1;
1034 used = 0;
1035 }
1036 }
1037 }
1038 }
1039
1040 fn enforce_max_code_size(num_codes: &mut [i32], code_list_len: usize, max_code_size: usize) {
1041 if code_list_len <= 1 {
1042 return;
1043 }
1044
1045 num_codes[max_code_size] += num_codes[max_code_size + 1..].iter().sum::<i32>();
1046 let total = num_codes[1..=max_code_size]
1047 .iter()
1048 .rev()
1049 .enumerate()
1050 .fold(0u32, |total, (i, &x)| total + ((x as u32) << i));
1051
1052 for _ in (1 << max_code_size)..total {
1053 num_codes[max_code_size] -= 1;
1054 for i in (1..max_code_size).rev() {
1055 if num_codes[i] != 0 {
1056 num_codes[i] -= 1;
1057 num_codes[i + 1] += 2;
1058 break;
1059 }
1060 }
1061 }
1062 }
1063
1064 fn optimize_table(
1065 &mut self,
1066 table_num: usize,
1067 table_len: usize,
1068 code_size_limit: usize,
1069 static_table: bool,
1070 ) {
1071 let mut num_codes = [0i32; 32 + 1];
1072 let mut next_code = [0u32; MAX_SUPPORTED_HUFF_CODESIZE + 1];
1073
1074 if static_table {
1075 for &code_size in &self.code_sizes[table_num][..table_len] {
1076 num_codes[code_size as usize] += 1;
1077 }
1078 } else {
1079 let mut symbols0 = [SymFreq {
1080 key: 0,
1081 sym_index: 0,
1082 }; MAX_HUFF_SYMBOLS];
1083 let mut symbols1 = [SymFreq {
1084 key: 0,
1085 sym_index: 0,
1086 }; MAX_HUFF_SYMBOLS];
1087
1088 let mut num_used_symbols = 0;
1089 for i in 0..table_len {
1090 if self.count[table_num][i] != 0 {
1091 symbols0[num_used_symbols] = SymFreq {
1092 key: self.count[table_num][i],
1093 sym_index: i as u16,
1094 };
1095 num_used_symbols += 1;
1096 }
1097 }
1098
1099 let symbols = Self::radix_sort_symbols(
1100 &mut symbols0[..num_used_symbols],
1101 &mut symbols1[..num_used_symbols],
1102 );
1103 Self::calculate_minimum_redundancy(symbols);
1104
1105 for symbol in symbols.iter() {
1106 num_codes[symbol.key as usize] += 1;
1107 }
1108
1109 Self::enforce_max_code_size(&mut num_codes, num_used_symbols, code_size_limit);
1110
1111 self.code_sizes[table_num].fill(0);
1112 self.codes[table_num].fill(0);
1113
1114 let mut last = num_used_symbols;
1115 for (i, &num_item) in num_codes
1116 .iter()
1117 .enumerate()
1118 .take(code_size_limit + 1)
1119 .skip(1)
1120 {
1121 let first = last - num_item as usize;
1122 for symbol in &symbols[first..last] {
1123 self.code_sizes[table_num][symbol.sym_index as usize] = i as u8;
1124 }
1125 last = first;
1126 }
1127 }
1128
1129 let mut j = 0;
1130 next_code[1] = 0;
1131 for i in 2..=code_size_limit {
1132 j = (j + num_codes[i - 1]) << 1;
1133 next_code[i] = j as u32;
1134 }
1135
1136 for (&code_size, huff_code) in self.code_sizes[table_num]
1137 .iter()
1138 .take(table_len)
1139 .zip(self.codes[table_num].iter_mut().take(table_len))
1140 {
1141 if code_size == 0 {
1142 continue;
1143 }
1144
1145 let code = next_code[code_size as usize];
1146
1147 next_code[code_size as usize] += 1;
1148
1149 let rev_code = (code as u16).reverse_bits() >> (16 - code_size);
1150
1151 *huff_code = rev_code;
1152 }
1153 }
1154
1155 fn start_static_block(&mut self, output: &mut OutputBufferOxide) {
1156 self.code_sizes[LITLEN_TABLE][0..144].fill(8);
1157 self.code_sizes[LITLEN_TABLE][144..256].fill(9);
1158 self.code_sizes[LITLEN_TABLE][256..280].fill(7);
1159 self.code_sizes[LITLEN_TABLE][280..288].fill(8);
1160
1161 self.code_sizes[DIST_TABLE][..32].fill(5);
1162
1163 self.optimize_table(LITLEN_TABLE, 288, 15, true);
1164 self.optimize_table(DIST_TABLE, 32, 15, true);
1165
1166 output.put_bits(0b01, 2)
1167 }
1168
1169 fn start_dynamic_block(&mut self, output: &mut OutputBufferOxide) -> Result<()> {
1170 self.count[0][256] = 1;
1172
1173 self.optimize_table(0, MAX_HUFF_SYMBOLS_0, 15, false);
1174 self.optimize_table(1, MAX_HUFF_SYMBOLS_1, 15, false);
1175
1176 let num_lit_codes = 286
1177 - &self.code_sizes[0][257..286]
1178 .iter()
1179 .rev()
1180 .take_while(|&x| *x == 0)
1181 .count();
1182
1183 let num_dist_codes = 30
1184 - &self.code_sizes[1][1..30]
1185 .iter()
1186 .rev()
1187 .take_while(|&x| *x == 0)
1188 .count();
1189
1190 let mut code_sizes_to_pack = [0u8; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1];
1191 let mut packed_code_sizes = [0u8; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1];
1192
1193 let total_code_sizes_to_pack = num_lit_codes + num_dist_codes;
1194
1195 code_sizes_to_pack[..num_lit_codes].copy_from_slice(&self.code_sizes[0][..num_lit_codes]);
1196
1197 code_sizes_to_pack[num_lit_codes..total_code_sizes_to_pack]
1198 .copy_from_slice(&self.code_sizes[1][..num_dist_codes]);
1199
1200 let mut rle = Rle {
1201 z_count: 0,
1202 repeat_count: 0,
1203 prev_code_size: 0xFF,
1204 };
1205
1206 self.count[HUFF_CODES_TABLE][..MAX_HUFF_SYMBOLS_2].fill(0);
1207
1208 let mut packed_pos = 0;
1209 for &code_size in &code_sizes_to_pack[..total_code_sizes_to_pack] {
1210 if code_size == 0 {
1211 rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1212 rle.z_count += 1;
1213 if rle.z_count == 138 {
1214 rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1215 }
1216 } else {
1217 rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1218 if code_size != rle.prev_code_size {
1219 rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1220 self.count[HUFF_CODES_TABLE][code_size as usize] =
1221 self.count[HUFF_CODES_TABLE][code_size as usize].wrapping_add(1);
1222 write(&[code_size], &mut packed_code_sizes, &mut packed_pos)?;
1223 } else {
1224 rle.repeat_count += 1;
1225 if rle.repeat_count == 6 {
1226 rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1227 }
1228 }
1229 }
1230 rle.prev_code_size = code_size;
1231 }
1232
1233 if rle.repeat_count != 0 {
1234 rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1235 } else {
1236 rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
1237 }
1238
1239 self.optimize_table(2, MAX_HUFF_SYMBOLS_2, 7, false);
1240
1241 output.put_bits_no_flush(2, 2);
1242
1243 output.put_bits_no_flush((num_lit_codes - 257) as u32, 5);
1244 output.put_bits_no_flush((num_dist_codes - 1) as u32, 5);
1245
1246 let mut num_bit_lengths = 18
1247 - HUFFMAN_LENGTH_ORDER
1248 .iter()
1249 .rev()
1250 .take_while(|&swizzle| self.code_sizes[HUFF_CODES_TABLE][*swizzle as usize] == 0)
1251 .count();
1252
1253 num_bit_lengths = cmp::max(4, num_bit_lengths + 1);
1254 output.put_bits(num_bit_lengths as u32 - 4, 4);
1255 for &swizzle in &HUFFMAN_LENGTH_ORDER[..num_bit_lengths] {
1256 output.put_bits(
1257 u32::from(self.code_sizes[HUFF_CODES_TABLE][swizzle as usize]),
1258 3,
1259 );
1260 }
1261
1262 let mut packed_code_size_index = 0;
1263 while packed_code_size_index < packed_pos {
1264 let code = packed_code_sizes[packed_code_size_index] as usize;
1265 packed_code_size_index += 1;
1266 assert!(code < MAX_HUFF_SYMBOLS_2);
1267 output.put_bits(
1268 u32::from(self.codes[HUFF_CODES_TABLE][code]),
1269 u32::from(self.code_sizes[HUFF_CODES_TABLE][code]),
1270 );
1271 if code >= 16 {
1272 output.put_bits(
1273 u32::from(packed_code_sizes[packed_code_size_index]),
1274 [2, 3, 7][code - 16],
1275 );
1276 packed_code_size_index += 1;
1277 }
1278 }
1279
1280 Ok(())
1281 }
1282}
1283
1284#[derive(Clone)]
1285pub(crate) struct DictOxide {
1286 pub max_probes: [u32; 2],
1289 pub b: HashBuffers,
1292
1293 pub code_buf_dict_pos: usize,
1294 pub lookahead_size: usize,
1295 pub lookahead_pos: usize,
1296 pub size: usize,
1297 loop_len: u8,
1298}
1299
1300const fn probes_from_flags(flags: u32) -> [u32; 2] {
1301 [
1302 1 + ((flags & 0xFFF) + 2) / 3,
1303 1 + (((flags & 0xFFF) >> 2) + 2) / 3,
1304 ]
1305}
1306
1307impl DictOxide {
1308 fn new(flags: u32) -> Self {
1309 DictOxide {
1310 max_probes: probes_from_flags(flags),
1311 b: HashBuffers::default(),
1312 code_buf_dict_pos: 0,
1313 lookahead_size: 0,
1314 lookahead_pos: 0,
1315 size: 0,
1316 loop_len: 32,
1317 }
1318 }
1319
1320 fn update_flags(&mut self, flags: u32) {
1321 self.max_probes = probes_from_flags(flags);
1322 }
1323
1324 fn reset(&mut self) {
1325 self.b.reset();
1326 self.code_buf_dict_pos = 0;
1327 self.lookahead_size = 0;
1328 self.lookahead_pos = 0;
1329 self.size = 0;
1330 }
1331
1332 #[inline]
1335 fn read_unaligned_u32(&self, pos: usize) -> u32 {
1336 let pos = pos & LZ_DICT_SIZE_MASK;
1338 let end = pos + 4;
1339 assert!(end < LZ_DICT_FULL_SIZE);
1343
1344 let bytes: [u8; 4] = self.b.dict[pos..end].try_into().unwrap();
1345 u32::from_le_bytes(bytes)
1346 }
1347
1348 #[inline]
1351 fn read_unaligned_u64(&self, pos: usize) -> u64 {
1352 let pos = pos & LZ_DICT_SIZE_MASK;
1356 let bytes: [u8; 8] = self.b.dict[pos..pos + 8].try_into().unwrap();
1357 u64::from_le_bytes(bytes)
1358 }
1359
1360 fn find_match(
1365 &self,
1366 lookahead_pos: usize,
1367 max_dist: usize,
1368 max_match_len: u32,
1369 mut match_dist: u32,
1370 mut match_len: u32,
1371 ) -> (u32, u32) {
1372 let max_match_len = cmp::min(MAX_MATCH_LEN as u32, max_match_len);
1378 match_len = cmp::max(match_len, 1);
1379
1380 if max_match_len <= match_len {
1382 return (match_dist, match_len);
1383 }
1384
1385 let pos = lookahead_pos & LZ_DICT_SIZE_MASK;
1386 let mut probe_pos = pos;
1387 let mut num_probes_left = if match_len < 32 {
1389 self.max_probes[0]
1390 } else {
1391 self.max_probes[1]
1392 };
1393
1394 let mut c01: u16 = read_u16_le(&self.b.dict, pos + match_len as usize - 1);
1396 let s01: u16 = read_u16_le(&self.b.dict, pos);
1398
1399 'outer: loop {
1400 let mut dist;
1401 'found: loop {
1402 num_probes_left -= 1;
1403 if num_probes_left == 0 {
1404 return (match_dist, match_len);
1407 }
1408
1409 for _ in 0..3 {
1410 let next_probe_pos = self.b.next[probe_pos] as usize;
1411
1412 dist = (lookahead_pos - next_probe_pos) & 0xFFFF;
1413 #[allow(clippy::int_plus_one)]
1423 if next_probe_pos == 0
1424 || dist > max_dist
1425 || match_len as usize - 1 >= MAX_MATCH_LEN
1426 {
1427 return (match_dist, match_len);
1431 }
1432
1433 probe_pos = next_probe_pos & LZ_DICT_SIZE_MASK;
1436
1437 if read_u16_le(&self.b.dict, probe_pos + match_len as usize - 1) == c01 {
1438 break 'found;
1439 }
1440 }
1441 }
1442
1443 if dist == 0 {
1444 return (match_dist, match_len);
1447 }
1448
1449 if read_u16_le(&self.b.dict, probe_pos) != s01 {
1451 continue;
1452 }
1453
1454 let mut p = pos + 2;
1455 let mut q = probe_pos + 2;
1456 for _ in 0..self.loop_len as i32 {
1461 let p_data: u64 = self.read_unaligned_u64(p);
1462 let q_data: u64 = self.read_unaligned_u64(q);
1463 let xor_data = p_data ^ q_data;
1465 if xor_data == 0 {
1466 p += 8;
1467 q += 8;
1468 } else {
1469 let trailing = xor_data.trailing_zeros();
1471
1472 let probe_len = p - pos + (trailing as usize >> 3);
1473 if probe_len > match_len as usize {
1474 match_dist = dist as u32;
1475 match_len = cmp::min(max_match_len, probe_len as u32);
1476 if match_len >= max_match_len {
1477 return (match_dist, match_len);
1480 }
1481 c01 =
1487 read_u16_le(&self.b.dict, (pos + match_len as usize).saturating_sub(1));
1488 }
1489 continue 'outer;
1490 }
1491 }
1492
1493 return (dist as u32, cmp::min(max_match_len, MAX_MATCH_LEN as u32));
1494 }
1495 }
1496}
1497
1498#[derive(Clone)]
1499pub(crate) struct ParamsOxide {
1500 pub flags: u32,
1501 pub greedy_parsing: bool,
1502 pub window_bits_max: u8,
1508 pub block_index: u32,
1509
1510 pub saved_match_dist: u32,
1511 pub saved_match_len: u32,
1512 pub saved_lit: u8,
1513
1514 pub flush: TDEFLFlush,
1515 pub flush_ofs: u32,
1516 pub flush_remaining: u32,
1517 pub finished: bool,
1518
1519 pub adler32: u32,
1520
1521 pub src_pos: usize,
1522
1523 pub out_buf_ofs: usize,
1524 pub prev_return_status: TDEFLStatus,
1525
1526 pub saved_bit_buffer: u32,
1527 pub saved_bits_in: u32,
1528
1529 pub local_buf: Box<LocalBuf>,
1530}
1531
1532impl ParamsOxide {
1533 fn new(flags: u32, window_bits: u8) -> Self {
1534 ParamsOxide {
1535 flags,
1536 greedy_parsing: flags & TDEFL_GREEDY_PARSING_FLAG != 0,
1537 window_bits_max: window_bits,
1538 block_index: 0,
1539 saved_match_dist: 0,
1540 saved_match_len: 0,
1541 saved_lit: 0,
1542 flush: TDEFLFlush::None,
1543 flush_ofs: 0,
1544 flush_remaining: 0,
1545 finished: false,
1546 adler32: MZ_ADLER32_INIT,
1547 src_pos: 0,
1548 out_buf_ofs: 0,
1549 prev_return_status: TDEFLStatus::Okay,
1550 saved_bit_buffer: 0,
1551 saved_bits_in: 0,
1552 local_buf: Box::default(),
1553 }
1554 }
1555
1556 fn update_flags(&mut self, flags: u32) {
1557 self.flags = flags;
1558 self.greedy_parsing = self.flags & TDEFL_GREEDY_PARSING_FLAG != 0;
1559 }
1560
1561 fn reset(&mut self) {
1563 self.block_index = 0;
1564 self.saved_match_len = 0;
1565 self.saved_match_dist = 0;
1566 self.saved_lit = 0;
1567 self.flush = TDEFLFlush::None;
1568 self.flush_ofs = 0;
1569 self.flush_remaining = 0;
1570 self.finished = false;
1571 self.adler32 = MZ_ADLER32_INIT;
1572 self.src_pos = 0;
1573 self.out_buf_ofs = 0;
1574 self.prev_return_status = TDEFLStatus::Okay;
1575 self.saved_bit_buffer = 0;
1576 self.saved_bits_in = 0;
1577 self.local_buf.b = [0; OUT_BUF_SIZE];
1578 }
1579}
1580
1581#[derive(Clone)]
1582pub(crate) struct LZOxide {
1583 #[cfg(target_arch = "wasm32")]
1584 pub codes: Box<[u8; LZ_CODE_BUF_SIZE]>,
1585 #[cfg(not(target_arch = "wasm32"))]
1586 pub codes: [u8; LZ_CODE_BUF_SIZE],
1587 pub code_position: usize,
1588 pub flag_position: usize,
1589
1590 pub total_bytes: u32,
1591 pub num_flags_left: u32,
1592}
1593
1594impl LZOxide {
1595 #[cfg(target_arch = "wasm32")]
1596 fn new() -> Self {
1597 LZOxide {
1598 codes: vec![0; LZ_CODE_BUF_SIZE]
1599 .into_boxed_slice()
1600 .try_into()
1601 .unwrap(),
1602 code_position: 1,
1603 flag_position: 0,
1604 total_bytes: 0,
1605 num_flags_left: 8,
1606 }
1607 }
1608
1609 #[cfg(not(target_arch = "wasm32"))]
1610 const fn new() -> Self {
1611 LZOxide {
1612 codes: [0; LZ_CODE_BUF_SIZE],
1613 code_position: 1,
1614 flag_position: 0,
1615 total_bytes: 0,
1616 num_flags_left: 8,
1617 }
1618 }
1619
1620 fn write_code(&mut self, val: u8) {
1621 self.codes[usize::from(self.code_position as u16)] = val;
1624 self.code_position += 1;
1625 }
1626
1627 fn init_flag(&mut self) {
1628 if self.num_flags_left == 8 {
1629 *self.get_flag() = 0;
1630 self.code_position -= 1;
1631 } else {
1632 *self.get_flag() >>= self.num_flags_left;
1633 }
1634 }
1635
1636 fn get_flag(&mut self) -> &mut u8 {
1637 &mut self.codes[usize::from(self.flag_position as u16)]
1640 }
1641
1642 fn plant_flag(&mut self) {
1643 self.flag_position = self.code_position;
1644 self.code_position += 1;
1645 }
1646
1647 fn consume_flag(&mut self) {
1648 self.num_flags_left -= 1;
1649 if self.num_flags_left == 0 {
1650 self.num_flags_left = 8;
1651 self.plant_flag();
1652 }
1653 }
1654}
1655
1656fn compress_lz_codes(
1657 huff: &HuffmanOxide,
1658 output: &mut OutputBufferOxide,
1659 lz_code_buf: &[u8; LZ_CODE_BUF_SIZE],
1660 lz_code_buf_used_len: usize,
1661) -> Result<bool> {
1662 let mut flags = 1;
1663 let mut bb = BitBuffer {
1664 bit_buffer: u64::from(output.bit_buffer),
1665 bits_in: output.bits_in,
1666 };
1667
1668 let lz_code_buf_used_len = cmp::min(lz_code_buf.len(), lz_code_buf_used_len);
1671
1672 let mut i: usize = 0;
1673 while i < lz_code_buf_used_len {
1674 if flags == 1 {
1675 flags = u32::from(lz_code_buf[i]) | 0x100;
1676 i += 1;
1677 }
1678
1679 if flags & 1 == 1 {
1681 flags >>= 1;
1682
1683 let sym;
1684 let num_extra_bits;
1685
1686 let match_len = lz_code_buf[i & LZ_CODE_BUF_MASK] as usize;
1687
1688 let match_dist = lz_code_buf[(i + 1) & LZ_CODE_BUF_MASK] as u16
1689 | ((lz_code_buf[(i + 2) & LZ_CODE_BUF_MASK] as u16) << 8);
1690
1691 i += 3;
1692
1693 debug_assert!(huff.code_sizes[0][LEN_SYM[match_len] as usize + LEN_SYM_OFFSET] != 0);
1694 let len_sym = (LEN_SYM[match_len] & 31) as usize + LEN_SYM_OFFSET;
1695
1696 bb.put_fast(
1697 u64::from(huff.codes[0][len_sym]),
1698 u32::from(huff.code_sizes[0][len_sym]),
1699 );
1700 bb.put_fast(
1701 match_len as u64 & u64::from(BITMASKS[(LEN_EXTRA[match_len] & 7) as usize]),
1702 u32::from(LEN_EXTRA[match_len]),
1703 );
1704
1705 if match_dist < 512 {
1706 sym = SMALL_DIST_SYM[match_dist as usize] as usize;
1707 num_extra_bits = SMALL_DIST_EXTRA[(match_dist >> 2) as usize] as usize;
1708 } else {
1709 sym = LARGE_DIST_SYM[(match_dist >> 8) as usize] as usize;
1710 num_extra_bits = LARGE_DIST_EXTRA[(match_dist >> 8) as usize] as usize;
1711 }
1712
1713 debug_assert!(huff.code_sizes[1][sym] != 0);
1714 bb.put_fast(
1715 u64::from(huff.codes[1][sym]),
1716 u32::from(huff.code_sizes[1][sym]),
1717 );
1718 bb.put_fast(
1719 u64::from(match_dist) & u64::from(BITMASKS[num_extra_bits & 15]),
1720 num_extra_bits as u32,
1721 );
1722 } else {
1723 for _ in 0..3 {
1725 flags >>= 1;
1726 let lit = lz_code_buf[i & LZ_CODE_BUF_MASK];
1727 i += 1;
1728
1729 debug_assert!(huff.code_sizes[0][lit as usize] != 0);
1730 bb.put_fast(
1731 u64::from(huff.codes[0][lit as usize]),
1732 u32::from(huff.code_sizes[0][lit as usize]),
1733 );
1734
1735 if flags & 1 == 1 || i >= lz_code_buf_used_len {
1736 break;
1737 }
1738 }
1739 }
1740
1741 bb.flush(output)?;
1742 }
1743
1744 output.bits_in = 0;
1745 output.bit_buffer = 0;
1746 while bb.bits_in != 0 {
1747 let n = cmp::min(bb.bits_in, 16);
1748 output.put_bits(bb.bit_buffer as u32 & BITMASKS[n as usize], n);
1749 bb.bit_buffer >>= n;
1750 bb.bits_in -= n;
1751 }
1752
1753 output.put_bits(
1755 u32::from(huff.codes[0][256]),
1756 u32::from(huff.code_sizes[0][256]),
1757 );
1758
1759 Ok(true)
1760}
1761
1762fn compress_block(
1763 huff: &mut HuffmanOxide,
1764 output: &mut OutputBufferOxide,
1765 lz: &LZOxide,
1766 static_block: bool,
1767) -> Result<bool> {
1768 if static_block {
1769 huff.start_static_block(output);
1770 } else {
1771 huff.start_dynamic_block(output)?;
1772 }
1773
1774 compress_lz_codes(huff, output, &lz.codes, lz.code_position)
1775}
1776
1777pub(crate) fn flush_block(
1778 d: &mut CompressorOxide,
1779 callback: &mut CallbackOxide,
1780 flush: TDEFLFlush,
1781) -> Result<i32> {
1782 let mut saved_buffer;
1783 {
1784 let mut output = callback
1785 .out
1786 .new_output_buffer(&mut d.params.local_buf.b, d.params.out_buf_ofs);
1787 output.bit_buffer = d.params.saved_bit_buffer;
1788 output.bits_in = d.params.saved_bits_in;
1789
1790 if d.params.flags & TDEFL_WRITE_ZLIB_HEADER != 0 && d.params.block_index == 0 {
1795 let header = zlib::header_from_flags(d.params.flags, d.params.window_bits_max);
1796 output.put_bits_no_flush(header[0].into(), 8);
1797 output.put_bits(header[1].into(), 8);
1798 }
1799
1800 if d.lz.total_bytes > 0 || flush == TDEFLFlush::Finish {
1801 let use_raw_block = (d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0)
1803 && (d.dict.lookahead_pos - d.dict.code_buf_dict_pos) <= d.dict.size;
1804 debug_assert_eq!(
1805 use_raw_block,
1806 d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0
1807 );
1808
1809 debug_assert!(d.params.flush_remaining == 0);
1810 d.params.flush_ofs = 0;
1811 d.params.flush_remaining = 0;
1812
1813 d.lz.init_flag();
1814
1815 output.put_bits((flush == TDEFLFlush::Finish) as u32, 1);
1817
1818 saved_buffer = output.save();
1819
1820 let comp_success = if !use_raw_block {
1821 let use_static = (d.params.flags & TDEFL_FORCE_ALL_STATIC_BLOCKS != 0)
1822 || (d.lz.total_bytes < 48);
1823 compress_block(&mut d.huff, &mut output, &d.lz, use_static)?
1824 } else {
1825 false
1826 };
1827
1828 let expanded = (d.lz.total_bytes > 32)
1838 && (output.inner_pos - saved_buffer.pos + 1 >= (d.lz.total_bytes as usize))
1839 && (d.dict.lookahead_pos - d.dict.code_buf_dict_pos <= d.dict.size);
1840
1841 if use_raw_block || expanded {
1842 output.load(saved_buffer);
1843
1844 output.put_bits(0, 2);
1846
1847 output.pad_to_bytes();
1849
1850 output.put_bits(d.lz.total_bytes & 0xFFFF, 16);
1852 output.put_bits(!d.lz.total_bytes & 0xFFFF, 16);
1853
1854 let start = d.dict.code_buf_dict_pos & LZ_DICT_SIZE_MASK;
1856 let end =
1857 (d.dict.code_buf_dict_pos + d.lz.total_bytes as usize) & LZ_DICT_SIZE_MASK;
1858 let dict = &mut d.dict.b.dict;
1859 if start < end {
1860 output.write_bytes(&dict[start..end]);
1862 } else if d.lz.total_bytes > 0 {
1863 output.write_bytes(&dict[start..LZ_DICT_SIZE]);
1865 output.write_bytes(&dict[..end]);
1866 }
1867 } else if !comp_success {
1868 output.load(saved_buffer);
1869 compress_block(&mut d.huff, &mut output, &d.lz, true)?;
1870 }
1871 }
1872
1873 match flush {
1874 TDEFLFlush::Finish => {
1875 output.pad_to_bytes();
1876 if d.params.flags & TDEFL_WRITE_ZLIB_HEADER != 0 {
1877 let mut adler = d.params.adler32;
1878 for _ in 0..4 {
1879 output.put_bits((adler >> 24) & 0xFF, 8);
1880 adler <<= 8;
1881 }
1882 }
1883 }
1884 TDEFLFlush::Partial => {
1885 output.put_bits(2, 10);
1886 }
1887 TDEFLFlush::PartialOpt => {
1888 if !output.is_byte_aligned() {
1889 output.put_bits(2, 10);
1890 }
1891 }
1892 TDEFLFlush::Sync | TDEFLFlush::Full => {
1893 output.put_bits(0, 3);
1895 output.pad_to_bytes();
1896 output.put_bits(0, 16);
1897 output.put_bits(0xFFFF, 16);
1898 }
1899 TDEFLFlush::SyncOpt => {
1900 if !output.is_byte_aligned() {
1901 output.put_bits(0, 3);
1902 output.pad_to_bytes();
1903 output.put_bits(0, 16);
1904 output.put_bits(0xFFFF, 16);
1905 }
1906 }
1907 TDEFLFlush::None | TDEFLFlush::NoSync => (),
1908 }
1909
1910 d.huff.count[0][..MAX_HUFF_SYMBOLS_0].fill(0);
1911 d.huff.count[1][..MAX_HUFF_SYMBOLS_1].fill(0);
1912
1913 d.lz.code_position = 1;
1915 d.lz.flag_position = 0;
1916 d.lz.num_flags_left = 8;
1917 d.dict.code_buf_dict_pos += d.lz.total_bytes as usize;
1918 d.lz.total_bytes = 0;
1919 d.params.block_index += 1;
1920
1921 saved_buffer = output.save();
1922
1923 d.params.saved_bit_buffer = saved_buffer.bit_buffer;
1924 d.params.saved_bits_in = saved_buffer.bits_in;
1925 }
1926
1927 Ok(callback.flush_output(saved_buffer, &mut d.params))
1928}
1929
1930pub(crate) fn record_literal(h: &mut HuffmanOxide, lz: &mut LZOxide, lit: u8) {
1931 lz.total_bytes += 1;
1932 lz.write_code(lit);
1933
1934 *lz.get_flag() >>= 1;
1935 lz.consume_flag();
1936
1937 h.count[0][lit as usize] += 1;
1938}
1939
1940fn record_match(h: &mut HuffmanOxide, lz: &mut LZOxide, match_len: u32, mut match_dist: u32) {
1941 debug_assert!(match_len >= MIN_MATCH_LEN.into());
1942 debug_assert!(match_dist >= 1);
1943 debug_assert!(match_dist as usize <= LZ_DICT_SIZE);
1944
1945 lz.total_bytes += match_len;
1946 match_dist -= 1;
1947 let match_len = (match_len - u32::from(MIN_MATCH_LEN)) as u8;
1948 lz.write_code(match_len);
1949 lz.write_code(match_dist as u8);
1950 lz.write_code((match_dist >> 8) as u8);
1951
1952 *lz.get_flag() >>= 1;
1953 *lz.get_flag() |= 0x80;
1954 lz.consume_flag();
1955
1956 let symbol = if match_dist < 512 {
1957 SMALL_DIST_SYM[match_dist as usize]
1958 } else {
1959 LARGE_DIST_SYM[((match_dist >> 8) & 127) as usize]
1960 } as usize;
1961 h.count[1][symbol] += 1;
1962 h.count[0][(LEN_SYM[match_len as usize] as usize & 31) + LEN_SYM_OFFSET] += 1;
1965}
1966
1967fn compress_normal(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool {
1968 let in_buf = match callback.in_buf {
1969 None => return true,
1970 Some(in_buf) => in_buf,
1971 };
1972
1973 let mut src_pos = d.params.src_pos;
1974 let mut lookahead_size = d.dict.lookahead_size;
1975 let mut lookahead_pos = d.dict.lookahead_pos;
1976 let mut saved_lit = d.params.saved_lit;
1977 let mut saved_match_dist = d.params.saved_match_dist;
1978 let mut saved_match_len = d.params.saved_match_len;
1979
1980 while src_pos < in_buf.len() || (d.params.flush != TDEFLFlush::None && lookahead_size != 0) {
1981 let in_buf_left = &in_buf[src_pos..];
1982 let num_bytes_to_process = cmp::min(in_buf_left.len(), MAX_MATCH_LEN - lookahead_size);
1983 let bytes_to_process = &in_buf_left[..num_bytes_to_process];
1984
1985 if lookahead_size + d.dict.size >= usize::from(MIN_MATCH_LEN) - 1
1986 && num_bytes_to_process > 0
1987 {
1988 let dictb = &mut d.dict.b;
1989
1990 let mut dst_pos = (lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK;
1991 let mut ins_pos = lookahead_pos + lookahead_size - 2;
1992 let mut hash = update_hash(
1994 u16::from(dictb.dict[ins_pos & LZ_DICT_SIZE_MASK]),
1995 dictb.dict[(ins_pos + 1) & LZ_DICT_SIZE_MASK],
1996 );
1997
1998 lookahead_size += num_bytes_to_process;
1999
2000 for &c in bytes_to_process {
2001 dictb.dict[dst_pos] = c;
2003 if dst_pos < MAX_MATCH_LEN - 1 {
2004 dictb.dict[LZ_DICT_SIZE + dst_pos] = c;
2005 }
2006
2007 hash = update_hash(hash, c);
2009 dictb.next[ins_pos & LZ_DICT_SIZE_MASK] = dictb.hash[hash as usize];
2010 dictb.hash[hash as usize] = ins_pos as u16;
2012 dst_pos = (dst_pos + 1) & LZ_DICT_SIZE_MASK;
2013 ins_pos += 1;
2014 }
2015
2016 src_pos += num_bytes_to_process;
2017 } else {
2018 let dictb = &mut d.dict.b;
2019 for &c in bytes_to_process {
2020 let dst_pos = (lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK;
2021 dictb.dict[dst_pos] = c;
2022 if dst_pos < MAX_MATCH_LEN - 1 {
2023 dictb.dict[LZ_DICT_SIZE + dst_pos] = c;
2024 }
2025
2026 lookahead_size += 1;
2027 if lookahead_size + d.dict.size >= MIN_MATCH_LEN.into() {
2028 let ins_pos = lookahead_pos + lookahead_size - 3;
2029 let hash = ((u32::from(dictb.dict[ins_pos & LZ_DICT_SIZE_MASK])
2030 << (LZ_HASH_SHIFT * 2))
2031 ^ ((u32::from(dictb.dict[(ins_pos + 1) & LZ_DICT_SIZE_MASK])
2032 << LZ_HASH_SHIFT)
2033 ^ u32::from(c)))
2034 & (LZ_HASH_SIZE as u32 - 1);
2035
2036 dictb.next[ins_pos & LZ_DICT_SIZE_MASK] = dictb.hash[hash as usize];
2037 dictb.hash[hash as usize] = ins_pos as u16;
2038 }
2039 }
2040
2041 src_pos += num_bytes_to_process;
2042 }
2043
2044 d.dict.size = cmp::min(LZ_DICT_SIZE - lookahead_size, d.dict.size);
2045 if d.params.flush == TDEFLFlush::None && lookahead_size < MAX_MATCH_LEN {
2046 break;
2047 }
2048
2049 let mut len_to_move = 1;
2050 let mut cur_match_dist = 0;
2051 let mut cur_match_len = if saved_match_len != 0 {
2052 saved_match_len
2053 } else {
2054 u32::from(MIN_MATCH_LEN) - 1
2055 };
2056 let cur_pos = lookahead_pos & LZ_DICT_SIZE_MASK;
2057 if d.params.flags & TDEFL_RLE_MATCHES != 0 {
2058 if d.dict.size != 0 {
2060 let c = d.dict.b.dict[(cur_pos.wrapping_sub(1)) & LZ_DICT_SIZE_MASK];
2061 cur_match_len = d.dict.b.dict[cur_pos..(cur_pos + lookahead_size)]
2062 .iter()
2063 .take_while(|&x| *x == c)
2064 .count() as u32;
2065 if cur_match_len < MIN_MATCH_LEN.into() {
2066 cur_match_len = 0
2067 } else {
2068 cur_match_dist = 1
2069 }
2070 }
2071 } else {
2072 let dist_len = d.dict.find_match(
2074 lookahead_pos,
2075 d.dict.size,
2076 lookahead_size as u32,
2077 cur_match_dist,
2078 cur_match_len,
2079 );
2080 cur_match_dist = dist_len.0;
2081 cur_match_len = dist_len.1;
2082 }
2083
2084 let far_and_small = cur_match_len == MIN_MATCH_LEN.into() && cur_match_dist >= 8 * 1024;
2085 let filter_small = d.params.flags & TDEFL_FILTER_MATCHES != 0 && cur_match_len <= 5;
2086 if far_and_small || filter_small || cur_pos == cur_match_dist as usize {
2087 cur_match_dist = 0;
2088 cur_match_len = 0;
2089 }
2090
2091 if saved_match_len != 0 {
2092 if cur_match_len > saved_match_len {
2093 record_literal(&mut d.huff, &mut d.lz, saved_lit);
2094 if cur_match_len >= 128 {
2095 record_match(&mut d.huff, &mut d.lz, cur_match_len, cur_match_dist);
2096 saved_match_len = 0;
2097 len_to_move = cur_match_len as usize;
2098 } else {
2099 saved_lit = d.dict.b.dict[cur_pos];
2100 saved_match_dist = cur_match_dist;
2101 saved_match_len = cur_match_len;
2102 }
2103 } else {
2104 record_match(&mut d.huff, &mut d.lz, saved_match_len, saved_match_dist);
2105 len_to_move = (saved_match_len - 1) as usize;
2106 saved_match_len = 0;
2107 }
2108 } else if cur_match_dist == 0 {
2109 record_literal(
2110 &mut d.huff,
2111 &mut d.lz,
2112 d.dict.b.dict[cmp::min(cur_pos, d.dict.b.dict.len() - 1)],
2113 );
2114 } else if d.params.greedy_parsing
2115 || (d.params.flags & TDEFL_RLE_MATCHES != 0)
2116 || cur_match_len >= 128
2117 {
2118 record_match(&mut d.huff, &mut d.lz, cur_match_len, cur_match_dist);
2121 len_to_move = cur_match_len as usize;
2122 } else {
2123 saved_lit = d.dict.b.dict[cmp::min(cur_pos, d.dict.b.dict.len() - 1)];
2124 saved_match_dist = cur_match_dist;
2125 saved_match_len = cur_match_len;
2126 }
2127
2128 lookahead_pos += len_to_move;
2129 debug_assert!(lookahead_size >= len_to_move);
2130 lookahead_size -= len_to_move;
2131 d.dict.size = cmp::min(d.dict.size + len_to_move, LZ_DICT_SIZE);
2132
2133 let lz_buf_tight = d.lz.code_position > LZ_CODE_BUF_SIZE - 8;
2134 let fat = ((d.lz.code_position * 115) >> 7) >= d.lz.total_bytes as usize;
2135 let buf_fat = (d.lz.total_bytes > 31 * 1024) && fat;
2136
2137 if lz_buf_tight || buf_fat {
2138 d.params.src_pos = src_pos;
2139 d.dict.lookahead_size = lookahead_size;
2141 d.dict.lookahead_pos = lookahead_pos;
2142
2143 let n = flush_block(d, callback, TDEFLFlush::None)
2144 .unwrap_or(TDEFLStatus::PutBufFailed as i32);
2145 if n != 0 {
2146 d.params.saved_lit = saved_lit;
2147 d.params.saved_match_dist = saved_match_dist;
2148 d.params.saved_match_len = saved_match_len;
2149 return n > 0;
2150 }
2151 }
2152 }
2153
2154 d.params.src_pos = src_pos;
2155 d.dict.lookahead_size = lookahead_size;
2156 d.dict.lookahead_pos = lookahead_pos;
2157 d.params.saved_lit = saved_lit;
2158 d.params.saved_match_dist = saved_match_dist;
2159 d.params.saved_match_len = saved_match_len;
2160 true
2161}
2162
2163const COMP_FAST_LOOKAHEAD_SIZE: usize = 4096;
2164
2165fn compress_fast(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool {
2166 let mut src_pos = d.params.src_pos;
2167 let mut lookahead_size = d.dict.lookahead_size;
2168 let mut lookahead_pos = d.dict.lookahead_pos;
2169
2170 let mut cur_pos = lookahead_pos & LZ_DICT_SIZE_MASK;
2171 let in_buf = match callback.in_buf {
2172 None => return true,
2173 Some(in_buf) => in_buf,
2174 };
2175
2176 debug_assert!(d.lz.code_position < LZ_CODE_BUF_SIZE - 2);
2177
2178 while src_pos < in_buf.len() || (d.params.flush != TDEFLFlush::None && lookahead_size > 0) {
2179 let mut dst_pos = (lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK;
2180 let mut num_bytes_to_process = cmp::min(
2181 in_buf.len() - src_pos,
2182 COMP_FAST_LOOKAHEAD_SIZE - lookahead_size,
2183 );
2184 lookahead_size += num_bytes_to_process;
2185
2186 while num_bytes_to_process != 0 {
2187 let n = cmp::min(LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
2188 d.dict.b.dict[dst_pos..dst_pos + n].copy_from_slice(&in_buf[src_pos..src_pos + n]);
2189
2190 if dst_pos < MAX_MATCH_LEN - 1 {
2191 let m = cmp::min(n, MAX_MATCH_LEN - 1 - dst_pos);
2192 d.dict.b.dict[dst_pos + LZ_DICT_SIZE..dst_pos + LZ_DICT_SIZE + m]
2193 .copy_from_slice(&in_buf[src_pos..src_pos + m]);
2194 }
2195
2196 src_pos += n;
2197 dst_pos = (dst_pos + n) & LZ_DICT_SIZE_MASK;
2198 num_bytes_to_process -= n;
2199 }
2200
2201 d.dict.size = cmp::min(LZ_DICT_SIZE - lookahead_size, d.dict.size);
2202 if d.params.flush == TDEFLFlush::None && lookahead_size < COMP_FAST_LOOKAHEAD_SIZE {
2203 break;
2204 }
2205
2206 while lookahead_size >= 4 {
2207 let mut cur_match_len = 1;
2208
2209 let first_trigram = d.dict.read_unaligned_u32(cur_pos) & 0xFF_FFFF;
2210
2211 let hash = (first_trigram ^ (first_trigram >> (24 - (LZ_HASH_BITS - 8))))
2212 & LEVEL1_HASH_SIZE_MASK;
2213
2214 let mut probe_pos = usize::from(d.dict.b.hash[hash as usize]);
2215 d.dict.b.hash[hash as usize] = lookahead_pos as u16;
2216
2217 let mut cur_match_dist = (lookahead_pos - probe_pos) as u16;
2218 if cur_match_dist as usize <= d.dict.size {
2219 probe_pos &= LZ_DICT_SIZE_MASK;
2220
2221 let trigram = d.dict.read_unaligned_u32(probe_pos) & 0xFF_FFFF;
2222
2223 if first_trigram == trigram {
2224 let mut p = cur_pos + 3;
2226 let mut q = probe_pos + 3;
2227 cur_match_len = (|| {
2228 for _ in 0..32 {
2229 let p_data: u64 = d.dict.read_unaligned_u64(p);
2230 let q_data: u64 = d.dict.read_unaligned_u64(q);
2231 let xor_data = p_data ^ q_data;
2232 if xor_data == 0 {
2233 p += 8;
2234 q += 8;
2235 } else {
2236 let trailing = xor_data.trailing_zeros();
2237 return p as u32 - cur_pos as u32 + (trailing >> 3);
2238 }
2239 }
2240
2241 if cur_match_dist == 0 {
2242 0
2243 } else {
2244 MAX_MATCH_LEN as u32
2245 }
2246 })();
2247
2248 if cur_match_len < MIN_MATCH_LEN.into()
2249 || (cur_match_len == MIN_MATCH_LEN.into() && cur_match_dist >= 8 * 1024)
2250 {
2251 let lit = first_trigram as u8;
2252 cur_match_len = 1;
2253 d.lz.write_code(lit);
2254 *d.lz.get_flag() >>= 1;
2255 d.huff.count[0][lit as usize] += 1;
2256 } else {
2257 cur_match_len = cmp::min(cur_match_len, lookahead_size as u32);
2260 debug_assert!(cur_match_len >= MIN_MATCH_LEN.into());
2261 debug_assert!(cur_match_len <= MAX_MATCH_LEN as u32);
2262 debug_assert!(cur_match_dist >= 1);
2263 debug_assert!(cur_match_dist as usize <= LZ_DICT_SIZE);
2264 cur_match_dist -= 1;
2265
2266 d.lz.write_code((cur_match_len - u32::from(MIN_MATCH_LEN)) as u8);
2267 d.lz.write_code(cur_match_dist as u8);
2268 d.lz.write_code((cur_match_dist >> 8) as u8);
2269
2270 *d.lz.get_flag() >>= 1;
2271 *d.lz.get_flag() |= 0x80;
2272 if cur_match_dist < 512 {
2273 d.huff.count[1][SMALL_DIST_SYM[cur_match_dist as usize] as usize] += 1;
2274 } else {
2275 d.huff.count[1]
2276 [LARGE_DIST_SYM[(cur_match_dist >> 8) as usize] as usize] += 1;
2277 }
2278
2279 d.huff.count[0][(LEN_SYM
2280 [(cur_match_len - u32::from(MIN_MATCH_LEN)) as usize & 255]
2281 as usize
2282 & 31)
2283 + LEN_SYM_OFFSET] += 1;
2284 }
2285 } else {
2286 d.lz.write_code(first_trigram as u8);
2287 *d.lz.get_flag() >>= 1;
2288 d.huff.count[0][first_trigram as u8 as usize] += 1;
2289 }
2290
2291 d.lz.consume_flag();
2292 d.lz.total_bytes += cur_match_len;
2293 lookahead_pos += cur_match_len as usize;
2294 d.dict.size = cmp::min(d.dict.size + cur_match_len as usize, LZ_DICT_SIZE);
2295 cur_pos = (cur_pos + cur_match_len as usize) & LZ_DICT_SIZE_MASK;
2296 lookahead_size -= cur_match_len as usize;
2297
2298 if d.lz.code_position > LZ_CODE_BUF_SIZE - 8 {
2299 d.dict.lookahead_size = lookahead_size;
2301 d.dict.lookahead_pos = lookahead_pos;
2302
2303 let n = match flush_block(d, callback, TDEFLFlush::None) {
2304 Err(_) => {
2305 d.params.src_pos = src_pos;
2306 d.params.prev_return_status = TDEFLStatus::PutBufFailed;
2307 return false;
2308 }
2309 Ok(status) => status,
2310 };
2311 if n != 0 {
2312 d.params.src_pos = src_pos;
2313 return n > 0;
2314 }
2315 debug_assert!(d.lz.code_position < LZ_CODE_BUF_SIZE - 2);
2316
2317 lookahead_size = d.dict.lookahead_size;
2318 lookahead_pos = d.dict.lookahead_pos;
2319 }
2320 }
2321 }
2322
2323 while lookahead_size != 0 {
2324 let lit = d.dict.b.dict[cur_pos];
2325 d.lz.total_bytes += 1;
2326 d.lz.write_code(lit);
2327 *d.lz.get_flag() >>= 1;
2328 d.lz.consume_flag();
2329
2330 d.huff.count[0][lit as usize] += 1;
2331 lookahead_pos += 1;
2332 d.dict.size = cmp::min(d.dict.size + 1, LZ_DICT_SIZE);
2333 cur_pos = (cur_pos + 1) & LZ_DICT_SIZE_MASK;
2334 lookahead_size -= 1;
2335
2336 if d.lz.code_position > LZ_CODE_BUF_SIZE - 8 {
2337 d.dict.lookahead_size = lookahead_size;
2339 d.dict.lookahead_pos = lookahead_pos;
2340
2341 let n = match flush_block(d, callback, TDEFLFlush::None) {
2342 Err(_) => {
2343 d.params.prev_return_status = TDEFLStatus::PutBufFailed;
2344 d.params.src_pos = src_pos;
2345 return false;
2346 }
2347 Ok(status) => status,
2348 };
2349 if n != 0 {
2350 d.params.src_pos = src_pos;
2351 return n > 0;
2352 }
2353
2354 lookahead_size = d.dict.lookahead_size;
2355 lookahead_pos = d.dict.lookahead_pos;
2356 }
2357 }
2358 }
2359
2360 d.params.src_pos = src_pos;
2361 d.dict.lookahead_size = lookahead_size;
2362 d.dict.lookahead_pos = lookahead_pos;
2363 true
2364}
2365
2366fn flush_output_buffer(c: &mut CallbackOxide, p: &mut ParamsOxide) -> (TDEFLStatus, usize, usize) {
2367 let mut res = (TDEFLStatus::Okay, p.src_pos, 0);
2368 if let CallbackOut::Buf(ref mut cb) = c.out {
2369 let n = cmp::min(cb.out_buf.len() - p.out_buf_ofs, p.flush_remaining as usize);
2370 if n != 0 {
2371 cb.out_buf[p.out_buf_ofs..p.out_buf_ofs + n]
2372 .copy_from_slice(&p.local_buf.b[p.flush_ofs as usize..p.flush_ofs as usize + n]);
2373 }
2374 p.flush_ofs += n as u32;
2375 p.flush_remaining -= n as u32;
2376 p.out_buf_ofs += n;
2377 res.2 = p.out_buf_ofs;
2378 }
2379
2380 if p.finished && p.flush_remaining == 0 {
2381 res.0 = TDEFLStatus::Done
2382 }
2383 res
2384}
2385
2386pub fn compress(
2406 d: &mut CompressorOxide,
2407 in_buf: &[u8],
2408 out_buf: &mut [u8],
2409 flush: TDEFLFlush,
2410) -> (TDEFLStatus, usize, usize) {
2411 compress_inner(
2412 d,
2413 &mut CallbackOxide::new_callback_buf(in_buf, out_buf),
2414 flush,
2415 )
2416}
2417
2418pub fn compress_to_output(
2427 d: &mut CompressorOxide,
2428 in_buf: &[u8],
2429 flush: TDEFLFlush,
2430 mut callback_func: impl FnMut(&[u8]) -> bool,
2431) -> (TDEFLStatus, usize) {
2432 let res = compress_inner(
2433 d,
2434 &mut CallbackOxide::new_callback_func(
2435 in_buf,
2436 CallbackFunc {
2437 put_buf_func: &mut callback_func,
2438 },
2439 ),
2440 flush,
2441 );
2442
2443 (res.0, res.1)
2444}
2445
2446fn compress_inner(
2447 d: &mut CompressorOxide,
2448 callback: &mut CallbackOxide,
2449 flush: TDEFLFlush,
2450) -> (TDEFLStatus, usize, usize) {
2451 d.params.out_buf_ofs = 0;
2452 d.params.src_pos = 0;
2453
2454 let prev_ok = d.params.prev_return_status == TDEFLStatus::Okay;
2455 let flush_finish_once = d.params.flush != TDEFLFlush::Finish || flush == TDEFLFlush::Finish;
2456
2457 d.params.flush = flush;
2458 if !prev_ok || !flush_finish_once {
2459 d.params.prev_return_status = TDEFLStatus::BadParam;
2460 return (d.params.prev_return_status, 0, 0);
2461 }
2462
2463 if d.params.flush_remaining != 0 || d.params.finished {
2464 let res = flush_output_buffer(callback, &mut d.params);
2465 d.params.prev_return_status = res.0;
2466 return res;
2467 }
2468
2469 let one_probe = d.params.flags & MAX_PROBES_MASK == 1;
2470 let greedy = d.params.flags & TDEFL_GREEDY_PARSING_FLAG != 0;
2471 let filter_or_rle = d.params.flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS) != 0;
2472
2473 let raw = d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0;
2474
2475 let compress_success = if raw {
2476 compress_stored(d, callback)
2477 } else if one_probe && greedy && !filter_or_rle {
2478 compress_fast(d, callback)
2479 } else {
2480 compress_normal(d, callback)
2481 };
2482
2483 if !compress_success {
2484 return (
2485 d.params.prev_return_status,
2486 d.params.src_pos,
2487 d.params.out_buf_ofs,
2488 );
2489 }
2490
2491 if let Some(in_buf) = callback.in_buf {
2492 if d.params.flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32) != 0 {
2493 d.params.adler32 = update_adler32(d.params.adler32, &in_buf[..d.params.src_pos]);
2494 }
2495 }
2496
2497 let flush_none = d.params.flush == TDEFLFlush::None;
2498 let in_left = callback.in_buf.map_or(0, |buf| buf.len()) - d.params.src_pos;
2499 let remaining = in_left != 0 || d.params.flush_remaining != 0;
2500 if !flush_none && d.dict.lookahead_size == 0 && !remaining {
2501 let flush = d.params.flush;
2502 match flush_block(d, callback, flush) {
2503 Err(_) => {
2504 d.params.prev_return_status = TDEFLStatus::PutBufFailed;
2505 return (
2506 d.params.prev_return_status,
2507 d.params.src_pos,
2508 d.params.out_buf_ofs,
2509 );
2510 }
2511 Ok(x) if x < 0 => {
2512 return (
2513 d.params.prev_return_status,
2514 d.params.src_pos,
2515 d.params.out_buf_ofs,
2516 )
2517 }
2518 _ => {
2519 d.params.finished = d.params.flush == TDEFLFlush::Finish;
2520 if d.params.flush == TDEFLFlush::Full {
2521 d.dict.b.hash.fill(0);
2522 d.dict.b.next.fill(0);
2523 d.dict.size = 0;
2524 }
2525 }
2526 }
2527 }
2528
2529 let res = flush_output_buffer(callback, &mut d.params);
2530 d.params.prev_return_status = res.0;
2531
2532 res
2533}
2534
2535pub const fn create_comp_flags_from_zip_params(level: i32, window_bits: i32, strategy: i32) -> u32 {
2548 let num_probes = (if level >= 0 {
2549 if level > 10 {
2551 10
2552 } else {
2553 level
2554 }
2555 } else {
2557 CompressionLevel::DefaultLevel as i32
2558 }) as usize;
2559 let greedy = if level <= 3 {
2560 TDEFL_GREEDY_PARSING_FLAG
2561 } else {
2562 0
2563 };
2564 let mut comp_flags = NUM_PROBES[num_probes] as u32 | greedy;
2565
2566 if window_bits > 0 {
2567 comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
2568 }
2569
2570 if level == 0 {
2571 comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
2572 } else if strategy == CompressionStrategy::Filtered as i32 {
2573 comp_flags |= TDEFL_FILTER_MATCHES;
2574 } else if strategy == CompressionStrategy::HuffmanOnly as i32 {
2575 comp_flags &= !MAX_PROBES_MASK;
2576 } else if strategy == CompressionStrategy::Fixed as i32 {
2577 comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
2578 } else if strategy == CompressionStrategy::RLE as i32 {
2579 comp_flags |= TDEFL_RLE_MATCHES;
2580 }
2581
2582 comp_flags
2583}
2584
2585const fn window_bits_from_flags(flags: u32) -> u8 {
2587 if (flags & TDEFL_FORCE_ALL_RAW_BLOCKS & TDEFL_RLE_MATCHES) != 0
2588 || (flags & MAX_PROBES_MASK) == 0
2589 {
2590 1
2591 } else if (flags & MAX_PROBES_MASK) == 1 {
2592 12
2593 } else {
2594 15
2595 }
2596}
2597
2598#[cfg(test)]
2599mod test {
2600 use super::{
2601 compress_to_output, create_comp_flags_from_zip_params, read_u16_le, write_u16_le,
2602 CompressionStrategy, CompressorOxide, TDEFLFlush, TDEFLStatus, DEFAULT_FLAGS,
2603 MZ_DEFAULT_WINDOW_BITS,
2604 };
2605 use crate::inflate::decompress_to_vec;
2606 use alloc::vec;
2607
2608 #[test]
2609 fn u16_to_slice() {
2610 let mut slice = [0, 0];
2611 write_u16_le(2000, &mut slice, 0);
2612 assert_eq!(slice, [208, 7]);
2613 }
2614
2615 #[test]
2616 fn u16_from_slice() {
2617 let slice = [208, 7];
2618 assert_eq!(read_u16_le(&slice, 0), 2000);
2619 }
2620
2621 #[test]
2622 fn compress_output() {
2623 assert_eq!(
2624 DEFAULT_FLAGS,
2625 create_comp_flags_from_zip_params(
2626 4,
2627 MZ_DEFAULT_WINDOW_BITS,
2628 CompressionStrategy::Default as i32
2629 )
2630 );
2631
2632 let slice = [
2633 1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 6, 1, 2, 3, 1, 2, 3, 2, 3, 1, 2, 3,
2634 ];
2635 let mut encoded = vec![];
2636 let flags = create_comp_flags_from_zip_params(6, 0, 0);
2637 let mut d = CompressorOxide::new(flags);
2638 let (status, in_consumed) =
2639 compress_to_output(&mut d, &slice, TDEFLFlush::Finish, |out: &[u8]| {
2640 encoded.extend_from_slice(out);
2641 true
2642 });
2643
2644 assert_eq!(status, TDEFLStatus::Done);
2645 assert_eq!(in_consumed, slice.len());
2646
2647 let decoded = decompress_to_vec(&encoded[..]).unwrap();
2648 assert_eq!(&decoded[..], &slice[..]);
2649 }
2650
2651 #[test]
2652 fn compress_fast() {
2654 let slice = [
2655 1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 6, 1, 2, 3, 1, 2, 3, 2, 3, 1, 2, 3,
2656 ];
2657 let mut encoded = vec![];
2658 let flags = create_comp_flags_from_zip_params(1, 0, 0);
2659 let mut d = CompressorOxide::new(flags);
2660 let (status, in_consumed) =
2661 compress_to_output(&mut d, &slice, TDEFLFlush::Finish, |out: &[u8]| {
2662 encoded.extend_from_slice(out);
2663 true
2664 });
2665
2666 assert_eq!(status, TDEFLStatus::Done);
2667 assert_eq!(in_consumed, slice.len());
2668
2669 assert_eq!(
2671 &encoded[..],
2672 [99, 100, 98, 102, 1, 98, 48, 98, 3, 147, 204, 76, 204, 140, 76, 204, 0]
2673 );
2674
2675 let decoded = decompress_to_vec(&encoded[..]).unwrap();
2676 assert_eq!(&decoded[..], &slice[..]);
2677 }
2678
2679 #[test]
2680 fn zlib_window_bits() {
2681 use super::TDEFL_RLE_MATCHES;
2682 use crate::deflate::CompressionLevel;
2683 use crate::inflate::stream::{inflate, InflateState};
2684 use crate::DataFormat;
2685 use alloc::boxed::Box;
2686 let slice = [
2687 1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 6, 1, 2, 3, 1, 2, 3, 2, 3, 1, 2, 3, 35, 22, 22, 2,
2688 6, 2, 6,
2689 ];
2690 let mut encoded = vec![];
2691
2692 let mut d = CompressorOxide::with_params(
2694 DataFormat::Zlib,
2695 CompressionLevel::DefaultCompression.into(),
2696 CompressionStrategy::Default,
2697 1,
2698 );
2699
2700 assert!((d.params.flags & TDEFL_RLE_MATCHES) != 0);
2701
2702 let (status, in_consumed) =
2703 compress_to_output(&mut d, &slice, TDEFLFlush::Finish, |out: &[u8]| {
2704 encoded.extend_from_slice(out);
2705 true
2706 });
2707
2708 assert_eq!(status, TDEFLStatus::Done);
2709 assert_eq!(in_consumed, slice.len());
2710
2711 let mut output = vec![0; slice.len()];
2712
2713 let mut decompressor = Box::new(InflateState::new(DataFormat::Zlib));
2714
2715 let mut out_slice = output.as_mut_slice();
2716 for i in 0..encoded.len() {
2718 let result = inflate(
2719 &mut decompressor,
2720 &encoded[i..i + 1],
2721 out_slice,
2722 crate::MZFlush::None,
2723 );
2724 out_slice = &mut out_slice[result.bytes_written..];
2725 }
2726 let cmf = decompressor.decompressor().zlib_header().0;
2727 assert_eq!(cmf, 8);
2728 assert_eq!(output, slice)
2729 }
2730}