1use std::fmt::Debug;
4use std::fmt::Formatter;
5
6use crate::BlockSize;
7use crate::buffer::filled;
8use crate::cm::CmCoder;
9use crate::crc32;
10use crate::error::Error;
11use crate::error::Result;
12use crate::frame::read_i32;
13use crate::frame::read_u32;
14use crate::lzp;
15use crate::rle;
16use crate::sais;
17use crate::sais::UnbwtScratch;
18
19use super::FILLER_CAP;
20use super::MODEL_LEN;
21use super::PREFIX_LEN;
22use super::PayloadPrefix;
23use super::STORED_MARKER;
24use super::STORED_MAX_BODY;
25use super::STORED_PREFIX_LEN;
26use super::model::Model;
27
28#[derive(Debug)]
30pub enum BlockStatus {
31 Intact,
33 BadChecksum,
35 Zeroed(Error),
37}
38
39pub struct BlockDecoder {
70 block_size: BlockSize,
72 lzp_table: Box<lzp::HashTable>,
74 coder: Box<CmCoder>,
78 buf_a: Vec<u8>,
80 buf_b: Vec<u8>,
82 unbwt_scratch: UnbwtScratch,
84}
85
86impl Debug for BlockDecoder {
87 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
88 f.debug_struct("BlockDecoder")
89 .field("block_size", &self.block_size)
90 .finish_non_exhaustive()
91 }
92}
93
94impl BlockDecoder {
95 pub fn new(block_size: BlockSize) -> Result<Self> {
113 let capacity = crate::compress_bound(block_size.as_usize());
114 Ok(Self {
115 block_size,
116 lzp_table: lzp::new_table()?,
117 coder: Box::new(CmCoder::new()),
118 buf_a: filled(capacity, 0).ok_or(Error::OutOfMemory)?,
119 buf_b: filled(capacity, 0).ok_or(Error::OutOfMemory)?,
120 unbwt_scratch: UnbwtScratch::default(),
121 })
122 }
123
124 #[must_use]
126 #[inline]
127 pub const fn block_size(&self) -> BlockSize {
128 self.block_size
129 }
130
131 #[must_use = "decoded output must be written to the frame"]
155 #[inline]
156 pub fn decode_block(&mut self, payload: &[u8], orig_size: u32) -> Result<Vec<u8>> {
157 let mut out = Vec::new();
158 self.decode_block_into(payload, orig_size, &mut out)?;
159 Ok(out)
160 }
161
162 pub fn decode_block_into(
194 &mut self,
195 payload: &[u8],
196 orig_size: u32,
197 out: &mut Vec<u8>,
198 ) -> Result<()> {
199 let head = self.read_prefix(payload, orig_size)?;
200 let old_len = out.len();
201 out.try_reserve(head.original_len)
202 .map_err(|_| Error::OutOfMemory)?;
203 out.resize(old_len + head.original_len, 0);
204 let result = self.decode_payload(payload, &head, &mut out[old_len..]);
205 if result.is_err() {
206 out.truncate(old_len);
207 }
208 result
209 }
210
211 pub fn recover_block_into(
254 &mut self,
255 payload: &[u8],
256 orig_size: u32,
257 out: &mut Vec<u8>,
258 ) -> Result<BlockStatus> {
259 let fill = usize::try_from(orig_size)
260 .unwrap_or(usize::MAX)
261 .min(self.block_size.as_usize());
262 let old_len = out.len();
263 out.try_reserve(fill).map_err(|_| Error::OutOfMemory)?;
264 out.resize(old_len + fill, 0);
265 let plain = &mut out[old_len..];
266 let decoded = self
267 .read_prefix(payload, orig_size)
268 .and_then(|head| self.decode_body(payload, &head, plain).map(|()| head));
269 Ok(match decoded {
270 Ok(head) if check_crc(plain, &head).is_ok() => BlockStatus::Intact,
271 Ok(_) => BlockStatus::BadChecksum,
272 Err(fault) => {
273 plain.fill(0);
274 BlockStatus::Zeroed(fault)
275 }
276 })
277 }
278
279 pub fn decode_block_to(
326 &mut self,
327 payload: &[u8],
328 orig_size: u32,
329 out: &mut [u8],
330 ) -> Result<()> {
331 let head = self.read_prefix(payload, orig_size)?;
332 if out.len() != head.original_len {
333 return Err(Error::OutputSizeMismatch);
334 }
335 self.decode_payload(payload, &head, out)
336 }
337
338 fn read_prefix(&self, payload: &[u8], orig_size: u32) -> Result<PayloadPrefix> {
340 let block = self.block_size.as_usize();
341 let limit = crate::compress_bound(block);
344 if limit < payload.len() {
345 return Err(Error::BufferTooSmall);
346 }
347 let Some(prefix) = payload.get(..PREFIX_LEN) else {
348 return Err(Error::TruncatedHeader);
349 };
350 let crc = read_u32(prefix);
351 let bwt_index = read_i32(&prefix[4..]);
352 let original_len = usize::try_from(orig_size).unwrap_or(usize::MAX);
353 if original_len > block {
354 return Err(Error::InvalidHeader);
355 }
356 Ok(PayloadPrefix {
357 original_len,
358 crc,
359 bwt_index,
360 limit,
361 })
362 }
363
364 #[inline]
366 fn decode_payload(
367 &mut self,
368 payload: &[u8],
369 head: &PayloadPrefix,
370 out: &mut [u8],
371 ) -> Result<()> {
372 self.decode_body(payload, head, out)?;
373 check_crc(out, head)
374 }
375
376 #[inline]
380 fn decode_body(&mut self, payload: &[u8], head: &PayloadPrefix, out: &mut [u8]) -> Result<()> {
381 if head.bwt_index == STORED_MARKER {
382 return decode_stored(payload, head, out);
383 }
384 self.decode_stages(payload, head, out)
385 }
386
387 fn decode_stages(
394 &mut self,
395 payload: &[u8],
396 head: &PayloadPrefix,
397 out: &mut [u8],
398 ) -> Result<()> {
399 let PayloadPrefix {
400 original_len,
401 bwt_index,
402 limit,
403 ..
404 } = *head;
405 let Some(&raw) = payload.get(PREFIX_LEN) else {
406 return Err(Error::TruncatedHeader);
407 };
408 let model = Model(raw);
409 let header_len = model.header_len();
410 let Some(header) = payload.get(..header_len) else {
411 return Err(Error::TruncatedHeader);
412 };
413 let mut sizes = &header[PREFIX_LEN + MODEL_LEN..];
414 let lzp_size = if model.has_lzp() {
415 let size = read_stage_size(sizes, limit)?;
416 sizes = &sizes[4..];
417 Some(size)
418 } else {
419 None
420 };
421 let rle_size = if model.has_rle() {
422 Some(read_stage_size(sizes, limit)?)
423 } else {
424 None
425 };
426 let bwt_len = lzp_size.or(rle_size).unwrap_or(original_len);
427 let coded = &payload[header_len..];
428 self.decode_entropy(coded, bwt_len, bwt_index, model)?;
429 if usize::try_from(bwt_index).is_ok_and(|index| index > bwt_len) {
430 return Err(Error::InvalidHeader);
431 }
432
433 if !model.has_lzp() && !model.has_rle() {
436 sais::unbwt_with(
437 &self.buf_a[..bwt_len],
438 out,
439 bwt_index,
440 &mut self.unbwt_scratch,
441 )?;
442 } else {
443 sais::unbwt_with(
444 &self.buf_a[..bwt_len],
445 &mut self.buf_b[..bwt_len],
446 bwt_index,
447 &mut self.unbwt_scratch,
448 )?;
449 let mut current = &self.buf_b[..bwt_len];
450 if model.has_lzp() {
451 let size =
452 lzp::decode_into(current, &mut self.buf_a[..limit], &mut self.lzp_table)?;
453 current = &self.buf_a[..size];
454 }
455 if model.has_rle() {
456 rle::decode_into(current, out)?;
457 } else {
458 if current.len() != original_len {
459 return Err(Error::InvalidHeader);
460 }
461 out.copy_from_slice(current);
462 }
463 }
464 Ok(())
465 }
466
467 fn decode_entropy(
484 &mut self,
485 coded: &[u8],
486 bwt_len: usize,
487 bwt_index: i32,
488 model: Model,
489 ) -> Result<()> {
490 let filler = bwt_len
491 .saturating_mul(32)
492 .saturating_add(64)
493 .min(FILLER_CAP);
494 match self.coder.decode(coded, filler, &mut self.buf_a[..bwt_len]) {
495 Err(Error::TruncatedData) => {
496 let index = i64::from(bwt_index);
497 let span = i64::try_from(bwt_len).unwrap_or(i64::MAX);
498 if index > span {
499 return Err(Error::InvalidHeader);
500 }
501 if index < 1 {
502 return Err(Error::BwtFailed);
503 }
504 if model.has_lzp() && !model.has_rle() {
505 return Err(Error::InvalidHeader);
506 }
507 if model.has_rle() {
508 return Err(Error::CorruptStageData);
509 }
510 Err(Error::ChecksumMismatch)
511 }
512 outcome => outcome,
513 }
514 }
515}
516
517#[inline]
523fn check_crc(plain: &[u8], head: &PayloadPrefix) -> Result<()> {
524 if crc32::sum(1, plain) == head.crc {
525 Ok(())
526 } else {
527 Err(Error::ChecksumMismatch)
528 }
529}
530
531#[inline]
537fn read_stage_size(bytes: &[u8], limit: usize) -> Result<usize> {
538 usize::try_from(read_i32(bytes))
539 .ok()
540 .filter(|&size| size <= limit)
541 .ok_or(Error::InvalidHeader)
542}
543
544#[inline]
549fn decode_stored(payload: &[u8], head: &PayloadPrefix, out: &mut [u8]) -> Result<()> {
550 let original_len = head.original_len;
551 let Some(body) = payload.get(STORED_PREFIX_LEN..) else {
552 return Err(Error::TruncatedHeader);
553 };
554 if body.len() > STORED_MAX_BODY || body.len() != original_len {
555 return Err(Error::InvalidHeader);
556 }
557 out.copy_from_slice(body);
558 Ok(())
559}
560
561#[cfg(test)]
562mod tests {
563 use super::BlockDecoder;
564 use super::BlockStatus;
565 use super::decode_stored;
566 use crate::BlockSize;
567 use crate::block::BlockEncoder;
568 use crate::compress_bound;
569 use crate::error::Error;
570
571 fn small_decoder() -> BlockDecoder {
573 BlockDecoder::new(BlockSize::MIN).unwrap()
574 }
575
576 fn small_state() -> BlockEncoder {
578 BlockEncoder::new(BlockSize::MIN).unwrap()
579 }
580
581 #[test]
582 fn decoder_restores_stored_blocks() {
583 let mut encoder = small_state();
584 let mut decoder = small_decoder();
585 let sixty_three = b"x".repeat(63);
586 for input in [b"A".as_slice(), b"".as_slice(), sixty_three.as_slice()] {
587 let payload = encoder.encode_block(input).unwrap();
588 let len = u32::try_from(input.len()).unwrap();
589 assert_eq!(decoder.decode_block(&payload, len).unwrap(), input);
590 }
591 }
592
593 #[test]
594 fn decoder_restores_every_model() {
595 let mut seed = 0x00C0_FFEE_u32;
596 let random: Vec<u8> = (0..1000)
597 .map(|_| {
598 seed = seed.wrapping_mul(1_103_515_245).wrapping_add(12_345);
599 u8::try_from((seed >> 16) & 0xFF).expect("masked byte fits")
600 })
601 .collect();
602 let phrase: Vec<u8> = (0..50_u8).collect();
603 let mut periodic = Vec::new();
604 for _ in 0..20 {
605 periodic.extend_from_slice(&phrase);
606 periodic.extend_from_slice(&phrase);
607 }
608 let inputs: Vec<Vec<u8>> = vec![
609 vec![b'A'; 1000],
610 periodic,
611 random,
612 [vec![b'B'; 300], (0..50_u8).collect::<Vec<u8>>().repeat(10)].concat(),
613 ];
614 let mut models = std::collections::HashSet::new();
615 for input in &inputs {
616 let payload = small_state().encode_block(input).unwrap();
617 models.insert(payload[8]);
618 let len = u32::try_from(input.len()).unwrap();
619 let got = small_decoder().decode_block(&payload, len).unwrap();
620 assert_eq!(&got, input);
621 }
622 assert!(models.contains(&0x04));
624 assert!(models.contains(&0x02));
625 assert!(models.contains(&0x00));
626 }
627
628 #[test]
629 fn decoder_enforces_check_order() {
630 let mut decoder = small_decoder();
631 let payload = small_state().encode_block(b"A").unwrap();
632 assert_eq!(decoder.decode_block(&payload, 1).unwrap(), b"A");
633 assert!(matches!(
635 decoder.decode_block(&payload[..4], 1),
636 Err(crate::error::Error::TruncatedHeader)
637 ));
638 assert!(matches!(
639 decoder.decode_block(&payload, 2),
640 Err(crate::error::Error::InvalidHeader)
641 ));
642 let mut big = payload.clone();
644 big.extend_from_slice(&[0; 64]);
645 assert!(matches!(
646 decoder.decode_block(&big, 65),
647 Err(crate::error::Error::InvalidHeader)
648 ));
649 let mut bad = payload.clone();
651 bad[8] ^= 0x01;
652 assert!(matches!(
653 decoder.decode_block(&bad, 1),
654 Err(crate::error::Error::ChecksumMismatch)
655 ));
656 assert!(matches!(
658 decoder.decode_block(&payload, 65 * 1024 + 1),
659 Err(crate::error::Error::InvalidHeader)
660 ));
661 }
662
663 #[test]
664 fn recover_keeps_bytes_on_checksum_fault() {
665 let data = [b'A'; 1000];
666 let mut decoder = small_decoder();
667 for input in [data.as_slice(), b"short".as_slice()] {
669 let mut payload = small_state().encode_block(input).unwrap();
670 payload[0] ^= 0x01;
671 let len = u32::try_from(input.len()).unwrap();
672 let mut out = b"head".to_vec();
673 let result = decoder.recover_block_into(&payload, len, &mut out);
674 assert!(matches!(result, Ok(BlockStatus::BadChecksum)));
675 assert_eq!(out[..4], *b"head");
676 assert_eq!(out[4..], *input);
677 }
678 }
679
680 #[test]
681 fn recover_writes_zeros_on_stage_fault() {
682 let payload = small_state().encode_block(&[b'A'; 1000]).unwrap();
683 let mut bad = payload.clone();
684 bad[13] ^= 0xFF;
685 let mut out = Vec::new();
686 let result = small_decoder().recover_block_into(&bad, 1000, &mut out);
687 assert!(matches!(
688 result,
689 Ok(BlockStatus::Zeroed(crate::error::Error::CorruptStageData))
690 ));
691 assert_eq!(out, vec![0_u8; 1000]);
692
693 let mut out = Vec::new();
695 let result = small_decoder().recover_block_into(&payload[..4], 10, &mut out);
696 assert!(matches!(
697 result,
698 Ok(BlockStatus::Zeroed(crate::error::Error::TruncatedHeader))
699 ));
700 assert_eq!(out, vec![0_u8; 10]);
701 let mut out = Vec::new();
702 let result = small_decoder().recover_block_into(&payload, u32::MAX, &mut out);
703 assert!(matches!(
704 result,
705 Ok(BlockStatus::Zeroed(crate::error::Error::InvalidHeader))
706 ));
707 assert_eq!(out.len(), BlockSize::MIN.as_usize());
708
709 let mut bad = payload.clone();
711 bad[4..8].copy_from_slice(&i32::MAX.to_le_bytes());
712 let mut out = Vec::new();
713 let result = small_decoder().recover_block_into(&bad, 1000, &mut out);
714 assert!(matches!(
715 result,
716 Ok(BlockStatus::Zeroed(crate::error::Error::InvalidHeader))
717 ));
718 assert_eq!(out, vec![0_u8; 1000]);
719 }
720
721 #[test]
722 fn recover_matches_decode_on_good_blocks() {
723 let mut decoder = small_decoder();
724 for input in [b"A".as_slice(), &[b'B'; 1000], &[]] {
725 let payload = small_state().encode_block(input).unwrap();
726 let len = u32::try_from(input.len()).unwrap();
727 let mut out = Vec::new();
728 let result = decoder.recover_block_into(&payload, len, &mut out);
729 assert!(matches!(result, Ok(BlockStatus::Intact)));
730 assert_eq!(out, input);
731 }
732 }
733
734 #[test]
735 fn decoder_enforces_coded_check_order() {
736 let payload = small_state().encode_block(&[b'A'; 1000]).unwrap();
738 assert_eq!(payload[8] & 0x04, 0x04);
739 let mut decoder = small_decoder();
740 assert_eq!(decoder.decode_block(&payload, 1000).unwrap().len(), 1000);
741 let mut bad = payload.clone();
743 bad[9..13].copy_from_slice(&i32::MAX.to_le_bytes());
744 assert!(matches!(
745 decoder.decode_block(&bad, 1000),
746 Err(crate::error::Error::InvalidHeader)
747 ));
748 let mut bad = payload.clone();
750 bad[4..8].copy_from_slice(&i32::MAX.to_le_bytes());
751 let last = bad.len() - 1;
752 bad[last] ^= 0xFF;
753 assert!(matches!(
754 decoder.decode_block(&bad, 1000),
755 Err(crate::error::Error::InvalidHeader)
756 ));
757 let mut bad = payload.clone();
761 bad[13] ^= 0xFF;
762 assert!(matches!(
763 decoder.decode_block(&bad, 1000),
764 Err(crate::error::Error::CorruptStageData)
765 ));
766 }
767
768 #[test]
769 fn decoder_final_size_mismatch_is_malformed() {
770 let phrase: Vec<u8> = (0..50_u8).collect();
772 let mut input = Vec::new();
773 for _ in 0..4 {
774 input.extend_from_slice(&phrase);
775 }
776 let payload = small_state().encode_block(&input).unwrap();
777 assert_eq!(payload[8] & 0x06, 0x02);
778 let short = u32::try_from(input.len() - 1).unwrap();
779 assert!(matches!(
780 small_decoder().decode_block(&payload, short),
781 Err(crate::error::Error::InvalidHeader)
782 ));
783 }
784
785 #[test]
786 fn decoder_reuse_gives_identical_bytes() {
787 let payload = small_state().encode_block(&[b'A'; 1000]).unwrap();
788 let mut decoder = small_decoder();
789 let first = decoder.decode_block(&payload, 1000).unwrap();
790 let other = small_state().encode_block(&[b'B'; 500]).unwrap();
791 let _ = decoder.decode_block(&other, 500).unwrap();
792 let again = decoder.decode_block(&payload, 1000).unwrap();
793 assert_eq!(first, again);
794 }
795
796 #[test]
797 fn decoder_block_size_accessor_matches_constructor() {
798 assert_eq!(small_decoder().block_size(), BlockSize::MIN);
799 }
800
801 #[test]
802 fn debug_names_type_and_block_size() {
803 let encoder_text = format!("{:?}", small_state());
804 assert!(encoder_text.contains("BlockEncoder"));
805 assert!(encoder_text.contains("block_size"));
806 let decoder_text = format!("{:?}", small_decoder());
807 assert!(decoder_text.contains("BlockDecoder"));
808 assert!(decoder_text.contains("block_size"));
809 }
810
811 #[test]
812 fn decode_block_to_rejects_wrong_output_length() {
813 let data = [b'A'; 1000];
814 let payload = small_state().encode_block(&data).unwrap();
815 let mut exact = vec![0_u8; data.len()];
816 small_decoder()
817 .decode_block_to(&payload, 1000, &mut exact)
818 .unwrap();
819 assert_eq!(exact, data);
820 for len in [0, data.len() - 1, data.len() + 1] {
821 let mut out = vec![0_u8; len];
822 assert!(matches!(
823 small_decoder().decode_block_to(&payload, 1000, &mut out),
824 Err(Error::OutputSizeMismatch)
825 ));
826 }
827 }
828
829 #[test]
830 fn oversize_payload_fails_buffer_too_small() {
831 let limit = compress_bound(BlockSize::MIN.as_usize());
832 let big = vec![0_u8; limit + 1];
833 assert!(matches!(
834 small_decoder().decode_block(&big, 1),
835 Err(Error::BufferTooSmall)
836 ));
837 let mut out = Vec::new();
838 assert!(matches!(
839 small_decoder().recover_block_into(&big, 1, &mut out),
840 Ok(BlockStatus::Zeroed(Error::BufferTooSmall))
841 ));
842 }
843
844 #[test]
845 fn eight_byte_prefix_fails_truncated_header() {
846 let mut payload = vec![0_u8; 8];
848 payload[4..8].copy_from_slice(&0_i32.to_le_bytes());
849 assert!(matches!(
850 small_decoder().decode_block(&payload, 100),
851 Err(Error::TruncatedHeader)
852 ));
853 }
854
855 #[test]
856 fn short_stage_header_fails_truncated_header() {
857 for model in [0x02_u8, 0x04_u8] {
859 let mut payload = vec![0_u8; 9];
860 payload[4..8].copy_from_slice(&0_i32.to_le_bytes());
861 payload[8] = model;
862 assert!(matches!(
863 small_decoder().decode_block(&payload, 100),
864 Err(Error::TruncatedHeader)
865 ));
866 }
867 }
868
869 #[test]
870 fn stored_prefix_short_fails_truncated_header() {
871 let head = crate::block::PayloadPrefix {
874 original_len: 4,
875 crc: 0,
876 bwt_index: -1,
877 limit: 64,
878 };
879 let mut out = [0_u8; 4];
880 assert!(matches!(
881 decode_stored(&[0_u8; 4], &head, &mut out),
882 Err(Error::TruncatedHeader)
883 ));
884 }
885}