fix: correct libaec FFI to use aec_stream struct (fixes SIGSEGV)
The previous aec_buffer_decode declaration used flat parameters which don't match the actual libaec C API; this caused a SIGSEGV at runtime. Replace with the correct aec_stream struct (mirroring <libaec.h>) and update filters_szip.rs to populate and pass &mut AecStream. Also add empty-input guard in szip_decode_impl and fallback library path search in build.rs for distros that omit the .pc file. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
d6c4d4f111
commit
e91f7fc539
@@ -1,6 +1,9 @@
|
||||
//! Raw FFI bindings to libaec (Adaptive Entropy Coding library).
|
||||
//!
|
||||
//! Provides the `aec_buffer_decode` convenience function for one-shot decompression.
|
||||
//! Exposes the `aec_buffer_decode` one-shot convenience function via
|
||||
//! the `AecStream` control structure, matching the libaec C API.
|
||||
|
||||
use std::os::raw::c_void;
|
||||
|
||||
// AEC flag constants matching aec.h
|
||||
pub const AEC_DATA_PREPROCESS: u32 = 1; // NN preprocessing
|
||||
@@ -8,20 +11,51 @@ pub const AEC_DATA_MSB: u32 = 2; // big-endian sample order
|
||||
pub const AEC_RESTRICTED: u32 = 4; // restricted coding set
|
||||
pub const AEC_ALLOW_K13: u32 = 8; // allow k=13 option
|
||||
|
||||
/// Mirror of `struct aec_stream` from `<libaec.h>`.
|
||||
///
|
||||
/// Must match the C layout exactly — all fields are C ABI integers/pointers.
|
||||
#[repr(C)]
|
||||
pub struct AecStream {
|
||||
pub next_in: *const u8,
|
||||
pub avail_in: usize,
|
||||
pub total_in: usize,
|
||||
pub next_out: *mut u8,
|
||||
pub avail_out: usize,
|
||||
pub total_out: usize,
|
||||
pub bits_per_sample: u32,
|
||||
pub block_size: u32,
|
||||
pub rsi: u32,
|
||||
pub flags: u32,
|
||||
/// Opaque internal state; initialised to null, set by libaec on first call.
|
||||
pub state: *mut c_void,
|
||||
}
|
||||
|
||||
impl AecStream {
|
||||
/// Return a zero-initialised stream safe to pass to libaec.
|
||||
pub fn zeroed() -> Self {
|
||||
Self {
|
||||
next_in: std::ptr::null(),
|
||||
avail_in: 0,
|
||||
total_in: 0,
|
||||
next_out: std::ptr::null_mut(),
|
||||
avail_out: 0,
|
||||
total_out: 0,
|
||||
bits_per_sample: 0,
|
||||
block_size: 0,
|
||||
rsi: 0,
|
||||
flags: 0,
|
||||
state: std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
/// One-shot decompression. Returns 0 on success.
|
||||
/// One-shot decompression. Returns `AEC_OK` (0) on success.
|
||||
///
|
||||
/// # Safety
|
||||
/// `src` must be valid for `src_len` bytes; `dst` must be valid for `*dst_len` bytes.
|
||||
pub fn aec_buffer_decode(
|
||||
src: *const u8,
|
||||
src_len: usize,
|
||||
dst: *mut u8,
|
||||
dst_len: *mut usize,
|
||||
bits_per_sample: u32,
|
||||
block_size: u32,
|
||||
flags: u32,
|
||||
) -> i32;
|
||||
/// `strm.next_in` must be valid for `strm.avail_in` bytes;
|
||||
/// `strm.next_out` must be valid for `strm.avail_out` bytes.
|
||||
pub fn aec_buffer_decode(strm: *mut AecStream) -> i32;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -33,4 +67,12 @@ mod tests {
|
||||
assert_eq!(AEC_DATA_PREPROCESS, 1);
|
||||
assert_eq!(AEC_DATA_MSB, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn aec_stream_zeroed_has_null_ptrs() {
|
||||
let s = AecStream::zeroed();
|
||||
assert!(s.next_in.is_null());
|
||||
assert!(s.next_out.is_null());
|
||||
assert!(s.state.is_null());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user