use crate::common::{MAGIC_NUM, MAX_WINDOW_SIZE, MIN_WINDOW_SIZE};
use crate::decoding::errors::{FrameDescriptorError, FrameHeaderError, ReadFrameHeaderError};
use crate::io::Read;
#[cfg(test)]
pub(crate) fn read_frame_header(r: impl Read) -> Result<(FrameHeader, u8), ReadFrameHeaderError> {
read_frame_header_with_format(r, false)
}
#[inline]
pub fn read_frame_header_with_format(
mut r: impl Read,
magicless: bool,
) -> Result<(FrameHeader, u8), ReadFrameHeaderError> {
use ReadFrameHeaderError as err;
let mut buf = [0u8; 4];
let mut bytes_read = 0;
if !magicless {
r.read_exact(&mut buf).map_err(err::MagicNumberReadError)?;
bytes_read = 4;
let magic_num = u32::from_le_bytes(buf);
if (0x184D2A50..=0x184D2A5F).contains(&magic_num) {
r.read_exact(&mut buf)
.map_err(err::FrameDescriptorReadError)?;
let skip_size = u32::from_le_bytes(buf);
return Err(ReadFrameHeaderError::SkipFrame {
magic_number: magic_num,
length: skip_size,
});
}
if magic_num != MAGIC_NUM {
return Err(ReadFrameHeaderError::BadMagicNumber(magic_num));
}
}
r.read_exact(&mut buf[0..1])
.map_err(err::FrameDescriptorReadError)?;
let desc = FrameDescriptor(buf[0]);
bytes_read += 1;
let mut frame_header = FrameHeader {
descriptor: FrameDescriptor(desc.0),
dict_id: None,
frame_content_size: 0,
window_descriptor: 0,
};
if !desc.single_segment_flag() {
r.read_exact(&mut buf[0..1])
.map_err(err::WindowDescriptorReadError)?;
frame_header.window_descriptor = buf[0];
bytes_read += 1;
}
let dict_id_len = desc.dictionary_id_bytes()? as usize;
if dict_id_len != 0 {
let buf = &mut buf[..dict_id_len];
r.read_exact(buf).map_err(err::DictionaryIdReadError)?;
bytes_read += dict_id_len;
let mut dict_id = 0u32;
for (i, &b) in buf.iter().enumerate() {
dict_id += (b as u32) << (8 * i);
}
if dict_id != 0 {
frame_header.dict_id = Some(dict_id);
}
}
let fcs_len = desc.frame_content_size_bytes()? as usize;
if fcs_len != 0 {
let mut fcs_buf = [0u8; 8];
let fcs_buf = &mut fcs_buf[..fcs_len];
r.read_exact(fcs_buf)
.map_err(err::FrameContentSizeReadError)?;
bytes_read += fcs_len;
let mut fcs = 0u64;
for (i, &b) in fcs_buf.iter().enumerate() {
fcs += (b as u64) << (8 * i);
}
if fcs_len == 2 {
fcs += 256;
}
frame_header.frame_content_size = fcs;
}
desc.check_reserved_bit()?;
Ok((frame_header, bytes_read as u8))
}
pub(crate) fn eof() -> crate::io::Error {
crate::io::Error::from(crate::io::ErrorKind::UnexpectedEof)
}
fn take<'a>(input: &mut &'a [u8], n: usize) -> Option<&'a [u8]> {
if input.len() < n {
return None;
}
let (head, tail) = input.split_at(n);
*input = tail;
Some(head)
}
pub(crate) fn take_magic_from_slice(input: &mut &[u8]) -> Result<(), ReadFrameHeaderError> {
use ReadFrameHeaderError as err;
let m = take(input, 4).ok_or_else(|| err::MagicNumberReadError(eof()))?;
let magic_num = u32::from_le_bytes([m[0], m[1], m[2], m[3]]);
if (0x184D2A50..=0x184D2A5F).contains(&magic_num) {
let s = take(input, 4).ok_or_else(|| err::FrameDescriptorReadError(eof()))?;
let skip_size = u32::from_le_bytes([s[0], s[1], s[2], s[3]]);
return Err(ReadFrameHeaderError::SkipFrame {
magic_number: magic_num,
length: skip_size,
});
}
if magic_num != MAGIC_NUM {
return Err(ReadFrameHeaderError::BadMagicNumber(magic_num));
}
Ok(())
}
pub(crate) fn measure_header_from_slice(input: &[u8]) -> Result<usize, ReadFrameHeaderError> {
measure_header_with_format(input, false)
}
pub(crate) fn measure_header_with_format(
mut input: &[u8],
magicless: bool,
) -> Result<usize, ReadFrameHeaderError> {
let magic_len = if magicless {
0
} else {
take_magic_from_slice(&mut input)?;
4
};
let d =
take(&mut input, 1).ok_or_else(|| ReadFrameHeaderError::FrameDescriptorReadError(eof()))?;
Ok(magic_len + FrameDescriptor(d[0]).header_len())
}
const SKIPPABLE_MAGIC_START: u32 = 0x184D_2A50;
const SKIPPABLE_MAGIC_MASK: u32 = 0xFFFF_FFF0;
pub(crate) fn header_input_needed(
input: &[u8],
magicless: bool,
) -> Result<usize, ReadFrameHeaderError> {
let start = if magicless { 1 } else { 5 };
let mut skippable = false;
if !magicless && !input.is_empty() {
let n = input.len().min(4);
let mut zstd = MAGIC_NUM.to_le_bytes();
zstd[..n].copy_from_slice(&input[..n]);
let mut skip = SKIPPABLE_MAGIC_START.to_le_bytes();
skip[..n].copy_from_slice(&input[..n]);
let read = u32::from_le_bytes(zstd);
if read != MAGIC_NUM {
if u32::from_le_bytes(skip) & SKIPPABLE_MAGIC_MASK != SKIPPABLE_MAGIC_START {
return Err(ReadFrameHeaderError::BadMagicNumber(read));
}
skippable = input.len() >= 4;
}
}
if input.len() < start {
return Ok(start);
}
if skippable {
return Ok(8);
}
measure_header_with_format(input, magicless)
}
pub(crate) fn read_frame_header_from_slice(
input: &mut &[u8],
magicless: bool,
) -> Result<(FrameHeader, u8), ReadFrameHeaderError> {
use ReadFrameHeaderError as err;
let mut bytes_read: u8 = 0;
if !magicless {
take_magic_from_slice(input)?;
bytes_read = 4;
}
let d = take(input, 1).ok_or_else(|| err::FrameDescriptorReadError(eof()))?;
let desc = FrameDescriptor(d[0]);
bytes_read += 1;
let mut frame_header = FrameHeader {
descriptor: FrameDescriptor(desc.0),
dict_id: None,
frame_content_size: 0,
window_descriptor: 0,
};
if !desc.single_segment_flag() {
let w = take(input, 1).ok_or_else(|| err::WindowDescriptorReadError(eof()))?;
frame_header.window_descriptor = w[0];
bytes_read += 1;
}
let dict_id_len = desc.dictionary_id_bytes()? as usize;
if dict_id_len != 0 {
let b = take(input, dict_id_len).ok_or_else(|| err::DictionaryIdReadError(eof()))?;
bytes_read += dict_id_len as u8;
let mut buf4 = [0u8; 4];
buf4[..dict_id_len].copy_from_slice(b);
let dict_id = u32::from_le_bytes(buf4);
if dict_id != 0 {
frame_header.dict_id = Some(dict_id);
}
}
let fcs_len = desc.frame_content_size_bytes()? as usize;
if fcs_len != 0 {
let b = take(input, fcs_len).ok_or_else(|| err::FrameContentSizeReadError(eof()))?;
bytes_read += fcs_len as u8;
let mut buf8 = [0u8; 8];
buf8[..fcs_len].copy_from_slice(b);
let mut fcs = u64::from_le_bytes(buf8);
if fcs_len == 2 {
fcs += 256;
}
frame_header.frame_content_size = fcs;
}
desc.check_reserved_bit()?;
Ok((frame_header, bytes_read))
}
pub struct FrameHeader {
pub descriptor: FrameDescriptor,
window_descriptor: u8,
dict_id: Option<u32>,
frame_content_size: u64,
}
impl FrameHeader {
pub fn window_size(&self) -> Result<u64, FrameHeaderError> {
if self.descriptor.single_segment_flag() {
Ok(self.frame_content_size())
} else {
let exp = self.window_descriptor >> 3;
let mantissa = self.window_descriptor & 0x7;
let window_log = 10 + u64::from(exp);
let window_base = 1 << window_log;
let window_add = (window_base / 8) * u64::from(mantissa);
let window_size = window_base + window_add;
if window_size >= MIN_WINDOW_SIZE {
if window_size < MAX_WINDOW_SIZE {
Ok(window_size)
} else {
Err(FrameHeaderError::WindowTooBig { got: window_size })
}
} else {
Err(FrameHeaderError::WindowTooSmall { got: window_size })
}
}
}
pub fn dictionary_id(&self) -> Option<u32> {
self.dict_id
}
pub fn frame_content_size(&self) -> u64 {
self.frame_content_size
}
#[allow(dead_code)]
pub fn fcs_declared(&self) -> bool {
self.descriptor
.frame_content_size_bytes()
.map(|n| n != 0)
.unwrap_or(false)
}
#[allow(dead_code)]
pub fn window_descriptor(&self) -> Option<u8> {
if self.descriptor.single_segment_flag() {
None
} else {
Some(self.window_descriptor)
}
}
}
pub struct FrameDescriptor(pub u8);
impl FrameDescriptor {
pub fn frame_content_size_flag(&self) -> u8 {
self.0 >> 6
}
pub fn reserved_flag(&self) -> bool {
((self.0 >> 3) & 0x1) == 1
}
pub(crate) fn check_reserved_bit(&self) -> Result<(), FrameDescriptorError> {
if self.reserved_flag() {
return Err(FrameDescriptorError::ReservedBitSet);
}
Ok(())
}
pub(crate) fn header_len(&self) -> usize {
let window = usize::from(!self.single_segment_flag());
let dict = self.dictionary_id_bytes().map_or(0, usize::from);
let fcs = self.frame_content_size_bytes().map_or(0, usize::from);
1 + window + dict + fcs
}
pub fn single_segment_flag(&self) -> bool {
((self.0 >> 5) & 0x1) == 1
}
pub fn content_checksum_flag(&self) -> bool {
((self.0 >> 2) & 0x1) == 1
}
pub fn dict_id_flag(&self) -> u8 {
self.0 & 0x3
}
pub fn frame_content_size_bytes(&self) -> Result<u8, FrameDescriptorError> {
match self.frame_content_size_flag() {
0 => {
if self.single_segment_flag() {
Ok(1)
} else {
Ok(0)
}
}
1 => Ok(2),
2 => Ok(4),
3 => Ok(8),
other => Err(FrameDescriptorError::InvalidFrameContentSizeFlag { got: other }),
}
}
pub fn dictionary_id_bytes(&self) -> Result<u8, FrameDescriptorError> {
match self.dict_id_flag() {
0 => Ok(0),
1 => Ok(1),
2 => Ok(2),
3 => Ok(4),
other => Err(FrameDescriptorError::InvalidFrameContentSizeFlag { got: other }),
}
}
}