1use core::{ffi::CStr, marker::PhantomData, mem::MaybeUninit, ops::ControlFlow, ptr::NonNull};
2
3use crate::{
4 adler32::adler32,
5 allocate::Allocator,
6 c_api::{gz_header, internal_state, z_checksum, z_stream},
7 crc32::{crc32, Crc32Fold},
8 trace,
9 weak_slice::{WeakArrayMut, WeakSliceMut},
10 DeflateFlush, ReturnCode, ADLER32_INITIAL_VALUE, CRC32_INITIAL_VALUE, MAX_WBITS, MIN_WBITS,
11};
12
13use self::{
14 algorithm::CONFIGURATION_TABLE,
15 hash_calc::{HashCalcVariant, RollHashCalc, StandardHashCalc},
16 pending::Pending,
17 sym_buf::SymBuf,
18 trees_tbl::STATIC_LTREE,
19 window::Window,
20};
21
22mod algorithm;
23mod compare256;
24mod hash_calc;
25mod longest_match;
26mod pending;
27mod slide_hash;
28mod sym_buf;
29mod trees_tbl;
30mod window;
31
32pub(crate) type Pos = u16;
34
35#[repr(C)]
38pub struct DeflateStream<'a> {
39 pub(crate) next_in: *mut crate::c_api::Bytef,
40 pub(crate) avail_in: crate::c_api::uInt,
41 pub(crate) total_in: crate::c_api::z_size,
42 pub(crate) next_out: *mut crate::c_api::Bytef,
43 pub(crate) avail_out: crate::c_api::uInt,
44 pub(crate) total_out: crate::c_api::z_size,
45 pub(crate) msg: *const core::ffi::c_char,
46 pub(crate) state: &'a mut State<'a>,
47 pub(crate) alloc: Allocator<'a>,
48 pub(crate) data_type: core::ffi::c_int,
49 pub(crate) adler: crate::c_api::z_checksum,
50 pub(crate) reserved: crate::c_api::uLong,
51}
52
53unsafe impl Sync for DeflateStream<'_> {}
54unsafe impl Send for DeflateStream<'_> {}
55
56impl<'a> DeflateStream<'a> {
57 const _S: () = assert!(core::mem::size_of::<z_stream>() == core::mem::size_of::<Self>());
60 const _A: () = assert!(core::mem::align_of::<z_stream>() == core::mem::align_of::<Self>());
61
62 #[inline(always)]
71 pub unsafe fn from_stream_mut(strm: *mut z_stream) -> Option<&'a mut Self> {
72 {
73 let stream = unsafe { strm.as_ref() }?;
75
76 if stream.zalloc.is_none() || stream.zfree.is_none() {
77 return None;
78 }
79
80 if stream.state.is_null() {
81 return None;
82 }
83 }
84
85 unsafe { strm.cast::<DeflateStream>().as_mut() }
87 }
88
89 #[inline(always)]
98 pub unsafe fn from_stream_ref(strm: *const z_stream) -> Option<&'a Self> {
99 {
100 let stream = unsafe { strm.as_ref() }?;
102
103 if stream.zalloc.is_none() || stream.zfree.is_none() {
104 return None;
105 }
106
107 if stream.state.is_null() {
108 return None;
109 }
110 }
111
112 unsafe { strm.cast::<DeflateStream>().as_ref() }
114 }
115
116 fn as_z_stream_mut(&mut self) -> &mut z_stream {
117 unsafe { &mut *(self as *mut DeflateStream as *mut z_stream) }
119 }
120
121 pub fn pending(&self) -> (usize, u8) {
122 (
123 self.state.bit_writer.pending.pending,
124 self.state.bit_writer.bits_valid,
125 )
126 }
127
128 pub fn bits_used(&self) -> u8 {
130 self.state.bit_writer.bits_used
131 }
132
133 pub fn new(config: DeflateConfig) -> Self {
134 let mut inner = crate::c_api::z_stream::default();
135
136 let ret = crate::deflate::init(&mut inner, config);
137 assert_eq!(ret, ReturnCode::Ok);
138
139 unsafe { core::mem::transmute(inner) }
140 }
141}
142
143pub(crate) const HASH_SIZE: usize = 65536;
145const HASH_BITS: usize = 16;
147
148const MAX_MEM_LEVEL: i32 = 9;
150pub const DEF_MEM_LEVEL: i32 = if MAX_MEM_LEVEL > 8 { 8 } else { MAX_MEM_LEVEL };
151
152#[repr(i32)]
153#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
154#[cfg_attr(feature = "__internal-fuzz", derive(arbitrary::Arbitrary))]
155pub enum Method {
156 #[default]
157 Deflated = 8,
158}
159
160impl TryFrom<i32> for Method {
161 type Error = ();
162
163 fn try_from(value: i32) -> Result<Self, Self::Error> {
164 match value {
165 8 => Ok(Self::Deflated),
166 _ => Err(()),
167 }
168 }
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
183#[cfg_attr(feature = "__internal-fuzz", derive(arbitrary::Arbitrary))]
184pub struct DeflateConfig {
185 pub level: i32,
186 pub method: Method,
187 pub window_bits: i32,
188 pub mem_level: i32,
189 pub strategy: Strategy,
190}
191
192#[cfg(any(test, feature = "__internal-test"))]
193impl quickcheck::Arbitrary for DeflateConfig {
194 fn arbitrary(g: &mut quickcheck::Gen) -> Self {
195 let mem_levels: Vec<_> = (1..=9).collect();
196 let levels: Vec<_> = (0..=9).collect();
197
198 let mut window_bits = Vec::new();
199 window_bits.extend(9..=15); window_bits.extend(9 + 16..=15 + 16); window_bits.extend(-15..=-9); Self {
204 level: *g.choose(&levels).unwrap(),
205 method: Method::Deflated,
206 window_bits: *g.choose(&window_bits).unwrap(),
207 mem_level: *g.choose(&mem_levels).unwrap(),
208 strategy: *g
209 .choose(&[
210 Strategy::Default,
211 Strategy::Filtered,
212 Strategy::HuffmanOnly,
213 Strategy::Rle,
214 Strategy::Fixed,
215 ])
216 .unwrap(),
217 }
218 }
219}
220
221impl DeflateConfig {
222 pub fn new(level: i32) -> Self {
223 Self {
224 level,
225 ..Self::default()
226 }
227 }
228
229 pub fn best_compression() -> Self {
231 Self::new(crate::c_api::Z_BEST_COMPRESSION)
232 }
233
234 pub fn best_speed() -> Self {
236 Self::new(crate::c_api::Z_BEST_SPEED)
237 }
238}
239
240impl Default for DeflateConfig {
241 fn default() -> Self {
242 Self {
243 level: crate::c_api::Z_DEFAULT_COMPRESSION,
244 method: Method::Deflated,
245 window_bits: MAX_WBITS,
246 mem_level: DEF_MEM_LEVEL,
247 strategy: Strategy::Default,
248 }
249 }
250}
251
252pub fn init(stream: &mut z_stream, config: DeflateConfig) -> ReturnCode {
253 let DeflateConfig {
254 mut level,
255 method: _,
256 mut window_bits,
257 mem_level,
258 strategy,
259 } = config;
260
261 stream.msg = core::ptr::null_mut();
263
264 #[cfg(feature = "rust-allocator")]
269 if stream.zalloc.is_none() || stream.zfree.is_none() {
270 stream.configure_default_rust_allocator()
271 }
272
273 #[cfg(feature = "c-allocator")]
274 if stream.zalloc.is_none() || stream.zfree.is_none() {
275 stream.configure_default_c_allocator()
276 }
277
278 if stream.zalloc.is_none() || stream.zfree.is_none() {
279 return ReturnCode::StreamError;
280 }
281
282 if level == crate::c_api::Z_DEFAULT_COMPRESSION {
283 level = 6;
284 }
285
286 let wrap = if window_bits < 0 {
287 if window_bits < -MAX_WBITS {
288 return ReturnCode::StreamError;
289 }
290 window_bits = -window_bits;
291
292 0
293 } else if window_bits > MAX_WBITS {
294 window_bits -= 16;
295 2
296 } else {
297 1
298 };
299
300 if (!(1..=MAX_MEM_LEVEL).contains(&mem_level))
301 || !(MIN_WBITS..=MAX_WBITS).contains(&window_bits)
302 || !(0..=9).contains(&level)
303 || (window_bits == 8 && wrap != 1)
304 {
305 return ReturnCode::StreamError;
306 }
307
308 let window_bits = if window_bits == 8 {
309 9 } else {
311 window_bits as usize
312 };
313
314 let alloc = Allocator {
315 zalloc: stream.zalloc.unwrap(),
316 zfree: stream.zfree.unwrap(),
317 opaque: stream.opaque,
318 _marker: PhantomData,
319 };
320
321 let lit_bufsize = 1 << (mem_level + 6); let allocs = DeflateAllocOffsets::new(window_bits, lit_bufsize);
323
324 let Some(allocation_start) = alloc.allocate_slice_raw::<u8>(allocs.total_size) else {
326 return ReturnCode::MemError;
327 };
328
329 let w_size = 1 << window_bits;
330 let align_offset = (allocation_start.as_ptr() as usize).next_multiple_of(64)
331 - (allocation_start.as_ptr() as usize);
332 let buf = unsafe { allocation_start.as_ptr().add(align_offset) };
333
334 let (window, prev, head, pending, sym_buf) = unsafe {
335 let window_ptr: *mut u8 = buf.add(allocs.window_pos);
336 window_ptr.write_bytes(0u8, 2 * w_size);
337 let window = Window::from_raw_parts(window_ptr, window_bits);
338
339 let prev_ptr = buf.add(allocs.prev_pos).cast::<Pos>();
341 prev_ptr.write_bytes(0, w_size);
342 let prev = WeakSliceMut::from_raw_parts_mut(prev_ptr, w_size);
343
344 let head_ptr = buf.add(allocs.head_pos).cast::<[Pos; HASH_SIZE]>();
345 head_ptr.write_bytes(0, 1);
347 let head = WeakArrayMut::<Pos, HASH_SIZE>::from_ptr(head_ptr);
348
349 let pending_ptr = buf.add(allocs.pending_pos).cast::<MaybeUninit<u8>>();
350 let pending = Pending::from_raw_parts(pending_ptr, 4 * lit_bufsize);
351
352 let sym_buf_ptr = buf.add(allocs.sym_buf_pos);
353 let sym_buf = SymBuf::from_raw_parts(sym_buf_ptr, lit_bufsize);
354
355 (window, prev, head, pending, sym_buf)
356 };
357
358 let state = State {
359 status: Status::Init,
360
361 w_size,
363
364 window,
366 prev,
367 head,
368 bit_writer: BitWriter::from_pending(pending),
369
370 lit_bufsize,
372
373 sym_buf,
375
376 level: level as i8, strategy,
379
380 last_flush: 0,
382 wrap,
383 strstart: 0,
384 block_start: 0,
385 block_open: 0,
386 window_size: 0,
387 insert: 0,
388 matches: 0,
389 opt_len: 0,
390 static_len: 0,
391 lookahead: 0,
392 ins_h: 0,
393 max_chain_length: 0,
394 max_lazy_match: 0,
395 good_match: 0,
396 nice_match: 0,
397
398 l_desc: TreeDesc::EMPTY,
400 d_desc: TreeDesc::EMPTY,
401 bl_desc: TreeDesc::EMPTY,
402
403 crc_fold: Crc32Fold::new(),
405 gzhead: None,
406 gzindex: 0,
407
408 match_start: 0,
410 prev_match: 0,
411 match_available: false,
412 prev_length: 0,
413
414 allocation_start,
415 total_allocation_size: allocs.total_size,
416
417 hash_calc_variant: HashCalcVariant::Standard,
419 _cache_line_0: (),
420 _cache_line_1: (),
421 _cache_line_2: (),
422 _cache_line_3: (),
423 _padding_0: [0; 16],
424 };
425
426 let state_allocation = unsafe { buf.add(allocs.state_pos).cast::<State>() };
427 unsafe { state_allocation.write(state) };
428
429 stream.state = state_allocation.cast::<internal_state>();
430
431 let Some(stream) = (unsafe { DeflateStream::from_stream_mut(stream) }) else {
432 if cfg!(debug_assertions) {
433 unreachable!("we should have initialized the stream properly");
434 }
435 return ReturnCode::StreamError;
436 };
437
438 reset(stream)
439}
440
441pub fn params(stream: &mut DeflateStream, level: i32, strategy: Strategy) -> ReturnCode {
442 let level = if level == crate::c_api::Z_DEFAULT_COMPRESSION {
443 6
444 } else {
445 level
446 };
447
448 if !(0..=9).contains(&level) {
449 return ReturnCode::StreamError;
450 }
451
452 let level = level as i8;
453
454 let func = CONFIGURATION_TABLE[stream.state.level as usize].func;
455
456 let state = &mut stream.state;
457
458 #[allow(unpredictable_function_pointer_comparisons)]
461 if (strategy != state.strategy || func != CONFIGURATION_TABLE[level as usize].func)
462 && state.last_flush != -2
463 {
464 let err = deflate(stream, DeflateFlush::Block);
466 if err == ReturnCode::StreamError {
467 return err;
468 }
469
470 let state = &mut stream.state;
471
472 if stream.avail_in != 0
473 || ((state.strstart as isize - state.block_start) + state.lookahead as isize) != 0
474 {
475 return ReturnCode::BufError;
476 }
477 }
478
479 let state = &mut stream.state;
480
481 if state.level != level {
482 if state.level == 0 && state.matches != 0 {
483 if state.matches == 1 {
484 self::slide_hash::slide_hash(state);
485 } else {
486 state.head.as_mut_slice().fill(0);
487 }
488 state.matches = 0;
489 }
490
491 lm_set_level(state, level);
492 }
493
494 state.strategy = strategy;
495
496 ReturnCode::Ok
497}
498
499pub fn set_dictionary(stream: &mut DeflateStream, mut dictionary: &[u8]) -> ReturnCode {
500 let state = &mut stream.state;
501
502 let wrap = state.wrap;
503
504 if wrap == 2 || (wrap == 1 && state.status != Status::Init) || state.lookahead != 0 {
505 return ReturnCode::StreamError;
506 }
507
508 if wrap == 1 {
510 stream.adler = adler32(stream.adler as u32, dictionary) as z_checksum;
511 }
512
513 state.wrap = 0;
515
516 if dictionary.len() >= state.window.capacity() {
518 if wrap == 0 {
519 state.head.as_mut_slice().fill(0);
521
522 state.strstart = 0;
523 state.block_start = 0;
524 state.insert = 0;
525 } else {
526 }
528
529 dictionary = &dictionary[dictionary.len() - state.w_size..];
531 }
532
533 let avail = stream.avail_in;
535 let next = stream.next_in;
536 stream.avail_in = dictionary.len() as _;
537 stream.next_in = dictionary.as_ptr() as *mut u8;
538 fill_window(stream);
539
540 while stream.state.lookahead >= STD_MIN_MATCH {
541 let str = stream.state.strstart;
542 let n = stream.state.lookahead - (STD_MIN_MATCH - 1);
543 stream.state.insert_string(str, n);
544 stream.state.strstart = str + n;
545 stream.state.lookahead = STD_MIN_MATCH - 1;
546 fill_window(stream);
547 }
548
549 let state = &mut stream.state;
550
551 state.strstart += state.lookahead;
552 state.block_start = state.strstart as _;
553 state.insert = state.lookahead;
554 state.lookahead = 0;
555 state.prev_length = 0;
556 state.match_available = false;
557
558 stream.next_in = next;
560 stream.avail_in = avail;
561 state.wrap = wrap;
562
563 ReturnCode::Ok
564}
565
566pub fn prime(stream: &mut DeflateStream, mut bits: i32, value: i32) -> ReturnCode {
567 debug_assert!(bits <= 16, "zlib only supports up to 16 bits here");
569
570 let mut value64 = value as u64;
571
572 let state = &mut stream.state;
573
574 if bits < 0
575 || bits > BitWriter::BIT_BUF_SIZE as i32
576 || bits > (core::mem::size_of_val(&value) << 3) as i32
577 {
578 return ReturnCode::BufError;
579 }
580
581 let mut put;
582
583 loop {
584 put = BitWriter::BIT_BUF_SIZE - state.bit_writer.bits_valid;
585 let put = Ord::min(put as i32, bits);
586
587 if state.bit_writer.bits_valid == 0 {
588 state.bit_writer.bit_buffer = value64;
589 } else {
590 state.bit_writer.bit_buffer |=
591 (value64 & ((1 << put) - 1)) << state.bit_writer.bits_valid;
592 }
593
594 state.bit_writer.bits_valid += put as u8;
595 state.bit_writer.flush_bits();
596 value64 >>= put;
597 bits -= put;
598
599 if bits == 0 {
600 break;
601 }
602 }
603
604 ReturnCode::Ok
605}
606
607pub fn copy<'a>(
608 dest: &mut MaybeUninit<DeflateStream<'a>>,
609 source: &mut DeflateStream<'a>,
610) -> ReturnCode {
611 let w_size = source.state.w_size;
612 let window_bits = source.state.w_bits() as usize;
613 let lit_bufsize = source.state.lit_bufsize;
614
615 unsafe { core::ptr::copy_nonoverlapping(source, dest.as_mut_ptr(), 1) };
618
619 let source_state = &source.state;
620 let alloc = &source.alloc;
621
622 let allocs = DeflateAllocOffsets::new(window_bits, lit_bufsize);
623
624 let Some(allocation_start) = alloc.allocate_slice_raw::<u8>(allocs.total_size) else {
625 return ReturnCode::MemError;
626 };
627
628 let align_offset = (allocation_start.as_ptr() as usize).next_multiple_of(64)
629 - (allocation_start.as_ptr() as usize);
630 let buf = unsafe { allocation_start.as_ptr().add(align_offset) };
631
632 let (window, prev, head, pending, sym_buf) = unsafe {
633 let window_ptr: *mut u8 = buf.add(allocs.window_pos);
634 window_ptr
635 .copy_from_nonoverlapping(source_state.window.as_ptr(), source_state.window.capacity());
636 let window = Window::from_raw_parts(window_ptr, window_bits);
637
638 let prev_ptr = buf.add(allocs.prev_pos).cast::<Pos>();
640 prev_ptr.copy_from_nonoverlapping(source_state.prev.as_ptr(), source_state.prev.len());
641 let prev = WeakSliceMut::from_raw_parts_mut(prev_ptr, w_size);
642
643 let head_ptr = buf.add(allocs.head_pos).cast::<[Pos; HASH_SIZE]>();
645 head_ptr.copy_from_nonoverlapping(source_state.head.as_ptr(), 1);
646 let head = WeakArrayMut::<Pos, HASH_SIZE>::from_ptr(head_ptr);
647
648 let pending_ptr = buf.add(allocs.pending_pos);
649 let pending = source_state.bit_writer.pending.clone_to(pending_ptr);
650
651 let sym_buf_ptr = buf.add(allocs.sym_buf_pos);
652 let sym_buf = source_state.sym_buf.clone_to(sym_buf_ptr);
653
654 (window, prev, head, pending, sym_buf)
655 };
656
657 let mut bit_writer = BitWriter::from_pending(pending);
658 bit_writer.bit_buffer = source_state.bit_writer.bit_buffer;
659 bit_writer.bits_valid = source_state.bit_writer.bits_valid;
660 bit_writer.bits_used = source_state.bit_writer.bits_used;
661
662 let dest_state = State {
663 status: source_state.status,
664 bit_writer,
665 last_flush: source_state.last_flush,
666 wrap: source_state.wrap,
667 strategy: source_state.strategy,
668 level: source_state.level,
669 good_match: source_state.good_match,
670 nice_match: source_state.nice_match,
671 l_desc: source_state.l_desc.clone(),
672 d_desc: source_state.d_desc.clone(),
673 bl_desc: source_state.bl_desc.clone(),
674 prev_match: source_state.prev_match,
675 match_available: source_state.match_available,
676 strstart: source_state.strstart,
677 match_start: source_state.match_start,
678 prev_length: source_state.prev_length,
679 max_chain_length: source_state.max_chain_length,
680 max_lazy_match: source_state.max_lazy_match,
681 block_start: source_state.block_start,
682 block_open: source_state.block_open,
683 window,
684 sym_buf,
685 lit_bufsize: source_state.lit_bufsize,
686 window_size: source_state.window_size,
687 matches: source_state.matches,
688 opt_len: source_state.opt_len,
689 static_len: source_state.static_len,
690 insert: source_state.insert,
691 w_size: source_state.w_size,
692 lookahead: source_state.lookahead,
693 prev,
694 head,
695 ins_h: source_state.ins_h,
696 hash_calc_variant: source_state.hash_calc_variant,
697 crc_fold: source_state.crc_fold,
698 gzhead: None,
699 gzindex: source_state.gzindex,
700 allocation_start,
701 total_allocation_size: allocs.total_size,
702 _cache_line_0: (),
703 _cache_line_1: (),
704 _cache_line_2: (),
705 _cache_line_3: (),
706 _padding_0: source_state._padding_0,
707 };
708
709 let state_allocation = unsafe { buf.add(allocs.state_pos).cast::<State>() };
711 unsafe { state_allocation.write(dest_state) }; let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state) };
715 unsafe { core::ptr::write(field_ptr as *mut *mut State, state_allocation) };
716
717 let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state.gzhead) };
719 unsafe { core::ptr::copy(&source_state.gzhead, field_ptr, 1) };
720
721 ReturnCode::Ok
722}
723
724pub fn end<'a>(stream: &'a mut DeflateStream) -> Result<&'a mut z_stream, &'a mut z_stream> {
729 let status = stream.state.status;
730 let allocation_start = stream.state.allocation_start;
731 let total_allocation_size = stream.state.total_allocation_size;
732 let alloc = stream.alloc;
733
734 let stream = stream.as_z_stream_mut();
735 let _ = core::mem::replace(&mut stream.state, core::ptr::null_mut());
736
737 unsafe { alloc.deallocate(allocation_start.as_ptr(), total_allocation_size) };
738
739 match status {
740 Status::Busy => Err(stream),
741 _ => Ok(stream),
742 }
743}
744
745pub fn reset(stream: &mut DeflateStream) -> ReturnCode {
746 let ret = reset_keep(stream);
747
748 if ret == ReturnCode::Ok {
749 lm_init(stream.state);
750 }
751
752 ret
753}
754
755pub fn reset_keep(stream: &mut DeflateStream) -> ReturnCode {
756 stream.total_in = 0;
757 stream.total_out = 0;
758 stream.msg = core::ptr::null_mut();
759 stream.data_type = crate::c_api::Z_UNKNOWN;
760
761 let state = &mut stream.state;
762
763 state.bit_writer.pending.reset_keep();
764
765 state.wrap = state.wrap.abs();
767
768 state.status = match state.wrap {
769 2 => Status::GZip,
770 _ => Status::Init,
771 };
772
773 stream.adler = match state.wrap {
774 2 => {
775 state.crc_fold = Crc32Fold::new();
776 CRC32_INITIAL_VALUE as _
777 }
778 _ => ADLER32_INITIAL_VALUE as _,
779 };
780
781 state.last_flush = -2;
782
783 state.zng_tr_init();
784
785 ReturnCode::Ok
786}
787
788fn lm_init(state: &mut State) {
789 state.window_size = 2 * state.w_size;
790
791 state.head.as_mut_slice().fill(0);
793
794 lm_set_level(state, state.level);
796
797 state.strstart = 0;
798 state.block_start = 0;
799 state.lookahead = 0;
800 state.insert = 0;
801 state.prev_length = 0;
802 state.match_available = false;
803 state.match_start = 0;
804 state.ins_h = 0;
805}
806
807fn lm_set_level(state: &mut State, level: i8) {
808 state.max_lazy_match = CONFIGURATION_TABLE[level as usize].max_lazy;
809 state.good_match = CONFIGURATION_TABLE[level as usize].good_length;
810 state.nice_match = CONFIGURATION_TABLE[level as usize].nice_length;
811 state.max_chain_length = CONFIGURATION_TABLE[level as usize].max_chain;
812
813 state.hash_calc_variant = HashCalcVariant::for_max_chain_length(state.max_chain_length);
814 state.level = level;
815}
816
817pub fn tune(
818 stream: &mut DeflateStream,
819 good_length: usize,
820 max_lazy: usize,
821 nice_length: usize,
822 max_chain: usize,
823) -> ReturnCode {
824 stream.state.good_match = good_length as u16;
825 stream.state.max_lazy_match = max_lazy as u16;
826 stream.state.nice_match = nice_length as u16;
827 stream.state.max_chain_length = max_chain as u16;
828
829 ReturnCode::Ok
830}
831
832#[repr(C)]
833#[derive(Debug, Clone, Copy, PartialEq, Eq)]
834pub(crate) struct Value {
835 a: u16,
836 b: u16,
837}
838
839impl Value {
840 pub(crate) const fn new(a: u16, b: u16) -> Self {
841 Self { a, b }
842 }
843
844 pub(crate) fn freq_mut(&mut self) -> &mut u16 {
845 &mut self.a
846 }
847
848 pub(crate) fn code_mut(&mut self) -> &mut u16 {
849 &mut self.a
850 }
851
852 pub(crate) fn dad_mut(&mut self) -> &mut u16 {
853 &mut self.b
854 }
855
856 pub(crate) fn len_mut(&mut self) -> &mut u16 {
857 &mut self.b
858 }
859
860 #[inline(always)]
861 pub(crate) const fn freq(self) -> u16 {
862 self.a
863 }
864
865 #[inline(always)]
866 pub(crate) const fn code(self) -> u16 {
867 self.a
868 }
869
870 #[inline(always)]
871 pub(crate) const fn dad(self) -> u16 {
872 self.b
873 }
874
875 #[inline(always)]
876 pub(crate) const fn len(self) -> u16 {
877 self.b
878 }
879}
880
881pub(crate) const LENGTH_CODES: usize = 29;
883
884const LITERALS: usize = 256;
886
887pub(crate) const L_CODES: usize = LITERALS + 1 + LENGTH_CODES;
889
890pub(crate) const D_CODES: usize = 30;
892
893const BL_CODES: usize = 19;
895
896const HEAP_SIZE: usize = 2 * L_CODES + 1;
898
899const MAX_BITS: usize = 15;
901
902const MAX_BL_BITS: usize = 7;
904
905pub(crate) const DIST_CODE_LEN: usize = 512;
906
907struct BitWriter<'a> {
908 pub(crate) pending: Pending<'a>, pub(crate) bit_buffer: u64,
912
913 pub(crate) bits_valid: u8,
915
916 pub(crate) bits_used: u8,
918
919 #[cfg(feature = "ZLIB_DEBUG")]
921 compressed_len: usize,
922 #[cfg(feature = "ZLIB_DEBUG")]
924 bits_sent: usize,
925}
926
927#[inline]
928const fn encode_len(ltree: &[Value], lc: u8) -> (u64, usize) {
929 let mut lc = lc as usize;
930
931 let code = self::trees_tbl::LENGTH_CODE[lc] as usize;
933 let c = code + LITERALS + 1;
934 assert!(c < L_CODES, "bad l_code");
935 let lnode = ltree[c];
938 let mut match_bits: u64 = lnode.code() as u64;
939 let mut match_bits_len = lnode.len() as usize;
940 let extra = StaticTreeDesc::EXTRA_LBITS[code] as usize;
941 if extra != 0 {
942 lc -= self::trees_tbl::BASE_LENGTH[code] as usize;
943 match_bits |= (lc as u64) << match_bits_len;
944 match_bits_len += extra;
945 }
946
947 (match_bits, match_bits_len)
948}
949
950#[inline]
951const fn encode_dist(dtree: &[Value], mut dist: u16) -> (u64, usize) {
952 dist -= 1; let code = State::d_code(dist as usize) as usize;
954 assert!(code < D_CODES, "bad d_code");
955 let dnode = dtree[code];
959 let mut match_bits = dnode.code() as u64;
960 let mut match_bits_len = dnode.len() as usize;
961 let extra = StaticTreeDesc::EXTRA_DBITS[code] as usize;
962 if extra != 0 {
963 dist -= self::trees_tbl::BASE_DIST[code];
964 match_bits |= (dist as u64) << match_bits_len;
965 match_bits_len += extra;
966 }
967
968 (match_bits, match_bits_len)
969}
970
971impl<'a> BitWriter<'a> {
972 pub(crate) const BIT_BUF_SIZE: u8 = 64;
973
974 fn from_pending(pending: Pending<'a>) -> Self {
975 Self {
976 pending,
977 bit_buffer: 0,
978 bits_valid: 0,
979 bits_used: 0,
980
981 #[cfg(feature = "ZLIB_DEBUG")]
982 compressed_len: 0,
983 #[cfg(feature = "ZLIB_DEBUG")]
984 bits_sent: 0,
985 }
986 }
987
988 fn flush_bits(&mut self) {
989 debug_assert!(self.bits_valid <= 64);
990 let removed = self.bits_valid.saturating_sub(7).next_multiple_of(8);
991 let keep_bytes = self.bits_valid / 8; let src = &self.bit_buffer.to_le_bytes();
994 self.pending.extend(&src[..keep_bytes as usize]);
995
996 self.bits_valid -= removed;
997 self.bit_buffer = self.bit_buffer.checked_shr(removed as u32).unwrap_or(0);
998 }
999
1000 fn emit_align(&mut self) {
1001 debug_assert!(self.bits_valid <= 64);
1002 let keep_bytes = self.bits_valid.div_ceil(8);
1003 let src = &self.bit_buffer.to_le_bytes();
1004 self.pending.extend(&src[..keep_bytes as usize]);
1005
1006 self.bits_used = match self.bits_valid {
1007 0 => 8,
1008 _ => ((self.bits_valid - 1) & 7) + 1,
1009 };
1010 self.bit_buffer = 0;
1011 self.bits_valid = 0;
1012
1013 self.sent_bits_align();
1014 }
1015
1016 fn send_bits_trace(&self, _value: u64, _len: u8) {
1017 trace!(" l {:>2} v {:>4x} ", _len, _value);
1018 }
1019
1020 fn cmpr_bits_add(&mut self, _len: usize) {
1021 #[cfg(feature = "ZLIB_DEBUG")]
1022 {
1023 self.compressed_len += _len;
1024 }
1025 }
1026
1027 fn cmpr_bits_align(&mut self) {
1028 #[cfg(feature = "ZLIB_DEBUG")]
1029 {
1030 self.compressed_len = self.compressed_len.next_multiple_of(8);
1031 }
1032 }
1033
1034 fn sent_bits_add(&mut self, _len: usize) {
1035 #[cfg(feature = "ZLIB_DEBUG")]
1036 {
1037 self.bits_sent += _len;
1038 }
1039 }
1040
1041 fn sent_bits_align(&mut self) {
1042 #[cfg(feature = "ZLIB_DEBUG")]
1043 {
1044 self.bits_sent = self.bits_sent.next_multiple_of(8);
1045 }
1046 }
1047
1048 #[inline(always)]
1049 fn send_bits(&mut self, val: u64, len: u8) {
1050 debug_assert!(len <= 64);
1051 debug_assert!(self.bits_valid <= 64);
1052
1053 let total_bits = len + self.bits_valid;
1054
1055 self.send_bits_trace(val, len);
1056 self.sent_bits_add(len as usize);
1057
1058 if total_bits < Self::BIT_BUF_SIZE {
1059 self.bit_buffer |= val << self.bits_valid;
1060 self.bits_valid = total_bits;
1061 } else {
1062 self.send_bits_overflow(val, total_bits);
1063 }
1064 }
1065
1066 fn send_bits_overflow(&mut self, val: u64, total_bits: u8) {
1067 if self.bits_valid == Self::BIT_BUF_SIZE {
1068 self.pending.extend(&self.bit_buffer.to_le_bytes());
1069 self.bit_buffer = val;
1070 self.bits_valid = total_bits - Self::BIT_BUF_SIZE;
1071 } else {
1072 self.bit_buffer |= val << self.bits_valid;
1073 self.pending.extend(&self.bit_buffer.to_le_bytes());
1074 self.bit_buffer = val >> (Self::BIT_BUF_SIZE - self.bits_valid);
1075 self.bits_valid = total_bits - Self::BIT_BUF_SIZE;
1076 }
1077 }
1078
1079 fn send_code(&mut self, code: usize, tree: &[Value]) {
1080 let node = tree[code];
1081 self.send_bits(node.code() as u64, node.len() as u8)
1082 }
1083
1084 pub fn align(&mut self) {
1087 self.emit_tree(BlockType::StaticTrees, false);
1088 self.emit_end_block(&STATIC_LTREE, false);
1089 self.flush_bits();
1090 }
1091
1092 pub(crate) fn emit_tree(&mut self, block_type: BlockType, is_last_block: bool) {
1093 let header_bits = ((block_type as u64) << 1) | (is_last_block as u64);
1094 self.send_bits(header_bits, 3);
1095 trace!("\n--- Emit Tree: Last: {}\n", is_last_block as u8);
1096 }
1097
1098 pub(crate) fn emit_end_block_and_align(&mut self, ltree: &[Value], is_last_block: bool) {
1099 self.emit_end_block(ltree, is_last_block);
1100
1101 if is_last_block {
1102 self.emit_align();
1103 }
1104 }
1105
1106 fn emit_end_block(&mut self, ltree: &[Value], _is_last_block: bool) {
1107 const END_BLOCK: usize = 256;
1108 self.send_code(END_BLOCK, ltree);
1109
1110 trace!(
1111 "\n+++ Emit End Block: Last: {} Pending: {} Total Out: {}\n",
1112 _is_last_block as u8,
1113 self.pending.pending().len(),
1114 "<unknown>"
1115 );
1116 }
1117
1118 pub(crate) fn emit_lit(&mut self, ltree: &[Value], c: u8) -> u16 {
1119 self.send_code(c as usize, ltree);
1120
1121 #[cfg(feature = "ZLIB_DEBUG")]
1122 if let Some(c) = char::from_u32(c as u32) {
1123 if isgraph(c as u8) {
1124 trace!(" '{}' ", c);
1125 }
1126 }
1127
1128 ltree[c as usize].len()
1129 }
1130
1131 pub(crate) fn emit_dist(
1132 &mut self,
1133 ltree: &[Value],
1134 dtree: &[Value],
1135 lc: u8,
1136 dist: u16,
1137 ) -> usize {
1138 let (mut match_bits, mut match_bits_len) = encode_len(ltree, lc);
1139
1140 let (dist_match_bits, dist_match_bits_len) = encode_dist(dtree, dist);
1141
1142 match_bits |= dist_match_bits << match_bits_len;
1143 match_bits_len += dist_match_bits_len;
1144
1145 self.send_bits(match_bits, match_bits_len as u8);
1146
1147 match_bits_len
1148 }
1149
1150 pub(crate) fn emit_dist_static(&mut self, lc: u8, dist: u16) -> usize {
1151 let precomputed_len = trees_tbl::STATIC_LTREE_ENCODINGS[lc as usize];
1152 let mut match_bits = precomputed_len.code() as u64;
1153 let mut match_bits_len = precomputed_len.len() as usize;
1154
1155 let dtree = self::trees_tbl::STATIC_DTREE.as_slice();
1156 let (dist_match_bits, dist_match_bits_len) = encode_dist(dtree, dist);
1157
1158 match_bits |= dist_match_bits << match_bits_len;
1159 match_bits_len += dist_match_bits_len;
1160
1161 self.send_bits(match_bits, match_bits_len as u8);
1162
1163 match_bits_len
1164 }
1165
1166 fn compress_block_help(&mut self, sym_buf: &SymBuf, ltree: &[Value], dtree: &[Value]) {
1167 for (dist, lc) in sym_buf.iter() {
1168 match dist {
1169 0 => self.emit_lit(ltree, lc) as usize,
1170 _ => self.emit_dist(ltree, dtree, lc, dist),
1171 };
1172 }
1173
1174 self.emit_end_block(ltree, false)
1175 }
1176
1177 fn send_tree(&mut self, tree: &[Value], bl_tree: &[Value], max_code: usize) {
1178 let mut prevlen: isize = -1; let mut curlen; let mut nextlen = tree[0].len(); let mut count = 0; let mut max_count = 7; let mut min_count = 4; if nextlen == 0 {
1190 max_count = 138;
1191 min_count = 3;
1192 }
1193
1194 for n in 0..=max_code {
1195 curlen = nextlen;
1196 nextlen = tree[n + 1].len();
1197 count += 1;
1198 if count < max_count && curlen == nextlen {
1199 continue;
1200 } else if count < min_count {
1201 loop {
1202 self.send_code(curlen as usize, bl_tree);
1203
1204 count -= 1;
1205 if count == 0 {
1206 break;
1207 }
1208 }
1209 } else if curlen != 0 {
1210 if curlen as isize != prevlen {
1211 self.send_code(curlen as usize, bl_tree);
1212 count -= 1;
1213 }
1214 assert!((3..=6).contains(&count), " 3_6?");
1215 self.send_code(REP_3_6, bl_tree);
1216 self.send_bits(count - 3, 2);
1217 } else if count <= 10 {
1218 self.send_code(REPZ_3_10, bl_tree);
1219 self.send_bits(count - 3, 3);
1220 } else {
1221 self.send_code(REPZ_11_138, bl_tree);
1222 self.send_bits(count - 11, 7);
1223 }
1224
1225 count = 0;
1226 prevlen = curlen as isize;
1227
1228 if nextlen == 0 {
1229 max_count = 138;
1230 min_count = 3;
1231 } else if curlen == nextlen {
1232 max_count = 6;
1233 min_count = 3;
1234 } else {
1235 max_count = 7;
1236 min_count = 4;
1237 }
1238 }
1239 }
1240}
1241
1242#[repr(C, align(64))]
1243pub(crate) struct State<'a> {
1244 status: Status,
1245
1246 last_flush: i8, pub(crate) wrap: i8, pub(crate) strategy: Strategy,
1251 pub(crate) level: i8,
1252
1253 pub(crate) block_open: u8,
1257
1258 pub(crate) hash_calc_variant: HashCalcVariant,
1259
1260 pub(crate) match_available: bool, pub(crate) good_match: u16,
1264
1265 pub(crate) nice_match: u16,
1267
1268 pub(crate) match_start: Pos, pub(crate) prev_match: Pos, pub(crate) strstart: usize, pub(crate) window: Window<'a>,
1273 pub(crate) w_size: usize, pub(crate) lookahead: usize, _cache_line_0: (),
1278
1279 pub(crate) prev: WeakSliceMut<'a, u16>,
1285 pub(crate) head: WeakArrayMut<'a, u16, HASH_SIZE>,
1288
1289 pub(crate) prev_length: u16,
1292
1293 pub(crate) max_chain_length: u16,
1296
1297 pub(crate) max_lazy_match: u16,
1307
1308 pub(crate) matches: u8,
1313
1314 pub(crate) block_start: isize,
1317
1318 pub(crate) sym_buf: SymBuf<'a>,
1319
1320 _cache_line_1: (),
1321
1322 lit_bufsize: usize,
1340
1341 pub(crate) window_size: usize,
1343
1344 bit_writer: BitWriter<'a>,
1345
1346 _cache_line_2: (),
1347
1348 opt_len: usize,
1350 static_len: usize,
1352
1353 pub(crate) insert: usize,
1355
1356 pub(crate) ins_h: u32,
1358
1359 gzhead: Option<&'a mut gz_header>,
1360 gzindex: usize,
1361
1362 _padding_0: [u8; 16],
1363
1364 _cache_line_3: (),
1365
1366 crc_fold: crate::crc32::Crc32Fold,
1367
1368 allocation_start: NonNull<u8>,
1370 total_allocation_size: usize,
1372
1373 l_desc: TreeDesc<HEAP_SIZE>, d_desc: TreeDesc<{ 2 * D_CODES + 1 }>, bl_desc: TreeDesc<{ 2 * BL_CODES + 1 }>, }
1377
1378#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
1379#[cfg_attr(feature = "__internal-fuzz", derive(arbitrary::Arbitrary))]
1380pub enum Strategy {
1381 #[default]
1382 Default = 0,
1383 Filtered = 1,
1384 HuffmanOnly = 2,
1385 Rle = 3,
1386 Fixed = 4,
1387}
1388
1389impl TryFrom<i32> for Strategy {
1390 type Error = ();
1391
1392 fn try_from(value: i32) -> Result<Self, Self::Error> {
1393 match value {
1394 0 => Ok(Strategy::Default),
1395 1 => Ok(Strategy::Filtered),
1396 2 => Ok(Strategy::HuffmanOnly),
1397 3 => Ok(Strategy::Rle),
1398 4 => Ok(Strategy::Fixed),
1399 _ => Err(()),
1400 }
1401 }
1402}
1403
1404#[derive(Debug, PartialEq, Eq)]
1405enum DataType {
1406 Binary = 0,
1407 Text = 1,
1408 Unknown = 2,
1409}
1410
1411impl<'a> State<'a> {
1412 pub const BIT_BUF_SIZE: u8 = BitWriter::BIT_BUF_SIZE;
1413
1414 pub(crate) fn w_bits(&self) -> u32 {
1416 self.w_size.trailing_zeros()
1417 }
1418
1419 pub(crate) fn w_mask(&self) -> usize {
1420 self.w_size - 1
1421 }
1422
1423 pub(crate) fn max_dist(&self) -> usize {
1424 self.w_size - MIN_LOOKAHEAD
1425 }
1426
1427 pub(crate) fn max_insert_length(&self) -> usize {
1430 self.max_lazy_match as usize
1431 }
1432
1433 pub(crate) fn pending_buf_size(&self) -> usize {
1436 self.lit_bufsize * 4
1437 }
1438
1439 #[inline(always)]
1440 pub(crate) fn update_hash(&self, h: u32, val: u32) -> u32 {
1441 match self.hash_calc_variant {
1442 HashCalcVariant::Standard => StandardHashCalc::update_hash(h, val),
1443 HashCalcVariant::Roll => RollHashCalc::update_hash(h, val),
1444 }
1445 }
1446
1447 #[inline(always)]
1448 pub(crate) fn quick_insert_string(&mut self, string: usize) -> u16 {
1449 match self.hash_calc_variant {
1450 HashCalcVariant::Standard => StandardHashCalc::quick_insert_string(self, string),
1451 HashCalcVariant::Roll => RollHashCalc::quick_insert_string(self, string),
1452 }
1453 }
1454
1455 #[inline(always)]
1456 pub(crate) fn insert_string(&mut self, string: usize, count: usize) {
1457 match self.hash_calc_variant {
1458 HashCalcVariant::Standard => StandardHashCalc::insert_string(self, string, count),
1459 HashCalcVariant::Roll => RollHashCalc::insert_string(self, string, count),
1460 }
1461 }
1462
1463 #[inline(always)]
1464 pub(crate) fn tally_lit(&mut self, unmatched: u8) -> bool {
1465 Self::tally_lit_help(&mut self.sym_buf, &mut self.l_desc, unmatched)
1466 }
1467
1468 pub(crate) fn tally_lit_help(
1470 sym_buf: &mut SymBuf,
1471 l_desc: &mut TreeDesc<HEAP_SIZE>,
1472 unmatched: u8,
1473 ) -> bool {
1474 const _VERIFY: () = {
1475 assert!(
1478 u8::MAX as usize <= STD_MAX_MATCH - STD_MIN_MATCH,
1479 "tally_lit: bad literal"
1480 );
1481 };
1482
1483 sym_buf.push_lit(unmatched);
1484
1485 *l_desc.dyn_tree[unmatched as usize].freq_mut() += 1;
1486
1487 sym_buf.should_flush_block()
1489 }
1490
1491 const fn d_code(dist: usize) -> u8 {
1492 const _VERIFY: () = {
1493 let mut i = 0;
1495 while i < trees_tbl::DIST_CODE.len() {
1496 assert!(trees_tbl::DIST_CODE[i] < D_CODES as u8);
1497 i += 1;
1498 }
1499 };
1500
1501 let index = if dist < 256 { dist } else { 256 + (dist >> 7) };
1502 self::trees_tbl::DIST_CODE[index]
1503 }
1504
1505 #[inline(always)]
1506 pub(crate) fn tally_dist(&mut self, mut dist: usize, len: usize) -> bool {
1507 self.sym_buf.push_dist(dist as u16, len as u8);
1508
1509 self.matches = self.matches.saturating_add(1);
1510 dist -= 1;
1511
1512 assert!(dist < self.max_dist(), "tally_dist: bad match");
1513
1514 let index = self::trees_tbl::LENGTH_CODE[len] as usize + LITERALS + 1;
1515 *self.l_desc.dyn_tree[index].freq_mut() += 1;
1516
1517 *self.d_desc.dyn_tree[Self::d_code(dist) as usize].freq_mut() += 1;
1518
1519 self.sym_buf.should_flush_block()
1521 }
1522
1523 fn detect_data_type(dyn_tree: &[Value]) -> DataType {
1524 const NON_TEXT: u64 = 0xf3ffc07f;
1527 let mut mask = NON_TEXT;
1528
1529 for value in &dyn_tree[0..32] {
1531 if (mask & 1) != 0 && value.freq() != 0 {
1532 return DataType::Binary;
1533 }
1534
1535 mask >>= 1;
1536 }
1537
1538 if dyn_tree[9].freq() != 0 || dyn_tree[10].freq() != 0 || dyn_tree[13].freq() != 0 {
1540 return DataType::Text;
1541 }
1542
1543 if dyn_tree[32..LITERALS].iter().any(|v| v.freq() != 0) {
1544 return DataType::Text;
1545 }
1546
1547 DataType::Binary
1550 }
1551
1552 fn compress_block_static_trees(&mut self) {
1553 let ltree = self::trees_tbl::STATIC_LTREE.as_slice();
1554 for (dist, lc) in self.sym_buf.iter() {
1555 match dist {
1556 0 => self.bit_writer.emit_lit(ltree, lc) as usize,
1557 _ => self.bit_writer.emit_dist_static(lc, dist),
1558 };
1559 }
1560
1561 self.bit_writer.emit_end_block(ltree, false)
1562 }
1563
1564 fn compress_block_dynamic_trees(&mut self) {
1565 self.bit_writer.compress_block_help(
1566 &self.sym_buf,
1567 &self.l_desc.dyn_tree,
1568 &self.d_desc.dyn_tree,
1569 );
1570 }
1571
1572 fn header(&self) -> u16 {
1573 const PRESET_DICT: u16 = 0x20;
1575
1576 const Z_DEFLATED: u16 = 8;
1578
1579 let dict = match self.strstart {
1580 0 => 0,
1581 _ => PRESET_DICT,
1582 };
1583
1584 let h = ((Z_DEFLATED + ((self.w_bits() as u16 - 8) << 4)) << 8)
1585 | (self.level_flags() << 6)
1586 | dict;
1587
1588 h + 31 - (h % 31)
1589 }
1590
1591 fn level_flags(&self) -> u16 {
1592 if self.strategy >= Strategy::HuffmanOnly || self.level < 2 {
1593 0
1594 } else if self.level < 6 {
1595 1
1596 } else if self.level == 6 {
1597 2
1598 } else {
1599 3
1600 }
1601 }
1602
1603 fn zng_tr_init(&mut self) {
1604 self.l_desc.stat_desc = &StaticTreeDesc::L;
1605
1606 self.d_desc.stat_desc = &StaticTreeDesc::D;
1607
1608 self.bl_desc.stat_desc = &StaticTreeDesc::BL;
1609
1610 self.bit_writer.bit_buffer = 0;
1611 self.bit_writer.bits_valid = 0;
1612 self.bit_writer.bits_used = 0;
1613
1614 #[cfg(feature = "ZLIB_DEBUG")]
1615 {
1616 self.bit_writer.compressed_len = 0;
1617 self.bit_writer.bits_sent = 0;
1618 }
1619
1620 self.init_block();
1622 }
1623
1624 fn init_block(&mut self) {
1626 for value in &mut self.l_desc.dyn_tree[..L_CODES] {
1630 *value.freq_mut() = 0;
1631 }
1632
1633 for value in &mut self.d_desc.dyn_tree[..D_CODES] {
1634 *value.freq_mut() = 0;
1635 }
1636
1637 for value in &mut self.bl_desc.dyn_tree[..BL_CODES] {
1638 *value.freq_mut() = 0;
1639 }
1640
1641 const END_BLOCK: usize = 256;
1643
1644 *self.l_desc.dyn_tree[END_BLOCK].freq_mut() = 1;
1645 self.opt_len = 0;
1646 self.static_len = 0;
1647 self.sym_buf.clear();
1648 self.matches = 0;
1649 }
1650}
1651
1652#[repr(u8)]
1653#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1654enum Status {
1655 Init = 1,
1656
1657 GZip = 4,
1658 Extra = 5,
1659 Name = 6,
1660 Comment = 7,
1661 Hcrc = 8,
1662
1663 Busy = 2,
1664 Finish = 3,
1665}
1666
1667const fn rank_flush(f: i8) -> i8 {
1668 ((f) * 2) - (if (f) > 4 { 9 } else { 0 })
1670}
1671
1672#[derive(Debug)]
1673pub(crate) enum BlockState {
1674 NeedMore = 0,
1676 BlockDone = 1,
1678 FinishStarted = 2,
1680 FinishDone = 3,
1682}
1683
1684pub(crate) const MAX_STORED: usize = 65535; pub(crate) fn read_buf_window(stream: &mut DeflateStream, offset: usize, size: usize) -> usize {
1688 let len = Ord::min(stream.avail_in as usize, size);
1689
1690 if len == 0 {
1691 return 0;
1692 }
1693
1694 stream.avail_in -= len as u32;
1695
1696 if stream.state.wrap == 2 {
1697 let window = &mut stream.state.window;
1700 unsafe { window.copy_and_initialize(offset..offset + len, stream.next_in) };
1702
1703 let data = &stream.state.window.filled()[offset..][..len];
1704 stream.state.crc_fold.fold(data, CRC32_INITIAL_VALUE);
1705 } else if stream.state.wrap == 1 {
1706 let window = &mut stream.state.window;
1709 unsafe { window.copy_and_initialize(offset..offset + len, stream.next_in) };
1711
1712 let data = &stream.state.window.filled()[offset..][..len];
1713 stream.adler = adler32(stream.adler as u32, data) as _;
1714 } else {
1715 let window = &mut stream.state.window;
1716 unsafe { window.copy_and_initialize(offset..offset + len, stream.next_in) };
1718 }
1719
1720 stream.next_in = stream.next_in.wrapping_add(len);
1723 stream.total_in = stream.total_in.wrapping_add(len as crate::c_api::z_size);
1724
1725 len
1726}
1727
1728pub(crate) enum BlockType {
1729 StoredBlock = 0,
1730 StaticTrees = 1,
1731 DynamicTrees = 2,
1732}
1733
1734pub(crate) fn zng_tr_stored_block(
1735 state: &mut State,
1736 window_range: core::ops::Range<usize>,
1737 is_last: bool,
1738) {
1739 state.bit_writer.emit_tree(BlockType::StoredBlock, is_last);
1741
1742 state.bit_writer.emit_align();
1744
1745 state.bit_writer.cmpr_bits_align();
1746
1747 let input_block: &[u8] = &state.window.filled()[window_range];
1748 let stored_len = input_block.len() as u16;
1749
1750 state.bit_writer.pending.extend(&stored_len.to_le_bytes());
1751 state
1752 .bit_writer
1753 .pending
1754 .extend(&(!stored_len).to_le_bytes());
1755
1756 state.bit_writer.cmpr_bits_add(32);
1757 state.bit_writer.sent_bits_add(32);
1758 if stored_len > 0 {
1759 state.bit_writer.pending.extend(input_block);
1760 state.bit_writer.cmpr_bits_add((stored_len << 3) as usize);
1761 state.bit_writer.sent_bits_add((stored_len << 3) as usize);
1762 }
1763}
1764
1765pub(crate) const STD_MIN_MATCH: usize = 3;
1767pub(crate) const STD_MAX_MATCH: usize = 258;
1769
1770pub(crate) const WANT_MIN_MATCH: usize = 4;
1772
1773pub(crate) const MIN_LOOKAHEAD: usize = STD_MAX_MATCH + STD_MIN_MATCH + 1;
1774
1775#[inline]
1776pub(crate) fn fill_window(stream: &mut DeflateStream) {
1777 debug_assert!(stream.state.lookahead < MIN_LOOKAHEAD);
1778
1779 let wsize = stream.state.w_size;
1780
1781 loop {
1782 let state = &mut *stream.state;
1783 let mut more = state.window_size - state.lookahead - state.strstart;
1784
1785 if state.strstart >= wsize + state.max_dist() {
1788 let (old, new) = state.window.filled_mut()[..2 * wsize].split_at_mut(wsize);
1790 old.copy_from_slice(new);
1791
1792 if state.match_start >= wsize as u16 {
1793 state.match_start -= wsize as u16;
1794 } else {
1795 state.match_start = 0;
1796 state.prev_length = 0;
1797 }
1798
1799 state.strstart -= wsize; state.block_start = state.block_start.wrapping_sub_unsigned(wsize);
1801 state.insert = Ord::min(state.insert, state.strstart);
1802
1803 self::slide_hash::slide_hash(state);
1804
1805 more += wsize;
1806 }
1807
1808 if stream.avail_in == 0 {
1809 break;
1810 }
1811
1812 assert!(more >= 2, "more < 2");
1823
1824 let n = read_buf_window(stream, stream.state.strstart + stream.state.lookahead, more);
1825
1826 let state = &mut *stream.state;
1827 state.lookahead += n;
1828
1829 if state.lookahead + state.insert >= STD_MIN_MATCH {
1831 let string = state.strstart - state.insert;
1832 if state.max_chain_length > 1024 {
1833 let v0 = state.window.filled()[string] as u32;
1834 let v1 = state.window.filled()[string + 1] as u32;
1835 state.ins_h = state.update_hash(v0, v1);
1836 } else if string >= 1 {
1837 state.quick_insert_string(string + 2 - STD_MIN_MATCH);
1838 }
1839 let mut count = state.insert;
1840 if state.lookahead == 1 {
1841 count -= 1;
1842 }
1843 if count > 0 {
1844 state.insert_string(string, count);
1845 state.insert -= count;
1846 }
1847 }
1848
1849 if !(stream.state.lookahead < MIN_LOOKAHEAD && stream.avail_in != 0) {
1853 break;
1854 }
1855 }
1856
1857 assert!(
1858 stream.state.strstart <= stream.state.window_size - MIN_LOOKAHEAD,
1859 "not enough room for search"
1860 );
1861}
1862
1863pub(crate) struct StaticTreeDesc {
1864 pub(crate) static_tree: &'static [Value],
1866 extra_bits: &'static [u8],
1868 extra_base: usize,
1870 elems: usize,
1872 max_length: u16,
1874}
1875
1876impl StaticTreeDesc {
1877 const EMPTY: Self = Self {
1878 static_tree: &[],
1879 extra_bits: &[],
1880 extra_base: 0,
1881 elems: 0,
1882 max_length: 0,
1883 };
1884
1885 const EXTRA_LBITS: [u8; LENGTH_CODES] = [
1887 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0,
1888 ];
1889
1890 const EXTRA_DBITS: [u8; D_CODES] = [
1892 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12,
1893 13, 13,
1894 ];
1895
1896 const EXTRA_BLBITS: [u8; BL_CODES] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7];
1898
1899 const BL_ORDER: [u8; BL_CODES] = [
1902 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
1903 ];
1904
1905 pub(crate) const L: Self = Self {
1906 static_tree: &self::trees_tbl::STATIC_LTREE,
1907 extra_bits: &Self::EXTRA_LBITS,
1908 extra_base: LITERALS + 1,
1909 elems: L_CODES,
1910 max_length: MAX_BITS as u16,
1911 };
1912
1913 pub(crate) const D: Self = Self {
1914 static_tree: &self::trees_tbl::STATIC_DTREE,
1915 extra_bits: &Self::EXTRA_DBITS,
1916 extra_base: 0,
1917 elems: D_CODES,
1918 max_length: MAX_BITS as u16,
1919 };
1920
1921 pub(crate) const BL: Self = Self {
1922 static_tree: &[],
1923 extra_bits: &Self::EXTRA_BLBITS,
1924 extra_base: 0,
1925 elems: BL_CODES,
1926 max_length: MAX_BL_BITS as u16,
1927 };
1928}
1929
1930#[derive(Clone)]
1931pub(crate) struct TreeDesc<const N: usize> {
1932 dyn_tree: [Value; N],
1933 max_code: usize,
1934 stat_desc: &'static StaticTreeDesc,
1935}
1936
1937impl<const N: usize> TreeDesc<N> {
1938 const EMPTY: Self = Self {
1939 dyn_tree: [Value::new(0, 0); N],
1940 max_code: 0,
1941 stat_desc: &StaticTreeDesc::EMPTY,
1942 };
1943}
1944
1945fn build_tree<const N: usize>(state: &mut State, desc: &mut TreeDesc<N>) {
1946 let tree = &mut desc.dyn_tree;
1947 let stree = desc.stat_desc.static_tree;
1948 let elements = desc.stat_desc.elems;
1949
1950 let mut heap = Heap::new();
1951 let mut max_code = heap.initialize(&mut tree[..elements]);
1952
1953 while heap.heap_len < 2 {
1958 heap.heap_len += 1;
1959 let node = if max_code < 2 {
1960 max_code += 1;
1961 max_code
1962 } else {
1963 0
1964 };
1965
1966 debug_assert!(node >= 0);
1967 let node = node as usize;
1968
1969 heap.heap[heap.heap_len] = node as u32;
1970 *tree[node].freq_mut() = 1;
1971 heap.depth[node] = 0;
1972 state.opt_len -= 1;
1973 if !stree.is_empty() {
1974 state.static_len -= stree[node].len() as usize;
1975 }
1976 }
1978
1979 debug_assert!(max_code >= 0);
1980 let max_code = max_code as usize;
1981 desc.max_code = max_code;
1982
1983 let mut n = heap.heap_len / 2;
1986 while n >= 1 {
1987 heap.pqdownheap(tree, n);
1988 n -= 1;
1989 }
1990
1991 heap.construct_huffman_tree(tree, elements);
1992
1993 let bl_count = gen_bitlen(state, &mut heap, desc);
1996
1997 gen_codes(&mut desc.dyn_tree, max_code, &bl_count);
1999}
2000
2001fn gen_bitlen<const N: usize>(
2002 state: &mut State,
2003 heap: &mut Heap,
2004 desc: &mut TreeDesc<N>,
2005) -> [u16; MAX_BITS + 1] {
2006 let tree = &mut desc.dyn_tree;
2007 let max_code = desc.max_code;
2008 let stree = desc.stat_desc.static_tree;
2009 let extra = desc.stat_desc.extra_bits;
2010 let base = desc.stat_desc.extra_base;
2011 let max_length = desc.stat_desc.max_length;
2012
2013 let mut bl_count = [0u16; MAX_BITS + 1];
2014
2015 *tree[heap.heap[heap.heap_max] as usize].len_mut() = 0; let mut overflow: i32 = 0;
2021
2022 for h in heap.heap_max + 1..HEAP_SIZE {
2023 let n = heap.heap[h] as usize;
2024 let mut bits = tree[tree[n].dad() as usize].len() + 1;
2025
2026 if bits > max_length {
2027 bits = max_length;
2028 overflow += 1;
2029 }
2030
2031 *tree[n].len_mut() = bits;
2033
2034 if n > max_code {
2036 continue;
2037 }
2038
2039 bl_count[bits as usize] += 1;
2040 let mut xbits = 0;
2041 if n >= base {
2042 xbits = extra[n - base] as usize;
2043 }
2044
2045 let f = tree[n].freq() as usize;
2046 state.opt_len += f * (bits as usize + xbits);
2047
2048 if !stree.is_empty() {
2049 state.static_len += f * (stree[n].len() as usize + xbits);
2050 }
2051 }
2052
2053 if overflow == 0 {
2054 return bl_count;
2055 }
2056
2057 loop {
2059 let mut bits = max_length as usize - 1;
2060 while bl_count[bits] == 0 {
2061 bits -= 1;
2062 }
2063 bl_count[bits] -= 1; bl_count[bits + 1] += 2; bl_count[max_length as usize] -= 1;
2066 overflow -= 2;
2070
2071 if overflow <= 0 {
2072 break;
2073 }
2074 }
2075
2076 let mut h = HEAP_SIZE;
2081 for bits in (1..=max_length).rev() {
2082 let mut n = bl_count[bits as usize];
2083 while n != 0 {
2084 h -= 1;
2085 let m = heap.heap[h] as usize;
2086 if m > max_code {
2087 continue;
2088 }
2089
2090 if tree[m].len() != bits {
2091 state.opt_len += (bits * tree[m].freq()) as usize;
2093 state.opt_len -= (tree[m].len() * tree[m].freq()) as usize;
2094 *tree[m].len_mut() = bits;
2095 }
2096
2097 n -= 1;
2098 }
2099 }
2100 bl_count
2101}
2102
2103#[allow(unused)]
2105fn isgraph(c: u8) -> bool {
2106 (c > 0x20) && (c <= 0x7E)
2107}
2108
2109fn gen_codes(tree: &mut [Value], max_code: usize, bl_count: &[u16]) {
2110 let mut next_code = [0; MAX_BITS + 1]; let mut code = 0; for bits in 1..=MAX_BITS {
2120 code = (code + bl_count[bits - 1]) << 1;
2121 next_code[bits] = code;
2122 }
2123
2124 assert!(
2128 code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,
2129 "inconsistent bit counts"
2130 );
2131
2132 trace!("\ngen_codes: max_code {max_code} ");
2133
2134 for n in 0..=max_code {
2135 let len = tree[n].len();
2136 if len == 0 {
2137 continue;
2138 }
2139
2140 assert!((1..=15).contains(&len), "code length must be 1-15");
2142 *tree[n].code_mut() = next_code[len as usize].reverse_bits() >> (16 - len);
2143 next_code[len as usize] += 1;
2144
2145 if tree != self::trees_tbl::STATIC_LTREE.as_slice() {
2146 trace!(
2147 "\nn {:>3} {} l {:>2} c {:>4x} ({:x}) ",
2148 n,
2149 if isgraph(n as u8) {
2150 char::from_u32(n as u32).unwrap()
2151 } else {
2152 ' '
2153 },
2154 len,
2155 tree[n].code(),
2156 next_code[len as usize] - 1
2157 );
2158 }
2159 }
2160}
2161
2162const REP_3_6: usize = 16;
2164
2165const REPZ_3_10: usize = 17;
2167
2168const REPZ_11_138: usize = 18;
2170
2171fn scan_tree(bl_desc: &mut TreeDesc<{ 2 * BL_CODES + 1 }>, tree: &mut [Value], max_code: usize) {
2172 let mut prevlen = -1isize; let mut curlen: isize; let mut nextlen = tree[0].len(); let mut count = 0; let mut max_count = 7; let mut min_count = 4; if nextlen == 0 {
2182 max_count = 138;
2183 min_count = 3;
2184 }
2185
2186 *tree[max_code + 1].len_mut() = 0xffff; let bl_tree = &mut bl_desc.dyn_tree;
2189
2190 for n in 0..=max_code {
2191 curlen = nextlen as isize;
2192 nextlen = tree[n + 1].len();
2193 count += 1;
2194 if count < max_count && curlen == nextlen as isize {
2195 continue;
2196 } else if count < min_count {
2197 *bl_tree[curlen as usize].freq_mut() += count;
2198 } else if curlen != 0 {
2199 if curlen != prevlen {
2200 *bl_tree[curlen as usize].freq_mut() += 1;
2201 }
2202 *bl_tree[REP_3_6].freq_mut() += 1;
2203 } else if count <= 10 {
2204 *bl_tree[REPZ_3_10].freq_mut() += 1;
2205 } else {
2206 *bl_tree[REPZ_11_138].freq_mut() += 1;
2207 }
2208
2209 count = 0;
2210 prevlen = curlen;
2211
2212 if nextlen == 0 {
2213 max_count = 138;
2214 min_count = 3;
2215 } else if curlen == nextlen as isize {
2216 max_count = 6;
2217 min_count = 3;
2218 } else {
2219 max_count = 7;
2220 min_count = 4;
2221 }
2222 }
2223}
2224
2225fn send_all_trees(state: &mut State, lcodes: usize, dcodes: usize, blcodes: usize) {
2226 assert!(
2227 lcodes >= 257 && dcodes >= 1 && blcodes >= 4,
2228 "not enough codes"
2229 );
2230 assert!(
2231 lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
2232 "too many codes"
2233 );
2234
2235 trace!("\nbl counts: ");
2236 state.bit_writer.send_bits(lcodes as u64 - 257, 5); state.bit_writer.send_bits(dcodes as u64 - 1, 5);
2238 state.bit_writer.send_bits(blcodes as u64 - 4, 4); for rank in 0..blcodes {
2241 trace!("\nbl code {:>2} ", StaticTreeDesc::BL_ORDER[rank]);
2242 state.bit_writer.send_bits(
2243 state.bl_desc.dyn_tree[StaticTreeDesc::BL_ORDER[rank] as usize].len() as u64,
2244 3,
2245 );
2246 }
2247 trace!("\nbl tree: sent {}", state.bit_writer.bits_sent);
2248
2249 state
2251 .bit_writer
2252 .send_tree(&state.l_desc.dyn_tree, &state.bl_desc.dyn_tree, lcodes - 1);
2253 trace!("\nlit tree: sent {}", state.bit_writer.bits_sent);
2254
2255 state
2257 .bit_writer
2258 .send_tree(&state.d_desc.dyn_tree, &state.bl_desc.dyn_tree, dcodes - 1);
2259 trace!("\ndist tree: sent {}", state.bit_writer.bits_sent);
2260}
2261
2262fn build_bl_tree(state: &mut State) -> usize {
2265 scan_tree(
2268 &mut state.bl_desc,
2269 &mut state.l_desc.dyn_tree,
2270 state.l_desc.max_code,
2271 );
2272
2273 scan_tree(
2274 &mut state.bl_desc,
2275 &mut state.d_desc.dyn_tree,
2276 state.d_desc.max_code,
2277 );
2278
2279 {
2281 let mut tmp = TreeDesc::EMPTY;
2282 core::mem::swap(&mut tmp, &mut state.bl_desc);
2283 build_tree(state, &mut tmp);
2284 core::mem::swap(&mut tmp, &mut state.bl_desc);
2285 }
2286
2287 let mut max_blindex = BL_CODES - 1;
2296 while max_blindex >= 3 {
2297 let index = StaticTreeDesc::BL_ORDER[max_blindex] as usize;
2298 if state.bl_desc.dyn_tree[index].len() != 0 {
2299 break;
2300 }
2301
2302 max_blindex -= 1;
2303 }
2304
2305 state.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
2307 trace!(
2308 "\ndyn trees: dyn {}, stat {}",
2309 state.opt_len,
2310 state.static_len
2311 );
2312
2313 max_blindex
2314}
2315
2316fn zng_tr_flush_block(
2317 stream: &mut DeflateStream,
2318 window_offset: Option<usize>,
2319 stored_len: u32,
2320 last: bool,
2321) {
2322 let mut opt_lenb;
2327 let static_lenb;
2328 let mut max_blindex = 0;
2329
2330 let state = &mut stream.state;
2331
2332 if state.sym_buf.is_empty() {
2333 opt_lenb = 0;
2334 static_lenb = 0;
2335 state.static_len = 7;
2336 } else if state.level > 0 {
2337 if stream.data_type == DataType::Unknown as i32 {
2338 stream.data_type = State::detect_data_type(&state.l_desc.dyn_tree) as i32;
2339 }
2340
2341 {
2342 let mut tmp = TreeDesc::EMPTY;
2343 core::mem::swap(&mut tmp, &mut state.l_desc);
2344
2345 build_tree(state, &mut tmp);
2346 core::mem::swap(&mut tmp, &mut state.l_desc);
2347
2348 trace!(
2349 "\nlit data: dyn {}, stat {}",
2350 state.opt_len,
2351 state.static_len
2352 );
2353 }
2354
2355 {
2356 let mut tmp = TreeDesc::EMPTY;
2357 core::mem::swap(&mut tmp, &mut state.d_desc);
2358 build_tree(state, &mut tmp);
2359 core::mem::swap(&mut tmp, &mut state.d_desc);
2360
2361 trace!(
2362 "\ndist data: dyn {}, stat {}",
2363 state.opt_len,
2364 state.static_len
2365 );
2366 }
2367
2368 max_blindex = build_bl_tree(state);
2371
2372 opt_lenb = (state.opt_len + 3 + 7) >> 3;
2374 static_lenb = (state.static_len + 3 + 7) >> 3;
2375
2376 trace!(
2377 "\nopt {}({}) stat {}({}) stored {} lit {} ",
2378 opt_lenb,
2379 state.opt_len,
2380 static_lenb,
2381 state.static_len,
2382 stored_len,
2383 state.sym_buf.iter().count()
2384 );
2385
2386 if static_lenb <= opt_lenb || state.strategy == Strategy::Fixed {
2387 opt_lenb = static_lenb;
2388 }
2389 } else {
2390 assert!(window_offset.is_some(), "lost buf");
2391 opt_lenb = stored_len as usize + 5;
2393 static_lenb = stored_len as usize + 5;
2394 }
2395
2396 #[allow(clippy::unnecessary_unwrap)]
2397 if stored_len as usize + 4 <= opt_lenb && window_offset.is_some() {
2398 let window_offset = window_offset.unwrap();
2406 let range = window_offset..window_offset + stored_len as usize;
2407 zng_tr_stored_block(state, range, last);
2408 } else if static_lenb == opt_lenb {
2409 state.bit_writer.emit_tree(BlockType::StaticTrees, last);
2410 state.compress_block_static_trees();
2411 } else {
2413 state.bit_writer.emit_tree(BlockType::DynamicTrees, last);
2414 send_all_trees(
2415 state,
2416 state.l_desc.max_code + 1,
2417 state.d_desc.max_code + 1,
2418 max_blindex + 1,
2419 );
2420
2421 state.compress_block_dynamic_trees();
2422 }
2423
2424 state.init_block();
2429 if last {
2430 state.bit_writer.emit_align();
2431 }
2432
2433 }
2435
2436pub(crate) fn flush_block_only(stream: &mut DeflateStream, is_last: bool) {
2437 zng_tr_flush_block(
2438 stream,
2439 (stream.state.block_start >= 0).then_some(stream.state.block_start as usize),
2440 (stream.state.strstart as isize - stream.state.block_start) as u32,
2441 is_last,
2442 );
2443
2444 stream.state.block_start = stream.state.strstart as isize;
2445 flush_pending(stream)
2446}
2447
2448fn flush_bytes(stream: &mut DeflateStream, mut bytes: &[u8]) -> ControlFlow<ReturnCode> {
2449 let mut state = &mut stream.state;
2450
2451 let mut beg = state.bit_writer.pending.pending().len(); while state.bit_writer.pending.remaining() < bytes.len() {
2455 let copy = state.bit_writer.pending.remaining();
2456
2457 state.bit_writer.pending.extend(&bytes[..copy]);
2458
2459 stream.adler = crc32(
2460 stream.adler as u32,
2461 &state.bit_writer.pending.pending()[beg..],
2462 ) as z_checksum;
2463
2464 state.gzindex += copy;
2465 flush_pending(stream);
2466 state = &mut stream.state;
2467
2468 if !state.bit_writer.pending.pending().is_empty() {
2470 state.last_flush = -1;
2471 return ControlFlow::Break(ReturnCode::Ok);
2472 }
2473
2474 beg = 0;
2475 bytes = &bytes[copy..];
2476 }
2477
2478 state.bit_writer.pending.extend(bytes);
2479
2480 stream.adler = crc32(
2481 stream.adler as u32,
2482 &state.bit_writer.pending.pending()[beg..],
2483 ) as z_checksum;
2484 state.gzindex = 0;
2485
2486 ControlFlow::Continue(())
2487}
2488
2489pub fn deflate(stream: &mut DeflateStream, flush: DeflateFlush) -> ReturnCode {
2490 if stream.next_out.is_null()
2491 || (stream.avail_in != 0 && stream.next_in.is_null())
2492 || (stream.state.status == Status::Finish && flush != DeflateFlush::Finish)
2493 {
2494 let err = ReturnCode::StreamError;
2495 stream.msg = err.error_message();
2496 return err;
2497 }
2498
2499 if stream.avail_out == 0 {
2500 let err = ReturnCode::BufError;
2501 stream.msg = err.error_message();
2502 return err;
2503 }
2504
2505 let old_flush = stream.state.last_flush;
2506 stream.state.last_flush = flush as i8;
2507
2508 if !stream.state.bit_writer.pending.pending().is_empty() {
2510 flush_pending(stream);
2511 if stream.avail_out == 0 {
2512 stream.state.last_flush = -1;
2519 return ReturnCode::Ok;
2520 }
2521
2522 } else if stream.avail_in == 0
2527 && rank_flush(flush as i8) <= rank_flush(old_flush)
2528 && flush != DeflateFlush::Finish
2529 {
2530 let err = ReturnCode::BufError;
2531 stream.msg = err.error_message();
2532 return err;
2533 }
2534
2535 if stream.state.status == Status::Finish && stream.avail_in != 0 {
2537 let err = ReturnCode::BufError;
2538 stream.msg = err.error_message();
2539 return err;
2540 }
2541
2542 if stream.state.status == Status::Init && stream.state.wrap == 0 {
2544 stream.state.status = Status::Busy;
2545 }
2546
2547 if stream.state.status == Status::Init {
2548 let header = stream.state.header();
2549 stream
2550 .state
2551 .bit_writer
2552 .pending
2553 .extend(&header.to_be_bytes());
2554
2555 if stream.state.strstart != 0 {
2557 let adler = stream.adler as u32;
2558 stream.state.bit_writer.pending.extend(&adler.to_be_bytes());
2559 }
2560
2561 stream.adler = ADLER32_INITIAL_VALUE as _;
2562 stream.state.status = Status::Busy;
2563
2564 flush_pending(stream);
2566
2567 if !stream.state.bit_writer.pending.pending().is_empty() {
2568 stream.state.last_flush = -1;
2569
2570 return ReturnCode::Ok;
2571 }
2572 }
2573
2574 if stream.state.status == Status::GZip {
2575 stream.state.crc_fold = Crc32Fold::new();
2577
2578 stream.state.bit_writer.pending.extend(&[31, 139, 8]);
2579
2580 let extra_flags = if stream.state.level == 9 {
2581 2
2582 } else if stream.state.strategy >= Strategy::HuffmanOnly || stream.state.level < 2 {
2583 4
2584 } else {
2585 0
2586 };
2587
2588 match &stream.state.gzhead {
2589 None => {
2590 let bytes = [0, 0, 0, 0, 0, extra_flags, gz_header::OS_CODE];
2591 stream.state.bit_writer.pending.extend(&bytes);
2592 stream.state.status = Status::Busy;
2593
2594 flush_pending(stream);
2596 if !stream.state.bit_writer.pending.pending().is_empty() {
2597 stream.state.last_flush = -1;
2598 return ReturnCode::Ok;
2599 }
2600 }
2601 Some(gzhead) => {
2602 stream.state.bit_writer.pending.extend(&[gzhead.flags()]);
2603 let bytes = (gzhead.time as u32).to_le_bytes();
2604 stream.state.bit_writer.pending.extend(&bytes);
2605 stream
2606 .state
2607 .bit_writer
2608 .pending
2609 .extend(&[extra_flags, gzhead.os as u8]);
2610
2611 if !gzhead.extra.is_null() {
2612 let bytes = (gzhead.extra_len as u16).to_le_bytes();
2613 stream.state.bit_writer.pending.extend(&bytes);
2614 }
2615
2616 if gzhead.hcrc != 0 {
2617 stream.adler = crc32(
2618 stream.adler as u32,
2619 stream.state.bit_writer.pending.pending(),
2620 ) as z_checksum
2621 }
2622
2623 stream.state.gzindex = 0;
2624 stream.state.status = Status::Extra;
2625 }
2626 }
2627 }
2628
2629 if stream.state.status == Status::Extra {
2630 if let Some(gzhead) = stream.state.gzhead.as_ref() {
2631 if !gzhead.extra.is_null() {
2632 let gzhead_extra = gzhead.extra;
2633
2634 let extra = unsafe {
2635 core::slice::from_raw_parts(
2636 gzhead_extra.add(stream.state.gzindex),
2639 (gzhead.extra_len & 0xffff) as usize - stream.state.gzindex,
2640 )
2641 };
2642
2643 if let ControlFlow::Break(err) = flush_bytes(stream, extra) {
2644 return err;
2645 }
2646 }
2647 }
2648 stream.state.status = Status::Name;
2649 }
2650
2651 if stream.state.status == Status::Name {
2652 if let Some(gzhead) = stream.state.gzhead.as_ref() {
2653 if !gzhead.name.is_null() {
2654 let gzhead_name = unsafe { CStr::from_ptr(gzhead.name.cast()) };
2656 let bytes = gzhead_name.to_bytes_with_nul();
2657 if let ControlFlow::Break(err) = flush_bytes(stream, bytes) {
2658 return err;
2659 }
2660 }
2661 stream.state.status = Status::Comment;
2662 }
2663 }
2664
2665 if stream.state.status == Status::Comment {
2666 if let Some(gzhead) = stream.state.gzhead.as_ref() {
2667 if !gzhead.comment.is_null() {
2668 let gzhead_comment = unsafe { CStr::from_ptr(gzhead.comment.cast()) };
2670 let bytes = gzhead_comment.to_bytes_with_nul();
2671 if let ControlFlow::Break(err) = flush_bytes(stream, bytes) {
2672 return err;
2673 }
2674 }
2675 stream.state.status = Status::Hcrc;
2676 }
2677 }
2678
2679 if stream.state.status == Status::Hcrc {
2680 if let Some(gzhead) = stream.state.gzhead.as_ref() {
2681 if gzhead.hcrc != 0 {
2682 let bytes = (stream.adler as u16).to_le_bytes();
2683 if let ControlFlow::Break(err) = flush_bytes(stream, &bytes) {
2684 return err;
2685 }
2686 }
2687 }
2688
2689 stream.state.status = Status::Busy;
2690
2691 flush_pending(stream);
2693 if !stream.state.bit_writer.pending.pending().is_empty() {
2694 stream.state.last_flush = -1;
2695 return ReturnCode::Ok;
2696 }
2697 }
2698
2699 let state = &mut stream.state;
2701 if stream.avail_in != 0
2702 || state.lookahead != 0
2703 || (flush != DeflateFlush::NoFlush && state.status != Status::Finish)
2704 {
2705 let bstate = self::algorithm::run(stream, flush);
2706
2707 let state = &mut stream.state;
2708
2709 if matches!(bstate, BlockState::FinishStarted | BlockState::FinishDone) {
2710 state.status = Status::Finish;
2711 }
2712
2713 match bstate {
2714 BlockState::NeedMore | BlockState::FinishStarted => {
2715 if stream.avail_out == 0 {
2716 state.last_flush = -1; }
2718 return ReturnCode::Ok;
2719 }
2727 BlockState::BlockDone => {
2728 match flush {
2729 DeflateFlush::NoFlush => unreachable!("condition of inner surrounding if"),
2730 DeflateFlush::PartialFlush => {
2731 state.bit_writer.align();
2732 }
2733 DeflateFlush::SyncFlush => {
2734 zng_tr_stored_block(state, 0..0, false);
2738 }
2739 DeflateFlush::FullFlush => {
2740 zng_tr_stored_block(state, 0..0, false);
2744
2745 state.head.as_mut_slice().fill(0); if state.lookahead == 0 {
2748 state.strstart = 0;
2749 state.block_start = 0;
2750 state.insert = 0;
2751 }
2752 }
2753 DeflateFlush::Block => { }
2754 DeflateFlush::Finish => unreachable!("condition of outer surrounding if"),
2755 }
2756
2757 flush_pending(stream);
2758
2759 if stream.avail_out == 0 {
2760 stream.state.last_flush = -1; return ReturnCode::Ok;
2762 }
2763 }
2764 BlockState::FinishDone => { }
2765 }
2766 }
2767
2768 if flush != DeflateFlush::Finish {
2769 return ReturnCode::Ok;
2770 }
2771
2772 if stream.state.wrap == 2 {
2774 let crc_fold = core::mem::take(&mut stream.state.crc_fold);
2775 stream.adler = crc_fold.finish() as z_checksum;
2776
2777 let adler = stream.adler as u32;
2778 stream.state.bit_writer.pending.extend(&adler.to_le_bytes());
2779
2780 let total_in = stream.total_in as u32;
2781 stream
2782 .state
2783 .bit_writer
2784 .pending
2785 .extend(&total_in.to_le_bytes());
2786 } else if stream.state.wrap == 1 {
2787 let adler = stream.adler as u32;
2788 stream.state.bit_writer.pending.extend(&adler.to_be_bytes());
2789 }
2790
2791 flush_pending(stream);
2792
2793 if stream.state.wrap > 0 {
2795 stream.state.wrap = -stream.state.wrap; }
2797
2798 if stream.state.bit_writer.pending.pending().is_empty() {
2799 assert_eq!(stream.state.bit_writer.bits_valid, 0, "bi_buf not flushed");
2800 return ReturnCode::StreamEnd;
2801 }
2802 ReturnCode::Ok
2803}
2804
2805pub(crate) fn flush_pending(stream: &mut DeflateStream) {
2806 let state = &mut stream.state;
2807
2808 state.bit_writer.flush_bits();
2809
2810 let pending = state.bit_writer.pending.pending();
2811 let len = Ord::min(pending.len(), stream.avail_out as usize);
2812
2813 if len == 0 {
2814 return;
2815 }
2816
2817 trace!("\n[FLUSH {len} bytes]");
2818 unsafe { core::ptr::copy_nonoverlapping(pending.as_ptr(), stream.next_out, len) };
2820
2821 stream.next_out = stream.next_out.wrapping_add(len);
2822 stream.total_out += len as crate::c_api::z_size;
2823 stream.avail_out -= len as crate::c_api::uInt;
2824
2825 state.bit_writer.pending.advance(len);
2826}
2827
2828pub fn compress_slice<'a>(
2846 output: &'a mut [u8],
2847 input: &[u8],
2848 config: DeflateConfig,
2849) -> (&'a mut [u8], ReturnCode) {
2850 let output_uninit = unsafe {
2852 core::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut MaybeUninit<u8>, output.len())
2853 };
2854
2855 compress(output_uninit, input, config)
2856}
2857
2858pub fn compress<'a>(
2859 output: &'a mut [MaybeUninit<u8>],
2860 input: &[u8],
2861 config: DeflateConfig,
2862) -> (&'a mut [u8], ReturnCode) {
2863 compress_with_flush(output, input, config, DeflateFlush::Finish)
2864}
2865
2866pub fn compress_slice_with_flush<'a>(
2867 output: &'a mut [u8],
2868 input: &[u8],
2869 config: DeflateConfig,
2870 flush: DeflateFlush,
2871) -> (&'a mut [u8], ReturnCode) {
2872 let output_uninit = unsafe {
2874 core::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut MaybeUninit<u8>, output.len())
2875 };
2876
2877 compress_with_flush(output_uninit, input, config, flush)
2878}
2879
2880pub fn compress_with_flush<'a>(
2881 output: &'a mut [MaybeUninit<u8>],
2882 input: &[u8],
2883 config: DeflateConfig,
2884 final_flush: DeflateFlush,
2885) -> (&'a mut [u8], ReturnCode) {
2886 let mut stream = z_stream {
2887 next_in: input.as_ptr() as *mut u8,
2888 avail_in: 0, total_in: 0,
2890 next_out: output.as_mut_ptr() as *mut u8,
2891 avail_out: 0, total_out: 0,
2893 msg: core::ptr::null_mut(),
2894 state: core::ptr::null_mut(),
2895 zalloc: None,
2896 zfree: None,
2897 opaque: core::ptr::null_mut(),
2898 data_type: 0,
2899 adler: 0,
2900 reserved: 0,
2901 };
2902
2903 let err = init(&mut stream, config);
2904 if err != ReturnCode::Ok {
2905 return (&mut [], err);
2906 }
2907
2908 let max = core::ffi::c_uint::MAX as usize;
2909
2910 let mut left = output.len();
2911 let mut source_len = input.len();
2912
2913 let return_code = loop {
2914 if stream.avail_out == 0 {
2915 stream.avail_out = Ord::min(left, max) as _;
2916 left -= stream.avail_out as usize;
2917 }
2918
2919 if stream.avail_in == 0 {
2920 stream.avail_in = Ord::min(source_len, max) as _;
2921 source_len -= stream.avail_in as usize;
2922 }
2923
2924 let flush = if source_len > 0 {
2925 DeflateFlush::NoFlush
2926 } else {
2927 final_flush
2928 };
2929
2930 let err = if let Some(stream) = unsafe { DeflateStream::from_stream_mut(&mut stream) } {
2931 deflate(stream, flush)
2932 } else {
2933 ReturnCode::StreamError
2934 };
2935
2936 match err {
2937 ReturnCode::Ok => continue,
2938 ReturnCode::StreamEnd => break ReturnCode::Ok,
2939 _ => break err,
2940 }
2941 };
2942
2943 let output_slice = unsafe {
2945 core::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut u8, stream.total_out as usize)
2946 };
2947
2948 if let Some(stream) = unsafe { DeflateStream::from_stream_mut(&mut stream) } {
2950 let _ = end(stream);
2951 }
2952
2953 (output_slice, return_code)
2954}
2955
2956pub const fn compress_bound(source_len: usize) -> usize {
2976 compress_bound_help(source_len, ZLIB_WRAPLEN)
2977}
2978
2979const fn compress_bound_help(source_len: usize, wrap_len: usize) -> usize {
2980 source_len .wrapping_add(if source_len == 0 { 1 } else { 0 })
2983 .wrapping_add(if source_len < 9 { 1 } else { 0 })
2985 .wrapping_add(deflate_quick_overhead(source_len))
2987 .wrapping_add(DEFLATE_BLOCK_OVERHEAD)
2989 .wrapping_add(wrap_len)
2991}
2992
2993#[derive(Clone)]
2998struct Heap {
2999 heap: [u32; 2 * L_CODES + 1],
3000
3001 heap_len: usize,
3003
3004 heap_max: usize,
3006
3007 depth: [u8; 2 * L_CODES + 1],
3008}
3009
3010impl Heap {
3011 fn new() -> Self {
3013 Self {
3014 heap: [0; 2 * L_CODES + 1],
3015 heap_len: 0,
3016 heap_max: 0,
3017 depth: [0; 2 * L_CODES + 1],
3018 }
3019 }
3020
3021 fn initialize(&mut self, tree: &mut [Value]) -> isize {
3024 let mut max_code = -1;
3025
3026 self.heap_len = 0;
3027 self.heap_max = HEAP_SIZE;
3028
3029 for (n, node) in tree.iter_mut().enumerate() {
3030 if node.freq() > 0 {
3031 self.heap_len += 1;
3032 self.heap[self.heap_len] = n as u32;
3033 max_code = n as isize;
3034 self.depth[n] = 0;
3035 } else {
3036 *node.len_mut() = 0;
3037 }
3038 }
3039
3040 max_code
3041 }
3042
3043 const SMALLEST: usize = 1;
3045
3046 fn pqdownheap(&mut self, tree: &[Value], mut k: usize) {
3047 macro_rules! freq_and_depth {
3055 ($i:expr) => {
3056 (tree[$i as usize].freq() as u32) << 8 | self.depth[$i as usize] as u32
3057 };
3058 }
3059
3060 let v = self.heap[k];
3061 let v_val = freq_and_depth!(v);
3062 let mut j = k << 1; while j <= self.heap_len {
3065 let mut j_val = freq_and_depth!(self.heap[j]);
3067 if j < self.heap_len {
3068 let j1_val = freq_and_depth!(self.heap[j + 1]);
3069 if j1_val <= j_val {
3070 j += 1;
3071 j_val = j1_val;
3072 }
3073 }
3074
3075 if v_val <= j_val {
3077 break;
3078 }
3079
3080 self.heap[k] = self.heap[j];
3082 k = j;
3083
3084 j <<= 1;
3086 }
3087
3088 self.heap[k] = v;
3089 }
3090
3091 fn pqremove(&mut self, tree: &[Value]) -> u32 {
3094 let top = self.heap[Self::SMALLEST];
3095 self.heap[Self::SMALLEST] = self.heap[self.heap_len];
3096 self.heap_len -= 1;
3097
3098 self.pqdownheap(tree, Self::SMALLEST);
3099
3100 top
3101 }
3102
3103 fn construct_huffman_tree(&mut self, tree: &mut [Value], mut node: usize) {
3105 loop {
3106 let n = self.pqremove(tree) as usize; let m = self.heap[Heap::SMALLEST] as usize; self.heap_max -= 1;
3110 self.heap[self.heap_max] = n as u32; self.heap_max -= 1;
3112 self.heap[self.heap_max] = m as u32;
3113
3114 *tree[node].freq_mut() = tree[n].freq() + tree[m].freq();
3116 self.depth[node] = Ord::max(self.depth[n], self.depth[m]) + 1;
3117
3118 *tree[n].dad_mut() = node as u16;
3119 *tree[m].dad_mut() = node as u16;
3120
3121 self.heap[Heap::SMALLEST] = node as u32;
3123 node += 1;
3124
3125 self.pqdownheap(tree, Heap::SMALLEST);
3126
3127 if self.heap_len < 2 {
3128 break;
3129 }
3130 }
3131
3132 self.heap_max -= 1;
3133 self.heap[self.heap_max] = self.heap[Heap::SMALLEST];
3134 }
3135}
3136
3137pub unsafe fn set_header<'a>(
3146 stream: &mut DeflateStream<'a>,
3147 head: Option<&'a mut gz_header>,
3148) -> ReturnCode {
3149 if stream.state.wrap != 2 {
3150 ReturnCode::StreamError
3151 } else {
3152 stream.state.gzhead = head;
3153 ReturnCode::Ok
3154 }
3155}
3156
3157const ZLIB_WRAPLEN: usize = 6;
3159const GZIP_WRAPLEN: usize = 18;
3161
3162const DEFLATE_HEADER_BITS: usize = 3;
3163const DEFLATE_EOBS_BITS: usize = 15;
3164const DEFLATE_PAD_BITS: usize = 6;
3165const DEFLATE_BLOCK_OVERHEAD: usize =
3166 (DEFLATE_HEADER_BITS + DEFLATE_EOBS_BITS + DEFLATE_PAD_BITS) >> 3;
3167
3168const DEFLATE_QUICK_LIT_MAX_BITS: usize = 9;
3169const fn deflate_quick_overhead(x: usize) -> usize {
3170 let sum = x
3171 .wrapping_mul(DEFLATE_QUICK_LIT_MAX_BITS - 8)
3172 .wrapping_add(7);
3173
3174 (sum as core::ffi::c_ulong >> 3) as usize
3176}
3177
3178pub fn bound(stream: Option<&mut DeflateStream>, source_len: usize) -> usize {
3194 let mask = core::ffi::c_ulong::MAX as usize;
3196
3197 let comp_len = source_len
3199 .wrapping_add((source_len.wrapping_add(7) & mask) >> 3)
3200 .wrapping_add((source_len.wrapping_add(63) & mask) >> 6)
3201 .wrapping_add(5);
3202
3203 let Some(stream) = stream else {
3204 return comp_len.wrapping_add(6);
3206 };
3207
3208 let wrap_len = match stream.state.wrap {
3210 0 => {
3211 0
3213 }
3214 1 => {
3215 if stream.state.strstart != 0 {
3217 ZLIB_WRAPLEN + 4
3218 } else {
3219 ZLIB_WRAPLEN
3220 }
3221 }
3222 2 => {
3223 let mut gz_wrap_len = GZIP_WRAPLEN;
3225
3226 if let Some(header) = &stream.state.gzhead {
3227 if !header.extra.is_null() {
3228 gz_wrap_len += 2 + header.extra_len as usize;
3229 }
3230
3231 let mut c_string = header.name;
3232 if !c_string.is_null() {
3233 loop {
3234 gz_wrap_len += 1;
3235 unsafe {
3237 if *c_string == 0 {
3238 break;
3239 }
3240 c_string = c_string.add(1);
3241 }
3242 }
3243 }
3244
3245 let mut c_string = header.comment;
3246 if !c_string.is_null() {
3247 loop {
3248 gz_wrap_len += 1;
3249 unsafe {
3251 if *c_string == 0 {
3252 break;
3253 }
3254 c_string = c_string.add(1);
3255 }
3256 }
3257 }
3258
3259 if header.hcrc != 0 {
3260 gz_wrap_len += 2;
3261 }
3262 }
3263
3264 gz_wrap_len
3265 }
3266 _ => {
3267 ZLIB_WRAPLEN
3269 }
3270 };
3271
3272 if stream.state.w_bits() != MAX_WBITS as u32 || HASH_BITS < 15 {
3273 if stream.state.level == 0 {
3274 source_len
3276 .wrapping_add(source_len >> 5)
3277 .wrapping_add(source_len >> 7)
3278 .wrapping_add(source_len >> 11)
3279 .wrapping_add(7)
3280 .wrapping_add(wrap_len)
3281 } else {
3282 comp_len.wrapping_add(wrap_len)
3283 }
3284 } else {
3285 compress_bound_help(source_len, wrap_len)
3286 }
3287}
3288
3289pub unsafe fn get_dictionary(stream: &DeflateStream<'_>, dictionary: *mut u8) -> usize {
3293 let s = &stream.state;
3294 let len = Ord::min(s.strstart + s.lookahead, s.w_size);
3295
3296 if !dictionary.is_null() && len > 0 {
3297 unsafe {
3298 core::ptr::copy_nonoverlapping(
3299 s.window.as_ptr().add(s.strstart + s.lookahead - len),
3300 dictionary,
3301 len,
3302 );
3303 }
3304 }
3305
3306 len
3307}
3308
3309struct DeflateAllocOffsets {
3310 total_size: usize,
3311 state_pos: usize,
3312 window_pos: usize,
3313 pending_pos: usize,
3314 sym_buf_pos: usize,
3315 prev_pos: usize,
3316 head_pos: usize,
3317}
3318
3319impl DeflateAllocOffsets {
3320 fn new(window_bits: usize, lit_bufsize: usize) -> Self {
3321 use core::mem::size_of;
3322
3323 const ALIGN_SIZE: usize = 64;
3326 const LIT_BUFS: usize = 4;
3327
3328 let mut curr_size = 0usize;
3329
3330 let state_size = size_of::<State>();
3332 let window_size = (1 << window_bits) * 2;
3334 let prev_size = (1 << window_bits) * size_of::<Pos>();
3335 let head_size = HASH_SIZE * size_of::<Pos>();
3336 let pending_size = lit_bufsize * LIT_BUFS;
3337 let sym_buf_size = lit_bufsize * (LIT_BUFS - 1);
3338 let state_pos = curr_size.next_multiple_of(ALIGN_SIZE);
3342 curr_size = state_pos + state_size;
3343
3344 let window_pos = curr_size.next_multiple_of(ALIGN_SIZE);
3345 curr_size = window_pos + window_size;
3346
3347 let prev_pos = curr_size.next_multiple_of(ALIGN_SIZE);
3348 curr_size = prev_pos + prev_size;
3349
3350 let head_pos = curr_size.next_multiple_of(ALIGN_SIZE);
3351 curr_size = head_pos + head_size;
3352
3353 let pending_pos = curr_size.next_multiple_of(ALIGN_SIZE);
3354 curr_size = pending_pos + pending_size;
3355
3356 let sym_buf_pos = curr_size.next_multiple_of(ALIGN_SIZE);
3357 curr_size = sym_buf_pos + sym_buf_size;
3358
3359 let total_size = (curr_size + (ALIGN_SIZE - 1)).next_multiple_of(ALIGN_SIZE);
3362
3363 Self {
3364 total_size,
3365 state_pos,
3366 window_pos,
3367 pending_pos,
3368 sym_buf_pos,
3369 prev_pos,
3370 head_pos,
3371 }
3372 }
3373}
3374
3375#[cfg(test)]
3376mod test {
3377 use crate::{
3378 inflate::{decompress_slice, InflateConfig, InflateStream},
3379 InflateFlush,
3380 };
3381
3382 use super::*;
3383
3384 use core::{ffi::CStr, sync::atomic::AtomicUsize};
3385
3386 #[test]
3387 fn detect_data_type_basic() {
3388 let empty = || [Value::new(0, 0); LITERALS];
3389
3390 assert_eq!(State::detect_data_type(&empty()), DataType::Binary);
3391
3392 let mut binary = empty();
3393 binary[0] = Value::new(1, 0);
3394 assert_eq!(State::detect_data_type(&binary), DataType::Binary);
3395
3396 let mut text = empty();
3397 text[b'\r' as usize] = Value::new(1, 0);
3398 assert_eq!(State::detect_data_type(&text), DataType::Text);
3399
3400 let mut text = empty();
3401 text[b'a' as usize] = Value::new(1, 0);
3402 assert_eq!(State::detect_data_type(&text), DataType::Text);
3403
3404 let mut non_text = empty();
3405 non_text[7] = Value::new(1, 0);
3406 assert_eq!(State::detect_data_type(&non_text), DataType::Binary);
3407 }
3408
3409 #[test]
3410 fn from_stream_mut() {
3411 unsafe {
3412 assert!(DeflateStream::from_stream_mut(core::ptr::null_mut()).is_none());
3413
3414 let mut stream = z_stream::default();
3415 assert!(DeflateStream::from_stream_mut(&mut stream).is_none());
3416
3417 assert!(DeflateStream::from_stream_mut(&mut stream).is_none());
3419
3420 init(&mut stream, DeflateConfig::default());
3421 let stream = DeflateStream::from_stream_mut(&mut stream);
3422 assert!(stream.is_some());
3423
3424 assert!(end(stream.unwrap()).is_ok());
3425 }
3426 }
3427
3428 #[cfg(feature = "c-allocator")]
3429 unsafe extern "C" fn fail_nth_allocation<const N: usize>(
3430 opaque: crate::c_api::voidpf,
3431 items: crate::c_api::uInt,
3432 size: crate::c_api::uInt,
3433 ) -> crate::c_api::voidpf {
3434 let count = unsafe { &*(opaque as *const AtomicUsize) };
3435
3436 if count.fetch_add(1, core::sync::atomic::Ordering::Relaxed) != N {
3437 unsafe { (crate::allocate::C.zalloc)(opaque, items, size) }
3441 } else {
3442 core::ptr::null_mut()
3443 }
3444 }
3445
3446 #[test]
3447 #[cfg(feature = "c-allocator")]
3448 fn init_invalid_allocator() {
3449 {
3450 let atomic = AtomicUsize::new(0);
3451 let mut stream = z_stream {
3452 zalloc: Some(fail_nth_allocation::<0>),
3453 zfree: Some(crate::allocate::C.zfree),
3454 opaque: &atomic as *const _ as *const core::ffi::c_void as *mut _,
3455 ..z_stream::default()
3456 };
3457 assert_eq!(
3458 init(&mut stream, DeflateConfig::default()),
3459 ReturnCode::MemError
3460 );
3461 }
3462 }
3463
3464 #[test]
3465 #[cfg(feature = "c-allocator")]
3466 fn copy_invalid_allocator() {
3467 let mut stream = z_stream::default();
3468
3469 let atomic = AtomicUsize::new(0);
3470 stream.opaque = &atomic as *const _ as *const core::ffi::c_void as *mut _;
3471 stream.zalloc = Some(fail_nth_allocation::<1>);
3472 stream.zfree = Some(crate::allocate::C.zfree);
3473
3474 assert_eq!(init(&mut stream, DeflateConfig::default()), ReturnCode::Ok);
3476
3477 let Some(stream) = (unsafe { DeflateStream::from_stream_mut(&mut stream) }) else {
3478 unreachable!()
3479 };
3480
3481 let mut stream_copy = MaybeUninit::<DeflateStream>::zeroed();
3482
3483 assert_eq!(copy(&mut stream_copy, stream), ReturnCode::MemError);
3484
3485 assert!(end(stream).is_ok());
3486 }
3487
3488 mod invalid_deflate_config {
3489 use super::*;
3490
3491 #[test]
3492 fn sanity_check() {
3493 let mut stream = z_stream::default();
3494 assert_eq!(init(&mut stream, DeflateConfig::default()), ReturnCode::Ok);
3495
3496 assert!(stream.zalloc.is_some());
3497 assert!(stream.zfree.is_some());
3498
3499 let stream = unsafe { DeflateStream::from_stream_mut(&mut stream) }.unwrap();
3501 assert_eq!(stream.state.level, 6);
3502
3503 assert!(end(stream).is_ok());
3504 }
3505
3506 #[test]
3507 fn window_bits_correction() {
3508 let mut stream = z_stream::default();
3510 let config = DeflateConfig {
3511 window_bits: 8,
3512 ..Default::default()
3513 };
3514 assert_eq!(init(&mut stream, config), ReturnCode::Ok);
3515 let stream = unsafe { DeflateStream::from_stream_mut(&mut stream) }.unwrap();
3516 assert_eq!(stream.state.w_bits(), 9);
3517
3518 assert!(end(stream).is_ok());
3519 }
3520
3521 #[test]
3522 fn window_bits_too_low() {
3523 let mut stream = z_stream::default();
3524 let config = DeflateConfig {
3525 window_bits: -16,
3526 ..Default::default()
3527 };
3528 assert_eq!(init(&mut stream, config), ReturnCode::StreamError);
3529 }
3530
3531 #[test]
3532 fn window_bits_too_high() {
3533 let mut stream = z_stream::default();
3535 let config = DeflateConfig {
3536 window_bits: 42,
3537 ..Default::default()
3538 };
3539 assert_eq!(init(&mut stream, config), ReturnCode::StreamError);
3540 }
3541 }
3542
3543 #[test]
3544 fn end_data_error() {
3545 let mut stream = z_stream::default();
3546 assert_eq!(init(&mut stream, DeflateConfig::default()), ReturnCode::Ok);
3547 let stream = unsafe { DeflateStream::from_stream_mut(&mut stream) }.unwrap();
3548
3549 let input = b"Hello World\n";
3551 stream.next_in = input.as_ptr() as *mut u8;
3552 stream.avail_in = input.len() as _;
3553 let output = &mut [0, 0, 0];
3554 stream.next_out = output.as_mut_ptr();
3555 stream.avail_out = output.len() as _;
3556
3557 assert_eq!(deflate(stream, DeflateFlush::NoFlush), ReturnCode::Ok);
3559
3560 assert!(end(stream).is_err());
3562 }
3563
3564 #[test]
3565 fn test_reset_keep() {
3566 let mut stream = z_stream::default();
3567 assert_eq!(init(&mut stream, DeflateConfig::default()), ReturnCode::Ok);
3568 let stream = unsafe { DeflateStream::from_stream_mut(&mut stream) }.unwrap();
3569
3570 let input = b"Hello World\n";
3572 stream.next_in = input.as_ptr() as *mut u8;
3573 stream.avail_in = input.len() as _;
3574
3575 let output = &mut [0; 1024];
3576 stream.next_out = output.as_mut_ptr();
3577 stream.avail_out = output.len() as _;
3578 assert_eq!(deflate(stream, DeflateFlush::Finish), ReturnCode::StreamEnd);
3579
3580 assert_eq!(reset_keep(stream), ReturnCode::Ok);
3581
3582 let output = &mut [0; 1024];
3583 stream.next_out = output.as_mut_ptr();
3584 stream.avail_out = output.len() as _;
3585 assert_eq!(deflate(stream, DeflateFlush::Finish), ReturnCode::StreamEnd);
3586
3587 assert!(end(stream).is_ok());
3588 }
3589
3590 #[test]
3591 fn hello_world_huffman_only() {
3592 const EXPECTED: &[u8] = &[
3593 0x78, 0x01, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x08, 0xcf, 0x2f, 0xca, 0x49, 0x51,
3594 0xe4, 0x02, 0x00, 0x20, 0x91, 0x04, 0x48,
3595 ];
3596
3597 let input = "Hello World!\n";
3598
3599 let mut output = vec![0; 128];
3600
3601 let config = DeflateConfig {
3602 level: 6,
3603 method: Method::Deflated,
3604 window_bits: crate::MAX_WBITS,
3605 mem_level: DEF_MEM_LEVEL,
3606 strategy: Strategy::HuffmanOnly,
3607 };
3608
3609 let (output, err) = compress_slice(&mut output, input.as_bytes(), config);
3610
3611 assert_eq!(err, ReturnCode::Ok);
3612
3613 assert_eq!(output.len(), EXPECTED.len());
3614
3615 assert_eq!(EXPECTED, output);
3616 }
3617
3618 #[test]
3619 fn hello_world_quick() {
3620 const EXPECTED: &[u8] = &[
3621 0x78, 0x01, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x08, 0xcf, 0x2f, 0xca, 0x49, 0x51,
3622 0xe4, 0x02, 0x00, 0x20, 0x91, 0x04, 0x48,
3623 ];
3624
3625 let input = "Hello World!\n";
3626
3627 let mut output = vec![0; 128];
3628
3629 let config = DeflateConfig {
3630 level: 1,
3631 method: Method::Deflated,
3632 window_bits: crate::MAX_WBITS,
3633 mem_level: DEF_MEM_LEVEL,
3634 strategy: Strategy::Default,
3635 };
3636
3637 let (output, err) = compress_slice(&mut output, input.as_bytes(), config);
3638
3639 assert_eq!(err, ReturnCode::Ok);
3640
3641 assert_eq!(output.len(), EXPECTED.len());
3642
3643 assert_eq!(EXPECTED, output);
3644 }
3645
3646 #[test]
3647 fn hello_world_quick_random() {
3648 const EXPECTED: &[u8] = &[
3649 0x78, 0x01, 0x53, 0xe1, 0x50, 0x51, 0xe1, 0x52, 0x51, 0x51, 0x01, 0x00, 0x03, 0xec,
3650 0x00, 0xeb,
3651 ];
3652
3653 let input = "$\u{8}$$\n$$$";
3654
3655 let mut output = vec![0; 128];
3656
3657 let config = DeflateConfig {
3658 level: 1,
3659 method: Method::Deflated,
3660 window_bits: crate::MAX_WBITS,
3661 mem_level: DEF_MEM_LEVEL,
3662 strategy: Strategy::Default,
3663 };
3664
3665 let (output, err) = compress_slice(&mut output, input.as_bytes(), config);
3666
3667 assert_eq!(err, ReturnCode::Ok);
3668
3669 assert_eq!(output.len(), EXPECTED.len());
3670
3671 assert_eq!(EXPECTED, output);
3672 }
3673
3674 fn fuzz_based_test(input: &[u8], config: DeflateConfig, expected: &[u8]) {
3675 let mut output_rs = [0; 1 << 17];
3676 let (output_rs, err) = compress_slice(&mut output_rs, input, config);
3677 assert_eq!(err, ReturnCode::Ok);
3678
3679 assert_eq!(output_rs, expected);
3680 }
3681
3682 #[test]
3683 fn simple_rle() {
3684 fuzz_based_test(
3685 "\0\0\0\0\u{6}".as_bytes(),
3686 DeflateConfig {
3687 level: -1,
3688 method: Method::Deflated,
3689 window_bits: 11,
3690 mem_level: 4,
3691 strategy: Strategy::Rle,
3692 },
3693 &[56, 17, 99, 0, 2, 54, 0, 0, 11, 0, 7],
3694 )
3695 }
3696
3697 #[test]
3698 fn fill_window_out_of_bounds() {
3699 const INPUT: &[u8] = &[
3700 0x71, 0x71, 0x71, 0x71, 0x71, 0x6a, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
3701 0x71, 0x71, 0x71, 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1d, 0x1d, 0x1d, 0x1d, 0x63,
3702 0x63, 0x63, 0x63, 0x63, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
3703 0x1d, 0x27, 0x0, 0x0, 0x0, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71,
3704 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0,
3705 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3706 0x0, 0x0, 0x0, 0x0, 0x1d, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
3707 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x48, 0x50,
3708 0x50, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x4a,
3709 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
3710 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x70, 0x71, 0x71, 0x0, 0x0,
3711 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71, 0x71, 0x6a, 0x0, 0x0, 0x0, 0x0,
3712 0x71, 0x0, 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3713 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3714 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3715 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, 0x0,
3716 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
3717 0x71, 0x71, 0x0, 0x4a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71,
3718 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
3719 0x70, 0x71, 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71, 0x71,
3720 0x6a, 0x0, 0x0, 0x0, 0x0, 0x71, 0x0, 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3721 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3722 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3723 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3724 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1d, 0x1d, 0x0, 0x0, 0x0, 0x0,
3725 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
3726 0x50, 0x50, 0x50, 0x50, 0x48, 0x50, 0x0, 0x0, 0x71, 0x71, 0x71, 0x71, 0x3b, 0x3f, 0x71,
3727 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x50, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3728 0x2c, 0x0, 0x0, 0x0, 0x0, 0x4a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71,
3729 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
3730 0x71, 0x70, 0x71, 0x71, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71,
3731 0x71, 0x71, 0x71, 0x70, 0x71, 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3732 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71, 0x71, 0x3b, 0x3f, 0x71, 0x71, 0x71,
3733 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
3734 0x71, 0x3b, 0x3f, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x20, 0x0, 0x0, 0x0, 0x0,
3735 0x0, 0x0, 0x0, 0x71, 0x75, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
3736 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x10, 0x0, 0x71, 0x71,
3737 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x3b, 0x71, 0x71, 0x71, 0x71, 0x71,
3738 0x71, 0x76, 0x71, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x71, 0x71, 0x71, 0x71, 0x71,
3739 0x71, 0x71, 0x71, 0x10, 0x0, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
3740 0x71, 0x3b, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x76, 0x71, 0x34, 0x34, 0x34, 0x34,
3741 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
3742 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x34, 0x34, 0x34,
3743 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
3744 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
3745 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
3746 0x34, 0x34, 0x30, 0x34, 0x34, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3747 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3748 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3749 0x0, 0x0, 0x71, 0x0, 0x0, 0x0, 0x0, 0x6,
3750 ];
3751
3752 fuzz_based_test(
3753 INPUT,
3754 DeflateConfig {
3755 level: -1,
3756 method: Method::Deflated,
3757 window_bits: 9,
3758 mem_level: 1,
3759 strategy: Strategy::HuffmanOnly,
3760 },
3761 &[
3762 0x18, 0x19, 0x4, 0xc1, 0x21, 0x1, 0xc4, 0x0, 0x10, 0x3, 0xb0, 0x18, 0x29, 0x1e,
3763 0x7e, 0x17, 0x83, 0xf5, 0x70, 0x6c, 0xac, 0xfe, 0xc9, 0x27, 0xdb, 0xb6, 0x6f, 0xdb,
3764 0xb6, 0x6d, 0xdb, 0x80, 0x24, 0xb9, 0xbb, 0xbb, 0x24, 0x49, 0x92, 0x24, 0xf, 0x2,
3765 0xd8, 0x36, 0x0, 0xf0, 0x3, 0x0, 0x0, 0x24, 0xd0, 0xb6, 0x6d, 0xdb, 0xb6, 0x6d,
3766 0xdb, 0xbe, 0x6d, 0xf9, 0x13, 0x4, 0xc7, 0x4, 0x0, 0x80, 0x30, 0x0, 0xc3, 0x22,
3767 0x68, 0xf, 0x36, 0x90, 0xc2, 0xb5, 0xfa, 0x7f, 0x48, 0x80, 0x81, 0xb, 0x40, 0x55,
3768 0x55, 0x55, 0xd5, 0x16, 0x80, 0xaa, 0x7, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3769 0xe, 0x7c, 0x82, 0xe0, 0x98, 0x0, 0x0, 0x0, 0x4, 0x60, 0x10, 0xf9, 0x8c, 0xe2,
3770 0xe5, 0xfa, 0x3f, 0x2, 0x54, 0x55, 0x55, 0x65, 0x0, 0xa8, 0xaa, 0xaa, 0xaa, 0xba,
3771 0x2, 0x50, 0xb5, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78, 0x82, 0xe0, 0xd0,
3772 0x8a, 0x41, 0x0, 0x0, 0xa2, 0x58, 0x54, 0xb7, 0x60, 0x83, 0x9a, 0x6a, 0x4, 0x96,
3773 0x87, 0xba, 0x51, 0xf8, 0xfb, 0x9b, 0x26, 0xfc, 0x0, 0x1c, 0x7, 0x6c, 0xdb, 0xb6,
3774 0x6d, 0xdb, 0xb6, 0x6d, 0xf7, 0xa8, 0x3a, 0xaf, 0xaa, 0x6a, 0x3, 0xf8, 0xc2, 0x3,
3775 0x40, 0x55, 0x55, 0x55, 0xd5, 0x5b, 0xf8, 0x80, 0xaa, 0x7a, 0xb, 0x0, 0x7f, 0x82,
3776 0xe0, 0x98, 0x0, 0x40, 0x18, 0x0, 0x82, 0xd8, 0x49, 0x40, 0x2, 0x22, 0x7e, 0xeb,
3777 0x80, 0xa6, 0xc, 0xa0, 0x9f, 0xa4, 0x2a, 0x38, 0xf, 0x0, 0x0, 0xe7, 0x1, 0xdc,
3778 0x55, 0x95, 0x17, 0x0, 0x0, 0xae, 0x0, 0x38, 0xc0, 0x67, 0xdb, 0x36, 0x80, 0x2b,
3779 0x0, 0xe, 0xf0, 0xd9, 0xf6, 0x13, 0x4, 0xc7, 0x4, 0x0, 0x0, 0x30, 0xc, 0x83, 0x22,
3780 0x69, 0x7, 0xc6, 0xea, 0xff, 0x19, 0x0, 0x0, 0x80, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x0,
3781 0x0, 0x8e, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a,
3782 0xf5, 0x63, 0x60, 0x60, 0x3, 0x0, 0xee, 0x8a, 0x88, 0x67,
3783 ],
3784 )
3785 }
3786
3787 #[test]
3788 fn gzip_no_header() {
3789 let config = DeflateConfig {
3790 level: 9,
3791 method: Method::Deflated,
3792 window_bits: 31, ..Default::default()
3794 };
3795
3796 let input = b"Hello World!";
3797 let os = gz_header::OS_CODE;
3798
3799 fuzz_based_test(
3800 input,
3801 config,
3802 &[
3803 31, 139, 8, 0, 0, 0, 0, 0, 2, os, 243, 72, 205, 201, 201, 87, 8, 207, 47, 202, 73,
3804 81, 4, 0, 163, 28, 41, 28, 12, 0, 0, 0,
3805 ],
3806 )
3807 }
3808
3809 #[test]
3810 #[rustfmt::skip]
3811 fn gzip_stored_block_checksum() {
3812 fuzz_based_test(
3813 &[
3814 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 9, 0,
3815 ],
3816 DeflateConfig {
3817 level: 0,
3818 method: Method::Deflated,
3819 window_bits: 26,
3820 mem_level: 6,
3821 strategy: Strategy::Default,
3822 },
3823 &[
3824 31, 139, 8, 0, 0, 0, 0, 0, 4, gz_header::OS_CODE, 1, 18, 0, 237, 255, 27, 27, 27, 27, 27, 27, 27,
3825 27, 27, 27, 27, 27, 27, 27, 27, 27, 9, 0, 60, 101, 156, 55, 18, 0, 0, 0,
3826 ],
3827 )
3828 }
3829
3830 #[test]
3831 fn gzip_header_pending_flush() {
3832 let extra = "aaaaaaaaaaaaaaaaaaaa\0";
3833 let name = "bbbbbbbbbbbbbbbbbbbb\0";
3834 let comment = "cccccccccccccccccccc\0";
3835
3836 let mut header = gz_header {
3837 text: 0,
3838 time: 0,
3839 xflags: 0,
3840 os: 0,
3841 extra: extra.as_ptr() as *mut _,
3842 extra_len: extra.len() as _,
3843 extra_max: 0,
3844 name: name.as_ptr() as *mut _,
3845 name_max: 0,
3846 comment: comment.as_ptr() as *mut _,
3847 comm_max: 0,
3848 hcrc: 1,
3849 done: 0,
3850 };
3851
3852 let config = DeflateConfig {
3853 window_bits: 31,
3854 mem_level: 1,
3855 ..Default::default()
3856 };
3857
3858 let mut stream = z_stream::default();
3859 assert_eq!(init(&mut stream, config), ReturnCode::Ok);
3860
3861 let Some(stream) = (unsafe { DeflateStream::from_stream_mut(&mut stream) }) else {
3862 unreachable!()
3863 };
3864
3865 unsafe { set_header(stream, Some(&mut header)) };
3866
3867 let input = b"Hello World\n";
3868 stream.next_in = input.as_ptr() as *mut _;
3869 stream.avail_in = input.len() as _;
3870
3871 let mut output = [0u8; 1024];
3872 stream.next_out = output.as_mut_ptr();
3873 stream.avail_out = 100;
3874
3875 assert_eq!(stream.state.bit_writer.pending.capacity(), 512);
3876
3877 stream.state.bit_writer.pending.extend(&[0; 500]);
3880
3881 assert_eq!(deflate(stream, DeflateFlush::Finish), ReturnCode::Ok);
3882
3883 stream.avail_out = output.len() as _;
3885 assert_eq!(deflate(stream, DeflateFlush::Finish), ReturnCode::StreamEnd);
3886
3887 let n = stream.total_out as usize;
3888
3889 assert!(end(stream).is_ok());
3890
3891 let output_rs = &mut output[..n];
3892
3893 assert_eq!(output_rs.len(), 500 + 99);
3894 }
3895
3896 #[test]
3897 fn gzip_with_header() {
3898 let extra = "some extra stuff\0";
3902 let name = "nomen est omen\0";
3903 let comment = "such comment\0";
3904
3905 let mut header = gz_header {
3906 text: 0,
3907 time: 0,
3908 xflags: 0,
3909 os: 0,
3910 extra: extra.as_ptr() as *mut _,
3911 extra_len: extra.len() as _,
3912 extra_max: 0,
3913 name: name.as_ptr() as *mut _,
3914 name_max: 0,
3915 comment: comment.as_ptr() as *mut _,
3916 comm_max: 0,
3917 hcrc: 1,
3918 done: 0,
3919 };
3920
3921 let config = DeflateConfig {
3922 window_bits: 31,
3923 ..Default::default()
3924 };
3925
3926 let mut stream = z_stream::default();
3927 assert_eq!(init(&mut stream, config), ReturnCode::Ok);
3928
3929 let Some(stream) = (unsafe { DeflateStream::from_stream_mut(&mut stream) }) else {
3930 unreachable!()
3931 };
3932
3933 unsafe { set_header(stream, Some(&mut header)) };
3934
3935 let input = b"Hello World\n";
3936 stream.next_in = input.as_ptr() as *mut _;
3937 stream.avail_in = input.len() as _;
3938
3939 let mut output = [0u8; 256];
3940 stream.next_out = output.as_mut_ptr();
3941 stream.avail_out = output.len() as _;
3942
3943 assert_eq!(deflate(stream, DeflateFlush::Finish), ReturnCode::StreamEnd);
3944
3945 let n = stream.total_out as usize;
3946
3947 assert!(end(stream).is_ok());
3948
3949 let output_rs = &mut output[..n];
3950
3951 assert_eq!(output_rs.len(), 81);
3952
3953 {
3954 let mut stream = z_stream::default();
3955
3956 let config = InflateConfig {
3957 window_bits: config.window_bits,
3958 };
3959
3960 assert_eq!(crate::inflate::init(&mut stream, config), ReturnCode::Ok);
3961
3962 let Some(stream) = (unsafe { InflateStream::from_stream_mut(&mut stream) }) else {
3963 unreachable!();
3964 };
3965
3966 stream.next_in = output_rs.as_mut_ptr() as _;
3967 stream.avail_in = output_rs.len() as _;
3968
3969 let mut output = [0u8; 12];
3970 stream.next_out = output.as_mut_ptr();
3971 stream.avail_out = output.len() as _;
3972
3973 let mut extra_buf = [0u8; 64];
3974 let mut name_buf = [0u8; 64];
3975 let mut comment_buf = [0u8; 64];
3976
3977 let mut header = gz_header {
3978 text: 0,
3979 time: 0,
3980 xflags: 0,
3981 os: 0,
3982 extra: extra_buf.as_mut_ptr(),
3983 extra_len: 0,
3984 extra_max: extra_buf.len() as _,
3985 name: name_buf.as_mut_ptr(),
3986 name_max: name_buf.len() as _,
3987 comment: comment_buf.as_mut_ptr(),
3988 comm_max: comment_buf.len() as _,
3989 hcrc: 0,
3990 done: 0,
3991 };
3992
3993 assert_eq!(
3994 unsafe { crate::inflate::get_header(stream, Some(&mut header)) },
3995 ReturnCode::Ok
3996 );
3997
3998 assert_eq!(
3999 unsafe { crate::inflate::inflate(stream, InflateFlush::Finish) },
4000 ReturnCode::StreamEnd
4001 );
4002
4003 crate::inflate::end(stream);
4004
4005 assert!(!header.comment.is_null());
4006 assert_eq!(
4007 unsafe { CStr::from_ptr(header.comment.cast()) }
4008 .to_str()
4009 .unwrap(),
4010 comment.trim_end_matches('\0')
4011 );
4012
4013 assert!(!header.name.is_null());
4014 assert_eq!(
4015 unsafe { CStr::from_ptr(header.name.cast()) }
4016 .to_str()
4017 .unwrap(),
4018 name.trim_end_matches('\0')
4019 );
4020
4021 assert!(!header.extra.is_null());
4022 assert_eq!(
4023 unsafe { CStr::from_ptr(header.extra.cast()) }
4024 .to_str()
4025 .unwrap(),
4026 extra.trim_end_matches('\0')
4027 );
4028 }
4029 }
4030
4031 #[test]
4032 fn insufficient_compress_space() {
4033 const DATA: &[u8] = include_bytes!("deflate/test-data/inflate_buf_error.dat");
4034
4035 fn helper(deflate_buf: &mut [u8], deflate_err: ReturnCode) -> ReturnCode {
4036 let config = DeflateConfig {
4037 level: 0,
4038 method: Method::Deflated,
4039 window_bits: 10,
4040 mem_level: 6,
4041 strategy: Strategy::Default,
4042 };
4043
4044 let (output, err) = compress_slice(deflate_buf, DATA, config);
4045 assert_eq!(err, deflate_err);
4046
4047 let config = InflateConfig {
4048 window_bits: config.window_bits,
4049 };
4050
4051 let mut uncompr = [0; 1 << 17];
4052 let (uncompr, err) = decompress_slice(&mut uncompr, output, config);
4053
4054 if err == ReturnCode::Ok {
4055 assert_eq!(DATA, uncompr);
4056 }
4057
4058 err
4059 }
4060
4061 let mut output = [0; 1 << 17];
4062
4063 assert_eq!(
4065 helper(&mut output[..1 << 16], ReturnCode::BufError),
4066 ReturnCode::DataError
4067 );
4068
4069 assert_eq!(helper(&mut output, ReturnCode::Ok), ReturnCode::Ok);
4071 }
4072
4073 fn test_flush(flush: DeflateFlush, expected: &[u8]) {
4074 let input = b"Hello World!\n";
4075
4076 let config = DeflateConfig {
4077 level: 6, method: Method::Deflated,
4079 window_bits: 16 + crate::MAX_WBITS,
4080 mem_level: DEF_MEM_LEVEL,
4081 strategy: Strategy::Default,
4082 };
4083
4084 let mut output_rs = vec![0; 128];
4085
4086 let expected_err = ReturnCode::BufError;
4090
4091 let (rs, err) = compress_slice_with_flush(&mut output_rs, input, config, flush);
4092 assert_eq!(expected_err, err);
4093
4094 assert_eq!(rs, expected);
4095 }
4096
4097 #[test]
4098 #[rustfmt::skip]
4099 fn sync_flush() {
4100 test_flush(
4101 DeflateFlush::SyncFlush,
4102 &[
4103 31, 139, 8, 0, 0, 0, 0, 0, 0, gz_header::OS_CODE, 242, 72, 205, 201, 201, 87, 8, 207, 47, 202, 73,
4104 81, 228, 2, 0, 0, 0, 255, 255,
4105 ],
4106 )
4107 }
4108
4109 #[test]
4110 #[rustfmt::skip]
4111 fn partial_flush() {
4112 test_flush(
4113 DeflateFlush::PartialFlush,
4114 &[
4115 31, 139, 8, 0, 0, 0, 0, 0, 0, gz_header::OS_CODE, 242, 72, 205, 201, 201, 87, 8, 207, 47, 202, 73,
4116 81, 228, 2, 8,
4117 ],
4118 );
4119 }
4120
4121 #[test]
4122 #[rustfmt::skip]
4123 fn full_flush() {
4124 test_flush(
4125 DeflateFlush::FullFlush,
4126 &[
4127 31, 139, 8, 0, 0, 0, 0, 0, 0, gz_header::OS_CODE, 242, 72, 205, 201, 201, 87, 8, 207, 47, 202, 73,
4128 81, 228, 2, 0, 0, 0, 255, 255,
4129 ],
4130 );
4131 }
4132
4133 #[test]
4134 #[rustfmt::skip]
4135 fn block_flush() {
4136 test_flush(
4137 DeflateFlush::Block,
4138 &[
4139 31, 139, 8, 0, 0, 0, 0, 0, 0, gz_header::OS_CODE, 242, 72, 205, 201, 201, 87, 8, 207, 47, 202, 73,
4140 81, 228, 2,
4141 ],
4142 );
4143 }
4144
4145 #[test]
4146 fn split_deflate() {
4150 let input = "Hello World!\n";
4151
4152 let (input1, input2) = input.split_at(6);
4153
4154 let mut output1 = vec![0; 128];
4155 let mut output2 = vec![0; 128];
4156
4157 let config = DeflateConfig {
4158 level: 6, method: Method::Deflated,
4160 window_bits: 16 + crate::MAX_WBITS,
4161 mem_level: DEF_MEM_LEVEL,
4162 strategy: Strategy::Default,
4163 };
4164
4165 let (prefix, err) = compress_slice_with_flush(
4168 &mut output1,
4169 input1.as_bytes(),
4170 config,
4171 DeflateFlush::SyncFlush,
4172 );
4173 assert_eq!(err, ReturnCode::BufError);
4174
4175 let (output2, err) = compress_slice_with_flush(
4176 &mut output2,
4177 input2.as_bytes(),
4178 config,
4179 DeflateFlush::Finish,
4180 );
4181 assert_eq!(err, ReturnCode::Ok);
4182
4183 let inflate_config = crate::inflate::InflateConfig {
4184 window_bits: 16 + 15,
4185 };
4186
4187 let (suffix, end) = output2.split_at(output2.len() - 8);
4189 let (crc2, len2) = end.split_at(4);
4190 let crc2 = u32::from_le_bytes(crc2.try_into().unwrap());
4191
4192 let suffix = &suffix[10..];
4194
4195 let mut result: Vec<u8> = Vec::new();
4196 result.extend(prefix.iter());
4197 result.extend(suffix);
4198
4199 let len1 = input1.len() as u32;
4202 let len2 = u32::from_le_bytes(len2.try_into().unwrap());
4203 assert_eq!(len2 as usize, input2.len());
4204
4205 let crc1 = crate::crc32::crc32(0, input1.as_bytes());
4206 let crc = crate::crc32::crc32_combine(crc1, crc2, len2 as u64);
4207
4208 let crc_cheating = crate::crc32::crc32(0, input.as_bytes());
4210 assert_eq!(crc, crc_cheating);
4211
4212 result.extend(crc.to_le_bytes());
4214 result.extend((len1 + len2).to_le_bytes());
4215
4216 let mut output = vec![0; 128];
4217 let (output, err) = crate::inflate::decompress_slice(&mut output, &result, inflate_config);
4218 assert_eq!(err, ReturnCode::Ok);
4219
4220 assert_eq!(output, input.as_bytes());
4221 }
4222
4223 #[test]
4224 fn inflate_window_copy_slice() {
4225 let uncompressed = [
4226 9, 126, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 76, 33, 8, 2, 0, 0,
4227 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4228 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4229 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4230 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12,
4231 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 76, 33, 8, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,
4232 0, 0, 0, 12, 10, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
4233 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 14, 0, 0, 0, 0, 0, 69, 69, 69, 69, 69, 69, 69,
4234 69, 69, 69, 69, 69, 69, 69, 69, 9, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
4235 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
4236 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
4237 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 12, 28, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
4238 0, 0, 12, 10, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
4239 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 14, 0, 0, 0, 0, 0, 69, 69, 69, 69, 69, 69, 69,
4240 69, 69, 69, 69, 69, 69, 69, 69, 9, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
4241 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
4242 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
4243 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 12, 28, 0, 2, 0, 0, 0, 63, 1, 0, 12, 2,
4244 36, 0, 28, 0, 0, 0, 1, 0, 0, 63, 63, 13, 0, 0, 0, 0, 0, 0, 0, 63, 63, 63, 63, 0, 0, 0,
4245 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0,
4246 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4247 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4248 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 12, 33, 2, 0, 0, 8,
4249 0, 4, 0, 0, 0, 12, 10, 41, 12, 10, 47,
4250 ];
4251
4252 let compressed = &[
4253 31, 139, 8, 0, 0, 0, 0, 0, 4, 3, 181, 193, 49, 14, 194, 32, 24, 128, 209, 175, 192, 0,
4254 228, 151, 232, 206, 66, 226, 226, 96, 60, 2, 113, 96, 235, 13, 188, 139, 103, 23, 106,
4255 104, 108, 100, 49, 169, 239, 185, 39, 11, 199, 7, 51, 39, 171, 248, 118, 226, 63, 52,
4256 157, 120, 86, 102, 78, 86, 209, 104, 58, 241, 84, 129, 166, 12, 4, 154, 178, 229, 202,
4257 30, 36, 130, 166, 19, 79, 21, 104, 202, 64, 160, 41, 91, 174, 236, 65, 34, 10, 200, 19,
4258 162, 206, 68, 96, 130, 156, 15, 188, 229, 138, 197, 157, 161, 35, 3, 87, 126, 245, 0,
4259 28, 224, 64, 146, 2, 139, 1, 196, 95, 196, 223, 94, 10, 96, 92, 33, 86, 2, 0, 0,
4260 ];
4261
4262 let config = InflateConfig { window_bits: 25 };
4263
4264 let mut dest_vec_rs = vec![0u8; uncompressed.len()];
4265 let (output_rs, error) =
4266 crate::inflate::decompress_slice(&mut dest_vec_rs, compressed, config);
4267
4268 assert_eq!(ReturnCode::Ok, error);
4269 assert_eq!(output_rs, uncompressed);
4270 }
4271
4272 #[test]
4273 fn hash_calc_difference() {
4274 let input = [
4275 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0,
4276 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4277 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4278 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4279 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
4280 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4281 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0,
4282 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 64, 0, 0,
4283 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 102, 102, 102, 102,
4284 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
4285 102, 102, 102, 102, 102, 102, 102, 102, 112, 102, 102, 102, 102, 102, 102, 102, 102,
4286 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 0,
4287 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4288 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4289 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4290 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4291 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4292 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0,
4293 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 64, 0, 0, 0, 0, 0, 0, 0,
4294 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0,
4295 50, 0,
4296 ];
4297
4298 let config = DeflateConfig {
4299 level: 6,
4300 method: Method::Deflated,
4301 window_bits: 9,
4302 mem_level: 8,
4303 strategy: Strategy::Default,
4304 };
4305
4306 let expected = [
4307 24, 149, 99, 96, 96, 96, 96, 208, 6, 17, 112, 138, 129, 193, 128, 1, 29, 24, 50, 208,
4308 1, 200, 146, 169, 79, 24, 74, 59, 96, 147, 52, 71, 22, 70, 246, 88, 26, 94, 80, 128,
4309 83, 6, 162, 219, 144, 76, 183, 210, 5, 8, 67, 105, 36, 159, 35, 128, 57, 118, 97, 100,
4310 160, 197, 192, 192, 96, 196, 0, 0, 3, 228, 25, 128,
4311 ];
4312
4313 fuzz_based_test(&input, config, &expected);
4314 }
4315
4316 #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
4317 mod _cache_lines {
4318 use super::State;
4319 use memoffset::offset_of;
4322
4323 const _: () = assert!(offset_of!(State, status) == 0);
4324 const _: () = assert!(offset_of!(State, _cache_line_0) == 64);
4325 const _: () = assert!(offset_of!(State, _cache_line_1) == 128);
4326 #[cfg(not(feature = "ZLIB_DEBUG"))] const _: () = assert!(offset_of!(State, _cache_line_2) == 192);
4328 #[cfg(not(feature = "ZLIB_DEBUG"))] const _: () = assert!(offset_of!(State, _cache_line_3) == 256);
4330 }
4331}