Files
zstd-rs/rust/src/zstd_decompress.rs
T
ddidderr fe7e24c770 feat(rust): migrate high-level runtime paths
Move long-distance matching and high-level decompression from C shims into
Rust. The decoder now owns context, dictionary, parameter, one-shot, and
buffered streaming state while C retains allocation/configuration, legacy,
and trace leaves.

Move CLI parsing, safety policy, and dispatch into a separate Rust static
archive. Keeping it separate prevents library builds from retaining FIO
symbols, while C continues to own file opening, replacement, and I/O.
Program targets now select matching compression/decompression archives.

The remaining C boundary is intentional: high-level compression, optimal
parsing, dictionary building, legacy callbacks, and CLI file I/O still need
migration.

Test Plan:
- cargo test --all-targets (native and i686)
- cargo test --all-targets in rust/cli (native and i686)
- CLI crate compression-only and decompression-only feature tests
- native and i686 fuzzer/zstreamtest runs, plus legacy and dictionary tests
- ZSTD_C_PREDICT and ZSTD_HEAPMODE=0 fuzzer coverage
- library, dynamic-link, and program-target build/round-trip matrix

Refs: rust/README.md
2026-07-11 09:03:41 +02:00

3475 lines
117 KiB
Rust

#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::too_many_arguments)]
#![allow(clippy::not_unsafe_ptr_arg_deref)]
//! Frame, context, and streaming decompression orchestration.
//!
//! `ZSTD_DCtx` deliberately remains C-owned. The companion C translation
//! unit projects its build-configuration-dependent leaves into
//! [`ZSTD_rustDctxView`]; this module owns the decoder state machine and
//! public ABI while never assumes offsets for the private C context.
use crate::entropy_common::FSE_readNCount;
use crate::errors::{ERR_isError, ZstdErrorCode, ERROR};
#[cfg(feature = "huf-force-decompress-x1")]
use crate::huf_decompress::HUF_readDTableX1_wksp;
#[cfg(not(feature = "huf-force-decompress-x1"))]
use crate::huf_decompress::HUF_readDTableX2_wksp;
use crate::mem::{MEM_32bits, MEM_readLE16, MEM_readLE32, MEM_readLE64};
use crate::xxhash::{XXH64_digest, XXH64_reset, XXH64_state_t, XXH64_update, XXH64};
use crate::zstd_ddict::{
ZSTD_DDict, ZSTD_DDict_dictContent, ZSTD_DDict_dictSize, ZSTD_copyDDictParameters,
ZSTD_freeDDict, ZSTD_getDictID_fromDDict,
};
use std::cmp::{max, min};
use std::ffi::c_void;
use std::mem::{size_of, MaybeUninit};
use std::os::raw::{c_int, c_uint};
use std::ptr;
const ZSTD_MAGICNUMBER: u32 = 0xFD2F_B528;
const ZSTD_MAGIC_DICTIONARY: u32 = 0xEC30_A437;
const ZSTD_MAGIC_SKIPPABLE_START: u32 = 0x184D_2A50;
const ZSTD_MAGIC_SKIPPABLE_MASK: u32 = 0xFFFF_FFF0;
const ZSTD_FRAMEIDSIZE: usize = 4;
const ZSTD_SKIPPABLEHEADERSIZE: usize = 8;
const ZSTD_BLOCKHEADERSIZE: usize = 3;
const ZSTD_BLOCKSIZE_MAX: usize = 128 << 10;
const ZSTD_BLOCKSIZE_MAX_MIN: usize = 1 << 10;
const ZSTD_WINDOWLOG_ABSOLUTEMIN: usize = 10;
const ZSTD_WINDOWLOG_LIMIT_DEFAULT: usize = 27;
const ZSTD_WINDOWLOG_MAX_32: usize = 30;
const ZSTD_WINDOWLOG_MAX_64: usize = 31;
const WILDCOPY_OVERLENGTH: usize = 32;
const ZSTD_WORKSPACETOOLARGE_FACTOR: usize = 3;
const ZSTD_WORKSPACETOOLARGE_MAXDURATION: usize = 128;
const ZSTD_HUFFDTABLE_CAPACITY_LOG: usize = 12;
const HUF_DTABLE_SIZE: usize = 1 + (1 << ZSTD_HUFFDTABLE_CAPACITY_LOG);
const ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32: usize = 157;
const LL_FSE_LOG: usize = 9;
const OFF_FSE_LOG: usize = 8;
const ML_FSE_LOG: usize = 9;
const MAX_LL: usize = 35;
const MAX_ML: usize = 52;
const MAX_OFF: usize = 31;
const ZSTD_REP_NUM: usize = 3;
const ZSTD_CONTENTSIZE_UNKNOWN: u64 = u64::MAX;
const ZSTD_CONTENTSIZE_ERROR: u64 = u64::MAX - 1;
const ZSTD_F_ZSTD1: c_int = 0;
const ZSTD_F_ZSTD1_MAGICLESS: c_int = 1;
const ZSTD_FRAME: c_int = 0;
const ZSTD_SKIPPABLE_FRAME: c_int = 1;
const ZSTD_BM_BUFFERED: c_int = 0;
const ZSTD_BM_STABLE: c_int = 1;
const ZSTD_D_VALIDATE_CHECKSUM: c_int = 0;
const ZSTD_D_IGNORE_CHECKSUM: c_int = 1;
const ZSTD_RMD_REF_SINGLE_DDICT: c_int = 0;
const ZSTD_RMD_REF_MULTIPLE_DDICTS: c_int = 1;
const ZSTD_DLM_BY_COPY: c_int = 0;
const ZSTD_DLM_BY_REF: c_int = 1;
const ZSTD_DCT_AUTO: c_int = 0;
const ZSTD_DCT_RAW_CONTENT: c_int = 1;
const ZSTD_USE_INDEFINITELY: c_int = -1;
const ZSTD_DONT_USE: c_int = 0;
const ZSTD_USE_ONCE: c_int = 1;
const ZSTDDS_GET_FRAME_HEADER_SIZE: c_int = 0;
const ZSTDDS_DECODE_FRAME_HEADER: c_int = 1;
const ZSTDDS_DECODE_BLOCK_HEADER: c_int = 2;
const ZSTDDS_DECOMPRESS_BLOCK: c_int = 3;
const ZSTDDS_DECOMPRESS_LAST_BLOCK: c_int = 4;
const ZSTDDS_CHECK_CHECKSUM: c_int = 5;
const ZSTDDS_DECODE_SKIPPABLE_HEADER: c_int = 6;
const ZSTDDS_SKIP_FRAME: c_int = 7;
const ZDSS_INIT: c_int = 0;
const ZDSS_LOAD_HEADER: c_int = 1;
const ZDSS_READ: c_int = 2;
const ZDSS_LOAD: c_int = 3;
const ZDSS_FLUSH: c_int = 4;
const BT_RAW: c_int = 0;
const BT_RLE: c_int = 1;
const BT_COMPRESSED: c_int = 2;
const BT_RESERVED: c_int = 3;
const ZSTD_D_WINDOW_LOG_MAX: c_int = 100;
const ZSTD_D_FORMAT: c_int = 1000;
const ZSTD_D_STABLE_OUT_BUFFER: c_int = 1001;
const ZSTD_D_FORCE_IGNORE_CHECKSUM: c_int = 1002;
const ZSTD_D_REF_MULTIPLE_DDICTS: c_int = 1003;
const ZSTD_D_DISABLE_HUFFMAN_ASSEMBLY: c_int = 1004;
const ZSTD_D_MAX_BLOCK_SIZE: c_int = 1005;
const ZSTD_RESET_SESSION_ONLY: c_int = 1;
const ZSTD_RESET_PARAMETERS: c_int = 2;
const ZSTD_RESET_SESSION_AND_PARAMETERS: c_int = 3;
const ZSTD_NIT_FRAME_HEADER: c_int = 0;
const ZSTD_NIT_BLOCK_HEADER: c_int = 1;
const ZSTD_NIT_BLOCK: c_int = 2;
const ZSTD_NIT_LAST_BLOCK: c_int = 3;
const ZSTD_NIT_CHECKSUM: c_int = 4;
const ZSTD_NIT_SKIPPABLE_FRAME: c_int = 5;
const LL_BASE: [u32; MAX_LL + 1] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 28, 32, 40, 48, 64,
0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000,
];
const OF_BASE: [u32; MAX_OFF + 1] = [
0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD,
0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, 0xFFFFFD, 0x1FFFFFD,
0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD,
];
const OF_BITS: [u8; MAX_OFF + 1] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31,
];
const ML_BASE: [u32; MAX_ML + 1] = [
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203,
0x403, 0x803, 0x1003, 0x2003, 0x4003, 0x8003, 0x10003,
];
const LL_BITS: [u8; MAX_LL + 1] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16,
];
const ML_BITS: [u8; MAX_ML + 1] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
];
#[repr(C)]
pub struct ZSTD_DCtx {
_private: [u8; 0],
}
pub type ZSTD_DStream = ZSTD_DCtx;
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
pub struct ZSTD_FrameHeader {
pub frame_content_size: u64,
pub window_size: u64,
pub block_size_max: c_uint,
pub frame_type: c_int,
pub header_size: c_uint,
pub dict_id: c_uint,
pub checksum_flag: c_uint,
pub reserved1: c_uint,
pub reserved2: c_uint,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct ZSTD_inBuffer {
pub src: *const c_void,
pub size: usize,
pub pos: usize,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct ZSTD_outBuffer {
pub dst: *mut c_void,
pub size: usize,
pub pos: usize,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
pub struct ZSTD_bounds {
pub error: usize,
pub lower_bound: c_int,
pub upper_bound: c_int,
}
type ZstdAllocFunction = unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void;
type ZstdFreeFunction = unsafe extern "C" fn(*mut c_void, *mut c_void);
#[repr(C)]
#[derive(Clone, Copy)]
pub struct ZSTD_customMem {
custom_alloc: Option<ZstdAllocFunction>,
custom_free: Option<ZstdFreeFunction>,
opaque: *mut c_void,
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
struct BlockProperties {
block_type: c_int,
last_block: u32,
orig_size: u32,
}
#[repr(C)]
pub struct ZSTD_entropyDTables_t {
ll_table: [crate::zstd_decompress_block::ZSTD_seqSymbol; 1 + (1 << LL_FSE_LOG)],
of_table: [crate::zstd_decompress_block::ZSTD_seqSymbol; 1 + (1 << OFF_FSE_LOG)],
ml_table: [crate::zstd_decompress_block::ZSTD_seqSymbol; 1 + (1 << ML_FSE_LOG)],
huf_table: [u32; HUF_DTABLE_SIZE],
rep: [u32; ZSTD_REP_NUM],
workspace: [u32; ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32],
}
/// C-provided leaves of `ZSTD_DCtx_s`. Every pointer is produced under the
/// active C preprocessor configuration; Rust never hard-codes a private
/// decoder-context offset.
#[repr(C)]
#[derive(Clone, Copy)]
struct ZSTD_rustDctxView {
dctx: *mut c_void,
llt_ptr: *mut c_void,
mlt_ptr: *mut c_void,
oft_ptr: *mut c_void,
huf_ptr: *mut c_void,
entropy: *mut c_void,
workspace: *mut c_void,
workspace_size: usize,
previous_dst_end: *mut c_void,
prefix_start: *mut c_void,
virtual_start: *mut c_void,
dict_end: *mut c_void,
expected: *mut c_void,
f_params: *mut c_void,
processed_c_size: *mut c_void,
decoded_size: *mut c_void,
b_type: *mut c_void,
stage: *mut c_void,
lit_entropy: *mut c_void,
fse_entropy: *mut c_void,
xxh_state: *mut c_void,
header_size: *mut c_void,
format: *mut c_void,
force_ignore_checksum: *mut c_void,
validate_checksum: *mut c_void,
lit_ptr: *mut c_void,
custom_mem: *mut c_void,
lit_size: *mut c_void,
rle_size: *mut c_void,
static_size: *mut c_void,
is_frame_decompression: *mut c_void,
ddict_local: *mut c_void,
ddict: *mut c_void,
dict_id: *mut c_void,
ddict_is_cold: *mut c_void,
dict_uses: *mut c_void,
ddict_set: *mut c_void,
ref_multiple_ddicts: *mut c_void,
disable_huf_asm: *mut c_void,
max_block_size_param: *mut c_void,
stream_stage: *mut c_void,
in_buff: *mut c_void,
in_buff_size: *mut c_void,
in_pos: *mut c_void,
max_window_size: *mut c_void,
out_buff: *mut c_void,
out_buff_size: *mut c_void,
out_start: *mut c_void,
out_end: *mut c_void,
lh_size: *mut c_void,
legacy_context: *mut c_void,
previous_legacy_version: *mut c_void,
legacy_version: *mut c_void,
hostage_byte: *mut c_void,
no_forward_progress: *mut c_void,
out_buffer_mode: *mut c_void,
expected_out_buffer: *mut c_void,
lit_buffer: *mut c_void,
lit_buffer_end: *mut c_void,
lit_buffer_location: *mut c_void,
lit_extra_buffer: *mut c_void,
lit_extra_buffer_size: usize,
header_buffer: *mut c_void,
header_buffer_size: usize,
oversized_duration: *mut c_void,
fuzz_begin: *mut c_void,
fuzz_end: *mut c_void,
dctx_size: usize,
}
unsafe extern "C" {
fn ZSTD_rust_dctx_view(dctx: *mut ZSTD_DCtx, out: *mut ZSTD_rustDctxView);
fn ZSTD_rust_dctx_sizeof() -> usize;
fn ZSTD_rust_dctx_alloc(custom_mem: ZSTD_customMem) -> *mut ZSTD_DCtx;
fn ZSTD_rust_dctx_free_storage(dctx: *mut ZSTD_DCtx, custom_mem: ZSTD_customMem);
fn ZSTD_rust_dctx_init_platform(dctx: *mut ZSTD_DCtx);
fn ZSTD_rust_dctx_default_max_window_size() -> usize;
fn ZSTD_rust_no_forward_progress_max() -> c_int;
fn ZSTD_rust_heapmode() -> c_int;
fn ZSTD_rust_decompress_stack(
dst: *mut c_void,
dst_capacity: usize,
src: *const c_void,
src_size: usize,
) -> usize;
fn ZSTD_rust_custom_malloc(size: usize, custom_mem: ZSTD_customMem) -> *mut c_void;
fn ZSTD_rust_custom_calloc(size: usize, custom_mem: ZSTD_customMem) -> *mut c_void;
fn ZSTD_rust_custom_free(allocation: *mut c_void, custom_mem: ZSTD_customMem);
fn ZSTD_rust_create_ddict(
dict: *const c_void,
dict_size: usize,
dict_load_method: c_int,
dict_content_type: c_int,
custom_mem: ZSTD_customMem,
) -> *mut ZSTD_DDict;
fn ZSTD_rust_dctx_trace_end(
dctx: *mut ZSTD_DCtx,
uncompressed_size: u64,
compressed_size: u64,
streaming: c_int,
);
fn ZSTD_rust_dctx_trace_begin(dctx: *mut ZSTD_DCtx);
fn ZSTD_rust_dctx_copy_prefix(dst: *mut ZSTD_DCtx, src: *const ZSTD_DCtx);
fn ZSTD_rust_legacy_is(src: *const c_void, src_size: usize) -> c_uint;
fn ZSTD_rust_legacy_get_decompressed_size(src: *const c_void, src_size: usize) -> u64;
fn ZSTD_rust_legacy_find_compressed_size(src: *const c_void, src_size: usize) -> usize;
fn ZSTD_rust_legacy_frame_size_info(
src: *const c_void,
src_size: usize,
compressed_size: *mut usize,
decompressed_bound: *mut u64,
nb_blocks: *mut usize,
) -> usize;
fn ZSTD_rust_legacy_decompress(
dst: *mut c_void,
dst_capacity: usize,
src: *const c_void,
src_size: usize,
dict: *const c_void,
dict_size: usize,
) -> usize;
fn ZSTD_rust_legacy_decompress_stream(
dctx: *mut ZSTD_DCtx,
output: *mut ZSTD_outBuffer,
input: *mut ZSTD_inBuffer,
dict: *const c_void,
dict_size: usize,
) -> usize;
fn ZSTD_rust_legacy_free_stream(dctx: *mut ZSTD_DCtx);
fn ZSTD_decompressBlock_internal(
dctx: *mut ZSTD_DCtx,
dst: *mut c_void,
dst_capacity: usize,
src: *const c_void,
src_size: usize,
streaming: c_int,
) -> usize;
fn ZSTD_checkContinuity(dctx: *mut ZSTD_DCtx, dst: *const c_void, dst_size: usize);
}
#[inline]
unsafe fn field<T: Copy>(slot: *mut c_void) -> T {
unsafe { slot.cast::<T>().read() }
}
#[inline]
unsafe fn set_field<T>(slot: *mut c_void, value: T) {
unsafe { slot.cast::<T>().write(value) }
}
unsafe fn dctx_view(dctx: *mut ZSTD_DCtx) -> ZSTD_rustDctxView {
let mut view = MaybeUninit::<ZSTD_rustDctxView>::zeroed();
unsafe { ZSTD_rust_dctx_view(dctx, view.as_mut_ptr()) };
unsafe { view.assume_init() }
}
#[inline]
fn frame_header_prefix(format: c_int) -> usize {
if format == ZSTD_F_ZSTD1 {
5
} else {
1
}
}
#[inline]
fn frame_header_min(format: c_int) -> usize {
if format == ZSTD_F_ZSTD1 {
6
} else {
2
}
}
#[inline]
fn window_log_max() -> usize {
if MEM_32bits() {
ZSTD_WINDOWLOG_MAX_32
} else {
ZSTD_WINDOWLOG_MAX_64
}
}
#[inline]
unsafe fn const_ptr_add(ptr: *const u8, amount: usize) -> *const u8 {
if ptr.is_null() {
debug_assert_eq!(amount, 0);
ptr
} else {
unsafe { ptr.add(amount) }
}
}
#[inline]
unsafe fn ptr_distance(end: *const u8, start: *const u8) -> usize {
(end as usize).wrapping_sub(start as usize)
}
#[inline]
unsafe fn copy_bytes(dst: *mut u8, src: *const u8, len: usize) {
if len != 0 {
unsafe { ptr::copy(src, dst, len) };
}
}
#[inline]
unsafe fn limit_copy(dst: *mut u8, dst_capacity: usize, src: *const u8, src_size: usize) -> usize {
let len = min(dst_capacity, src_size);
if len != 0 {
unsafe { ptr::copy_nonoverlapping(src, dst, len) };
}
len
}
#[inline]
fn default_custom_mem() -> ZSTD_customMem {
ZSTD_customMem {
custom_alloc: None,
custom_free: None,
opaque: ptr::null_mut(),
}
}
#[inline]
fn custom_mem_valid(custom_mem: ZSTD_customMem) -> bool {
custom_mem.custom_alloc.is_some() == custom_mem.custom_free.is_some()
}
#[inline]
unsafe fn get_frame_header_ptr(view: &ZSTD_rustDctxView) -> *mut ZSTD_FrameHeader {
view.f_params.cast()
}
#[inline]
unsafe fn entropy_ptr(view: &ZSTD_rustDctxView) -> *mut ZSTD_entropyDTables_t {
view.entropy.cast()
}
#[inline]
unsafe fn dctx_custom_mem(view: &ZSTD_rustDctxView) -> ZSTD_customMem {
unsafe { field(view.custom_mem) }
}
#[inline]
unsafe fn dctx_ddict(view: &ZSTD_rustDctxView) -> *const ZSTD_DDict {
unsafe { field(view.ddict) }
}
#[inline]
unsafe fn set_dctx_ddict(view: &ZSTD_rustDctxView, ddict: *const ZSTD_DDict) {
unsafe { set_field(view.ddict, ddict) }
}
#[inline]
unsafe fn dctx_ddict_local(view: &ZSTD_rustDctxView) -> *mut ZSTD_DDict {
unsafe { field(view.ddict_local) }
}
#[inline]
unsafe fn set_dctx_ddict_local(view: &ZSTD_rustDctxView, ddict: *mut ZSTD_DDict) {
unsafe { set_field(view.ddict_local, ddict) }
}
#[inline]
unsafe fn get_pointer(slot: *mut c_void) -> *const u8 {
unsafe { field(slot) }
}
#[inline]
unsafe fn set_pointer(slot: *mut c_void, value: *const u8) {
unsafe { set_field(slot, value) }
}
#[inline]
unsafe fn get_mut_pointer(slot: *mut c_void) -> *mut u8 {
unsafe { field(slot) }
}
#[inline]
unsafe fn set_mut_pointer(slot: *mut c_void, value: *mut u8) {
unsafe { set_field(slot, value) }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_isFrame(buffer: *const c_void, size: usize) -> c_uint {
if size < ZSTD_FRAMEIDSIZE || buffer.is_null() {
return 0;
}
let magic = unsafe { MEM_readLE32(buffer) };
if magic == ZSTD_MAGICNUMBER
|| (magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START
{
return 1;
}
unsafe { ZSTD_rust_legacy_is(buffer, size) }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_isSkippableFrame(buffer: *const c_void, size: usize) -> c_uint {
if size < ZSTD_FRAMEIDSIZE || buffer.is_null() {
return 0;
}
u32::from(
unsafe { MEM_readLE32(buffer) } & ZSTD_MAGIC_SKIPPABLE_MASK == ZSTD_MAGIC_SKIPPABLE_START,
)
}
unsafe fn frame_header_size_internal(src: *const u8, src_size: usize, format: c_int) -> usize {
let min_input_size = frame_header_prefix(format);
if src_size < min_input_size {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
let fhd = unsafe { *src.add(min_input_size - 1) };
let dict_id = fhd & 3;
let single_segment = (fhd >> 5) & 1;
let fcs_id = fhd >> 6;
let did_size = [0usize, 1, 2, 4][dict_id as usize];
let fcs_size = [0usize, 2, 4, 8][fcs_id as usize];
min_input_size
+ usize::from(single_segment == 0)
+ did_size
+ fcs_size
+ usize::from(single_segment != 0 && fcs_id == 0)
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_frameHeaderSize(src: *const c_void, src_size: usize) -> usize {
unsafe { frame_header_size_internal(src.cast(), src_size, ZSTD_F_ZSTD1) }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_getFrameHeader_advanced(
zfh: *mut ZSTD_FrameHeader,
src: *const c_void,
src_size: usize,
format: c_int,
) -> usize {
let min_input_size = frame_header_prefix(format);
if src_size != 0 && src.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
if src_size < min_input_size {
if src_size != 0 && format != ZSTD_F_ZSTD1_MAGICLESS {
let mut header = ZSTD_MAGICNUMBER.to_le_bytes();
unsafe {
ptr::copy_nonoverlapping(src.cast::<u8>(), header.as_mut_ptr(), min(4, src_size))
};
if u32::from_le_bytes(header) != ZSTD_MAGICNUMBER {
header = ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes();
unsafe {
ptr::copy_nonoverlapping(
src.cast::<u8>(),
header.as_mut_ptr(),
min(4, src_size),
)
};
if u32::from_le_bytes(header) & ZSTD_MAGIC_SKIPPABLE_MASK
!= ZSTD_MAGIC_SKIPPABLE_START
{
return ERROR(ZstdErrorCode::PrefixUnknown);
}
}
}
return min_input_size;
}
if zfh.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
unsafe { zfh.write(ZSTD_FrameHeader::default()) };
let ip = src.cast::<u8>();
if format != ZSTD_F_ZSTD1_MAGICLESS && unsafe { MEM_readLE32(src) } != ZSTD_MAGICNUMBER {
let magic = unsafe { MEM_readLE32(src) };
if magic & ZSTD_MAGIC_SKIPPABLE_MASK == ZSTD_MAGIC_SKIPPABLE_START {
if src_size < ZSTD_SKIPPABLEHEADERSIZE {
return ZSTD_SKIPPABLEHEADERSIZE;
}
unsafe {
(*zfh).frame_type = ZSTD_SKIPPABLE_FRAME;
(*zfh).dict_id = magic - ZSTD_MAGIC_SKIPPABLE_START;
(*zfh).header_size = ZSTD_SKIPPABLEHEADERSIZE as c_uint;
(*zfh).frame_content_size = MEM_readLE32(ip.add(ZSTD_FRAMEIDSIZE).cast()) as u64;
}
return 0;
}
return ERROR(ZstdErrorCode::PrefixUnknown);
}
let fh_size = unsafe { frame_header_size_internal(ip, src_size, format) };
if ERR_isError(fh_size) {
return fh_size;
}
if src_size < fh_size {
return fh_size;
}
unsafe { (*zfh).header_size = fh_size as c_uint };
let fhd = unsafe { *ip.add(min_input_size - 1) };
if fhd & 0x08 != 0 {
return ERROR(ZstdErrorCode::FrameParameterUnsupported);
}
let dict_id_size_code = fhd & 3;
let checksum_flag = (fhd >> 2) & 1;
let single_segment = (fhd >> 5) & 1;
let fcs_id = fhd >> 6;
let mut pos = min_input_size;
let mut window_size = 0u64;
let mut dict_id = 0u32;
let mut frame_content_size = ZSTD_CONTENTSIZE_UNKNOWN;
if single_segment == 0 {
let wl = unsafe { *ip.add(pos) };
pos += 1;
let window_log = usize::from(wl >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
if window_log > window_log_max() {
return ERROR(ZstdErrorCode::FrameParameterWindowTooLarge);
}
window_size = 1u64 << window_log;
window_size = window_size.wrapping_add((window_size >> 3) * u64::from(wl & 7));
}
match dict_id_size_code {
0 => {}
1 => {
dict_id = unsafe { *ip.add(pos) } as u32;
pos += 1;
}
2 => {
dict_id = unsafe { MEM_readLE16(ip.add(pos).cast()) as u32 };
pos += 2;
}
_ => {
dict_id = unsafe { MEM_readLE32(ip.add(pos).cast()) };
pos += 4;
}
}
match fcs_id {
0 => {
if single_segment != 0 {
frame_content_size = unsafe { *ip.add(pos) } as u64;
}
}
1 => frame_content_size = unsafe { MEM_readLE16(ip.add(pos).cast()) as u64 + 256 },
2 => frame_content_size = unsafe { MEM_readLE32(ip.add(pos).cast()) as u64 },
_ => frame_content_size = unsafe { MEM_readLE64(ip.add(pos).cast()) },
}
if single_segment != 0 {
window_size = frame_content_size;
}
unsafe {
(*zfh).frame_type = ZSTD_FRAME;
(*zfh).frame_content_size = frame_content_size;
(*zfh).window_size = window_size;
(*zfh).block_size_max = min(window_size, ZSTD_BLOCKSIZE_MAX as u64) as c_uint;
(*zfh).dict_id = dict_id;
(*zfh).checksum_flag = checksum_flag as c_uint;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_getFrameHeader(
zfh: *mut ZSTD_FrameHeader,
src: *const c_void,
src_size: usize,
) -> usize {
unsafe { ZSTD_getFrameHeader_advanced(zfh, src, src_size, ZSTD_F_ZSTD1) }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_getFrameContentSize(src: *const c_void, src_size: usize) -> u64 {
if unsafe { ZSTD_rust_legacy_is(src, src_size) } != 0 {
let size = unsafe { ZSTD_rust_legacy_get_decompressed_size(src, src_size) };
return if size == 0 {
ZSTD_CONTENTSIZE_UNKNOWN
} else {
size
};
}
let mut zfh = ZSTD_FrameHeader::default();
if unsafe { ZSTD_getFrameHeader(&mut zfh, src, src_size) } != 0 {
return ZSTD_CONTENTSIZE_ERROR;
}
if zfh.frame_type == ZSTD_SKIPPABLE_FRAME {
0
} else {
zfh.frame_content_size
}
}
unsafe fn read_skippable_frame_size(src: *const u8, src_size: usize) -> usize {
if src_size < ZSTD_SKIPPABLEHEADERSIZE {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
let size = unsafe { MEM_readLE32(src.add(ZSTD_FRAMEIDSIZE).cast()) };
if size.wrapping_add(ZSTD_SKIPPABLEHEADERSIZE as u32) < size {
return ERROR(ZstdErrorCode::FrameParameterUnsupported);
}
let frame_size = ZSTD_SKIPPABLEHEADERSIZE + size as usize;
if frame_size > src_size {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
frame_size
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_readSkippableFrame(
dst: *mut c_void,
dst_capacity: usize,
magic_variant: *mut c_uint,
src: *const c_void,
src_size: usize,
) -> usize {
if src_size < ZSTD_SKIPPABLEHEADERSIZE {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
let src_u8 = src.cast::<u8>();
let magic = unsafe { MEM_readLE32(src) };
let frame_size = unsafe { read_skippable_frame_size(src_u8, src_size) };
if ERR_isError(frame_size) {
return frame_size;
}
let content_size = frame_size - ZSTD_SKIPPABLEHEADERSIZE;
if unsafe { ZSTD_isSkippableFrame(src, src_size) } == 0 {
return ERROR(ZstdErrorCode::FrameParameterUnsupported);
}
if content_size > dst_capacity {
return ERROR(ZstdErrorCode::DstSizeTooSmall);
}
if content_size != 0 && !dst.is_null() {
unsafe {
copy_bytes(
dst.cast(),
src_u8.add(ZSTD_SKIPPABLEHEADERSIZE),
content_size,
)
};
}
if !magic_variant.is_null() {
unsafe { magic_variant.write(magic - ZSTD_MAGIC_SKIPPABLE_START) };
}
content_size
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
struct FrameSizeInfo {
nb_blocks: usize,
compressed_size: usize,
decompressed_bound: u64,
}
#[inline]
fn error_frame_size_info(error: usize) -> FrameSizeInfo {
FrameSizeInfo {
nb_blocks: 0,
compressed_size: error,
decompressed_bound: ZSTD_CONTENTSIZE_ERROR,
}
}
unsafe fn find_frame_size_info(src: *const u8, src_size: usize, format: c_int) -> FrameSizeInfo {
if format == ZSTD_F_ZSTD1 && unsafe { ZSTD_rust_legacy_is(src.cast(), src_size) } != 0 {
let mut info = FrameSizeInfo::default();
let status = unsafe {
ZSTD_rust_legacy_frame_size_info(
src.cast(),
src_size,
&mut info.compressed_size,
&mut info.decompressed_bound,
&mut info.nb_blocks,
)
};
return if ERR_isError(status) {
error_frame_size_info(status)
} else {
info
};
}
if format == ZSTD_F_ZSTD1
&& src_size >= ZSTD_SKIPPABLEHEADERSIZE
&& unsafe { MEM_readLE32(src.cast()) } & ZSTD_MAGIC_SKIPPABLE_MASK
== ZSTD_MAGIC_SKIPPABLE_START
{
return FrameSizeInfo {
nb_blocks: 0,
compressed_size: unsafe { read_skippable_frame_size(src, src_size) },
decompressed_bound: 0,
};
}
let mut zfh = ZSTD_FrameHeader::default();
let header_result =
unsafe { ZSTD_getFrameHeader_advanced(&mut zfh, src.cast(), src_size, format) };
if ERR_isError(header_result) {
return error_frame_size_info(header_result);
}
if header_result != 0 {
return error_frame_size_info(ERROR(ZstdErrorCode::SrcSizeWrong));
}
let mut ip = unsafe { src.add(zfh.header_size as usize) };
let mut remaining = src_size - zfh.header_size as usize;
let mut nb_blocks = 0usize;
loop {
let mut block = BlockProperties::default();
let c_block_size = unsafe {
crate::zstd_decompress_block::ZSTD_getcBlockSize(
ip.cast(),
remaining,
(&mut block as *mut BlockProperties).cast(),
)
};
if ERR_isError(c_block_size) {
return error_frame_size_info(c_block_size);
}
let total_size = match ZSTD_BLOCKHEADERSIZE.checked_add(c_block_size) {
Some(size) => size,
None => return error_frame_size_info(ERROR(ZstdErrorCode::SrcSizeWrong)),
};
if total_size > remaining {
return error_frame_size_info(ERROR(ZstdErrorCode::SrcSizeWrong));
}
ip = unsafe { ip.add(total_size) };
remaining -= total_size;
nb_blocks += 1;
if block.last_block != 0 {
break;
}
}
if zfh.checksum_flag != 0 {
if remaining < 4 {
return error_frame_size_info(ERROR(ZstdErrorCode::SrcSizeWrong));
}
ip = unsafe { ip.add(4) };
}
FrameSizeInfo {
nb_blocks,
compressed_size: unsafe { ip.offset_from(src) as usize },
decompressed_bound: if zfh.frame_content_size != ZSTD_CONTENTSIZE_UNKNOWN {
zfh.frame_content_size
} else {
(nb_blocks as u64).wrapping_mul(zfh.block_size_max as u64)
},
}
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_findFrameCompressedSize(
src: *const c_void,
src_size: usize,
) -> usize {
unsafe { find_frame_size_info(src.cast(), src_size, ZSTD_F_ZSTD1).compressed_size }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_findDecompressedSize(src: *const c_void, mut src_size: usize) -> u64 {
let mut input = src.cast::<u8>();
let mut total = 0u64;
while src_size >= frame_header_prefix(ZSTD_F_ZSTD1) {
if unsafe { MEM_readLE32(input.cast()) } & ZSTD_MAGIC_SKIPPABLE_MASK
== ZSTD_MAGIC_SKIPPABLE_START
{
let size = unsafe { read_skippable_frame_size(input, src_size) };
if ERR_isError(size) {
return ZSTD_CONTENTSIZE_ERROR;
}
input = unsafe { input.add(size) };
src_size -= size;
continue;
}
let frame_size = unsafe { ZSTD_getFrameContentSize(input.cast(), src_size) };
if frame_size >= ZSTD_CONTENTSIZE_ERROR {
return frame_size;
}
let next = total.wrapping_add(frame_size);
if next < total {
return ZSTD_CONTENTSIZE_ERROR;
}
total = next;
let compressed = unsafe { ZSTD_findFrameCompressedSize(input.cast(), src_size) };
if ERR_isError(compressed) || compressed > src_size {
return ZSTD_CONTENTSIZE_ERROR;
}
input = unsafe { input.add(compressed) };
src_size -= compressed;
}
if src_size != 0 {
ZSTD_CONTENTSIZE_ERROR
} else {
total
}
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_getDecompressedSize(src: *const c_void, src_size: usize) -> u64 {
let result = unsafe { ZSTD_getFrameContentSize(src, src_size) };
if result >= ZSTD_CONTENTSIZE_ERROR {
0
} else {
result
}
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_decompressBound(src: *const c_void, mut src_size: usize) -> u64 {
let mut input = src.cast::<u8>();
let mut bound = 0u64;
while src_size != 0 {
let info = unsafe { find_frame_size_info(input, src_size, ZSTD_F_ZSTD1) };
if ERR_isError(info.compressed_size) || info.decompressed_bound == ZSTD_CONTENTSIZE_ERROR {
return ZSTD_CONTENTSIZE_ERROR;
}
if info.compressed_size > src_size {
return ZSTD_CONTENTSIZE_ERROR;
}
bound = bound.wrapping_add(info.decompressed_bound);
input = unsafe { input.add(info.compressed_size) };
src_size -= info.compressed_size;
}
bound
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_decompressionMargin(
src: *const c_void,
mut src_size: usize,
) -> usize {
let mut input = src.cast::<u8>();
let mut margin = 0usize;
let mut max_block_size = 0usize;
while src_size != 0 {
let info = unsafe { find_frame_size_info(input, src_size, ZSTD_F_ZSTD1) };
let mut zfh = ZSTD_FrameHeader::default();
let header = unsafe { ZSTD_getFrameHeader(&mut zfh, input.cast(), src_size) };
if ERR_isError(header) {
return header;
}
if header != 0
|| ERR_isError(info.compressed_size)
|| info.decompressed_bound == ZSTD_CONTENTSIZE_ERROR
{
return ERROR(ZstdErrorCode::CorruptionDetected);
}
if zfh.frame_type == ZSTD_FRAME {
margin = margin
.wrapping_add(zfh.header_size as usize)
.wrapping_add(if zfh.checksum_flag != 0 { 4 } else { 0 })
.wrapping_add(ZSTD_BLOCKHEADERSIZE.wrapping_mul(info.nb_blocks));
max_block_size = max(max_block_size, zfh.block_size_max as usize);
} else {
margin = margin.wrapping_add(info.compressed_size);
}
if info.compressed_size > src_size {
return ERROR(ZstdErrorCode::CorruptionDetected);
}
input = unsafe { input.add(info.compressed_size) };
src_size -= info.compressed_size;
}
margin.wrapping_add(max_block_size)
}
unsafe fn ref_dict_content(view: &ZSTD_rustDctxView, dict: *const u8, dict_size: usize) -> usize {
let previous = unsafe { get_pointer(view.previous_dst_end) };
let prefix = unsafe { get_pointer(view.prefix_start) };
unsafe {
set_pointer(view.dict_end, previous);
/* Do the same address arithmetic as the C implementation without
* forming a Rust pointer outside of an allocation. These are virtual
* history addresses and are only compared/subtracted by the block
* decoder, never dereferenced until they again name live history. */
let history = (previous as usize).wrapping_sub(prefix as usize);
set_pointer(
view.virtual_start,
(dict as usize).wrapping_sub(history) as *const u8,
);
set_pointer(view.prefix_start, dict);
set_pointer(view.previous_dst_end, const_ptr_add(dict, dict_size));
if !view.fuzz_begin.is_null() {
set_pointer(view.fuzz_begin, dict);
set_pointer(view.fuzz_end, const_ptr_add(dict, dict_size));
}
}
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_loadDEntropy(
entropy: *mut ZSTD_entropyDTables_t,
dict: *const c_void,
dict_size: usize,
) -> usize {
if dict_size <= 8 || dict.is_null() {
return ERROR(ZstdErrorCode::DictionaryCorrupted);
}
let mut dict_ptr = unsafe { dict.cast::<u8>().add(8) };
let dict_end = unsafe { dict.cast::<u8>().add(dict_size) };
let workspace = entropy.cast::<c_void>();
let workspace_size = size_of::<crate::zstd_decompress_block::ZSTD_seqSymbol>()
* ((1 << LL_FSE_LOG) + (1 << OFF_FSE_LOG) + (1 << ML_FSE_LOG) + 3);
let huf_size = unsafe {
#[cfg(feature = "huf-force-decompress-x1")]
{
HUF_readDTableX1_wksp(
(*entropy).huf_table.as_mut_ptr(),
dict_ptr.cast(),
ptr_distance(dict_end, dict_ptr),
workspace,
workspace_size,
0,
)
}
#[cfg(not(feature = "huf-force-decompress-x1"))]
{
HUF_readDTableX2_wksp(
(*entropy).huf_table.as_mut_ptr(),
dict_ptr.cast(),
ptr_distance(dict_end, dict_ptr),
workspace,
workspace_size,
0,
)
}
};
if ERR_isError(huf_size) {
return ERROR(ZstdErrorCode::DictionaryCorrupted);
}
dict_ptr = unsafe { dict_ptr.add(huf_size) };
unsafe fn load_table(
table: *mut crate::zstd_decompress_block::ZSTD_seqSymbol,
max_symbol: usize,
max_log: usize,
base: *const u32,
bits: *const u8,
workspace: *mut u32,
dict_ptr: *const u8,
dict_end: *const u8,
) -> Result<usize, usize> {
let mut norm = [0i16; MAX_ML + 1];
let mut max = max_symbol as c_uint;
let mut log = 0u32;
let size = unsafe {
FSE_readNCount(
norm.as_mut_ptr(),
&mut max,
&mut log,
dict_ptr.cast(),
ptr_distance(dict_end, dict_ptr),
)
};
if ERR_isError(size) || max as usize > max_symbol || log as usize > max_log {
return Err(ERROR(ZstdErrorCode::DictionaryCorrupted));
}
unsafe {
crate::zstd_decompress_block::ZSTD_buildFSETable(
table,
norm.as_ptr(),
max,
base,
bits,
log,
workspace.cast(),
ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 * size_of::<u32>(),
0,
);
}
Ok(size)
}
let entropy_ref = unsafe { &mut *entropy };
let off_size = match unsafe {
load_table(
entropy_ref.of_table.as_mut_ptr(),
MAX_OFF,
OFF_FSE_LOG,
OF_BASE.as_ptr(),
OF_BITS.as_ptr(),
entropy_ref.workspace.as_mut_ptr(),
dict_ptr,
dict_end,
)
} {
Ok(size) => size,
Err(error) => return error,
};
dict_ptr = unsafe { dict_ptr.add(off_size) };
let ml_size = match unsafe {
load_table(
entropy_ref.ml_table.as_mut_ptr(),
MAX_ML,
ML_FSE_LOG,
ML_BASE.as_ptr(),
ML_BITS.as_ptr(),
entropy_ref.workspace.as_mut_ptr(),
dict_ptr,
dict_end,
)
} {
Ok(size) => size,
Err(error) => return error,
};
dict_ptr = unsafe { dict_ptr.add(ml_size) };
let ll_size = match unsafe {
load_table(
entropy_ref.ll_table.as_mut_ptr(),
MAX_LL,
LL_FSE_LOG,
LL_BASE.as_ptr(),
LL_BITS.as_ptr(),
entropy_ref.workspace.as_mut_ptr(),
dict_ptr,
dict_end,
)
} {
Ok(size) => size,
Err(error) => return error,
};
dict_ptr = unsafe { dict_ptr.add(ll_size) };
if unsafe { ptr_distance(dict_end, dict_ptr) } < 12 {
return ERROR(ZstdErrorCode::DictionaryCorrupted);
}
let content_size = unsafe { ptr_distance(dict_end, dict_ptr.add(12)) };
for rep in &mut entropy_ref.rep {
let value = unsafe { MEM_readLE32(dict_ptr.cast()) };
dict_ptr = unsafe { dict_ptr.add(4) };
if value == 0 || value as usize > content_size {
return ERROR(ZstdErrorCode::DictionaryCorrupted);
}
*rep = value;
}
unsafe { dict_ptr.offset_from(dict.cast()) as usize }
}
#[repr(C)]
struct DDictHashSet {
table: *mut *const ZSTD_DDict,
size: usize,
count: usize,
}
unsafe fn ddict_hash_index(set: *const DDictHashSet, dict_id: u32) -> usize {
let hash = unsafe { XXH64((&dict_id as *const u32).cast(), size_of::<u32>(), 0) };
hash as usize & (unsafe { (*set).size } - 1)
}
unsafe fn ddict_hashset_create(custom_mem: ZSTD_customMem) -> *mut DDictHashSet {
let set = unsafe { ZSTD_rust_custom_malloc(size_of::<DDictHashSet>(), custom_mem) }
.cast::<DDictHashSet>();
if set.is_null() {
return ptr::null_mut();
}
let table = unsafe { ZSTD_rust_custom_calloc(64 * size_of::<*const ZSTD_DDict>(), custom_mem) }
.cast::<*const ZSTD_DDict>();
if table.is_null() {
unsafe { ZSTD_rust_custom_free(set.cast(), custom_mem) };
return ptr::null_mut();
}
unsafe {
set.write(DDictHashSet {
table,
size: 64,
count: 0,
});
}
set
}
unsafe fn ddict_hashset_free(set: *mut DDictHashSet, custom_mem: ZSTD_customMem) {
if set.is_null() {
return;
}
unsafe {
ZSTD_rust_custom_free((*set).table.cast(), custom_mem);
ZSTD_rust_custom_free(set.cast(), custom_mem);
}
}
unsafe fn ddict_hashset_emplace(set: *mut DDictHashSet, ddict: *const ZSTD_DDict) -> usize {
let dict_id = unsafe { ZSTD_getDictID_fromDDict(ddict) };
let mut index = unsafe { ddict_hash_index(set, dict_id) };
let mask = unsafe { (*set).size } - 1;
if unsafe { (*set).count == (*set).size } {
return ERROR(ZstdErrorCode::Generic);
}
while !unsafe { *(*set).table.add(index) }.is_null() {
if unsafe { ZSTD_getDictID_fromDDict(*(*set).table.add(index)) } == dict_id {
unsafe { (*set).table.add(index).write(ddict) };
return 0;
}
index = (index + 1) & mask;
}
unsafe {
(*set).table.add(index).write(ddict);
(*set).count += 1;
}
0
}
unsafe fn ddict_hashset_expand(set: *mut DDictHashSet, custom_mem: ZSTD_customMem) -> usize {
let old_table = unsafe { (*set).table };
let old_size = unsafe { (*set).size };
let new_size = match old_size.checked_mul(2) {
Some(size) => size,
None => return ERROR(ZstdErrorCode::MemoryAllocation),
};
let new_table =
unsafe { ZSTD_rust_custom_calloc(new_size * size_of::<*const ZSTD_DDict>(), custom_mem) }
.cast::<*const ZSTD_DDict>();
if new_table.is_null() {
return ERROR(ZstdErrorCode::MemoryAllocation);
}
unsafe {
(*set).table = new_table;
(*set).size = new_size;
(*set).count = 0;
for index in 0..old_size {
let ddict = *old_table.add(index);
if !ddict.is_null() {
let result = ddict_hashset_emplace(set, ddict);
if ERR_isError(result) {
return result;
}
}
}
ZSTD_rust_custom_free(old_table.cast(), custom_mem);
}
0
}
unsafe fn ddict_hashset_add(
set: *mut DDictHashSet,
ddict: *const ZSTD_DDict,
custom_mem: ZSTD_customMem,
) -> usize {
let should_expand = unsafe { (*set).count }
.wrapping_mul(4)
.wrapping_div(unsafe { (*set).size })
.wrapping_mul(3)
!= 0;
if should_expand {
let result = unsafe { ddict_hashset_expand(set, custom_mem) };
if ERR_isError(result) {
return result;
}
}
unsafe { ddict_hashset_emplace(set, ddict) }
}
unsafe fn ddict_hashset_get(set: *const DDictHashSet, dict_id: u32) -> *const ZSTD_DDict {
let mut index = unsafe { ddict_hash_index(set, dict_id) };
let mask = unsafe { (*set).size } - 1;
loop {
let ddict = unsafe { *(*set).table.add(index) };
let current_id = unsafe { ZSTD_getDictID_fromDDict(ddict) };
if current_id == dict_id || current_id == 0 {
return ddict;
}
index = (index + 1) & mask;
}
}
unsafe fn reset_parameters(view: &ZSTD_rustDctxView) {
unsafe {
set_field(view.format, ZSTD_F_ZSTD1);
set_field(
view.max_window_size,
ZSTD_rust_dctx_default_max_window_size(),
);
set_field(view.out_buffer_mode, ZSTD_BM_BUFFERED);
set_field(view.force_ignore_checksum, ZSTD_D_VALIDATE_CHECKSUM);
set_field(view.ref_multiple_ddicts, ZSTD_RMD_REF_SINGLE_DDICT);
set_field(view.disable_huf_asm, 0 as c_int);
set_field(view.max_block_size_param, 0 as c_int);
}
}
unsafe fn init_dctx_internal(view: &ZSTD_rustDctxView) {
unsafe {
set_field(view.static_size, 0usize);
set_dctx_ddict(view, ptr::null());
set_dctx_ddict_local(view, ptr::null_mut());
set_pointer(view.dict_end, ptr::null());
set_field(view.ddict_is_cold, 0 as c_int);
set_field(view.dict_uses, ZSTD_DONT_USE);
set_mut_pointer(view.in_buff, ptr::null_mut());
set_field(view.in_buff_size, 0usize);
set_field(view.out_buff_size, 0usize);
set_field(view.stream_stage, ZDSS_INIT);
if !view.legacy_context.is_null() {
set_field(view.legacy_context, ptr::null_mut::<c_void>());
set_field(view.previous_legacy_version, 0u32);
set_field(view.legacy_version, 0u32);
}
set_field(view.no_forward_progress, 0 as c_int);
set_field(view.oversized_duration, 0usize);
set_field(view.is_frame_decompression, 1 as c_int);
set_field(view.ddict_set, ptr::null_mut::<DDictHashSet>());
reset_parameters(view);
if !view.fuzz_end.is_null() {
set_pointer(view.fuzz_end, ptr::null());
}
ZSTD_rust_dctx_init_platform(view.dctx.cast());
}
}
unsafe fn clear_dict(view: &ZSTD_rustDctxView) {
unsafe {
let local = dctx_ddict_local(view);
if !local.is_null() {
ZSTD_freeDDict(local);
}
set_dctx_ddict_local(view, ptr::null_mut());
set_dctx_ddict(view, ptr::null());
set_field(view.dict_uses, ZSTD_DONT_USE);
}
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_sizeof_DCtx(dctx: *const ZSTD_DCtx) -> usize {
if dctx.is_null() {
return 0;
}
let view = unsafe { dctx_view(dctx.cast_mut()) };
let local = unsafe { dctx_ddict_local(&view) };
let ddict_size = if local.is_null() {
0
} else {
unsafe { crate::zstd_ddict::ZSTD_sizeof_DDict(local) }
};
view.dctx_size
.wrapping_add(ddict_size)
.wrapping_add(unsafe { field::<usize>(view.in_buff_size) })
.wrapping_add(unsafe { field::<usize>(view.out_buff_size) })
}
#[no_mangle]
pub extern "C" fn ZSTD_estimateDCtxSize() -> usize {
unsafe { ZSTD_rust_dctx_sizeof() }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_initStaticDCtx(
workspace: *mut c_void,
workspace_size: usize,
) -> *mut ZSTD_DCtx {
let dctx_size = unsafe { ZSTD_rust_dctx_sizeof() };
if workspace.is_null() || (workspace as usize & 7) != 0 || workspace_size < dctx_size {
return ptr::null_mut();
}
let dctx = workspace.cast::<ZSTD_DCtx>();
let view = unsafe { dctx_view(dctx) };
unsafe {
set_field(view.custom_mem, default_custom_mem());
init_dctx_internal(&view);
set_field(view.static_size, workspace_size);
set_mut_pointer(view.in_buff, workspace.cast::<u8>().add(dctx_size));
}
dctx
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_createDCtx_advanced(custom_mem: ZSTD_customMem) -> *mut ZSTD_DCtx {
if !custom_mem_valid(custom_mem) {
return ptr::null_mut();
}
let dctx = unsafe { ZSTD_rust_dctx_alloc(custom_mem) };
if dctx.is_null() {
return ptr::null_mut();
}
let view = unsafe { dctx_view(dctx) };
unsafe {
set_field(view.custom_mem, custom_mem);
init_dctx_internal(&view);
}
dctx
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_createDCtx() -> *mut ZSTD_DCtx {
unsafe { ZSTD_createDCtx_advanced(default_custom_mem()) }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_freeDCtx(dctx: *mut ZSTD_DCtx) -> usize {
if dctx.is_null() {
return 0;
}
let view = unsafe { dctx_view(dctx) };
if unsafe { field::<usize>(view.static_size) } != 0 {
return ERROR(ZstdErrorCode::MemoryAllocation);
}
let custom_mem = unsafe { dctx_custom_mem(&view) };
unsafe {
clear_dict(&view);
let in_buff = get_mut_pointer(view.in_buff);
ZSTD_rust_custom_free(in_buff.cast(), custom_mem);
set_mut_pointer(view.in_buff, ptr::null_mut());
let set: *mut DDictHashSet = field(view.ddict_set);
ddict_hashset_free(set, custom_mem);
set_field(view.ddict_set, ptr::null_mut::<DDictHashSet>());
if !view.legacy_context.is_null() {
ZSTD_rust_legacy_free_stream(dctx);
}
ZSTD_rust_dctx_free_storage(dctx, custom_mem);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_copyDCtx(dst: *mut ZSTD_DCtx, src: *const ZSTD_DCtx) {
unsafe { ZSTD_rust_dctx_copy_prefix(dst, src) }
}
unsafe fn select_frame_ddict(view: &ZSTD_rustDctxView) {
let set: *mut DDictHashSet = unsafe { field(view.ddict_set) };
if set.is_null() || unsafe { dctx_ddict(view) }.is_null() {
return;
}
let dict_id = unsafe { (*get_frame_header_ptr(view)).dict_id };
let ddict = unsafe { ddict_hashset_get(set, dict_id) };
if !ddict.is_null() {
unsafe {
clear_dict(view);
set_field(view.dict_id, dict_id);
set_dctx_ddict(view, ddict);
set_field(view.dict_uses, ZSTD_USE_INDEFINITELY);
}
}
}
unsafe fn decode_frame_header(
view: &ZSTD_rustDctxView,
src: *const u8,
header_size: usize,
) -> usize {
let format = unsafe { field::<c_int>(view.format) };
let result = unsafe {
ZSTD_getFrameHeader_advanced(get_frame_header_ptr(view), src.cast(), header_size, format)
};
if ERR_isError(result) {
return result;
}
if result != 0 {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
if unsafe { field::<c_int>(view.ref_multiple_ddicts) } == ZSTD_RMD_REF_MULTIPLE_DDICTS
&& !unsafe { field::<*mut DDictHashSet>(view.ddict_set) }.is_null()
{
unsafe { select_frame_ddict(view) };
}
if view.fuzz_begin.is_null()
&& unsafe { (*get_frame_header_ptr(view)).dict_id } != 0
&& unsafe { field::<u32>(view.dict_id) } != unsafe { (*get_frame_header_ptr(view)).dict_id }
{
return ERROR(ZstdErrorCode::DictionaryWrong);
}
let validate = u32::from(
unsafe { (*get_frame_header_ptr(view)).checksum_flag } != 0
&& unsafe { field::<c_int>(view.force_ignore_checksum) } == ZSTD_D_VALIDATE_CHECKSUM,
);
unsafe {
set_field(view.validate_checksum, validate);
if validate != 0 {
let _ = XXH64_reset(view.xxh_state.cast::<XXH64_state_t>(), 0);
}
let processed = field::<u64>(view.processed_c_size).wrapping_add(header_size as u64);
set_field(view.processed_c_size, processed);
}
0
}
unsafe fn decompress_begin(view: &ZSTD_rustDctxView) -> usize {
unsafe {
ZSTD_rust_dctx_trace_begin(view.dctx.cast());
let format = field::<c_int>(view.format);
set_field(view.expected, frame_header_prefix(format));
set_field(view.stage, ZSTDDS_GET_FRAME_HEADER_SIZE);
set_field(view.processed_c_size, 0u64);
set_field(view.decoded_size, 0u64);
set_pointer(view.previous_dst_end, ptr::null());
set_pointer(view.prefix_start, ptr::null());
set_pointer(view.virtual_start, ptr::null());
set_pointer(view.dict_end, ptr::null());
let entropy = &mut *entropy_ptr(view);
entropy.huf_table[0] = (ZSTD_HUFFDTABLE_CAPACITY_LOG as u32).wrapping_mul(0x0100_0001);
set_field(view.lit_entropy, 0u32);
set_field(view.fse_entropy, 0u32);
set_field(view.dict_id, 0u32);
set_field(view.b_type, BT_RESERVED);
set_field(view.is_frame_decompression, 1 as c_int);
entropy.rep = [1, 4, 8];
set_field(view.llt_ptr, entropy.ll_table.as_ptr());
set_field(view.mlt_ptr, entropy.ml_table.as_ptr());
set_field(view.oft_ptr, entropy.of_table.as_ptr());
set_field(view.huf_ptr, entropy.huf_table.as_ptr());
}
0
}
unsafe fn decompress_insert_dictionary(
view: &ZSTD_rustDctxView,
mut dict: *const u8,
mut dict_size: usize,
) -> usize {
if dict_size < 8 || unsafe { MEM_readLE32(dict.cast()) } != ZSTD_MAGIC_DICTIONARY {
return unsafe { ref_dict_content(view, dict, dict_size) };
}
unsafe {
set_field(
view.dict_id,
MEM_readLE32(dict.add(ZSTD_FRAMEIDSIZE).cast()),
)
};
let entropy_size = unsafe { ZSTD_loadDEntropy(entropy_ptr(view), dict.cast(), dict_size) };
if ERR_isError(entropy_size) {
return ERROR(ZstdErrorCode::DictionaryCorrupted);
}
dict = unsafe { dict.add(entropy_size) };
dict_size -= entropy_size;
unsafe {
set_field(view.lit_entropy, 1u32);
set_field(view.fse_entropy, 1u32);
ref_dict_content(view, dict, dict_size)
}
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_decompressBegin(dctx: *mut ZSTD_DCtx) -> usize {
if dctx.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
unsafe { decompress_begin(&dctx_view(dctx)) }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_decompressBegin_usingDict(
dctx: *mut ZSTD_DCtx,
dict: *const c_void,
dict_size: usize,
) -> usize {
let view = unsafe { dctx_view(dctx) };
let result = unsafe { decompress_begin(&view) };
if ERR_isError(result) {
return result;
}
if !dict.is_null() && dict_size != 0 {
let result = unsafe { decompress_insert_dictionary(&view, dict.cast(), dict_size) };
if ERR_isError(result) {
return ERROR(ZstdErrorCode::DictionaryCorrupted);
}
}
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_decompressBegin_usingDDict(
dctx: *mut ZSTD_DCtx,
ddict: *const ZSTD_DDict,
) -> usize {
let view = unsafe { dctx_view(dctx) };
if !ddict.is_null() {
let dict_start = unsafe { ZSTD_DDict_dictContent(ddict) };
let dict_size = unsafe { ZSTD_DDict_dictSize(ddict) };
let dict_end = unsafe { dict_start.cast::<u8>().add(dict_size).cast::<c_void>() };
unsafe {
set_field(
view.ddict_is_cold,
c_int::from(get_pointer(view.dict_end).cast::<c_void>() != dict_end),
)
};
}
let result = unsafe { decompress_begin(&view) };
if ERR_isError(result) {
return result;
}
if !ddict.is_null() {
unsafe { ZSTD_copyDDictParameters(dctx.cast(), ddict) };
}
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_getDictID_fromDict(dict: *const c_void, dict_size: usize) -> c_uint {
if dict.is_null() || dict_size < 8 || unsafe { MEM_readLE32(dict) } != ZSTD_MAGIC_DICTIONARY {
0
} else {
unsafe { MEM_readLE32(dict.cast::<u8>().add(ZSTD_FRAMEIDSIZE).cast()) }
}
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_getDictID_fromFrame(src: *const c_void, src_size: usize) -> c_uint {
let mut zfh = ZSTD_FrameHeader::default();
if ERR_isError(unsafe { ZSTD_getFrameHeader(&mut zfh, src, src_size) }) {
0
} else {
zfh.dict_id
}
}
/*-*************************************************************
* Frame decoding
***************************************************************/
#[inline]
unsafe fn copy_raw_block(
dst: *mut u8,
dst_capacity: usize,
src: *const u8,
src_size: usize,
) -> usize {
if src_size > dst_capacity {
return ERROR(ZstdErrorCode::DstSizeTooSmall);
}
if dst.is_null() {
return if src_size == 0 {
0
} else {
ERROR(ZstdErrorCode::DstBufferNull)
};
}
unsafe { copy_bytes(dst, src, src_size) };
src_size
}
#[inline]
unsafe fn set_rle_block(
dst: *mut u8,
dst_capacity: usize,
byte: u8,
regenerated_size: usize,
) -> usize {
if regenerated_size > dst_capacity {
return ERROR(ZstdErrorCode::DstSizeTooSmall);
}
if dst.is_null() {
return if regenerated_size == 0 {
0
} else {
ERROR(ZstdErrorCode::DstBufferNull)
};
}
if regenerated_size != 0 {
unsafe { dst.write_bytes(byte, regenerated_size) };
}
regenerated_size
}
/// Decode exactly one non-skippable modern frame and advance the caller's
/// input cursor. The state preparation deliberately stays in the public
/// `decompressBegin*()` calls, just as in the C implementation.
unsafe fn decompress_frame(
dctx: *mut ZSTD_DCtx,
view: &ZSTD_rustDctxView,
dst: *mut c_void,
dst_capacity: usize,
src_ptr: &mut *const u8,
src_size_ptr: &mut usize,
) -> usize {
let istart = *src_ptr;
let mut ip = istart;
let ostart = dst.cast::<u8>();
/* `dst == NULL, dstCapacity == 0` is supported for empty frames. A
* wrapping endpoint preserves C's address-only calculation until a
* block decoder reports the appropriate null/size error. */
let oend = ostart.wrapping_add(dst_capacity);
let mut op = ostart;
let mut remaining = *src_size_ptr;
let format = unsafe { field::<c_int>(view.format) };
if remaining < frame_header_min(format) + ZSTD_BLOCKHEADERSIZE {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
let header_size =
unsafe { frame_header_size_internal(ip, frame_header_prefix(format), format) };
if ERR_isError(header_size) {
return header_size;
}
if remaining < header_size + ZSTD_BLOCKHEADERSIZE {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
let result = unsafe { decode_frame_header(view, ip, header_size) };
if ERR_isError(result) {
return result;
}
ip = unsafe { ip.add(header_size) };
remaining -= header_size;
let max_block_size_param = unsafe { field::<c_int>(view.max_block_size_param) };
if max_block_size_param != 0 {
let mut params = unsafe { field::<ZSTD_FrameHeader>(view.f_params) };
params.block_size_max = min(params.block_size_max, max_block_size_param as c_uint);
unsafe { set_field(view.f_params, params) };
}
loop {
let mut block = BlockProperties::default();
let c_block_size = unsafe {
crate::zstd_decompress_block::ZSTD_getcBlockSize(
ip.cast(),
remaining,
(&mut block as *mut BlockProperties).cast(),
)
};
if ERR_isError(c_block_size) {
return c_block_size;
}
ip = unsafe { ip.add(ZSTD_BLOCKHEADERSIZE) };
remaining -= ZSTD_BLOCKHEADERSIZE;
if c_block_size > remaining {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
let mut block_end = oend;
if (ip as usize) >= (op as usize) && (ip as usize) < (block_end as usize) {
block_end = op.wrapping_add((ip as usize).wrapping_sub(op as usize));
}
let block_capacity = (block_end as usize).wrapping_sub(op as usize);
let decoded_size = match block.block_type {
BT_COMPRESSED => unsafe {
ZSTD_decompressBlock_internal(
dctx,
op.cast(),
block_capacity,
ip.cast(),
c_block_size,
0,
)
},
/* This deliberately uses `oend`, not `block_end`: memmove is
* overlap-safe for raw blocks. */
BT_RAW => unsafe {
copy_raw_block(
op,
(oend as usize).wrapping_sub(op as usize),
ip,
c_block_size,
)
},
BT_RLE => {
if c_block_size == 0 {
return ERROR(ZstdErrorCode::CorruptionDetected);
}
unsafe { set_rle_block(op, block_capacity, *ip, block.orig_size as usize) }
}
_ => ERROR(ZstdErrorCode::CorruptionDetected),
};
if ERR_isError(decoded_size) {
return decoded_size;
}
if unsafe { field::<u32>(view.validate_checksum) } != 0 {
let _ = unsafe {
XXH64_update(
view.xxh_state.cast::<XXH64_state_t>(),
op.cast(),
decoded_size,
)
};
}
if decoded_size != 0 {
op = unsafe { op.add(decoded_size) };
}
ip = unsafe { ip.add(c_block_size) };
remaining -= c_block_size;
if block.last_block != 0 {
break;
}
}
let params = unsafe { field::<ZSTD_FrameHeader>(view.f_params) };
let decoded = (op as usize).wrapping_sub(ostart as usize);
if params.frame_content_size != ZSTD_CONTENTSIZE_UNKNOWN
&& decoded as u64 != params.frame_content_size
{
return ERROR(ZstdErrorCode::CorruptionDetected);
}
if params.checksum_flag != 0 {
if remaining < 4 {
return ERROR(ZstdErrorCode::ChecksumWrong);
}
if unsafe { field::<c_int>(view.force_ignore_checksum) } == ZSTD_D_VALIDATE_CHECKSUM {
let calculated = unsafe { XXH64_digest(view.xxh_state.cast::<XXH64_state_t>()) } as u32;
let read = unsafe { MEM_readLE32(ip.cast()) };
if calculated != read {
return ERROR(ZstdErrorCode::ChecksumWrong);
}
}
ip = unsafe { ip.add(4) };
remaining -= 4;
}
unsafe {
ZSTD_rust_dctx_trace_end(
dctx,
decoded as u64,
(ip as usize).wrapping_sub(istart as usize) as u64,
0,
);
}
*src_ptr = ip;
*src_size_ptr = remaining;
decoded
}
unsafe fn decompress_multi_frame(
dctx: *mut ZSTD_DCtx,
dst: *mut c_void,
mut dst_capacity: usize,
src: *const c_void,
mut src_size: usize,
mut dict: *const c_void,
mut dict_size: usize,
ddict: *const ZSTD_DDict,
) -> usize {
if dctx.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(dctx) };
if !ddict.is_null() {
dict = unsafe { ZSTD_DDict_dictContent(ddict) };
dict_size = unsafe { ZSTD_DDict_dictSize(ddict) };
}
let dst_start = dst.cast::<u8>();
let mut output = dst_start;
let mut input = src.cast::<u8>();
let mut more_than_one_frame = false;
let starting_input = frame_header_prefix(unsafe { field::<c_int>(view.format) });
while src_size >= starting_input {
if unsafe { field::<c_int>(view.format) } == ZSTD_F_ZSTD1
&& unsafe { ZSTD_rust_legacy_is(input.cast(), src_size) } != 0
{
let frame_size =
unsafe { ZSTD_rust_legacy_find_compressed_size(input.cast(), src_size) };
if ERR_isError(frame_size) {
return frame_size;
}
if unsafe { field::<usize>(view.static_size) } != 0 {
return ERROR(ZstdErrorCode::MemoryAllocation);
}
if frame_size > src_size {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
let decoded = unsafe {
ZSTD_rust_legacy_decompress(
output.cast(),
dst_capacity,
input.cast(),
frame_size,
dict,
dict_size,
)
};
if ERR_isError(decoded) {
return decoded;
}
let expected = unsafe { ZSTD_getFrameContentSize(input.cast(), src_size) };
if expected == ZSTD_CONTENTSIZE_ERROR
|| (expected != ZSTD_CONTENTSIZE_UNKNOWN && expected != decoded as u64)
{
return ERROR(ZstdErrorCode::CorruptionDetected);
}
if decoded > dst_capacity {
return ERROR(ZstdErrorCode::DstSizeTooSmall);
}
if decoded != 0 {
output = unsafe { output.add(decoded) };
}
dst_capacity -= decoded;
input = unsafe { input.add(frame_size) };
src_size -= frame_size;
continue;
}
if unsafe { field::<c_int>(view.format) } == ZSTD_F_ZSTD1 && src_size >= ZSTD_FRAMEIDSIZE {
let magic = unsafe { MEM_readLE32(input.cast()) };
if magic & ZSTD_MAGIC_SKIPPABLE_MASK == ZSTD_MAGIC_SKIPPABLE_START {
let size = unsafe { read_skippable_frame_size(input, src_size) };
if ERR_isError(size) {
return size;
}
input = unsafe { input.add(size) };
src_size -= size;
continue;
}
}
let init = if !ddict.is_null() {
unsafe { ZSTD_decompressBegin_usingDDict(dctx, ddict) }
} else {
unsafe { ZSTD_decompressBegin_usingDict(dctx, dict, dict_size) }
};
if ERR_isError(init) {
return init;
}
unsafe { ZSTD_checkContinuity(dctx, output.cast(), dst_capacity) };
let decoded = unsafe {
decompress_frame(
dctx,
&view,
output.cast(),
dst_capacity,
&mut input,
&mut src_size,
)
};
if decoded == ERROR(ZstdErrorCode::PrefixUnknown) && more_than_one_frame {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
if ERR_isError(decoded) {
return decoded;
}
if decoded > dst_capacity {
return ERROR(ZstdErrorCode::DstSizeTooSmall);
}
if decoded != 0 {
output = unsafe { output.add(decoded) };
}
dst_capacity -= decoded;
more_than_one_frame = true;
}
if src_size != 0 {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
(output as usize).wrapping_sub(dst_start as usize)
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_insertBlock(
dctx: *mut ZSTD_DCtx,
block_start: *const c_void,
block_size: usize,
) -> usize {
if dctx.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
unsafe {
ZSTD_checkContinuity(dctx, block_start, block_size);
let view = dctx_view(dctx);
set_pointer(
view.previous_dst_end,
const_ptr_add(block_start.cast(), block_size),
);
}
block_size
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_decompress_usingDict(
dctx: *mut ZSTD_DCtx,
dst: *mut c_void,
dst_capacity: usize,
src: *const c_void,
src_size: usize,
dict: *const c_void,
dict_size: usize,
) -> usize {
unsafe {
decompress_multi_frame(
dctx,
dst,
dst_capacity,
src,
src_size,
dict,
dict_size,
ptr::null(),
)
}
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_decompress_usingDDict(
dctx: *mut ZSTD_DCtx,
dst: *mut c_void,
dst_capacity: usize,
src: *const c_void,
src_size: usize,
ddict: *const ZSTD_DDict,
) -> usize {
unsafe {
decompress_multi_frame(
dctx,
dst,
dst_capacity,
src,
src_size,
ptr::null(),
0,
ddict,
)
}
}
unsafe fn get_ddict(view: &ZSTD_rustDctxView) -> *const ZSTD_DDict {
match unsafe { field::<c_int>(view.dict_uses) } {
ZSTD_DONT_USE => {
unsafe { clear_dict(view) };
ptr::null()
}
ZSTD_USE_INDEFINITELY => unsafe { dctx_ddict(view) },
ZSTD_USE_ONCE => {
unsafe { set_field(view.dict_uses, ZSTD_DONT_USE) };
unsafe { dctx_ddict(view) }
}
_ => {
unsafe { clear_dict(view) };
ptr::null()
}
}
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_decompressDCtx(
dctx: *mut ZSTD_DCtx,
dst: *mut c_void,
dst_capacity: usize,
src: *const c_void,
src_size: usize,
) -> usize {
if dctx.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(dctx) };
let ddict = unsafe { get_ddict(&view) };
unsafe { ZSTD_decompress_usingDDict(dctx, dst, dst_capacity, src, src_size, ddict) }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_decompress(
dst: *mut c_void,
dst_capacity: usize,
src: *const c_void,
src_size: usize,
) -> usize {
if unsafe { ZSTD_rust_heapmode() } < 1 {
return unsafe { ZSTD_rust_decompress_stack(dst, dst_capacity, src, src_size) };
}
let dctx = unsafe { ZSTD_createDCtx() };
if dctx.is_null() {
return ERROR(ZstdErrorCode::MemoryAllocation);
}
let result = unsafe { ZSTD_decompressDCtx(dctx, dst, dst_capacity, src, src_size) };
let _ = unsafe { ZSTD_freeDCtx(dctx) };
result
}
/*-**************************************
* Advanced bufferless decompression
****************************************/
#[inline]
unsafe fn next_src_size_with_input_size(view: &ZSTD_rustDctxView, input_size: usize) -> usize {
let stage = unsafe { field::<c_int>(view.stage) };
if (stage == ZSTDDS_DECOMPRESS_BLOCK || stage == ZSTDDS_DECOMPRESS_LAST_BLOCK)
&& unsafe { field::<c_int>(view.b_type) } == BT_RAW
{
let expected = unsafe { field::<usize>(view.expected) };
return max(1, min(input_size, expected));
}
unsafe { field::<usize>(view.expected) }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_nextSrcSizeToDecompress(dctx: *mut ZSTD_DCtx) -> usize {
if dctx.is_null() {
return 0;
}
let view = unsafe { dctx_view(dctx) };
unsafe { field(view.expected) }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_nextInputType(dctx: *mut ZSTD_DCtx) -> c_int {
if dctx.is_null() {
return ZSTD_NIT_FRAME_HEADER;
}
let view = unsafe { dctx_view(dctx) };
match unsafe { field::<c_int>(view.stage) } {
ZSTDDS_GET_FRAME_HEADER_SIZE | ZSTDDS_DECODE_FRAME_HEADER => ZSTD_NIT_FRAME_HEADER,
ZSTDDS_DECODE_BLOCK_HEADER => ZSTD_NIT_BLOCK_HEADER,
ZSTDDS_DECOMPRESS_BLOCK => ZSTD_NIT_BLOCK,
ZSTDDS_DECOMPRESS_LAST_BLOCK => ZSTD_NIT_LAST_BLOCK,
ZSTDDS_CHECK_CHECKSUM => ZSTD_NIT_CHECKSUM,
ZSTDDS_DECODE_SKIPPABLE_HEADER | ZSTDDS_SKIP_FRAME => ZSTD_NIT_SKIPPABLE_FRAME,
_ => ZSTD_NIT_FRAME_HEADER,
}
}
#[inline]
unsafe fn is_skip_frame(view: &ZSTD_rustDctxView) -> bool {
(unsafe { field::<c_int>(view.stage) }) == ZSTDDS_SKIP_FRAME
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_decompressContinue(
dctx: *mut ZSTD_DCtx,
dst: *mut c_void,
dst_capacity: usize,
src: *const c_void,
src_size: usize,
) -> usize {
if dctx.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(dctx) };
if src_size != unsafe { next_src_size_with_input_size(&view, src_size) } {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
unsafe { ZSTD_checkContinuity(dctx, dst.cast(), dst_capacity) };
let processed = unsafe { field::<u64>(view.processed_c_size) }.wrapping_add(src_size as u64);
unsafe { set_field(view.processed_c_size, processed) };
match unsafe { field::<c_int>(view.stage) } {
ZSTDDS_GET_FRAME_HEADER_SIZE => {
let format = unsafe { field::<c_int>(view.format) };
let header_buffer = view.header_buffer.cast::<u8>();
if format == ZSTD_F_ZSTD1
&& src_size >= ZSTD_FRAMEIDSIZE
&& unsafe { MEM_readLE32(src) } & ZSTD_MAGIC_SKIPPABLE_MASK
== ZSTD_MAGIC_SKIPPABLE_START
{
unsafe { copy_bytes(header_buffer, src.cast(), src_size) };
unsafe {
set_field(view.expected, ZSTD_SKIPPABLEHEADERSIZE - src_size);
set_field(view.stage, ZSTDDS_DECODE_SKIPPABLE_HEADER);
}
return 0;
}
let header_size = unsafe { frame_header_size_internal(src.cast(), src_size, format) };
if ERR_isError(header_size) {
return header_size;
}
unsafe {
copy_bytes(header_buffer, src.cast(), src_size);
set_field(view.header_size, header_size);
set_field(view.expected, header_size - src_size);
set_field(view.stage, ZSTDDS_DECODE_FRAME_HEADER);
}
0
}
ZSTDDS_DECODE_FRAME_HEADER => {
let header_size = unsafe { field::<usize>(view.header_size) };
let offset = header_size - src_size;
unsafe {
copy_bytes(
view.header_buffer.cast::<u8>().add(offset),
src.cast(),
src_size,
);
}
let result =
unsafe { decode_frame_header(&view, view.header_buffer.cast(), header_size) };
if ERR_isError(result) {
return result;
}
unsafe {
set_field(view.expected, ZSTD_BLOCKHEADERSIZE);
set_field(view.stage, ZSTDDS_DECODE_BLOCK_HEADER);
}
0
}
ZSTDDS_DECODE_BLOCK_HEADER => {
let mut block = BlockProperties::default();
let c_block_size = unsafe {
crate::zstd_decompress_block::ZSTD_getcBlockSize(
src,
ZSTD_BLOCKHEADERSIZE,
(&mut block as *mut BlockProperties).cast(),
)
};
if ERR_isError(c_block_size) {
return c_block_size;
}
let params = unsafe { field::<ZSTD_FrameHeader>(view.f_params) };
if c_block_size > params.block_size_max as usize {
return ERROR(ZstdErrorCode::CorruptionDetected);
}
unsafe {
set_field(view.expected, c_block_size);
set_field(view.b_type, block.block_type);
set_field(view.rle_size, block.orig_size as usize);
}
if c_block_size != 0 {
unsafe {
set_field(
view.stage,
if block.last_block != 0 {
ZSTDDS_DECOMPRESS_LAST_BLOCK
} else {
ZSTDDS_DECOMPRESS_BLOCK
},
);
}
return 0;
}
unsafe {
if block.last_block != 0 {
if params.checksum_flag != 0 {
set_field(view.expected, 4usize);
set_field(view.stage, ZSTDDS_CHECK_CHECKSUM);
} else {
set_field(view.expected, 0usize);
set_field(view.stage, ZSTDDS_GET_FRAME_HEADER_SIZE);
}
} else {
set_field(view.expected, ZSTD_BLOCKHEADERSIZE);
set_field(view.stage, ZSTDDS_DECODE_BLOCK_HEADER);
}
}
0
}
ZSTDDS_DECOMPRESS_BLOCK | ZSTDDS_DECOMPRESS_LAST_BLOCK => {
let stage = unsafe { field::<c_int>(view.stage) };
let b_type = unsafe { field::<c_int>(view.b_type) };
let decoded = match b_type {
BT_COMPRESSED => {
let result = unsafe {
ZSTD_decompressBlock_internal(dctx, dst, dst_capacity, src, src_size, 1)
};
unsafe { set_field(view.expected, 0usize) };
result
}
BT_RAW => {
let result =
unsafe { copy_raw_block(dst.cast(), dst_capacity, src.cast(), src_size) };
if ERR_isError(result) {
return result;
}
let expected = unsafe { field::<usize>(view.expected) } - result;
unsafe { set_field(view.expected, expected) };
result
}
BT_RLE => {
if src_size == 0 {
return ERROR(ZstdErrorCode::CorruptionDetected);
}
let result = unsafe {
set_rle_block(
dst.cast(),
dst_capacity,
*src.cast::<u8>(),
field::<usize>(view.rle_size),
)
};
unsafe { set_field(view.expected, 0usize) };
result
}
_ => return ERROR(ZstdErrorCode::CorruptionDetected),
};
if ERR_isError(decoded) {
return decoded;
}
let params = unsafe { field::<ZSTD_FrameHeader>(view.f_params) };
if decoded > params.block_size_max as usize {
return ERROR(ZstdErrorCode::CorruptionDetected);
}
let decoded_total =
unsafe { field::<u64>(view.decoded_size) }.wrapping_add(decoded as u64);
unsafe {
set_field(view.decoded_size, decoded_total);
if field::<u32>(view.validate_checksum) != 0 {
let _ = XXH64_update(view.xxh_state.cast::<XXH64_state_t>(), dst, decoded);
}
set_pointer(view.previous_dst_end, const_ptr_add(dst.cast(), decoded));
}
if unsafe { field::<usize>(view.expected) } != 0 {
return decoded;
}
if stage == ZSTDDS_DECOMPRESS_LAST_BLOCK {
if params.frame_content_size != ZSTD_CONTENTSIZE_UNKNOWN
&& decoded_total != params.frame_content_size
{
return ERROR(ZstdErrorCode::CorruptionDetected);
}
unsafe {
if params.checksum_flag != 0 {
set_field(view.expected, 4usize);
set_field(view.stage, ZSTDDS_CHECK_CHECKSUM);
} else {
ZSTD_rust_dctx_trace_end(
dctx,
decoded_total,
field::<u64>(view.processed_c_size),
1,
);
set_field(view.expected, 0usize);
set_field(view.stage, ZSTDDS_GET_FRAME_HEADER_SIZE);
}
}
} else {
unsafe {
set_field(view.stage, ZSTDDS_DECODE_BLOCK_HEADER);
set_field(view.expected, ZSTD_BLOCKHEADERSIZE);
}
}
decoded
}
ZSTDDS_CHECK_CHECKSUM => {
if src_size != 4 {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
if unsafe { field::<u32>(view.validate_checksum) } != 0 {
let calculated =
unsafe { XXH64_digest(view.xxh_state.cast::<XXH64_state_t>()) } as u32;
let read = unsafe { MEM_readLE32(src) };
if calculated != read {
return ERROR(ZstdErrorCode::ChecksumWrong);
}
}
unsafe {
ZSTD_rust_dctx_trace_end(
dctx,
field::<u64>(view.decoded_size),
field::<u64>(view.processed_c_size),
1,
);
set_field(view.expected, 0usize);
set_field(view.stage, ZSTDDS_GET_FRAME_HEADER_SIZE);
}
0
}
ZSTDDS_DECODE_SKIPPABLE_HEADER => {
if src_size > ZSTD_SKIPPABLEHEADERSIZE {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
unsafe {
let header = view.header_buffer.cast::<u8>();
copy_bytes(
header.add(ZSTD_SKIPPABLEHEADERSIZE - src_size),
src.cast(),
src_size,
);
set_field(
view.expected,
MEM_readLE32(header.add(ZSTD_FRAMEIDSIZE).cast()) as usize,
);
set_field(view.stage, ZSTDDS_SKIP_FRAME);
}
0
}
ZSTDDS_SKIP_FRAME => {
unsafe {
set_field(view.expected, 0usize);
set_field(view.stage, ZSTDDS_GET_FRAME_HEADER_SIZE);
}
0
}
_ => ERROR(ZstdErrorCode::Generic),
}
}
/*-**************************************
* Streaming context management
****************************************/
#[no_mangle]
pub unsafe extern "C" fn ZSTD_createDStream() -> *mut ZSTD_DStream {
unsafe { ZSTD_createDCtx() }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_initStaticDStream(
workspace: *mut c_void,
workspace_size: usize,
) -> *mut ZSTD_DStream {
unsafe { ZSTD_initStaticDCtx(workspace, workspace_size) }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_createDStream_advanced(
custom_mem: ZSTD_customMem,
) -> *mut ZSTD_DStream {
unsafe { ZSTD_createDCtx_advanced(custom_mem) }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_freeDStream(zds: *mut ZSTD_DStream) -> usize {
unsafe { ZSTD_freeDCtx(zds) }
}
#[no_mangle]
pub extern "C" fn ZSTD_DStreamInSize() -> usize {
ZSTD_BLOCKSIZE_MAX + ZSTD_BLOCKHEADERSIZE
}
#[no_mangle]
pub extern "C" fn ZSTD_DStreamOutSize() -> usize {
ZSTD_BLOCKSIZE_MAX
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_DCtx_loadDictionary_advanced(
dctx: *mut ZSTD_DCtx,
dict: *const c_void,
dict_size: usize,
dict_load_method: c_int,
dict_content_type: c_int,
) -> usize {
if dctx.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(dctx) };
if unsafe { field::<c_int>(view.stream_stage) } != ZDSS_INIT {
return ERROR(ZstdErrorCode::StageWrong);
}
unsafe { clear_dict(&view) };
if !dict.is_null() && dict_size != 0 {
let ddict = unsafe {
ZSTD_rust_create_ddict(
dict,
dict_size,
dict_load_method,
dict_content_type,
dctx_custom_mem(&view),
)
};
if ddict.is_null() {
return ERROR(ZstdErrorCode::MemoryAllocation);
}
unsafe {
set_dctx_ddict_local(&view, ddict);
set_dctx_ddict(&view, ddict);
set_field(view.dict_uses, ZSTD_USE_INDEFINITELY);
}
}
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_DCtx_loadDictionary_byReference(
dctx: *mut ZSTD_DCtx,
dict: *const c_void,
dict_size: usize,
) -> usize {
unsafe {
ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dict_size, ZSTD_DLM_BY_REF, ZSTD_DCT_AUTO)
}
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_DCtx_loadDictionary(
dctx: *mut ZSTD_DCtx,
dict: *const c_void,
dict_size: usize,
) -> usize {
unsafe {
ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dict_size, ZSTD_DLM_BY_COPY, ZSTD_DCT_AUTO)
}
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_DCtx_refPrefix_advanced(
dctx: *mut ZSTD_DCtx,
prefix: *const c_void,
prefix_size: usize,
dict_content_type: c_int,
) -> usize {
let result = unsafe {
ZSTD_DCtx_loadDictionary_advanced(
dctx,
prefix,
prefix_size,
ZSTD_DLM_BY_REF,
dict_content_type,
)
};
if ERR_isError(result) {
return result;
}
if dctx.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(dctx) };
unsafe { set_field(view.dict_uses, ZSTD_USE_ONCE) };
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_DCtx_refPrefix(
dctx: *mut ZSTD_DCtx,
prefix: *const c_void,
prefix_size: usize,
) -> usize {
unsafe { ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefix_size, ZSTD_DCT_RAW_CONTENT) }
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_initDStream_usingDict(
zds: *mut ZSTD_DStream,
dict: *const c_void,
dict_size: usize,
) -> usize {
let result = unsafe { ZSTD_DCtx_reset(zds, ZSTD_RESET_SESSION_ONLY) };
if ERR_isError(result) {
return result;
}
let result = unsafe { ZSTD_DCtx_loadDictionary(zds, dict, dict_size) };
if ERR_isError(result) {
return result;
}
if zds.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(zds) };
frame_header_prefix(unsafe { field::<c_int>(view.format) })
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_initDStream(zds: *mut ZSTD_DStream) -> usize {
let result = unsafe { ZSTD_DCtx_reset(zds, ZSTD_RESET_SESSION_ONLY) };
if ERR_isError(result) {
return result;
}
let result = unsafe { ZSTD_DCtx_refDDict(zds, ptr::null()) };
if ERR_isError(result) {
return result;
}
if zds.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(zds) };
frame_header_prefix(unsafe { field::<c_int>(view.format) })
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_initDStream_usingDDict(
zds: *mut ZSTD_DStream,
ddict: *const ZSTD_DDict,
) -> usize {
let result = unsafe { ZSTD_DCtx_reset(zds, ZSTD_RESET_SESSION_ONLY) };
if ERR_isError(result) {
return result;
}
let result = unsafe { ZSTD_DCtx_refDDict(zds, ddict) };
if ERR_isError(result) {
return result;
}
if zds.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(zds) };
frame_header_prefix(unsafe { field::<c_int>(view.format) })
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_resetDStream(zds: *mut ZSTD_DStream) -> usize {
let result = unsafe { ZSTD_DCtx_reset(zds, ZSTD_RESET_SESSION_ONLY) };
if ERR_isError(result) {
return result;
}
if zds.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(zds) };
frame_header_prefix(unsafe { field::<c_int>(view.format) })
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_DCtx_refDDict(
dctx: *mut ZSTD_DCtx,
ddict: *const ZSTD_DDict,
) -> usize {
if dctx.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(dctx) };
if unsafe { field::<c_int>(view.stream_stage) } != ZDSS_INIT {
return ERROR(ZstdErrorCode::StageWrong);
}
unsafe { clear_dict(&view) };
if ddict.is_null() {
return 0;
}
unsafe {
set_dctx_ddict(&view, ddict);
set_field(view.dict_uses, ZSTD_USE_INDEFINITELY);
}
if unsafe { field::<c_int>(view.ref_multiple_ddicts) } == ZSTD_RMD_REF_MULTIPLE_DDICTS {
let mut set: *mut DDictHashSet = unsafe { field(view.ddict_set) };
if set.is_null() {
if unsafe { field::<usize>(view.static_size) } != 0 {
return ERROR(ZstdErrorCode::ParameterUnsupported);
}
set = unsafe { ddict_hashset_create(dctx_custom_mem(&view)) };
if set.is_null() {
return ERROR(ZstdErrorCode::MemoryAllocation);
}
unsafe { set_field(view.ddict_set, set) };
}
let result = unsafe { ddict_hashset_add(set, ddict, dctx_custom_mem(&view)) };
if ERR_isError(result) {
return result;
}
}
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_DCtx_setMaxWindowSize(
dctx: *mut ZSTD_DCtx,
max_window_size: usize,
) -> usize {
if dctx.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(dctx) };
let bounds = ZSTD_dParam_getBounds(ZSTD_D_WINDOW_LOG_MAX);
let minimum = 1usize << bounds.lower_bound;
let maximum = 1usize << bounds.upper_bound;
if unsafe { field::<c_int>(view.stream_stage) } != ZDSS_INIT {
return ERROR(ZstdErrorCode::StageWrong);
}
if max_window_size < minimum || max_window_size > maximum {
return ERROR(ZstdErrorCode::ParameterOutOfBound);
}
unsafe { set_field(view.max_window_size, max_window_size) };
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_DCtx_setFormat(dctx: *mut ZSTD_DCtx, format: c_int) -> usize {
unsafe { ZSTD_DCtx_setParameter(dctx, ZSTD_D_FORMAT, format) }
}
#[no_mangle]
pub extern "C" fn ZSTD_dParam_getBounds(param: c_int) -> ZSTD_bounds {
match param {
ZSTD_D_WINDOW_LOG_MAX => ZSTD_bounds {
error: 0,
lower_bound: ZSTD_WINDOWLOG_ABSOLUTEMIN as c_int,
upper_bound: window_log_max() as c_int,
},
ZSTD_D_FORMAT => ZSTD_bounds {
error: 0,
lower_bound: ZSTD_F_ZSTD1,
upper_bound: ZSTD_F_ZSTD1_MAGICLESS,
},
ZSTD_D_STABLE_OUT_BUFFER => ZSTD_bounds {
error: 0,
lower_bound: ZSTD_BM_BUFFERED,
upper_bound: ZSTD_BM_STABLE,
},
ZSTD_D_FORCE_IGNORE_CHECKSUM => ZSTD_bounds {
error: 0,
lower_bound: ZSTD_D_VALIDATE_CHECKSUM,
upper_bound: ZSTD_D_IGNORE_CHECKSUM,
},
ZSTD_D_REF_MULTIPLE_DDICTS => ZSTD_bounds {
error: 0,
lower_bound: ZSTD_RMD_REF_SINGLE_DDICT,
upper_bound: ZSTD_RMD_REF_MULTIPLE_DDICTS,
},
ZSTD_D_DISABLE_HUFFMAN_ASSEMBLY => ZSTD_bounds {
error: 0,
lower_bound: 0,
upper_bound: 1,
},
ZSTD_D_MAX_BLOCK_SIZE => ZSTD_bounds {
error: 0,
lower_bound: ZSTD_BLOCKSIZE_MAX_MIN as c_int,
upper_bound: ZSTD_BLOCKSIZE_MAX as c_int,
},
_ => ZSTD_bounds {
error: ERROR(ZstdErrorCode::ParameterUnsupported),
lower_bound: 0,
upper_bound: 0,
},
}
}
#[inline]
fn dparam_within_bounds(param: c_int, value: c_int) -> bool {
let bounds = ZSTD_dParam_getBounds(param);
!ERR_isError(bounds.error) && value >= bounds.lower_bound && value <= bounds.upper_bound
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_DCtx_getParameter(
dctx: *mut ZSTD_DCtx,
param: c_int,
value: *mut c_int,
) -> usize {
if dctx.is_null() || value.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(dctx) };
let result = match param {
ZSTD_D_WINDOW_LOG_MAX => {
let window = unsafe { field::<usize>(view.max_window_size) } as u32;
(u32::BITS - 1 - window.leading_zeros()) as c_int
}
ZSTD_D_FORMAT => unsafe { field::<c_int>(view.format) },
ZSTD_D_STABLE_OUT_BUFFER => unsafe { field::<c_int>(view.out_buffer_mode) },
ZSTD_D_FORCE_IGNORE_CHECKSUM => unsafe { field::<c_int>(view.force_ignore_checksum) },
ZSTD_D_REF_MULTIPLE_DDICTS => unsafe { field::<c_int>(view.ref_multiple_ddicts) },
ZSTD_D_DISABLE_HUFFMAN_ASSEMBLY => unsafe { field::<c_int>(view.disable_huf_asm) },
ZSTD_D_MAX_BLOCK_SIZE => unsafe { field::<c_int>(view.max_block_size_param) },
_ => return ERROR(ZstdErrorCode::ParameterUnsupported),
};
unsafe { value.write(result) };
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_DCtx_setParameter(
dctx: *mut ZSTD_DCtx,
param: c_int,
mut value: c_int,
) -> usize {
if dctx.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(dctx) };
if unsafe { field::<c_int>(view.stream_stage) } != ZDSS_INIT {
return ERROR(ZstdErrorCode::StageWrong);
}
match param {
ZSTD_D_WINDOW_LOG_MAX => {
if value == 0 {
value = ZSTD_WINDOWLOG_LIMIT_DEFAULT as c_int;
}
if !dparam_within_bounds(param, value) {
return ERROR(ZstdErrorCode::ParameterOutOfBound);
}
unsafe { set_field(view.max_window_size, 1usize << value) };
}
ZSTD_D_FORMAT => {
if !dparam_within_bounds(param, value) {
return ERROR(ZstdErrorCode::ParameterOutOfBound);
}
unsafe { set_field(view.format, value) };
}
ZSTD_D_STABLE_OUT_BUFFER => {
if !dparam_within_bounds(param, value) {
return ERROR(ZstdErrorCode::ParameterOutOfBound);
}
unsafe { set_field(view.out_buffer_mode, value) };
}
ZSTD_D_FORCE_IGNORE_CHECKSUM => {
if !dparam_within_bounds(param, value) {
return ERROR(ZstdErrorCode::ParameterOutOfBound);
}
unsafe { set_field(view.force_ignore_checksum, value) };
}
ZSTD_D_REF_MULTIPLE_DDICTS => {
if !dparam_within_bounds(param, value) {
return ERROR(ZstdErrorCode::ParameterOutOfBound);
}
if unsafe { field::<usize>(view.static_size) } != 0 {
return ERROR(ZstdErrorCode::ParameterUnsupported);
}
unsafe { set_field(view.ref_multiple_ddicts, value) };
}
ZSTD_D_DISABLE_HUFFMAN_ASSEMBLY => {
if !dparam_within_bounds(param, value) {
return ERROR(ZstdErrorCode::ParameterOutOfBound);
}
unsafe { set_field(view.disable_huf_asm, c_int::from(value != 0)) };
}
ZSTD_D_MAX_BLOCK_SIZE => {
if value != 0 && !dparam_within_bounds(param, value) {
return ERROR(ZstdErrorCode::ParameterOutOfBound);
}
unsafe { set_field(view.max_block_size_param, value) };
}
_ => return ERROR(ZstdErrorCode::ParameterUnsupported),
}
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_DCtx_reset(dctx: *mut ZSTD_DCtx, reset: c_int) -> usize {
if dctx.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let view = unsafe { dctx_view(dctx) };
if reset == ZSTD_RESET_SESSION_ONLY || reset == ZSTD_RESET_SESSION_AND_PARAMETERS {
unsafe {
set_field(view.stream_stage, ZDSS_INIT);
set_field(view.no_forward_progress, 0 as c_int);
set_field(view.is_frame_decompression, 1 as c_int);
}
}
if reset == ZSTD_RESET_PARAMETERS || reset == ZSTD_RESET_SESSION_AND_PARAMETERS {
if unsafe { field::<c_int>(view.stream_stage) } != ZDSS_INIT {
return ERROR(ZstdErrorCode::StageWrong);
}
unsafe {
clear_dict(&view);
reset_parameters(&view);
}
}
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_sizeof_DStream(dctx: *const ZSTD_DStream) -> usize {
unsafe { ZSTD_sizeof_DCtx(dctx) }
}
unsafe fn decoding_buffer_size_internal(
window_size: u64,
frame_content_size: u64,
block_size_max: usize,
) -> usize {
let block_size = min(
min(window_size, ZSTD_BLOCKSIZE_MAX as u64) as usize,
block_size_max,
);
let needed_ring = window_size
.wrapping_add((block_size as u64).wrapping_mul(2))
.wrapping_add((WILDCOPY_OVERLENGTH as u64).wrapping_mul(2));
let needed = min(frame_content_size, needed_ring);
let result = needed as usize;
if result as u64 != needed {
return ERROR(ZstdErrorCode::FrameParameterWindowTooLarge);
}
result
}
#[no_mangle]
pub extern "C" fn ZSTD_decodingBufferSize_min(window_size: u64, frame_content_size: u64) -> usize {
unsafe { decoding_buffer_size_internal(window_size, frame_content_size, ZSTD_BLOCKSIZE_MAX) }
}
#[no_mangle]
pub extern "C" fn ZSTD_estimateDStreamSize(window_size: usize) -> usize {
let block_size = min(window_size, ZSTD_BLOCKSIZE_MAX);
let out_size = ZSTD_decodingBufferSize_min(window_size as u64, ZSTD_CONTENTSIZE_UNKNOWN);
ZSTD_estimateDCtxSize()
.wrapping_add(block_size)
.wrapping_add(out_size)
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_estimateDStreamSize_fromFrame(
src: *const c_void,
src_size: usize,
) -> usize {
let mut zfh = ZSTD_FrameHeader::default();
let result = unsafe { ZSTD_getFrameHeader(&mut zfh, src, src_size) };
if ERR_isError(result) {
return result;
}
if result != 0 {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
if zfh.window_size > (1u64 << window_log_max()) {
return ERROR(ZstdErrorCode::FrameParameterWindowTooLarge);
}
ZSTD_estimateDStreamSize(zfh.window_size as usize)
}
#[inline]
unsafe fn dctx_is_overflow(
view: &ZSTD_rustDctxView,
needed_in_size: usize,
needed_out_size: usize,
) -> bool {
let current = unsafe { field::<usize>(view.in_buff_size) }
.wrapping_add(unsafe { field::<usize>(view.out_buff_size) });
let needed = needed_in_size
.wrapping_add(needed_out_size)
.wrapping_mul(ZSTD_WORKSPACETOOLARGE_FACTOR);
current >= needed
}
#[inline]
unsafe fn update_oversized_duration(
view: &ZSTD_rustDctxView,
needed_in_size: usize,
needed_out_size: usize,
) {
let duration = if unsafe { dctx_is_overflow(view, needed_in_size, needed_out_size) } {
unsafe { field::<usize>(view.oversized_duration) }.wrapping_add(1)
} else {
0
};
unsafe { set_field(view.oversized_duration, duration) };
}
#[inline]
unsafe fn oversized_too_long(view: &ZSTD_rustDctxView) -> bool {
(unsafe { field::<usize>(view.oversized_duration) }) >= ZSTD_WORKSPACETOOLARGE_MAXDURATION
}
unsafe fn check_out_buffer(view: &ZSTD_rustDctxView, output: &ZSTD_outBuffer) -> usize {
if unsafe { field::<c_int>(view.out_buffer_mode) } != ZSTD_BM_STABLE
|| unsafe { field::<c_int>(view.stream_stage) } == ZDSS_INIT
{
return 0;
}
let expected = unsafe { field::<ZSTD_outBuffer>(view.expected_out_buffer) };
if expected.dst == output.dst && expected.size == output.size && expected.pos == output.pos {
0
} else {
ERROR(ZstdErrorCode::DstBufferWrong)
}
}
/// Invoke the bufferless state machine from the streaming adapter and translate
/// its output into either the rolling internal buffer or the stable user buffer.
unsafe fn decompress_continue_stream(
dctx: *mut ZSTD_DCtx,
view: &ZSTD_rustDctxView,
op: &mut *mut u8,
oend: *mut u8,
src: *const u8,
src_size: usize,
) -> usize {
let skip = unsafe { is_skip_frame(view) };
if unsafe { field::<c_int>(view.out_buffer_mode) } == ZSTD_BM_BUFFERED {
let out_start = unsafe { field::<usize>(view.out_start) };
let out_size = unsafe { field::<usize>(view.out_buff_size) };
let dst_size = if skip {
0
} else {
out_size.wrapping_sub(out_start)
};
let out_buff = unsafe { get_mut_pointer(view.out_buff) };
let decoded = unsafe {
ZSTD_decompressContinue(
dctx,
out_buff.wrapping_add(out_start).cast(),
dst_size,
src.cast(),
src_size,
)
};
if ERR_isError(decoded) {
return decoded;
}
unsafe {
if decoded == 0 && !skip {
set_field(view.stream_stage, ZDSS_READ);
} else {
set_field(view.out_end, out_start.wrapping_add(decoded));
set_field(view.stream_stage, ZDSS_FLUSH);
}
}
} else {
let dst_size = (oend as usize).wrapping_sub(*op as usize);
let decoded =
unsafe { ZSTD_decompressContinue(dctx, (*op).cast(), dst_size, src.cast(), src_size) };
if ERR_isError(decoded) {
return decoded;
}
if decoded != 0 {
*op = unsafe { (*op).add(decoded) };
}
unsafe { set_field(view.stream_stage, ZDSS_READ) };
}
0
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_decompressStream(
zds: *mut ZSTD_DStream,
output: *mut ZSTD_outBuffer,
input: *mut ZSTD_inBuffer,
) -> usize {
if zds.is_null() || output.is_null() || input.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let output_ref = unsafe { &mut *output };
let input_ref = unsafe { &mut *input };
if input_ref.pos > input_ref.size {
return ERROR(ZstdErrorCode::SrcSizeWrong);
}
if output_ref.pos > output_ref.size {
return ERROR(ZstdErrorCode::DstSizeTooSmall);
}
let view = unsafe { dctx_view(zds) };
let src = input_ref.src.cast::<u8>();
let istart = src.wrapping_add(input_ref.pos);
let iend = src.wrapping_add(input_ref.size);
let mut ip = istart;
let dst = output_ref.dst.cast::<u8>();
let ostart = dst.wrapping_add(output_ref.pos);
let oend = dst.wrapping_add(output_ref.size);
let mut op = ostart;
let mut some_more_work = true;
let output_check = unsafe { check_out_buffer(&view, output_ref) };
if ERR_isError(output_check) {
return output_check;
}
while some_more_work {
match unsafe { field::<c_int>(view.stream_stage) } {
ZDSS_INIT => {
unsafe {
set_field(view.stream_stage, ZDSS_LOAD_HEADER);
set_field(view.lh_size, 0usize);
set_field(view.in_pos, 0usize);
set_field(view.out_start, 0usize);
set_field(view.out_end, 0usize);
if !view.legacy_version.is_null() {
set_field(view.legacy_version, 0u32);
}
set_field(view.hostage_byte, 0u32);
set_field(view.expected_out_buffer, *output_ref);
}
continue;
}
ZDSS_LOAD_HEADER => {
if !view.legacy_version.is_null()
&& unsafe { field::<u32>(view.legacy_version) } != 0
{
let ddict = unsafe { dctx_ddict(&view) };
let dict = if ddict.is_null() {
ptr::null()
} else {
unsafe { ZSTD_DDict_dictContent(ddict) }
};
let dict_size = if ddict.is_null() {
0
} else {
unsafe { ZSTD_DDict_dictSize(ddict) }
};
return unsafe {
ZSTD_rust_legacy_decompress_stream(zds, output, input, dict, dict_size)
};
}
let lh_size = unsafe { field::<usize>(view.lh_size) };
let header_result = unsafe {
ZSTD_getFrameHeader_advanced(
get_frame_header_ptr(&view),
view.header_buffer.cast(),
lh_size,
field::<c_int>(view.format),
)
};
if unsafe { field::<c_int>(view.ref_multiple_ddicts) }
== ZSTD_RMD_REF_MULTIPLE_DDICTS
&& !unsafe { field::<*mut DDictHashSet>(view.ddict_set) }.is_null()
{
unsafe { select_frame_ddict(&view) };
}
if ERR_isError(header_result) {
let available = (iend as usize).wrapping_sub(istart as usize);
if unsafe { ZSTD_rust_legacy_is(istart.cast(), available) } != 0 {
if unsafe { field::<usize>(view.static_size) } != 0 {
return ERROR(ZstdErrorCode::MemoryAllocation);
}
let ddict = unsafe { get_ddict(&view) };
let dict = if ddict.is_null() {
ptr::null()
} else {
unsafe { ZSTD_DDict_dictContent(ddict) }
};
let dict_size = if ddict.is_null() {
0
} else {
unsafe { ZSTD_DDict_dictSize(ddict) }
};
return unsafe {
ZSTD_rust_legacy_decompress_stream(zds, output, input, dict, dict_size)
};
}
return header_result;
}
if header_result != 0 {
let to_load = header_result - lh_size;
let remaining_input = (iend as usize).wrapping_sub(ip as usize);
if to_load > remaining_input {
if remaining_input != 0 {
unsafe {
copy_bytes(
view.header_buffer.cast::<u8>().add(lh_size),
ip,
remaining_input,
);
set_field(view.lh_size, lh_size + remaining_input);
}
}
input_ref.pos = input_ref.size;
let check = unsafe {
ZSTD_getFrameHeader_advanced(
get_frame_header_ptr(&view),
view.header_buffer.cast(),
field::<usize>(view.lh_size),
field::<c_int>(view.format),
)
};
if ERR_isError(check) {
return check;
}
let minimum = max(
frame_header_min(unsafe { field::<c_int>(view.format) }),
header_result,
);
return minimum
.wrapping_sub(unsafe { field::<usize>(view.lh_size) })
.wrapping_add(ZSTD_BLOCKHEADERSIZE);
}
unsafe {
copy_bytes(view.header_buffer.cast::<u8>().add(lh_size), ip, to_load);
set_field(view.lh_size, header_result);
}
ip = unsafe { ip.add(to_load) };
continue;
}
let params = unsafe { field::<ZSTD_FrameHeader>(view.f_params) };
let available = (iend as usize).wrapping_sub(istart as usize);
if params.frame_content_size != ZSTD_CONTENTSIZE_UNKNOWN
&& params.frame_type != ZSTD_SKIPPABLE_FRAME
&& (oend as usize).wrapping_sub(op as usize)
>= params.frame_content_size as usize
{
let frame_size = unsafe {
find_frame_size_info(istart, available, field::<c_int>(view.format))
.compressed_size
};
if frame_size <= available {
let ddict = unsafe { get_ddict(&view) };
let decoded = unsafe {
ZSTD_decompress_usingDDict(
zds,
op.cast(),
(oend as usize).wrapping_sub(op as usize),
istart.cast(),
frame_size,
ddict,
)
};
if ERR_isError(decoded) {
return decoded;
}
ip = unsafe { istart.add(frame_size) };
if decoded != 0 {
op = unsafe { op.add(decoded) };
}
unsafe {
set_field(view.expected, 0usize);
set_field(view.stream_stage, ZDSS_INIT);
}
some_more_work = false;
continue;
}
}
if unsafe { field::<c_int>(view.out_buffer_mode) } == ZSTD_BM_STABLE
&& params.frame_type != ZSTD_SKIPPABLE_FRAME
&& params.frame_content_size != ZSTD_CONTENTSIZE_UNKNOWN
&& (oend as usize).wrapping_sub(op as usize)
< params.frame_content_size as usize
{
return ERROR(ZstdErrorCode::DstSizeTooSmall);
}
let ddict = unsafe { get_ddict(&view) };
let begin = unsafe { ZSTD_decompressBegin_usingDDict(zds, ddict) };
if ERR_isError(begin) {
return begin;
}
let format = unsafe { field::<c_int>(view.format) };
if format == ZSTD_F_ZSTD1
&& unsafe { MEM_readLE32(view.header_buffer) } & ZSTD_MAGIC_SKIPPABLE_MASK
== ZSTD_MAGIC_SKIPPABLE_START
{
unsafe {
set_field(
view.expected,
MEM_readLE32(
view.header_buffer.cast::<u8>().add(ZSTD_FRAMEIDSIZE).cast(),
) as usize,
);
set_field(view.stage, ZSTDDS_SKIP_FRAME);
}
} else {
let result = unsafe {
decode_frame_header(
&view,
view.header_buffer.cast(),
field::<usize>(view.lh_size),
)
};
if ERR_isError(result) {
return result;
}
unsafe {
set_field(view.expected, ZSTD_BLOCKHEADERSIZE);
set_field(view.stage, ZSTDDS_DECODE_BLOCK_HEADER);
}
}
let mut frame_params = unsafe { field::<ZSTD_FrameHeader>(view.f_params) };
frame_params.window_size =
max(frame_params.window_size, 1u64 << ZSTD_WINDOWLOG_ABSOLUTEMIN);
if frame_params.window_size > unsafe { field::<usize>(view.max_window_size) } as u64
{
return ERROR(ZstdErrorCode::FrameParameterWindowTooLarge);
}
let max_block_size_param = unsafe { field::<c_int>(view.max_block_size_param) };
if max_block_size_param != 0 {
frame_params.block_size_max =
min(frame_params.block_size_max, max_block_size_param as c_uint);
}
unsafe { set_field(view.f_params, frame_params) };
let needed_in_size = max(frame_params.block_size_max as usize, 4);
let needed_out_size =
if unsafe { field::<c_int>(view.out_buffer_mode) } == ZSTD_BM_BUFFERED {
let size = unsafe {
decoding_buffer_size_internal(
frame_params.window_size,
frame_params.frame_content_size,
frame_params.block_size_max as usize,
)
};
if ERR_isError(size) {
return size;
}
size
} else {
0
};
unsafe { update_oversized_duration(&view, needed_in_size, needed_out_size) };
let too_small = unsafe { field::<usize>(view.in_buff_size) } < needed_in_size
|| unsafe { field::<usize>(view.out_buff_size) } < needed_out_size;
let too_large = unsafe { oversized_too_long(&view) };
if too_small || too_large {
let buffer_size = needed_in_size.wrapping_add(needed_out_size);
if unsafe { field::<usize>(view.static_size) } != 0 {
let static_size = unsafe { field::<usize>(view.static_size) };
if buffer_size > static_size.wrapping_sub(view.dctx_size) {
return ERROR(ZstdErrorCode::MemoryAllocation);
}
} else {
unsafe {
ZSTD_rust_custom_free(
get_mut_pointer(view.in_buff).cast(),
dctx_custom_mem(&view),
);
set_field(view.in_buff_size, 0usize);
set_field(view.out_buff_size, 0usize);
}
let allocation =
unsafe { ZSTD_rust_custom_malloc(buffer_size, dctx_custom_mem(&view)) };
if allocation.is_null() {
return ERROR(ZstdErrorCode::MemoryAllocation);
}
unsafe { set_mut_pointer(view.in_buff, allocation.cast()) };
}
let in_buff = unsafe { get_mut_pointer(view.in_buff) };
unsafe {
set_field(view.in_buff_size, needed_in_size);
set_mut_pointer(view.out_buff, in_buff.wrapping_add(needed_in_size));
set_field(view.out_buff_size, needed_out_size);
}
}
unsafe { set_field(view.stream_stage, ZDSS_READ) };
continue;
}
ZDSS_READ => {
let available = (iend as usize).wrapping_sub(ip as usize);
let needed = unsafe { next_src_size_with_input_size(&view, available) };
if needed == 0 {
unsafe { set_field(view.stream_stage, ZDSS_INIT) };
some_more_work = false;
continue;
}
if available >= needed {
let result = unsafe {
decompress_continue_stream(zds, &view, &mut op, oend, ip, needed)
};
if ERR_isError(result) {
return result;
}
ip = unsafe { ip.add(needed) };
continue;
}
if ip == iend {
some_more_work = false;
continue;
}
unsafe { set_field(view.stream_stage, ZDSS_LOAD) };
continue;
}
ZDSS_LOAD => {
let needed = unsafe { field::<usize>(view.expected) };
let in_pos = unsafe { field::<usize>(view.in_pos) };
let to_load = needed.wrapping_sub(in_pos);
let skip = unsafe { is_skip_frame(&view) };
let available = (iend as usize).wrapping_sub(ip as usize);
let loaded = if skip {
min(to_load, available)
} else {
let in_size = unsafe { field::<usize>(view.in_buff_size) };
if to_load > in_size.wrapping_sub(in_pos) {
return ERROR(ZstdErrorCode::CorruptionDetected);
}
unsafe {
limit_copy(
get_mut_pointer(view.in_buff).wrapping_add(in_pos),
to_load,
ip,
available,
)
}
};
if loaded != 0 {
ip = unsafe { ip.add(loaded) };
unsafe { set_field(view.in_pos, in_pos + loaded) };
}
if loaded < to_load {
some_more_work = false;
continue;
}
unsafe { set_field(view.in_pos, 0usize) };
let result = unsafe {
decompress_continue_stream(
zds,
&view,
&mut op,
oend,
get_mut_pointer(view.in_buff).cast(),
needed,
)
};
if ERR_isError(result) {
return result;
}
continue;
}
ZDSS_FLUSH => {
let out_start = unsafe { field::<usize>(view.out_start) };
let out_end = unsafe { field::<usize>(view.out_end) };
let to_flush = out_end.wrapping_sub(out_start);
let flushed = unsafe {
limit_copy(
op,
(oend as usize).wrapping_sub(op as usize),
get_mut_pointer(view.out_buff).wrapping_add(out_start),
to_flush,
)
};
if flushed != 0 {
op = unsafe { op.add(flushed) };
}
let new_out_start = out_start + flushed;
unsafe { set_field(view.out_start, new_out_start) };
if flushed == to_flush {
unsafe {
set_field(view.stream_stage, ZDSS_READ);
let frame_params = field::<ZSTD_FrameHeader>(view.f_params);
if field::<usize>(view.out_buff_size)
< frame_params.frame_content_size as usize
&& new_out_start + frame_params.block_size_max as usize
> field::<usize>(view.out_buff_size)
{
set_field(view.out_start, 0usize);
set_field(view.out_end, 0usize);
}
}
continue;
}
some_more_work = false;
continue;
}
_ => return ERROR(ZstdErrorCode::Generic),
}
}
input_ref.pos = (ip as usize).wrapping_sub(src as usize);
output_ref.pos = (op as usize).wrapping_sub(dst as usize);
unsafe { set_field(view.expected_out_buffer, *output_ref) };
if ip == istart && op == ostart {
let stalled = unsafe { field::<c_int>(view.no_forward_progress) } + 1;
unsafe { set_field(view.no_forward_progress, stalled) };
if stalled >= unsafe { ZSTD_rust_no_forward_progress_max() } {
if op == oend {
return ERROR(ZstdErrorCode::NoForwardProgressDestFull);
}
if ip == iend {
return ERROR(ZstdErrorCode::NoForwardProgressInputEmpty);
}
return ERROR(ZstdErrorCode::Generic);
}
} else {
unsafe { set_field(view.no_forward_progress, 0 as c_int) };
}
let mut hint = unsafe { field::<usize>(view.expected) };
if hint == 0 {
if unsafe { field::<usize>(view.out_end) } == unsafe { field::<usize>(view.out_start) } {
if unsafe { field::<u32>(view.hostage_byte) } != 0 {
if input_ref.pos >= input_ref.size {
unsafe { set_field(view.stream_stage, ZDSS_READ) };
return 1;
}
input_ref.pos += 1;
}
return 0;
}
if unsafe { field::<u32>(view.hostage_byte) } == 0 {
if input_ref.pos == 0 {
return ERROR(ZstdErrorCode::Generic);
}
input_ref.pos -= 1;
unsafe { set_field(view.hostage_byte, 1u32) };
}
return 1;
}
if unsafe { ZSTD_nextInputType(zds) } == ZSTD_NIT_BLOCK {
hint = hint.wrapping_add(ZSTD_BLOCKHEADERSIZE);
}
let in_pos = unsafe { field::<usize>(view.in_pos) };
if in_pos > hint {
return ERROR(ZstdErrorCode::CorruptionDetected);
}
hint - in_pos
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_decompressStream_simpleArgs(
dctx: *mut ZSTD_DCtx,
dst: *mut c_void,
dst_capacity: usize,
dst_pos: *mut usize,
src: *const c_void,
src_size: usize,
src_pos: *mut usize,
) -> usize {
if dst_pos.is_null() || src_pos.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let mut output = ZSTD_outBuffer {
dst,
size: dst_capacity,
pos: unsafe { dst_pos.read() },
};
let mut input = ZSTD_inBuffer {
src,
size: src_size,
pos: unsafe { src_pos.read() },
};
let result = unsafe { ZSTD_decompressStream(dctx, &mut output, &mut input) };
unsafe {
dst_pos.write(output.pos);
src_pos.write(input.pos);
}
result
}