diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 11b827e60..eb78f9f29 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -1499,6 +1499,30 @@ typedef char ZSTD_rust_compress_using_cdict_state_layout[ == 3 * sizeof(void*) && sizeof(ZSTD_rust_compressUsingCDictState) == 4 * sizeof(void*)) ? 1 : -1]; +typedef struct { + void* callbackContext; + const void* cdict; + const ZSTD_frameParameters* fParams; + ZSTD_rust_compressUsingCDictBegin_f begin; + ZSTD_rust_compressUsingCDictEnd_f end; +} ZSTD_rust_compressUsingCDictAdvancedState; +size_t ZSTD_rust_compressUsingCDictAdvanced( + const ZSTD_rust_compressUsingCDictAdvancedState* state, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); +typedef char ZSTD_rust_compress_using_cdict_advanced_state_layout[ + (offsetof(ZSTD_rust_compressUsingCDictAdvancedState, callbackContext) == 0 + && offsetof(ZSTD_rust_compressUsingCDictAdvancedState, cdict) + == sizeof(void*) + && offsetof(ZSTD_rust_compressUsingCDictAdvancedState, fParams) + == 2 * sizeof(void*) + && offsetof(ZSTD_rust_compressUsingCDictAdvancedState, begin) + == 3 * sizeof(void*) + && offsetof(ZSTD_rust_compressUsingCDictAdvancedState, end) + == 4 * sizeof(void*) + && sizeof(ZSTD_rust_compressUsingCDictAdvancedState) + == 5 * sizeof(void*)) + ? 1 : -1]; typedef size_t (*ZSTD_rust_compressBeginUsingCDictPublicBegin_f)( void* context, const void* cdict, const ZSTD_frameParameters* fParams, U64 pledgedSrcSize); @@ -5851,18 +5875,6 @@ size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) return ZSTD_compressBegin_usingCDict_deprecated(cctx, cdict); } -/*! ZSTD_compress_usingCDict_internal(): - * Implementation of various ZSTD_compress_usingCDict* functions. - */ -static size_t ZSTD_compress_usingCDict_internal(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) -{ - FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */ - return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); -} - static size_t ZSTD_rust_compressUsingCDict_begin( void* context, const void* cdict, const ZSTD_frameParameters* fParams, U64 pledgedSrcSize) @@ -5888,7 +5900,14 @@ size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, const void* src, size_t srcSize, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) { - return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); + ZSTD_rust_compressUsingCDictAdvancedState state; + state.callbackContext = cctx; + state.cdict = cdict; + state.fParams = &fParams; + state.begin = ZSTD_rust_compressUsingCDict_begin; + state.end = ZSTD_rust_compressUsingCDict_end; + return ZSTD_rust_compressUsingCDictAdvanced( + &state, dst, dstCapacity, src, srcSize); } /*! ZSTD_compress_usingCDict() : diff --git a/rust/src/zstd_compress_dictionary.rs b/rust/src/zstd_compress_dictionary.rs index 5e7cd6eca..3c335ea9f 100644 --- a/rust/src/zstd_compress_dictionary.rs +++ b/rust/src/zstd_compress_dictionary.rs @@ -300,6 +300,68 @@ pub unsafe extern "C" fn ZSTD_rust_compressUsingCDict( unsafe { (state.end)(state.callback_context, dst, dst_capacity, src, src_size) } } +/// Explicit projection for the deprecated public +/// `ZSTD_compress_usingCDict_advanced` wrapper. +/// +/// Rust owns CDict validation and begin-then-end ordering while C retains the +/// private begin and end operations behind callbacks. +#[repr(C)] +pub struct ZSTD_rust_compressUsingCDictAdvancedState { + callback_context: *mut c_void, + cdict: *const c_void, + f_params: *const ZSTD_frameParameters, + begin: CompressUsingCDictBeginFn, + end: CompressUsingCDictEndFn, +} + +const _: () = { + assert!(offset_of!(ZSTD_rust_compressUsingCDictAdvancedState, callback_context) == 0); + assert!(offset_of!(ZSTD_rust_compressUsingCDictAdvancedState, cdict) == size_of::()); + assert!( + offset_of!(ZSTD_rust_compressUsingCDictAdvancedState, f_params) == 2 * size_of::() + ); + assert!(offset_of!(ZSTD_rust_compressUsingCDictAdvancedState, begin) == 3 * size_of::()); + assert!(offset_of!(ZSTD_rust_compressUsingCDictAdvancedState, end) == 4 * size_of::()); + assert!(size_of::() == size_of::<[usize; 5]>()); +}; + +/// Compress a complete source using an explicit CDict frame policy. +#[no_mangle] +pub unsafe extern "C" fn ZSTD_rust_compressUsingCDictAdvanced( + state: *const ZSTD_rust_compressUsingCDictAdvancedState, + dst: *mut c_void, + dst_capacity: usize, + src: *const c_void, + src_size: usize, +) -> usize { + if state.is_null() { + return ERROR(ZstdErrorCode::Generic); + } + let state = unsafe { &*state }; + if state.callback_context.is_null() { + return ERROR(ZstdErrorCode::Generic); + } + if state.cdict.is_null() { + return ERROR(ZstdErrorCode::DictionaryWrong); + } + if state.f_params.is_null() { + return ERROR(ZstdErrorCode::Generic); + } + + let begin_result = unsafe { + (state.begin)( + state.callback_context, + state.cdict, + state.f_params, + src_size as u64, + ) + }; + if ERR_isError(begin_result) { + return begin_result; + } + unsafe { (state.end)(state.callback_context, dst, dst_capacity, src, src_size) } +} + type CompressBeginUsingCDictPublicBeginFn = unsafe extern "C" fn(*mut c_void, *const c_void, *const ZSTD_frameParameters, u64) -> usize; @@ -2779,6 +2841,78 @@ mod tests { assert_eq!(probe.events, ["begin"]); } + fn compress_using_cdict_advanced_test_state( + probe: &mut CompressUsingCDictProbe, + cdict: *const c_void, + f_params: &ZSTD_frameParameters, + ) -> ZSTD_rust_compressUsingCDictAdvancedState { + ZSTD_rust_compressUsingCDictAdvancedState { + callback_context: (probe as *mut CompressUsingCDictProbe).cast(), + cdict, + f_params, + begin: compress_using_cdict_test_begin, + end: compress_using_cdict_test_end, + } + } + + #[test] + fn compress_using_cdict_advanced_preserves_frame_policy_and_begin_end_order() { + let mut probe = CompressUsingCDictProbe { + end_result: 41, + ..Default::default() + }; + let cdict = ptr::dangling::(); + let f_params = ZSTD_frameParameters { + contentSizeFlag: 0, + checksumFlag: 1, + noDictIDFlag: 1, + }; + let state = compress_using_cdict_advanced_test_state(&mut probe, cdict, &f_params); + let mut dst = [0u8; 4]; + let src = [9u8, 8]; + + let result = unsafe { + ZSTD_rust_compressUsingCDictAdvanced( + &state, + dst.as_mut_ptr().cast(), + dst.len(), + src.as_ptr().cast(), + src.len(), + ) + }; + + assert_eq!(result, probe.end_result); + assert_eq!(probe.events, ["begin", "end"]); + assert_eq!(probe.cdict, cdict); + assert_eq!(probe.frame_params.contentSizeFlag, 0); + assert_eq!(probe.frame_params.checksumFlag, 1); + assert_eq!(probe.frame_params.noDictIDFlag, 1); + assert_eq!(probe.pledged_src_size, src.len() as u64); + assert_eq!(probe.dst, dst.as_mut_ptr().cast()); + assert_eq!(probe.dst_capacity, dst.len()); + assert_eq!(probe.src, src.as_ptr().cast()); + assert_eq!(probe.src_size, src.len()); + } + + #[test] + fn compress_using_cdict_advanced_rejects_a_missing_frame_policy_before_callback() { + let mut probe = CompressUsingCDictProbe::default(); + let state = ZSTD_rust_compressUsingCDictAdvancedState { + callback_context: (&mut probe as *mut CompressUsingCDictProbe).cast(), + cdict: ptr::dangling(), + f_params: ptr::null(), + begin: compress_using_cdict_test_begin, + end: compress_using_cdict_test_end, + }; + + let result = unsafe { + ZSTD_rust_compressUsingCDictAdvanced(&state, ptr::null_mut(), 0, ptr::null(), 0) + }; + + assert_eq!(result, ERROR(ZstdErrorCode::Generic)); + assert!(probe.events.is_empty()); + } + fn compress_begin_using_cdict_public_test_state( probe: &mut CompressUsingCDictProbe, cdict: *const c_void,