Skip to main content

git_zero_core/zlib/
inflate.rs

1mod huffman;
2
3use super::adler::Adler32;
4use crate::{Error, Result};
5use huffman::{Bits, Huffman, Symbol};
6
7// A missing value retains the reader's partial state for the next input chunk.
8macro_rules! ready {
9    ($value:expr, $pending:expr) => {
10        match $value? {
11            Some(value) => value,
12            None => return Ok($pending),
13        }
14    };
15}
16
17/// DEFLATE's maximum back-reference distance. Each decoder borrows one window.
18pub const WINDOW_SIZE: usize = 32_768;
19
20const CODE_LENGTH_ORDER: [usize; 19] = [
21    16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
22];
23
24// RFC 1951 length/distance bases and the number of following extra bits.
25// Tables keep parameter decoding independent of the Huffman symbol reader.
26const LENGTH_CODES: [(u16, u8); 29] = [
27    (3, 0),
28    (4, 0),
29    (5, 0),
30    (6, 0),
31    (7, 0),
32    (8, 0),
33    (9, 0),
34    (10, 0),
35    (11, 1),
36    (13, 1),
37    (15, 1),
38    (17, 1),
39    (19, 2),
40    (23, 2),
41    (27, 2),
42    (31, 2),
43    (35, 3),
44    (43, 3),
45    (51, 3),
46    (59, 3),
47    (67, 4),
48    (83, 4),
49    (99, 4),
50    (115, 4),
51    (131, 5),
52    (163, 5),
53    (195, 5),
54    (227, 5),
55    (258, 0),
56];
57const DISTANCE_CODES: [(u16, u8); 30] = [
58    (1, 0),
59    (2, 0),
60    (3, 0),
61    (4, 0),
62    (5, 1),
63    (7, 1),
64    (9, 2),
65    (13, 2),
66    (17, 3),
67    (25, 3),
68    (33, 4),
69    (49, 4),
70    (65, 5),
71    (97, 5),
72    (129, 6),
73    (193, 6),
74    (257, 7),
75    (385, 7),
76    (513, 8),
77    (769, 8),
78    (1025, 9),
79    (1537, 9),
80    (2049, 10),
81    (3073, 10),
82    (4097, 11),
83    (6145, 11),
84    (8193, 12),
85    (12289, 12),
86    (16385, 13),
87    (24577, 13),
88];
89
90/// Budgets for one zlib stream, including its decompressed loose-object header.
91#[derive(Clone, Copy, Debug, Eq, PartialEq)]
92pub struct InflateLimits {
93    pub max_output: u64,
94    /// Before each output byte, enforce
95    /// `output <= consumed_input * max_ratio + ratio_slack` using saturating math.
96    /// Input counts only bytes consumed from this stream, including its wrapper.
97    pub max_ratio: u32,
98    /// An explicit allowance for highly compressible prefixes. Zero is permitted.
99    pub ratio_slack: u64,
100}
101
102#[derive(Clone, Copy, Debug, Eq, PartialEq)]
103pub enum InflateStatus {
104    /// All supplied input was consumed; provide more, preserving this decoder.
105    NeedInput,
106    /// A pending byte needs output space; resubmit any unconsumed input suffix.
107    NeedOutput,
108    /// The final block and Adler-32 trailer have been validated.
109    Finished,
110}
111
112#[derive(Clone, Copy, Debug, Eq, PartialEq)]
113pub struct InflateProgress {
114    pub consumed: usize,
115    pub written: usize,
116    pub status: InflateStatus,
117}
118
119/// Incremental zlib decoder with no allocation or dependency on `std`/`alloc`.
120///
121/// The caller owns a 32 KiB history window, this state (less than 2 KiB), and
122/// arbitrarily sized input/output chunks. Stored, fixed and dynamic Huffman
123/// blocks are supported. Preset dictionaries return [`Error::Unsupported`].
124/// Output is provisional until [`InflateStatus::Finished`]; discard it on error.
125/// Inflation does not validate Git object headers, lengths or IDs.
126pub struct Inflater<'a> {
127    window: &'a mut [u8; WINDOW_SIZE],
128    position: usize,
129    window_limit: usize,
130    limits: InflateLimits,
131    bits: Bits,
132    symbol: Symbol,
133    literal: Huffman<288, 256>,
134    distance: Huffman<32, 32>,
135    code: Huffman<19, 16>,
136    lengths: [u8; 320],
137    dynamic: Dynamic,
138    state: State,
139    final_block: bool,
140    total_output: u64,
141    adler: Adler32,
142    failure: Option<Error>,
143    raw: bool,
144}
145
146impl<'a> Inflater<'a> {
147    pub fn new(window: &'a mut [u8; WINDOW_SIZE], limits: InflateLimits) -> Self {
148        Self {
149            window,
150            position: 0,
151            window_limit: WINDOW_SIZE,
152            limits,
153            bits: Bits::default(),
154            symbol: Symbol::default(),
155            literal: Huffman::new(),
156            distance: Huffman::new(),
157            code: Huffman::new(),
158            lengths: [0; 320],
159            dynamic: Dynamic::default(),
160            state: State::Header,
161            final_block: false,
162            total_output: 0,
163            adler: Adler32::new(),
164            failure: None,
165            raw: false,
166        }
167    }
168
169    /// Decode a raw RFC 1951 stream. The host must validate its outer envelope
170    /// and checksum before exposing output. `reset` starts a zlib stream again.
171    pub fn new_raw(window: &'a mut [u8; WINDOW_SIZE], limits: InflateLimits) -> Self {
172        let mut decoder = Self::new(window, limits);
173        decoder.state = State::Block;
174        decoder.raw = true;
175        decoder
176    }
177
178    /// Start an independent stream. Old history is inaccessible: each distance
179    /// must refer to bytes emitted by the new stream before it can be read.
180    pub fn reset(&mut self, limits: InflateLimits) {
181        self.position = 0;
182        self.window_limit = WINDOW_SIZE;
183        self.limits = limits;
184        self.bits = Bits::default();
185        self.symbol = Symbol::default();
186        self.dynamic = Dynamic::default();
187        self.state = State::Header;
188        self.final_block = false;
189        self.total_output = 0;
190        self.adler = Adler32::new();
191        self.failure = None;
192        self.raw = false;
193    }
194
195    pub fn total_input(&self) -> u64 {
196        self.bits.total
197    }
198
199    pub fn total_output(&self) -> u64 {
200        self.total_output
201    }
202
203    /// Consume only one stream, leaving subsequent pack entries/trailing bytes
204    /// untouched. Empty chunks are accepted. `end_of_input` means this slice
205    /// contains the last available bytes: a need for further input is truncation,
206    /// while a need for more output remains resumable with the unconsumed suffix.
207    ///
208    /// Errors are terminal until `reset`; output from the failing call may have
209    /// been modified and must be discarded. Limits are checked before emitting
210    /// each byte and do not depend on input/output chunk boundaries.
211    pub fn update(
212        &mut self,
213        input: &[u8],
214        output: &mut [u8],
215        end_of_input: bool,
216    ) -> Result<InflateProgress> {
217        if let Some(error) = self.failure {
218            return Err(error);
219        }
220        let mut remaining = input;
221        let result = self
222            .run(&mut remaining, output)
223            .and_then(|(written, status)| {
224                if end_of_input && status == InflateStatus::NeedInput {
225                    return Err(Error::InvalidZlib);
226                }
227                Ok(InflateProgress {
228                    consumed: input.len() - remaining.len(),
229                    written,
230                    status,
231                })
232            });
233        if let Err(error) = result {
234            self.failure = Some(error);
235        }
236        result
237    }
238
239    fn run(&mut self, input: &mut &[u8], output: &mut [u8]) -> Result<(usize, InflateStatus)> {
240        let mut written = 0;
241        // An unavailable bit/symbol leaves its partial state intact.
242        macro_rules! bits {
243            ($count:expr) => {
244                ready!(
245                    self.bits.read($count, input),
246                    (written, InflateStatus::NeedInput)
247                )
248            };
249        }
250        macro_rules! symbol {
251            ($table:ident) => {
252                ready!(
253                    self.symbol.read(&self.$table, &mut self.bits, input),
254                    (written, InflateStatus::NeedInput)
255                )
256            };
257        }
258        loop {
259            match self.state {
260                State::Header => {
261                    self.window_limit = zlib_window(bits!(16))?;
262                    self.state = State::Block;
263                }
264                State::Block => {
265                    let header = bits!(3);
266                    self.begin_block(header)?;
267                }
268                State::StoredLength => self.state = State::StoredComplement(bits!(16) as u16),
269                State::StoredComplement(length) => {
270                    if bits!(16) as u16 != !length {
271                        return Err(Error::InvalidZlib);
272                    }
273                    self.state = State::Stored(length);
274                }
275                State::Stored(0) => self.end_block(),
276                State::Stored(remaining) => {
277                    let count = self.copy_stored(input, &mut output[written..], remaining);
278                    if count != 0 {
279                        written += count;
280                        continue;
281                    }
282                    // Preserve the pending byte and failure position even when
283                    // a run ends at an output, input or budget boundary.
284                    let byte = bits!(8) as u8;
285                    self.state = State::Literal {
286                        byte,
287                        stored_remaining: Some(remaining - 1),
288                    };
289                }
290                State::Dynamic | State::CodeLengths { .. } | State::Lengths | State::Repeat(_) => {
291                    if !self.read_dynamic_tables(input)? {
292                        return Ok((written, InflateStatus::NeedInput));
293                    }
294                }
295                State::Compressed => {
296                    let value = symbol!(literal);
297                    self.state = match value {
298                        0..=255 => State::Literal {
299                            byte: value as u8,
300                            stored_remaining: None,
301                        },
302                        256 => {
303                            self.end_block();
304                            continue;
305                        }
306                        257..=285 => State::Length(value - 257),
307                        _ => return Err(Error::InvalidZlib),
308                    };
309                }
310                State::Literal {
311                    byte,
312                    stored_remaining,
313                } => {
314                    if written == output.len() {
315                        return Ok((written, InflateStatus::NeedOutput));
316                    }
317                    self.emit(byte, &mut output[written])?;
318                    written += 1;
319                    self.state = stored_remaining.map_or(State::Compressed, State::Stored);
320                }
321                State::Length(index) => {
322                    let (base, extra) = LENGTH_CODES[usize::from(index)];
323                    self.state = State::Distance(base + bits!(extra) as u16);
324                }
325                State::Distance(length) => {
326                    let index = symbol!(distance);
327                    if usize::from(index) >= DISTANCE_CODES.len() {
328                        return Err(Error::InvalidZlib);
329                    }
330                    self.state = State::DistanceExtra { length, index };
331                }
332                State::DistanceExtra { length, index } => {
333                    let (base, extra) = DISTANCE_CODES[usize::from(index)];
334                    let distance = base + bits!(extra) as u16;
335                    if usize::from(distance) > self.window_limit
336                        || u64::from(distance) > self.total_output
337                    {
338                        return Err(Error::InvalidZlib);
339                    }
340                    self.state = State::Copy {
341                        remaining: length,
342                        distance,
343                    };
344                }
345                State::Copy {
346                    remaining,
347                    distance,
348                } => {
349                    if written == output.len() {
350                        return Ok((written, InflateStatus::NeedOutput));
351                    }
352                    written +=
353                        self.copy_back_reference(&mut output[written..], remaining, distance)?;
354                }
355                State::Trailer { read, value } => {
356                    let value = (value << 8) | bits!(8);
357                    if read == 3 {
358                        let actual = self.adler.value();
359                        if value != actual {
360                            return Err(Error::InvalidZlib);
361                        }
362                        self.state = State::Done;
363                    } else {
364                        self.state = State::Trailer {
365                            read: read + 1,
366                            value,
367                        };
368                    }
369                }
370                State::Done => return Ok((written, InflateStatus::Finished)),
371            }
372        }
373    }
374
375    fn begin_block(&mut self, header: u32) -> Result<()> {
376        self.final_block = header & 1 != 0;
377        self.state = match header >> 1 {
378            0 => {
379                self.bits.align();
380                State::StoredLength
381            }
382            1 => {
383                self.fixed_tables()?;
384                State::Compressed
385            }
386            2 => State::Dynamic,
387            _ => return Err(Error::InvalidZlib),
388        };
389        Ok(())
390    }
391
392    /// Advance one dynamic-table phase, retaining partial bits/symbols when
393    /// more input is needed. Keeping table construction separate makes the
394    /// object-emission loop independent of the code-length grammar.
395    fn read_dynamic_tables(&mut self, input: &mut &[u8]) -> Result<bool> {
396        macro_rules! bits {
397            ($count:expr) => {
398                ready!(self.bits.read($count, input), false)
399            };
400        }
401        macro_rules! symbol {
402            ($table:ident) => {
403                ready!(self.symbol.read(&self.$table, &mut self.bits, input), false)
404            };
405        }
406        match self.state {
407            State::Dynamic => {
408                let header = bits!(14);
409                let literal = (header & 31) as u16 + 257;
410                if literal > 286 {
411                    return Err(Error::InvalidZlib);
412                }
413                let distance = ((header >> 5) & 31) as u16 + 1;
414                let count = ((header >> 10) & 15) as u8 + 4;
415                self.lengths.fill(0);
416                self.dynamic = Dynamic {
417                    next: 0,
418                    literal,
419                    total: literal + distance,
420                };
421                self.state = State::CodeLengths { next: 0, count };
422            }
423            State::CodeLengths { next, count } => {
424                self.lengths[CODE_LENGTH_ORDER[usize::from(next)]] = bits!(3) as u8;
425                self.state = if next + 1 == count {
426                    self.code.build(&self.lengths[..19], false, false)?;
427                    State::Lengths
428                } else {
429                    State::CodeLengths {
430                        next: next + 1,
431                        count,
432                    }
433                };
434            }
435            State::Lengths => {
436                let next = self.dynamic.next;
437                let value = symbol!(code);
438                if value <= 15 {
439                    self.lengths[usize::from(next)] = value as u8;
440                    self.finish_lengths(1)?;
441                } else {
442                    if value == 16 && next == 0 {
443                        return Err(Error::InvalidZlib);
444                    }
445                    self.state = State::Repeat(value);
446                }
447            }
448            State::Repeat(value) => {
449                let next = self.dynamic.next;
450                let (extra, base, length) = match value {
451                    16 => (2, 3, self.lengths[usize::from(next - 1)]),
452                    17 => (3, 3, 0),
453                    18 => (7, 11, 0),
454                    _ => return Err(Error::InvalidZlib),
455                };
456                let count = bits!(extra) as u16 + base;
457                if count > self.dynamic.total - next {
458                    return Err(Error::InvalidZlib);
459                }
460                self.lengths[usize::from(next)..usize::from(next + count)].fill(length);
461                self.finish_lengths(count)?;
462            }
463            _ => unreachable!("only dynamic-table phases enter this helper"),
464        }
465        Ok(true)
466    }
467
468    #[inline]
469    fn copy_stored(&mut self, input: &mut &[u8], output: &mut [u8], remaining: u16) -> usize {
470        // Each stored byte consumes one input byte before its limit
471        // check. With a positive integer ratio, an allowed first
472        // byte guarantees the rest of this run's ratio checks.
473        let next_input = self.bits.total.saturating_add(1);
474        let ratio_limit = next_input
475            .saturating_mul(u64::from(self.limits.max_ratio))
476            .saturating_add(self.limits.ratio_slack);
477        if self.bits.count != 0 || self.total_output >= ratio_limit {
478            return 0;
479        }
480        let budget = if self.limits.max_ratio == 0 {
481            self.limits.max_output.min(self.limits.ratio_slack)
482        } else {
483            self.limits.max_output
484        };
485        let count = usize::from(remaining)
486            .min(input.len())
487            .min(output.len())
488            .min(WINDOW_SIZE)
489            .min(
490                budget
491                    .saturating_sub(self.total_output)
492                    .min(u16::MAX as u64) as usize,
493            )
494            .min((u64::MAX - self.bits.total).min(u16::MAX as u64) as usize);
495        if count == 0 {
496            return 0;
497        }
498        output[..count].copy_from_slice(&input[..count]);
499        self.bits.total += count as u64;
500        *input = &input[count..];
501        self.emit_slice(&output[..count]);
502        self.state = State::Stored(remaining - count as u16);
503        count
504    }
505
506    #[inline]
507    fn copy_back_reference(
508        &mut self,
509        output: &mut [u8],
510        remaining: u16,
511        distance: u16,
512    ) -> Result<usize> {
513        let count = usize::from(remaining)
514            .min(output.len())
515            .min(self.output_budget().min(u16::MAX as u64) as usize);
516        if count == 0 {
517            return Err(Error::LimitExceeded);
518        }
519        let target = &mut output[..count];
520        let distance = usize::from(distance);
521        let position = (self.position + WINDOW_SIZE - distance) & (WINDOW_SIZE - 1);
522        let seed = count.min(distance);
523        let first = seed.min(WINDOW_SIZE - position);
524        target[..first].copy_from_slice(&self.window[position..position + first]);
525        target[first..seed].copy_from_slice(&self.window[..seed - first]);
526        // Expand overlapping copies from already produced bytes,
527        // doubling the initialized prefix on each iteration.
528        let mut initialized = seed;
529        while initialized < count {
530            let next = initialized.min(count - initialized);
531            target.copy_within(..next, initialized);
532            initialized += next;
533        }
534        self.emit_slice(target);
535        self.state = if remaining == count as u16 {
536            State::Compressed
537        } else {
538            State::Copy {
539                remaining: remaining - count as u16,
540                distance: distance as u16,
541            }
542        };
543        Ok(count)
544    }
545
546    fn output_budget(&self) -> u64 {
547        let ratio_limit = self
548            .bits
549            .total
550            .saturating_mul(u64::from(self.limits.max_ratio))
551            .saturating_add(self.limits.ratio_slack);
552        self.limits
553            .max_output
554            .min(ratio_limit)
555            .saturating_sub(self.total_output)
556    }
557
558    fn emit(&mut self, byte: u8, output: &mut u8) -> Result<()> {
559        if self.output_budget() == 0 {
560            return Err(Error::LimitExceeded);
561        }
562        *output = byte;
563        self.emit_slice(core::slice::from_ref(output));
564        Ok(())
565    }
566
567    /// Commit an already budgeted run of at most one history window.
568    #[inline]
569    fn emit_slice(&mut self, bytes: &[u8]) {
570        let first = bytes.len().min(WINDOW_SIZE - self.position);
571        self.window[self.position..self.position + first].copy_from_slice(&bytes[..first]);
572        self.window[..bytes.len() - first].copy_from_slice(&bytes[first..]);
573        self.position = (self.position + bytes.len()) & (WINDOW_SIZE - 1);
574        self.total_output += bytes.len() as u64;
575        self.adler.update(bytes);
576    }
577
578    fn end_block(&mut self) {
579        self.state = if self.final_block {
580            self.bits.align();
581            if self.raw {
582                State::Done
583            } else {
584                State::Trailer { read: 0, value: 0 }
585            }
586        } else {
587            State::Block
588        };
589    }
590
591    fn fixed_tables(&mut self) -> Result<()> {
592        self.lengths[..144].fill(8);
593        self.lengths[144..256].fill(9);
594        self.lengths[256..280].fill(7);
595        self.lengths[280..288].fill(8);
596        self.lengths[288..].fill(5);
597        self.literal.build(&self.lengths[..288], false, false)?;
598        self.distance.build(&self.lengths[288..], false, false)
599    }
600
601    fn finish_lengths(&mut self, count: u16) -> Result<()> {
602        self.dynamic.next += count;
603        let Dynamic {
604            next,
605            literal,
606            total,
607        } = self.dynamic;
608        self.state = if next == total {
609            if self.lengths[256] == 0 {
610                return Err(Error::InvalidZlib);
611            }
612            self.literal
613                .build(&self.lengths[..usize::from(literal)], false, true)?;
614            self.distance.build(
615                &self.lengths[usize::from(literal)..usize::from(total)],
616                true,
617                true,
618            )?;
619            State::Compressed
620        } else {
621            State::Lengths
622        };
623        Ok(())
624    }
625}
626
627fn zlib_window(header: u32) -> Result<usize> {
628    let cmf = header & 255;
629    let flg = header >> 8;
630    if cmf & 15 != 8 || cmf >> 4 > 7 || (cmf * 256 + flg) % 31 != 0 {
631        return Err(Error::InvalidZlib);
632    }
633    if flg & 32 != 0 {
634        return Err(Error::Unsupported);
635    }
636    Ok(1 << ((cmf >> 4) + 8))
637}
638
639/// Counts shared by the resumable phases of one dynamic Huffman header.
640#[derive(Clone, Copy, Default)]
641struct Dynamic {
642    next: u16,
643    literal: u16,
644    total: u16,
645}
646
647#[derive(Clone, Copy)]
648enum State {
649    Header,
650    Block,
651    StoredLength,
652    StoredComplement(u16),
653    Stored(u16),
654    Dynamic,
655    CodeLengths {
656        next: u8,
657        count: u8,
658    },
659    Lengths,
660    Repeat(u16),
661    Compressed,
662    Literal {
663        byte: u8,
664        stored_remaining: Option<u16>,
665    },
666    Length(u16),
667    Distance(u16),
668    DistanceExtra {
669        length: u16,
670        index: u16,
671    },
672    Copy {
673        remaining: u16,
674        distance: u16,
675    },
676    Trailer {
677        read: u8,
678        value: u32,
679    },
680    Done,
681}