Coverage Report

Created: 2026-10-28 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zlib-rs-0.6.8/src/inflate/infback.rs
Line
Count
Source
1
use core::ffi::c_void;
2
use core::marker::PhantomData;
3
4
use crate::allocate::Allocator;
5
use crate::c_api::{in_func, internal_state, out_func};
6
use crate::inflate::bitreader::BitReader;
7
use crate::inflate::inftrees::{inflate_table, CodeType, InflateTable};
8
use 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
};
12
use crate::traceln;
13
use crate::{c_api::z_stream, inflate::writer::Writer, ReturnCode};
14
use crate::{MAX_WBITS, MIN_WBITS};
15
16
/// Initialize the stream in an inflate state
17
0
pub fn back_init(stream: &mut z_stream, config: InflateConfig, window: Window) -> ReturnCode {
18
0
    assert_eq!(1 << config.window_bits, window.buffer_size());
19
20
0
    if !(MIN_WBITS..=MAX_WBITS).contains(&config.window_bits) {
21
0
        return ReturnCode::StreamError as _;
22
0
    }
23
24
0
    stream.msg = core::ptr::null_mut();
25
26
    // for safety we must really make sure that alloc and free are consistent
27
    // this is a (slight) deviation from stock zlib. In this crate we pick the rust
28
    // allocator as the default, but `libz-rs-sys` configures the C allocator
29
    #[cfg(feature = "rust-allocator")]
30
0
    if stream.zalloc.is_none() || stream.zfree.is_none() {
31
0
        stream.configure_default_rust_allocator()
32
0
    }
33
34
    #[cfg(feature = "c-allocator")]
35
    if stream.zalloc.is_none() || stream.zfree.is_none() {
36
        stream.configure_default_c_allocator()
37
    }
38
39
0
    if stream.zalloc.is_none() || stream.zfree.is_none() {
40
0
        return ReturnCode::StreamError;
41
0
    }
42
43
0
    let mut state = State::new(&[], Writer::new(&mut []));
44
45
    // TODO this can change depending on the used/supported SIMD instructions
46
0
    state.chunksize = 32;
47
48
0
    let alloc = Allocator {
49
0
        zalloc: stream.zalloc.unwrap(),
50
0
        zfree: stream.zfree.unwrap(),
51
0
        opaque: stream.opaque,
52
0
        _marker: PhantomData,
53
0
    };
54
0
    let allocs = InflateAllocOffsets::new();
55
56
0
    let Some(allocation_start) = alloc.allocate_slice_raw::<u8>(allocs.total_size) else {
57
0
        return ReturnCode::MemError;
58
    };
59
60
0
    let address = allocation_start.as_ptr() as usize;
61
0
    let align_offset = address.next_multiple_of(64) - address;
62
0
    let buf = unsafe { allocation_start.as_ptr().add(align_offset) };
63
64
    // NOTE: the window part of the allocation is ignored in this case.
65
0
    state.window = window;
66
67
0
    let state_allocation = unsafe { buf.add(allocs.state_pos).cast::<State>() };
68
0
    unsafe { state_allocation.write(state) };
69
0
    stream.state = state_allocation.cast::<internal_state>();
70
71
    // SAFETY: we've correctly initialized the stream to be an InflateStream
72
0
    let Some(stream) = (unsafe { InflateStream::from_stream_mut(stream) }) else {
73
0
        return ReturnCode::StreamError;
74
    };
75
76
0
    stream.state.allocation_start = allocation_start.as_ptr();
77
0
    stream.state.total_allocation_size = allocs.total_size;
78
79
0
    stream.state.wbits = config.window_bits as u8;
80
0
    stream.state.flags.update(Flags::SANE, true);
81
82
0
    ReturnCode::Ok
83
0
}
84
85
0
pub unsafe fn back(
86
0
    strm: &mut InflateStream,
87
0
    in_: in_func,
88
0
    in_desc: *mut c_void,
89
0
    out: out_func,
90
0
    out_desc: *mut c_void,
91
0
) -> ReturnCode {
92
    let mut ret;
93
94
    /* Reset the state */
95
0
    strm.msg = core::ptr::null_mut();
96
0
    strm.state.mode = Mode::Type;
97
0
    strm.state.flags.update(Flags::IS_LAST_BLOCK, false);
98
0
    strm.state.window.clear();
99
100
0
    let mut next = strm.next_in.cast_const();
101
0
    let mut have = if !next.is_null() { strm.avail_in } else { 0 };
102
0
    let mut hold = 0;
103
0
    let mut bits = 0u8;
104
0
    let mut put = strm.state.window.as_mut_ptr();
105
0
    let mut left = strm.state.window.buffer_size();
106
107
0
    let state = &mut strm.state;
108
109
    'inf_leave: loop {
110
        macro_rules! initbits {
111
            () => {
112
                hold = 0;
113
                bits = 0;
114
            };
115
        }
116
117
        macro_rules! bytebits {
118
            () => {
119
                hold >>= bits & 7;
120
                bits -= bits & 7;
121
            };
122
        }
123
124
        macro_rules! dropbits {
125
            ($n:expr) => {
126
                hold >>= $n;
127
                bits -= $n;
128
            };
129
        }
130
131
        macro_rules! bits {
132
            ($n:expr) => {
133
                hold & ((1 << $n) - 1)
134
            };
135
        }
136
137
        macro_rules! needbits {
138
            ($n:expr) => {
139
                while usize::from(bits) < $n {
140
                    pullbyte!();
141
                }
142
            };
143
        }
144
145
        macro_rules! pull {
146
            () => {
147
                if have == 0 {
148
                    have = unsafe { in_(in_desc, &mut next) };
149
                    if have == 0 {
150
                        #[allow(unused_assignments)]
151
                        {
152
                            next = core::ptr::null();
153
                        }
154
                        ret = ReturnCode::BufError;
155
                        break 'inf_leave;
156
                    }
157
                }
158
            };
159
        }
160
161
        macro_rules! pullbyte {
162
            () => {
163
                pull!();
164
                have -= 1;
165
                hold += (unsafe { *next as u64 }) << bits;
166
                next = unsafe { next.add(1) };
167
                bits += 8;
168
            };
169
        }
170
171
        macro_rules! room {
172
            () => {
173
                if left == 0 {
174
                    left = state.window.buffer_size();
175
                    put = state.window.as_mut_ptr();
176
177
                    unsafe { state.window.set_have(left) };
178
179
                    if unsafe { out(out_desc, put, left as u32) } != 0 {
180
                        ret = ReturnCode::BufError;
181
                        break 'inf_leave;
182
                    }
183
                }
184
            };
185
        }
186
187
0
        match state.mode {
188
            Mode::Type => {
189
0
                if state.flags.contains(Flags::IS_LAST_BLOCK) {
190
0
                    bytebits!();
191
0
                    state.mode = Mode::Done;
192
0
                    continue;
193
0
                }
194
195
0
                needbits!(3);
196
197
0
                let last = bits!(1) != 0;
198
0
                state.flags.update(Flags::IS_LAST_BLOCK, last);
199
0
                dropbits!(1);
200
201
0
                match bits!(2) {
202
                    0b00 => {
203
                        traceln!("inflate:     stored block (last = {last})");
204
205
0
                        dropbits!(2);
206
0
                        state.mode = Mode::Stored;
207
0
                        continue;
208
                    }
209
                    0b01 => {
210
                        traceln!("inflate:     fixed codes block (last = {last})");
211
212
0
                        state.len_table = Table {
213
0
                            codes: Codes::Fixed,
214
0
                            bits: 9,
215
0
                        };
216
217
0
                        state.dist_table = Table {
218
0
                            codes: Codes::Fixed,
219
0
                            bits: 5,
220
0
                        };
221
222
0
                        dropbits!(2);
223
0
                        state.mode = Mode::Len;
224
0
                        continue;
225
                    }
226
                    0b10 => {
227
                        traceln!("inflate:     dynamic codes block (last = {last})");
228
229
0
                        dropbits!(2);
230
0
                        state.mode = Mode::Table;
231
0
                        continue;
232
                    }
233
                    0b11 => {
234
                        traceln!("inflate:     invalid block type");
235
236
0
                        dropbits!(2);
237
0
                        state.mode = Mode::Bad;
238
0
                        state.bad("invalid block type\0");
239
0
                        continue;
240
                    }
241
                    _ => {
242
                        // LLVM will optimize this branch away
243
0
                        unreachable!("BitReader::bits(2) only yields a value of two bits, so this match is already exhaustive")
244
                    }
245
                }
246
            }
247
            Mode::Stored => {
248
0
                bytebits!();
249
0
                needbits!(32);
250
251
0
                if hold as u16 != !((hold >> 16) as u16) {
252
0
                    state.mode = Mode::Bad;
253
0
                    state.bad("invalid stored block lengths\0");
254
0
                    continue;
255
0
                }
256
257
0
                state.length = hold as usize & 0xFFFF;
258
                traceln!("inflate:     stored length {}", state.length);
259
260
0
                initbits!();
261
262
                /* copy stored block from input to output */
263
0
                while state.length != 0 {
264
0
                    let mut copy = state.length;
265
266
0
                    pull!();
267
0
                    room!();
268
269
0
                    copy = Ord::min(copy, have as usize);
270
0
                    copy = Ord::min(copy, left);
271
272
0
                    unsafe { core::ptr::copy(next, put, copy) };
273
274
0
                    have -= copy as u32;
275
0
                    next = unsafe { next.add(copy) };
276
277
0
                    left -= copy;
278
0
                    put = unsafe { put.add(copy) };
279
280
0
                    state.length -= copy;
281
                }
282
283
0
                state.mode = Mode::Type;
284
0
                continue;
285
            }
286
            Mode::Table => {
287
0
                needbits!(14);
288
0
                state.nlen = bits!(5) as usize + 257;
289
0
                dropbits!(5);
290
0
                state.ndist = bits!(5) as usize + 1;
291
0
                dropbits!(5);
292
0
                state.ncode = bits!(4) as usize + 4;
293
0
                dropbits!(4);
294
295
                // TODO pkzit_bug_workaround
296
0
                if state.nlen > 286 || state.ndist > 30 {
297
0
                    state.mode = Mode::Bad;
298
0
                    state.bad("too many length or distance symbols\0");
299
0
                    continue;
300
0
                }
301
302
                traceln!("inflate:       table sizes ok");
303
0
                state.have = 0;
304
305
                // permutation of code lengths ;
306
                const ORDER: [u8; 19] = [
307
                    16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
308
                ];
309
310
0
                while state.have < state.ncode {
311
0
                    needbits!(3);
312
0
                    state.lens[usize::from(ORDER[state.have])] = bits!(3) as u16;
313
0
                    state.have += 1;
314
0
                    dropbits!(3);
315
                }
316
317
0
                while state.have < 19 {
318
0
                    state.lens[usize::from(ORDER[state.have])] = 0;
319
0
                    state.have += 1;
320
0
                }
321
322
0
                let InflateTable::Success { root, used } = inflate_table(
323
0
                    CodeType::Codes,
324
0
                    &state.lens[..19],
325
0
                    &mut state.codes_codes,
326
0
                    7,
327
0
                    &mut state.work,
328
0
                ) else {
329
0
                    state.mode = Mode::Bad;
330
0
                    state.bad("invalid code lengths set\0");
331
0
                    continue;
332
                };
333
334
0
                state.next = used;
335
0
                state.len_table.codes = Codes::Codes;
336
0
                state.len_table.bits = root;
337
338
                traceln!("inflate:       table sizes ok");
339
0
                state.have = 0;
340
341
0
                while state.have < state.nlen + state.ndist {
342
0
                    let here = loop {
343
0
                        let here = state.len_table_get(bits!(state.len_table.bits) as usize);
344
0
                        if here.bits <= bits {
345
0
                            break here;
346
0
                        }
347
348
0
                        pullbyte!();
349
                    };
350
351
0
                    let here_bits = here.bits;
352
353
0
                    match here.val {
354
0
                        0..=15 => {
355
0
                            dropbits!(here_bits);
356
0
                            state.lens[state.have] = here.val;
357
0
                            state.have += 1;
358
0
                        }
359
                        16 => {
360
0
                            needbits!(usize::from(here_bits) + 2);
361
0
                            dropbits!(here_bits);
362
0
                            if state.have == 0 {
363
0
                                state.mode = Mode::Bad;
364
0
                                state.bad("invalid bit length repeat\0");
365
0
                                continue 'inf_leave;
366
0
                            }
367
368
0
                            let len = state.lens[state.have - 1];
369
0
                            let copy = 3 + bits!(2) as usize;
370
0
                            dropbits!(2);
371
372
0
                            if state.have + copy > state.nlen + state.ndist {
373
0
                                state.mode = Mode::Bad;
374
0
                                state.bad("invalid bit length repeat\0");
375
0
                                continue 'inf_leave;
376
0
                            }
377
378
0
                            state.lens[state.have..][..copy].fill(len);
379
0
                            state.have += copy;
380
                        }
381
                        17 => {
382
0
                            needbits!(usize::from(here_bits) + 3);
383
0
                            dropbits!(here_bits);
384
0
                            let copy = 3 + bits!(3) as usize;
385
0
                            dropbits!(3);
386
387
0
                            if state.have + copy > state.nlen + state.ndist {
388
0
                                state.mode = Mode::Bad;
389
0
                                state.bad("invalid bit length repeat\0");
390
0
                                continue 'inf_leave;
391
0
                            }
392
393
0
                            state.lens[state.have..][..copy].fill(0);
394
0
                            state.have += copy;
395
                        }
396
0
                        18.. => {
397
0
                            needbits!(usize::from(here_bits) + 7);
398
0
                            dropbits!(here_bits);
399
0
                            let copy = 11 + bits!(7) as usize;
400
0
                            dropbits!(7);
401
402
0
                            if state.have + copy > state.nlen + state.ndist {
403
0
                                state.mode = Mode::Bad;
404
0
                                state.bad("invalid bit length repeat\0");
405
0
                                continue 'inf_leave;
406
0
                            }
407
408
0
                            state.lens[state.have..][..copy].fill(0);
409
0
                            state.have += copy;
410
                        }
411
                    }
412
                }
413
414
                // check for end-of-block code (better have one)
415
0
                if state.lens[256] == 0 {
416
0
                    state.mode = Mode::Bad;
417
0
                    state.bad("invalid code -- missing end-of-block\0");
418
0
                    continue 'inf_leave;
419
0
                }
420
421
                // build code tables
422
423
0
                let InflateTable::Success { root, used } = inflate_table(
424
0
                    CodeType::Lens,
425
0
                    &state.lens[..state.nlen],
426
0
                    &mut state.len_codes,
427
0
                    10,
428
0
                    &mut state.work,
429
0
                ) else {
430
0
                    state.mode = Mode::Bad;
431
0
                    state.bad("invalid literal/lengths set\0");
432
0
                    continue 'inf_leave;
433
                };
434
435
0
                state.len_table.codes = Codes::Len;
436
0
                state.len_table.bits = root;
437
0
                state.next = used;
438
439
0
                let InflateTable::Success { root, used } = inflate_table(
440
0
                    CodeType::Dists,
441
0
                    &state.lens[state.nlen..][..state.ndist],
442
0
                    &mut state.dist_codes,
443
0
                    9,
444
0
                    &mut state.work,
445
0
                ) else {
446
0
                    state.mode = Mode::Bad;
447
0
                    state.bad("invalid distances set\0");
448
0
                    continue 'inf_leave;
449
                };
450
451
0
                state.dist_table.bits = root;
452
0
                state.dist_table.codes = Codes::Dist;
453
0
                state.next += used;
454
455
0
                state.mode = Mode::Len;
456
            }
457
            Mode::Len => {
458
0
                if (have as usize) >= INFLATE_FAST_MIN_HAVE && left >= INFLATE_FAST_MIN_LEFT {
459
0
                    let mut bit_reader = BitReader::new(&[]);
460
0
                    unsafe { bit_reader.update_slice(next, have as usize) };
461
0
                    bit_reader.prime(bits, hold);
462
463
0
                    state.bit_reader = bit_reader;
464
0
                    state.writer = unsafe {
465
0
                        Writer::new_uninit_raw(
466
0
                            put.wrapping_sub(state.window.buffer_size() - left),
467
0
                            state.window.buffer_size() - left,
468
0
                            state.window.buffer_size(),
469
0
                        )
470
0
                    };
471
472
0
                    if state.window.have() < state.window.buffer_size() {
473
0
                        unsafe { state.window.set_have(state.window.buffer_size() - left) };
474
0
                    }
475
476
0
                    unsafe { inflate_fast_back(state) };
477
478
0
                    hold = state.bit_reader.hold();
479
0
                    bits = state.bit_reader.bits_in_buffer();
480
481
0
                    next = state.bit_reader.as_ptr();
482
0
                    have = state.bit_reader.bytes_remaining() as u32;
483
484
0
                    put = state.writer.next_out().cast();
485
0
                    left = state.writer.remaining();
486
487
0
                    continue 'inf_leave;
488
0
                }
489
490
0
                let len_table = match state.len_table.codes {
491
0
                    Codes::Fixed => &crate::inflate::inffixed_tbl::LENFIX[..],
492
0
                    Codes::Codes => &state.codes_codes,
493
0
                    Codes::Len => &state.len_codes,
494
0
                    Codes::Dist => &state.dist_codes,
495
                };
496
497
                // get a literal, length, or end-of-block code
498
                let mut here;
499
                loop {
500
0
                    here = len_table[bits!(state.len_table.bits) as usize];
501
502
0
                    if here.bits <= bits {
503
0
                        break;
504
0
                    }
505
506
0
                    pullbyte!();
507
                }
508
509
0
                if here.op != 0 && here.op & 0xf0 == 0 {
510
0
                    let last = here;
511
                    loop {
512
0
                        let tmp = bits!((last.bits + last.op) as usize) as u16;
513
0
                        here = len_table[(last.val + (tmp >> last.bits)) as usize];
514
0
                        if last.bits + here.bits <= bits {
515
0
                            break;
516
0
                        }
517
518
0
                        pullbyte!();
519
                    }
520
521
0
                    dropbits!(last.bits);
522
0
                }
523
524
0
                dropbits!(here.bits);
525
0
                state.length = here.val as usize;
526
527
0
                if here.op == 0 {
528
0
                    if here.val >= 0x20 && here.val < 0x7f {
529
0
                        traceln!("inflate:         literal '{}'", here.val as u8 as char);
530
0
                    } else {
531
0
                        traceln!("inflate:         literal {:#04x}", here.val);
532
0
                    }
533
0
                    room!();
534
535
                    unsafe {
536
0
                        *put = state.length as u8;
537
0
                        put = put.add(1)
538
                    }
539
0
                    left -= 1;
540
541
0
                    state.mode = Mode::Len;
542
0
                    continue;
543
0
                } else if here.op & 32 != 0 {
544
                    // end of block
545
546
                    traceln!("inflate:         end of block");
547
548
0
                    state.mode = Mode::Type;
549
0
                    continue;
550
0
                } else if here.op & 64 != 0 {
551
0
                    state.mode = Mode::Bad;
552
0
                    state.bad("invalid literal/length code\0");
553
0
                    continue;
554
0
                } else {
555
0
                    // length code
556
0
                    state.extra = (here.op & MAX_BITS) as usize;
557
0
                }
558
559
                // get extra bits, if any
560
0
                if state.extra != 0 {
561
0
                    needbits!(state.extra);
562
0
                    state.length += bits!(state.extra) as usize;
563
0
                    dropbits!(state.extra as u8);
564
0
                }
565
                traceln!("inflate:         length {}", state.length);
566
567
                // get distance code
568
                let mut here;
569
                loop {
570
0
                    here = state.dist_table_get(bits!(state.dist_table.bits) as usize);
571
0
                    if here.bits <= bits {
572
0
                        break;
573
0
                    }
574
575
0
                    pullbyte!();
576
                }
577
578
0
                if here.op & 0xf0 == 0 {
579
0
                    let last = here;
580
581
                    loop {
582
0
                        here = state.dist_table_get(
583
0
                            last.val as usize
584
0
                                + ((bits!((last.bits + last.op) as usize) as usize) >> last.bits),
585
0
                        );
586
587
0
                        if last.bits + here.bits <= bits {
588
0
                            break;
589
0
                        }
590
591
0
                        pullbyte!();
592
                    }
593
594
0
                    dropbits!(last.bits);
595
0
                }
596
597
0
                dropbits!(here.bits);
598
599
0
                if here.op & 64 != 0 {
600
0
                    state.mode = Mode::Bad;
601
0
                    state.bad("invalid distance code\0");
602
0
                    continue 'inf_leave;
603
0
                }
604
605
0
                state.offset = here.val as usize;
606
607
0
                state.extra = (here.op & MAX_BITS) as usize;
608
609
0
                let extra = state.extra;
610
611
0
                if extra > 0 {
612
0
                    needbits!(extra);
613
0
                    state.offset += bits!(extra) as usize;
614
0
                    dropbits!(extra as u8);
615
0
                }
616
617
0
                if INFLATE_STRICT
618
0
                    && state.offset
619
0
                        > state.window.buffer_size()
620
0
                            - (if state.window.have() < state.window.buffer_size() {
621
0
                                left
622
                            } else {
623
0
                                0
624
                            })
625
                {
626
0
                    state.mode = Mode::Bad;
627
0
                    state.bad("invalid distance too far back\0");
628
0
                    continue 'inf_leave;
629
0
                }
630
631
                traceln!("inflate:         distance {}", state.offset);
632
633
                loop {
634
0
                    room!();
635
0
                    let mut copy = state.window.buffer_size() - state.offset;
636
                    let mut from;
637
638
0
                    if copy < left {
639
0
                        from = put.wrapping_add(copy);
640
0
                        copy = left - copy;
641
0
                    } else {
642
0
                        from = put.wrapping_sub(state.offset);
643
0
                        copy = left;
644
0
                    }
645
646
0
                    copy = Ord::min(copy, state.length);
647
0
                    state.length -= copy;
648
0
                    left -= copy;
649
650
0
                    for _ in 0..copy {
651
0
                        unsafe {
652
0
                            *put = *from;
653
0
                            put = put.add(1);
654
0
                            from = from.add(1);
655
0
                        }
656
                    }
657
658
0
                    if state.length == 0 {
659
0
                        break;
660
0
                    }
661
                }
662
663
0
                continue 'inf_leave;
664
            }
665
            Mode::Done => {
666
0
                ret = ReturnCode::StreamEnd;
667
0
                break 'inf_leave;
668
            }
669
            Mode::Bad => {
670
0
                ret = ReturnCode::DataError;
671
0
                break 'inf_leave;
672
            }
673
674
            Mode::Head
675
            | Mode::Flags
676
            | Mode::Time
677
            | Mode::Os
678
            | Mode::ExLen
679
            | Mode::Extra
680
            | Mode::Name
681
            | Mode::Comment
682
            | Mode::HCrc
683
            | Mode::Sync
684
            | Mode::Mem
685
            | Mode::Length
686
            | Mode::TypeDo
687
            | Mode::CopyBlock
688
            | Mode::Check
689
            | Mode::Len_
690
            | Mode::Lit
691
            | Mode::LenExt
692
            | Mode::Dist
693
            | Mode::DistExt
694
            | Mode::Match
695
            | Mode::LenLens
696
            | Mode::CodeLens
697
            | Mode::DictId
698
            | Mode::Dict => {
699
                // All other states should be unreachable, and return StreamError.
700
0
                ret = ReturnCode::StreamError;
701
0
                break 'inf_leave;
702
            }
703
        }
704
    }
705
706
0
    if left < state.window.buffer_size()
707
0
        && unsafe {
708
0
            out(
709
0
                out_desc,
710
0
                state.window.as_mut_ptr(),
711
0
                state.window.buffer_size() as u32 - left as u32,
712
0
            )
713
0
        } != 0
714
0
        && ret == ReturnCode::StreamEnd
715
0
    {
716
0
        ret = ReturnCode::BufError;
717
0
    }
718
719
0
    strm.next_in = next.cast_mut();
720
0
    strm.avail_in = have;
721
722
0
    ret
723
0
}
724
725
#[inline(always)]
726
0
unsafe fn inflate_fast_back(state: &mut State) {
727
0
    let mut bit_reader = BitReader::new(&[]);
728
0
    core::mem::swap(&mut bit_reader, &mut state.bit_reader);
729
0
    debug_assert!(bit_reader.bytes_remaining() >= 15);
730
731
0
    let mut writer = Writer::new(&mut []);
732
0
    core::mem::swap(&mut writer, &mut state.writer);
733
734
0
    let lcode = state.len_table_ref();
735
0
    let dcode = state.dist_table_ref();
736
737
    // IDEA: use const generics for the bits here?
738
0
    let lmask = (1u64 << state.len_table.bits) - 1;
739
0
    let dmask = (1u64 << state.dist_table.bits) - 1;
740
741
    // TODO verify if this is relevant for us
742
0
    let extra_safe = false;
743
744
0
    let window_size = state.window.buffer_size();
745
746
0
    let mut bad = None;
747
748
0
    if bit_reader.bits_in_buffer() < 10 {
749
0
        debug_assert!(bit_reader.bytes_remaining() >= 15);
750
        // Safety: Caller ensured that bit_reader has >= 15 bytes available; refill only needs 8.
751
0
        unsafe { bit_reader.refill() };
752
0
    }
753
    // We had at least 15 bytes in the slice, plus whatever was in the buffer. After filling the
754
    // buffer from the slice, we now have at least 8 bytes remaining in the slice, plus a full buffer.
755
0
    debug_assert!(
756
0
        bit_reader.bytes_remaining() >= 8 && bit_reader.bytes_remaining_including_buffer() >= 15
757
    );
758
759
    'outer: loop {
760
        // This condition is ensured above for the first iteration of the `outer` loop. For
761
        // subsequent iterations, the loop continuation condition is
762
        // `bit_reader.bytes_remaining_including_buffer() > 15`. And because the buffer
763
        // contributes at most 7 bytes to the result of bit_reader.bytes_remaining_including_buffer(),
764
        // that means that the slice contains at least 8 bytes.
765
0
        debug_assert!(
766
0
            bit_reader.bytes_remaining() >= 8
767
0
                && bit_reader.bytes_remaining_including_buffer() >= 15
768
        );
769
770
0
        let mut here = {
771
0
            let bits = bit_reader.bits_in_buffer();
772
0
            let hold = bit_reader.hold();
773
774
            // Safety: As described in the comments for the debug_assert at the start of
775
            // the `outer` loop, it is guaranteed that `bit_reader.bytes_remaining() >= 8` here,
776
            // which satisfies the safety precondition for `refill`. And, because the total
777
            // number of bytes in `bit_reader`'s buffer plus its slice is at least 15, and
778
            // `refill` moves at most 7 bytes from the slice to the buffer, the slice will still
779
            // contain at least 8 bytes after this `refill` call.
780
0
            unsafe { bit_reader.refill() };
781
            // After the refill, there will be at least 8 bytes left in the bit_reader's slice.
782
0
            debug_assert!(bit_reader.bytes_remaining() >= 8);
783
784
            // in most cases, the read can be interleaved with the logic
785
            // based on benchmarks this matters in practice. wild.
786
0
            if bits as usize >= state.len_table.bits {
787
0
                lcode[(hold & lmask) as usize]
788
            } else {
789
0
                lcode[(bit_reader.hold() & lmask) as usize]
790
            }
791
        };
792
793
0
        if here.op == 0 {
794
0
            writer.push(here.val as u8);
795
0
            bit_reader.drop_bits(here.bits);
796
0
            here = lcode[(bit_reader.hold() & lmask) as usize];
797
798
0
            if here.op == 0 {
799
0
                writer.push(here.val as u8);
800
0
                bit_reader.drop_bits(here.bits);
801
0
                here = lcode[(bit_reader.hold() & lmask) as usize];
802
0
            }
803
0
        }
804
805
        'dolen: loop {
806
0
            bit_reader.drop_bits(here.bits);
807
0
            let op = here.op;
808
809
0
            if op == 0 {
810
0
                writer.push(here.val as u8);
811
0
            } else if op & 16 != 0 {
812
0
                let op = op & MAX_BITS;
813
0
                let mut len = here.val + bit_reader.bits(op as usize) as u16;
814
0
                bit_reader.drop_bits(op);
815
816
0
                here = dcode[(bit_reader.hold() & dmask) as usize];
817
818
                // we have two fast-path loads: 10+10 + 15+5 = 40,
819
                // but we may need to refill here in the worst case
820
0
                if bit_reader.bits_in_buffer() < MAX_BITS + MAX_DIST_EXTRA_BITS {
821
0
                    debug_assert!(bit_reader.bytes_remaining() >= 8);
822
                    // Safety: On the first iteration of the `dolen` loop, we can rely on the
823
                    // invariant documented for the previous `refill` call above: after that
824
                    // operation, `bit_reader.bytes_remining >= 8`, which satisfies the safety
825
                    // precondition for this call. For subsequent iterations, this invariant
826
                    // remains true because nothing else within the `dolen` loop consumes data
827
                    // from the slice.
828
0
                    unsafe { bit_reader.refill() };
829
0
                }
830
831
                'dodist: loop {
832
0
                    bit_reader.drop_bits(here.bits);
833
0
                    let op = here.op;
834
835
0
                    if op & 16 != 0 {
836
0
                        let op = op & MAX_BITS;
837
0
                        let dist = here.val + bit_reader.bits(op as usize) as u16;
838
839
0
                        if INFLATE_STRICT && dist as usize > state.dmax {
840
0
                            bad = Some("invalid distance too far back\0");
841
0
                            state.mode = Mode::Bad;
842
0
                            break 'outer;
843
0
                        }
844
845
0
                        bit_reader.drop_bits(op);
846
847
                        // max distance in output
848
0
                        let written = writer.len();
849
850
0
                        if dist as usize > written {
851
                            // copy fropm the window
852
0
                            if (dist as usize - written) > state.window.have() {
853
0
                                if state.flags.contains(Flags::SANE) {
854
0
                                    bad = Some("invalid distance too far back\0");
855
0
                                    state.mode = Mode::Bad;
856
0
                                    break 'outer;
857
0
                                }
858
859
0
                                panic!("INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR")
860
0
                            }
861
862
0
                            let mut op = dist as usize - written;
863
                            let mut from;
864
865
0
                            let window_next = state.window.next();
866
867
0
                            if window_next == 0 {
868
0
                                // This case is hit when the window has just wrapped around
869
0
                                // by logic in `Window::extend`. It is special-cased because
870
0
                                // apparently this is quite common.
871
0
                                //
872
0
                                // the match is at the end of the window, even though the next
873
0
                                // position has now wrapped around.
874
0
                                from = window_size - op;
875
0
                            } else if window_next >= op {
876
0
                                // the standard case: a contiguous copy from the window, no wrapping
877
0
                                from = window_next - op;
878
0
                            } else {
879
                                // This case is hit when the window has recently wrapped around
880
                                // by logic in `Window::extend`.
881
                                //
882
                                // The match is (partially) at the end of the window
883
0
                                op -= window_next;
884
0
                                from = window_size - op;
885
886
0
                                if op < len as usize {
887
0
                                    // This case is hit when part of the match is at the end of the
888
0
                                    // window, and part of it has wrapped around to the start. Copy
889
0
                                    // the end section here, the start section will be copied below.
890
0
                                    len -= op as u16;
891
0
                                    writer.extend_from_window_back(&state.window, from..from + op);
892
0
                                    from = 0;
893
0
                                    op = window_next;
894
0
                                }
895
                            }
896
897
0
                            let copy = Ord::min(op, len as usize);
898
0
                            writer.extend_from_window_back(&state.window, from..from + copy);
899
900
0
                            if op < len as usize {
901
0
                                // here we need some bytes from the output itself
902
0
                                writer.copy_match_back(dist as usize, len as usize - op);
903
0
                            }
904
0
                        } else if extra_safe {
905
0
                            todo!()
906
                        } else {
907
0
                            writer.copy_match_back(dist as usize, len as usize)
908
                        }
909
0
                    } else if (op & 64) == 0 {
910
                        // 2nd level distance code
911
0
                        here = dcode[(here.val + bit_reader.bits(op as usize) as u16) as usize];
912
0
                        continue 'dodist;
913
                    } else {
914
0
                        bad = Some("invalid distance code\0");
915
0
                        state.mode = Mode::Bad;
916
0
                        break 'outer;
917
                    }
918
919
0
                    break 'dodist;
920
                }
921
0
            } else if (op & 64) == 0 {
922
                // 2nd level length code
923
0
                here = lcode[(here.val + bit_reader.bits(op as usize) as u16) as usize];
924
0
                continue 'dolen;
925
0
            } else if op & 32 != 0 {
926
                // end of block
927
0
                state.mode = Mode::Type;
928
0
                break 'outer;
929
            } else {
930
0
                bad = Some("invalid literal/length code\0");
931
0
                state.mode = Mode::Bad;
932
0
                break 'outer;
933
            }
934
935
0
            break 'dolen;
936
        }
937
938
        // For normal `inflate`, include the bits in the bit_reader buffer in the count of available bytes.
939
0
        let remaining = bit_reader.bytes_remaining();
940
0
        if remaining >= INFLATE_FAST_MIN_HAVE && writer.remaining() >= INFLATE_FAST_MIN_LEFT {
941
0
            continue;
942
0
        }
943
944
0
        break 'outer;
945
    }
946
947
    // return unused bytes (on entry, bits < 8, so in won't go too far back)
948
0
    bit_reader.return_unused_bytes();
949
950
0
    state.bit_reader = bit_reader;
951
0
    state.writer = writer;
952
953
0
    if let Some(error_message) = bad {
954
0
        debug_assert!(matches!(state.mode, Mode::Bad));
955
0
        state.bad(error_message);
956
0
    }
957
0
}
958
959
0
pub fn back_end<'a>(strm: &'a mut InflateStream<'a>) {
960
    // With infback the window is user-supplied, so we mustn't try to free it.
961
0
    let _ = core::mem::replace(&mut strm.state.window, Window::empty());
962
0
    crate::inflate::end(strm);
963
0
}