use core::borrow::BorrowMut;
use crate::common::MAX_BLOCK_SIZE;
use crate::decoding::errors::{FrameDecoderError, ReadFrameHeaderError};
use crate::decoding::{BlockDecodingStrategy, DictionaryHandle, FrameDecoder};
use crate::io::{Error, ErrorKind, Read};
pub struct StreamingDecoder<READ: Read, DEC: BorrowMut<FrameDecoder>> {
pub decoder: DEC,
source: READ,
forced_dictionary: bool,
exhausted: bool,
input: Input,
}
const SKIP_CHUNK: u32 = 8 * 1024;
struct Input {
buf: alloc::vec::Vec<u8>,
start: usize,
end: usize,
skip_left: u32,
raw: Option<RawBlock>,
}
struct RawBlock {
size: u32,
left: u32,
last: bool,
#[cfg(all(feature = "lsm", feature = "hash"))]
digest: Option<twox_hash::XxHash64>,
}
const RAW_CHUNK: usize = 32 * 1024;
impl Input {
const fn new() -> Self {
Self {
buf: alloc::vec::Vec::new(),
start: 0,
end: 0,
skip_left: 0,
raw: None,
}
}
fn pending(&self) -> &[u8] {
&self.buf[self.start..self.end]
}
fn read_rest<R: Read>(&mut self, source: &mut R) -> Result<(), Error> {
if self.start > 0 {
self.buf.copy_within(self.start..self.end, 0);
self.end -= self.start;
self.start = 0;
}
self.buf.truncate(self.end);
let result = source.read_to_end(&mut self.buf);
self.end = self.buf.len();
result.map(drop)
}
fn read_raw<R: Read>(&mut self, source: &mut R, left: u32) -> Result<usize, Error> {
debug_assert!(
self.pending().is_empty(),
"a Raw block is read with nothing pending"
);
let chunk = left.min(RAW_CHUNK as u32) as usize;
if self.buf.len() < chunk {
self.buf.resize(chunk, 0);
}
loop {
match source.read(&mut self.buf[..chunk]) {
Err(e) if e.kind() == ErrorKind::Interrupted => {}
other => return other,
}
}
}
fn release(&mut self) {
self.buf = alloc::vec::Vec::new();
self.start = 0;
self.end = 0;
}
fn consume(&mut self, n: usize) {
debug_assert!(n <= self.end - self.start);
self.start += n;
if self.start == self.end {
self.start = 0;
self.end = 0;
}
}
fn fill<R: Read>(&mut self, source: &mut R, want: usize) -> Result<usize, Error> {
if self.start > 0 {
self.buf.copy_within(self.start..self.end, 0);
self.end -= self.start;
self.start = 0;
}
debug_assert!(self.end < want, "a fill must ask for more than is pending");
if self.buf.len() < want {
let len = want.max(2 * self.buf.len());
self.buf.resize(len, 0);
}
loop {
match source.read(&mut self.buf[self.end..want]) {
Ok(n) => {
self.end += n;
return Ok(n);
}
Err(e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
}
}
fn header_len(bytes: &[u8], magicless: bool) -> usize {
let descriptor_at = if magicless {
0
} else {
let Some(magic) = bytes.first_chunk::<4>() else {
return 4;
};
let magic = u32::from_le_bytes(*magic);
if magic & 0xFFFF_FFF0 == 0x184D_2A50 {
return 8;
}
if magic != crate::common::MAGIC_NUM {
return 4;
}
4
};
let Some(&descriptor) = bytes.get(descriptor_at) else {
return descriptor_at + 1;
};
let descriptor = crate::decoding::frame::FrameDescriptor(descriptor);
let window = usize::from(!descriptor.single_segment_flag());
let dict = descriptor.dictionary_id_bytes().map_or(0, usize::from);
let fcs = descriptor.frame_content_size_bytes().map_or(0, usize::from);
descriptor_at + 1 + window + dict + fcs
}
impl<READ: Read, DEC: BorrowMut<FrameDecoder>> StreamingDecoder<READ, DEC> {
pub fn new_with_decoder(
mut source: READ,
mut decoder: DEC,
) -> Result<StreamingDecoder<READ, DEC>, FrameDecoderError> {
let started = start_first_frame(decoder.borrow_mut(), &mut source, FrameStart::Plain)?;
Ok(StreamingDecoder {
decoder,
source,
forced_dictionary: false,
exhausted: !started,
input: Input::new(),
})
}
pub fn new_with_decoder_and_dictionary_handle(
mut source: READ,
mut decoder: DEC,
dict: &DictionaryHandle,
) -> Result<StreamingDecoder<READ, DEC>, FrameDecoderError> {
let started = start_first_frame(
decoder.borrow_mut(),
&mut source,
FrameStart::Dictionary(dict),
)?;
Ok(StreamingDecoder {
decoder,
source,
forced_dictionary: true,
exhausted: !started,
input: Input::new(),
})
}
}
impl<READ: Read> StreamingDecoder<READ, FrameDecoder> {
pub fn new(
mut source: READ,
) -> Result<StreamingDecoder<READ, FrameDecoder>, FrameDecoderError> {
let mut decoder = FrameDecoder::new();
let started = start_first_frame(&mut decoder, &mut source, FrameStart::Plain)?;
Ok(StreamingDecoder {
decoder,
source,
forced_dictionary: false,
exhausted: !started,
input: Input::new(),
})
}
pub fn new_with_dictionary_handle(
source: READ,
dict: &DictionaryHandle,
) -> Result<StreamingDecoder<READ, FrameDecoder>, FrameDecoderError> {
Self::new_with_decoder_and_dictionary_handle(source, FrameDecoder::new(), dict)
}
pub fn new_with_dictionary_bytes(
source: READ,
raw_dictionary: &[u8],
) -> Result<StreamingDecoder<READ, FrameDecoder>, FrameDecoderError> {
let dict = DictionaryHandle::decode_dict(raw_dictionary)?;
Self::new_with_dictionary_handle(source, &dict)
}
}
impl<READ: Read, DEC: BorrowMut<FrameDecoder>> StreamingDecoder<READ, DEC> {
pub fn get_ref(&self) -> &READ {
&self.source
}
pub fn get_mut(&mut self) -> &mut READ {
&mut self.source
}
pub fn decoder_mut(&mut self) -> &mut FrameDecoder {
self.decoder.borrow_mut()
}
pub fn into_inner(self) -> READ
where
READ: Sized,
{
self.source
}
pub fn into_parts(self) -> (READ, DEC)
where
READ: Sized,
{
(self.source, self.decoder)
}
pub fn into_frame_decoder(self) -> DEC {
self.decoder
}
fn cut_short(&mut self) -> Error {
let decoder = self.decoder.borrow_mut();
if decoder.awaits_checksum() {
return frame_error(FrameDecoderError::FailedToReadChecksum(Error::from(
ErrorKind::UnexpectedEof,
)));
}
let mut rest = self.input.pending();
decoder
.decode_blocks(&mut rest, BlockDecodingStrategy::All)
.map_or_else(frame_error, |_| Error::from(ErrorKind::UnexpectedEof))
}
fn start_next_frame(&mut self) -> Result<bool, Error> {
let how = if self.forced_dictionary {
FrameStart::HeldDictionary
} else {
FrameStart::Plain
};
let magicless = self.decoder.borrow_mut().is_magicless();
loop {
while self.input.skip_left > 0 {
let step = self.input.skip_left.min(SKIP_CHUNK);
if self.input.pending().is_empty()
&& self.input.fill(&mut self.source, step as usize)? == 0
{
return Err(frame_error(FrameDecoderError::FailedToSkipFrame));
}
let pending = u32::try_from(self.input.pending().len()).unwrap_or(u32::MAX);
let take = self.input.skip_left.min(pending);
self.input.consume(take as usize);
self.input.skip_left -= take;
}
loop {
let have = self.input.pending().len();
let want = header_len(self.input.pending(), magicless);
if have >= want {
break;
}
if self.input.fill(&mut self.source, want)? == 0 {
if have == 0 {
return Ok(false);
}
break;
}
}
let mut header = self.input.pending();
let before = header.len();
let started = how.start(self.decoder.borrow_mut(), &mut header);
let used = before - header.len();
self.input.consume(used);
match started {
Ok(()) => return Ok(true),
Err(e) => match skippable_frame_length(&e) {
Some(length) => self.input.skip_left = length,
None => return Err(frame_error(e)),
},
}
}
}
}
struct Prefixed<'a, R: Read> {
first: Option<u8>,
inner: &'a mut R,
}
impl<R: Read> Read for Prefixed<'_, R> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
match (self.first.take(), buf.first_mut()) {
(Some(byte), Some(slot)) => {
*slot = byte;
Ok(1)
}
(byte, _) => {
self.first = byte;
self.inner.read(buf)
}
}
}
}
fn skippable_frame_length(e: &FrameDecoderError) -> Option<u32> {
match e {
FrameDecoderError::ReadFrameHeaderError(ReadFrameHeaderError::SkipFrame {
length, ..
}) => Some(*length),
_ => None,
}
}
fn skip_frame_content<R: Read>(source: &mut R, length: u32) -> Result<(), FrameDecoderError> {
let mut left = length;
if left == 0 {
return Ok(());
}
let mut scratch = alloc::vec![0u8; left.min(SKIP_CHUNK) as usize];
while left > 0 {
let take = left.min(scratch.len() as u32) as usize;
match source.read(&mut scratch[..take]) {
Ok(0) => return Err(FrameDecoderError::FailedToSkipFrame),
Ok(n) => left -= n as u32,
Err(e) if e.kind() == crate::io::ErrorKind::Interrupted => {}
Err(e) => return Err(FrameDecoderError::FailedToReadSkippableFrame(e)),
}
}
Ok(())
}
enum FrameStart<'d> {
Plain,
Dictionary(&'d DictionaryHandle),
HeldDictionary,
}
impl FrameStart<'_> {
fn start(
&self,
decoder: &mut FrameDecoder,
source: impl Read,
) -> Result<(), FrameDecoderError> {
match self {
Self::Plain => decoder.init(source),
Self::Dictionary(dict) => decoder.init_with_dict_handle(source, dict),
Self::HeldDictionary => decoder.reset_with_active_dict(source),
}
}
}
fn start_first_frame<R: Read>(
decoder: &mut FrameDecoder,
source: &mut R,
how: FrameStart<'_>,
) -> Result<bool, FrameDecoderError> {
let mut started = how.start(decoder, &mut *source);
loop {
let length = match started {
Ok(()) => return Ok(true),
Err(e) => skippable_frame_length(&e).ok_or(e)?,
};
skip_frame_content(source, length)?;
let mut probe = [0u8; 1];
let n = read_at_boundary(source, &mut probe).map_err(|e| {
FrameDecoderError::ReadFrameHeaderError(ReadFrameHeaderError::MagicNumberReadError(e))
})?;
if n == 0 {
return Ok(false);
}
started = how.start(
decoder,
Prefixed {
first: Some(probe[0]),
inner: source,
},
);
}
}
fn read_at_boundary<R: Read>(source: &mut R, probe: &mut [u8; 1]) -> Result<usize, Error> {
loop {
match source.read(probe) {
Err(e) if e.kind() == crate::io::ErrorKind::Interrupted => {}
other => return other,
}
}
}
fn finish_raw_block(decoder: &mut FrameDecoder, raw: RawBlock) {
#[cfg(all(feature = "lsm", feature = "hash"))]
if let Some(digest) = raw.digest {
decoder.record_block_checksum(core::hash::Hasher::finish(&digest) as u32);
}
decoder.finish_raw_block(raw.size, raw.last);
}
fn frame_error(e: FrameDecoderError) -> Error {
#[cfg(feature = "std")]
return Error::other(e);
#[cfg(not(feature = "std"))]
return Error::new(ErrorKind::Other, alloc::boxed::Box::new(e));
}
fn verify_finished_frame(decoder: &FrameDecoder) -> Result<(), Error> {
decoder.verify_content_size().map_err(frame_error)?;
#[cfg(feature = "hash")]
decoder.verify_content_checksum().map_err(frame_error)?;
Ok(())
}
impl<READ: Read, DEC: BorrowMut<FrameDecoder>> Read for StreamingDecoder<READ, DEC> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
if buf.is_empty() || self.exhausted {
return Ok(0);
}
let mut written = 0;
loop {
let decoder = self.decoder.borrow_mut();
if decoder.is_finished() && decoder.can_collect() == 0 {
if written > 0 {
return Ok(written);
}
verify_finished_frame(decoder)?;
if !self.start_next_frame()? {
self.exhausted = true;
return Ok(0);
}
continue;
}
if written == buf.len() {
return Ok(written);
}
if self.input.raw.is_some() && decoder.can_collect() == 0 {
if written > 0 {
return Ok(written);
}
let left = self.input.raw.as_ref().map_or(0, |raw| raw.left);
let n = self.input.read_raw(&mut self.source, left)?;
let mut raw = self.input.raw.take().expect("checked just above");
if n == 0 {
return Err(frame_error(decoder.raw_block_cut_short(raw.size, raw.last)));
}
let content = &self.input.buf[..n];
decoder.raw_block_push(content);
#[cfg(all(feature = "lsm", feature = "hash"))]
if let Some(digest) = raw.digest.as_mut() {
core::hash::Hasher::write(digest, content);
}
raw.left -= n as u32;
if raw.left == 0 {
finish_raw_block(decoder, raw);
} else {
self.input.raw = Some(raw);
}
continue;
}
let want = decoder.input_needed(self.input.pending());
if self.input.raw.is_none()
&& want > self.input.pending().len()
&& decoder.can_collect() == 0
{
if written > 0 {
return Ok(written);
}
if let Some(&header) = self.input.pending().first_chunk::<3>()
&& self.input.pending().len() == 3
&& let Some((size, last)) = decoder
.start_raw_block(&header, true)
.map_err(frame_error)?
{
self.input.consume(3);
let raw = RawBlock {
size,
left: size,
last,
#[cfg(all(feature = "lsm", feature = "hash"))]
digest: decoder
.per_block_checksums_enabled()
.then(|| twox_hash::XxHash64::with_seed(0)),
};
if size == 0 {
finish_raw_block(decoder, raw);
} else {
self.input.raw = Some(raw);
}
continue;
}
if self.input.fill(&mut self.source, want)? == 0 {
return Err(self.cut_short());
}
continue;
}
let (consumed, produced) = decoder
.decode_available(self.input.pending(), &mut buf[written..], true)
.map_err(frame_error)?;
self.input.consume(consumed);
written += produced;
if consumed > 0 || produced > 0 {
continue;
}
if written > 0 {
return Ok(written);
}
return Err(self.cut_short());
}
}
#[cfg(feature = "std")]
fn read_to_end(&mut self, output: &mut alloc::vec::Vec<u8>) -> Result<usize, Error> {
let start_total = output.len();
if self.exhausted {
return Ok(0);
}
let at_start = self.input.raw.is_none() && {
let d = self.decoder.borrow_mut();
d.is_at_frame_start() && d.can_collect() == 0
};
let keep_dictionary = self.forced_dictionary;
if at_start {
self.input.read_rest(&mut self.source)?;
let decoded = self.decoder.borrow_mut().decode_current_frame_to_vec(
self.input.pending(),
output,
keep_dictionary,
);
self.input.release();
decoded.map_err(Error::other)?;
return Ok(output.len() - start_total);
}
loop {
let start = output.len();
output.resize(start + MAX_BLOCK_SIZE as usize, 0);
let n = match self.read(&mut output[start..]) {
Ok(n) => n,
Err(e) => {
output.truncate(start);
return Err(e);
}
};
output.truncate(start + n);
if n == 0 {
break;
}
}
Ok(output.len() - start_total)
}
#[cfg(not(feature = "std"))]
fn read_to_end(&mut self, output: &mut alloc::vec::Vec<u8>) -> Result<(), Error> {
if self.exhausted {
return Ok(());
}
let at_start = self.input.raw.is_none() && {
let d = self.decoder.borrow_mut();
d.is_at_frame_start() && d.can_collect() == 0
};
let keep_dictionary = self.forced_dictionary;
if at_start {
self.input.read_rest(&mut self.source)?;
let decoded = self.decoder.borrow_mut().decode_current_frame_to_vec(
self.input.pending(),
output,
keep_dictionary,
);
self.input.release();
decoded.map_err(|e| Error::new(ErrorKind::Other, alloc::boxed::Box::new(e)))?;
return Ok(());
}
loop {
let start = output.len();
output.resize(start + MAX_BLOCK_SIZE as usize, 0);
let n = match self.read(&mut output[start..]) {
Ok(n) => n,
Err(e) => {
output.truncate(start);
return Err(e);
}
};
output.truncate(start + n);
if n == 0 {
break;
}
}
Ok(())
}
}
#[cfg(test)]
mod tests;