Skip to content

Commit b99a8b9

Browse files
authored
Add decode_all and decode_all_to_vec (#70)
1 parent 603ee2d commit b99a8b9

File tree

2 files changed

+173
-0
lines changed

2 files changed

+173
-0
lines changed

src/frame_decoder.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ pub enum FrameDecoderError {
102102
NotYetInitialized,
103103
FailedToInitialize(frame::FrameHeaderError),
104104
FailedToDrainDecodebuffer(Error),
105+
FailedToSkipFrame,
105106
TargetTooSmall,
106107
DictNotProvided { dict_id: u32 },
107108
}
@@ -164,6 +165,12 @@ impl core::fmt::Display for FrameDecoderError {
164165
e,
165166
)
166167
}
168+
FrameDecoderError::FailedToSkipFrame => {
169+
write!(
170+
f,
171+
"Failed to skip bytes for the length given in the frame header"
172+
)
173+
}
167174
FrameDecoderError::TargetTooSmall => {
168175
write!(f, "Target must have at least as many bytes as the contentsize of the frame reports")
169176
}
@@ -605,6 +612,87 @@ impl FrameDecoder {
605612
let read_len = bytes_read_at_end - bytes_read_at_start;
606613
Ok((read_len as usize, result_len))
607614
}
615+
616+
/// Decode multiple frames into the output slice.
617+
///
618+
/// `input` must contain an exact number of frames.
619+
///
620+
/// `output` must be large enough to hold the decompressed data. If you don't know
621+
/// how large the output will be, use [`FrameDecoder::decode_blocks`] instead.
622+
///
623+
/// This calls [`FrameDecoder::init`], and all bytes currently in the decoder will be lost.
624+
///
625+
/// Returns the number of bytes written to `output`.
626+
pub fn decode_all(
627+
&mut self,
628+
mut input: &[u8],
629+
mut output: &mut [u8],
630+
) -> Result<usize, FrameDecoderError> {
631+
let mut total_bytes_written = 0;
632+
while !input.is_empty() {
633+
match self.init(&mut input) {
634+
Ok(_) => {}
635+
Err(FrameDecoderError::ReadFrameHeaderError(
636+
frame::ReadFrameHeaderError::SkipFrame { length, .. },
637+
)) => {
638+
input = input
639+
.get(length as usize..)
640+
.ok_or(FrameDecoderError::FailedToSkipFrame)?;
641+
continue;
642+
}
643+
Err(e) => return Err(e),
644+
};
645+
loop {
646+
self.decode_blocks(&mut input, BlockDecodingStrategy::UptoBlocks(1))?;
647+
let bytes_written = self
648+
.read(output)
649+
.map_err(FrameDecoderError::FailedToDrainDecodebuffer)?;
650+
output = &mut output[bytes_written..];
651+
total_bytes_written += bytes_written;
652+
if self.can_collect() != 0 {
653+
return Err(FrameDecoderError::TargetTooSmall);
654+
}
655+
if self.is_finished() {
656+
break;
657+
}
658+
}
659+
}
660+
661+
Ok(total_bytes_written)
662+
}
663+
664+
/// Decode multiple frames into the extra capacity of the output vector.
665+
///
666+
/// `input` must contain an exact number of frames.
667+
///
668+
/// `output` must have enough extra capacity to hold the decompressed data.
669+
/// This function will not reallocate or grow the vector. If you don't know
670+
/// how large the output will be, use [`FrameDecoder::decode_blocks`] instead.
671+
///
672+
/// This calls [`FrameDecoder::init`], and all bytes currently in the decoder will be lost.
673+
///
674+
/// The length of the output vector is updated to include the decompressed data.
675+
/// The length is not changed if an error occurs.
676+
pub fn decode_all_to_vec(
677+
&mut self,
678+
input: &[u8],
679+
output: &mut Vec<u8>,
680+
) -> Result<(), FrameDecoderError> {
681+
let len = output.len();
682+
let cap = output.capacity();
683+
output.resize(cap, 0);
684+
match self.decode_all(input, &mut output[len..]) {
685+
Ok(bytes_written) => {
686+
let new_len = core::cmp::min(len + bytes_written, cap); // Sanitizes `bytes_written`.
687+
output.resize(new_len, 0);
688+
Ok(())
689+
}
690+
Err(e) => {
691+
output.resize(len, 0);
692+
Err(e)
693+
}
694+
}
695+
}
608696
}
609697

610698
/// Read bytes from the decode_buffer that are no longer needed. While the frame is not yet finished

src/tests/mod.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,91 @@ fn test_streaming_no_std() {
481481
}
482482
}
483483

484+
#[test]
485+
fn test_decode_all() {
486+
use crate::frame_decoder::{FrameDecoder, FrameDecoderError};
487+
488+
let skip_frame = |input: &mut Vec<u8>, length: usize| {
489+
input.extend_from_slice(&0x184D2A50u32.to_le_bytes());
490+
input.extend_from_slice(&(length as u32).to_le_bytes());
491+
input.resize(input.len() + length, 0);
492+
};
493+
494+
let mut original = Vec::new();
495+
let mut input = Vec::new();
496+
497+
skip_frame(&mut input, 300);
498+
input.extend_from_slice(include_bytes!("../../decodecorpus_files/z000089.zst"));
499+
original.extend_from_slice(include_bytes!("../../decodecorpus_files/z000089"));
500+
skip_frame(&mut input, 400);
501+
input.extend_from_slice(include_bytes!("../../decodecorpus_files/z000090.zst"));
502+
original.extend_from_slice(include_bytes!("../../decodecorpus_files/z000090"));
503+
skip_frame(&mut input, 500);
504+
505+
let mut decoder = FrameDecoder::new();
506+
507+
// decode_all with correct buffers.
508+
let mut output = vec![0; original.len()];
509+
let result = decoder.decode_all(&input, &mut output).unwrap();
510+
assert_eq!(result, original.len());
511+
assert_eq!(output, original);
512+
513+
// decode_all with smaller output length.
514+
let mut output = vec![0; original.len() - 1];
515+
let result = decoder.decode_all(&input, &mut output);
516+
assert!(
517+
matches!(result, Err(FrameDecoderError::TargetTooSmall)),
518+
"{:?}",
519+
result
520+
);
521+
522+
// decode_all with larger output length.
523+
let mut output = vec![0; original.len() + 1];
524+
let result = decoder.decode_all(&input, &mut output).unwrap();
525+
assert_eq!(result, original.len());
526+
assert_eq!(&output[..result], original);
527+
528+
// decode_all with truncated regular frame.
529+
let mut output = vec![0; original.len()];
530+
let result = decoder.decode_all(&input[..input.len() - 600], &mut output);
531+
assert!(
532+
matches!(result, Err(FrameDecoderError::FailedToReadBlockBody(_))),
533+
"{:?}",
534+
result
535+
);
536+
537+
// decode_all with truncated skip frame.
538+
let mut output = vec![0; original.len()];
539+
let result = decoder.decode_all(&input[..input.len() - 1], &mut output);
540+
assert!(
541+
matches!(result, Err(FrameDecoderError::FailedToSkipFrame)),
542+
"{:?}",
543+
result
544+
);
545+
546+
// decode_all_to_vec with correct output capacity.
547+
let mut output = Vec::new();
548+
output.reserve_exact(original.len());
549+
decoder.decode_all_to_vec(&input, &mut output).unwrap();
550+
assert_eq!(output, original);
551+
552+
// decode_all_to_vec with smaller output capacity.
553+
let mut output = Vec::new();
554+
output.reserve_exact(original.len() - 1);
555+
let result = decoder.decode_all_to_vec(&input, &mut output);
556+
assert!(
557+
matches!(result, Err(FrameDecoderError::TargetTooSmall)),
558+
"{:?}",
559+
result
560+
);
561+
562+
// decode_all_to_vec with larger output capacity.
563+
let mut output = Vec::new();
564+
output.reserve_exact(original.len() + 1);
565+
decoder.decode_all_to_vec(&input, &mut output).unwrap();
566+
assert_eq!(output, original);
567+
}
568+
484569
pub mod bit_reader;
485570
pub mod decode_corpus;
486571
pub mod dict_test;

0 commit comments

Comments
 (0)