#![warn(unused_must_use)]
#![allow(non_upper_case_globals)]
use zstd_pure_rs::prelude as zstd_api;
#[inline(never)]
pub fn force_link() {}
pub enum Result {
Success(usize),
Err(&'static str),
}
#[derive(strum::IntoStaticStr, Debug)]
pub enum ZstdError {
OutOfMemory,
InvalidZstdData,
DecompressionFailed,
ZstdFailedToCreateInstance,
ZstdDecompressionError,
ShortRead,
}
bun_core::impl_tag_error!(ZstdError);
bun_core::named_error_set!(ZstdError);
impl ZstdError {
fn for_decompression(rc: usize, other: ZstdError) -> ZstdError {
if zstd_api::ZSTD_getErrorCode(rc) == zstd_api::ErrorCode::MemoryAllocation {
ZstdError::OutOfMemory
} else {
other
}
}
}
const STREAMING_OUTPUT_STEP: usize = 4096;
pub fn compress(dest: &mut [u8], src: &[u8], level: Option<i32>) -> Result {
let level = level.unwrap_or_else(|| zstd_api::ZSTD_defaultCLevel());
let n = zstd_api::ZSTD_compress(dest, src, level);
if zstd_api::ZSTD_isError(n) {
return Result::Err(zstd_api::ZSTD_getErrorName(n));
}
Result::Success(n)
}
pub fn compress_bound(src_size: usize) -> usize {
zstd_api::ZSTD_compressBound(src_size)
}
pub fn decompress(dest: &mut [u8], src: &[u8]) -> Result {
let n = zstd_api::ZSTD_decompress(dest, src);
if zstd_api::ZSTD_isError(n) {
return Result::Err(zstd_api::ZSTD_getErrorName(n));
}
Result::Success(n)
}
pub fn decompress_alloc(src: &[u8]) -> core::result::Result<Vec<u8>, ZstdError> {
let size = get_decompressed_size(src);
const ZSTD_CONTENTSIZE_UNKNOWN: u64 = u64::MAX;
const ZSTD_CONTENTSIZE_ERROR: u64 = u64::MAX - 1;
const MAX_PREALLOCATE_SIZE: usize = 16 * 1024 * 1024;
if size as u64 == ZSTD_CONTENTSIZE_ERROR {
return Err(ZstdError::InvalidZstdData);
}
if size as u64 == ZSTD_CONTENTSIZE_UNKNOWN || size > MAX_PREALLOCATE_SIZE {
let initial_capacity = if size as u64 == ZSTD_CONTENTSIZE_UNKNOWN {
src.len().clamp(STREAMING_OUTPUT_STEP, MAX_PREALLOCATE_SIZE)
} else {
MAX_PREALLOCATE_SIZE
};
let mut list: bun_core::vec::ChanVec<u8> = bun_core::vec::ChanVec::new();
if list.try_reserve_exact(initial_capacity).is_err() {
return Err(ZstdError::OutOfMemory);
}
let mut reader = ZstdReaderArrayList::init(src, &mut list)?;
reader.read_all(true)?;
drop(reader);
return Ok(list.into_iter().collect::<::std::vec::Vec<u8>>());
}
let mut output: Vec<u8> = Vec::new();
if output.try_reserve_exact(size).is_err() {
return Err(ZstdError::OutOfMemory);
}
output.spare_capacity_mut().fill(core::mem::MaybeUninit::new(0));
unsafe { output.set_len(size) };
let rc = zstd_api::ZSTD_decompress(&mut output, src);
if zstd_api::ZSTD_isError(rc) {
return Err(ZstdError::for_decompression(
rc,
ZstdError::DecompressionFailed,
));
}
output.truncate(rc);
Ok(output)
}
pub fn get_decompressed_size(src: &[u8]) -> usize {
zstd_api::ZSTD_findDecompressedSize(src) as usize
}
pub use bun_core::compress::State;
pub struct ZstdReaderArrayList<'a, V: bun_core::vec::SpareBytesVec = bun_core::vec::ChanVec<u8>> {
pub input: &'a [u8],
pub list_ptr: &'a mut V,
zstd: Option<Box<zstd_api::ZSTD_DStream>>,
pub state: State,
pub total_out: usize,
pub total_in: usize,
pub max_output_size: usize,
}
impl<'a, V: bun_core::vec::SpareBytesVec> ZstdReaderArrayList<'a, V> {
pub fn init(
input: &'a [u8],
list: &'a mut V,
) -> core::result::Result<Box<ZstdReaderArrayList<'a, V>>, ZstdError> {
Self::init_with_list_allocator(input, list)
}
pub fn init_with_list_allocator(
input: &'a [u8],
list: &'a mut V,
) -> core::result::Result<Box<ZstdReaderArrayList<'a, V>>, ZstdError> {
let mut dstream = zstd_api::ZSTD_createDStream().ok_or(ZstdError::ZstdFailedToCreateInstance)?;
let _ = zstd_api::ZSTD_initDStream(&mut *dstream);
Ok(Box::new(ZstdReaderArrayList {
input,
list_ptr: list,
zstd: Some(dstream),
state: State::Uninitialized,
total_out: 0,
total_in: 0,
max_output_size: usize::MAX,
}))
}
pub fn end(&mut self) {
if self.state != State::End {
self.zstd.take();
self.state = State::End;
}
}
pub fn read_all(&mut self, is_done: bool) -> core::result::Result<(), ZstdError> {
if self.state == State::End || self.state == State::Error {
return Ok(());
}
let dstream = self.zstd.as_mut().ok_or(ZstdError::ZstdFailedToCreateInstance)?;
let mut output_full = false;
while self.state == State::Uninitialized || self.state == State::Inflating {
let next_in = &self.input[self.total_in..];
if next_in.is_empty() && !output_full {
if is_done {
if self.state == State::Inflating {
self.state = State::Error;
return Err(ZstdError::ZstdDecompressionError);
}
self.end();
}
return Ok(());
}
let remaining_output = self.max_output_size.saturating_sub(self.list_ptr.sb_len());
if remaining_output == 0 {
self.state = State::Error;
return Err(ZstdError::ZstdDecompressionError);
}
if !self.list_ptr.sb_try_reserve(STREAMING_OUTPUT_STEP) {
self.state = State::Error;
return Err(ZstdError::OutOfMemory);
}
let spare = unsafe { bun_core::vec::spare_bytes_mut(self.list_ptr) };
let out_cap = spare.len().min(remaining_output);
let mut out_pos = 0usize;
let mut in_pos = 0usize;
let rc = zstd_api::ZSTD_decompressStream(
dstream,
&mut spare[..out_cap],
&mut out_pos,
next_in,
&mut in_pos,
);
if zstd_api::ZSTD_isError(rc) {
self.state = State::Error;
return Err(ZstdError::for_decompression(
rc,
ZstdError::ZstdDecompressionError,
));
}
let bytes_written = out_pos;
let bytes_read = in_pos;
output_full = bytes_written == out_cap;
unsafe { bun_core::vec::commit_spare(self.list_ptr, bytes_written) };
self.total_in += bytes_read;
self.total_out += bytes_written;
if rc == 0 {
self.state = State::Uninitialized;
if self.total_in >= self.input.len() {
if is_done {
self.end();
return Ok(());
}
return Ok(());
}
let _ = zstd_api::ZSTD_initDStream(dstream);
continue;
}
if rc > 0 {
self.state = State::Inflating;
}
if bytes_read == next_in.len() {
if output_full {
continue;
}
if is_done {
self.state = State::Error;
return Err(ZstdError::ZstdDecompressionError);
}
return Err(ZstdError::ShortRead);
}
}
Ok(())
}
}
impl<V: bun_core::vec::SpareBytesVec> Drop for ZstdReaderArrayList<'_, V> {
fn drop(&mut self) {
self.end();
}
}
pub use zstd_pure_rs::prelude::{
ZSTD_CCtx, ZSTD_DStream,
ZSTD_cParameter, ZSTD_dParameter,
ZSTD_EndDirective, ZSTD_ResetDirective, ZSTD_DResetDirective,
ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_CONTENTSIZE_ERROR,
ZSTD_createCCtx, ZSTD_freeCCtx,
ZSTD_createDCtx, ZSTD_freeDCtx,
ZSTD_CCtx_setPledgedSrcSize, ZSTD_CCtx_setParameter,
ZSTD_DCtx_setParameter, ZSTD_CCtx_reset, ZSTD_DCtx_reset,
ZSTD_compressStream2, ZSTD_decompressStream,
ZSTD_getErrorCode, ZSTD_getErrorString,
ZSTD_isError, ZSTD_getErrorName,
ZSTD_defaultCLevel,
};
pub use zstd_pure_rs::prelude::ErrorCode as ZSTD_ErrorCode;
pub use zstd_pure_rs::prelude::ZSTD_EndDirective::ZSTD_e_continue;
pub use zstd_pure_rs::prelude::ZSTD_ResetDirective::ZSTD_reset_session_and_parameters;
#[repr(C)]
pub struct InBuffer<'a> {
pub src: &'a [u8],
pub pos: usize,
}
#[repr(C)]
pub struct OutBuffer<'a> {
pub dst: &'a mut [u8],
pub pos: usize,
}
pub mod error_codes {
pub const ZSTD_error_no_error: u32 = 0;
pub const ZSTD_error_GENERIC: u32 = 1;
pub const ZSTD_error_prefix_unknown: u32 = 10;
pub const ZSTD_error_version_unsupported: u32 = 12;
pub const ZSTD_error_frameParameter_unsupported: u32 = 14;
pub const ZSTD_error_frameParameter_windowTooLarge: u32 = 16;
pub const ZSTD_error_corruption_detected: u32 = 20;
pub const ZSTD_error_checksum_wrong: u32 = 22;
pub const ZSTD_error_literals_headerWrong: u32 = 24;
pub const ZSTD_error_dictionary_corrupted: u32 = 30;
pub const ZSTD_error_dictionary_wrong: u32 = 32;
pub const ZSTD_error_dictionaryCreation_failed: u32 = 34;
pub const ZSTD_error_parameter_unsupported: u32 = 40;
pub const ZSTD_error_parameter_combination_unsupported: u32 = 41;
pub const ZSTD_error_parameter_outOfBound: u32 = 42;
pub const ZSTD_error_tableLog_tooLarge: u32 = 44;
pub const ZSTD_error_maxSymbolValue_tooLarge: u32 = 46;
pub const ZSTD_error_maxSymbolValue_tooSmall: u32 = 48;
pub const ZSTD_error_stabilityCondition_notRespected: u32 = 50;
pub const ZSTD_error_stage_wrong: u32 = 60;
pub const ZSTD_error_init_missing: u32 = 62;
pub const ZSTD_error_memory_allocation: u32 = 64;
pub const ZSTD_error_workSpace_tooSmall: u32 = 66;
pub const ZSTD_error_dstSize_tooSmall: u32 = 70;
pub const ZSTD_error_srcSize_wrong: u32 = 72;
pub const ZSTD_error_dstBuffer_null: u32 = 74;
pub const ZSTD_error_noForwardProgress_destFull: u32 = 80;
pub const ZSTD_error_noForwardProgress_inputEmpty: u32 = 82;
}