lzma_adaptive_sys/lib.rs
1//! FFI bindings to sasquatch's LZMA adaptive library
2//!
3//! This crate provides Rust bindings to the LZMA adaptive decompression
4//! functionality from the sasquatch project, which implements brute-force
5//! parameter discovery for LZMA compressed data in SquashFS v3 filesystems.
6
7use std::os::raw::{c_int, c_ulong};
8
9extern "C" {
10 /// Decompress LZMA data with specific parameters
11 ///
12 /// This function is from sasquatch's LZMA adaptive implementation and supports
13 /// brute-force parameter discovery for LZMA compressed data blocks.
14 ///
15 /// # Parameters
16 /// - `dest`: Output buffer for decompressed data
17 /// - `dest_len`: Pointer to size of output buffer, updated with actual decompressed size
18 /// - `source`: Input compressed data
19 /// - `source_len`: Size of input data
20 /// - `lc`: Literal context bits (0-4)
21 /// - `lp`: Literal position bits (0-4)
22 /// - `pb`: Position bits (0-4)
23 /// - `dictionary_size`: LZMA dictionary size (or 0 for default 8MB)
24 /// - `offset`: Offset into source data where LZMA data begins
25 ///
26 /// # Returns
27 /// 0 on success (Z_OK), non-zero error code on failure
28 pub fn lzmaspec_uncompress(
29 dest: *mut u8,
30 dest_len: *mut c_ulong,
31 source: *const u8,
32 source_len: c_ulong,
33 lc: c_int,
34 lp: c_int,
35 pb: c_int,
36 dictionary_size: c_int,
37 offset: c_int,
38 ) -> c_int;
39}
40
41/// Safe wrapper around lzmaspec_uncompress
42///
43/// # Parameters
44/// - `source`: Input compressed data
45/// - `lc`: Literal context bits (0-4)
46/// - `lp`: Literal position bits (0-4)
47/// - `pb`: Position bits (0-4)
48/// - `dictionary_size`: LZMA dictionary size (0 for default)
49/// - `offset`: Offset into source data where LZMA data begins
50/// - `max_output_size`: Maximum expected output size
51///
52/// # Returns
53/// `Ok(Vec<u8>)` with decompressed data on success, `Err(i32)` with error code on failure
54pub fn decompress_lzma(
55 source: &[u8],
56 lc: u32,
57 lp: u32,
58 pb: u32,
59 dictionary_size: u32,
60 offset: usize,
61 max_output_size: usize,
62) -> Result<Vec<u8>, i32> {
63 if offset >= source.len() {
64 return Err(-1); // Invalid offset
65 }
66
67 let mut output = vec![0u8; max_output_size];
68 let mut dest_len = max_output_size as c_ulong;
69
70 let result = unsafe {
71 lzmaspec_uncompress(
72 output.as_mut_ptr(),
73 &mut dest_len,
74 source.as_ptr(),
75 source.len() as c_ulong,
76 lc as c_int,
77 lp as c_int,
78 pb as c_int,
79 dictionary_size as c_int,
80 offset as c_int,
81 )
82 };
83
84 if result == 0 && dest_len > 0 {
85 output.truncate(dest_len as usize);
86 Ok(output)
87 } else {
88 Err(result)
89 }
90}