1use core::ffi::c_void;
2use core::marker::PhantomData;
3
4use crate::allocate::Allocator;
5use crate::c_api::{in_func, internal_state, out_func};
6use crate::inflate::bitreader::BitReader;
7use crate::inflate::inftrees::{inflate_table, CodeType, InflateTable};
8use crate::inflate::{
9 Codes, Flags, InflateAllocOffsets, InflateConfig, InflateStream, Mode, State, Table, Window,
10 INFLATE_FAST_MIN_HAVE, INFLATE_FAST_MIN_LEFT, INFLATE_STRICT, MAX_BITS, MAX_DIST_EXTRA_BITS,
11};
12use crate::{c_api::z_stream, inflate::writer::Writer, ReturnCode};
13
14macro_rules! tracev {
15 ($template:expr) => {
16 #[cfg(test)]
17 eprintln!($template);
18 };
19 ($template:expr, $($x:expr),* $(,)?) => {
20 #[cfg(test)]
21 eprintln!($template, $($x),*);
22 };
23}
24
25pub fn back_init(stream: &mut z_stream, config: InflateConfig, window: Window) -> ReturnCode {
27 assert_eq!(1 << config.window_bits, window.buffer_size());
28
29 stream.msg = core::ptr::null_mut();
30
31 #[cfg(feature = "rust-allocator")]
35 if stream.zalloc.is_none() || stream.zfree.is_none() {
36 stream.configure_default_rust_allocator()
37 }
38
39 #[cfg(feature = "c-allocator")]
40 if stream.zalloc.is_none() || stream.zfree.is_none() {
41 stream.configure_default_c_allocator()
42 }
43
44 if stream.zalloc.is_none() || stream.zfree.is_none() {
45 return ReturnCode::StreamError;
46 }
47
48 let mut state = State::new(&[], Writer::new(&mut []));
49
50 state.chunksize = 32;
52
53 let alloc = Allocator {
54 zalloc: stream.zalloc.unwrap(),
55 zfree: stream.zfree.unwrap(),
56 opaque: stream.opaque,
57 _marker: PhantomData,
58 };
59 let allocs = InflateAllocOffsets::new();
60
61 let Some(allocation_start) = alloc.allocate_slice_raw::<u8>(allocs.total_size) else {
62 return ReturnCode::MemError;
63 };
64
65 let address = allocation_start.as_ptr() as usize;
66 let align_offset = address.next_multiple_of(64) - address;
67 let buf = unsafe { allocation_start.as_ptr().add(align_offset) };
68
69 state.window = window;
71
72 let state_allocation = unsafe { buf.add(allocs.state_pos).cast::<State>() };
73 unsafe { state_allocation.write(state) };
74 stream.state = state_allocation.cast::<internal_state>();
75
76 let Some(stream) = (unsafe { InflateStream::from_stream_mut(stream) }) else {
78 return ReturnCode::StreamError;
79 };
80
81 stream.state.allocation_start = allocation_start.as_ptr();
82 stream.state.total_allocation_size = allocs.total_size;
83
84 stream.state.wbits = config.window_bits as u8;
85 stream.state.flags.update(Flags::SANE, true);
86
87 ReturnCode::Ok
88}
89
90pub unsafe fn back(
91 strm: &mut InflateStream,
92 in_: in_func,
93 in_desc: *mut c_void,
94 out: out_func,
95 out_desc: *mut c_void,
96) -> ReturnCode {
97 let mut ret;
98
99 strm.msg = core::ptr::null_mut();
101 strm.state.mode = Mode::Type;
102 strm.state.flags.update(Flags::IS_LAST_BLOCK, false);
103 strm.state.window.clear();
104
105 let mut next = strm.next_in.cast_const();
106 let mut have = if !next.is_null() { strm.avail_in } else { 0 };
107 let mut hold = 0;
108 let mut bits = 0u8;
109 let mut put = strm.state.window.as_ptr().cast_mut();
110 let mut left = strm.state.window.buffer_size();
111
112 let state = &mut strm.state;
113
114 'inf_leave: loop {
115 macro_rules! initbits {
116 () => {
117 hold = 0;
118 bits = 0;
119 };
120 }
121
122 macro_rules! bytebits {
123 () => {
124 hold >>= bits & 7;
125 bits -= bits & 7;
126 };
127 }
128
129 macro_rules! dropbits {
130 ($n:expr) => {
131 hold >>= $n;
132 bits -= $n;
133 };
134 }
135
136 macro_rules! bits {
137 ($n:expr) => {
138 hold & ((1 << $n) - 1)
139 };
140 }
141
142 macro_rules! needbits {
143 ($n:expr) => {
144 while usize::from(bits) < $n {
145 pullbyte!();
146 }
147 };
148 }
149
150 macro_rules! pull {
151 () => {
152 if have == 0 {
153 have = unsafe { in_(in_desc, &mut next) };
154 if have == 0 {
155 #[allow(unused_assignments)]
156 {
157 next = core::ptr::null();
158 }
159 ret = ReturnCode::BufError;
160 break 'inf_leave;
161 }
162 }
163 };
164 }
165
166 macro_rules! pullbyte {
167 () => {
168 pull!();
169 have -= 1;
170 hold += (unsafe { *next as u64 }) << bits;
171 next = unsafe { next.add(1) };
172 bits += 8;
173 };
174 }
175
176 macro_rules! room {
177 () => {
178 if left == 0 {
179 left = state.window.buffer_size();
180 let window = state.window.as_slice();
181 put = window.as_ptr().cast_mut();
182
183 unsafe { state.window.set_have(left) };
184
185 if unsafe { out(out_desc, put, left as u32) } != 0 {
186 ret = ReturnCode::BufError;
187 break 'inf_leave;
188 }
189 }
190 };
191 }
192
193 match state.mode {
194 Mode::Type => {
195 if state.flags.contains(Flags::IS_LAST_BLOCK) {
196 bytebits!();
197 state.mode = Mode::Done;
198 continue;
199 }
200
201 needbits!(3);
202
203 let last = bits!(1) != 0;
204 state.flags.update(Flags::IS_LAST_BLOCK, last);
205 dropbits!(1);
206
207 match bits!(2) {
208 0b00 => {
209 tracev!("inflate: stored block (last = {last})");
210
211 dropbits!(2);
212 state.mode = Mode::Stored;
213 continue;
214 }
215 0b01 => {
216 tracev!("inflate: fixed codes block (last = {last})");
217
218 state.len_table = Table {
219 codes: Codes::Fixed,
220 bits: 9,
221 };
222
223 state.dist_table = Table {
224 codes: Codes::Fixed,
225 bits: 5,
226 };
227
228 dropbits!(2);
229 state.mode = Mode::Len;
230 continue;
231 }
232 0b10 => {
233 tracev!("inflate: dynamic codes block (last = {last})");
234
235 dropbits!(2);
236 state.mode = Mode::Table;
237 continue;
238 }
239 0b11 => {
240 tracev!("inflate: invalid block type");
241
242 dropbits!(2);
243 state.mode = Mode::Bad;
244 state.bad("invalid block type\0");
245 continue;
246 }
247 _ => {
248 unreachable!("BitReader::bits(2) only yields a value of two bits, so this match is already exhaustive")
250 }
251 }
252 }
253 Mode::Stored => {
254 bytebits!();
255 needbits!(32);
256
257 if hold as u16 != !((hold >> 16) as u16) {
258 state.mode = Mode::Bad;
259 state.bad("invalid stored block lengths\0");
260 continue;
261 }
262
263 state.length = hold as usize & 0xFFFF;
264 tracev!("inflate: stored length {}", state.length);
265
266 initbits!();
267
268 while state.length != 0 {
270 let mut copy = state.length;
271
272 pull!();
273 room!();
274
275 copy = Ord::min(copy, have as usize);
276 copy = Ord::min(copy, left);
277
278 unsafe { core::ptr::copy(next, put, copy) };
279
280 have -= copy as u32;
281 next = unsafe { next.add(copy) };
282
283 left -= copy;
284 put = unsafe { put.add(copy) };
285
286 state.length -= copy;
287 }
288
289 state.mode = Mode::Type;
290 continue;
291 }
292 Mode::Table => {
293 needbits!(14);
294 state.nlen = bits!(5) as usize + 257;
295 dropbits!(5);
296 state.ndist = bits!(5) as usize + 1;
297 dropbits!(5);
298 state.ncode = bits!(4) as usize + 4;
299 dropbits!(4);
300
301 if state.nlen > 286 || state.ndist > 30 {
303 state.mode = Mode::Bad;
304 state.bad("too many length or distance symbols\0");
305 continue;
306 }
307
308 tracev!("inflate: table sizes ok");
309 state.have = 0;
310
311 const ORDER: [u8; 19] = [
313 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
314 ];
315
316 while state.have < state.ncode {
317 needbits!(3);
318 state.lens[usize::from(ORDER[state.have])] = bits!(3) as u16;
319 state.have += 1;
320 dropbits!(3);
321 }
322
323 while state.have < 19 {
324 state.lens[usize::from(ORDER[state.have])] = 0;
325 state.have += 1;
326 }
327
328 let InflateTable::Success { root, used } = inflate_table(
329 CodeType::Codes,
330 &state.lens,
331 19,
332 &mut state.codes_codes,
333 7,
334 &mut state.work,
335 ) else {
336 state.mode = Mode::Bad;
337 state.bad("invalid code lengths set\0");
338 continue;
339 };
340
341 state.next = used;
342 state.len_table.codes = Codes::Codes;
343 state.len_table.bits = root;
344
345 tracev!("inflate: table sizes ok");
346 state.have = 0;
347
348 while state.have < state.nlen + state.ndist {
349 let here = loop {
350 let here = state.len_table_get(bits!(state.len_table.bits) as usize);
351 if here.bits <= bits {
352 break here;
353 }
354
355 pullbyte!();
356 };
357
358 let here_bits = here.bits;
359
360 match here.val {
361 0..=15 => {
362 dropbits!(here_bits);
363 state.lens[state.have] = here.val;
364 state.have += 1;
365 }
366 16 => {
367 needbits!(usize::from(here_bits) + 2);
368 dropbits!(here_bits);
369 if state.have == 0 {
370 state.mode = Mode::Bad;
371 state.bad("invalid bit length repeat\0");
372 continue 'inf_leave;
373 }
374
375 let len = state.lens[state.have - 1];
376 let copy = 3 + bits!(2) as usize;
377 dropbits!(2);
378
379 if state.have + copy > state.nlen + state.ndist {
380 state.mode = Mode::Bad;
381 state.bad("invalid bit length repeat\0");
382 continue 'inf_leave;
383 }
384
385 state.lens[state.have..][..copy].fill(len);
386 state.have += copy;
387 }
388 17 => {
389 needbits!(usize::from(here_bits) + 3);
390 dropbits!(here_bits);
391 let copy = 3 + bits!(3) as usize;
392 dropbits!(3);
393
394 if state.have + copy > state.nlen + state.ndist {
395 state.mode = Mode::Bad;
396 state.bad("invalid bit length repeat\0");
397 continue 'inf_leave;
398 }
399
400 state.lens[state.have..][..copy].fill(0);
401 state.have += copy;
402 }
403 18.. => {
404 needbits!(usize::from(here_bits) + 7);
405 dropbits!(here_bits);
406 let copy = 11 + bits!(7) as usize;
407 dropbits!(7);
408
409 if state.have + copy > state.nlen + state.ndist {
410 state.mode = Mode::Bad;
411 state.bad("invalid bit length repeat\0");
412 continue 'inf_leave;
413 }
414
415 state.lens[state.have..][..copy].fill(0);
416 state.have += copy;
417 }
418 }
419 }
420
421 if state.lens[256] == 0 {
423 state.mode = Mode::Bad;
424 state.bad("invalid code -- missing end-of-block\0");
425 continue 'inf_leave;
426 }
427
428 let InflateTable::Success { root, used } = inflate_table(
431 CodeType::Lens,
432 &state.lens,
433 state.nlen,
434 &mut state.len_codes,
435 10,
436 &mut state.work,
437 ) else {
438 state.mode = Mode::Bad;
439 state.bad("invalid literal/lengths set\0");
440 continue 'inf_leave;
441 };
442
443 state.len_table.codes = Codes::Len;
444 state.len_table.bits = root;
445 state.next = used;
446
447 let InflateTable::Success { root, used } = inflate_table(
448 CodeType::Dists,
449 &state.lens[state.nlen..],
450 state.ndist,
451 &mut state.dist_codes,
452 9,
453 &mut state.work,
454 ) else {
455 state.mode = Mode::Bad;
456 state.bad("invalid distances set\0");
457 continue 'inf_leave;
458 };
459
460 state.dist_table.bits = root;
461 state.dist_table.codes = Codes::Dist;
462 state.next += used;
463
464 state.mode = Mode::Len;
465 }
466 Mode::Len => {
467 if (have as usize) >= INFLATE_FAST_MIN_HAVE && left >= INFLATE_FAST_MIN_LEFT {
468 let mut bit_reader = BitReader::new(&[]);
469 unsafe { bit_reader.update_slice(next, have as usize) };
470 bit_reader.prime(bits, hold);
471
472 state.bit_reader = bit_reader;
473 state.writer = unsafe {
474 Writer::new_uninit_raw(
475 put.wrapping_sub(state.window.buffer_size() - left),
476 state.window.buffer_size() - left,
477 state.window.buffer_size(),
478 )
479 };
480
481 if state.window.have() < state.window.buffer_size() {
482 unsafe { state.window.set_have(state.window.buffer_size() - left) };
483 }
484
485 unsafe { inflate_fast_back(state) };
486
487 hold = state.bit_reader.hold();
488 bits = state.bit_reader.bits_in_buffer();
489
490 next = state.bit_reader.as_ptr();
491 have = state.bit_reader.bytes_remaining() as u32;
492
493 put = state.writer.next_out().cast();
494 left = state.writer.remaining();
495
496 continue 'inf_leave;
497 }
498
499 let len_table = match state.len_table.codes {
500 Codes::Fixed => &crate::inflate::inffixed_tbl::LENFIX[..],
501 Codes::Codes => &state.codes_codes,
502 Codes::Len => &state.len_codes,
503 Codes::Dist => &state.dist_codes,
504 };
505
506 let mut here;
508 loop {
509 here = len_table[bits!(state.len_table.bits) as usize];
510
511 if here.bits <= bits {
512 break;
513 }
514
515 pullbyte!();
516 }
517
518 if here.op != 0 && here.op & 0xf0 == 0 {
519 let last = here;
520 loop {
521 let tmp = bits!((last.bits + last.op) as usize) as u16;
522 here = len_table[(last.val + (tmp >> last.bits)) as usize];
523 if last.bits + here.bits <= bits {
524 break;
525 }
526
527 pullbyte!();
528 }
529
530 dropbits!(last.bits);
531 }
532
533 dropbits!(here.bits);
534 state.length = here.val as usize;
535
536 if here.op == 0 {
537 if here.val >= 0x20 && here.val < 0x7f {
538 tracev!("inflate: literal '{}'", here.val as u8 as char);
539 } else {
540 tracev!("inflate: literal {:#04x}", here.val);
541 }
542 room!();
543
544 unsafe {
545 *put = state.length as u8;
546 put = put.add(1)
547 }
548 left -= 1;
549
550 state.mode = Mode::Len;
551 continue;
552 } else if here.op & 32 != 0 {
553 tracev!("inflate: end of block");
556
557 state.mode = Mode::Type;
558 continue;
559 } else if here.op & 64 != 0 {
560 state.mode = Mode::Bad;
561 state.bad("invalid literal/length code\0");
562 continue;
563 } else {
564 state.extra = (here.op & MAX_BITS) as usize;
566 }
567
568 if state.extra != 0 {
570 needbits!(state.extra);
571 state.length += bits!(state.extra) as usize;
572 dropbits!(state.extra as u8);
573 }
574 tracev!("inflate: length {}", state.length);
575
576 let mut here;
578 loop {
579 here = state.dist_table_get(bits!(state.dist_table.bits) as usize);
580 if here.bits <= bits {
581 break;
582 }
583
584 pullbyte!();
585 }
586
587 if here.op & 0xf0 == 0 {
588 let last = here;
589
590 loop {
591 here = state.dist_table_get(
592 last.val as usize
593 + ((bits!((last.bits + last.op) as usize) as usize) >> last.bits),
594 );
595
596 if last.bits + here.bits <= bits {
597 break;
598 }
599
600 pullbyte!();
601 }
602
603 dropbits!(last.bits);
604 }
605
606 dropbits!(here.bits);
607
608 if here.op & 64 != 0 {
609 state.mode = Mode::Bad;
610 state.bad("invalid distance code\0");
611 continue 'inf_leave;
612 }
613
614 state.offset = here.val as usize;
615
616 state.extra = (here.op & MAX_BITS) as usize;
617
618 let extra = state.extra;
619
620 if extra > 0 {
621 needbits!(extra);
622 state.offset += bits!(extra) as usize;
623 dropbits!(extra as u8);
624 }
625
626 if INFLATE_STRICT
627 && state.offset
628 > state.window.buffer_size()
629 - (if state.window.have() < state.window.buffer_size() {
630 left
631 } else {
632 0
633 })
634 {
635 state.mode = Mode::Bad;
636 state.bad("invalid distance too far back\0");
637 continue 'inf_leave;
638 }
639
640 tracev!("inflate: distance {}", state.offset);
641
642 loop {
643 room!();
644 let mut copy = state.window.buffer_size() - state.offset;
645 let mut from;
646
647 if copy < left {
648 from = put.wrapping_add(copy);
649 copy = left - copy;
650 } else {
651 from = put.wrapping_sub(state.offset);
652 copy = left;
653 }
654
655 copy = Ord::min(copy, state.length);
656 state.length -= copy;
657 left -= copy;
658
659 for _ in 0..copy {
660 unsafe {
661 *put = *from;
662 put = put.add(1);
663 from = from.add(1);
664 }
665 }
666
667 if state.length == 0 {
668 break;
669 }
670 }
671
672 continue 'inf_leave;
673 }
674 Mode::Done => {
675 ret = ReturnCode::StreamEnd;
676 break 'inf_leave;
677 }
678 Mode::Bad => {
679 ret = ReturnCode::DataError;
680 break 'inf_leave;
681 }
682
683 Mode::Head
684 | Mode::Flags
685 | Mode::Time
686 | Mode::Os
687 | Mode::ExLen
688 | Mode::Extra
689 | Mode::Name
690 | Mode::Comment
691 | Mode::HCrc
692 | Mode::Sync
693 | Mode::Mem
694 | Mode::Length
695 | Mode::TypeDo
696 | Mode::CopyBlock
697 | Mode::Check
698 | Mode::Len_
699 | Mode::Lit
700 | Mode::LenExt
701 | Mode::Dist
702 | Mode::DistExt
703 | Mode::Match
704 | Mode::LenLens
705 | Mode::CodeLens
706 | Mode::DictId
707 | Mode::Dict => {
708 ret = ReturnCode::StreamError;
710 break 'inf_leave;
711 }
712 }
713 }
714
715 if left < state.window.buffer_size()
716 && unsafe {
717 out(
718 out_desc,
719 state.window.as_ptr().cast_mut(),
720 state.window.buffer_size() as u32 - left as u32,
721 )
722 } != 0
723 && ret == ReturnCode::StreamEnd
724 {
725 ret = ReturnCode::BufError;
726 }
727
728 strm.next_in = next.cast_mut();
729 strm.avail_in = have;
730
731 ret
732}
733
734#[inline(always)]
735unsafe fn inflate_fast_back(state: &mut State) {
736 let mut bit_reader = BitReader::new(&[]);
737 core::mem::swap(&mut bit_reader, &mut state.bit_reader);
738 debug_assert!(bit_reader.bytes_remaining() >= 15);
739
740 let mut writer = Writer::new(&mut []);
741 core::mem::swap(&mut writer, &mut state.writer);
742
743 let lcode = state.len_table_ref();
744 let dcode = state.dist_table_ref();
745
746 let lmask = (1u64 << state.len_table.bits) - 1;
748 let dmask = (1u64 << state.dist_table.bits) - 1;
749
750 let extra_safe = false;
752
753 let window_size = state.window.buffer_size();
754
755 let mut bad = None;
756
757 if bit_reader.bits_in_buffer() < 10 {
758 debug_assert!(bit_reader.bytes_remaining() >= 15);
759 unsafe { bit_reader.refill() };
761 }
762 debug_assert!(
765 bit_reader.bytes_remaining() >= 8 && bit_reader.bytes_remaining_including_buffer() >= 15
766 );
767
768 'outer: loop {
769 debug_assert!(
775 bit_reader.bytes_remaining() >= 8
776 && bit_reader.bytes_remaining_including_buffer() >= 15
777 );
778
779 let mut here = {
780 let bits = bit_reader.bits_in_buffer();
781 let hold = bit_reader.hold();
782
783 unsafe { bit_reader.refill() };
790 debug_assert!(bit_reader.bytes_remaining() >= 8);
792
793 if bits as usize >= state.len_table.bits {
796 lcode[(hold & lmask) as usize]
797 } else {
798 lcode[(bit_reader.hold() & lmask) as usize]
799 }
800 };
801
802 if here.op == 0 {
803 writer.push(here.val as u8);
804 bit_reader.drop_bits(here.bits);
805 here = lcode[(bit_reader.hold() & lmask) as usize];
806
807 if here.op == 0 {
808 writer.push(here.val as u8);
809 bit_reader.drop_bits(here.bits);
810 here = lcode[(bit_reader.hold() & lmask) as usize];
811 }
812 }
813
814 'dolen: loop {
815 bit_reader.drop_bits(here.bits);
816 let op = here.op;
817
818 if op == 0 {
819 writer.push(here.val as u8);
820 } else if op & 16 != 0 {
821 let op = op & MAX_BITS;
822 let mut len = here.val + bit_reader.bits(op as usize) as u16;
823 bit_reader.drop_bits(op);
824
825 here = dcode[(bit_reader.hold() & dmask) as usize];
826
827 if bit_reader.bits_in_buffer() < MAX_BITS + MAX_DIST_EXTRA_BITS {
830 debug_assert!(bit_reader.bytes_remaining() >= 8);
831 unsafe { bit_reader.refill() };
838 }
839
840 'dodist: loop {
841 bit_reader.drop_bits(here.bits);
842 let op = here.op;
843
844 if op & 16 != 0 {
845 let op = op & MAX_BITS;
846 let dist = here.val + bit_reader.bits(op as usize) as u16;
847
848 if INFLATE_STRICT && dist as usize > state.dmax {
849 bad = Some("invalid distance too far back\0");
850 state.mode = Mode::Bad;
851 break 'outer;
852 }
853
854 bit_reader.drop_bits(op);
855
856 let written = writer.len();
858
859 if dist as usize > written {
860 if (dist as usize - written) > state.window.have() {
862 if state.flags.contains(Flags::SANE) {
863 bad = Some("invalid distance too far back\0");
864 state.mode = Mode::Bad;
865 break 'outer;
866 }
867
868 panic!("INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR")
869 }
870
871 let mut op = dist as usize - written;
872 let mut from;
873
874 let window_next = state.window.next();
875
876 if window_next == 0 {
877 from = window_size - op;
884 } else if window_next >= op {
885 from = window_next - op;
887 } else {
888 op -= window_next;
893 from = window_size - op;
894
895 if op < len as usize {
896 len -= op as u16;
900 writer.extend_from_window_back(&state.window, from..from + op);
901 from = 0;
902 op = window_next;
903 }
904 }
905
906 let copy = Ord::min(op, len as usize);
907 writer.extend_from_window_back(&state.window, from..from + copy);
908
909 if op < len as usize {
910 writer.copy_match_back(dist as usize, len as usize - op);
912 }
913 } else if extra_safe {
914 todo!()
915 } else {
916 writer.copy_match_back(dist as usize, len as usize)
917 }
918 } else if (op & 64) == 0 {
919 here = dcode[(here.val + bit_reader.bits(op as usize) as u16) as usize];
921 continue 'dodist;
922 } else {
923 bad = Some("invalid distance code\0");
924 state.mode = Mode::Bad;
925 break 'outer;
926 }
927
928 break 'dodist;
929 }
930 } else if (op & 64) == 0 {
931 here = lcode[(here.val + bit_reader.bits(op as usize) as u16) as usize];
933 continue 'dolen;
934 } else if op & 32 != 0 {
935 state.mode = Mode::Type;
937 break 'outer;
938 } else {
939 bad = Some("invalid literal/length code\0");
940 state.mode = Mode::Bad;
941 break 'outer;
942 }
943
944 break 'dolen;
945 }
946
947 let remaining = bit_reader.bytes_remaining();
949 if remaining >= INFLATE_FAST_MIN_HAVE && writer.remaining() >= INFLATE_FAST_MIN_LEFT {
950 continue;
951 }
952
953 break 'outer;
954 }
955
956 bit_reader.return_unused_bytes();
958
959 state.bit_reader = bit_reader;
960 state.writer = writer;
961
962 if let Some(error_message) = bad {
963 debug_assert!(matches!(state.mode, Mode::Bad));
964 state.bad(error_message);
965 }
966}
967
968pub fn back_end<'a>(strm: &'a mut InflateStream<'a>) {
969 let _ = core::mem::replace(&mut strm.state.window, Window::empty());
971 crate::inflate::end(strm);
972}