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