Skip to main content

zstd_complete/decoding/
frame_decoder.rs

1//! Framedecoder is the main low-level struct users interact with to decode zstd frames
2//!
3//! Zstandard compressed data is made of one or more frames. Each frame is independent and can be
4//! decompressed independently of other frames. This module contains structures
5//! and utilities that can be used to decode a frame.
6
7use super::frame;
8use crate::decoding;
9use crate::decoding::dictionary::Dictionary;
10use crate::decoding::errors::FrameDecoderError;
11use crate::decoding::scratch::DecoderScratch;
12use crate::io::{Error, Read, Write};
13use alloc::collections::BTreeMap;
14use alloc::vec::Vec;
15use core::convert::TryInto;
16
17/// While the maximum window size allowed by the spec is significantly larger,
18/// our implementation limits it to 100mb to protect against malformed frames.
19const MAXIMUM_ALLOWED_WINDOW_SIZE: u64 = 1024 * 1024 * 100;
20
21/// Low level Zstandard decoder that can be used to decompress frames with fine control over when and how many bytes are decoded.
22///
23/// This decoder is able to decode frames only partially and gives control
24/// over how many bytes/blocks will be decoded at a time (so you don't have to decode a 10GB file into memory all at once).
25/// It reads bytes as needed from a provided source and can be read from to collect partial results.
26///
27/// If you want to just read the whole frame with an `io::Read` without having to deal with manually calling [FrameDecoder::decode_blocks]
28/// you can use the provided [crate::decoding::StreamingDecoder] wich wraps this FrameDecoder.
29///
30/// Workflow is as follows:
31/// ```
32/// use zstd_complete::decoding::BlockDecodingStrategy;
33///
34/// # #[cfg(feature = "std")]
35/// use std::io::{Read, Write};
36///
37/// // no_std environments can use the crate's own Read traits
38/// # #[cfg(not(feature = "std"))]
39/// use zstd_complete::io::{Read, Write};
40///
41/// fn decode_this(mut file: impl Read) {
42///     //Create a new decoder
43///     let mut frame_dec = zstd_complete::decoding::FrameDecoder::new();
44///     let mut result = Vec::new();
45///
46///     // Use reset or init to make the decoder ready to decode the frame from the io::Read
47///     frame_dec.reset(&mut file).unwrap();
48///
49///     // Loop until the frame has been decoded completely
50///     while !frame_dec.is_finished() {
51///         // decode (roughly) batch_size many bytes
52///         frame_dec.decode_blocks(&mut file, BlockDecodingStrategy::UptoBytes(1024)).unwrap();
53///
54///         // read from the decoder to collect bytes from the internal buffer
55///         let bytes_read = frame_dec.read(result.as_mut_slice()).unwrap();
56///
57///         // then do something with it
58///         do_something(&result[0..bytes_read]);
59///     }
60///
61///     // handle the last chunk of data
62///     while frame_dec.can_collect() > 0 {
63///         let x = frame_dec.read(result.as_mut_slice()).unwrap();
64///
65///         do_something(&result[0..x]);
66///     }
67/// }
68///
69/// fn do_something(data: &[u8]) {
70/// # #[cfg(feature = "std")]
71///     std::io::stdout().write_all(data).unwrap();
72/// }
73/// ```
74pub struct FrameDecoder {
75    state: Option<FrameDecoderState>,
76    dicts: BTreeMap<u32, Dictionary>,
77}
78
79struct FrameDecoderState {
80    pub frame_header: frame::FrameHeader,
81    decoder_scratch: DecoderScratch,
82    frame_finished: bool,
83    block_counter: usize,
84    bytes_read_counter: u64,
85    decoded_size_counter: u64,
86    check_sum: Option<u32>,
87    using_dict: Option<u32>,
88}
89
90pub enum BlockDecodingStrategy {
91    All,
92    UptoBlocks(usize),
93    UptoBytes(usize),
94}
95
96impl FrameDecoderState {
97    pub fn new(source: impl Read) -> Result<FrameDecoderState, FrameDecoderError> {
98        let (frame, header_size) = frame::read_frame_header(source)?;
99        let window_size = frame.window_size()?;
100        Ok(FrameDecoderState {
101            frame_header: frame,
102            frame_finished: false,
103            block_counter: 0,
104            decoder_scratch: DecoderScratch::new(window_size as usize),
105            bytes_read_counter: u64::from(header_size),
106            decoded_size_counter: 0,
107            check_sum: None,
108            using_dict: None,
109        })
110    }
111
112    pub fn reset(&mut self, source: impl Read) -> Result<(), FrameDecoderError> {
113        let (frame_header, header_size) = frame::read_frame_header(source)?;
114        let window_size = frame_header.window_size()?;
115
116        if window_size > MAXIMUM_ALLOWED_WINDOW_SIZE {
117            return Err(FrameDecoderError::WindowSizeTooBig {
118                requested: window_size,
119            });
120        }
121
122        self.frame_header = frame_header;
123        self.frame_finished = false;
124        self.block_counter = 0;
125        self.decoder_scratch.reset(window_size as usize);
126        self.bytes_read_counter = u64::from(header_size);
127        self.decoded_size_counter = 0;
128        self.check_sum = None;
129        self.using_dict = None;
130        Ok(())
131    }
132}
133
134impl Default for FrameDecoder {
135    fn default() -> Self {
136        Self::new()
137    }
138}
139
140impl FrameDecoder {
141    /// This will create a new decoder without allocating anything yet.
142    /// init()/reset() will allocate all needed buffers if it is the first time this decoder is used
143    /// else they just reset these buffers with not further allocations
144    pub fn new() -> FrameDecoder {
145        FrameDecoder {
146            state: None,
147            dicts: BTreeMap::new(),
148        }
149    }
150
151    /// init() will allocate all needed buffers if it is the first time this decoder is used
152    /// else they just reset these buffers with not further allocations
153    ///
154    /// Note that all bytes currently in the decodebuffer from any previous frame will be lost. Collect them with collect()/collect_to_writer()
155    ///
156    /// equivalent to reset()
157    pub fn init(&mut self, source: impl Read) -> Result<(), FrameDecoderError> {
158        self.reset(source)
159    }
160
161    /// reset() will allocate all needed buffers if it is the first time this decoder is used
162    /// else they just reset these buffers with not further allocations
163    ///
164    /// Note that all bytes currently in the decodebuffer from any previous frame will be lost. Collect them with collect()/collect_to_writer()
165    ///
166    /// equivalent to init()
167    pub fn reset(&mut self, source: impl Read) -> Result<(), FrameDecoderError> {
168        use FrameDecoderError as err;
169        let state = match &mut self.state {
170            Some(s) => {
171                s.reset(source)?;
172                s
173            }
174            None => {
175                self.state = Some(FrameDecoderState::new(source)?);
176                self.state.as_mut().unwrap()
177            }
178        };
179        if let Some(dict_id) = state.frame_header.dictionary_id() {
180            let dict = self
181                .dicts
182                .get(&dict_id)
183                .ok_or(err::DictNotProvided { dict_id })?;
184            state.decoder_scratch.init_from_dict(dict);
185            state.using_dict = Some(dict_id);
186        }
187        Ok(())
188    }
189
190    /// Add a dict to the FrameDecoder that can be used when needed. The FrameDecoder uses the appropriate one dynamically
191    pub fn add_dict(&mut self, dict: Dictionary) -> Result<(), FrameDecoderError> {
192        self.dicts.insert(dict.id, dict);
193        Ok(())
194    }
195
196    pub fn force_dict(&mut self, dict_id: u32) -> Result<(), FrameDecoderError> {
197        use FrameDecoderError as err;
198        let Some(state) = self.state.as_mut() else {
199            return Err(err::NotYetInitialized);
200        };
201
202        let dict = self
203            .dicts
204            .get(&dict_id)
205            .ok_or(err::DictNotProvided { dict_id })?;
206        state.decoder_scratch.init_from_dict(dict);
207        state.using_dict = Some(dict_id);
208
209        Ok(())
210    }
211
212    /// Returns how many bytes the frame contains after decompression
213    pub fn content_size(&self) -> u64 {
214        match &self.state {
215            None => 0,
216            Some(s) => s.frame_header.frame_content_size(),
217        }
218    }
219
220    /// Returns the checksum that was read from the data. Only available after all bytes have been read. It is the last 4 bytes of a zstd-frame
221    pub fn get_checksum_from_data(&self) -> Option<u32> {
222        let state = self.state.as_ref()?;
223
224        state.check_sum
225    }
226
227    /// Returns the checksum that was calculated while decoding.
228    /// Only a sensible value after all decoded bytes have been collected/read from the FrameDecoder
229    #[cfg(feature = "hash")]
230    pub fn get_calculated_checksum(&self) -> Option<u32> {
231        use core::hash::Hasher;
232
233        let state = self.state.as_ref()?;
234        let cksum_64bit = state.decoder_scratch.buffer.hash.finish();
235        //truncate to lower 32bit because reasons...
236        Some(cksum_64bit as u32)
237    }
238
239    /// Counter for how many bytes have been consumed while decoding the frame
240    pub fn bytes_read_from_source(&self) -> u64 {
241        let state = match &self.state {
242            None => return 0,
243            Some(s) => s,
244        };
245        state.bytes_read_counter
246    }
247
248    /// Counter for how many bytes have been produced while decoding the frame.
249    pub fn decoded_size(&self) -> u64 {
250        let state = match &self.state {
251            None => return 0,
252            Some(s) => s,
253        };
254        state.decoded_size_counter
255    }
256
257    /// Whether the current frames last block has been decoded yet
258    /// If this returns true you can call the drain* functions to get all content
259    /// (the read() function will drain automatically if this returns true)
260    pub fn is_finished(&self) -> bool {
261        let state = match &self.state {
262            None => return true,
263            Some(s) => s,
264        };
265        if state.frame_header.descriptor.content_checksum_flag() {
266            state.frame_finished && state.check_sum.is_some()
267        } else {
268            state.frame_finished
269        }
270    }
271
272    /// Counter for how many blocks have already been decoded
273    pub fn blocks_decoded(&self) -> usize {
274        let state = match &self.state {
275            None => return 0,
276            Some(s) => s,
277        };
278        state.block_counter
279    }
280
281    /// Decodes blocks from a reader. It requires that the framedecoder has been initialized first.
282    /// The Strategy influences how many blocks will be decoded before the function returns
283    /// This is important if you want to manage memory consumption carefully. If you don't care
284    /// about that you can just choose the strategy "All" and have all blocks of the frame decoded into the buffer
285    pub fn decode_blocks(
286        &mut self,
287        mut source: impl Read,
288        strat: BlockDecodingStrategy,
289    ) -> Result<bool, FrameDecoderError> {
290        use FrameDecoderError as err;
291        let state = self.state.as_mut().ok_or(err::NotYetInitialized)?;
292
293        let mut block_dec = decoding::block_decoder::new();
294
295        let buffer_size_before = state.decoder_scratch.buffer.len();
296        let block_counter_before = state.block_counter;
297        loop {
298            vprintln!("################");
299            vprintln!("Next Block: {}", state.block_counter);
300            vprintln!("################");
301            let (block_header, block_header_size) = block_dec
302                .read_block_header(&mut source)
303                .map_err(err::FailedToReadBlockHeader)?;
304            state.bytes_read_counter += u64::from(block_header_size);
305
306            vprintln!();
307            vprintln!(
308                "Found {} block with size: {}, which will be of size: {}",
309                block_header.block_type,
310                block_header.content_size,
311                block_header.decompressed_size
312            );
313
314            let decoded_size_before_block = state.decoder_scratch.buffer.len();
315            let bytes_read_in_block_body = block_dec
316                .decode_block_content(&block_header, &mut state.decoder_scratch, &mut source)
317                .map_err(err::FailedToReadBlockBody)?;
318            state.bytes_read_counter += bytes_read_in_block_body;
319            state.decoded_size_counter +=
320                (state.decoder_scratch.buffer.len() - decoded_size_before_block) as u64;
321
322            state.block_counter += 1;
323
324            vprintln!("Output: {}", state.decoder_scratch.buffer.len());
325
326            if block_header.last_block {
327                state.frame_finished = true;
328                if state.frame_header.descriptor.content_checksum_flag() {
329                    let mut chksum = [0u8; 4];
330                    source
331                        .read_exact(&mut chksum)
332                        .map_err(err::FailedToReadChecksum)?;
333                    state.bytes_read_counter += 4;
334                    let chksum = u32::from_le_bytes(chksum);
335                    state.check_sum = Some(chksum);
336                }
337                break;
338            }
339
340            match strat {
341                BlockDecodingStrategy::All => { /* keep going */ }
342                BlockDecodingStrategy::UptoBlocks(n) => {
343                    if state.block_counter - block_counter_before >= n {
344                        break;
345                    }
346                }
347                BlockDecodingStrategy::UptoBytes(n) => {
348                    if state.decoder_scratch.buffer.len() - buffer_size_before >= n {
349                        break;
350                    }
351                }
352            }
353        }
354
355        Ok(state.frame_finished)
356    }
357
358    /// Collect bytes and retain window_size bytes while decoding is still going on.
359    /// After decoding of the frame (is_finished() == true) has finished it will collect all remaining bytes
360    pub fn collect(&mut self) -> Option<Vec<u8>> {
361        let finished = self.is_finished();
362        let state = self.state.as_mut()?;
363        if finished {
364            Some(state.decoder_scratch.buffer.drain())
365        } else {
366            state.decoder_scratch.buffer.drain_to_window_size()
367        }
368    }
369
370    /// Collect bytes and retain window_size bytes while decoding is still going on.
371    /// After decoding of the frame (is_finished() == true) has finished it will collect all remaining bytes
372    pub fn collect_to_writer(&mut self, w: impl Write) -> Result<usize, Error> {
373        let finished = self.is_finished();
374        let state = match &mut self.state {
375            None => return Ok(0),
376            Some(s) => s,
377        };
378        if finished {
379            state.decoder_scratch.buffer.drain_to_writer(w)
380        } else {
381            state.decoder_scratch.buffer.drain_to_window_size_writer(w)
382        }
383    }
384
385    /// How many bytes can currently be collected from the decodebuffer, while decoding is going on this will be lower than the actual decodbuffer size
386    /// because window_size bytes need to be retained for decoding.
387    /// After decoding of the frame (is_finished() == true) has finished it will report all remaining bytes
388    pub fn can_collect(&self) -> usize {
389        let finished = self.is_finished();
390        let state = match &self.state {
391            None => return 0,
392            Some(s) => s,
393        };
394        if finished {
395            state.decoder_scratch.buffer.can_drain()
396        } else {
397            state
398                .decoder_scratch
399                .buffer
400                .can_drain_to_window_size()
401                .unwrap_or(0)
402        }
403    }
404
405    /// Decodes as many blocks as possible from the source slice and reads from the decodebuffer into the target slice
406    /// The source slice may contain only parts of a frame but must contain at least one full block to make progress
407    ///
408    /// By all means use decode_blocks if you have a io.Reader available. This is just for compatibility with other decompressors
409    /// which try to serve an old-style c api
410    ///
411    /// Returns (read, written), if read == 0 then the source did not contain a full block and further calls with the same
412    /// input will not make any progress!
413    ///
414    /// Note that no kind of block can be bigger than 128kb.
415    /// So to be safe use at least 128*1024 (max block content size) + 3 (block_header size) + 18 (max frame_header size) bytes as your source buffer
416    ///
417    /// You may call this function with an empty source after all bytes have been decoded. This is equivalent to just call decoder.read(&mut target)
418    pub fn decode_from_to(
419        &mut self,
420        source: &[u8],
421        target: &mut [u8],
422    ) -> Result<(usize, usize), FrameDecoderError> {
423        use FrameDecoderError as err;
424        let bytes_read_at_start = match &self.state {
425            Some(s) => s.bytes_read_counter,
426            None => 0,
427        };
428
429        if !self.is_finished() || self.state.is_none() {
430            let mut mt_source = source;
431
432            if self.state.is_none() {
433                self.init(&mut mt_source)?;
434            }
435
436            //pseudo block to scope "state" so we can borrow self again after the block
437            {
438                let state = match &mut self.state {
439                    Some(s) => s,
440                    None => panic!("Bug in library"),
441                };
442                let mut block_dec = decoding::block_decoder::new();
443
444                if state.frame_header.descriptor.content_checksum_flag()
445                    && state.frame_finished
446                    && state.check_sum.is_none()
447                {
448                    //this block is needed if the checksum were the only 4 bytes that were not included in the last decode_from_to call for a frame
449                    if mt_source.len() >= 4 {
450                        let chksum = mt_source[..4].try_into().expect("optimized away");
451                        state.bytes_read_counter += 4;
452                        let chksum = u32::from_le_bytes(chksum);
453                        state.check_sum = Some(chksum);
454                    }
455                    return Ok((4, 0));
456                }
457
458                loop {
459                    //check if there are enough bytes for the next header
460                    if mt_source.len() < 3 {
461                        break;
462                    }
463                    let (block_header, block_header_size) = block_dec
464                        .read_block_header(&mut mt_source)
465                        .map_err(err::FailedToReadBlockHeader)?;
466
467                    // check the needed size for the block before updating counters.
468                    // If not enough bytes are in the source, the header will have to be read again, so act like we never read it in the first place
469                    if mt_source.len() < block_header.content_size as usize {
470                        break;
471                    }
472                    state.bytes_read_counter += u64::from(block_header_size);
473
474                    let bytes_read_in_block_body = block_dec
475                        .decode_block_content(
476                            &block_header,
477                            &mut state.decoder_scratch,
478                            &mut mt_source,
479                        )
480                        .map_err(err::FailedToReadBlockBody)?;
481                    state.bytes_read_counter += bytes_read_in_block_body;
482                    state.block_counter += 1;
483
484                    if block_header.last_block {
485                        state.frame_finished = true;
486                        if state.frame_header.descriptor.content_checksum_flag() {
487                            //if there are enough bytes handle this here. Else the block at the start of this function will handle it at the next call
488                            if mt_source.len() >= 4 {
489                                let chksum = mt_source[..4].try_into().expect("optimized away");
490                                state.bytes_read_counter += 4;
491                                let chksum = u32::from_le_bytes(chksum);
492                                state.check_sum = Some(chksum);
493                            }
494                        }
495                        break;
496                    }
497                }
498            }
499        }
500
501        let result_len = self.read(target).map_err(err::FailedToDrainDecodebuffer)?;
502        let bytes_read_at_end = match &mut self.state {
503            Some(s) => s.bytes_read_counter,
504            None => panic!("Bug in library"),
505        };
506        let read_len = bytes_read_at_end - bytes_read_at_start;
507        Ok((read_len as usize, result_len))
508    }
509
510    /// Decode multiple frames into the output slice.
511    ///
512    /// `input` must contain an exact number of frames.
513    ///
514    /// `output` must be large enough to hold the decompressed data. If you don't know
515    /// how large the output will be, use [`FrameDecoder::decode_blocks`] instead.
516    ///
517    /// This calls [`FrameDecoder::init`], and all bytes currently in the decoder will be lost.
518    ///
519    /// Returns the number of bytes written to `output`.
520    pub fn decode_all(
521        &mut self,
522        mut input: &[u8],
523        mut output: &mut [u8],
524    ) -> Result<usize, FrameDecoderError> {
525        let mut total_bytes_written = 0;
526        while !input.is_empty() {
527            match self.init(&mut input) {
528                Ok(_) => {}
529                Err(FrameDecoderError::ReadFrameHeaderError(
530                    crate::decoding::errors::ReadFrameHeaderError::SkipFrame { length, .. },
531                )) => {
532                    input = input
533                        .get(length as usize..)
534                        .ok_or(FrameDecoderError::FailedToSkipFrame)?;
535                    continue;
536                }
537                Err(e) => return Err(e),
538            };
539            loop {
540                self.decode_blocks(&mut input, BlockDecodingStrategy::UptoBytes(1024 * 1024))?;
541                let bytes_written = self
542                    .read(output)
543                    .map_err(FrameDecoderError::FailedToDrainDecodebuffer)?;
544                output = &mut output[bytes_written..];
545                total_bytes_written += bytes_written;
546                if self.can_collect() != 0 {
547                    return Err(FrameDecoderError::TargetTooSmall);
548                }
549                if self.is_finished() {
550                    break;
551                }
552            }
553        }
554
555        Ok(total_bytes_written)
556    }
557
558    /// Decode multiple frames into the extra capacity of the output vector.
559    ///
560    /// `input` must contain an exact number of frames.
561    ///
562    /// `output` must have enough extra capacity to hold the decompressed data.
563    /// This function will not reallocate or grow the vector. If you don't know
564    /// how large the output will be, use [`FrameDecoder::decode_blocks`] instead.
565    ///
566    /// This calls [`FrameDecoder::init`], and all bytes currently in the decoder will be lost.
567    ///
568    /// The length of the output vector is updated to include the decompressed data.
569    /// The length is not changed if an error occurs.
570    pub fn decode_all_to_vec(
571        &mut self,
572        input: &[u8],
573        output: &mut Vec<u8>,
574    ) -> Result<(), FrameDecoderError> {
575        let len = output.len();
576        let cap = output.capacity();
577        output.resize(cap, 0);
578        match self.decode_all(input, &mut output[len..]) {
579            Ok(bytes_written) => {
580                let new_len = core::cmp::min(len + bytes_written, cap); // Sanitizes `bytes_written`.
581                output.resize(new_len, 0);
582                Ok(())
583            }
584            Err(e) => {
585                output.resize(len, 0);
586                Err(e)
587            }
588        }
589    }
590}
591
592/// Read bytes from the decode_buffer that are no longer needed. While the frame is not yet finished
593/// this will retain window_size bytes, else it will drain it completely
594impl Read for FrameDecoder {
595    fn read(&mut self, target: &mut [u8]) -> Result<usize, Error> {
596        let state = match &mut self.state {
597            None => return Ok(0),
598            Some(s) => s,
599        };
600        if state.frame_finished {
601            state.decoder_scratch.buffer.read_all(target)
602        } else {
603            state.decoder_scratch.buffer.read(target)
604        }
605    }
606}