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