Skip to main content

zstd_zero/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3#![forbid(unsafe_code)]
4
5#[cfg(test)]
6extern crate std;
7
8mod bitstream;
9mod error;
10mod fse;
11mod huffman;
12mod xxhash;
13
14use bitstream::BackwardBits;
15pub use error::DecodeError;
16use fse::Table as FseTable;
17use huffman::Table as HuffmanTable;
18use xxhash::XxHash64;
19
20pub const MAX_BLOCK_SIZE: usize = 128 * 1024;
21pub const MAX_FRAME_HEADER_SIZE: usize = 18;
22
23const ZSTD_MAGIC: u32 = 0xfd2f_b528;
24const SKIPPABLE_MAGIC_MIN: u32 = 0x184d_2a50;
25const SKIPPABLE_MAGIC_MAX: u32 = 0x184d_2a5f;
26
27#[derive(Clone, Copy, Debug, Eq, PartialEq)]
28pub struct FrameHeader {
29    pub window_size: u64,
30    pub content_size: Option<u64>,
31    pub dictionary_id: u32,
32    pub has_checksum: bool,
33}
34
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub enum StreamHeader {
37    Zstandard(FrameHeader),
38    Skippable { magic: u32, size: u32 },
39}
40
41#[derive(Clone, Copy, Debug, Eq, PartialEq)]
42pub enum FrameKind {
43    Zstandard,
44    Skippable { magic: u32, size: u32 },
45}
46
47#[derive(Clone, Copy, Debug, Eq, PartialEq)]
48pub enum HeaderStatus {
49    NeedMore { minimum: usize },
50    Complete { header: StreamHeader, size: usize },
51}
52
53#[derive(Debug, Eq, PartialEq)]
54pub enum DecodeStep<'a> {
55    NeedInput {
56        consumed: usize,
57    },
58    FrameStarted {
59        consumed: usize,
60        header: StreamHeader,
61    },
62    Output {
63        consumed: usize,
64        bytes: &'a [u8],
65    },
66    FrameFinished {
67        consumed: usize,
68        kind: FrameKind,
69    },
70}
71
72impl DecodeStep<'_> {
73    pub const fn consumed(&self) -> usize {
74        match self {
75            Self::NeedInput { consumed }
76            | Self::FrameStarted { consumed, .. }
77            | Self::Output { consumed, .. }
78            | Self::FrameFinished { consumed, .. } => *consumed,
79        }
80    }
81}
82
83/// A failure while driving a [`Decoder`] through its callback API.
84#[derive(Debug, Eq, PartialEq)]
85pub enum StreamError<E> {
86    Decode(DecodeError),
87    Output(E),
88    DecoderStalled,
89}
90
91impl<E: core::fmt::Display> core::fmt::Display for StreamError<E> {
92    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
93        match self {
94            Self::Decode(error) => write!(formatter, "Zstandard decode failed: {error}"),
95            Self::Output(error) => write!(formatter, "Zstandard output failed: {error}"),
96            Self::DecoderStalled => {
97                formatter.write_str("Zstandard decoder stopped making progress")
98            }
99        }
100    }
101}
102
103enum InternalStep {
104    NeedInput {
105        consumed: usize,
106    },
107    FrameStarted {
108        consumed: usize,
109        header: StreamHeader,
110    },
111    Output {
112        consumed: usize,
113        start: usize,
114        length: usize,
115    },
116    FrameFinished {
117        consumed: usize,
118        kind: FrameKind,
119    },
120}
121
122pub struct DecoderBuffers<'a> {
123    pub history: &'a mut [u8],
124    pub block: &'a mut [u8],
125    pub literals: &'a mut [u8],
126}
127
128#[derive(Clone, Copy)]
129enum State {
130    Header,
131    Skippable {
132        magic: u32,
133        size: u32,
134        remaining: usize,
135    },
136    BlockHeader,
137    BlockPayload {
138        header: BlockHeader,
139        filled: usize,
140    },
141    Checksum {
142        filled: usize,
143    },
144    FrameDone(FrameKind),
145}
146
147#[derive(Clone, Copy)]
148struct BlockHeader {
149    last: bool,
150    kind: BlockKind,
151    size: usize,
152}
153
154#[derive(Clone, Copy, Eq, PartialEq)]
155enum BlockKind {
156    Raw,
157    Rle,
158    Compressed,
159}
160
161pub struct Decoder<'a> {
162    history: &'a mut [u8],
163    block: &'a mut [u8],
164    literals: &'a mut [u8],
165    state: State,
166    poisoned: bool,
167    completed_frames: u64,
168    header_buffer: [u8; MAX_FRAME_HEADER_SIZE],
169    header_len: usize,
170    block_header_buffer: [u8; 3],
171    block_header_len: usize,
172    checksum_buffer: [u8; 4],
173    current_header: Option<FrameHeader>,
174    block_limit: usize,
175    history_position: usize,
176    frame_output: u64,
177    pending_start: usize,
178    pending_len: usize,
179    offsets: [u32; 3],
180    checksum: XxHash64,
181    huffman: HuffmanTable,
182    literal_lengths: FseTable,
183    offsets_table: FseTable,
184    match_lengths: FseTable,
185}
186
187impl<'a> Decoder<'a> {
188    pub fn new(buffers: DecoderBuffers<'a>) -> Self {
189        Self {
190            history: buffers.history,
191            block: buffers.block,
192            literals: buffers.literals,
193            state: State::Header,
194            poisoned: false,
195            completed_frames: 0,
196            header_buffer: [0; MAX_FRAME_HEADER_SIZE],
197            header_len: 0,
198            block_header_buffer: [0; 3],
199            block_header_len: 0,
200            checksum_buffer: [0; 4],
201            current_header: None,
202            block_limit: 0,
203            history_position: 0,
204            frame_output: 0,
205            pending_start: 0,
206            pending_len: 0,
207            offsets: [1, 4, 8],
208            checksum: XxHash64::new(),
209            huffman: HuffmanTable::new(),
210            literal_lengths: FseTable::new(),
211            offsets_table: FseTable::new(),
212            match_lengths: FseTable::new(),
213        }
214    }
215
216    pub fn decode<'decoder>(
217        &'decoder mut self,
218        input: &[u8],
219    ) -> Result<DecodeStep<'decoder>, DecodeError> {
220        if self.poisoned {
221            return Err(DecodeError::DecoderPoisoned);
222        }
223        let step = match self.decode_inner(input) {
224            Ok(step) => step,
225            Err(error) => {
226                self.poisoned = true;
227                return Err(error);
228            }
229        };
230        Ok(match step {
231            InternalStep::NeedInput { consumed } => DecodeStep::NeedInput { consumed },
232            InternalStep::FrameStarted { consumed, header } => {
233                DecodeStep::FrameStarted { consumed, header }
234            }
235            InternalStep::Output {
236                consumed,
237                start,
238                length,
239            } => DecodeStep::Output {
240                consumed,
241                bytes: &self.history[start..start + length],
242            },
243            InternalStep::FrameFinished { consumed, kind } => {
244                DecodeStep::FrameFinished { consumed, kind }
245            }
246        })
247    }
248
249    /// Consumes an input fragment and sends decoded bytes to `output`.
250    ///
251    /// This is the convenient callback-driven counterpart to [`decode`](Self::decode).
252    /// Frame events are handled internally while output errors remain distinct
253    /// from compressed-stream errors.
254    pub fn push<E>(
255        &mut self,
256        mut input: &[u8],
257        mut output: impl FnMut(&[u8]) -> Result<(), E>,
258    ) -> Result<(), StreamError<E>> {
259        let mut idle_steps = 0;
260        while !input.is_empty() {
261            let step = self.decode(input).map_err(StreamError::Decode)?;
262            let consumed = step.consumed();
263            if consumed > input.len() {
264                return Err(StreamError::DecoderStalled);
265            }
266            let needs_input = matches!(step, DecodeStep::NeedInput { .. });
267            let produced = match step {
268                DecodeStep::Output { bytes, .. } => {
269                    if bytes.is_empty() {
270                        false
271                    } else {
272                        output(bytes).map_err(StreamError::Output)?;
273                        true
274                    }
275                }
276                _ => false,
277            };
278            input = &input[consumed..];
279            if needs_input && !input.is_empty() {
280                return Err(StreamError::DecoderStalled);
281            }
282            if consumed != 0 || produced {
283                idle_steps = 0;
284            } else {
285                idle_steps += 1;
286                if idle_steps > 16 {
287                    return Err(StreamError::DecoderStalled);
288                }
289            }
290        }
291        Ok(())
292    }
293
294    /// Drains buffered output and validates the end of the stream.
295    pub fn finish_with<E>(
296        &mut self,
297        mut output: impl FnMut(&[u8]) -> Result<(), E>,
298    ) -> Result<(), StreamError<E>> {
299        let mut idle_steps = 0;
300        loop {
301            match self.decode(&[]).map_err(StreamError::Decode)? {
302                DecodeStep::NeedInput { .. } => break,
303                DecodeStep::Output { bytes, .. } if !bytes.is_empty() => {
304                    output(bytes).map_err(StreamError::Output)?;
305                    idle_steps = 0;
306                }
307                _ => {
308                    idle_steps += 1;
309                    if idle_steps > 16 {
310                        return Err(StreamError::DecoderStalled);
311                    }
312                }
313            }
314        }
315        self.finish().map_err(StreamError::Decode)
316    }
317
318    pub fn finish(&self) -> Result<(), DecodeError> {
319        if self.poisoned {
320            return Err(DecodeError::DecoderPoisoned);
321        }
322        if self.pending_len != 0 || self.header_len != 0 || self.completed_frames == 0 {
323            return Err(DecodeError::UnexpectedEof);
324        }
325        match self.state {
326            State::Header | State::FrameDone(_) => Ok(()),
327            _ => Err(DecodeError::UnexpectedEof),
328        }
329    }
330
331    pub fn reset(&mut self) {
332        self.state = State::Header;
333        self.poisoned = false;
334        self.completed_frames = 0;
335        self.header_len = 0;
336        self.block_header_len = 0;
337        self.current_header = None;
338        self.frame_output = 0;
339        self.pending_len = 0;
340        self.offsets = [1, 4, 8];
341        self.checksum = XxHash64::new();
342        self.huffman = HuffmanTable::new();
343        self.literal_lengths = FseTable::new();
344        self.offsets_table = FseTable::new();
345        self.match_lengths = FseTable::new();
346    }
347
348    fn decode_inner(&mut self, input: &[u8]) -> Result<InternalStep, DecodeError> {
349        if self.pending_len != 0 {
350            let start = self.pending_start;
351            let length = core::cmp::min(self.pending_len, self.history.len() - start);
352            self.pending_start = (start + length) % self.history.len();
353            self.pending_len -= length;
354            return Ok(InternalStep::Output {
355                consumed: 0,
356                start,
357                length,
358            });
359        }
360
361        let mut consumed = 0usize;
362        loop {
363            match self.state {
364                State::Header => match inspect_frame(&self.header_buffer[..self.header_len])? {
365                    HeaderStatus::NeedMore { minimum } => {
366                        if consumed == input.len() {
367                            return Ok(InternalStep::NeedInput { consumed });
368                        }
369                        let amount =
370                            core::cmp::min(minimum - self.header_len, input.len() - consumed);
371                        self.header_buffer[self.header_len..self.header_len + amount]
372                            .copy_from_slice(&input[consumed..consumed + amount]);
373                        self.header_len += amount;
374                        consumed += amount;
375                    }
376                    HeaderStatus::Complete { header, .. } => {
377                        self.header_len = 0;
378                        match header {
379                            StreamHeader::Zstandard(frame) => {
380                                self.start_frame(frame)?;
381                                self.state = State::BlockHeader;
382                            }
383                            StreamHeader::Skippable { magic, size } => {
384                                self.state = State::Skippable {
385                                    magic,
386                                    size,
387                                    remaining: size as usize,
388                                };
389                            }
390                        }
391                        return Ok(InternalStep::FrameStarted { consumed, header });
392                    }
393                },
394                State::Skippable {
395                    magic,
396                    size,
397                    remaining,
398                } => {
399                    let amount = core::cmp::min(remaining, input.len() - consumed);
400                    consumed += amount;
401                    let remaining = remaining - amount;
402                    if remaining == 0 {
403                        self.state = State::FrameDone(FrameKind::Skippable { magic, size });
404                    } else {
405                        self.state = State::Skippable {
406                            magic,
407                            size,
408                            remaining,
409                        };
410                        return Ok(InternalStep::NeedInput { consumed });
411                    }
412                }
413                State::BlockHeader => {
414                    let amount = core::cmp::min(3 - self.block_header_len, input.len() - consumed);
415                    self.block_header_buffer[self.block_header_len..self.block_header_len + amount]
416                        .copy_from_slice(&input[consumed..consumed + amount]);
417                    self.block_header_len += amount;
418                    consumed += amount;
419                    if self.block_header_len != 3 {
420                        return Ok(InternalStep::NeedInput { consumed });
421                    }
422                    self.block_header_len = 0;
423                    let header = parse_block_header(self.block_header_buffer, self.block_limit)?;
424                    let payload_size = if header.kind == BlockKind::Rle {
425                        1
426                    } else {
427                        header.size
428                    };
429                    if payload_size > self.block.len() {
430                        return Err(DecodeError::BlockScratchTooSmall {
431                            required: payload_size,
432                            provided: self.block.len(),
433                        });
434                    }
435                    self.state = State::BlockPayload { header, filled: 0 };
436                }
437                State::BlockPayload { header, filled } => {
438                    let payload_size = if header.kind == BlockKind::Rle {
439                        1
440                    } else {
441                        header.size
442                    };
443                    let amount = core::cmp::min(payload_size - filled, input.len() - consumed);
444                    self.block[filled..filled + amount]
445                        .copy_from_slice(&input[consumed..consumed + amount]);
446                    consumed += amount;
447                    let filled = filled + amount;
448                    if filled != payload_size {
449                        self.state = State::BlockPayload { header, filled };
450                        return Ok(InternalStep::NeedInput { consumed });
451                    }
452                    self.process_block(header)?;
453                    self.state = if header.last {
454                        if self.current_header()?.has_checksum {
455                            self.checksum_buffer = [0; 4];
456                            State::Checksum { filled: 0 }
457                        } else {
458                            self.validate_frame_end()?;
459                            State::FrameDone(FrameKind::Zstandard)
460                        }
461                    } else {
462                        State::BlockHeader
463                    };
464                    if self.pending_len != 0 {
465                        let start = self.pending_start;
466                        let length = core::cmp::min(self.pending_len, self.history.len() - start);
467                        self.pending_start = (start + length) % self.history.len();
468                        self.pending_len -= length;
469                        return Ok(InternalStep::Output {
470                            consumed,
471                            start,
472                            length,
473                        });
474                    }
475                }
476                State::Checksum { filled } => {
477                    let amount = core::cmp::min(4 - filled, input.len() - consumed);
478                    self.checksum_buffer[filled..filled + amount]
479                        .copy_from_slice(&input[consumed..consumed + amount]);
480                    consumed += amount;
481                    let filled = filled + amount;
482                    if filled != 4 {
483                        self.state = State::Checksum { filled };
484                        return Ok(InternalStep::NeedInput { consumed });
485                    }
486                    let expected = u32::from_le_bytes(self.checksum_buffer);
487                    let actual = self.checksum.digest() as u32;
488                    if actual != expected {
489                        return Err(DecodeError::ChecksumMismatch { expected, actual });
490                    }
491                    self.validate_frame_end()?;
492                    self.state = State::FrameDone(FrameKind::Zstandard);
493                }
494                State::FrameDone(kind) => {
495                    self.completed_frames = self
496                        .completed_frames
497                        .checked_add(1)
498                        .ok_or(DecodeError::ArithmeticOverflow)?;
499                    self.current_header = None;
500                    self.state = State::Header;
501                    return Ok(InternalStep::FrameFinished { consumed, kind });
502                }
503            }
504        }
505    }
506
507    fn start_frame(&mut self, header: FrameHeader) -> Result<(), DecodeError> {
508        if header.dictionary_id != 0 {
509            return Err(DecodeError::UnsupportedDictionary {
510                id: header.dictionary_id,
511            });
512        }
513        let window =
514            usize::try_from(header.window_size).map_err(|_| DecodeError::WindowTooLarge)?;
515        if window > self.history.len() {
516            return Err(DecodeError::HistoryTooSmall {
517                required: window,
518                provided: self.history.len(),
519            });
520        }
521        self.current_header = Some(header);
522        self.block_limit = core::cmp::min(window, MAX_BLOCK_SIZE);
523        self.frame_output = 0;
524        self.pending_len = 0;
525        self.offsets = [1, 4, 8];
526        self.checksum = XxHash64::new();
527        self.huffman = HuffmanTable::new();
528        self.literal_lengths = FseTable::new();
529        self.offsets_table = FseTable::new();
530        self.match_lengths = FseTable::new();
531        Ok(())
532    }
533
534    fn current_header(&self) -> Result<FrameHeader, DecodeError> {
535        self.current_header.ok_or(DecodeError::InvalidFrameHeader)
536    }
537
538    fn process_block(&mut self, header: BlockHeader) -> Result<(), DecodeError> {
539        let start = self.history_position;
540        let before = self.frame_output;
541        match header.kind {
542            BlockKind::Raw => {
543                for index in 0..header.size {
544                    self.write_byte(self.block[index])?;
545                }
546            }
547            BlockKind::Rle => {
548                let byte = self.block[0];
549                for _ in 0..header.size {
550                    self.write_byte(byte)?;
551                }
552            }
553            BlockKind::Compressed => self.decode_compressed(header.size)?,
554        }
555        let produced = usize::try_from(self.frame_output - before)
556            .map_err(|_| DecodeError::ArithmeticOverflow)?;
557        if produced > self.block_limit {
558            return Err(DecodeError::InvalidBlock);
559        }
560        self.record_output(start, produced);
561        Ok(())
562    }
563
564    fn decode_compressed(&mut self, size: usize) -> Result<(), DecodeError> {
565        let (literal_count, consumed) = decode_literals(
566            &self.block[..size],
567            self.literals,
568            &mut self.huffman,
569            self.block_limit,
570        )?;
571        let sequence_input = &self.block[consumed..size];
572        let (sequence_count, mut position) = parse_sequence_count(sequence_input)?;
573        if sequence_count == 0 {
574            if position != sequence_input.len() {
575                return Err(DecodeError::InvalidBlock);
576            }
577            let window_size = self.current_header()?.window_size;
578            let mut writer = HistoryWriter {
579                history: self.history,
580                position: &mut self.history_position,
581                frame_output: &mut self.frame_output,
582                window_size,
583            };
584            for byte in &self.literals[..literal_count] {
585                writer.write(*byte)?;
586            }
587            return Ok(());
588        }
589        let modes = *sequence_input
590            .get(position)
591            .ok_or(DecodeError::InvalidBlock)?;
592        position += 1;
593        if modes & 3 != 0 {
594            return Err(DecodeError::InvalidBlock);
595        }
596        position += build_sequence_table(
597            &mut self.literal_lengths,
598            modes >> 6,
599            &sequence_input[position..],
600            &LL_DEFAULT,
601            6,
602            35,
603            9,
604        )?;
605        position += build_sequence_table(
606            &mut self.offsets_table,
607            (modes >> 4) & 3,
608            &sequence_input[position..],
609            &OF_DEFAULT,
610            5,
611            31,
612            8,
613        )?;
614        position += build_sequence_table(
615            &mut self.match_lengths,
616            (modes >> 2) & 3,
617            &sequence_input[position..],
618            &ML_DEFAULT,
619            6,
620            52,
621            9,
622        )?;
623        let mut bits = BackwardBits::new(
624            sequence_input
625                .get(position..)
626                .ok_or(DecodeError::InvalidBitstream)?,
627        )?;
628        let mut ll_state = bits.read(self.literal_lengths.log())?;
629        let mut of_state = bits.read(self.offsets_table.log())?;
630        let mut ml_state = bits.read(self.match_lengths.log())?;
631        let mut literal_position = 0usize;
632        let window_size = self.current_header()?.window_size;
633        let literal_lengths = &self.literal_lengths;
634        let offsets_table = &self.offsets_table;
635        let match_lengths = &self.match_lengths;
636        let literals = &self.literals[..literal_count];
637        let repeated_offsets = &mut self.offsets;
638        let mut writer = HistoryWriter {
639            history: self.history,
640            position: &mut self.history_position,
641            frame_output: &mut self.frame_output,
642            window_size,
643        };
644
645        for sequence in 0..sequence_count {
646            let ll_code = literal_lengths.symbol(ll_state)? as usize;
647            let of_code = offsets_table.symbol(of_state)?;
648            let ml_code = match_lengths.symbol(ml_state)? as usize;
649            if ll_code >= LL_BASE.len() || ml_code >= ML_BASE.len() || of_code > 31 {
650                return Err(DecodeError::InvalidEntropyTable);
651            }
652            let raw_offset = (1u32 << of_code)
653                .checked_add(bits.read(of_code)?)
654                .ok_or(DecodeError::ArithmeticOverflow)?;
655            let match_length = ML_BASE[ml_code]
656                .checked_add(bits.read(ML_BITS[ml_code])?)
657                .ok_or(DecodeError::ArithmeticOverflow)?;
658            let literal_length = LL_BASE[ll_code]
659                .checked_add(bits.read(LL_BITS[ll_code])?)
660                .ok_or(DecodeError::ArithmeticOverflow)?;
661            let literal_end = literal_position
662                .checked_add(literal_length as usize)
663                .ok_or(DecodeError::ArithmeticOverflow)?;
664            if literal_end > literal_count {
665                return Err(DecodeError::InvalidBlock);
666            }
667            for byte in &literals[literal_position..literal_end] {
668                writer.write(*byte)?;
669            }
670            literal_position = literal_end;
671            let offset = resolve_offset(raw_offset, literal_length, repeated_offsets)?;
672            writer.copy_match(offset as usize, match_length as usize)?;
673
674            if sequence + 1 != sequence_count {
675                literal_lengths.update(&mut ll_state, &mut bits)?;
676                match_lengths.update(&mut ml_state, &mut bits)?;
677                offsets_table.update(&mut of_state, &mut bits)?;
678            }
679        }
680        if bits.remaining() != 0 {
681            return Err(DecodeError::InvalidBitstream);
682        }
683        for byte in &literals[literal_position..literal_count] {
684            writer.write(*byte)?;
685        }
686        Ok(())
687    }
688
689    fn write_byte(&mut self, byte: u8) -> Result<(), DecodeError> {
690        write_history_byte(
691            self.history,
692            &mut self.history_position,
693            &mut self.frame_output,
694            byte,
695        )
696    }
697
698    fn record_output(&mut self, start: usize, length: usize) {
699        if length == 0 {
700            return;
701        }
702        let first = core::cmp::min(length, self.history.len() - start);
703        self.checksum.update(&self.history[start..start + first]);
704        if first != length {
705            self.checksum.update(&self.history[..length - first]);
706        }
707        self.pending_start = start;
708        self.pending_len = length;
709    }
710
711    fn validate_frame_end(&self) -> Result<(), DecodeError> {
712        if let Some(expected) = self.current_header()?.content_size {
713            if self.frame_output != expected {
714                return Err(DecodeError::ContentSizeMismatch {
715                    expected,
716                    actual: self.frame_output,
717                });
718            }
719        }
720        Ok(())
721    }
722}
723
724struct HistoryWriter<'a> {
725    history: &'a mut [u8],
726    position: &'a mut usize,
727    frame_output: &'a mut u64,
728    window_size: u64,
729}
730
731impl HistoryWriter<'_> {
732    fn write(&mut self, byte: u8) -> Result<(), DecodeError> {
733        write_history_byte(self.history, self.position, self.frame_output, byte)
734    }
735
736    fn copy_match(&mut self, offset: usize, length: usize) -> Result<(), DecodeError> {
737        let available = core::cmp::min(*self.frame_output, self.window_size);
738        if offset == 0 || offset as u64 > available {
739            return Err(DecodeError::InvalidOffset);
740        }
741        for _ in 0..length {
742            let source = (*self.position + self.history.len() - offset) % self.history.len();
743            self.write(self.history[source])?;
744        }
745        Ok(())
746    }
747}
748
749fn write_history_byte(
750    history: &mut [u8],
751    position: &mut usize,
752    frame_output: &mut u64,
753    byte: u8,
754) -> Result<(), DecodeError> {
755    if history.is_empty() {
756        return Err(DecodeError::HistoryTooSmall {
757            required: 1,
758            provided: 0,
759        });
760    }
761    history[*position] = byte;
762    *position += 1;
763    if *position == history.len() {
764        *position = 0;
765    }
766    *frame_output = frame_output
767        .checked_add(1)
768        .ok_or(DecodeError::ArithmeticOverflow)?;
769    Ok(())
770}
771
772pub fn inspect_frame(input: &[u8]) -> Result<HeaderStatus, DecodeError> {
773    if input.len() < 4 {
774        return Ok(HeaderStatus::NeedMore { minimum: 4 });
775    }
776    let magic = read_u32(input);
777    if (SKIPPABLE_MAGIC_MIN..=SKIPPABLE_MAGIC_MAX).contains(&magic) {
778        if input.len() < 8 {
779            return Ok(HeaderStatus::NeedMore { minimum: 8 });
780        }
781        return Ok(HeaderStatus::Complete {
782            header: StreamHeader::Skippable {
783                magic,
784                size: read_u32(&input[4..]),
785            },
786            size: 8,
787        });
788    }
789    if magic != ZSTD_MAGIC {
790        return Err(DecodeError::InvalidMagic);
791    }
792    if input.len() < 5 {
793        return Ok(HeaderStatus::NeedMore { minimum: 5 });
794    }
795    let descriptor = input[4];
796    if descriptor & 0x08 != 0 {
797        return Err(DecodeError::InvalidFrameHeader);
798    }
799    let single_segment = descriptor & 0x20 != 0;
800    let dictionary_size = [0usize, 1, 2, 4][(descriptor & 3) as usize];
801    let content_flag = descriptor >> 6;
802    let content_size_bytes = match content_flag {
803        0 if single_segment => 1,
804        0 => 0,
805        1 => 2,
806        2 => 4,
807        _ => 8,
808    };
809    let size = 5 + usize::from(!single_segment) + dictionary_size + content_size_bytes;
810    if input.len() < size {
811        return Ok(HeaderStatus::NeedMore { minimum: size });
812    }
813    let mut position = 5usize;
814    let encoded_window = if single_segment {
815        None
816    } else {
817        let value = input[position];
818        position += 1;
819        let exponent = (value >> 3) as u32;
820        let base = 1u64 << (10 + exponent);
821        Some(base + (base / 8) * (value as u64 & 7))
822    };
823    let dictionary_id = read_variable(&input[position..position + dictionary_size]);
824    position += dictionary_size;
825    let content_size = if content_size_bytes == 0 {
826        None
827    } else {
828        let mut value = read_variable_u64(&input[position..position + content_size_bytes]);
829        if content_size_bytes == 2 {
830            value += 256;
831        }
832        Some(value)
833    };
834    let window_size = if single_segment {
835        content_size.ok_or(DecodeError::InvalidFrameHeader)?
836    } else {
837        encoded_window.ok_or(DecodeError::InvalidFrameHeader)?
838    };
839    Ok(HeaderStatus::Complete {
840        header: StreamHeader::Zstandard(FrameHeader {
841            window_size,
842            content_size,
843            dictionary_id,
844            has_checksum: descriptor & 4 != 0,
845        }),
846        size,
847    })
848}
849
850fn parse_block_header(bytes: [u8; 3], limit: usize) -> Result<BlockHeader, DecodeError> {
851    let value = bytes[0] as u32 | (bytes[1] as u32) << 8 | (bytes[2] as u32) << 16;
852    let kind = match (value >> 1) & 3 {
853        0 => BlockKind::Raw,
854        1 => BlockKind::Rle,
855        2 => BlockKind::Compressed,
856        _ => return Err(DecodeError::InvalidBlock),
857    };
858    let size = (value >> 3) as usize;
859    if size > limit {
860        return Err(DecodeError::InvalidBlock);
861    }
862    Ok(BlockHeader {
863        last: value & 1 != 0,
864        kind,
865        size,
866    })
867}
868
869fn decode_literals(
870    input: &[u8],
871    output: &mut [u8],
872    table: &mut HuffmanTable,
873    block_limit: usize,
874) -> Result<(usize, usize), DecodeError> {
875    let first = *input.first().ok_or(DecodeError::InvalidBlock)?;
876    let kind = first & 3;
877    let format = (first >> 2) & 3;
878    if kind <= 1 {
879        let (regenerated, header_size): (usize, usize) = match format {
880            0 | 2 => ((first >> 3) as usize, 1),
881            1 => {
882                let second = *input.get(1).ok_or(DecodeError::InvalidBlock)?;
883                (((first >> 4) as usize) | ((second as usize) << 4), 2)
884            }
885            _ => {
886                let second = *input.get(1).ok_or(DecodeError::InvalidBlock)?;
887                let third = *input.get(2).ok_or(DecodeError::InvalidBlock)?;
888                (
889                    ((first >> 4) as usize) | ((second as usize) << 4) | ((third as usize) << 12),
890                    3,
891                )
892            }
893        };
894        ensure_literal_space(regenerated, output.len(), block_limit)?;
895        if kind == 0 {
896            let end = header_size
897                .checked_add(regenerated)
898                .ok_or(DecodeError::ArithmeticOverflow)?;
899            let source = input
900                .get(header_size..end)
901                .ok_or(DecodeError::InvalidBlock)?;
902            output[..regenerated].copy_from_slice(source);
903            Ok((regenerated, end))
904        } else {
905            let value = *input.get(header_size).ok_or(DecodeError::InvalidBlock)?;
906            output[..regenerated].fill(value);
907            Ok((regenerated, header_size + 1))
908        }
909    } else {
910        let (regenerated, compressed, streams, header_size): (usize, usize, usize, usize) =
911            match format {
912                0 | 1 => {
913                    if input.len() < 3 {
914                        return Err(DecodeError::InvalidBlock);
915                    }
916                    let combined =
917                        input[0] as u32 | (input[1] as u32) << 8 | (input[2] as u32) << 16;
918                    (
919                        ((combined >> 4) & 0x3ff) as usize,
920                        ((combined >> 14) & 0x3ff) as usize,
921                        if format == 0 { 1 } else { 4 },
922                        3,
923                    )
924                }
925                2 => {
926                    if input.len() < 4 {
927                        return Err(DecodeError::InvalidBlock);
928                    }
929                    let combined = read_u32(input);
930                    (
931                        ((combined >> 4) & 0x3fff) as usize,
932                        ((combined >> 18) & 0x3fff) as usize,
933                        4,
934                        4,
935                    )
936                }
937                _ => {
938                    if input.len() < 5 {
939                        return Err(DecodeError::InvalidBlock);
940                    }
941                    let combined = read_variable_u64(&input[..5]);
942                    (
943                        ((combined >> 4) & 0x3ffff) as usize,
944                        ((combined >> 22) & 0x3ffff) as usize,
945                        4,
946                        5,
947                    )
948                }
949            };
950        ensure_literal_space(regenerated, output.len(), block_limit)?;
951        let end = header_size
952            .checked_add(compressed)
953            .ok_or(DecodeError::ArithmeticOverflow)?;
954        let mut encoded = input
955            .get(header_size..end)
956            .ok_or(DecodeError::InvalidBlock)?;
957        if kind == 2 {
958            let table_size = table.read_description(encoded)?;
959            encoded = &encoded[table_size..];
960        } else if !table.is_valid() {
961            return Err(DecodeError::InvalidEntropyTable);
962        }
963        if streams == 1 {
964            table.decode(encoded, &mut output[..regenerated])?;
965        } else {
966            table.decode_four(encoded, &mut output[..regenerated])?;
967        }
968        Ok((regenerated, end))
969    }
970}
971
972fn ensure_literal_space(
973    required: usize,
974    provided: usize,
975    block_limit: usize,
976) -> Result<(), DecodeError> {
977    if required > block_limit {
978        return Err(DecodeError::InvalidBlock);
979    }
980    if required > provided {
981        return Err(DecodeError::LiteralScratchTooSmall { required, provided });
982    }
983    Ok(())
984}
985
986fn parse_sequence_count(input: &[u8]) -> Result<(usize, usize), DecodeError> {
987    let first = *input.first().ok_or(DecodeError::InvalidBlock)? as usize;
988    match first {
989        0 => Ok((0, 1)),
990        1..=127 => Ok((first, 1)),
991        128..=254 => Ok((
992            ((first - 128) << 8) + *input.get(1).ok_or(DecodeError::InvalidBlock)? as usize,
993            2,
994        )),
995        _ => Ok((
996            0x7f00
997                + u16::from_le_bytes([
998                    *input.get(1).ok_or(DecodeError::InvalidBlock)?,
999                    *input.get(2).ok_or(DecodeError::InvalidBlock)?,
1000                ]) as usize,
1001            3,
1002        )),
1003    }
1004}
1005
1006fn build_sequence_table(
1007    table: &mut FseTable,
1008    mode: u8,
1009    input: &[u8],
1010    predefined: &[i16],
1011    predefined_log: u8,
1012    max_symbol: usize,
1013    max_log: u8,
1014) -> Result<usize, DecodeError> {
1015    match mode {
1016        0 => {
1017            table.build(predefined, predefined_log)?;
1018            Ok(0)
1019        }
1020        1 => {
1021            table.build_rle(*input.first().ok_or(DecodeError::InvalidEntropyTable)?);
1022            Ok(1)
1023        }
1024        2 => table.read_description(input, max_symbol, max_log),
1025        3 if table.is_valid() => Ok(0),
1026        _ => Err(DecodeError::InvalidEntropyTable),
1027    }
1028}
1029
1030fn resolve_offset(
1031    encoded: u32,
1032    literal_length: u32,
1033    repeated: &mut [u32; 3],
1034) -> Result<u32, DecodeError> {
1035    let value = if encoded > 3 {
1036        let value = encoded - 3;
1037        repeated[2] = repeated[1];
1038        repeated[1] = repeated[0];
1039        repeated[0] = value;
1040        value
1041    } else if literal_length != 0 {
1042        match encoded {
1043            1 => repeated[0],
1044            2 => {
1045                repeated.swap(0, 1);
1046                repeated[0]
1047            }
1048            3 => {
1049                let value = repeated[2];
1050                repeated[2] = repeated[1];
1051                repeated[1] = repeated[0];
1052                repeated[0] = value;
1053                value
1054            }
1055            _ => return Err(DecodeError::InvalidOffset),
1056        }
1057    } else {
1058        match encoded {
1059            1 => {
1060                repeated.swap(0, 1);
1061                repeated[0]
1062            }
1063            2 => {
1064                let value = repeated[2];
1065                repeated[2] = repeated[1];
1066                repeated[1] = repeated[0];
1067                repeated[0] = value;
1068                value
1069            }
1070            3 => {
1071                let value = repeated[0]
1072                    .checked_sub(1)
1073                    .filter(|value| *value != 0)
1074                    .ok_or(DecodeError::InvalidOffset)?;
1075                repeated[2] = repeated[1];
1076                repeated[1] = repeated[0];
1077                repeated[0] = value;
1078                value
1079            }
1080            _ => return Err(DecodeError::InvalidOffset),
1081        }
1082    };
1083    Ok(value)
1084}
1085
1086fn read_u32(input: &[u8]) -> u32 {
1087    u32::from_le_bytes([input[0], input[1], input[2], input[3]])
1088}
1089
1090fn read_variable(input: &[u8]) -> u32 {
1091    read_variable_u64(input) as u32
1092}
1093
1094fn read_variable_u64(input: &[u8]) -> u64 {
1095    let mut value = 0u64;
1096    for (index, byte) in input.iter().enumerate() {
1097        value |= (*byte as u64) << (index * 8);
1098    }
1099    value
1100}
1101
1102const LL_BASE: [u32; 36] = [
1103    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 28, 32, 40, 48, 64,
1104    128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536,
1105];
1106const LL_BITS: [u8; 36] = [
1107    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11,
1108    12, 13, 14, 15, 16,
1109];
1110const ML_BASE: [u32; 53] = [
1111    3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
1112    28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 131, 259, 515, 1027,
1113    2051, 4099, 8195, 16387, 32771, 65539,
1114];
1115const ML_BITS: [u8; 53] = [
1116    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1117    1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
1118];
1119const LL_DEFAULT: [i16; 36] = [
1120    4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
1121    -1, -1, -1, -1,
1122];
1123const ML_DEFAULT: [i16; 53] = [
1124    1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1125    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
1126];
1127const OF_DEFAULT: [i16; 29] = [
1128    1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1129];
1130
1131#[cfg(test)]
1132mod tests {
1133    use super::*;
1134    use std::vec::Vec;
1135
1136    #[test]
1137    fn parses_sampled_datadog_header() {
1138        let bytes = [0x28, 0xb5, 0x2f, 0xfd, 0x04, 0x78];
1139        assert_eq!(
1140            inspect_frame(&bytes),
1141            Ok(HeaderStatus::Complete {
1142                header: StreamHeader::Zstandard(FrameHeader {
1143                    window_size: 32 * 1024 * 1024,
1144                    content_size: None,
1145                    dictionary_id: 0,
1146                    has_checksum: true,
1147                }),
1148                size: 6,
1149            })
1150        );
1151    }
1152
1153    #[test]
1154    fn decodes_raw_frame_incrementally() {
1155        let frame = [
1156            0x28, 0xb5, 0x2f, 0xfd, 0x20, 0x05, // one-segment, size 5
1157            0x29, 0, 0, // last raw block, size 5
1158            b'h', b'e', b'l', b'l', b'o',
1159        ];
1160        let mut history = [0u8; 5];
1161        let mut block = [0u8; 5];
1162        let mut literals = [0u8; 5];
1163        let mut decoder = Decoder::new(DecoderBuffers {
1164            history: &mut history,
1165            block: &mut block,
1166            literals: &mut literals,
1167        });
1168        let mut input = &frame[..];
1169        let mut output = [0u8; 5];
1170        let mut output_len = 0;
1171        loop {
1172            let step = decoder.decode(input).unwrap();
1173            let consumed = step.consumed();
1174            input = &input[consumed..];
1175            match step {
1176                DecodeStep::Output { bytes, .. } => {
1177                    output[output_len..output_len + bytes.len()].copy_from_slice(bytes);
1178                    output_len += bytes.len();
1179                }
1180                DecodeStep::NeedInput { .. } if input.is_empty() => break,
1181                _ => {}
1182            }
1183        }
1184        assert_eq!(&output, b"hello");
1185        decoder.finish().unwrap();
1186    }
1187
1188    #[test]
1189    fn streams_fragmented_output_through_callback() {
1190        let frame = [
1191            0x28, 0xb5, 0x2f, 0xfd, 0x20, 0x05, 0x29, 0, 0, b'h', b'e', b'l', b'l', b'o',
1192        ];
1193        let mut history = [0u8; 5];
1194        let mut block = [0u8; 5];
1195        let mut literals = [0u8; 5];
1196        let mut decoder = Decoder::new(DecoderBuffers {
1197            history: &mut history,
1198            block: &mut block,
1199            literals: &mut literals,
1200        });
1201        let mut output = Vec::new();
1202        for fragment in frame.chunks(2) {
1203            decoder
1204                .push(fragment, |bytes| {
1205                    output.extend_from_slice(bytes);
1206                    Ok::<_, ()>(())
1207                })
1208                .unwrap();
1209        }
1210        decoder
1211            .finish_with(|bytes| {
1212                output.extend_from_slice(bytes);
1213                Ok::<_, ()>(())
1214            })
1215            .unwrap();
1216        assert_eq!(output, b"hello");
1217    }
1218
1219    #[test]
1220    fn decodes_rle_and_empty_frames() {
1221        let rle = [
1222            0x28, 0xb5, 0x2f, 0xfd, 0x20, 10, // one-segment, content size 10
1223            0x53, 0, 0, // last RLE block, regenerated size 10
1224            b'x',
1225        ];
1226        let mut history = [0u8; 10];
1227        let mut block = [0u8; 1];
1228        let mut literals = [];
1229        let mut decoder = Decoder::new(DecoderBuffers {
1230            history: &mut history,
1231            block: &mut block,
1232            literals: &mut literals,
1233        });
1234        let mut input = rle.as_slice();
1235        let mut output = [0u8; 10];
1236        let mut position = 0;
1237        loop {
1238            let step = decoder.decode(input).unwrap();
1239            let consumed = step.consumed();
1240            input = &input[consumed..];
1241            if let DecodeStep::Output { bytes, .. } = step {
1242                output[position..position + bytes.len()].copy_from_slice(bytes);
1243                position += bytes.len();
1244            } else if matches!(step, DecodeStep::NeedInput { .. }) {
1245                break;
1246            }
1247        }
1248        assert_eq!(output, [b'x'; 10]);
1249        decoder.finish().unwrap();
1250
1251        let empty = [
1252            0x28, 0xb5, 0x2f, 0xfd, 0x20, 0, // one-segment, empty content
1253            1, 0, 0, // last raw block, size 0
1254        ];
1255        let mut history = [];
1256        let mut block = [];
1257        let mut literals = [];
1258        let mut decoder = Decoder::new(DecoderBuffers {
1259            history: &mut history,
1260            block: &mut block,
1261            literals: &mut literals,
1262        });
1263        let mut input = empty.as_slice();
1264        loop {
1265            let step = decoder.decode(input).unwrap();
1266            let consumed = step.consumed();
1267            input = &input[consumed..];
1268            if matches!(step, DecodeStep::NeedInput { .. }) {
1269                break;
1270            }
1271        }
1272        decoder.finish().unwrap();
1273    }
1274}