feat(decompress): move legacy dispatch into Rust
Legacy detection, frame-size queries, one-shot decode, and buffered streaming were still routed through the C header dispatcher even though every historical v0.1 through v0.7 decoder is already ported under Rust feature gates. The C implementation also duplicated the support-level boundary independently from the Rust archive selection. Move the dispatcher and stream lifecycle to Rust using the existing DCtx field projection. Rust now selects the version, preserves the null-buffer and position semantics, initializes and frees buffered legacy contexts, and calls the frozen per-version modules. C retains only the configuration leaf that reports ZSTD_LEGACY_SUPPORT plus the private DCtx layout and trace helpers, so library, program, and test builds can still choose different support levels. Test Plan: - `cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression,decompression,dict-builder,legacy-v01,legacy-v02,legacy-v03,legacy-v04,legacy-v05,legacy-v06,legacy-v07 --all-targets -- --test-threads=1` -- 528 passed. - Native `test-legacy`, `test-invalidDictionaries`, `test-decodecorpus`, and `test-zstd` -- passed. - Strict C syntax checks with legacy support 0, 4, 5, and 7 -- passed. - `cargo clippy` default, benches, and tests for library and CLI -- passed.
This commit is contained in:
@@ -16,10 +16,6 @@
|
||||
#include "zstd_decompress_internal.h"
|
||||
#include "zstd_ddict.h"
|
||||
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
|
||||
# include "../legacy/zstd_legacy.h"
|
||||
#endif
|
||||
|
||||
/* Keep the three public build-time tuning knobs in the C configuration domain.
|
||||
* Rust queries them through the small leaves below rather than baking a second
|
||||
* set of defaults into its source. */
|
||||
@@ -125,18 +121,7 @@ void ZSTD_rust_dctx_copy_prefix(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx);
|
||||
void ZSTD_rust_dctx_trace_begin(ZSTD_DCtx* dctx);
|
||||
void ZSTD_rust_dctx_trace_end(ZSTD_DCtx* dctx, U64 uncompressedSize,
|
||||
U64 compressedSize, int streaming);
|
||||
unsigned ZSTD_rust_legacy_is(const void* src, size_t srcSize);
|
||||
unsigned long long ZSTD_rust_legacy_get_decompressed_size(const void* src,
|
||||
size_t srcSize);
|
||||
size_t ZSTD_rust_legacy_find_compressed_size(const void* src, size_t srcSize);
|
||||
size_t ZSTD_rust_legacy_frame_size_info(const void* src, size_t srcSize,
|
||||
size_t* compressedSize,
|
||||
unsigned long long* decompressedBound,
|
||||
size_t* nbBlocks);
|
||||
size_t ZSTD_rust_legacy_decompress(void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
const void* dict, size_t dictSize);
|
||||
void ZSTD_rust_legacy_free_stream(ZSTD_DCtx* dctx);
|
||||
unsigned ZSTD_rust_legacy_support(void);
|
||||
|
||||
void ZSTD_rust_dctx_view(ZSTD_DCtx* dctx, ZSTD_rustDctxView* out)
|
||||
{
|
||||
@@ -319,87 +304,16 @@ void ZSTD_rust_dctx_trace_end(ZSTD_DCtx* dctx, U64 uncompressedSize,
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned ZSTD_rust_legacy_is(const void* src, size_t srcSize)
|
||||
/* The Rust dispatcher has all version-specific legacy implementations. Keep
|
||||
* the active C configuration as a leaf so test builds, which compile every
|
||||
* Rust legacy module but vary this C macro per target, retain the historical
|
||||
* support boundary. */
|
||||
unsigned ZSTD_rust_legacy_support(void)
|
||||
{
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
|
||||
return ZSTD_isLegacy(src, srcSize);
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) \
|
||||
&& (ZSTD_LEGACY_SUPPORT <= 7)
|
||||
return ZSTD_LEGACY_SUPPORT;
|
||||
#else
|
||||
(void)src;
|
||||
(void)srcSize;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long long ZSTD_rust_legacy_get_decompressed_size(const void* src, size_t srcSize)
|
||||
{
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
|
||||
return ZSTD_getDecompressedSize_legacy(src, srcSize);
|
||||
#else
|
||||
(void)src;
|
||||
(void)srcSize;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t ZSTD_rust_legacy_find_compressed_size(const void* src, size_t srcSize)
|
||||
{
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
|
||||
return ZSTD_findFrameCompressedSizeLegacy(src, srcSize);
|
||||
#else
|
||||
(void)src;
|
||||
(void)srcSize;
|
||||
return ERROR(prefix_unknown);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t ZSTD_rust_legacy_frame_size_info(const void* src, size_t srcSize,
|
||||
size_t* compressedSize,
|
||||
unsigned long long* decompressedBound,
|
||||
size_t* nbBlocks)
|
||||
{
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
|
||||
ZSTD_frameSizeInfo const info = ZSTD_findFrameSizeInfoLegacy(src, srcSize);
|
||||
*compressedSize = info.compressedSize;
|
||||
*decompressedBound = info.decompressedBound;
|
||||
*nbBlocks = info.decompressedBound == ZSTD_CONTENTSIZE_ERROR
|
||||
? 0 : (size_t)(info.decompressedBound / ZSTD_BLOCKSIZE_MAX);
|
||||
return ZSTD_isError(info.compressedSize) ? info.compressedSize : 0;
|
||||
#else
|
||||
(void)src;
|
||||
(void)srcSize;
|
||||
*compressedSize = ERROR(prefix_unknown);
|
||||
*decompressedBound = ZSTD_CONTENTSIZE_ERROR;
|
||||
*nbBlocks = 0;
|
||||
return ERROR(prefix_unknown);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t ZSTD_rust_legacy_decompress(void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
const void* dict, size_t dictSize)
|
||||
{
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
|
||||
return ZSTD_decompressLegacy(dst, dstCapacity, src, srcSize, dict, dictSize);
|
||||
#else
|
||||
(void)dst;
|
||||
(void)dstCapacity;
|
||||
(void)src;
|
||||
(void)srcSize;
|
||||
(void)dict;
|
||||
(void)dictSize;
|
||||
return ERROR(prefix_unknown);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ZSTD_rust_legacy_free_stream(ZSTD_DCtx* dctx)
|
||||
{
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
|
||||
if (dctx->legacyContext) {
|
||||
ZSTD_freeLegacyStreamContext(dctx->legacyContext,
|
||||
dctx->previousLegacyVersion);
|
||||
dctx->legacyContext = NULL;
|
||||
}
|
||||
#else
|
||||
(void)dctx;
|
||||
#endif
|
||||
}
|
||||
|
||||
+591
-19
@@ -327,25 +327,19 @@ unsafe extern "C" {
|
||||
);
|
||||
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_free_stream(dctx: *mut ZSTD_DCtx);
|
||||
#[cfg(all(
|
||||
not(test),
|
||||
any(
|
||||
feature = "legacy-v01",
|
||||
feature = "legacy-v02",
|
||||
feature = "legacy-v03",
|
||||
feature = "legacy-v04",
|
||||
feature = "legacy-v05",
|
||||
feature = "legacy-v06",
|
||||
feature = "legacy-v07"
|
||||
)
|
||||
))]
|
||||
fn ZSTD_rust_legacy_support() -> c_uint;
|
||||
fn ZSTD_decompressBlock_internal(
|
||||
dctx: *mut ZSTD_DCtx,
|
||||
dst: *mut c_void,
|
||||
@@ -388,6 +382,9 @@ fn legacy_empty_mut_ptr() -> *mut c_void {
|
||||
* C helper's historical behavior is to leave that slot untouched while an
|
||||
* initialization attempt replaces it only after successful creation. */
|
||||
unsafe fn free_legacy_stream_context(_legacy_context: *mut c_void, version: u32) {
|
||||
if _legacy_context.is_null() {
|
||||
return;
|
||||
}
|
||||
match version {
|
||||
#[cfg(feature = "legacy-v04")]
|
||||
4 => {
|
||||
@@ -417,6 +414,395 @@ unsafe fn free_legacy_stream_context(_legacy_context: *mut c_void, version: u32)
|
||||
}
|
||||
}
|
||||
|
||||
/* The Rust archive used by the C test harness deliberately contains all
|
||||
* ported legacy modules, even when a particular test target lowers
|
||||
* ZSTD_LEGACY_SUPPORT. Query the active C setting instead of deriving the
|
||||
* dispatch boundary from Cargo features alone. Standalone Rust tests have no
|
||||
* C adapter to query; enabling all configured modules there gives the helper
|
||||
* tests a deterministic support boundary without changing production builds. */
|
||||
#[inline]
|
||||
unsafe fn configured_legacy_support() -> u32 {
|
||||
#[cfg(test)]
|
||||
{
|
||||
1
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
#[cfg(any(
|
||||
feature = "legacy-v01",
|
||||
feature = "legacy-v02",
|
||||
feature = "legacy-v03",
|
||||
feature = "legacy-v04",
|
||||
feature = "legacy-v05",
|
||||
feature = "legacy-v06",
|
||||
feature = "legacy-v07"
|
||||
))]
|
||||
{
|
||||
unsafe { ZSTD_rust_legacy_support() }
|
||||
}
|
||||
#[cfg(not(any(
|
||||
feature = "legacy-v01",
|
||||
feature = "legacy-v02",
|
||||
feature = "legacy-v03",
|
||||
feature = "legacy-v04",
|
||||
feature = "legacy-v05",
|
||||
feature = "legacy-v06",
|
||||
feature = "legacy-v07"
|
||||
)))]
|
||||
{
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This is the Rust equivalent of ZSTD_isLegacy(). The v0.1 magic is the one
|
||||
* historical exception: its bytes are checked as the little-endian constant
|
||||
* 0x1EB52FFD, while v0.2 through v0.7 use the usual 0xFD2FB52N values. */
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTD_rust_legacy_is(src: *const c_void, src_size: usize) -> c_uint {
|
||||
if src.is_null() || src_size < ZSTD_FRAMEIDSIZE {
|
||||
return 0;
|
||||
}
|
||||
let support = unsafe { configured_legacy_support() };
|
||||
if support == 0 {
|
||||
return 0;
|
||||
}
|
||||
let _magic = unsafe { MEM_readLE32(src) };
|
||||
|
||||
#[cfg(feature = "legacy-v01")]
|
||||
if support <= 1 && _magic == 0x1EB5_2FFD {
|
||||
return 1;
|
||||
}
|
||||
#[cfg(feature = "legacy-v02")]
|
||||
if support <= 2 && _magic == 0xFD2F_B522 {
|
||||
return 2;
|
||||
}
|
||||
#[cfg(feature = "legacy-v03")]
|
||||
if support <= 3 && _magic == 0xFD2F_B523 {
|
||||
return 3;
|
||||
}
|
||||
#[cfg(feature = "legacy-v04")]
|
||||
if support <= 4 && _magic == 0xFD2F_B524 {
|
||||
return 4;
|
||||
}
|
||||
#[cfg(feature = "legacy-v05")]
|
||||
if support <= 5 && _magic == 0xFD2F_B525 {
|
||||
return 5;
|
||||
}
|
||||
#[cfg(feature = "legacy-v06")]
|
||||
if support <= 6 && _magic == 0xFD2F_B526 {
|
||||
return 6;
|
||||
}
|
||||
#[cfg(feature = "legacy-v07")]
|
||||
if support <= 7 && _magic == 0xFD2F_B527 {
|
||||
return 7;
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn legacy_frame_size_info_values(
|
||||
src: *const c_void,
|
||||
src_size: usize,
|
||||
) -> (usize, u64, usize) {
|
||||
let version = unsafe { ZSTD_rust_legacy_is(src, src_size) };
|
||||
let mut compressed_size = ERROR(ZstdErrorCode::PrefixUnknown);
|
||||
let mut decompressed_bound = ZSTD_CONTENTSIZE_ERROR;
|
||||
|
||||
match version {
|
||||
#[cfg(feature = "legacy-v01")]
|
||||
1 => unsafe {
|
||||
crate::legacy::zstd_v01::ZSTDv01_findFrameSizeInfoLegacy(
|
||||
src,
|
||||
src_size,
|
||||
&mut compressed_size,
|
||||
&mut decompressed_bound,
|
||||
);
|
||||
},
|
||||
#[cfg(feature = "legacy-v02")]
|
||||
2 => unsafe {
|
||||
crate::legacy::zstd_v02::ZSTDv02_findFrameSizeInfoLegacy(
|
||||
src,
|
||||
src_size,
|
||||
&mut compressed_size,
|
||||
&mut decompressed_bound,
|
||||
);
|
||||
},
|
||||
#[cfg(feature = "legacy-v03")]
|
||||
3 => unsafe {
|
||||
crate::legacy::zstd_v03::ZSTDv03_findFrameSizeInfoLegacy(
|
||||
src,
|
||||
src_size,
|
||||
&mut compressed_size,
|
||||
&mut decompressed_bound,
|
||||
);
|
||||
},
|
||||
#[cfg(feature = "legacy-v04")]
|
||||
4 => unsafe {
|
||||
crate::legacy::zstd_v04::ZSTDv04_findFrameSizeInfoLegacy(
|
||||
src,
|
||||
src_size,
|
||||
&mut compressed_size,
|
||||
&mut decompressed_bound,
|
||||
);
|
||||
},
|
||||
#[cfg(feature = "legacy-v05")]
|
||||
5 => unsafe {
|
||||
crate::legacy::zstd_v05::ZSTDv05_findFrameSizeInfoLegacy(
|
||||
src,
|
||||
src_size,
|
||||
&mut compressed_size,
|
||||
&mut decompressed_bound,
|
||||
);
|
||||
},
|
||||
#[cfg(feature = "legacy-v06")]
|
||||
6 => unsafe {
|
||||
crate::legacy::zstd_v06::ZSTDv06_findFrameSizeInfoLegacy(
|
||||
src,
|
||||
src_size,
|
||||
&mut compressed_size,
|
||||
&mut decompressed_bound,
|
||||
);
|
||||
},
|
||||
#[cfg(feature = "legacy-v07")]
|
||||
7 => unsafe {
|
||||
crate::legacy::zstd_v07::ZSTDv07_findFrameSizeInfoLegacy(
|
||||
src,
|
||||
src_size,
|
||||
&mut compressed_size,
|
||||
&mut decompressed_bound,
|
||||
);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if !ERR_isError(compressed_size) && compressed_size > src_size {
|
||||
compressed_size = ERROR(ZstdErrorCode::SrcSizeWrong);
|
||||
decompressed_bound = ZSTD_CONTENTSIZE_ERROR;
|
||||
}
|
||||
|
||||
let nb_blocks = if decompressed_bound == ZSTD_CONTENTSIZE_ERROR {
|
||||
0
|
||||
} else {
|
||||
debug_assert_eq!(decompressed_bound & (ZSTD_BLOCKSIZE_MAX as u64 - 1), 0);
|
||||
(decompressed_bound / ZSTD_BLOCKSIZE_MAX as u64) as usize
|
||||
};
|
||||
(compressed_size, decompressed_bound, nb_blocks)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTD_rust_legacy_get_decompressed_size(
|
||||
src: *const c_void,
|
||||
src_size: usize,
|
||||
) -> u64 {
|
||||
let version = unsafe { ZSTD_rust_legacy_is(src, src_size) };
|
||||
match version {
|
||||
#[cfg(feature = "legacy-v05")]
|
||||
5 => {
|
||||
/* ZstdParameters is repr(C), and src_size is its first field. The
|
||||
* field is private inside the frozen module because it is not part
|
||||
* of that module's public Rust API, so read the documented C ABI
|
||||
* prefix only after the version-specific parser succeeds. */
|
||||
let mut params = MaybeUninit::<crate::legacy::zstd_v05::ZstdParameters>::zeroed();
|
||||
let result = unsafe {
|
||||
crate::legacy::zstd_v05::ZSTDv05_getFrameParams(params.as_mut_ptr(), src, src_size)
|
||||
};
|
||||
if result == 0 {
|
||||
unsafe { params.as_ptr().cast::<u64>().read() }
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "legacy-v06")]
|
||||
6 => {
|
||||
let mut params = crate::legacy::zstd_v06::ZSTDv06_frameParams {
|
||||
frame_content_size: 0,
|
||||
window_log: 0,
|
||||
};
|
||||
let result = unsafe {
|
||||
crate::legacy::zstd_v06::ZSTDv06_getFrameParams(&mut params, src, src_size)
|
||||
};
|
||||
if result == 0 {
|
||||
params.frame_content_size
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "legacy-v07")]
|
||||
7 => {
|
||||
let mut params = crate::legacy::zstd_v07::ZSTDv07_frameParams {
|
||||
frameContentSize: 0,
|
||||
windowSize: 0,
|
||||
dictID: 0,
|
||||
checksumFlag: 0,
|
||||
};
|
||||
let result = unsafe {
|
||||
crate::legacy::zstd_v07::ZSTDv07_getFrameParams(&mut params, src, src_size)
|
||||
};
|
||||
if result == 0 {
|
||||
params.frameContentSize
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTD_rust_legacy_find_compressed_size(
|
||||
src: *const c_void,
|
||||
src_size: usize,
|
||||
) -> usize {
|
||||
unsafe { legacy_frame_size_info_values(src, src_size).0 }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" 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 {
|
||||
let (c_size, d_bound, blocks) = unsafe { legacy_frame_size_info_values(src, src_size) };
|
||||
unsafe {
|
||||
compressed_size.write(c_size);
|
||||
decompressed_bound.write(d_bound);
|
||||
nb_blocks.write(blocks);
|
||||
}
|
||||
if ERR_isError(c_size) {
|
||||
c_size
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" 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 {
|
||||
let version = unsafe { ZSTD_rust_legacy_is(src, src_size) };
|
||||
let _dst = if dst.is_null() {
|
||||
debug_assert_eq!(dst_capacity, 0);
|
||||
legacy_empty_mut_ptr()
|
||||
} else {
|
||||
dst
|
||||
};
|
||||
let _src = if src.is_null() {
|
||||
debug_assert_eq!(src_size, 0);
|
||||
legacy_empty_const_ptr()
|
||||
} else {
|
||||
src
|
||||
};
|
||||
let _dict = if dict.is_null() {
|
||||
debug_assert_eq!(dict_size, 0);
|
||||
legacy_empty_const_ptr()
|
||||
} else {
|
||||
dict
|
||||
};
|
||||
|
||||
match version {
|
||||
#[cfg(feature = "legacy-v01")]
|
||||
1 => unsafe {
|
||||
crate::legacy::zstd_v01::ZSTDv01_decompress(_dst, dst_capacity, _src, src_size)
|
||||
},
|
||||
#[cfg(feature = "legacy-v02")]
|
||||
2 => unsafe {
|
||||
crate::legacy::zstd_v02::ZSTDv02_decompress(_dst, dst_capacity, _src, src_size)
|
||||
},
|
||||
#[cfg(feature = "legacy-v03")]
|
||||
3 => unsafe {
|
||||
crate::legacy::zstd_v03::ZSTDv03_decompress(_dst, dst_capacity, _src, src_size)
|
||||
},
|
||||
#[cfg(feature = "legacy-v04")]
|
||||
4 => unsafe {
|
||||
crate::legacy::zstd_v04::ZSTDv04_decompress(_dst, dst_capacity, _src, src_size)
|
||||
},
|
||||
#[cfg(feature = "legacy-v05")]
|
||||
5 => {
|
||||
let dctx = unsafe { crate::legacy::zstd_v05::ZSTDv05_createDCtx() };
|
||||
if dctx.is_null() {
|
||||
return ERROR(ZstdErrorCode::MemoryAllocation);
|
||||
}
|
||||
let result = unsafe {
|
||||
crate::legacy::zstd_v05::ZSTDv05_decompress_usingDict(
|
||||
dctx,
|
||||
_dst,
|
||||
dst_capacity,
|
||||
_src,
|
||||
src_size,
|
||||
_dict,
|
||||
dict_size,
|
||||
)
|
||||
};
|
||||
unsafe { crate::legacy::zstd_v05::ZSTDv05_freeDCtx(dctx) };
|
||||
result
|
||||
}
|
||||
#[cfg(feature = "legacy-v06")]
|
||||
6 => {
|
||||
let dctx = unsafe { crate::legacy::zstd_v06::ZSTDv06_createDCtx() };
|
||||
if dctx.is_null() {
|
||||
return ERROR(ZstdErrorCode::MemoryAllocation);
|
||||
}
|
||||
let result = unsafe {
|
||||
crate::legacy::zstd_v06::ZSTDv06_decompress_usingDict(
|
||||
dctx,
|
||||
_dst,
|
||||
dst_capacity,
|
||||
_src,
|
||||
src_size,
|
||||
_dict,
|
||||
dict_size,
|
||||
)
|
||||
};
|
||||
unsafe { crate::legacy::zstd_v06::ZSTDv06_freeDCtx(dctx) };
|
||||
result
|
||||
}
|
||||
#[cfg(feature = "legacy-v07")]
|
||||
7 => {
|
||||
let dctx = unsafe { crate::legacy::zstd_v07::ZSTDv07_createDCtx() };
|
||||
if dctx.is_null() {
|
||||
return ERROR(ZstdErrorCode::MemoryAllocation);
|
||||
}
|
||||
let result = unsafe {
|
||||
crate::legacy::zstd_v07::ZSTDv07_decompress_usingDict(
|
||||
dctx,
|
||||
_dst,
|
||||
dst_capacity,
|
||||
_src,
|
||||
src_size,
|
||||
_dict,
|
||||
dict_size,
|
||||
)
|
||||
};
|
||||
unsafe { crate::legacy::zstd_v07::ZSTDv07_freeDCtx(dctx) };
|
||||
result
|
||||
}
|
||||
_ => ERROR(ZstdErrorCode::PrefixUnknown),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTD_rust_legacy_free_stream(dctx: *mut ZSTD_DCtx) {
|
||||
if dctx.is_null() {
|
||||
return;
|
||||
}
|
||||
let view = unsafe { dctx_view(dctx) };
|
||||
if view.legacy_context.is_null() {
|
||||
return;
|
||||
}
|
||||
let legacy_context = unsafe { field::<*mut c_void>(view.legacy_context) };
|
||||
let previous_version = unsafe { field::<u32>(view.previous_legacy_version) };
|
||||
unsafe { free_legacy_stream_context(legacy_context, previous_version) };
|
||||
unsafe { set_field(view.legacy_context, ptr::null_mut::<c_void>()) };
|
||||
}
|
||||
|
||||
/* This is the narrow Rust equivalent of ZSTD_initLegacyStream(). It only
|
||||
* touches the three legacy projections in ZSTD_rustDctxView; the enclosing
|
||||
* decoder context and every version-specific stream context remain opaque to
|
||||
@@ -795,6 +1181,192 @@ mod legacy_stream_dispatch_tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod legacy_dispatch_helper_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn legacy_detection_rejects_short_null_and_unknown_input() {
|
||||
assert_eq!(unsafe { ZSTD_rust_legacy_is(ptr::null(), 0) }, 0);
|
||||
let short = [0x27, 0xB5, 0x2F];
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_legacy_is(short.as_ptr().cast(), short.len()) },
|
||||
0
|
||||
);
|
||||
let unknown = [0u8; ZSTD_FRAMEIDSIZE];
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_legacy_is(unknown.as_ptr().cast(), unknown.len()) },
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "legacy-v01")]
|
||||
#[test]
|
||||
fn detects_v01_magic() {
|
||||
let magic: [u8; 4] = [0xFD, 0x2F, 0xB5, 0x1E];
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_legacy_is(magic.as_ptr().cast(), magic.len()) },
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "legacy-v02")]
|
||||
#[test]
|
||||
fn detects_v02_magic() {
|
||||
let magic: [u8; 4] = [0x22, 0xB5, 0x2F, 0xFD];
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_legacy_is(magic.as_ptr().cast(), magic.len()) },
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "legacy-v03")]
|
||||
#[test]
|
||||
fn detects_v03_magic() {
|
||||
let magic: [u8; 4] = [0x23, 0xB5, 0x2F, 0xFD];
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_legacy_is(magic.as_ptr().cast(), magic.len()) },
|
||||
3
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "legacy-v04")]
|
||||
#[test]
|
||||
fn detects_v04_magic() {
|
||||
let magic: [u8; 4] = [0x24, 0xB5, 0x2F, 0xFD];
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_legacy_is(magic.as_ptr().cast(), magic.len()) },
|
||||
4
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "legacy-v05")]
|
||||
#[test]
|
||||
fn detects_v05_magic() {
|
||||
let magic: [u8; 4] = [0x25, 0xB5, 0x2F, 0xFD];
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_legacy_is(magic.as_ptr().cast(), magic.len()) },
|
||||
5
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "legacy-v06")]
|
||||
#[test]
|
||||
fn detects_v06_magic() {
|
||||
let magic: [u8; 4] = [0x26, 0xB5, 0x2F, 0xFD];
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_legacy_is(magic.as_ptr().cast(), magic.len()) },
|
||||
6
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "legacy-v07")]
|
||||
#[test]
|
||||
fn legacy_v07_size_and_one_shot_helpers_match_frame() {
|
||||
let payload = b"legacy-dispatch";
|
||||
let mut frame = Vec::with_capacity(6 + 3 + payload.len() + 3);
|
||||
frame.extend_from_slice(&[0x27, 0xB5, 0x2F, 0xFD]);
|
||||
frame.extend_from_slice(&[0x20, payload.len() as u8]);
|
||||
frame.extend_from_slice(&[
|
||||
0x40 | (((payload.len() >> 16) & 7) as u8),
|
||||
(payload.len() >> 8) as u8,
|
||||
payload.len() as u8,
|
||||
]);
|
||||
frame.extend_from_slice(payload);
|
||||
frame.extend_from_slice(&[0xC0, 0, 0]);
|
||||
|
||||
let mut compressed_size = 0;
|
||||
let mut decompressed_bound = 0;
|
||||
let mut nb_blocks = 0;
|
||||
let status = unsafe {
|
||||
ZSTD_rust_legacy_frame_size_info(
|
||||
frame.as_ptr().cast(),
|
||||
frame.len(),
|
||||
&mut compressed_size,
|
||||
&mut decompressed_bound,
|
||||
&mut nb_blocks,
|
||||
)
|
||||
};
|
||||
assert_eq!(status, 0);
|
||||
assert_eq!(compressed_size, frame.len());
|
||||
assert_eq!(
|
||||
decompressed_bound, ZSTD_BLOCKSIZE_MAX as u64,
|
||||
"legacy frame bounds are reported in whole legacy blocks"
|
||||
);
|
||||
assert_eq!(nb_blocks, 1);
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_legacy_find_compressed_size(frame.as_ptr().cast(), frame.len()) },
|
||||
frame.len()
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_legacy_get_decompressed_size(frame.as_ptr().cast(), frame.len()) },
|
||||
payload.len() as u64
|
||||
);
|
||||
|
||||
let mut output = vec![0u8; payload.len()];
|
||||
let decoded = unsafe {
|
||||
ZSTD_rust_legacy_decompress(
|
||||
output.as_mut_ptr().cast(),
|
||||
output.len(),
|
||||
frame.as_ptr().cast(),
|
||||
frame.len(),
|
||||
ptr::null(),
|
||||
0,
|
||||
)
|
||||
};
|
||||
assert_eq!(decoded, payload.len());
|
||||
assert_eq!(output, payload);
|
||||
}
|
||||
|
||||
#[cfg(feature = "legacy-v07")]
|
||||
#[test]
|
||||
fn legacy_size_and_decompress_helpers_report_truncation() {
|
||||
let mut truncated = vec![0x27, 0xB5, 0x2F, 0xFD, 0x20, 4, 0x40, 0, 4, b't'];
|
||||
let mut compressed_size = 0;
|
||||
let mut decompressed_bound = 0;
|
||||
let mut nb_blocks = 0;
|
||||
let status = unsafe {
|
||||
ZSTD_rust_legacy_frame_size_info(
|
||||
truncated.as_ptr().cast(),
|
||||
truncated.len(),
|
||||
&mut compressed_size,
|
||||
&mut decompressed_bound,
|
||||
&mut nb_blocks,
|
||||
)
|
||||
};
|
||||
assert_eq!(status, ERROR(ZstdErrorCode::SrcSizeWrong));
|
||||
assert_eq!(compressed_size, status);
|
||||
assert_eq!(decompressed_bound, ZSTD_CONTENTSIZE_ERROR);
|
||||
assert_eq!(nb_blocks, 0);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
ZSTD_rust_legacy_find_compressed_size(truncated.as_ptr().cast(), truncated.len())
|
||||
},
|
||||
status
|
||||
);
|
||||
|
||||
let mut output = [0u8; 4];
|
||||
let decoded = unsafe {
|
||||
ZSTD_rust_legacy_decompress(
|
||||
output.as_mut_ptr().cast(),
|
||||
output.len(),
|
||||
truncated.as_ptr().cast(),
|
||||
truncated.len(),
|
||||
ptr::null(),
|
||||
0,
|
||||
)
|
||||
};
|
||||
assert!(ERR_isError(decoded));
|
||||
truncated[0] ^= 1;
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
ZSTD_rust_legacy_get_decompressed_size(truncated.as_ptr().cast(), truncated.len())
|
||||
},
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn frame_header_prefix(format: c_int) -> usize {
|
||||
if format == ZSTD_F_ZSTD1 {
|
||||
|
||||
Reference in New Issue
Block a user