use crate::error::Error;
pub fn decompress_lzma(
compressed: &[u8],
max_output: usize,
expected_size: Option<usize>,
) -> Result<Vec<u8>, Error> {
if compressed.len() < 5 {
return Err(Error::DecompressionFailed {
method: "lzma",
detail: "LZMA stream too short (need at least 5 bytes for header)".into(),
});
}
let uncompressed_size_bytes: [u8; 8] = match expected_size {
Some(size) => (size as u64).to_le_bytes(),
None => [0xFF; 8],
};
let mut lzma_header = Vec::with_capacity(13 + compressed.len() - 5);
lzma_header.extend_from_slice(&compressed[..5]); lzma_header.extend_from_slice(&uncompressed_size_bytes);
lzma_header.extend_from_slice(&compressed[5..]);
let mut output = Vec::with_capacity(max_output.min(compressed.len() * 4));
let mut reader = std::io::BufReader::new(std::io::Cursor::new(&lzma_header));
match lzma_rs::lzma_decompress(&mut reader, &mut output) {
Ok(()) => {}
Err(e) => {
let msg = e.to_string();
if !output.is_empty() && msg.contains("more bytes are available") {
} else {
return Err(Error::DecompressionFailed {
method: "lzma",
detail: msg,
});
}
}
}
if output.len() > max_output {
output.truncate(max_output);
}
Ok(output)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn too_short_input() {
let result = decompress_lzma(&[0x5D, 0x00, 0x00], 1024, None);
assert!(result.is_err());
}
}