mod structures;
pub use structures::*;
use super::traits::CType;
use lzham_sys::lzham_decompress_state_ptr;
use std::{
io::{BufRead, Write},
os::raw::c_uint,
};
#[derive(Clone, Debug)]
pub struct Decompressor(lzham_decompress_state_ptr);
impl Decompressor {
pub fn from_options(options: DecompressionOptions) -> Self {
Self(unsafe { lzham_sys::lzham_decompress_init(&options.to_c_type()) })
}
pub fn reinit(&self, options: DecompressionOptions) -> Self {
Self(unsafe { lzham_sys::lzham_decompress_reinit(self.0, &options.to_c_type()) })
}
pub fn deinit(&self) -> u32 {
unsafe { lzham_sys::lzham_decompress_deinit(self.0) }
}
pub fn decompress<R: BufRead, W: Write>(
&self,
input: &mut R,
output: &mut W,
uncompressed_size: usize,
) -> DecompressionStatus {
let mut input_buf = Vec::new();
if input.read_to_end(&mut input_buf).is_err() {
return DecompressionStatus::Failed;
}
let mut output_buffer: Vec<u8> = Vec::with_capacity(uncompressed_size);
let uncompressed_size_szt = uncompressed_size as lzham_sys::size_t;
let mut in_buf_ofs = 0;
let mut out_buf_ofs = 0;
let mut dst_bytes_left = uncompressed_size_szt;
let mut status;
let mut num_in_bytes;
let mut out_buf_len;
loop {
num_in_bytes = input_buf.len() as lzham_sys::size_t;
out_buf_len = uncompressed_size_szt - out_buf_ofs;
let status_int = unsafe {
lzham_sys::lzham_decompress(
self.0,
input_buf.as_ptr().add(in_buf_ofs as usize),
&mut num_in_bytes,
output_buffer.as_mut_ptr().add(out_buf_ofs as usize),
&mut out_buf_len,
1 as c_uint,
)
};
in_buf_ofs += num_in_bytes;
out_buf_ofs += out_buf_len;
if out_buf_len > dst_bytes_left {
return DecompressionStatus::Failed;
}
dst_bytes_left -= out_buf_len;
status = DecompressionStatus::from_c_type(status_int);
if status.is_success_or_first_failure() {
break;
}
}
unsafe {
output_buffer.set_len(uncompressed_size);
}
if output.write(&output_buffer).is_err() {
return DecompressionStatus::Failed;
}
status
}
}