Skip to main content

zlib_rs/
inflate.rs

1#![allow(non_snake_case)] // TODO ultimately remove this
2#![allow(clippy::missing_safety_doc)] // obviously needs to be fixed long-term
3
4use core::ffi::{c_char, c_int, c_long, c_ulong};
5use core::marker::PhantomData;
6use core::mem::MaybeUninit;
7use core::ops::ControlFlow;
8
9mod bitreader;
10mod infback;
11mod inffixed_tbl;
12mod inftrees;
13mod window;
14mod writer;
15
16use crate::allocate::Allocator;
17use crate::c_api::internal_state;
18use crate::cpu_features::CpuFeatures;
19use crate::{
20    adler32::adler32,
21    c_api::{gz_header, z_checksum, z_size, z_stream, Z_DEFLATED},
22    inflate::writer::Writer,
23    traceln, Code, InflateFlush, ReturnCode, DEF_WBITS, MAX_WBITS, MIN_WBITS,
24};
25
26use crate::crc32::{crc32, Crc32Fold};
27
28pub use self::infback::{back, back_end, back_init};
29pub use self::window::Window;
30use self::{
31    bitreader::BitReader,
32    inftrees::{inflate_table, CodeType, InflateTable},
33};
34
35const INFLATE_STRICT: bool = false;
36
37// SAFETY: This struct must have the same layout as [`z_stream`], so that casts and transmutations
38// between the two can work without UB.
39#[repr(C)]
40pub struct InflateStream<'a> {
41    pub(crate) next_in: *mut crate::c_api::Bytef,
42    pub(crate) avail_in: crate::c_api::uInt,
43    pub(crate) total_in: crate::c_api::z_size,
44    pub(crate) next_out: *mut crate::c_api::Bytef,
45    pub(crate) avail_out: crate::c_api::uInt,
46    pub(crate) total_out: crate::c_api::z_size,
47    pub(crate) msg: *mut c_char,
48    pub(crate) state: &'a mut State<'a>,
49    pub(crate) alloc: Allocator<'a>,
50    pub(crate) data_type: c_int,
51    pub(crate) adler: crate::c_api::z_checksum,
52    pub(crate) reserved: crate::c_api::uLong,
53}
54
55unsafe impl Sync for InflateStream<'_> {}
56unsafe impl Send for InflateStream<'_> {}
57
58#[cfg(feature = "__internal-test")]
59#[doc(hidden)]
60pub const INFLATE_STATE_SIZE: usize = core::mem::size_of::<crate::inflate::State>();
61
62#[cfg(feature = "__internal-test")]
63#[doc(hidden)]
64pub unsafe fn set_mode_dict(strm: &mut z_stream) {
65    unsafe {
66        (*(strm.state as *mut State)).mode = Mode::Dict;
67    }
68}
69
70#[cfg(feature = "__internal-test")]
71#[doc(hidden)]
72pub unsafe fn set_mode_sync(strm: *mut z_stream) {
73    unsafe {
74        (*((*strm).state as *mut State)).mode = Mode::Sync;
75    }
76}
77
78impl<'a> InflateStream<'a> {
79    // z_stream and DeflateStream must have the same layout. Do our best to check if this is true.
80    // (imperfect check, but should catch most mistakes.)
81    const _S: () = assert!(core::mem::size_of::<z_stream>() == core::mem::size_of::<Self>());
82    const _A: () = assert!(core::mem::align_of::<z_stream>() == core::mem::align_of::<Self>());
83
84    /// # Safety
85    ///
86    /// Behavior is undefined if any of the following conditions are violated:
87    ///
88    /// - `strm` satisfies the conditions of [`pointer::as_ref`]
89    /// - if not `NULL`, `strm` as initialized using [`init`] or similar
90    ///
91    /// [`pointer::as_ref`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.as_ref
92    #[inline(always)]
93    pub unsafe fn from_stream_ref(strm: *const z_stream) -> Option<&'a Self> {
94        {
95            // Safety: ptr points to a valid value of type z_stream (if non-null)
96            let stream = unsafe { strm.as_ref() }?;
97
98            if stream.zalloc.is_none() || stream.zfree.is_none() {
99                return None;
100            }
101
102            if stream.state.is_null() {
103                return None;
104            }
105        }
106
107        // Safety: InflateStream has an equivalent layout as z_stream
108        unsafe { strm.cast::<InflateStream>().as_ref() }
109    }
110
111    /// # Safety
112    ///
113    /// Behavior is undefined if any of the following conditions are violated:
114    ///
115    /// - `strm` satisfies the conditions of [`pointer::as_mut`]
116    /// - if not `NULL`, `strm` as initialized using [`init`] or similar
117    ///
118    /// [`pointer::as_mut`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.as_mut
119    #[inline(always)]
120    pub unsafe fn from_stream_mut(strm: *mut z_stream) -> Option<&'a mut Self> {
121        {
122            // Safety: ptr points to a valid value of type z_stream (if non-null)
123            let stream = unsafe { strm.as_ref() }?;
124
125            if stream.zalloc.is_none() || stream.zfree.is_none() {
126                return None;
127            }
128
129            if stream.state.is_null() {
130                return None;
131            }
132        }
133
134        // Safety: InflateStream has an equivalent layout as z_stream
135        unsafe { strm.cast::<InflateStream>().as_mut() }
136    }
137
138    fn as_z_stream_mut(&mut self) -> &mut z_stream {
139        // safety: a valid &mut InflateStream is also a valid &mut z_stream
140        unsafe { &mut *(self as *mut _ as *mut z_stream) }
141    }
142
143    pub fn new(config: InflateConfig) -> Self {
144        let mut inner = crate::c_api::z_stream::default();
145
146        let ret = crate::inflate::init(&mut inner, config);
147        assert_eq!(ret, ReturnCode::Ok);
148
149        unsafe { core::mem::transmute(inner) }
150    }
151}
152
153const MAX_BITS: u8 = 15; // maximum number of bits in a code
154const MAX_DIST_EXTRA_BITS: u8 = 13; // maximum number of extra distance bits
155
156/// Decompresses `input` into the provided `output` buffer.
157///
158/// Returns a subslice of `output` containing the decompressed bytes and a
159/// [`ReturnCode`] indicating the result of the operation. Returns [`ReturnCode::BufError`] if
160/// there is insufficient output space.
161///
162/// # Example
163///
164/// ```
165/// # use zlib_rs::*;
166/// # fn foo(compressed: &[u8]) {
167/// let mut buffer = [0u8; 1024];
168/// let (decompressed, rc) = decompress_slice(&mut buffer, compressed, InflateConfig::default());
169/// assert_eq!(rc, ReturnCode::Ok);
170/// # }
171/// ```
172pub fn decompress_slice<'a>(
173    output: &'a mut [u8],
174    input: &[u8],
175    config: InflateConfig,
176) -> (&'a mut [u8], ReturnCode) {
177    // SAFETY: [u8] is also a valid [MaybeUninit<u8>]
178    let output_uninit = unsafe {
179        core::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut MaybeUninit<u8>, output.len())
180    };
181
182    uncompress(output_uninit, input, config)
183}
184
185/// Inflates `source` into `dest`, and writes the final inflated size into `dest_len`.
186pub fn uncompress<'a>(
187    output: &'a mut [MaybeUninit<u8>],
188    input: &[u8],
189    config: InflateConfig,
190) -> (&'a mut [u8], ReturnCode) {
191    let (_consumed, output, ret) = uncompress2(output, input, config);
192    (output, ret)
193}
194
195pub fn uncompress2<'a>(
196    output: &'a mut [MaybeUninit<u8>],
197    input: &[u8],
198    config: InflateConfig,
199) -> (u64, &'a mut [u8], ReturnCode) {
200    let mut dest_len_ptr = output.len() as z_checksum;
201
202    // for detection of incomplete stream when *destLen == 0
203    let mut buf = [0u8];
204
205    let mut left;
206    let mut len = input.len() as u64;
207
208    let dest = if output.is_empty() {
209        left = 1;
210
211        buf.as_mut_ptr()
212    } else {
213        left = output.len() as u64;
214        dest_len_ptr = 0;
215
216        output.as_mut_ptr() as *mut u8
217    };
218
219    let mut stream = z_stream {
220        next_in: input.as_ptr() as *mut u8,
221        avail_in: 0,
222
223        zalloc: None,
224        zfree: None,
225        opaque: core::ptr::null_mut(),
226
227        ..z_stream::default()
228    };
229
230    let err = init(&mut stream, config);
231    if err != ReturnCode::Ok {
232        return (0, &mut [], err);
233    }
234
235    stream.next_out = dest;
236    stream.avail_out = 0;
237
238    let Some(stream) = (unsafe { InflateStream::from_stream_mut(&mut stream) }) else {
239        return (0, &mut [], ReturnCode::StreamError);
240    };
241
242    let err = loop {
243        if stream.avail_out == 0 {
244            stream.avail_out = Ord::min(left, u32::MAX as u64) as u32;
245            left -= stream.avail_out as u64;
246        }
247
248        if stream.avail_in == 0 {
249            stream.avail_in = Ord::min(len, u32::MAX as u64) as u32;
250            len -= stream.avail_in as u64;
251        }
252
253        let err = unsafe { inflate(stream, InflateFlush::NoFlush) };
254
255        if err != ReturnCode::Ok {
256            break err;
257        }
258    };
259
260    let consumed = len + u64::from(stream.avail_in);
261    if !output.is_empty() {
262        dest_len_ptr = stream.total_out;
263    } else if stream.total_out != 0 && err == ReturnCode::BufError {
264        left = 1;
265    }
266
267    let avail_out = stream.avail_out;
268
269    end(stream);
270
271    let ret = match err {
272        ReturnCode::StreamEnd => ReturnCode::Ok,
273        ReturnCode::NeedDict => ReturnCode::DataError,
274        ReturnCode::BufError if (left + avail_out as u64) != 0 => ReturnCode::DataError,
275        _ => err,
276    };
277
278    // SAFETY: we have now initialized these bytes
279    let output_slice = unsafe {
280        core::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut u8, dest_len_ptr as usize)
281    };
282
283    (consumed, output_slice, ret)
284}
285
286#[derive(Debug, Clone, Copy)]
287#[repr(u8)]
288pub enum Mode {
289    Head,
290    Flags,
291    Time,
292    Os,
293    ExLen,
294    Extra,
295    Name,
296    Comment,
297    HCrc,
298    Sync,
299    Mem,
300    Length,
301    Type,
302    TypeDo,
303    Stored,
304    CopyBlock,
305    Check,
306    Len_,
307    Len,
308    Lit,
309    LenExt,
310    Dist,
311    DistExt,
312    Match,
313    Table,
314    LenLens,
315    CodeLens,
316    DictId,
317    Dict,
318    Done,
319    Bad,
320}
321
322#[derive(Default, Clone, Copy)]
323#[allow(clippy::enum_variant_names)]
324enum Codes {
325    #[default]
326    Fixed,
327    Codes,
328    Len,
329    Dist,
330}
331
332#[derive(Default, Clone, Copy)]
333struct Table {
334    codes: Codes,
335    bits: usize,
336}
337
338#[derive(Clone, Copy)]
339struct Flags(u8);
340
341impl Default for Flags {
342    fn default() -> Self {
343        Self::SANE
344    }
345}
346
347impl Flags {
348    /// set if currently processing the last block
349    const IS_LAST_BLOCK: Self = Self(0b0000_0001);
350
351    /// set if a custom dictionary was provided
352    const HAVE_DICT: Self = Self(0b0000_0010);
353
354    /// if false, allow invalid distance too far
355    const SANE: Self = Self(0b0000_0100);
356
357    pub(crate) const fn contains(self, other: Self) -> bool {
358        debug_assert!(other.0.count_ones() == 1);
359
360        self.0 & other.0 != 0
361    }
362
363    #[inline(always)]
364    pub(crate) fn update(&mut self, other: Self, value: bool) {
365        if value {
366            *self = Self(self.0 | other.0);
367        } else {
368            *self = Self(self.0 & !other.0);
369        }
370    }
371}
372
373#[repr(C, align(64))]
374pub(crate) struct State<'a> {
375    /// Current inflate mode
376    mode: Mode,
377
378    flags: Flags,
379
380    /// log base 2 of requested window size
381    wbits: u8,
382
383    /// bitflag
384    ///
385    /// - bit 0 true if zlib
386    /// - bit 1 true if gzip
387    /// - bit 2 true to validate check value
388    wrap: u8,
389
390    flush: InflateFlush,
391
392    // allocated window if needed (capacity == 0 if unused)
393    window: Window<'a>,
394
395    //
396    /// number of code length code lengths
397    ncode: usize,
398    /// number of length code lengths
399    nlen: usize,
400    /// number of distance code lengths
401    ndist: usize,
402    /// number of code lengths in lens[]
403    have: usize,
404    /// next available space in codes[]
405    next: usize, // represented as an index, don't want a self-referential structure here
406
407    // IO
408    bit_reader: BitReader<'a>,
409
410    writer: Writer<'a>,
411    total: usize,
412
413    /// length of a block to copy
414    length: usize,
415    /// distance back to copy the string from
416    offset: usize,
417
418    /// extra bits needed
419    extra: usize,
420
421    /// bits back of last unprocessed length/lit
422    back: usize,
423
424    /// initial length of match
425    was: usize,
426
427    /// size of memory copying chunk
428    chunksize: usize,
429
430    in_available: usize,
431    out_available: usize,
432
433    gzip_flags: i32,
434
435    checksum: u32,
436    crc_fold: Crc32Fold,
437
438    error_message: Option<&'static str>,
439
440    /// place to store gzip header if needed
441    head: Option<&'a mut gz_header>,
442    dmax: usize,
443
444    /// table for length/literal codes
445    len_table: Table,
446
447    /// table for dist codes
448    dist_table: Table,
449
450    codes_codes: [Code; crate::ENOUGH_LENS],
451    len_codes: [Code; crate::ENOUGH_LENS],
452    dist_codes: [Code; crate::ENOUGH_DISTS],
453
454    /// temporary storage space for code lengths
455    lens: [u16; 320],
456    /// work area for code table building
457    work: [u16; 288],
458
459    allocation_start: *mut u8,
460    total_allocation_size: usize,
461}
462
463impl<'a> State<'a> {
464    fn new(reader: &'a [u8], writer: Writer<'a>) -> Self {
465        let in_available = reader.len();
466        let out_available = writer.capacity();
467
468        Self {
469            flush: InflateFlush::NoFlush,
470
471            flags: Flags::default(),
472            wrap: 0,
473            mode: Mode::Head,
474            length: 0,
475
476            len_table: Table::default(),
477            dist_table: Table::default(),
478
479            wbits: 0,
480            offset: 0,
481            extra: 0,
482            back: 0,
483            was: 0,
484            chunksize: 0,
485            in_available,
486            out_available,
487
488            bit_reader: BitReader::new(reader),
489
490            writer,
491            total: 0,
492
493            window: Window::empty(),
494            head: None,
495
496            lens: [0u16; 320],
497            work: [0u16; 288],
498
499            ncode: 0,
500            nlen: 0,
501            ndist: 0,
502            have: 0,
503            next: 0,
504
505            error_message: None,
506
507            checksum: 0,
508            crc_fold: Crc32Fold::new(),
509
510            dmax: 0,
511            gzip_flags: 0,
512
513            codes_codes: [Code::default(); crate::ENOUGH_LENS],
514            len_codes: [Code::default(); crate::ENOUGH_LENS],
515            dist_codes: [Code::default(); crate::ENOUGH_DISTS],
516
517            allocation_start: core::ptr::null_mut(),
518            total_allocation_size: 0,
519        }
520    }
521
522    fn len_table_ref(&self) -> &[Code] {
523        match self.len_table.codes {
524            Codes::Fixed => &self::inffixed_tbl::LENFIX,
525            Codes::Codes => &self.codes_codes,
526            Codes::Len => &self.len_codes,
527            Codes::Dist => &self.dist_codes,
528        }
529    }
530
531    fn dist_table_ref(&self) -> &[Code] {
532        match self.dist_table.codes {
533            Codes::Fixed => &self::inffixed_tbl::DISTFIX,
534            Codes::Codes => &self.codes_codes,
535            Codes::Len => &self.len_codes,
536            Codes::Dist => &self.dist_codes,
537        }
538    }
539
540    fn len_table_get(&self, index: usize) -> Code {
541        self.len_table_ref()[index]
542    }
543
544    fn dist_table_get(&self, index: usize) -> Code {
545        self.dist_table_ref()[index]
546    }
547}
548
549// swaps endianness
550const fn zswap32(q: u32) -> u32 {
551    u32::from_be(q.to_le())
552}
553
554const INFLATE_FAST_MIN_HAVE: usize = 15;
555const INFLATE_FAST_MIN_LEFT: usize = 260;
556
557impl State<'_> {
558    // This logic is split into its own function for two reasons
559    //
560    // - We get to load state to the stack; doing this in all cases is expensive, but doing it just
561    //      for Len and related states is very helpful.
562    // - The `-Cllvm-args=-enable-dfa-jump-thread` llvm arg is able to optimize this function, but
563    //      not the entirity of `dispatch`. We get a massive boost from that pass.
564    //
565    // It unfortunately does duplicate the code for some of the states; deduplicating it by having
566    // more of the states call this function is slower.
567    fn len_and_friends(&mut self) -> ControlFlow<ReturnCode, ()> {
568        let avail_in = self.bit_reader.bytes_remaining();
569        let avail_out = self.writer.remaining();
570
571        if avail_in >= INFLATE_FAST_MIN_HAVE && avail_out >= INFLATE_FAST_MIN_LEFT {
572            // SAFETY: INFLATE_FAST_MIN_HAVE is enough bytes remaining to satisfy the precondition.
573            unsafe { inflate_fast_help(self, 0) };
574            match self.mode {
575                Mode::Len => {}
576                _ => return ControlFlow::Continue(()),
577            }
578        }
579
580        let mut mode;
581        let mut writer;
582        let mut bit_reader;
583
584        macro_rules! load {
585            () => {
586                mode = self.mode;
587                writer = core::mem::replace(&mut self.writer, Writer::new(&mut []));
588                bit_reader = self.bit_reader;
589            };
590        }
591
592        macro_rules! restore {
593            () => {
594                self.mode = mode;
595                self.writer = writer;
596                self.bit_reader = bit_reader;
597            };
598        }
599
600        load!();
601
602        let len_table = match self.len_table.codes {
603            Codes::Fixed => &self::inffixed_tbl::LENFIX[..],
604            Codes::Codes => &self.codes_codes,
605            Codes::Len => &self.len_codes,
606            Codes::Dist => &self.dist_codes,
607        };
608
609        let dist_table = match self.dist_table.codes {
610            Codes::Fixed => &self::inffixed_tbl::DISTFIX[..],
611            Codes::Codes => &self.codes_codes,
612            Codes::Len => &self.len_codes,
613            Codes::Dist => &self.dist_codes,
614        };
615
616        loop {
617            mode = 'top: {
618                match mode {
619                    Mode::Len => {
620                        let avail_in = bit_reader.bytes_remaining();
621                        let avail_out = writer.remaining();
622
623                        // INFLATE_FAST_MIN_LEFT is important. It makes sure there is at least 32 bytes of free
624                        // space available. This means for many SIMD operations we don't need to process a
625                        // remainder; we just copy blindly, and a later operation will overwrite the extra copied
626                        // bytes
627                        if avail_in >= INFLATE_FAST_MIN_HAVE && avail_out >= INFLATE_FAST_MIN_LEFT {
628                            restore!();
629                            // SAFETY: INFLATE_FAST_MIN_HAVE >= 15.
630                            // Note that the restore macro does not do anything that would
631                            // reduce the number of bytes available.
632                            unsafe { inflate_fast_help(self, 0) };
633                            return ControlFlow::Continue(());
634                        }
635
636                        self.back = 0;
637
638                        // get a literal, length, or end-of-block code
639                        let mut here;
640                        loop {
641                            let bits = bit_reader.bits(self.len_table.bits);
642                            here = len_table[bits as usize];
643
644                            if here.bits <= bit_reader.bits_in_buffer() {
645                                break;
646                            }
647
648                            if let Err(return_code) = bit_reader.pull_byte() {
649                                restore!();
650                                return ControlFlow::Break(return_code);
651                            };
652                        }
653
654                        if here.op != 0 && here.op & 0xf0 == 0 {
655                            let last = here;
656                            loop {
657                                let bits = bit_reader.bits((last.bits + last.op) as usize) as u16;
658                                here = len_table[(last.val + (bits >> last.bits)) as usize];
659                                if last.bits + here.bits <= bit_reader.bits_in_buffer() {
660                                    break;
661                                }
662
663                                if let Err(return_code) = bit_reader.pull_byte() {
664                                    restore!();
665                                    return ControlFlow::Break(return_code);
666                                };
667                            }
668
669                            bit_reader.drop_bits(last.bits);
670                            self.back += last.bits as usize;
671                        }
672
673                        bit_reader.drop_bits(here.bits);
674                        self.back += here.bits as usize;
675                        self.length = here.val as usize;
676
677                        if here.op == 0 {
678                            break 'top Mode::Lit;
679                        } else if here.op & 32 != 0 {
680                            // end of block
681
682                            traceln!("inflate:         end of block");
683
684                            self.back = usize::MAX;
685                            mode = Mode::Type;
686
687                            restore!();
688                            return ControlFlow::Continue(());
689                        } else if here.op & 64 != 0 {
690                            mode = Mode::Bad;
691                            {
692                                restore!();
693                                let this = &mut *self;
694                                let msg: &'static str = "invalid literal/length code\0";
695                                #[cfg(all(feature = "std", test))]
696                                dbg!(msg);
697                                this.error_message = Some(msg);
698                                return ControlFlow::Break(ReturnCode::DataError);
699                            }
700                        } else {
701                            // length code
702                            self.extra = (here.op & MAX_BITS) as usize;
703                            break 'top Mode::LenExt;
704                        }
705                    }
706                    Mode::Lit => {
707                        // NOTE: this branch must be kept in sync with its counterpart in `dispatch`
708                        if writer.is_full() {
709                            restore!();
710                            traceln!("Ok: writer is full ({} bytes)", self.writer.capacity());
711                            return ControlFlow::Break(ReturnCode::Ok);
712                        }
713
714                        writer.push(self.length as u8);
715
716                        break 'top Mode::Len;
717                    }
718                    Mode::LenExt => {
719                        // NOTE: this branch must be kept in sync with its counterpart in `dispatch`
720                        let extra = self.extra;
721
722                        // get extra bits, if any
723                        if extra != 0 {
724                            match bit_reader.need_bits(extra) {
725                                Err(return_code) => {
726                                    restore!();
727                                    return ControlFlow::Break(return_code);
728                                }
729                                Ok(v) => v,
730                            };
731                            self.length += bit_reader.bits(extra) as usize;
732                            bit_reader.drop_bits(extra as u8);
733                            self.back += extra;
734                        }
735
736                        traceln!("inflate: length {}", state.length);
737
738                        self.was = self.length;
739
740                        break 'top Mode::Dist;
741                    }
742                    Mode::Dist => {
743                        // NOTE: this branch must be kept in sync with its counterpart in `dispatch`
744
745                        // get distance code
746                        let mut here;
747                        loop {
748                            let bits = bit_reader.bits(self.dist_table.bits) as usize;
749                            here = dist_table[bits];
750                            if here.bits <= bit_reader.bits_in_buffer() {
751                                break;
752                            }
753
754                            if let Err(return_code) = bit_reader.pull_byte() {
755                                restore!();
756                                return ControlFlow::Break(return_code);
757                            };
758                        }
759
760                        if here.op & 0xf0 == 0 {
761                            let last = here;
762
763                            loop {
764                                let bits = bit_reader.bits((last.bits + last.op) as usize);
765                                here =
766                                    dist_table[last.val as usize + ((bits as usize) >> last.bits)];
767
768                                if last.bits + here.bits <= bit_reader.bits_in_buffer() {
769                                    break;
770                                }
771
772                                if let Err(return_code) = bit_reader.pull_byte() {
773                                    restore!();
774                                    return ControlFlow::Break(return_code);
775                                };
776                            }
777
778                            bit_reader.drop_bits(last.bits);
779                            self.back += last.bits as usize;
780                        }
781
782                        bit_reader.drop_bits(here.bits);
783
784                        if here.op & 64 != 0 {
785                            restore!();
786                            self.mode = Mode::Bad;
787                            return ControlFlow::Break(self.bad("invalid distance code\0"));
788                        }
789
790                        self.offset = here.val as usize;
791
792                        self.extra = (here.op & MAX_BITS) as usize;
793
794                        break 'top Mode::DistExt;
795                    }
796                    Mode::DistExt => {
797                        // NOTE: this branch must be kept in sync with its counterpart in `dispatch`
798                        let extra = self.extra;
799
800                        if extra > 0 {
801                            match bit_reader.need_bits(extra) {
802                                Err(return_code) => {
803                                    restore!();
804                                    return ControlFlow::Break(return_code);
805                                }
806                                Ok(v) => v,
807                            };
808                            self.offset += bit_reader.bits(extra) as usize;
809                            bit_reader.drop_bits(extra as u8);
810                            self.back += extra;
811                        }
812
813                        if INFLATE_STRICT && self.offset > self.dmax {
814                            restore!();
815                            self.mode = Mode::Bad;
816                            return ControlFlow::Break(
817                                self.bad("invalid distance code too far back\0"),
818                            );
819                        }
820
821                        traceln!("inflate: distance {}", state.offset);
822
823                        break 'top Mode::Match;
824                    }
825                    Mode::Match => {
826                        // NOTE: this branch must be kept in sync with its counterpart in `dispatch`
827                        if writer.is_full() {
828                            restore!();
829                            traceln!(
830                                "BufError: writer is full ({} bytes)",
831                                self.writer.capacity()
832                            );
833                            return ControlFlow::Break(ReturnCode::Ok);
834                        }
835
836                        let left = writer.remaining();
837                        let copy = writer.len();
838
839                        let copy = if self.offset > copy {
840                            // copy from window to output
841
842                            let mut copy = self.offset - copy;
843
844                            if copy > self.window.have() {
845                                if self.flags.contains(Flags::SANE) {
846                                    restore!();
847                                    self.mode = Mode::Bad;
848                                    return ControlFlow::Break(
849                                        self.bad("invalid distance too far back\0"),
850                                    );
851                                }
852
853                                // TODO INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
854                                panic!("INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR")
855                            }
856
857                            let wnext = self.window.next();
858                            let wsize = self.window.size();
859
860                            let from = if copy > wnext {
861                                copy -= wnext;
862                                wsize - copy
863                            } else {
864                                wnext - copy
865                            };
866
867                            copy = Ord::min(copy, self.length);
868                            copy = Ord::min(copy, left);
869
870                            writer.extend_from_window(&self.window, from..from + copy);
871
872                            copy
873                        } else {
874                            let copy = Ord::min(self.length, left);
875                            writer.copy_match(self.offset, copy);
876
877                            copy
878                        };
879
880                        self.length -= copy;
881
882                        if self.length == 0 {
883                            break 'top Mode::Len;
884                        } else {
885                            // otherwise it seems to recurse?
886                            // self.match_()
887                            break 'top Mode::Match;
888                        }
889                    }
890                    _ => unsafe { core::hint::unreachable_unchecked() },
891                }
892            }
893        }
894    }
895
896    fn dispatch(&mut self) -> ReturnCode {
897        // Note: All early returns must save mode into self.mode again.
898        let mut mode = self.mode;
899
900        macro_rules! pull_byte {
901            ($self:expr) => {
902                match $self.bit_reader.pull_byte() {
903                    Err(return_code) => {
904                        self.mode = mode;
905                        return $self.inflate_leave(return_code);
906                    }
907                    Ok(_) => (),
908                }
909            };
910        }
911
912        macro_rules! need_bits {
913            ($self:expr, $n:expr) => {
914                match $self.bit_reader.need_bits($n) {
915                    Err(return_code) => {
916                        self.mode = mode;
917                        return $self.inflate_leave(return_code);
918                    }
919                    Ok(v) => v,
920                }
921            };
922        }
923
924        let ret = 'label: loop {
925            mode = 'blk: {
926                match mode {
927                    Mode::Head => {
928                        if self.wrap == 0 {
929                            break 'blk Mode::TypeDo;
930                        }
931
932                        need_bits!(self, 16);
933
934                        // Gzip
935                        if (self.wrap & 2) != 0 && self.bit_reader.hold() == 0x8b1f {
936                            if self.wbits == 0 {
937                                self.wbits = 15;
938                            }
939
940                            let b0 = self.bit_reader.bits(8) as u8;
941                            let b1 = (self.bit_reader.hold() >> 8) as u8;
942                            self.checksum = crc32(crate::CRC32_INITIAL_VALUE, &[b0, b1]);
943                            self.bit_reader.init_bits();
944
945                            break 'blk Mode::Flags;
946                        }
947
948                        if let Some(header) = &mut self.head {
949                            header.done = -1;
950                        }
951
952                        // check if zlib header is allowed
953                        if (self.wrap & 1) == 0
954                            || ((self.bit_reader.bits(8) << 8) + (self.bit_reader.hold() >> 8)) % 31
955                                != 0
956                        {
957                            mode = Mode::Bad;
958                            break 'label self.bad("incorrect header check\0");
959                        }
960
961                        if self.bit_reader.bits(4) != Z_DEFLATED as u64 {
962                            mode = Mode::Bad;
963                            break 'label self.bad("unknown compression method\0");
964                        }
965
966                        self.bit_reader.drop_bits(4);
967                        let len = self.bit_reader.bits(4) as u8 + 8;
968
969                        if self.wbits == 0 {
970                            self.wbits = len;
971                        }
972
973                        if len as i32 > MAX_WBITS || len > self.wbits {
974                            mode = Mode::Bad;
975                            break 'label self.bad("invalid window size\0");
976                        }
977
978                        self.dmax = 1 << len;
979                        self.gzip_flags = 0; // indicate zlib header
980                        self.checksum = crate::ADLER32_INITIAL_VALUE as _;
981
982                        if self.bit_reader.hold() & 0x200 != 0 {
983                            self.bit_reader.init_bits();
984
985                            break 'blk Mode::DictId;
986                        } else {
987                            self.bit_reader.init_bits();
988
989                            break 'blk Mode::Type;
990                        }
991                    }
992                    Mode::Flags => {
993                        need_bits!(self, 16);
994                        self.gzip_flags = self.bit_reader.hold() as i32;
995
996                        // Z_DEFLATED = 8 is the only supported method
997                        if self.gzip_flags & 0xff != Z_DEFLATED {
998                            mode = Mode::Bad;
999                            break 'label self.bad("unknown compression method\0");
1000                        }
1001
1002                        if self.gzip_flags & 0xe000 != 0 {
1003                            mode = Mode::Bad;
1004                            break 'label self.bad("unknown header flags set\0");
1005                        }
1006
1007                        if let Some(head) = self.head.as_mut() {
1008                            head.text = ((self.bit_reader.hold() >> 8) & 1) as i32;
1009                        }
1010
1011                        if (self.gzip_flags & 0x0200) != 0 && (self.wrap & 4) != 0 {
1012                            let b0 = self.bit_reader.bits(8) as u8;
1013                            let b1 = (self.bit_reader.hold() >> 8) as u8;
1014                            self.checksum = crc32(self.checksum, &[b0, b1]);
1015                        }
1016
1017                        self.bit_reader.init_bits();
1018
1019                        break 'blk Mode::Time;
1020                    }
1021                    Mode::Time => {
1022                        need_bits!(self, 32);
1023                        if let Some(head) = self.head.as_mut() {
1024                            head.time = self.bit_reader.hold() as z_size;
1025                        }
1026
1027                        if (self.gzip_flags & 0x0200) != 0 && (self.wrap & 4) != 0 {
1028                            let bytes = (self.bit_reader.hold() as u32).to_le_bytes();
1029                            self.checksum = crc32(self.checksum, &bytes);
1030                        }
1031
1032                        self.bit_reader.init_bits();
1033
1034                        break 'blk Mode::Os;
1035                    }
1036                    Mode::Os => {
1037                        need_bits!(self, 16);
1038                        if let Some(head) = self.head.as_mut() {
1039                            head.xflags = (self.bit_reader.hold() & 0xff) as i32;
1040                            head.os = (self.bit_reader.hold() >> 8) as i32;
1041                        }
1042
1043                        if (self.gzip_flags & 0x0200) != 0 && (self.wrap & 4) != 0 {
1044                            let bytes = (self.bit_reader.hold() as u16).to_le_bytes();
1045                            self.checksum = crc32(self.checksum, &bytes);
1046                        }
1047
1048                        self.bit_reader.init_bits();
1049
1050                        break 'blk Mode::ExLen;
1051                    }
1052                    Mode::ExLen => {
1053                        if (self.gzip_flags & 0x0400) != 0 {
1054                            need_bits!(self, 16);
1055
1056                            // self.length (and head.extra_len) represent the length of the extra field
1057                            self.length = self.bit_reader.hold() as usize;
1058                            if let Some(head) = self.head.as_mut() {
1059                                head.extra_len = self.length as u32;
1060                            }
1061
1062                            if (self.gzip_flags & 0x0200) != 0 && (self.wrap & 4) != 0 {
1063                                let bytes = (self.bit_reader.hold() as u16).to_le_bytes();
1064                                self.checksum = crc32(self.checksum, &bytes);
1065                            }
1066                            self.bit_reader.init_bits();
1067                        } else if let Some(head) = self.head.as_mut() {
1068                            head.extra = core::ptr::null_mut();
1069                        }
1070
1071                        break 'blk Mode::Extra;
1072                    }
1073                    Mode::Extra => {
1074                        if (self.gzip_flags & 0x0400) != 0 {
1075                            // self.length is the number of remaining `extra` bytes. But they may not all be available
1076                            let extra_available =
1077                                Ord::min(self.length, self.bit_reader.bytes_remaining());
1078
1079                            if extra_available > 0 {
1080                                if let Some(head) = self.head.as_mut() {
1081                                    if !head.extra.is_null() {
1082                                        // at `head.extra`, the caller has reserved `head.extra_max` bytes.
1083                                        // in the deflated byte stream, we've found a gzip header with
1084                                        // `head.extra_len` bytes of data. We must be careful because
1085                                        // `head.extra_len` may be larger than `head.extra_max`.
1086
1087                                        // how many bytes we've already written into `head.extra`
1088                                        let written_so_far = head.extra_len as usize - self.length;
1089
1090                                        // min of number of bytes available at dst and at src
1091                                        let count = Ord::min(
1092                                            (head.extra_max as usize)
1093                                                .saturating_sub(written_so_far),
1094                                            extra_available,
1095                                        );
1096
1097                                        // SAFETY: location where we'll write: this saturates at the
1098                                        // `head.extra.add(head.extra.max)` to prevent UB
1099                                        let next_write_offset =
1100                                            Ord::min(written_so_far, head.extra_max as usize);
1101
1102                                        unsafe {
1103                                            // SAFETY: count is effectively bounded by head.extra_max
1104                                            // and bit_reader.bytes_remaining(), so the count won't
1105                                            // go out of bounds.
1106                                            core::ptr::copy_nonoverlapping(
1107                                                self.bit_reader.as_mut_ptr(),
1108                                                head.extra.add(next_write_offset),
1109                                                count,
1110                                            );
1111                                        }
1112                                    }
1113                                }
1114
1115                                // Checksum
1116                                if (self.gzip_flags & 0x0200) != 0 && (self.wrap & 4) != 0 {
1117                                    let extra_slice =
1118                                        &self.bit_reader.as_slice()[..extra_available];
1119                                    self.checksum = crc32(self.checksum, extra_slice)
1120                                }
1121
1122                                self.in_available -= extra_available;
1123                                self.bit_reader.advance(extra_available);
1124                                self.length -= extra_available;
1125                            }
1126
1127                            // Checks for errors occur after returning
1128                            if self.length != 0 {
1129                                break 'label self.inflate_leave(ReturnCode::Ok);
1130                            }
1131                        }
1132
1133                        self.length = 0;
1134
1135                        break 'blk Mode::Name;
1136                    }
1137                    Mode::Name => {
1138                        if (self.gzip_flags & 0x0800) != 0 {
1139                            if self.in_available == 0 {
1140                                break 'label self.inflate_leave(ReturnCode::Ok);
1141                            }
1142
1143                            // the name string will always be null-terminated, but might be longer than we have
1144                            // space for in the header struct. Nonetheless, we read the whole thing.
1145                            let slice = self.bit_reader.as_slice();
1146                            let null_terminator_index = slice.iter().position(|c| *c == 0);
1147
1148                            // we include the null terminator if it exists
1149                            let name_slice = match null_terminator_index {
1150                                Some(i) => &slice[..=i],
1151                                None => slice,
1152                            };
1153
1154                            // if the header has space, store as much as possible in there
1155                            if let Some(head) = self.head.as_mut() {
1156                                if !head.name.is_null() {
1157                                    let remaining_name_bytes = (head.name_max as usize)
1158                                        .checked_sub(self.length)
1159                                        .expect("name out of bounds");
1160                                    let copy = Ord::min(name_slice.len(), remaining_name_bytes);
1161
1162                                    unsafe {
1163                                        // SAFETY: copy is effectively bound by the name length and
1164                                        // head.name_max, so this won't go out of bounds.
1165                                        core::ptr::copy_nonoverlapping(
1166                                            name_slice.as_ptr(),
1167                                            head.name.add(self.length),
1168                                            copy,
1169                                        )
1170                                    };
1171
1172                                    self.length += copy;
1173                                }
1174                            }
1175
1176                            if (self.gzip_flags & 0x0200) != 0 && (self.wrap & 4) != 0 {
1177                                self.checksum = crc32(self.checksum, name_slice);
1178                            }
1179
1180                            let reached_end = name_slice.last() == Some(&0);
1181                            self.bit_reader.advance(name_slice.len());
1182
1183                            if !reached_end && self.bit_reader.bytes_remaining() == 0 {
1184                                break 'label self.inflate_leave(ReturnCode::Ok);
1185                            }
1186                        } else if let Some(head) = self.head.as_mut() {
1187                            head.name = core::ptr::null_mut();
1188                        }
1189
1190                        self.length = 0;
1191
1192                        break 'blk Mode::Comment;
1193                    }
1194                    Mode::Comment => {
1195                        if (self.gzip_flags & 0x01000) != 0 {
1196                            if self.in_available == 0 {
1197                                break 'label self.inflate_leave(ReturnCode::Ok);
1198                            }
1199
1200                            // the comment string will always be null-terminated, but might be longer than we have
1201                            // space for in the header struct. Nonetheless, we read the whole thing.
1202                            let slice = self.bit_reader.as_slice();
1203                            let null_terminator_index = slice.iter().position(|c| *c == 0);
1204
1205                            // we include the null terminator if it exists
1206                            let comment_slice = match null_terminator_index {
1207                                Some(i) => &slice[..=i],
1208                                None => slice,
1209                            };
1210
1211                            // if the header has space, store as much as possible in there
1212                            if let Some(head) = self.head.as_mut() {
1213                                if !head.comment.is_null() {
1214                                    let remaining_comm_bytes = (head.comm_max as usize)
1215                                        .checked_sub(self.length)
1216                                        .expect("comm out of bounds");
1217                                    let copy = Ord::min(comment_slice.len(), remaining_comm_bytes);
1218
1219                                    unsafe {
1220                                        // SAFETY: copy is effectively bound by the comment length and
1221                                        // head.comm_max, so this won't go out of bounds.
1222                                        core::ptr::copy_nonoverlapping(
1223                                            comment_slice.as_ptr(),
1224                                            head.comment.add(self.length),
1225                                            copy,
1226                                        )
1227                                    };
1228
1229                                    self.length += copy;
1230                                }
1231                            }
1232
1233                            if (self.gzip_flags & 0x0200) != 0 && (self.wrap & 4) != 0 {
1234                                self.checksum = crc32(self.checksum, comment_slice);
1235                            }
1236
1237                            let reached_end = comment_slice.last() == Some(&0);
1238                            self.bit_reader.advance(comment_slice.len());
1239
1240                            if !reached_end && self.bit_reader.bytes_remaining() == 0 {
1241                                break 'label self.inflate_leave(ReturnCode::Ok);
1242                            }
1243                        } else if let Some(head) = self.head.as_mut() {
1244                            head.comment = core::ptr::null_mut();
1245                        }
1246
1247                        break 'blk Mode::HCrc;
1248                    }
1249                    Mode::HCrc => {
1250                        if (self.gzip_flags & 0x0200) != 0 {
1251                            need_bits!(self, 16);
1252
1253                            if (self.wrap & 4) != 0
1254                                && self.bit_reader.hold() as u32 != (self.checksum & 0xffff)
1255                            {
1256                                mode = Mode::Bad;
1257                                break 'label self.bad("header crc mismatch\0");
1258                            }
1259
1260                            self.bit_reader.init_bits();
1261                        }
1262
1263                        if let Some(head) = self.head.as_mut() {
1264                            head.hcrc = (self.gzip_flags >> 9) & 1;
1265                            head.done = 1;
1266                        }
1267
1268                        // compute crc32 checksum if not in raw mode
1269                        if (self.wrap & 4 != 0) && self.gzip_flags != 0 {
1270                            self.crc_fold = Crc32Fold::new();
1271                            self.checksum = crate::CRC32_INITIAL_VALUE;
1272                        }
1273
1274                        break 'blk Mode::Type;
1275                    }
1276                    Mode::Type => {
1277                        use InflateFlush::*;
1278
1279                        match self.flush {
1280                            Block | Trees => break 'label ReturnCode::Ok,
1281                            NoFlush | SyncFlush | Finish => {
1282                                // NOTE: this is slightly different to what zlib-rs does!
1283                                break 'blk Mode::TypeDo;
1284                            }
1285                        }
1286                    }
1287                    Mode::TypeDo => {
1288                        if self.flags.contains(Flags::IS_LAST_BLOCK) {
1289                            self.bit_reader.next_byte_boundary();
1290                            break 'blk Mode::Check;
1291                        }
1292
1293                        need_bits!(self, 3);
1294                        // self.last = self.bit_reader.bits(1) != 0;
1295                        self.flags
1296                            .update(Flags::IS_LAST_BLOCK, self.bit_reader.bits(1) != 0);
1297                        self.bit_reader.drop_bits(1);
1298
1299                        match self.bit_reader.bits(2) {
1300                            0b00 => {
1301                                traceln!("inflate:     stored block (last = {last})");
1302
1303                                self.bit_reader.drop_bits(2);
1304
1305                                break 'blk Mode::Stored;
1306                            }
1307                            0b01 => {
1308                                traceln!("inflate:     fixed codes block (last = {last})");
1309
1310                                self.len_table = Table {
1311                                    codes: Codes::Fixed,
1312                                    bits: 9,
1313                                };
1314
1315                                self.dist_table = Table {
1316                                    codes: Codes::Fixed,
1317                                    bits: 5,
1318                                };
1319
1320                                mode = Mode::Len_;
1321
1322                                self.bit_reader.drop_bits(2);
1323
1324                                if let InflateFlush::Trees = self.flush {
1325                                    break 'label self.inflate_leave(ReturnCode::Ok);
1326                                } else {
1327                                    break 'blk Mode::Len_;
1328                                }
1329                            }
1330                            0b10 => {
1331                                traceln!("inflate:     dynamic codes block (last = {last})");
1332
1333                                self.bit_reader.drop_bits(2);
1334
1335                                break 'blk Mode::Table;
1336                            }
1337                            0b11 => {
1338                                traceln!("inflate:     invalid block type");
1339
1340                                self.bit_reader.drop_bits(2);
1341
1342                                mode = Mode::Bad;
1343                                break 'label self.bad("invalid block type\0");
1344                            }
1345                            _ => {
1346                                // LLVM will optimize this branch away
1347                                unreachable!("BitReader::bits(2) only yields a value of two bits, so this match is already exhaustive")
1348                            }
1349                        }
1350                    }
1351                    Mode::Stored => {
1352                        self.bit_reader.next_byte_boundary();
1353
1354                        need_bits!(self, 32);
1355
1356                        let hold = self.bit_reader.bits(32) as u32;
1357
1358                        traceln!("hold {hold:#x}");
1359
1360                        if hold as u16 != !((hold >> 16) as u16) {
1361                            mode = Mode::Bad;
1362                            break 'label self.bad("invalid stored block lengths\0");
1363                        }
1364
1365                        self.length = hold as usize & 0xFFFF;
1366                        traceln!("inflate:     stored length {}", state.length);
1367
1368                        self.bit_reader.init_bits();
1369
1370                        if let InflateFlush::Trees = self.flush {
1371                            break 'label self.inflate_leave(ReturnCode::Ok);
1372                        } else {
1373                            break 'blk Mode::CopyBlock;
1374                        }
1375                    }
1376                    Mode::CopyBlock => {
1377                        loop {
1378                            let mut copy = self.length;
1379
1380                            if copy == 0 {
1381                                break;
1382                            }
1383
1384                            copy = Ord::min(copy, self.writer.remaining());
1385                            copy = Ord::min(copy, self.bit_reader.bytes_remaining());
1386
1387                            if copy == 0 {
1388                                break 'label self.inflate_leave(ReturnCode::Ok);
1389                            }
1390
1391                            self.writer.extend(&self.bit_reader.as_slice()[..copy]);
1392                            self.bit_reader.advance(copy);
1393
1394                            self.length -= copy;
1395                        }
1396
1397                        break 'blk Mode::Type;
1398                    }
1399                    Mode::Check => {
1400                        if !cfg!(feature = "__internal-fuzz-disable-checksum") && self.wrap != 0 {
1401                            need_bits!(self, 32);
1402
1403                            self.total += self.writer.len();
1404
1405                            if self.wrap & 4 != 0 {
1406                                if self.gzip_flags != 0 {
1407                                    self.crc_fold.fold(self.writer.filled(), self.checksum);
1408                                    self.checksum = self.crc_fold.finish();
1409                                } else {
1410                                    self.checksum = adler32(self.checksum, self.writer.filled());
1411                                }
1412                            }
1413
1414                            let given_checksum = if self.gzip_flags != 0 {
1415                                self.bit_reader.hold() as u32
1416                            } else {
1417                                zswap32(self.bit_reader.hold() as u32)
1418                            };
1419
1420                            self.out_available = self.writer.capacity() - self.writer.len();
1421
1422                            if self.wrap & 4 != 0 && given_checksum != self.checksum {
1423                                mode = Mode::Bad;
1424                                break 'label self.bad("incorrect data check\0");
1425                            }
1426
1427                            self.bit_reader.init_bits();
1428                        }
1429
1430                        break 'blk Mode::Length;
1431                    }
1432                    Mode::Len_ => {
1433                        break 'blk Mode::Len;
1434                    }
1435                    Mode::Len => {
1436                        self.mode = mode;
1437                        let val = self.len_and_friends();
1438                        mode = self.mode;
1439                        match val {
1440                            ControlFlow::Break(return_code) => break 'label return_code,
1441                            ControlFlow::Continue(()) => continue 'label,
1442                        }
1443                    }
1444                    Mode::LenExt => {
1445                        // NOTE: this branch must be kept in sync with its counterpart in `len_and_friends`
1446                        let extra = self.extra;
1447
1448                        // get extra bits, if any
1449                        if extra != 0 {
1450                            need_bits!(self, extra);
1451                            self.length += self.bit_reader.bits(extra) as usize;
1452                            self.bit_reader.drop_bits(extra as u8);
1453                            self.back += extra;
1454                        }
1455
1456                        traceln!("inflate: length {}", state.length);
1457
1458                        self.was = self.length;
1459
1460                        break 'blk Mode::Dist;
1461                    }
1462                    Mode::Lit => {
1463                        // NOTE: this branch must be kept in sync with its counterpart in `len_and_friends`
1464                        if self.writer.is_full() {
1465                            traceln!("Ok: writer is full ({} bytes)", self.writer.capacity());
1466                            break 'label self.inflate_leave(ReturnCode::Ok);
1467                        }
1468
1469                        self.writer.push(self.length as u8);
1470
1471                        break 'blk Mode::Len;
1472                    }
1473                    Mode::Dist => {
1474                        // NOTE: this branch must be kept in sync with its counterpart in `len_and_friends`
1475
1476                        // get distance code
1477                        let mut here;
1478                        loop {
1479                            let bits = self.bit_reader.bits(self.dist_table.bits) as usize;
1480                            here = self.dist_table_get(bits);
1481                            if here.bits <= self.bit_reader.bits_in_buffer() {
1482                                break;
1483                            }
1484
1485                            pull_byte!(self);
1486                        }
1487
1488                        if here.op & 0xf0 == 0 {
1489                            let last = here;
1490
1491                            loop {
1492                                let bits = self.bit_reader.bits((last.bits + last.op) as usize);
1493                                here = self.dist_table_get(
1494                                    last.val as usize + ((bits as usize) >> last.bits),
1495                                );
1496
1497                                if last.bits + here.bits <= self.bit_reader.bits_in_buffer() {
1498                                    break;
1499                                }
1500
1501                                pull_byte!(self);
1502                            }
1503
1504                            self.bit_reader.drop_bits(last.bits);
1505                            self.back += last.bits as usize;
1506                        }
1507
1508                        self.bit_reader.drop_bits(here.bits);
1509
1510                        if here.op & 64 != 0 {
1511                            mode = Mode::Bad;
1512                            break 'label self.bad("invalid distance code\0");
1513                        }
1514
1515                        self.offset = here.val as usize;
1516
1517                        self.extra = (here.op & MAX_BITS) as usize;
1518
1519                        break 'blk Mode::DistExt;
1520                    }
1521                    Mode::DistExt => {
1522                        // NOTE: this branch must be kept in sync with its counterpart in `len_and_friends`
1523                        let extra = self.extra;
1524
1525                        if extra > 0 {
1526                            need_bits!(self, extra);
1527                            self.offset += self.bit_reader.bits(extra) as usize;
1528                            self.bit_reader.drop_bits(extra as u8);
1529                            self.back += extra;
1530                        }
1531
1532                        if INFLATE_STRICT && self.offset > self.dmax {
1533                            mode = Mode::Bad;
1534                            break 'label self.bad("invalid distance code too far back\0");
1535                        }
1536
1537                        traceln!("inflate: distance {}", state.offset);
1538
1539                        break 'blk Mode::Match;
1540                    }
1541                    Mode::Match => {
1542                        // NOTE: this branch must be kept in sync with its counterpart in `len_and_friends`
1543
1544                        'match_: loop {
1545                            if self.writer.is_full() {
1546                                traceln!(
1547                                    "BufError: writer is full ({} bytes)",
1548                                    self.writer.capacity()
1549                                );
1550                                break 'label self.inflate_leave(ReturnCode::Ok);
1551                            }
1552
1553                            let left = self.writer.remaining();
1554                            let copy = self.writer.len();
1555
1556                            let copy = if self.offset > copy {
1557                                // copy from window to output
1558
1559                                let mut copy = self.offset - copy;
1560
1561                                if copy > self.window.have() {
1562                                    if self.flags.contains(Flags::SANE) {
1563                                        mode = Mode::Bad;
1564                                        break 'label self.bad("invalid distance too far back\0");
1565                                    }
1566
1567                                    // TODO INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
1568                                    panic!("INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR")
1569                                }
1570
1571                                let wnext = self.window.next();
1572                                let wsize = self.window.size();
1573
1574                                let from = if copy > wnext {
1575                                    copy -= wnext;
1576                                    wsize - copy
1577                                } else {
1578                                    wnext - copy
1579                                };
1580
1581                                copy = Ord::min(copy, self.length);
1582                                copy = Ord::min(copy, left);
1583
1584                                self.writer
1585                                    .extend_from_window(&self.window, from..from + copy);
1586
1587                                copy
1588                            } else {
1589                                let copy = Ord::min(self.length, left);
1590                                self.writer.copy_match(self.offset, copy);
1591
1592                                copy
1593                            };
1594
1595                            self.length -= copy;
1596
1597                            if self.length == 0 {
1598                                break 'blk Mode::Len;
1599                            } else {
1600                                // otherwise it seems to recurse?
1601                                continue 'match_;
1602                            }
1603                        }
1604                    }
1605                    Mode::Table => {
1606                        need_bits!(self, 14);
1607                        self.nlen = self.bit_reader.bits(5) as usize + 257;
1608                        self.bit_reader.drop_bits(5);
1609                        self.ndist = self.bit_reader.bits(5) as usize + 1;
1610                        self.bit_reader.drop_bits(5);
1611                        self.ncode = self.bit_reader.bits(4) as usize + 4;
1612                        self.bit_reader.drop_bits(4);
1613
1614                        // TODO pkzit_bug_workaround
1615                        if self.nlen > 286 || self.ndist > 30 {
1616                            mode = Mode::Bad;
1617                            break 'label self.bad("too many length or distance symbols\0");
1618                        }
1619
1620                        self.have = 0;
1621
1622                        break 'blk Mode::LenLens;
1623                    }
1624                    Mode::LenLens => {
1625                        // permutation of code lengths ;
1626                        const ORDER: [u8; 19] = [
1627                            16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
1628                        ];
1629
1630                        while self.have < self.ncode {
1631                            need_bits!(self, 3);
1632                            self.lens[usize::from(ORDER[self.have])] =
1633                                self.bit_reader.bits(3) as u16;
1634                            self.have += 1;
1635                            self.bit_reader.drop_bits(3);
1636                        }
1637
1638                        while self.have < 19 {
1639                            self.lens[usize::from(ORDER[self.have])] = 0;
1640                            self.have += 1;
1641                        }
1642
1643                        let InflateTable::Success { root, used } = inflate_table(
1644                            CodeType::Codes,
1645                            &self.lens[..19],
1646                            &mut self.codes_codes,
1647                            7,
1648                            &mut self.work,
1649                        ) else {
1650                            mode = Mode::Bad;
1651                            break 'label self.bad("invalid code lengths set\0");
1652                        };
1653
1654                        self.next = used;
1655                        self.len_table.codes = Codes::Codes;
1656                        self.len_table.bits = root;
1657
1658                        self.have = 0;
1659
1660                        break 'blk Mode::CodeLens;
1661                    }
1662                    Mode::CodeLens => {
1663                        while self.have < self.nlen + self.ndist {
1664                            let here = loop {
1665                                let bits = self.bit_reader.bits(self.len_table.bits);
1666                                let here = self.len_table_get(bits as usize);
1667                                if here.bits <= self.bit_reader.bits_in_buffer() {
1668                                    break here;
1669                                }
1670
1671                                pull_byte!(self);
1672                            };
1673
1674                            let here_bits = here.bits;
1675
1676                            match here.val {
1677                                0..=15 => {
1678                                    self.bit_reader.drop_bits(here_bits);
1679                                    self.lens[self.have] = here.val;
1680                                    self.have += 1;
1681                                }
1682                                16 => {
1683                                    need_bits!(self, usize::from(here_bits) + 2);
1684                                    self.bit_reader.drop_bits(here_bits);
1685                                    if self.have == 0 {
1686                                        mode = Mode::Bad;
1687                                        break 'label self.bad("invalid bit length repeat\0");
1688                                    }
1689
1690                                    let len = self.lens[self.have - 1];
1691                                    let copy = 3 + self.bit_reader.bits(2) as usize;
1692                                    self.bit_reader.drop_bits(2);
1693
1694                                    if self.have + copy > self.nlen + self.ndist {
1695                                        mode = Mode::Bad;
1696                                        break 'label self.bad("invalid bit length repeat\0");
1697                                    }
1698
1699                                    self.lens[self.have..][..copy].fill(len);
1700                                    self.have += copy;
1701                                }
1702                                17 => {
1703                                    need_bits!(self, usize::from(here_bits) + 3);
1704                                    self.bit_reader.drop_bits(here_bits);
1705                                    let copy = 3 + self.bit_reader.bits(3) as usize;
1706                                    self.bit_reader.drop_bits(3);
1707
1708                                    if self.have + copy > self.nlen + self.ndist {
1709                                        mode = Mode::Bad;
1710                                        break 'label self.bad("invalid bit length repeat\0");
1711                                    }
1712
1713                                    self.lens[self.have..][..copy].fill(0);
1714                                    self.have += copy;
1715                                }
1716                                18.. => {
1717                                    need_bits!(self, usize::from(here_bits) + 7);
1718                                    self.bit_reader.drop_bits(here_bits);
1719                                    let copy = 11 + self.bit_reader.bits(7) as usize;
1720                                    self.bit_reader.drop_bits(7);
1721
1722                                    if self.have + copy > self.nlen + self.ndist {
1723                                        mode = Mode::Bad;
1724                                        break 'label self.bad("invalid bit length repeat\0");
1725                                    }
1726
1727                                    self.lens[self.have..][..copy].fill(0);
1728                                    self.have += copy;
1729                                }
1730                            }
1731                        }
1732
1733                        // check for end-of-block code (better have one)
1734                        if self.lens[256] == 0 {
1735                            mode = Mode::Bad;
1736                            break 'label self.bad("invalid code -- missing end-of-block\0");
1737                        }
1738
1739                        // build code tables
1740
1741                        let InflateTable::Success { root, used } = inflate_table(
1742                            CodeType::Lens,
1743                            &self.lens[..self.nlen],
1744                            &mut self.len_codes,
1745                            10,
1746                            &mut self.work,
1747                        ) else {
1748                            mode = Mode::Bad;
1749                            break 'label self.bad("invalid literal/lengths set\0");
1750                        };
1751
1752                        self.len_table.codes = Codes::Len;
1753                        self.len_table.bits = root;
1754                        self.next = used;
1755
1756                        let InflateTable::Success { root, used } = inflate_table(
1757                            CodeType::Dists,
1758                            &self.lens[self.nlen..][..self.ndist],
1759                            &mut self.dist_codes,
1760                            9,
1761                            &mut self.work,
1762                        ) else {
1763                            mode = Mode::Bad;
1764                            break 'label self.bad("invalid distances set\0");
1765                        };
1766
1767                        self.dist_table.bits = root;
1768                        self.dist_table.codes = Codes::Dist;
1769                        self.next += used;
1770
1771                        mode = Mode::Len_;
1772
1773                        if matches!(self.flush, InflateFlush::Trees) {
1774                            break 'label self.inflate_leave(ReturnCode::Ok);
1775                        }
1776
1777                        break 'blk Mode::Len_;
1778                    }
1779                    Mode::Dict => {
1780                        if !self.flags.contains(Flags::HAVE_DICT) {
1781                            break 'label self.inflate_leave(ReturnCode::NeedDict);
1782                        }
1783
1784                        self.checksum = crate::ADLER32_INITIAL_VALUE as _;
1785
1786                        break 'blk Mode::Type;
1787                    }
1788                    Mode::DictId => {
1789                        need_bits!(self, 32);
1790
1791                        self.checksum = zswap32(self.bit_reader.hold() as u32);
1792
1793                        self.bit_reader.init_bits();
1794
1795                        break 'blk Mode::Dict;
1796                    }
1797                    Mode::Done => {
1798                        // Inflate stream terminated properly.
1799                        break 'label ReturnCode::StreamEnd;
1800                    }
1801                    Mode::Bad => {
1802                        let msg = "repeated call with bad state\0";
1803                        #[cfg(all(feature = "std", test))]
1804                        dbg!(msg);
1805                        self.error_message = Some(msg);
1806
1807                        break 'label ReturnCode::DataError;
1808                    }
1809                    Mode::Mem => {
1810                        break 'label ReturnCode::MemError;
1811                    }
1812                    Mode::Sync => {
1813                        break 'label ReturnCode::StreamError;
1814                    }
1815                    Mode::Length => {
1816                        // for gzip, last bytes contain LENGTH
1817                        if self.wrap != 0 && self.gzip_flags != 0 {
1818                            need_bits!(self, 32);
1819                            if (self.wrap & 0b100) != 0
1820                                && self.bit_reader.hold() as u32 != self.total as u32
1821                            {
1822                                mode = Mode::Bad;
1823                                break 'label self.bad("incorrect length check\0");
1824                            }
1825
1826                            self.bit_reader.init_bits();
1827                        }
1828
1829                        mode = Mode::Done;
1830                        // Inflate stream terminated properly.
1831                        break 'label ReturnCode::StreamEnd;
1832                    }
1833                };
1834            }
1835        };
1836
1837        self.mode = mode;
1838
1839        ret
1840    }
1841
1842    fn bad(&mut self, msg: &'static str) -> ReturnCode {
1843        #[cfg(all(feature = "std", test))]
1844        dbg!(msg);
1845        self.error_message = Some(msg);
1846        self.inflate_leave(ReturnCode::DataError)
1847    }
1848
1849    // NOTE: it is crucial for the internal bookkeeping that this is the only route for actually
1850    // leaving the inflate function call chain
1851    fn inflate_leave(&mut self, return_code: ReturnCode) -> ReturnCode {
1852        // actual logic is in `inflate` itself
1853        return_code
1854    }
1855
1856    /// Stored in the `z_stream.data_type` field
1857    fn decoding_state(&self) -> i32 {
1858        let bit_reader_bits = self.bit_reader.bits_in_buffer() as i32;
1859        debug_assert!(bit_reader_bits < 64);
1860
1861        let last = if self.flags.contains(Flags::IS_LAST_BLOCK) {
1862            64
1863        } else {
1864            0
1865        };
1866
1867        let mode = match self.mode {
1868            Mode::Type => 128,
1869            Mode::Len_ | Mode::CopyBlock => 256,
1870            _ => 0,
1871        };
1872
1873        bit_reader_bits | last | mode
1874    }
1875}
1876
1877/// # Safety
1878///
1879/// `state.bit_reader` must have at least 15 bytes available to read, as
1880/// indicated by `state.bit_reader.bytes_remaining() >= 15`
1881unsafe fn inflate_fast_help(state: &mut State, start: usize) {
1882    #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
1883    if crate::cpu_features::is_enabled_avx2_and_bmi2() {
1884        // SAFETY: we've verified the target features and the caller ensured enough bytes_remaining
1885        return unsafe { inflate_fast_help_avx2(state, start) };
1886    }
1887
1888    // SAFETY: The caller ensured enough bytes_remaining
1889    unsafe { inflate_fast_help_vanilla(state, start) };
1890}
1891
1892/// # Safety
1893///
1894/// `state.bit_reader` must have at least 15 bytes available to read, as
1895/// indicated by `state.bit_reader.bytes_remaining() >= 15`
1896#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
1897#[target_feature(enable = "avx2")]
1898#[target_feature(enable = "bmi2")]
1899#[target_feature(enable = "bmi1")]
1900unsafe fn inflate_fast_help_avx2(state: &mut State, start: usize) {
1901    // SAFETY: `bytes_remaining` checked by our caller
1902    unsafe { inflate_fast_help_impl::<{ CpuFeatures::AVX2 }>(state, start) };
1903}
1904
1905/// # Safety
1906///
1907/// `state.bit_reader` must have at least 15 bytes available to read, as
1908/// indicated by `state.bit_reader.bytes_remaining() >= 15`
1909unsafe fn inflate_fast_help_vanilla(state: &mut State, start: usize) {
1910    // SAFETY: `bytes_remaining` checked by our caller
1911    unsafe { inflate_fast_help_impl::<{ CpuFeatures::NONE }>(state, start) };
1912}
1913
1914/// # Safety
1915///
1916/// `state.bit_reader` must have at least 15 bytes available to read, as
1917/// indicated by `state.bit_reader.bytes_remaining() >= 15`
1918#[inline(always)]
1919unsafe fn inflate_fast_help_impl<const FEATURES: usize>(state: &mut State, _start: usize) {
1920    let mut bit_reader = BitReader::new(&[]);
1921    core::mem::swap(&mut bit_reader, &mut state.bit_reader);
1922    debug_assert!(bit_reader.bytes_remaining() >= 15);
1923
1924    let mut writer = Writer::new(&mut []);
1925    core::mem::swap(&mut writer, &mut state.writer);
1926
1927    let lcode = state.len_table_ref();
1928    let dcode = state.dist_table_ref();
1929
1930    // IDEA: use const generics for the bits here?
1931    let lmask = (1u64 << state.len_table.bits) - 1;
1932    let dmask = (1u64 << state.dist_table.bits) - 1;
1933
1934    // TODO verify if this is relevant for us
1935    let extra_safe = false;
1936
1937    let window_size = state.window.size();
1938
1939    let mut bad = None;
1940
1941    if bit_reader.bits_in_buffer() < 10 {
1942        debug_assert!(bit_reader.bytes_remaining() >= 15);
1943        // Safety: Caller ensured that bit_reader has >= 15 bytes available; refill only needs 8.
1944        unsafe { bit_reader.refill() };
1945    }
1946    // We had at least 15 bytes in the slice, plus whatever was in the buffer. After filling the
1947    // buffer from the slice, we now have at least 8 bytes remaining in the slice, plus a full buffer.
1948    debug_assert!(
1949        bit_reader.bytes_remaining() >= 8 && bit_reader.bytes_remaining_including_buffer() >= 15
1950    );
1951
1952    'outer: loop {
1953        // This condition is ensured above for the first iteration of the `outer` loop. For
1954        // subsequent iterations, the loop continuation condition is
1955        // `bit_reader.bytes_remaining_including_buffer() > 15`. And because the buffer
1956        // contributes at most 7 bytes to the result of bit_reader.bytes_remaining_including_buffer(),
1957        // that means that the slice contains at least 8 bytes.
1958        debug_assert!(
1959            bit_reader.bytes_remaining() >= 8
1960                && bit_reader.bytes_remaining_including_buffer() >= 15
1961        );
1962
1963        let mut here = {
1964            let bits = bit_reader.bits_in_buffer();
1965            let hold = bit_reader.hold();
1966
1967            // Safety: As described in the comments for the debug_assert at the start of
1968            // the `outer` loop, it is guaranteed that `bit_reader.bytes_remaining() >= 8` here,
1969            // which satisfies the safety precondition for `refill`. And, because the total
1970            // number of bytes in `bit_reader`'s buffer plus its slice is at least 15, and
1971            // `refill` moves at most 7 bytes from the slice to the buffer, the slice will still
1972            // contain at least 8 bytes after this `refill` call.
1973            unsafe { bit_reader.refill() };
1974            // After the refill, there will be at least 8 bytes left in the bit_reader's slice.
1975            debug_assert!(bit_reader.bytes_remaining() >= 8);
1976
1977            // in most cases, the read can be interleaved with the logic
1978            // based on benchmarks this matters in practice. wild.
1979            if bits as usize >= state.len_table.bits {
1980                lcode[(hold & lmask) as usize]
1981            } else {
1982                lcode[(bit_reader.hold() & lmask) as usize]
1983            }
1984        };
1985
1986        if here.op == 0 {
1987            writer.push(here.val as u8);
1988            bit_reader.drop_bits(here.bits);
1989            here = lcode[(bit_reader.hold() & lmask) as usize];
1990
1991            if here.op == 0 {
1992                writer.push(here.val as u8);
1993                bit_reader.drop_bits(here.bits);
1994                here = lcode[(bit_reader.hold() & lmask) as usize];
1995            }
1996        }
1997
1998        'dolen: loop {
1999            bit_reader.drop_bits(here.bits);
2000            let op = here.op;
2001
2002            if op == 0 {
2003                writer.push(here.val as u8);
2004            } else if op & 16 != 0 {
2005                let op = op & MAX_BITS;
2006                let mut len = here.val + bit_reader.bits(op as usize) as u16;
2007                bit_reader.drop_bits(op);
2008
2009                here = dcode[(bit_reader.hold() & dmask) as usize];
2010
2011                // we have two fast-path loads: 10+10 + 15+5 = 40,
2012                // but we may need to refill here in the worst case
2013                if bit_reader.bits_in_buffer() < MAX_BITS + MAX_DIST_EXTRA_BITS {
2014                    debug_assert!(bit_reader.bytes_remaining() >= 8);
2015                    // Safety: On the first iteration of the `dolen` loop, we can rely on the
2016                    // invariant documented for the previous `refill` call above: after that
2017                    // operation, `bit_reader.bytes_remining >= 8`, which satisfies the safety
2018                    // precondition for this call. For subsequent iterations, this invariant
2019                    // remains true because nothing else within the `dolen` loop consumes data
2020                    // from the slice.
2021                    unsafe { bit_reader.refill() };
2022                }
2023
2024                'dodist: loop {
2025                    bit_reader.drop_bits(here.bits);
2026                    let op = here.op;
2027
2028                    if op & 16 != 0 {
2029                        let op = op & MAX_BITS;
2030                        let dist = here.val + bit_reader.bits(op as usize) as u16;
2031
2032                        if INFLATE_STRICT && dist as usize > state.dmax {
2033                            bad = Some("invalid distance too far back\0");
2034                            state.mode = Mode::Bad;
2035                            break 'outer;
2036                        }
2037
2038                        bit_reader.drop_bits(op);
2039
2040                        // max distance in output
2041                        let written = writer.len();
2042
2043                        if dist as usize > written {
2044                            // copy fropm the window
2045                            if (dist as usize - written) > state.window.have() {
2046                                if state.flags.contains(Flags::SANE) {
2047                                    bad = Some("invalid distance too far back\0");
2048                                    state.mode = Mode::Bad;
2049                                    break 'outer;
2050                                }
2051
2052                                panic!("INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR")
2053                            }
2054
2055                            let mut op = dist as usize - written;
2056                            let mut from;
2057
2058                            let window_next = state.window.next();
2059
2060                            if window_next == 0 {
2061                                // This case is hit when the window has just wrapped around
2062                                // by logic in `Window::extend`. It is special-cased because
2063                                // apparently this is quite common.
2064                                //
2065                                // the match is at the end of the window, even though the next
2066                                // position has now wrapped around.
2067                                from = window_size - op;
2068                            } else if window_next >= op {
2069                                // the standard case: a contiguous copy from the window, no wrapping
2070                                from = window_next - op;
2071                            } else {
2072                                // This case is hit when the window has recently wrapped around
2073                                // by logic in `Window::extend`.
2074                                //
2075                                // The match is (partially) at the end of the window
2076                                op -= window_next;
2077                                from = window_size - op;
2078
2079                                if op < len as usize {
2080                                    // This case is hit when part of the match is at the end of the
2081                                    // window, and part of it has wrapped around to the start. Copy
2082                                    // the end section here, the start section will be copied below.
2083                                    len -= op as u16;
2084                                    writer.extend_from_window_with_features::<FEATURES>(
2085                                        &state.window,
2086                                        from..from + op,
2087                                    );
2088                                    from = 0;
2089                                    op = window_next;
2090                                }
2091                            }
2092
2093                            let copy = Ord::min(op, len as usize);
2094                            writer.extend_from_window_with_features::<FEATURES>(
2095                                &state.window,
2096                                from..from + copy,
2097                            );
2098
2099                            if op < len as usize {
2100                                // here we need some bytes from the output itself
2101                                writer.copy_match_with_features::<FEATURES>(
2102                                    dist as usize,
2103                                    len as usize - op,
2104                                );
2105                            }
2106                        } else if extra_safe {
2107                            todo!()
2108                        } else {
2109                            writer.copy_match_with_features::<FEATURES>(dist as usize, len as usize)
2110                        }
2111                    } else if (op & 64) == 0 {
2112                        // 2nd level distance code
2113                        here = dcode[(here.val + bit_reader.bits(op as usize) as u16) as usize];
2114                        continue 'dodist;
2115                    } else {
2116                        bad = Some("invalid distance code\0");
2117                        state.mode = Mode::Bad;
2118                        break 'outer;
2119                    }
2120
2121                    break 'dodist;
2122                }
2123            } else if (op & 64) == 0 {
2124                // 2nd level length code
2125                here = lcode[(here.val + bit_reader.bits(op as usize) as u16) as usize];
2126                continue 'dolen;
2127            } else if op & 32 != 0 {
2128                // end of block
2129                state.mode = Mode::Type;
2130                break 'outer;
2131            } else {
2132                bad = Some("invalid literal/length code\0");
2133                state.mode = Mode::Bad;
2134                break 'outer;
2135            }
2136
2137            break 'dolen;
2138        }
2139
2140        // For normal `inflate`, include the bits in the bit_reader buffer in the count of available bytes.
2141        let remaining = bit_reader.bytes_remaining_including_buffer();
2142        if remaining >= INFLATE_FAST_MIN_HAVE && writer.remaining() >= INFLATE_FAST_MIN_LEFT {
2143            continue;
2144        }
2145
2146        break 'outer;
2147    }
2148
2149    // return unused bytes (on entry, bits < 8, so in won't go too far back)
2150    bit_reader.return_unused_bytes();
2151
2152    state.bit_reader = bit_reader;
2153    state.writer = writer;
2154
2155    if let Some(error_message) = bad {
2156        debug_assert!(matches!(state.mode, Mode::Bad));
2157        state.bad(error_message);
2158    }
2159}
2160
2161pub fn prime(stream: &mut InflateStream, bits: i32, value: i32) -> ReturnCode {
2162    if bits == 0 {
2163        /* fall through */
2164    } else if bits < 0 {
2165        stream.state.bit_reader.init_bits();
2166    } else if bits > 16 || stream.state.bit_reader.bits_in_buffer() + bits as u8 > 32 {
2167        return ReturnCode::StreamError;
2168    } else {
2169        stream.state.bit_reader.prime(bits as u8, value as u64);
2170    }
2171
2172    ReturnCode::Ok
2173}
2174
2175struct InflateAllocOffsets {
2176    total_size: usize,
2177    state_pos: usize,
2178    window_pos: usize,
2179}
2180
2181impl InflateAllocOffsets {
2182    fn new() -> Self {
2183        use core::mem::size_of;
2184
2185        // 64B padding for SIMD operations. This allows unaligned operations (up to 512-bit) to run
2186        // off the end of the object without issue.
2187        const WINDOW_PAD_SIZE: usize = 64;
2188
2189        // 64B alignment of individual items in the alloc.
2190        // Note that changing this also requires changes in 'init' and 'copy'.
2191        const ALIGN_SIZE: usize = 64;
2192        let mut curr_size = 0usize;
2193
2194        /* Define sizes */
2195        let state_size = size_of::<State>();
2196        let window_size = (1 << MAX_WBITS) + WINDOW_PAD_SIZE;
2197
2198        /* Calculate relative buffer positions and paddings */
2199        let state_pos = curr_size.next_multiple_of(ALIGN_SIZE);
2200        curr_size = state_pos + state_size;
2201
2202        let window_pos = curr_size.next_multiple_of(ALIGN_SIZE);
2203        curr_size = window_pos + window_size;
2204
2205        /* Add ALIGN_SIZE-1 to allow alignment (done in the 'init' and 'copy' functions), and round
2206         * size of buffer up to next multiple of ALIGN_SIZE */
2207        let total_size = (curr_size + (ALIGN_SIZE - 1)).next_multiple_of(ALIGN_SIZE);
2208
2209        Self {
2210            total_size,
2211            state_pos,
2212            window_pos,
2213        }
2214    }
2215}
2216
2217/// Configuration for decompresssion.
2218///
2219/// Used with [`decompress_slice`].
2220#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
2221pub struct InflateConfig {
2222    pub window_bits: i32,
2223}
2224
2225impl Default for InflateConfig {
2226    fn default() -> Self {
2227        Self {
2228            window_bits: DEF_WBITS,
2229        }
2230    }
2231}
2232
2233/// Initialize the stream in an inflate state
2234pub fn init(stream: &mut z_stream, config: InflateConfig) -> ReturnCode {
2235    stream.msg = core::ptr::null_mut();
2236
2237    // for safety we must really make sure that alloc and free are consistent
2238    // this is a (slight) deviation from stock zlib. In this crate we pick the rust
2239    // allocator as the default, but `libz-rs-sys` configures the C allocator
2240    #[cfg(feature = "rust-allocator")]
2241    if stream.zalloc.is_none() || stream.zfree.is_none() {
2242        stream.configure_default_rust_allocator()
2243    }
2244
2245    #[cfg(feature = "c-allocator")]
2246    if stream.zalloc.is_none() || stream.zfree.is_none() {
2247        stream.configure_default_c_allocator()
2248    }
2249
2250    if stream.zalloc.is_none() || stream.zfree.is_none() {
2251        return ReturnCode::StreamError;
2252    }
2253
2254    let mut state = State::new(&[], Writer::new(&mut []));
2255
2256    // TODO this can change depending on the used/supported SIMD instructions
2257    state.chunksize = 32;
2258
2259    let alloc = Allocator {
2260        zalloc: stream.zalloc.unwrap(),
2261        zfree: stream.zfree.unwrap(),
2262        opaque: stream.opaque,
2263        _marker: PhantomData,
2264    };
2265    let allocs = InflateAllocOffsets::new();
2266
2267    let Some(allocation_start) = alloc.allocate_slice_raw::<u8>(allocs.total_size) else {
2268        return ReturnCode::MemError;
2269    };
2270
2271    let address = allocation_start.as_ptr() as usize;
2272    let align_offset = address.next_multiple_of(64) - address;
2273    let buf = unsafe { allocation_start.as_ptr().add(align_offset) };
2274
2275    let window_allocation = unsafe { buf.add(allocs.window_pos) };
2276    let window = unsafe { Window::from_raw_parts(window_allocation, (1 << MAX_WBITS) + 64) };
2277    state.window = window;
2278
2279    let state_allocation = unsafe { buf.add(allocs.state_pos).cast::<State>() };
2280    unsafe { state_allocation.write(state) };
2281    stream.state = state_allocation.cast::<internal_state>();
2282
2283    // SAFETY: we've correctly initialized the stream to be an InflateStream
2284    if let Some(stream) = unsafe { InflateStream::from_stream_mut(stream) } {
2285        stream.state.allocation_start = allocation_start.as_ptr();
2286        stream.state.total_allocation_size = allocs.total_size;
2287        let ret = reset_with_config(stream, config);
2288
2289        if ret != ReturnCode::Ok {
2290            end(stream);
2291        }
2292
2293        ret
2294    } else {
2295        ReturnCode::StreamError
2296    }
2297}
2298
2299pub fn reset_with_config(stream: &mut InflateStream, config: InflateConfig) -> ReturnCode {
2300    let mut window_bits = config.window_bits;
2301    let wrap;
2302
2303    if window_bits < 0 {
2304        wrap = 0;
2305
2306        if window_bits < -MAX_WBITS {
2307            return ReturnCode::StreamError;
2308        }
2309
2310        window_bits = -window_bits;
2311    } else {
2312        wrap = (window_bits >> 4) + 5; // TODO wth?
2313
2314        if window_bits < 48 {
2315            window_bits &= MAX_WBITS;
2316        }
2317    }
2318
2319    if window_bits != 0 && !(MIN_WBITS..=MAX_WBITS).contains(&window_bits) {
2320        traceln!("invalid windowBits");
2321        return ReturnCode::StreamError;
2322    }
2323
2324    stream.state.wrap = wrap as u8;
2325    stream.state.wbits = window_bits as _;
2326
2327    reset(stream)
2328}
2329
2330pub fn reset(stream: &mut InflateStream) -> ReturnCode {
2331    // reset the state of the window
2332    stream.state.window.clear();
2333
2334    stream.state.error_message = None;
2335
2336    reset_keep(stream)
2337}
2338
2339pub fn reset_keep(stream: &mut InflateStream) -> ReturnCode {
2340    stream.total_in = 0;
2341    stream.total_out = 0;
2342    stream.state.total = 0;
2343
2344    stream.msg = core::ptr::null_mut();
2345
2346    let state = &mut stream.state;
2347
2348    if state.wrap != 0 {
2349        // to support ill-conceived Java test suite
2350        stream.adler = (state.wrap & 1) as _;
2351    }
2352
2353    state.mode = Mode::Head;
2354    state.checksum = crate::ADLER32_INITIAL_VALUE as u32;
2355
2356    state.flags.update(Flags::IS_LAST_BLOCK, false);
2357    state.flags.update(Flags::HAVE_DICT, false);
2358    state.flags.update(Flags::SANE, true);
2359    state.gzip_flags = -1;
2360    state.dmax = 32768;
2361    state.head = None;
2362    state.bit_reader = BitReader::new(&[]);
2363
2364    state.next = 0;
2365    state.len_table = Table::default();
2366    state.dist_table = Table::default();
2367
2368    state.back = usize::MAX;
2369
2370    ReturnCode::Ok
2371}
2372
2373pub fn codes_used(stream: &InflateStream) -> usize {
2374    stream.state.next
2375}
2376
2377pub unsafe fn inflate(stream: &mut InflateStream, flush: InflateFlush) -> ReturnCode {
2378    if stream.next_out.is_null() || (stream.next_in.is_null() && stream.avail_in != 0) {
2379        return ReturnCode::StreamError;
2380    }
2381
2382    let state = &mut stream.state;
2383
2384    // skip check
2385    if let Mode::Type = state.mode {
2386        state.mode = Mode::TypeDo;
2387    }
2388
2389    state.flush = flush;
2390
2391    unsafe {
2392        state
2393            .bit_reader
2394            .update_slice(stream.next_in, stream.avail_in as usize)
2395    };
2396    // Safety: `stream.next_out` is non-null and points to at least `stream.avail_out` bytes.
2397    state.writer = unsafe { Writer::new_uninit(stream.next_out.cast(), stream.avail_out as usize) };
2398
2399    state.in_available = stream.avail_in as _;
2400    state.out_available = stream.avail_out as _;
2401
2402    let err = state.dispatch();
2403
2404    let in_read = state.bit_reader.as_ptr() as usize - stream.next_in as usize;
2405    let out_written = state.out_available - (state.writer.capacity() - state.writer.len());
2406
2407    stream.total_in += in_read as z_size;
2408    state.total = state.total.wrapping_add(out_written);
2409    stream.total_out = state.total as _;
2410
2411    stream.avail_in = state.bit_reader.bytes_remaining() as u32;
2412    stream.next_in = state.bit_reader.as_ptr() as *mut u8;
2413
2414    stream.avail_out = (state.writer.capacity() - state.writer.len()) as u32;
2415    stream.next_out = state.writer.next_out() as *mut u8;
2416
2417    stream.adler = state.checksum as z_checksum;
2418
2419    let valid_mode = |mode| !matches!(mode, Mode::Bad | Mode::Mem | Mode::Sync);
2420    let not_done = |mode| {
2421        !matches!(
2422            mode,
2423            Mode::Check | Mode::Length | Mode::Bad | Mode::Mem | Mode::Sync
2424        )
2425    };
2426
2427    let must_update_window = state.window.size() != 0
2428        || (out_written != 0
2429            && valid_mode(state.mode)
2430            && (not_done(state.mode) || !matches!(state.flush, InflateFlush::Finish)));
2431
2432    let update_checksum = state.wrap & 4 != 0;
2433
2434    if must_update_window {
2435        state.window.extend(
2436            &state.writer.filled()[..out_written],
2437            state.gzip_flags,
2438            update_checksum,
2439            &mut state.checksum,
2440            &mut state.crc_fold,
2441        );
2442    }
2443
2444    if let Some(msg) = state.error_message {
2445        assert!(msg.ends_with('\0'));
2446        stream.msg = msg.as_ptr() as *mut u8 as *mut core::ffi::c_char;
2447    }
2448
2449    stream.data_type = state.decoding_state();
2450
2451    if ((in_read == 0 && out_written == 0) || flush == InflateFlush::Finish)
2452        && err == ReturnCode::Ok
2453    {
2454        ReturnCode::BufError
2455    } else {
2456        err
2457    }
2458}
2459
2460fn syncsearch(mut got: usize, buf: &[u8]) -> (usize, usize) {
2461    let len = buf.len();
2462    let mut next = 0;
2463
2464    while next < len && got < 4 {
2465        if buf[next] == if got < 2 { 0 } else { 0xff } {
2466            got += 1;
2467        } else if buf[next] != 0 {
2468            got = 0;
2469        } else {
2470            got = 4 - got;
2471        }
2472        next += 1;
2473    }
2474
2475    (got, next)
2476}
2477
2478pub fn sync(stream: &mut InflateStream) -> ReturnCode {
2479    let state = &mut stream.state;
2480
2481    if stream.avail_in == 0 && state.bit_reader.bits_in_buffer() < 8 {
2482        return ReturnCode::BufError;
2483    }
2484    /* if first time, start search in bit buffer */
2485    if !matches!(state.mode, Mode::Sync) {
2486        state.mode = Mode::Sync;
2487
2488        let (buf, len) = state.bit_reader.start_sync_search();
2489
2490        (state.have, _) = syncsearch(0, &buf[..len]);
2491    }
2492
2493    // search available input
2494    // SAFETY: user guarantees that pointer and length are valid.
2495    let slice = unsafe { core::slice::from_raw_parts(stream.next_in, stream.avail_in as usize) };
2496
2497    let len;
2498    (state.have, len) = syncsearch(state.have, slice);
2499    // SAFETY: syncsearch() returns an index that is in-bounds of the slice.
2500    stream.next_in = unsafe { stream.next_in.add(len) };
2501    stream.avail_in -= len as u32;
2502    stream.total_in += len as z_size;
2503
2504    /* return no joy or set up to restart inflate() on a new block */
2505    if state.have != 4 {
2506        return ReturnCode::DataError;
2507    }
2508
2509    if state.gzip_flags == -1 {
2510        state.wrap = 0; /* if no header yet, treat as raw */
2511    } else {
2512        state.wrap &= !4; /* no point in computing a check value now */
2513    }
2514
2515    let flags = state.gzip_flags;
2516    let total_in = stream.total_in;
2517    let total_out = stream.total_out;
2518
2519    reset(stream);
2520
2521    stream.total_in = total_in;
2522    stream.total_out = total_out;
2523
2524    stream.state.gzip_flags = flags;
2525    stream.state.mode = Mode::Type;
2526
2527    ReturnCode::Ok
2528}
2529
2530/*
2531  Returns true if inflate is currently at the end of a block generated by
2532  Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
2533  implementation to provide an additional safety check. PPP uses
2534  Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
2535  block. When decompressing, PPP checks that at the end of input packet,
2536  inflate is waiting for these length bytes.
2537*/
2538pub fn sync_point(stream: &mut InflateStream) -> bool {
2539    matches!(stream.state.mode, Mode::Stored) && stream.state.bit_reader.bits_in_buffer() == 0
2540}
2541
2542pub unsafe fn copy<'a>(
2543    dest: &mut MaybeUninit<InflateStream<'a>>,
2544    source: &InflateStream<'a>,
2545) -> ReturnCode {
2546    if source.next_out.is_null() || (source.next_in.is_null() && source.avail_in != 0) {
2547        return ReturnCode::StreamError;
2548    }
2549
2550    // Safety: source and dest are both mutable references, so guaranteed not to overlap.
2551    // dest being a reference to maybe uninitialized memory makes a copy of 1 DeflateStream valid.
2552    unsafe { core::ptr::copy_nonoverlapping(source, dest.as_mut_ptr(), 1) };
2553
2554    // Allocate space.
2555    let allocs = InflateAllocOffsets::new();
2556    debug_assert_eq!(allocs.total_size, source.state.total_allocation_size);
2557
2558    let Some(allocation_start) = source.alloc.allocate_slice_raw::<u8>(allocs.total_size) else {
2559        return ReturnCode::MemError;
2560    };
2561
2562    let address = allocation_start.as_ptr() as usize;
2563    let align_offset = address.next_multiple_of(64) - address;
2564    let buf = unsafe { allocation_start.as_ptr().add(align_offset) };
2565
2566    let window_allocation = unsafe { buf.add(allocs.window_pos) };
2567    let window = unsafe {
2568        source
2569            .state
2570            .window
2571            .clone_to(window_allocation, (1 << MAX_WBITS) + 64)
2572    };
2573
2574    let copy = unsafe { buf.add(allocs.state_pos).cast::<State>() };
2575    unsafe { core::ptr::copy_nonoverlapping(source.state, copy, 1) };
2576
2577    let field_ptr = unsafe { core::ptr::addr_of_mut!((*copy).window) };
2578    unsafe { core::ptr::write(field_ptr, window) };
2579
2580    let field_ptr = unsafe { core::ptr::addr_of_mut!((*copy).allocation_start) };
2581    unsafe { core::ptr::write(field_ptr, allocation_start.as_ptr()) };
2582
2583    let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state) };
2584    unsafe { core::ptr::write(field_ptr as *mut *mut State, copy) };
2585
2586    ReturnCode::Ok
2587}
2588
2589pub fn undermine(stream: &mut InflateStream, subvert: i32) -> ReturnCode {
2590    stream.state.flags.update(Flags::SANE, (!subvert) != 0);
2591
2592    ReturnCode::Ok
2593}
2594
2595/// Configures whether the checksum is calculated and checked.
2596pub fn validate(stream: &mut InflateStream, check: bool) -> ReturnCode {
2597    if check && stream.state.wrap != 0 {
2598        stream.state.wrap |= 0b100;
2599    } else {
2600        stream.state.wrap &= !0b100;
2601    }
2602
2603    ReturnCode::Ok
2604}
2605
2606pub fn mark(stream: &InflateStream) -> c_long {
2607    if stream.next_out.is_null() || (stream.next_in.is_null() && stream.avail_in != 0) {
2608        return c_long::MIN;
2609    }
2610
2611    let state = &stream.state;
2612
2613    let length = match state.mode {
2614        Mode::CopyBlock => state.length,
2615        Mode::Match => state.was - state.length,
2616        _ => 0,
2617    };
2618
2619    (((state.back as c_long) as c_ulong) << 16) as c_long + length as c_long
2620}
2621
2622pub fn set_dictionary(stream: &mut InflateStream, dictionary: &[u8]) -> ReturnCode {
2623    if stream.state.wrap != 0 && !matches!(stream.state.mode, Mode::Dict) {
2624        return ReturnCode::StreamError;
2625    }
2626
2627    // check for correct dictionary identifier
2628    if matches!(stream.state.mode, Mode::Dict) {
2629        let dictid = adler32(1, dictionary);
2630
2631        if dictid != stream.state.checksum {
2632            return ReturnCode::DataError;
2633        }
2634    }
2635
2636    stream.state.window.extend(
2637        dictionary,
2638        stream.state.gzip_flags,
2639        false,
2640        &mut stream.state.checksum,
2641        &mut stream.state.crc_fold,
2642    );
2643
2644    stream.state.flags.update(Flags::HAVE_DICT, true);
2645
2646    ReturnCode::Ok
2647}
2648
2649pub fn end<'a>(stream: &'a mut InflateStream<'_>) -> &'a mut z_stream {
2650    let alloc = stream.alloc;
2651    let allocation_start = stream.state.allocation_start;
2652    let total_allocation_size = stream.state.total_allocation_size;
2653
2654    let mut window = Window::empty();
2655    core::mem::swap(&mut window, &mut stream.state.window);
2656
2657    let stream = stream.as_z_stream_mut();
2658    let _ = core::mem::replace(&mut stream.state, core::ptr::null_mut());
2659
2660    unsafe { alloc.deallocate(allocation_start, total_allocation_size) };
2661
2662    stream
2663}
2664
2665/// # Safety
2666///
2667/// The caller must guarantee:
2668///
2669/// * If `head` is `Some`:
2670///     - If `head.extra` is not NULL, it must be writable for at least `head.extra_max` bytes
2671///     - if `head.name` is not NULL, it must be writable for at least `head.name_max` bytes
2672///     - if `head.comment` is not NULL, it must be writable for at least `head.comm_max` bytes
2673pub unsafe fn get_header<'a>(
2674    stream: &mut InflateStream<'a>,
2675    head: Option<&'a mut gz_header>,
2676) -> ReturnCode {
2677    if (stream.state.wrap & 2) == 0 {
2678        return ReturnCode::StreamError;
2679    }
2680
2681    stream.state.head = head.map(|head| {
2682        head.done = 0;
2683        head
2684    });
2685    ReturnCode::Ok
2686}
2687
2688/// # Safety
2689///
2690/// The `dictionary` must have enough space for the dictionary.
2691pub unsafe fn get_dictionary(stream: &InflateStream<'_>, dictionary: *mut u8) -> usize {
2692    let whave = stream.state.window.have();
2693    let wnext = stream.state.window.next();
2694
2695    if !dictionary.is_null() {
2696        unsafe {
2697            core::ptr::copy_nonoverlapping(
2698                stream.state.window.as_ptr().add(wnext),
2699                dictionary,
2700                whave - wnext,
2701            );
2702
2703            core::ptr::copy_nonoverlapping(
2704                stream.state.window.as_ptr(),
2705                dictionary.add(whave).sub(wnext).cast(),
2706                wnext,
2707            );
2708        }
2709    }
2710
2711    stream.state.window.have()
2712}
2713
2714#[cfg(test)]
2715mod tests {
2716    use super::*;
2717
2718    #[test]
2719    fn uncompress_buffer_overflow() {
2720        let mut output = [0; 1 << 13];
2721        let input = [
2722            72, 137, 58, 0, 3, 39, 255, 255, 255, 255, 255, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
2723            14, 14, 184, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 184, 14, 14,
2724            14, 14, 14, 14, 14, 63, 14, 14, 14, 14, 14, 14, 14, 14, 184, 14, 14, 255, 14, 103, 14,
2725            14, 14, 14, 14, 14, 61, 14, 255, 255, 63, 14, 14, 14, 14, 14, 14, 14, 14, 184, 14, 14,
2726            255, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 6, 14, 14, 14, 14, 14, 14, 14, 14, 71,
2727            4, 137, 106,
2728        ];
2729
2730        let config = InflateConfig { window_bits: 15 };
2731
2732        let (_decompressed, err) = decompress_slice(&mut output, &input, config);
2733        assert_eq!(err, ReturnCode::DataError);
2734    }
2735}