use core::ptr;
use super::decompress_core::{decompress_generic, DecompressError};
use super::types::{DictDirective, KB};
pub use super::decompress_core::DecompressError as BlockDecompressError;
pub const LZ4_MAX_INPUT_SIZE: usize = 0x7E000000;
const KB64_MINUS1: usize = 64 * KB - 1;
#[repr(C)]
pub struct Lz4StreamDecode {
pub(crate) external_dict: *const u8,
pub(crate) prefix_end: *const u8,
pub(crate) ext_dict_size: usize,
pub(crate) prefix_size: usize,
}
unsafe impl Send for Lz4StreamDecode {}
impl Lz4StreamDecode {
pub const fn new() -> Self {
Self {
external_dict: ptr::null(),
prefix_end: ptr::null(),
ext_dict_size: 0,
prefix_size: 0,
}
}
}
impl Default for Lz4StreamDecode {
fn default() -> Self {
Self::new()
}
}
pub fn decompress_safe(src: &[u8], dst: &mut [u8]) -> Result<usize, DecompressError> {
unsafe {
decompress_generic(
src.as_ptr(),
dst.as_mut_ptr(),
src.len(),
dst.len(),
false, DictDirective::NoDict,
dst.as_ptr() as *const u8, ptr::null(), 0,
)
}
}
pub fn decompress_safe_partial(
src: &[u8],
dst: &mut [u8],
target_output_size: usize,
) -> Result<usize, DecompressError> {
let output_size = target_output_size.min(dst.len());
unsafe {
decompress_generic(
src.as_ptr(),
dst.as_mut_ptr(),
src.len(),
output_size,
true, DictDirective::NoDict,
dst.as_ptr() as *const u8,
ptr::null(),
0,
)
}
}
#[inline]
pub(crate) unsafe fn decompress_safe_with_prefix64k(
src_ptr: *const u8,
dst_ptr: *mut u8,
src_size: usize,
max_output: usize,
) -> Result<usize, DecompressError> {
decompress_generic(
src_ptr,
dst_ptr,
src_size,
max_output,
false,
DictDirective::WithPrefix64k,
dst_ptr.sub(64 * KB) as *const u8,
ptr::null(),
0,
)
}
#[inline]
pub(crate) unsafe fn decompress_safe_partial_with_prefix64k(
src_ptr: *const u8,
dst_ptr: *mut u8,
src_size: usize,
target_output_size: usize,
dst_capacity: usize,
) -> Result<usize, DecompressError> {
let output_size = target_output_size.min(dst_capacity);
decompress_generic(
src_ptr,
dst_ptr,
src_size,
output_size,
true,
DictDirective::WithPrefix64k,
dst_ptr.sub(64 * KB) as *const u8,
ptr::null(),
0,
)
}
#[inline]
pub(crate) unsafe fn decompress_safe_with_small_prefix(
src_ptr: *const u8,
dst_ptr: *mut u8,
src_size: usize,
max_output: usize,
prefix_size: usize,
) -> Result<usize, DecompressError> {
decompress_generic(
src_ptr,
dst_ptr,
src_size,
max_output,
false,
DictDirective::NoDict,
dst_ptr.sub(prefix_size) as *const u8,
ptr::null(),
0,
)
}
#[inline]
pub(crate) unsafe fn decompress_safe_partial_with_small_prefix(
src_ptr: *const u8,
dst_ptr: *mut u8,
src_size: usize,
target_output_size: usize,
dst_capacity: usize,
prefix_size: usize,
) -> Result<usize, DecompressError> {
let output_size = target_output_size.min(dst_capacity);
decompress_generic(
src_ptr,
dst_ptr,
src_size,
output_size,
true,
DictDirective::NoDict,
dst_ptr.sub(prefix_size) as *const u8,
ptr::null(),
0,
)
}
pub unsafe fn decompress_safe_force_ext_dict(
src_ptr: *const u8,
dst_ptr: *mut u8,
src_size: usize,
max_output: usize,
dict_start: *const u8,
dict_size: usize,
) -> Result<usize, DecompressError> {
decompress_generic(
src_ptr,
dst_ptr,
src_size,
max_output,
false,
DictDirective::UsingExtDict,
dst_ptr as *const u8, dict_start,
dict_size,
)
}
pub unsafe fn decompress_safe_partial_force_ext_dict(
src_ptr: *const u8,
dst_ptr: *mut u8,
src_size: usize,
target_output_size: usize,
dst_capacity: usize,
dict_start: *const u8,
dict_size: usize,
) -> Result<usize, DecompressError> {
let output_size = target_output_size.min(dst_capacity);
decompress_generic(
src_ptr,
dst_ptr,
src_size,
output_size,
true,
DictDirective::UsingExtDict,
dst_ptr as *const u8,
dict_start,
dict_size,
)
}
#[inline]
pub(crate) unsafe fn decompress_safe_double_dict(
src_ptr: *const u8,
dst_ptr: *mut u8,
src_size: usize,
max_output: usize,
prefix_size: usize,
dict_start: *const u8,
dict_size: usize,
) -> Result<usize, DecompressError> {
decompress_generic(
src_ptr,
dst_ptr,
src_size,
max_output,
false,
DictDirective::UsingExtDict,
dst_ptr.sub(prefix_size) as *const u8,
dict_start,
dict_size,
)
}
pub unsafe fn set_stream_decode(ctx: &mut Lz4StreamDecode, dict: &[u8]) -> bool {
ctx.prefix_size = dict.len();
if !dict.is_empty() {
ctx.prefix_end = dict.as_ptr().add(dict.len());
} else {
ctx.prefix_end = dict.as_ptr();
}
ctx.external_dict = ptr::null();
ctx.ext_dict_size = 0;
true
}
pub fn decoder_ring_buffer_size(max_block_size: usize) -> Option<usize> {
if max_block_size > LZ4_MAX_INPUT_SIZE {
return None;
}
let block = max_block_size.max(16);
Some(65536 + 14 + block)
}
pub unsafe fn decompress_safe_continue(
ctx: &mut Lz4StreamDecode,
src_ptr: *const u8,
dst_ptr: *mut u8,
src_size: usize,
max_output: usize,
) -> Result<usize, DecompressError> {
let result: usize;
if ctx.prefix_size == 0 {
debug_assert!(ctx.ext_dict_size == 0);
let mut tmp_dst = core::slice::from_raw_parts_mut(dst_ptr, max_output);
let tmp_src = core::slice::from_raw_parts(src_ptr, src_size);
result = decompress_safe(tmp_src, tmp_dst)?;
ctx.prefix_size = result;
ctx.prefix_end = dst_ptr.add(result) as *const u8;
} else if std::ptr::eq(ctx.prefix_end, dst_ptr) {
if ctx.prefix_size >= KB64_MINUS1 {
result = decompress_safe_with_prefix64k(src_ptr, dst_ptr, src_size, max_output)?;
} else if ctx.ext_dict_size == 0 {
result = decompress_safe_with_small_prefix(
src_ptr,
dst_ptr,
src_size,
max_output,
ctx.prefix_size,
)?;
} else {
result = decompress_safe_double_dict(
src_ptr,
dst_ptr,
src_size,
max_output,
ctx.prefix_size,
ctx.external_dict,
ctx.ext_dict_size,
)?;
}
ctx.prefix_size += result;
ctx.prefix_end = ctx.prefix_end.add(result);
} else {
ctx.ext_dict_size = ctx.prefix_size;
ctx.external_dict = ctx.prefix_end.sub(ctx.ext_dict_size);
result = decompress_safe_force_ext_dict(
src_ptr,
dst_ptr,
src_size,
max_output,
ctx.external_dict,
ctx.ext_dict_size,
)?;
ctx.prefix_size = result;
ctx.prefix_end = dst_ptr.add(result) as *const u8;
}
Ok(result)
}
pub unsafe fn decompress_safe_using_dict(
src_ptr: *const u8,
dst_ptr: *mut u8,
src_size: usize,
max_output: usize,
dict_start: *const u8,
dict_size: usize,
) -> Result<usize, DecompressError> {
if dict_size == 0 {
let src = core::slice::from_raw_parts(src_ptr, src_size);
let dst = core::slice::from_raw_parts_mut(dst_ptr, max_output);
return decompress_safe(src, dst);
}
if std::ptr::eq(dict_start.add(dict_size), dst_ptr) {
if dict_size >= KB64_MINUS1 {
return decompress_safe_with_prefix64k(src_ptr, dst_ptr, src_size, max_output);
}
return decompress_safe_with_small_prefix(
src_ptr, dst_ptr, src_size, max_output, dict_size,
);
}
decompress_safe_force_ext_dict(
src_ptr, dst_ptr, src_size, max_output, dict_start, dict_size,
)
}
pub unsafe fn decompress_safe_partial_using_dict(
src_ptr: *const u8,
dst_ptr: *mut u8,
src_size: usize,
target_output_size: usize,
dst_capacity: usize,
dict_start: *const u8,
dict_size: usize,
) -> Result<usize, DecompressError> {
if dict_size == 0 {
let src = core::slice::from_raw_parts(src_ptr, src_size);
let dst = core::slice::from_raw_parts_mut(dst_ptr, dst_capacity);
return decompress_safe_partial(src, dst, target_output_size);
}
if std::ptr::eq(dict_start.add(dict_size), dst_ptr) {
if dict_size >= KB64_MINUS1 {
return decompress_safe_partial_with_prefix64k(
src_ptr,
dst_ptr,
src_size,
target_output_size,
dst_capacity,
);
}
return decompress_safe_partial_with_small_prefix(
src_ptr,
dst_ptr,
src_size,
target_output_size,
dst_capacity,
dict_size,
);
}
decompress_safe_partial_force_ext_dict(
src_ptr,
dst_ptr,
src_size,
target_output_size,
dst_capacity,
dict_start,
dict_size,
)
}