pub mod errors;
mod frame_decoder;
mod streaming_decoder;
#[cfg(feature = "caller-workspace")]
#[cfg_attr(docsrs, doc(cfg(feature = "caller-workspace")))]
pub mod workspace;
pub use dictionary::{Dictionary, DictionaryHandle, MAGIC_NUM as DICTIONARY_MAGIC};
pub use frame_decoder::{BlockDecodingStrategy, ContentChecksum, FrameDecoder};
#[cfg(feature = "legacy")]
#[cfg_attr(docsrs, doc(cfg(feature = "legacy")))]
pub use legacy::LegacyVersion;
pub use crate::common::MAXIMUM_ALLOWED_WINDOW_SIZE;
pub use crate::common::MAX_DECODER_WINDOW_SIZE;
#[cfg(feature = "lsm")]
pub use frame_decoder::{PartialDecode, ResumeInput, ResumeState};
pub use streaming_decoder::{DictionaryRefused, FinishedFrame, StreamingDecoder};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FrameContentSize {
Known(u64),
Unknown,
}
pub fn read_frame_content_size(
src: &[u8],
) -> Result<FrameContentSize, errors::ReadFrameHeaderError> {
#[cfg(feature = "legacy")]
if LegacyVersion::of(src).is_some() {
return Ok(legacy::declared_content_size(src)
.map_or(FrameContentSize::Unknown, FrameContentSize::Known));
}
let (header, _consumed) = frame::read_frame_header_with_format(src, false)?;
Ok(if header.fcs_declared() {
FrameContentSize::Known(header.frame_content_size())
} else {
FrameContentSize::Unknown
})
}
#[derive(Debug)]
pub enum FrameSizeError {
Header(errors::ReadFrameHeaderError),
Truncated,
ReservedBlock,
OversizedBlock,
}
pub fn find_frame_compressed_size(src: &[u8]) -> Result<usize, FrameSizeError> {
#[cfg(feature = "legacy")]
if let Some(version) = LegacyVersion::of(src) {
return legacy::frame_size(version, src).map(|(size, _)| size);
}
let (header, header_len) = match frame::read_frame_header_with_format(src, false) {
Ok(parsed) => parsed,
Err(errors::ReadFrameHeaderError::SkipFrame { length, .. }) => {
return 8usize
.checked_add(length as usize)
.filter(|end| *end <= src.len())
.ok_or(FrameSizeError::Truncated);
}
Err(e) => return Err(FrameSizeError::Header(e)),
};
let walk = walk_blocks(src, header_len as usize, frame_block_size_max(&header))?;
if header.descriptor.content_checksum_flag() {
walk.end
.checked_add(4)
.filter(|end| *end <= src.len())
.ok_or(FrameSizeError::Truncated)
} else {
Ok(walk.end)
}
}
#[derive(Debug)]
pub enum DecompressedSizeError {
Header(errors::ReadFrameHeaderError),
Frame(FrameSizeError),
Overflow,
}
pub fn find_decompressed_size(src: &[u8]) -> Result<FrameContentSize, DecompressedSizeError> {
let mut rest = src;
let mut total: u64 = 0;
while !rest.is_empty() {
#[cfg(feature = "legacy")]
if rest.len() < 5 && LegacyVersion::of(rest).is_some() {
return Err(DecompressedSizeError::Frame(FrameSizeError::Truncated));
}
match read_frame_content_size(rest) {
Ok(FrameContentSize::Known(size)) => {
total = total
.checked_add(size)
.ok_or(DecompressedSizeError::Overflow)?;
}
Ok(FrameContentSize::Unknown) => return Ok(FrameContentSize::Unknown),
Err(errors::ReadFrameHeaderError::SkipFrame { .. }) => {}
Err(err) => return Err(DecompressedSizeError::Header(err)),
}
let consumed = find_frame_compressed_size(rest).map_err(DecompressedSizeError::Frame)?;
rest = &rest[consumed..];
}
Ok(FrameContentSize::Known(total))
}
struct BlockWalk {
end: usize,
count: u64,
}
fn frame_block_size_max(header: &frame::FrameHeader) -> usize {
let window_size = match header.window_descriptor() {
Some(desc) => {
let exponent = u64::from(desc >> 3);
let mantissa = u64::from(desc & 0x7);
let window_base = 1u64 << (10 + exponent);
window_base + (window_base / 8) * mantissa
}
None => header.frame_content_size(),
};
window_size.min(128 * 1024) as usize
}
fn walk_blocks(
src: &[u8],
start: usize,
max_block_size: usize,
) -> Result<BlockWalk, FrameSizeError> {
let mut offset = start;
let mut count = 0u64;
loop {
let hdr = src
.get(offset..offset + 3)
.ok_or(FrameSizeError::Truncated)?;
let raw = u32::from(hdr[0]) | (u32::from(hdr[1]) << 8) | (u32::from(hdr[2]) << 16);
let last_block = (raw & 1) != 0;
let block_type = (raw >> 1) & 0b11;
let block_size = (raw >> 3) as usize;
let on_disk = match block_type {
1 => 1, 0 | 2 => block_size, _ => return Err(FrameSizeError::ReservedBlock),
};
if block_size > max_block_size {
return Err(FrameSizeError::OversizedBlock);
}
offset = offset
.checked_add(3 + on_disk)
.filter(|end| *end <= src.len())
.ok_or(FrameSizeError::Truncated)?;
count += 1;
if last_block {
break;
}
}
Ok(BlockWalk { end: offset, count })
}
pub fn frame_decompressed_bound(src: &[u8]) -> Result<u64, FrameSizeError> {
#[cfg(feature = "legacy")]
if let Some(version) = LegacyVersion::of(src) {
return legacy::frame_size(version, src).map(|(_, bound)| bound);
}
let (header, header_len) = match frame::read_frame_header_with_format(src, false) {
Ok(parsed) => parsed,
Err(errors::ReadFrameHeaderError::SkipFrame { length, .. }) => {
return 8usize
.checked_add(length as usize)
.filter(|end| *end <= src.len())
.map(|_| 0)
.ok_or(FrameSizeError::Truncated);
}
Err(e) => return Err(FrameSizeError::Header(e)),
};
let block_size_max = frame_block_size_max(&header);
let walk = walk_blocks(src, header_len as usize, block_size_max)?;
if header.descriptor.content_checksum_flag() {
walk.end
.checked_add(4)
.filter(|end| *end <= src.len())
.ok_or(FrameSizeError::Truncated)?;
}
if header.fcs_declared() {
return Ok(header.frame_content_size());
}
Ok(walk.count.saturating_mul(block_size_max as u64))
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FrameMagic {
Zstd,
Skippable(u8),
}
pub fn frame_magic(src: &[u8]) -> Option<FrameMagic> {
let magic = u32::from_le_bytes(src.get(..4)?.try_into().ok()?);
if magic == crate::common::MAGIC_NUM {
Some(FrameMagic::Zstd)
} else if magic & 0xFFFF_FFF0 == crate::skippable::SKIPPABLE_MAGIC_START {
Some(FrameMagic::Skippable((magic & 0xF) as u8))
} else {
None
}
}
pub fn is_frame(src: &[u8]) -> bool {
#[cfg(feature = "legacy")]
if LegacyVersion::of(src).is_some() {
return true;
}
frame_magic(src).is_some()
}
pub fn decompression_margin(src: &[u8]) -> Result<usize, FrameSizeError> {
let mut rest = src;
let mut margin = 0usize;
let mut max_block_size = 0usize;
while !rest.is_empty() {
let consumed = match frame::read_frame_header_with_format(rest, false) {
Ok((header, header_len)) => {
let block_size_max = frame_block_size_max(&header);
let walk = walk_blocks(rest, header_len as usize, block_size_max)?;
let checksum = if header.descriptor.content_checksum_flag() {
4
} else {
0
};
let end = walk
.end
.checked_add(checksum)
.filter(|end| *end <= rest.len())
.ok_or(FrameSizeError::Truncated)?;
margin += header_len as usize + checksum + 3 * walk.count as usize;
max_block_size = max_block_size.max(block_size_max);
end
}
Err(errors::ReadFrameHeaderError::SkipFrame { .. }) => {
let end = find_frame_compressed_size(rest)?;
margin += end;
end
}
Err(e) => return Err(FrameSizeError::Header(e)),
};
rest = &rest[consumed..];
}
Ok(margin + max_block_size)
}
pub fn min_decoding_buffer_size(
window_size: u64,
frame_content_size: Option<u64>,
) -> Option<usize> {
const WILDCOPY_OVERLENGTH: u64 = 32;
let block_size = window_size.min(crate::common::MAX_BLOCK_SIZE as u64);
let needed = window_size.checked_add(2 * block_size + 2 * WILDCOPY_OVERLENGTH);
let size = match (frame_content_size, needed) {
(Some(content), Some(needed)) => content.min(needed),
(Some(content), None) => content,
(None, Some(needed)) => needed,
(None, None) => return None,
};
usize::try_from(size).ok()
}
#[derive(Copy, Clone, Debug)]
pub struct FrameHeaderInfo {
pub content_size: FrameContentSize,
pub window_size: u64,
pub dictionary_id: Option<u32>,
pub content_checksum: bool,
pub header_size: usize,
}
pub fn frame_header_size(src: &[u8]) -> Result<usize, errors::ReadFrameHeaderError> {
#[cfg(feature = "legacy")]
if let Some(version) = LegacyVersion::of(src) {
return version
.header_size(src)
.ok_or_else(|| errors::ReadFrameHeaderError::FrameDescriptorReadError(frame::eof()));
}
frame::measure_header_from_slice(src)
}
pub fn frame_header_size_in_format(
src: &[u8],
magicless: bool,
) -> Result<usize, errors::ReadFrameHeaderError> {
frame::measure_header_with_format(src, magicless)
}
pub fn frame_header_input_needed(
src: &[u8],
magicless: bool,
) -> Result<usize, errors::ReadFrameHeaderError> {
frame::header_input_needed(src, magicless)
}
pub fn read_frame_header_info(
src: &[u8],
magicless: bool,
) -> Result<FrameHeaderInfo, errors::ReadFrameHeaderError> {
let (header, consumed) = frame::read_frame_header_with_format(src, magicless)?;
let content_size = if header.fcs_declared() {
FrameContentSize::Known(header.frame_content_size())
} else {
FrameContentSize::Unknown
};
let window_size = match header.window_descriptor() {
Some(desc) => {
let exponent = u64::from(desc >> 3);
let mantissa = u64::from(desc & 0x7);
let window_base = 1u64 << (10 + exponent);
window_base + (window_base / 8) * mantissa
}
None => header.frame_content_size(),
};
Ok(FrameHeaderInfo {
content_size,
window_size,
dictionary_id: header.dictionary_id(),
content_checksum: header.descriptor.content_checksum_flag(),
header_size: consumed as usize,
})
}
pub(crate) mod block_decoder;
pub(crate) mod buffer_backend;
pub(crate) mod decode_buffer;
pub(crate) mod dictionary;
pub(crate) mod exec_sequence_inline;
pub(crate) mod flat_buf;
pub(crate) mod frame;
#[cfg(feature = "legacy")]
pub(crate) mod legacy;
pub(crate) mod literals_section_decoder;
pub(crate) mod prefetch;
mod ringbuffer;
#[allow(dead_code)]
pub(crate) mod scratch;
#[cfg(all(target_arch = "x86_64", feature = "kernel-avx2"))]
pub(crate) mod seq_decoder_avx2;
#[cfg(all(target_arch = "x86_64", feature = "kernel-bmi2"))]
pub(crate) mod seq_decoder_bmi2;
pub(crate) mod seq_decoder_scalar;
#[cfg(all(target_arch = "x86_64", feature = "kernel-vbmi2"))]
pub(crate) mod seq_decoder_vbmi2;
pub(crate) mod sequence_execution;
pub(crate) mod sequence_section_decoder;
pub(crate) mod simd_copy;
#[cfg(feature = "copy-shape-stats")]
pub use simd_copy::shape_stats;
pub(crate) mod user_slice_buf;
#[cfg(feature = "bench-internals")]
pub(crate) use self::simd_copy::copy_bytes_overshooting_for_bench;
#[cfg(test)]
mod block_api_tests;
#[cfg(test)]
mod frame_inspection_tests;