Skip to main content

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}