zlib_rs/inflate/
infback.rs

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
25/// Initialize the stream in an inflate state
26pub 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    // for safety we must really make sure that alloc and free are consistent
32    // this is a (slight) deviation from stock zlib. In this crate we pick the rust
33    // allocator as the default, but `libz-rs-sys` configures the C allocator
34    #[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    // TODO this can change depending on the used/supported SIMD instructions
51    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    // NOTE: the window part of the allocation is ignored in this case.
70    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    // SAFETY: we've correctly initialized the stream to be an InflateStream
77    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    /* Reset the state */
100    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                        // LLVM will optimize this branch away
249                        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                /* copy stored block from input to output */
269                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                // TODO pkzit_bug_workaround
302                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                // permutation of code lengths ;
312                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                // check for end-of-block code (better have one)
422                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                // build code tables
429
430                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                // get a literal, length, or end-of-block code
507                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                    // end of block
554
555                    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                    // length code
565                    state.extra = (here.op & MAX_BITS) as usize;
566                }
567
568                // get extra bits, if any
569                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                // get distance code
577                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                // All other states should be unreachable, and return StreamError.
709                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    // IDEA: use const generics for the bits here?
747    let lmask = (1u64 << state.len_table.bits) - 1;
748    let dmask = (1u64 << state.dist_table.bits) - 1;
749
750    // TODO verify if this is relevant for us
751    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        // Safety: Caller ensured that bit_reader has >= 15 bytes available; refill only needs 8.
760        unsafe { bit_reader.refill() };
761    }
762    // We had at least 15 bytes in the slice, plus whatever was in the buffer. After filling the
763    // buffer from the slice, we now have at least 8 bytes remaining in the slice, plus a full buffer.
764    debug_assert!(
765        bit_reader.bytes_remaining() >= 8 && bit_reader.bytes_remaining_including_buffer() >= 15
766    );
767
768    'outer: loop {
769        // This condition is ensured above for the first iteration of the `outer` loop. For
770        // subsequent iterations, the loop continuation condition is
771        // `bit_reader.bytes_remaining_including_buffer() > 15`. And because the buffer
772        // contributes at most 7 bytes to the result of bit_reader.bytes_remaining_including_buffer(),
773        // that means that the slice contains at least 8 bytes.
774        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            // Safety: As described in the comments for the debug_assert at the start of
784            // the `outer` loop, it is guaranteed that `bit_reader.bytes_remaining() >= 8` here,
785            // which satisfies the safety precondition for `refill`. And, because the total
786            // number of bytes in `bit_reader`'s buffer plus its slice is at least 15, and
787            // `refill` moves at most 7 bytes from the slice to the buffer, the slice will still
788            // contain at least 8 bytes after this `refill` call.
789            unsafe { bit_reader.refill() };
790            // After the refill, there will be at least 8 bytes left in the bit_reader's slice.
791            debug_assert!(bit_reader.bytes_remaining() >= 8);
792
793            // in most cases, the read can be interleaved with the logic
794            // based on benchmarks this matters in practice. wild.
795            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                // we have two fast-path loads: 10+10 + 15+5 = 40,
828                // but we may need to refill here in the worst case
829                if bit_reader.bits_in_buffer() < MAX_BITS + MAX_DIST_EXTRA_BITS {
830                    debug_assert!(bit_reader.bytes_remaining() >= 8);
831                    // Safety: On the first iteration of the `dolen` loop, we can rely on the
832                    // invariant documented for the previous `refill` call above: after that
833                    // operation, `bit_reader.bytes_remining >= 8`, which satisfies the safety
834                    // precondition for this call. For subsequent iterations, this invariant
835                    // remains true because nothing else within the `dolen` loop consumes data
836                    // from the slice.
837                    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                        // max distance in output
857                        let written = writer.len();
858
859                        if dist as usize > written {
860                            // copy fropm the window
861                            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                                // This case is hit when the window has just wrapped around
878                                // by logic in `Window::extend`. It is special-cased because
879                                // apparently this is quite common.
880                                //
881                                // the match is at the end of the window, even though the next
882                                // position has now wrapped around.
883                                from = window_size - op;
884                            } else if window_next >= op {
885                                // the standard case: a contiguous copy from the window, no wrapping
886                                from = window_next - op;
887                            } else {
888                                // This case is hit when the window has recently wrapped around
889                                // by logic in `Window::extend`.
890                                //
891                                // The match is (partially) at the end of the window
892                                op -= window_next;
893                                from = window_size - op;
894
895                                if op < len as usize {
896                                    // This case is hit when part of the match is at the end of the
897                                    // window, and part of it has wrapped around to the start. Copy
898                                    // the end section here, the start section will be copied below.
899                                    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                                // here we need some bytes from the output itself
911                                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                        // 2nd level distance code
920                        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                // 2nd level length code
932                here = lcode[(here.val + bit_reader.bits(op as usize) as u16) as usize];
933                continue 'dolen;
934            } else if op & 32 != 0 {
935                // end of block
936                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        // For normal `inflate`, include the bits in the bit_reader buffer in the count of available bytes.
948        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    // return unused bytes (on entry, bits < 8, so in won't go too far back)
957    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    // With infback the window is user-supplied, so we mustn't try to free it.
970    let _ = core::mem::replace(&mut strm.state.window, Window::empty());
971    crate::inflate::end(strm);
972}