Skip to main content

structured_zstd/decoding/legacy/
mod.rs

1//! Decoders for the frame formats zstd wrote before 1.0: v0.5, v0.6 and v0.7.
2//!
3//! libzstd 1.5.7 reads these by default (upstream's legacy level 5 in every
4//! build system), so a consumer that holds an archive from 2016 gets its
5//! content back from `ZSTD_decompress`; this module gives the same answer.
6//! The formats differ from RFC 8878 and from each other in their headers,
7//! literal and sequence coding, and dictionaries: each has its own module,
8//! and what they share lives here and in [`entropy`].
9//!
10//! Upstream's decoders are `lib/legacy/zstd_v0{5,6,7}.c`.
11
12mod entropy;
13mod v05;
14mod v06;
15mod v07;
16
17#[cfg(feature = "hash")]
18use crate::decoding::ContentChecksum;
19use crate::decoding::Dictionary;
20use crate::decoding::FrameSizeError;
21use crate::decoding::errors::LegacyFrameError as Error;
22use alloc::vec::Vec;
23
24/// One of the pre-1.0 frame formats this crate decodes.
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26#[non_exhaustive]
27pub enum LegacyVersion {
28    /// The v0.5 format, magic number `0xFD2FB525`.
29    V05,
30    /// The v0.6 format, magic number `0xFD2FB526`.
31    V06,
32    /// The v0.7 format, magic number `0xFD2FB527`.
33    V07,
34}
35
36impl LegacyVersion {
37    /// The format whose magic number starts `src`, if it is one of these.
38    pub fn of(src: &[u8]) -> Option<LegacyVersion> {
39        let magic = u32::from_le_bytes(src.get(..4)?.try_into().ok()?);
40        match magic {
41            0xFD2F_B525 => Some(LegacyVersion::V05),
42            0xFD2F_B526 => Some(LegacyVersion::V06),
43            0xFD2F_B527 => Some(LegacyVersion::V07),
44            _ => None,
45        }
46    }
47
48    /// The minor version number: 5, 6 or 7.
49    pub fn minor(self) -> u8 {
50        match self {
51            LegacyVersion::V05 => 5,
52            LegacyVersion::V06 => 6,
53            LegacyVersion::V07 => 7,
54        }
55    }
56
57    /// The length of a frame header of this format starting `src`, magic
58    /// number included, as its size fields give it; `None` until `src` holds
59    /// the descriptor byte after the magic number. For a caller reading a
60    /// header in pieces, as [`frame_header_input_needed`] serves an RFC 8878
61    /// one.
62    ///
63    /// [`frame_header_input_needed`]: crate::decoding::frame_header_input_needed
64    ///
65    /// ```
66    /// use structured_zstd::decoding::LegacyVersion;
67    /// // v0.7, a one-byte dictionary ID and a window byte.
68    /// let header = [0x27, 0xB5, 0x2F, 0xFD, 0x01];
69    /// let version = LegacyVersion::of(&header).unwrap();
70    /// assert_eq!(version.header_size(&header[..4]), None);
71    /// assert_eq!(version.header_size(&header), Some(7));
72    /// ```
73    pub fn header_size(self, src: &[u8]) -> Option<usize> {
74        header_len(self, src).ok()
75    }
76}
77
78/// Most bytes one compressed block decodes to, the formats' `BLOCKSIZE`.
79const BLOCK_SIZE_MAX: usize = 128 * 1024;
80
81/// Most bytes a stored block (raw, or RLE in v0.7) holds: its 19-bit size
82/// field, which upstream's one-shot decoders check against nothing but the
83/// output's room (`ZSTDv0{5,6,7}_decompressFrame`).
84const STORED_BLOCK_MAX: usize = (1 << 19) - 1;
85
86/// Most bytes a block may decode to, by its type.
87#[derive(Debug, Clone, Copy)]
88struct BlockLimits {
89    compressed: usize,
90    stored: usize,
91}
92
93impl BlockLimits {
94    /// Each type's own limit, or the caller's `block_max` for every type
95    /// where it lowered the setting below the formats' 128 KiB: a limit set
96    /// for memory binds whatever the block's type.
97    fn of(block_max: usize) -> BlockLimits {
98        if block_max >= BLOCK_SIZE_MAX {
99            BlockLimits {
100                compressed: BLOCK_SIZE_MAX,
101                stored: STORED_BLOCK_MAX,
102            }
103        } else {
104            BlockLimits {
105                compressed: block_max,
106                stored: block_max,
107            }
108        }
109    }
110
111    /// The limit `block`'s output is held to.
112    fn of_block(self, block: Block) -> usize {
113        match block {
114            Block::Compressed(_) => self.compressed,
115            Block::Raw(_) | Block::Rle(_) | Block::End => self.stored,
116        }
117    }
118}
119
120fn corrupt(reason: &'static str) -> Error {
121    Error::Corrupted { reason }
122}
123
124/// Whether `raw` is a dictionary in the v0.5 or v0.6 layout: that format's
125/// magic number, its tables, then content. Its decoder parses it whole, so it
126/// is kept whole as content; an RFC 8878 frame reads it as raw content, as
127/// upstream reads any dictionary without the RFC 8878 magic number
128/// (`zstd_ddict.c:97`).
129pub(crate) fn is_older_dictionary(raw: &[u8]) -> bool {
130    raw.first_chunk::<4>().is_some_and(|magic| {
131        matches!(
132            u32::from_le_bytes(*magic),
133            v05::DICT_MAGIC | v06::DICT_MAGIC
134        )
135    })
136}
137
138/// A dictionary as the legacy decoders take it.
139#[derive(Clone, Copy)]
140pub(crate) enum LegacyDict<'a> {
141    None,
142    /// A dictionary the RFC 8878 parser has read. Its layout is the v0.7 one,
143    /// so a v0.7 frame takes its tables, repeat offsets and ID. v0.5 and v0.6
144    /// read any dictionary of the v0.7 layout whole as plain content,
145    /// `header` (the serialized bytes in front of the content, empty when
146    /// they are not known) and then the content.
147    Parsed {
148        dict: &'a Dictionary,
149        header: &'a [u8],
150    },
151}
152
153impl<'a> LegacyDict<'a> {
154    /// The dictionary `handle` holds, with the serialized header it keeps.
155    pub(crate) fn of(handle: &'a crate::decoding::DictionaryHandle) -> LegacyDict<'a> {
156        LegacyDict::Parsed {
157            dict: handle.as_dict(),
158            header: handle.serialized_header(),
159        }
160    }
161
162    /// The bytes a v0.5 or v0.6 frame reads as its dictionary: the header,
163    /// then the content.
164    fn pieces(&self) -> (&'a [u8], &'a [u8]) {
165        match *self {
166            LegacyDict::None => (&[], &[]),
167            LegacyDict::Parsed { dict, header } => (header, &dict.dict_content),
168        }
169    }
170}
171
172/// The dictionary bytes a frame's matches may reach in front of its own
173/// output, in at most two pieces: `head` and then `tail`.
174#[derive(Clone, Copy)]
175pub(crate) struct History<'a> {
176    head: &'a [u8],
177    tail: &'a [u8],
178}
179
180/// Which bytes of its dictionary a frame's matches reach.
181#[derive(Clone)]
182enum HistoryShape {
183    /// This range of the dictionary's content.
184    Content(core::ops::Range<usize>),
185    /// The serialized header and then the whole content: a v0.5 or v0.6
186    /// frame given a dictionary of the v0.7 layout reads it whole.
187    Whole,
188}
189
190impl HistoryShape {
191    fn of<'a>(&self, dict: LegacyDict<'a>) -> History<'a> {
192        let (head, tail) = dict.pieces();
193        match self {
194            HistoryShape::Content(range) => History {
195                head: &[],
196                tail: &tail[range.clone()],
197            },
198            HistoryShape::Whole => History { head, tail },
199        }
200    }
201}
202
203impl History<'_> {
204    fn len(&self) -> usize {
205        self.head.len() + self.tail.len()
206    }
207
208    /// Append the `len` bytes starting `from` into the history, which holds
209    /// them all.
210    fn copy_out<O: Output>(&self, from: usize, len: usize, out: &mut O) {
211        debug_assert!(from + len <= self.len());
212        if from >= self.head.len() {
213            let start = from - self.head.len();
214            out.extend(&self.tail[start..start + len]);
215            return;
216        }
217        let in_head = (self.head.len() - from).min(len);
218        out.extend(&self.head[from..from + in_head]);
219        if len > in_head {
220            out.extend(&self.tail[..len - in_head]);
221        }
222    }
223}
224
225/// The frame header fields the decoders and the size queries need.
226#[derive(Debug, Clone, Copy)]
227pub(crate) struct FrameHeader {
228    pub(crate) version: LegacyVersion,
229    /// Header length including the magic number.
230    pub(crate) size: usize,
231    /// The window the frame needs, in bytes.
232    pub(crate) window: u64,
233    /// The declared content size; the formats write 0 for unknown.
234    pub(crate) content_size: Option<u64>,
235    /// The dictionary the frame names, 0 for none.
236    pub(crate) dict_id: u32,
237    /// Whether a v0.7 frame carries a content checksum.
238    pub(crate) checksum: bool,
239}
240
241/// Read the frame header at the start of `src`.
242pub(crate) fn read_header(src: &[u8]) -> Result<FrameHeader, Error> {
243    match LegacyVersion::of(src).ok_or(corrupt("not a v0.5-v0.7 frame"))? {
244        LegacyVersion::V05 => v05::read_header(src),
245        LegacyVersion::V06 => v06::read_header(src),
246        LegacyVersion::V07 => v07::read_header(src),
247    }
248}
249
250/// [`read_header`] for a frame decoded whole, with libzstd's code for that
251/// path: its v0.6 and v0.7 one-shot decoders report any header field they
252/// refuse, reserved bit or window alike, as corruption (`zstd_v06.c:3523`,
253/// `zstd_v07.c:3758`), where their buffered decoders report the field's own
254/// unsupported-parameter error. v0.5 passes its header's error through on
255/// both paths (`zstd_v05.c:3386-3391`).
256pub(crate) fn read_header_whole(src: &[u8]) -> Result<FrameHeader, Error> {
257    match read_header(src) {
258        Err(Error::UnsupportedParameter)
259            if LegacyVersion::of(src).is_some_and(|version| version != LegacyVersion::V05) =>
260        {
261            Err(corrupt("frame header"))
262        }
263        result => result,
264    }
265}
266
267/// The content size the frame at the start of `src` declares, `None` when it
268/// declares none or its header does not read: libzstd reports both as an
269/// unknown size (`ZSTD_getDecompressedSize_legacy`).
270pub(crate) fn declared_content_size(src: &[u8]) -> Option<u64> {
271    read_header(src).ok()?.content_size
272}
273
274/// A block as its three-byte header describes it.
275#[derive(Debug, Clone, Copy, PartialEq, Eq)]
276enum Block {
277    Compressed(usize),
278    Raw(usize),
279    /// A byte repeated this many times.
280    Rle(usize),
281    End,
282}
283
284impl Block {
285    fn read(src: &[u8]) -> Result<Block, Error> {
286        let header = src.get(..3).ok_or(Error::Truncated)?;
287        let size =
288            usize::from(header[2]) | usize::from(header[1]) << 8 | usize::from(header[0] & 7) << 16;
289        Ok(match header[0] >> 6 {
290            0 => Block::Compressed(size),
291            1 => Block::Raw(size),
292            2 => Block::Rle(size),
293            _ => Block::End,
294        })
295    }
296
297    /// Bytes the block's body takes after its header.
298    fn body_len(self) -> usize {
299        match self {
300            Block::Compressed(size) | Block::Raw(size) => size,
301            Block::Rle(_) => 1,
302            Block::End => 0,
303        }
304    }
305
306    /// Refuse a block its header alone rules out: an RLE block in v0.5 or
307    /// v0.6, which reserve the type (`ZSTDv0{5,6}_decompressFrame` fail on
308    /// `bt_rle`), and a block past its type's limit.
309    fn check(self, version: LegacyVersion, limits: BlockLimits) -> Result<(), Error> {
310        let size = match self {
311            Block::Rle(_) if version != LegacyVersion::V07 => {
312                return Err(corrupt("reserved block type"));
313            }
314            Block::Compressed(size) | Block::Raw(size) | Block::Rle(size) => size,
315            Block::End => 0,
316        };
317        if size > limits.of_block(self) {
318            return Err(corrupt("block larger than the block maximum"));
319        }
320        Ok(())
321    }
322
323    /// Most bytes the block decodes to: its size for a stored block, the
324    /// formats' largest for a compressed one.
325    fn decoded_max(self) -> usize {
326        match self {
327            Block::Compressed(_) => BLOCK_SIZE_MAX,
328            Block::Raw(size) | Block::Rle(size) => size,
329            Block::End => 0,
330        }
331    }
332}
333
334/// Whether `block` ends the frame. v0.5 and v0.6 end it at any block whose
335/// body is empty, as their decoders and size walks do
336/// (`if (cBlockSize == 0) break;`); v0.7 only at the end block.
337fn ends_frame(version: LegacyVersion, block: Block) -> bool {
338    match version {
339        LegacyVersion::V07 => block == Block::End,
340        LegacyVersion::V05 | LegacyVersion::V06 => block.body_len() == 0,
341    }
342}
343
344/// The length of the frame header at the start of `src` from its size fields
345/// alone, its other fields unchecked, as upstream's size walks read it
346/// (`ZSTDv0{6,7}_frameHeaderSize`; v0.5 headers are always 5 bytes).
347pub(crate) fn header_len(version: LegacyVersion, src: &[u8]) -> Result<usize, Error> {
348    let descriptor = *src.get(4).ok_or(Error::Truncated)?;
349    let fields = HeaderFields::of(version, descriptor);
350    Ok(5 + fields.window + fields.dict_id + fields.content_size)
351}
352
353impl FrameHeader {
354    /// The window byte of the header starting `src`, which a v0.7 header
355    /// that is not single-segment carries right after its descriptor, laid
356    /// out as RFC 8878's `Window_Descriptor`. v0.5 and v0.6 headers keep
357    /// their window in the descriptor and carry none.
358    #[cfg(feature = "lsm")]
359    pub(crate) fn window_descriptor(&self, src: &[u8]) -> Option<u8> {
360        let fields = HeaderFields::of(self.version, src[4]);
361        (fields.window == 1).then(|| src[5])
362    }
363
364    /// The dictionary ID the header names, `None` for none.
365    #[cfg(feature = "lsm")]
366    pub(crate) fn dictionary_id(&self) -> Option<u32> {
367        (self.dict_id != 0).then_some(self.dict_id)
368    }
369}
370
371/// The lengths of the fields that follow a frame header's descriptor byte,
372/// in the order they follow it.
373#[derive(Debug, Clone, Copy)]
374pub(crate) struct HeaderFields {
375    pub(crate) window: usize,
376    pub(crate) dict_id: usize,
377    pub(crate) content_size: usize,
378}
379
380impl HeaderFields {
381    pub(crate) fn of(version: LegacyVersion, descriptor: u8) -> HeaderFields {
382        match version {
383            LegacyVersion::V05 => HeaderFields {
384                window: 0,
385                dict_id: 0,
386                content_size: 0,
387            },
388            LegacyVersion::V06 => HeaderFields {
389                window: 0,
390                dict_id: 0,
391                content_size: [0, 1, 2, 8][usize::from(descriptor >> 6)],
392            },
393            LegacyVersion::V07 => {
394                let single_segment = descriptor & 0x20 != 0;
395                let fcs = [0, 2, 4, 8][usize::from(descriptor >> 6)];
396                HeaderFields {
397                    window: usize::from(!single_segment),
398                    dict_id: [0, 1, 2, 4][usize::from(descriptor & 3)],
399                    // A single-segment frame always carries its size, one
400                    // byte at least.
401                    content_size: fcs + usize::from(single_segment && fcs == 0),
402                }
403            }
404        }
405    }
406}
407
408/// Where the `version` frame starting `src` ends, and the most it can decode
409/// to: the formats' largest per compressed block, as
410/// `ZSTD_findFrameSizeInfoLegacy` counts every block, and a stored block's
411/// own size, which can be more.
412///
413/// # Errors
414/// [`FrameSizeError::Truncated`] when `src` ends inside the frame, and a
415/// block the decoder refuses from its header, as the RFC 8878 walk refuses
416/// one: [`FrameSizeError::ReservedBlock`] for an RLE block in v0.5 or v0.6,
417/// [`FrameSizeError::OversizedBlock`] for a compressed block past 128 KiB.
418/// (Upstream's walk takes both; its decoders then refuse them.)
419pub(crate) fn frame_size(
420    version: LegacyVersion,
421    src: &[u8],
422) -> Result<(usize, u64), FrameSizeError> {
423    let mut at = header_len(version, src).map_err(|_| FrameSizeError::Truncated)?;
424    let mut bound = 0u64;
425    loop {
426        let rest = src.get(at..).ok_or(FrameSizeError::Truncated)?;
427        let block = Block::read(rest).map_err(|_| FrameSizeError::Truncated)?;
428        if block
429            .check(version, BlockLimits::of(BLOCK_SIZE_MAX))
430            .is_err()
431        {
432            // `check` refuses a reserved type or a block past its limit.
433            return Err(match block {
434                Block::Rle(_) => FrameSizeError::ReservedBlock,
435                _ => FrameSizeError::OversizedBlock,
436            });
437        }
438        at += 3;
439        let body = block.body_len();
440        if body > src.len() - at {
441            return Err(FrameSizeError::Truncated);
442        }
443        if ends_frame(version, block) {
444            break;
445        }
446        at += body;
447        bound += block.decoded_max() as u64;
448    }
449    Ok((at, bound))
450}
451
452/// Where decoded bytes go: an output that knows how much of the frame it has
453/// produced and how much of that it still holds for matches to reach.
454pub(crate) trait Output {
455    /// Bytes of the current frame produced so far.
456    fn produced(&self) -> usize;
457    /// Bytes of the current frame still held, the most a match can reach
458    /// back within the frame.
459    fn held(&self) -> usize;
460    /// Refuse `len` more bytes the output cannot take.
461    fn reserve(&mut self, len: usize) -> Result<(), Error>;
462    fn extend(&mut self, bytes: &[u8]);
463    fn repeat(&mut self, byte: u8, len: usize);
464    /// Append `len` bytes copied from `offset` back, `1 <= offset <= held`;
465    /// an overlapping copy repeats the bytes it has just written.
466    fn copy_back(&mut self, offset: usize, len: usize);
467    /// The bytes produced since `from` (a value of `produced()`), for the
468    /// content checksum.
469    #[cfg(feature = "hash")]
470    fn since(&self, from: usize) -> &[u8];
471    /// Append a match of `len` bytes from `offset` back. An output holding
472    /// the whole frame takes it from the frame, the dictionary in front of
473    /// it, or both ([`copy_match`]); the room for `len` bytes is reserved.
474    fn copy_match(&mut self, offset: usize, len: usize, dict: &History<'_>) -> Result<(), Error>
475    where
476        Self: Sized,
477    {
478        copy_match(self, offset, len, dict)
479    }
480}
481
482/// Output into a growing vector, the current frame starting at `start`.
483pub(crate) struct VecOutput<'a> {
484    pub(crate) buf: &'a mut Vec<u8>,
485    pub(crate) start: usize,
486}
487
488impl Output for VecOutput<'_> {
489    fn produced(&self) -> usize {
490        self.held()
491    }
492
493    fn held(&self) -> usize {
494        self.buf.len() - self.start
495    }
496
497    fn reserve(&mut self, len: usize) -> Result<(), Error> {
498        // The block budget in front of this output bounds `len`.
499        self.buf.reserve(len);
500        Ok(())
501    }
502
503    fn extend(&mut self, bytes: &[u8]) {
504        self.buf.extend_from_slice(bytes);
505    }
506
507    fn repeat(&mut self, byte: u8, len: usize) {
508        self.buf.resize(self.buf.len() + len, byte);
509    }
510
511    fn copy_back(&mut self, offset: usize, len: usize) {
512        // A match longer than its offset repeats the bytes it has just
513        // written: each piece copies everything from `from` on, so the
514        // pieces double until the match is whole.
515        let from = self.buf.len() - offset;
516        let mut left = len;
517        while left > 0 {
518            let piece = left.min(self.buf.len() - from);
519            self.buf.extend_from_within(from..from + piece);
520            left -= piece;
521        }
522    }
523
524    #[cfg(feature = "hash")]
525    fn since(&self, from: usize) -> &[u8] {
526        &self.buf[self.start + from..]
527    }
528}
529
530/// Copy `len` bytes from `from` to `to` within `buf`, `from < to`. The source
531/// may run into the bytes being written, a match longer than its offset: the
532/// first `to - from` bytes repeat, copied in pieces that double as what is
533/// written becomes source, so no piece overlaps its own destination.
534fn copy_repeating(buf: &mut [u8], from: usize, to: usize, len: usize) {
535    debug_assert!(from < to);
536    let mut done = 0;
537    while done < len {
538        let piece = (to + done - from).min(len - done);
539        buf.copy_within(from..from + piece, to + done);
540        done += piece;
541    }
542}
543
544/// Output into a caller's slice, the current frame starting at its start.
545pub(crate) struct SliceOutput<'a> {
546    pub(crate) buf: &'a mut [u8],
547    pub(crate) pos: usize,
548}
549
550impl Output for SliceOutput<'_> {
551    fn produced(&self) -> usize {
552        self.pos
553    }
554
555    fn held(&self) -> usize {
556        self.pos
557    }
558
559    fn reserve(&mut self, len: usize) -> Result<(), Error> {
560        if len > self.buf.len() - self.pos {
561            return Err(Error::OutputTooSmall);
562        }
563        Ok(())
564    }
565
566    fn extend(&mut self, bytes: &[u8]) {
567        self.buf[self.pos..self.pos + bytes.len()].copy_from_slice(bytes);
568        self.pos += bytes.len();
569    }
570
571    fn repeat(&mut self, byte: u8, len: usize) {
572        self.buf[self.pos..self.pos + len].fill(byte);
573        self.pos += len;
574    }
575
576    fn copy_back(&mut self, offset: usize, len: usize) {
577        copy_repeating(self.buf, self.pos - offset, self.pos, len);
578        self.pos += len;
579    }
580
581    #[cfg(feature = "hash")]
582    fn since(&self, from: usize) -> &[u8] {
583        &self.buf[from..self.pos]
584    }
585}
586
587/// Copy a match of `len` bytes from `offset` back: within the frame, from
588/// the dictionary's content in front of it, or across both
589/// (`ZSTDv07_execSequence`). The output holds the whole frame so far and has
590/// room for `len` more bytes.
591///
592/// An offset is held to the output and the dictionary, not to the frame's
593/// window: upstream's decoders check it the same way
594/// (`zstd_v07.c:3559-3561`, and likewise for v0.5 and v0.6), so
595/// `ZSTD_decompress` reads a frame whose match reaches past its window, and
596/// refusing it would refuse what libzstd decodes.
597fn copy_match<O: Output>(
598    out: &mut O,
599    offset: usize,
600    len: usize,
601    dict: &History<'_>,
602) -> Result<(), Error> {
603    // An output that drops older bytes reads matches through its own
604    // `Output::copy_match`.
605    debug_assert_eq!(out.held(), out.produced());
606    // Every format's offsets are at least 1 by construction: a repeat offset
607    // starts at 1 (or a dictionary's, which must not be 0), and a coded one
608    // is a base of at least 1 plus extra bits.
609    debug_assert!(offset >= 1);
610    let held = out.held();
611    if offset <= held {
612        out.copy_back(offset, len);
613        return Ok(());
614    }
615    let back = offset - held;
616    if back > dict.len() {
617        return Err(corrupt("match reaches before the dictionary"));
618    }
619    let first = len.min(back);
620    dict.copy_out(dict.len() - back, first, out);
621    let rest = len - first;
622    if rest > 0 {
623        // The match runs on from the frame's first byte.
624        let distance = out.held();
625        out.copy_back(distance, rest);
626    }
627    Ok(())
628}
629
630/// Append one sequence: `lit_len` literals from `literals[*lit_pos..]`, then a
631/// match of `match_len` bytes from `offset` back.
632fn execute<O: Output>(
633    out: &mut O,
634    literals: &[u8],
635    lit_pos: &mut usize,
636    lit_len: usize,
637    match_len: usize,
638    offset: usize,
639    dict: &History<'_>,
640) -> Result<(), Error> {
641    out.reserve(
642        lit_len
643            .checked_add(match_len)
644            .ok_or(Error::OutputTooSmall)?,
645    )?;
646    let lits = literals
647        .get(*lit_pos..)
648        .and_then(|rest| rest.get(..lit_len))
649        .ok_or(corrupt("sequence takes more literals than the block has"))?;
650    out.extend(lits);
651    *lit_pos += lit_len;
652    out.copy_match(offset, match_len, dict)
653}
654
655/// The literal section's header, common to the three formats.
656enum Literals {
657    /// Huffman-coded: `size` literals from `compressed` bytes after a
658    /// `header`-byte header, in one stream or four.
659    Huffman {
660        header: usize,
661        size: usize,
662        compressed: usize,
663        single_stream: bool,
664    },
665    /// Huffman-coded with the previous table: one stream.
666    Repeat {
667        size: usize,
668        compressed: usize,
669    },
670    Raw {
671        header: usize,
672        size: usize,
673    },
674    Rle {
675        header: usize,
676        size: usize,
677    },
678}
679
680impl Literals {
681    /// Read the literal header at the start of a compressed block
682    /// (`ZSTDv07_decodeLiteralsBlock`).
683    fn read(src: &[u8]) -> Result<Literals, Error> {
684        // A compressed block holds at least a literal header byte, one
685        // literal or run byte, and the sequence count.
686        if src.len() < 3 {
687            return Err(corrupt("compressed block too short"));
688        }
689        let b0 = usize::from(src[0]);
690        let b1 = usize::from(src[1]);
691        let b2 = usize::from(src[2]);
692        let size_format = (b0 >> 4) & 3;
693        Ok(match b0 >> 6 {
694            0 => {
695                if src.len() < 5 {
696                    return Err(corrupt("compressed block too short"));
697                }
698                let b3 = usize::from(src[3]);
699                let b4 = usize::from(src[4]);
700                let (header, size, compressed, single_stream) = match size_format {
701                    0 | 1 => (
702                        3,
703                        ((b0 & 15) << 6) + (b1 >> 2),
704                        ((b1 & 3) << 8) + b2,
705                        b0 & 16 != 0,
706                    ),
707                    2 => (
708                        4,
709                        ((b0 & 15) << 10) + (b1 << 2) + (b2 >> 6),
710                        ((b2 & 63) << 8) + b3,
711                        false,
712                    ),
713                    _ => (
714                        5,
715                        ((b0 & 15) << 14) + (b1 << 6) + (b2 >> 2),
716                        ((b2 & 3) << 16) + (b3 << 8) + b4,
717                        false,
718                    ),
719                };
720                if size > BLOCK_SIZE_MAX {
721                    return Err(corrupt("literal section too large"));
722                }
723                if compressed + header > src.len() {
724                    return Err(corrupt("literals run past the block"));
725                }
726                Literals::Huffman {
727                    header,
728                    size,
729                    compressed,
730                    single_stream,
731                }
732            }
733            1 => {
734                // Only the small single-stream form exists.
735                if size_format != 1 {
736                    return Err(corrupt("repeated-table literals in an unknown form"));
737                }
738                let size = ((b0 & 15) << 6) + (b1 >> 2);
739                let compressed = ((b1 & 3) << 8) + b2;
740                if compressed + 3 > src.len() {
741                    return Err(corrupt("literals run past the block"));
742                }
743                Literals::Repeat { size, compressed }
744            }
745            kind => {
746                let (header, size) = match size_format {
747                    0 | 1 => (1, b0 & 31),
748                    2 => (2, ((b0 & 15) << 8) + b1),
749                    _ => (3, ((b0 & 15) << 16) + (b1 << 8) + b2),
750                };
751                if kind == 2 {
752                    if size + header > src.len() {
753                        return Err(corrupt("literals run past the block"));
754                    }
755                    Literals::Raw { header, size }
756                } else {
757                    if header == 3 && src.len() < 4 {
758                        return Err(corrupt("compressed block too short"));
759                    }
760                    if size > BLOCK_SIZE_MAX {
761                        return Err(corrupt("literal section too large"));
762                    }
763                    Literals::Rle { header, size }
764                }
765            }
766        })
767    }
768}
769
770/// Where a block's literals are once decoded.
771enum LiteralSource {
772    /// In the block itself, at this range.
773    Block(core::ops::Range<usize>),
774    /// In the decoder's literal buffer.
775    Buffer,
776}
777
778/// The per-format state of a frame being decoded: its entropy tables and
779/// literal buffer, kept from frame to frame so their storage is reused.
780enum VersionDecoder {
781    V05(v05::Decoder),
782    V06(v06::Decoder),
783    V07(v07::Decoder),
784}
785
786impl VersionDecoder {
787    fn version(&self) -> LegacyVersion {
788        match self {
789            VersionDecoder::V05(_) => LegacyVersion::V05,
790            VersionDecoder::V06(_) => LegacyVersion::V06,
791            VersionDecoder::V07(_) => LegacyVersion::V07,
792        }
793    }
794
795    fn heap_bytes(&self) -> usize {
796        match self {
797            VersionDecoder::V05(decoder) => decoder.heap_bytes(),
798            VersionDecoder::V06(decoder) => decoder.heap_bytes(),
799            VersionDecoder::V07(decoder) => decoder.heap_bytes(),
800        }
801    }
802}
803
804/// What a frame decodes in, kept from frame to frame so its storage is
805/// reused: the per-format decoder, and the per-block digests when asked for.
806#[derive(Default)]
807struct Workspace {
808    decoder: Option<VersionDecoder>,
809    /// The current frame's per-block XXH64 digests, low 32 bits.
810    #[cfg(all(feature = "lsm", feature = "hash"))]
811    block_digests: Vec<u32>,
812}
813
814impl Workspace {
815    fn heap_bytes(&self) -> usize {
816        let bytes = self.decoder.as_ref().map_or(0, VersionDecoder::heap_bytes);
817        #[cfg(all(feature = "lsm", feature = "hash"))]
818        let bytes = bytes + self.block_digests.capacity() * core::mem::size_of::<u32>();
819        bytes
820    }
821}
822
823/// What the caller set on the decoder that a frame of these formats obeys.
824#[derive(Debug, Clone, Copy)]
825pub(crate) struct FrameOptions {
826    /// Without `hash` no checksum is computed, whatever the mode.
827    #[cfg(feature = "hash")]
828    pub(crate) checksum: ContentChecksum,
829    /// Most bytes a block may hold, compressed or decoded; at the formats'
830    /// 128 KiB, each block type's own limit ([`BlockLimits::of`]).
831    pub(crate) block_max: usize,
832    /// Whether each data block's output is digested, for the per-block
833    /// checksums.
834    #[cfg(all(feature = "lsm", feature = "hash"))]
835    pub(crate) block_digests: bool,
836}
837
838impl Default for FrameOptions {
839    fn default() -> FrameOptions {
840        FrameOptions {
841            #[cfg(feature = "hash")]
842            checksum: ContentChecksum::EmitOnly,
843            block_max: BLOCK_SIZE_MAX,
844            #[cfg(all(feature = "lsm", feature = "hash"))]
845            block_digests: false,
846        }
847    }
848}
849
850/// An output that refuses to grow past `end` produced bytes: a block decodes
851/// to at most its type's limit ([`BlockLimits`]), however many sequences it
852/// holds.
853struct Budget<'o, O: Output> {
854    out: &'o mut O,
855    end: usize,
856}
857
858impl<O: Output> Output for Budget<'_, O> {
859    fn produced(&self) -> usize {
860        self.out.produced()
861    }
862    fn held(&self) -> usize {
863        self.out.held()
864    }
865    fn reserve(&mut self, len: usize) -> Result<(), Error> {
866        if len > self.end - self.out.produced() {
867            return Err(corrupt("block decodes past the largest block size"));
868        }
869        self.out.reserve(len)
870    }
871    fn extend(&mut self, bytes: &[u8]) {
872        self.out.extend(bytes);
873    }
874    fn repeat(&mut self, byte: u8, len: usize) {
875        self.out.repeat(byte, len);
876    }
877    fn copy_back(&mut self, offset: usize, len: usize) {
878        self.out.copy_back(offset, len);
879    }
880    #[cfg(feature = "hash")]
881    fn since(&self, from: usize) -> &[u8] {
882        self.out.since(from)
883    }
884    fn copy_match(&mut self, offset: usize, len: usize, dict: &History<'_>) -> Result<(), Error> {
885        self.out.copy_match(offset, len, dict)
886    }
887}
888
889/// A frame being decoded block by block: the whole-buffer and the streaming
890/// decoders both drive one. The dictionary it was started with is passed to
891/// each block again, as a [`LegacyDict`], so the frame holds no borrow and a
892/// stream can keep it beside the dictionary's handle; the per-format decoder
893/// is passed too, so it outlives the frame.
894struct LegacyFrame {
895    version: LegacyVersion,
896    /// The dictionary the header names, 0 for none.
897    dict_id: u32,
898    /// What of the dictionary matches reach.
899    history: HistoryShape,
900    /// Most bytes a block may hold, by type.
901    limits: BlockLimits,
902    #[cfg(feature = "hash")]
903    checksum_mode: ContentChecksum,
904    /// The declared content size, 0 when the frame declares none.
905    content_size: u64,
906    /// Data blocks decoded so far.
907    blocks: usize,
908    /// Whether the end block holds a content checksum.
909    has_checksum: bool,
910    /// The checksum the end block stores, once read.
911    stored_checksum: Option<u32>,
912    /// The checksum the content gives, once the end block is read and the
913    /// mode computes one.
914    #[cfg(feature = "hash")]
915    calculated_checksum: Option<u32>,
916    #[cfg(feature = "hash")]
917    hash: Option<twox_hash::XxHash64>,
918    #[cfg(all(feature = "lsm", feature = "hash"))]
919    block_digests: bool,
920}
921
922impl LegacyFrame {
923    /// Start decoding the frame `header` describes, readying `workspace` for
924    /// it: the decoder the previous frame left, when of the same format.
925    fn new(
926        header: FrameHeader,
927        dict: LegacyDict<'_>,
928        options: FrameOptions,
929        workspace: &mut Workspace,
930    ) -> Result<LegacyFrame, Error> {
931        #[cfg(all(feature = "lsm", feature = "hash"))]
932        workspace.block_digests.clear();
933        let decoder = &mut workspace.decoder;
934        if decoder.as_ref().map(VersionDecoder::version) != Some(header.version) {
935            *decoder = Some(match header.version {
936                LegacyVersion::V05 => VersionDecoder::V05(v05::Decoder::empty()),
937                LegacyVersion::V06 => VersionDecoder::V06(v06::Decoder::empty()),
938                LegacyVersion::V07 => VersionDecoder::V07(v07::Decoder::empty()),
939            });
940        }
941        let history = prime(header.dict_id, dict, workspace)?;
942        // Without `hash` no digest can be computed, so `Verify` checks
943        // nothing, as for an RFC 8878 frame.
944        #[cfg(feature = "hash")]
945        let hash = (header.checksum && options.checksum != ContentChecksum::None)
946            .then(|| twox_hash::XxHash64::with_seed(0));
947        Ok(LegacyFrame {
948            version: header.version,
949            dict_id: header.dict_id,
950            history,
951            limits: BlockLimits::of(options.block_max),
952            #[cfg(feature = "hash")]
953            checksum_mode: options.checksum,
954            content_size: header.content_size.unwrap_or(0),
955            blocks: 0,
956            has_checksum: header.checksum,
957            stored_checksum: None,
958            #[cfg(feature = "hash")]
959            calculated_checksum: None,
960            #[cfg(feature = "hash")]
961            hash,
962            #[cfg(all(feature = "lsm", feature = "hash"))]
963            block_digests: options.block_digests,
964        })
965    }
966
967    /// Prime the frame's decoder with `dict` for the blocks still to come, as
968    /// an RFC 8878 frame's decoder takes a forced dictionary: its tables and
969    /// repeat offsets become the dictionary's, and matches reach into its
970    /// content. What the frame has decoded so far stands.
971    fn set_dict(&mut self, dict: LegacyDict<'_>, workspace: &mut Workspace) -> Result<(), Error> {
972        self.history = prime(self.dict_id, dict, workspace)?;
973        Ok(())
974    }
975
976    /// Take `mode` for the blocks still to come. A digest starts only while
977    /// no block has been decoded: one begun later could not cover the
978    /// content, so a frame switched on past its first block stays unchecked.
979    #[cfg(feature = "hash")]
980    fn set_checksum_mode(&mut self, mode: ContentChecksum) {
981        self.checksum_mode = mode;
982        if mode == ContentChecksum::None {
983            self.hash = None;
984        } else if self.hash.is_none() && self.has_checksum && self.blocks == 0 {
985            self.hash = Some(twox_hash::XxHash64::with_seed(0));
986        }
987    }
988
989    /// Decode one block, `body` being the bytes after its header, with the
990    /// dictionary the frame was started with. The block has passed
991    /// [`Block::check`].
992    fn block<O: Output>(
993        &mut self,
994        workspace: &mut Workspace,
995        block: Block,
996        body: &[u8],
997        out: &mut O,
998        dict: LegacyDict<'_>,
999    ) -> Result<(), Error> {
1000        let decoder = workspace.decoder.as_mut().expect("readied with the frame");
1001        let before = out.produced();
1002        let mut out = Budget {
1003            end: before + self.limits.of_block(block),
1004            out,
1005        };
1006        let dict = self.history.of(dict);
1007        match block {
1008            Block::Compressed(_) => match decoder {
1009                VersionDecoder::V05(decoder) => decoder.block(body, &mut out, dict)?,
1010                VersionDecoder::V06(decoder) => decoder.block(body, &mut out, dict)?,
1011                VersionDecoder::V07(decoder) => decoder.block(body, &mut out, dict)?,
1012            },
1013            Block::Raw(len) => {
1014                out.reserve(len)?;
1015                out.extend(body);
1016            }
1017            Block::Rle(len) => {
1018                out.reserve(len)?;
1019                out.repeat(body[0], len);
1020            }
1021            Block::End => {}
1022        }
1023        #[cfg(feature = "hash")]
1024        if let Some(hash) = &mut self.hash {
1025            use core::hash::Hasher;
1026            hash.write(out.since(before));
1027        }
1028        #[cfg(all(feature = "lsm", feature = "hash"))]
1029        if self.block_digests {
1030            let digest = twox_hash::XxHash64::oneshot(0, out.since(before));
1031            // The low 32 bits, as for an RFC 8878 frame's blocks.
1032            workspace.block_digests.push(digest as u32);
1033        }
1034        self.blocks += 1;
1035        Ok(())
1036    }
1037
1038    /// Close the frame at its end block, whose header is `end`: the content
1039    /// checksum a v0.7 frame keeps there, held against the content as the
1040    /// caller's [`ContentChecksum`] mode says.
1041    ///
1042    /// The declared content size is not checked against the output. It is
1043    /// no integrity field in these formats: the v0.6.2 command line writes
1044    /// the size of the first chunk it read, so a v0.6 archive past 128 KiB
1045    /// declares too little. Upstream's streaming decoder (`zstd -d`) reads
1046    /// such an archive whole; its one-shot `ZSTD_decompress` calls it
1047    /// corrupt, which would refuse intact data.
1048    fn finish(&mut self, end: [u8; 3]) -> Result<(), Error> {
1049        // Only a v0.7 header announces a checksum; with none the end block's
1050        // size bits are 0 and nothing reads them.
1051        if !self.has_checksum {
1052            return Ok(());
1053        }
1054        let expected = u32::from(end[2]) | u32::from(end[1]) << 8 | u32::from(end[0] & 0x3F) << 16;
1055        self.stored_checksum = Some(expected);
1056        #[cfg(feature = "hash")]
1057        if let Some(hash) = &self.hash {
1058            use core::hash::Hasher;
1059            let calculated = ((hash.finish() >> 11) & 0x3F_FFFF) as u32;
1060            self.calculated_checksum = Some(calculated);
1061            if self.checksum_mode == ContentChecksum::Verify && expected != calculated {
1062                return Err(Error::ChecksumMismatch {
1063                    expected,
1064                    calculated,
1065                });
1066            }
1067        }
1068        Ok(())
1069    }
1070}
1071
1072/// Load `dict` into `workspace`'s decoder, readied for the frame's format,
1073/// and say which of its bytes matches reach. A v0.7 header naming a
1074/// dictionary (`dict_id`, 0 for none) takes only that one, as
1075/// `ZSTDv07_decompressFrameHeader` refuses another.
1076fn prime(
1077    dict_id: u32,
1078    dict: LegacyDict<'_>,
1079    workspace: &mut Workspace,
1080) -> Result<HistoryShape, Error> {
1081    let (header, content) = dict.pieces();
1082    Ok(
1083        match workspace.decoder.as_mut().expect("readied for the frame") {
1084            VersionDecoder::V07(decoder) => {
1085                let content = decoder.reset(dict)?;
1086                if dict_id != 0 && dict_id != decoder.dict_id {
1087                    return Err(Error::DictionaryMismatch {
1088                        expected: dict_id,
1089                        provided: decoder.dict_id,
1090                    });
1091                }
1092                HistoryShape::Content(content)
1093            }
1094            // A serialized header starts with the v0.7 layout's magic number,
1095            // which is neither format's own: they read the bytes whole as
1096            // content (`ZSTDv0{5,6}_decompress_insertDictionary`).
1097            VersionDecoder::V06(decoder) if !header.is_empty() => {
1098                decoder.reset(&[])?;
1099                HistoryShape::Whole
1100            }
1101            VersionDecoder::V05(decoder) if !header.is_empty() => {
1102                decoder.reset(&[])?;
1103                HistoryShape::Whole
1104            }
1105            VersionDecoder::V06(decoder) => HistoryShape::Content(decoder.reset(content)?),
1106            VersionDecoder::V05(decoder) => HistoryShape::Content(decoder.reset(content)?),
1107        },
1108    )
1109}
1110
1111/// Decode the frame starting `src` into `out`, in `workspace`. Returns the
1112/// bytes the frame took and the frame, finished.
1113fn decode_frame<O: Output>(
1114    src: &[u8],
1115    dict: LegacyDict<'_>,
1116    options: FrameOptions,
1117    workspace: &mut Workspace,
1118    out: &mut O,
1119) -> Result<(usize, LegacyFrame), Error> {
1120    let header = read_header_whole(src)?;
1121    let mut frame = LegacyFrame::new(header, dict, options, workspace)?;
1122    let mut at = header.size;
1123    loop {
1124        let block_header = src.get(at..at + 3).ok_or(Error::Truncated)?;
1125        let block = Block::read(block_header)?;
1126        block.check(header.version, frame.limits)?;
1127        let end = [block_header[0], block_header[1], block_header[2]];
1128        at += 3;
1129        let body = src.get(at..at + block.body_len()).ok_or(Error::Truncated)?;
1130        if ends_frame(header.version, block) {
1131            frame.finish(end)?;
1132            return Ok((at, frame));
1133        }
1134        frame.block(workspace, block, body, out, dict)?;
1135        at += body.len();
1136    }
1137}
1138
1139/// A v0.5-v0.7 frame decoded from input that arrives in pieces, a block at a
1140/// time, its output handed out as each block completes. It holds the window
1141/// the formats reach back into plus one block, as upstream's buffered
1142/// decoders (`ZBUFFv0{5,6,7}`) size theirs, and drops older output once it
1143/// has been handed out.
1144pub(crate) struct LegacyStream {
1145    /// The frame in progress; `None` when no frame is.
1146    frame: Option<LegacyFrame>,
1147    /// What frames decode in, kept across frames, whole-buffer ones too.
1148    workspace: Workspace,
1149    /// The dictionary the frame was started with.
1150    dict: Option<crate::decoding::DictionaryHandle>,
1151    /// The window the frame needs.
1152    window: u64,
1153    /// The window ceiling, once the caller lowered it below `window` after
1154    /// the frame started; the next step refuses the frame.
1155    window_refused_at: Option<u64>,
1156    /// The output segments: the current one at `..end`, and past it what is
1157    /// left of the one before.
1158    buf: Vec<u8>,
1159    /// End of the current segment.
1160    end: usize,
1161    /// Bytes of the frame in segments before the current one.
1162    earlier: usize,
1163    /// End of the segment before the current one, once there is one.
1164    previous_end: Option<usize>,
1165    /// How much of the current segment has been handed out.
1166    delivered: usize,
1167    /// Most the buffer holds before a block starts a new segment: the window
1168    /// and one block, so the segment before keeps the window in reach.
1169    capacity: usize,
1170    /// Whether the frame's end block has been read.
1171    finished: bool,
1172    /// Bytes of the frame read so far, its header included.
1173    consumed: u64,
1174    /// A block read from a `Read` source, held while it decodes.
1175    block: Vec<u8>,
1176}
1177
1178impl LegacyStream {
1179    pub(crate) const fn new() -> LegacyStream {
1180        LegacyStream {
1181            frame: None,
1182            workspace: Workspace {
1183                decoder: None,
1184                #[cfg(all(feature = "lsm", feature = "hash"))]
1185                block_digests: Vec::new(),
1186            },
1187            dict: None,
1188            window: 0,
1189            window_refused_at: None,
1190            buf: Vec::new(),
1191            end: 0,
1192            earlier: 0,
1193            previous_end: None,
1194            delivered: 0,
1195            capacity: 0,
1196            finished: false,
1197            consumed: 0,
1198            block: Vec::new(),
1199        }
1200    }
1201
1202    /// Start the frame `header` describes, with `dict`. A frame already in
1203    /// progress is dropped.
1204    pub(crate) fn start(
1205        &mut self,
1206        header: FrameHeader,
1207        dict: Option<&crate::decoding::DictionaryHandle>,
1208        options: FrameOptions,
1209    ) -> Result<(), Error> {
1210        self.frame = None;
1211        let legacy_dict = dict.map_or(LegacyDict::None, LegacyDict::of);
1212        self.frame = Some(LegacyFrame::new(
1213            header,
1214            legacy_dict,
1215            options,
1216            &mut self.workspace,
1217        )?);
1218        self.hold_dict(dict);
1219        self.window = header.window;
1220        self.window_refused_at = None;
1221        self.buf.clear();
1222        self.end = 0;
1223        self.earlier = 0;
1224        self.previous_end = None;
1225        self.delivered = 0;
1226        // Every header reader holds the window to its format's largest, at
1227        // most 128 MiB, which every target addresses.
1228        debug_assert!(header.window <= 1 << 27);
1229        self.capacity = header.window as usize + BLOCK_SIZE_MAX;
1230        self.finished = false;
1231        self.consumed = header.size as u64;
1232        Ok(())
1233    }
1234
1235    /// Keep `dict` as the frame's dictionary, taking a handle only when it is
1236    /// another dictionary than the one held, as an RFC 8878 frame's decoder
1237    /// keeps its own: the same dictionary frame after frame costs no count.
1238    fn hold_dict(&mut self, dict: Option<&crate::decoding::DictionaryHandle>) {
1239        match dict {
1240            None => self.dict = None,
1241            Some(dict) => {
1242                if self
1243                    .dict
1244                    .as_ref()
1245                    .is_none_or(|held| !core::ptr::eq(held.as_dict(), dict.as_dict()))
1246                {
1247                    self.dict = Some(dict.clone());
1248                }
1249            }
1250        }
1251    }
1252
1253    /// Leave the frame in progress, if any, keeping the buffer's capacity
1254    /// and the decoder's, and the dictionary handle for the next frame.
1255    pub(crate) fn end(&mut self) {
1256        self.frame = None;
1257        self.window_refused_at = None;
1258        self.buf.clear();
1259        self.end = 0;
1260        self.delivered = 0;
1261        self.finished = false;
1262    }
1263
1264    /// Decode the whole frame starting `src` into `out`, in the stream's
1265    /// workspace, leaving any frame the stream had in progress. The frame
1266    /// stays the stream's, finished with all its output handed out, so the
1267    /// decoder's accessors describe it. Returns the bytes the frame took.
1268    pub(crate) fn decode_whole<O: Output>(
1269        &mut self,
1270        src: &[u8],
1271        dict: Option<&crate::decoding::DictionaryHandle>,
1272        options: FrameOptions,
1273        out: &mut O,
1274    ) -> Result<usize, Error> {
1275        self.end();
1276        let before = out.produced();
1277        let legacy_dict = dict.map_or(LegacyDict::None, LegacyDict::of);
1278        let (consumed, frame) = decode_frame(src, legacy_dict, options, &mut self.workspace, out)?;
1279        self.hold_dict(dict);
1280        self.frame = Some(frame);
1281        self.earlier = out.produced() - before;
1282        self.previous_end = None;
1283        self.finished = true;
1284        self.consumed = consumed as u64;
1285        Ok(consumed)
1286    }
1287
1288    /// The content size the frame declares, 0 when it declares none.
1289    pub(crate) fn content_size(&self) -> u64 {
1290        self.frame.as_ref().map_or(0, |frame| frame.content_size)
1291    }
1292
1293    /// Data blocks the frame has decoded so far.
1294    pub(crate) fn blocks_decoded(&self) -> usize {
1295        self.frame.as_ref().map_or(0, |frame| frame.blocks)
1296    }
1297
1298    /// The checksum the frame's end block stores, once read.
1299    pub(crate) fn stored_checksum(&self) -> Option<u32> {
1300        self.frame.as_ref()?.stored_checksum
1301    }
1302
1303    /// The checksum the frame's content gives, once its end block is read
1304    /// and the checksum mode computes one.
1305    #[cfg(feature = "hash")]
1306    pub(crate) fn calculated_checksum(&self) -> Option<u32> {
1307        self.frame.as_ref()?.calculated_checksum
1308    }
1309
1310    /// Take the decoder's checksum mode for the rest of the frame in
1311    /// progress, as an RFC 8878 frame reads it at each decode step.
1312    #[cfg(feature = "hash")]
1313    pub(crate) fn set_checksum_mode(&mut self, mode: ContentChecksum) {
1314        if self.finished {
1315            return;
1316        }
1317        if let Some(frame) = self.frame.as_mut() {
1318            frame.set_checksum_mode(mode);
1319        }
1320    }
1321
1322    /// Decode the rest of the frame with `dict`, as an RFC 8878 frame takes a
1323    /// forced dictionary.
1324    pub(crate) fn force_dict(
1325        &mut self,
1326        dict: &crate::decoding::DictionaryHandle,
1327    ) -> Result<(), Error> {
1328        let frame = self.frame.as_mut().ok_or(corrupt("no frame in progress"))?;
1329        frame.set_dict(LegacyDict::of(dict), &mut self.workspace)?;
1330        self.hold_dict(Some(dict));
1331        Ok(())
1332    }
1333
1334    /// The dictionary the frame decodes with, when the stream holds one.
1335    pub(crate) fn dictionary(&self) -> Option<&crate::decoding::DictionaryHandle> {
1336        self.dict.as_ref()
1337    }
1338
1339    /// The frame's per-block digests so far, when they were asked for.
1340    #[cfg(all(feature = "lsm", feature = "hash"))]
1341    pub(crate) fn block_digests(&self) -> &[u32] {
1342        &self.workspace.block_digests
1343    }
1344
1345    /// Take a new window ceiling: a frame whose window it no longer admits
1346    /// is refused at its next step, one it admits again goes on.
1347    pub(crate) fn set_window_ceiling(&mut self, limit: u64) {
1348        if self.frame.is_some() && !self.finished {
1349            self.window_refused_at = (self.window > limit).then_some(limit);
1350        }
1351    }
1352
1353    /// The frame's window and the ceiling it was refused at, when lowered
1354    /// below it after the frame started.
1355    pub(crate) fn window_refusal(&self) -> Option<(u64, u64)> {
1356        Some((self.window, self.window_refused_at?))
1357    }
1358
1359    /// Whether a frame is in progress, or finished with output still to hand
1360    /// out.
1361    pub(crate) fn active(&self) -> bool {
1362        self.frame.is_some()
1363    }
1364
1365    /// Whether the frame's end block has been read.
1366    pub(crate) fn is_finished(&self) -> bool {
1367        self.finished
1368    }
1369
1370    /// Decoded bytes not handed out yet.
1371    pub(crate) fn undelivered(&self) -> usize {
1372        self.end - self.delivered
1373    }
1374
1375    /// Bytes the frame has decoded to so far.
1376    pub(crate) fn produced(&self) -> u64 {
1377        (self.earlier + self.end) as u64
1378    }
1379
1380    /// Bytes of the frame read so far, its header included.
1381    pub(crate) fn consumed(&self) -> u64 {
1382        self.consumed
1383    }
1384
1385    /// Heap bytes the stream holds: its buffers and the decoder's tables and
1386    /// literal buffer.
1387    pub(crate) fn heap_bytes(&self) -> usize {
1388        self.buf.capacity() + self.block.capacity() + self.workspace.heap_bytes()
1389    }
1390
1391    /// How many bytes from the start of `pending` the next step needs: a
1392    /// block header, then the whole block; 0 once the frame is finished. A
1393    /// block its header rules out needs only the header, whose step then
1394    /// refuses it.
1395    pub(crate) fn input_needed(&self, pending: &[u8]) -> usize {
1396        if self.finished {
1397            return 0;
1398        }
1399        let Ok(block) = Block::read(pending) else {
1400            return 3;
1401        };
1402        match &self.frame {
1403            Some(frame) if block.check(frame.version, frame.limits).is_err() => 3,
1404            _ => 3 + block.body_len(),
1405        }
1406    }
1407
1408    /// Decode the whole steps `src` holds into `target`, a block at a time,
1409    /// decoding no further while `target` cannot take what is decoded.
1410    /// Returns the bytes read and written.
1411    ///
1412    /// A step that fails after output went to `target` in the same call
1413    /// reports the error alone, as the RFC 8878 loop does and as upstream's
1414    /// buffered decoders do: they flush, decode the next block in the same
1415    /// call and return its error (`zstd_v07.c:4421`, `:4447`, reached from
1416    /// `ZSTD_decompressStream`). The `Read` adapter never meets that case:
1417    /// it holds one step of input at a time and returns delivered bytes
1418    /// before it reads the next.
1419    pub(crate) fn decode(
1420        &mut self,
1421        src: &[u8],
1422        target: &mut [u8],
1423    ) -> Result<(usize, usize), Error> {
1424        let mut read = 0;
1425        let mut written = 0;
1426        loop {
1427            written += self.hand_out(&mut target[written..]);
1428            if self.undelivered() > 0 || self.finished {
1429                break;
1430            }
1431            let rest = &src[read..];
1432            let need = self.input_needed(rest);
1433            if need > rest.len() {
1434                break;
1435            }
1436            self.step(&rest[..need])?;
1437            read += need;
1438        }
1439        Ok((read, written))
1440    }
1441
1442    /// Hand out what `target` takes of the undelivered output.
1443    pub(crate) fn hand_out(&mut self, target: &mut [u8]) -> usize {
1444        let n = self.undelivered().min(target.len());
1445        target[..n].copy_from_slice(&self.buf[self.delivered..self.delivered + n]);
1446        self.delivered += n;
1447        n
1448    }
1449
1450    /// The undelivered output, which [`Self::mark_delivered`] then hands out.
1451    pub(crate) fn undelivered_bytes(&self) -> &[u8] {
1452        &self.buf[self.delivered..self.end]
1453    }
1454
1455    /// Count the first `n` undelivered bytes as handed out.
1456    pub(crate) fn mark_delivered(&mut self, n: usize) {
1457        debug_assert!(n <= self.undelivered());
1458        self.delivered += n;
1459    }
1460
1461    /// Read the next block from `source` and decode it.
1462    pub(crate) fn read_step<R: crate::io::Read>(
1463        &mut self,
1464        source: &mut R,
1465    ) -> Result<(), crate::decoding::errors::FrameDecoderError> {
1466        use crate::blocks::block::BlockType;
1467        use crate::decoding::errors::{
1468            BlockHeaderReadError, DecodeBlockContentError, FrameDecoderError,
1469        };
1470        // Lent out while the block decodes, which needs `self`.
1471        let mut block = core::mem::take(&mut self.block);
1472        block.clear();
1473        block.resize(3, 0);
1474        let result = source
1475            .read_exact(&mut block)
1476            .map_err(|source| {
1477                FrameDecoderError::FailedToReadBlockHeader(BlockHeaderReadError::ReadError(source))
1478            })
1479            .and_then(|()| {
1480                let need = self.input_needed(&block);
1481                block.resize(need, 0);
1482                // The header names the block whose body is read.
1483                let step = match Block::read(&block) {
1484                    Ok(Block::Raw(_)) => BlockType::Raw,
1485                    Ok(Block::Rle(_)) => BlockType::RLE,
1486                    _ => BlockType::Compressed,
1487                };
1488                source.read_exact(&mut block[3..]).map_err(|source| {
1489                    FrameDecoderError::FailedToReadBlockBody(DecodeBlockContentError::ReadError {
1490                        step,
1491                        source,
1492                    })
1493                })
1494            })
1495            .and_then(|()| Ok(self.step(&block)?));
1496        self.block = block;
1497        result
1498    }
1499
1500    /// Decode one block, `step` holding its header and body.
1501    fn step(&mut self, step: &[u8]) -> Result<(), Error> {
1502        let LegacyStream {
1503            frame,
1504            workspace,
1505            dict,
1506            window,
1507            window_refused_at: _,
1508            buf,
1509            end,
1510            earlier,
1511            previous_end,
1512            delivered,
1513            capacity,
1514            finished,
1515            consumed,
1516            block: _,
1517        } = self;
1518        let frame = frame.as_mut().ok_or(corrupt("no frame in progress"))?;
1519        let block = Block::read(step)?;
1520        block.check(frame.version, frame.limits)?;
1521        *consumed += step.len() as u64;
1522        if ends_frame(frame.version, block) {
1523            frame.finish([step[0], step[1], step[2]])?;
1524            *finished = true;
1525            return Ok(());
1526        }
1527        // A block that would not fit starts a new segment at the buffer's
1528        // start, once the current one is all handed out; the one before stays
1529        // where it is for matches, as upstream's buffered decoders wrap
1530        // (`ZBUFFv07_decompressContinue`). Only a segment that holds the
1531        // window may become the one before, so matches into it stay in reach.
1532        // Output held back by a caller that has not collected it grows the
1533        // buffer instead.
1534        let block_max = block.decoded_max();
1535        let handed_out = *delivered == *end;
1536        if *end + block_max > *capacity && handed_out && *end > 0 && *end as u64 >= *window {
1537            *earlier += *end;
1538            *previous_end = Some(*end);
1539            *end = 0;
1540            *delivered = 0;
1541        }
1542        // A stored block past 128 KiB that cannot wrap grows the buffer by
1543        // itself: the stream holds its window and one block of any type.
1544        let limit = if handed_out {
1545            (*capacity).max(*end + block_max)
1546        } else {
1547            *capacity
1548        };
1549        let dict = dict.as_ref().map_or(LegacyDict::None, LegacyDict::of);
1550        let mut out = SegmentOutput {
1551            buf,
1552            end: *end,
1553            earlier: *earlier,
1554            previous_end: *previous_end,
1555            capacity: limit,
1556        };
1557        let decoded = frame.block(workspace, block, &step[3..], &mut out, dict);
1558        *end = out.end;
1559        decoded
1560    }
1561}
1562
1563/// Output into a stream's segments: the current segment from the buffer's
1564/// start to `end`, and the segment before it, which ends at `previous_end`,
1565/// past the current one.
1566struct SegmentOutput<'b> {
1567    buf: &'b mut Vec<u8>,
1568    end: usize,
1569    earlier: usize,
1570    previous_end: Option<usize>,
1571    /// What the buffer grows to at most while segments wrap.
1572    capacity: usize,
1573}
1574
1575impl SegmentOutput<'_> {
1576    /// Make room for `len` more bytes at `end`; the buffer grows only where
1577    /// the segment runs past what it holds, doubling up to `capacity` and
1578    /// past it only for output a caller holds back.
1579    fn room(&mut self, len: usize) -> core::ops::Range<usize> {
1580        let to = self.end + len;
1581        if to > self.buf.capacity() {
1582            // A `Vec` holds at most `isize::MAX` bytes, so doubling its
1583            // length stays within `usize`.
1584            let doubled = 2 * self.buf.len();
1585            let target = if to <= self.capacity {
1586                doubled.clamp(to, self.capacity)
1587            } else {
1588                doubled.max(to)
1589            };
1590            self.buf.reserve_exact(target - self.buf.len());
1591        }
1592        if to > self.buf.len() {
1593            self.buf.resize(to, 0);
1594        }
1595        self.end..to
1596    }
1597}
1598
1599impl Output for SegmentOutput<'_> {
1600    fn produced(&self) -> usize {
1601        self.earlier + self.end
1602    }
1603
1604    fn held(&self) -> usize {
1605        self.end
1606    }
1607
1608    fn reserve(&mut self, _len: usize) -> Result<(), Error> {
1609        // The block's own budget bounds what it adds.
1610        Ok(())
1611    }
1612
1613    fn extend(&mut self, bytes: &[u8]) {
1614        let at = self.room(bytes.len());
1615        self.buf[at].copy_from_slice(bytes);
1616        self.end += bytes.len();
1617    }
1618
1619    fn repeat(&mut self, byte: u8, len: usize) {
1620        let at = self.room(len);
1621        self.buf[at].fill(byte);
1622        self.end += len;
1623    }
1624
1625    fn copy_back(&mut self, offset: usize, len: usize) {
1626        let from = self.end - offset;
1627        let at = self.room(len);
1628        copy_repeating(self.buf, from, at.start, len);
1629        self.end += len;
1630    }
1631
1632    #[cfg(feature = "hash")]
1633    fn since(&self, from: usize) -> &[u8] {
1634        &self.buf[self.end - (self.produced() - from)..self.end]
1635    }
1636
1637    fn copy_match(&mut self, offset: usize, len: usize, dict: &History<'_>) -> Result<(), Error> {
1638        let Some(previous_end) = self.previous_end else {
1639            // One segment so far: it holds the whole frame.
1640            return copy_match(self, offset, len, dict);
1641        };
1642        // At least 1 by construction, as in `copy_match`.
1643        debug_assert!(offset >= 1);
1644        if offset <= self.end {
1645            self.copy_back(offset, len);
1646            return Ok(());
1647        }
1648        // Into the segment before, which the current one has not yet
1649        // overwritten from `end` on.
1650        let back = offset - self.end;
1651        let from = previous_end
1652            .checked_sub(back)
1653            .filter(|&from| from >= self.end)
1654            .ok_or(corrupt("match reaches before the window"))?;
1655        let first = len.min(back);
1656        let at = self.room(first);
1657        self.buf.copy_within(from..from + first, at.start);
1658        self.end += first;
1659        let rest = len - first;
1660        if rest > 0 {
1661            // The match runs on from the current segment's first byte.
1662            let distance = self.end;
1663            self.copy_back(distance, rest);
1664        }
1665        Ok(())
1666    }
1667}
1668
1669#[cfg(test)]
1670mod tests;