Skip to content

Commit

Permalink
Merge pull request #59 from Sorseg/document-multi-segment
Browse files Browse the repository at this point in the history
Document how to deal with multi-segment streams
  • Loading branch information
KillingSpark committed Apr 1, 2024
2 parents b64ad31 + 729e5df commit 29a6566
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 12 deletions.
8 changes: 4 additions & 4 deletions src/bin/zstd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ fn main() {

while tracker.file_pos < tracker.file_size {
match frame_dec.reset(&mut f) {
Err(FrameDecoderError::ReadFrameHeaderError(ReadFrameHeaderError::SkipFrame(
magic_num,
skip_size,
))) => {
Err(FrameDecoderError::ReadFrameHeaderError(ReadFrameHeaderError::SkipFrame {
magic_number: magic_num,
length: skip_size,
})) => {
eprintln!("Found a skippable frame with magic number: {magic_num} and size: {skip_size}");
tracker.file_pos = f.stream_position().unwrap();
tracker.file_pos += skip_size as u64;
Expand Down
11 changes: 8 additions & 3 deletions src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,10 @@ pub enum ReadFrameHeaderError {
DictionaryIdReadError(Error),
#[display(fmt = "Error while reading frame content size: {_0}")]
FrameContentSizeReadError(Error),
#[display(fmt = "SkippableFrame encountered with MagicNumber 0x{_0:X} and length {_1} bytes")]
SkipFrame(u32, u32),
#[display(
fmt = "SkippableFrame encountered with MagicNumber 0x{magic_number:X} and length {length} bytes"
)]
SkipFrame { magic_number: u32, length: u32 },
}

pub fn read_frame_header(mut r: impl Read) -> Result<(Frame, u8), ReadFrameHeaderError> {
Expand All @@ -171,7 +173,10 @@ pub fn read_frame_header(mut r: impl Read) -> Result<(Frame, u8), ReadFrameHeade
r.read_exact(&mut buf)
.map_err(err::FrameDescriptorReadError)?;
let skip_size = u32::from_le_bytes(buf);
return Err(ReadFrameHeaderError::SkipFrame(magic_num, skip_size));
return Err(ReadFrameHeaderError::SkipFrame {
magic_number: magic_num,
length: skip_size,
});
}

if magic_num != MAGIC_NUM {
Expand Down
8 changes: 8 additions & 0 deletions src/streaming_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ use crate::io::{Error, ErrorKind, Read};
///
/// The lower level FrameDecoder by comparison allows for finer grained control but need sto have it's decode_blocks method called continously
/// to decode the zstd-frame.
///
/// ## Caveat
/// [StreamingDecoder] expects the underlying stream to only contain a single frame.
/// To decode all the frames in a finite stream, the calling code needs to recreate
/// the instance of the decoder
/// and handle
/// [crate::frame::ReadFrameHeaderError::SkipFrame]
/// errors by skipping forward the `length` amount of bytes, see <https://github.com/KillingSpark/zstd-rs/issues/57>
pub struct StreamingDecoder<READ: Read, DEC: BorrowMut<FrameDecoder>> {
pub decoder: DEC,
source: READ,
Expand Down
13 changes: 8 additions & 5 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ fn skippable_frame() {
let err = frame::read_frame_header(content.as_slice());
assert!(matches!(
err,
Err(frame::ReadFrameHeaderError::SkipFrame(0x184D2A50u32, 300))
Err(frame::ReadFrameHeaderError::SkipFrame {
magic_number: 0x184D2A50u32,
length: 300
})
));

content.clear();
Expand All @@ -65,10 +68,10 @@ fn skippable_frame() {
let err = frame::read_frame_header(content.as_slice());
assert!(matches!(
err,
Err(frame::ReadFrameHeaderError::SkipFrame(
0x184D2A5Fu32,
0xFFFFFFFF
))
Err(frame::ReadFrameHeaderError::SkipFrame {
magic_number: 0x184D2A5Fu32,
length: 0xFFFFFFFF
})
));
}

Expand Down

0 comments on commit 29a6566

Please sign in to comment.