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