infinite_rs/module/kraken.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
//! Kraken decompressor wrapper.
//!
//! Originally from: <https://github.com/rfuzzo/red4lib>
use crate::common::errors::{DecompressionError, Error};
use crate::Result;
#[link(name = "kraken_static")]
extern "C" {
// EXPORT int Kraken_Decompress(const byte *src, size_t src_len, byte *dst, size_t dst_len)
fn Kraken_Decompress(
buffer: *const u8,
bufferSize: usize,
outputBuffer: *mut u8,
outputBufferSize: usize,
) -> i32;
}
/// UNSAFE: Decompresses a Kraken-compressed buffer.
///
/// # Arguments
///
/// * `compressed_buffer` - A vector containing the compressed data.
/// * `output_buffer` - A mutable reference to a vector where the decompressed data will be stored.
/// * `size` - The expected size of the decompressed data.
///
/// # Returns
///
/// Offset of `compressed_buffer` after the compressed data has been read, or -1 if decompression has failed.
///
/// # Errors
///
/// This function will return a [`DecompressionError`] if:
/// - The length of `compressed_buffer` or `size` cannot be converted to [`i64`].
/// - The decompression fails as indicated by a negative result from [`Kraken_Decompress`].
/// - The resulting decompressed size exceeds the buffer length.
///
/// # Safety
///
/// This function is unsafe because it calls an external C function [`Kraken_Decompress`] which operates on raw pointers.
/// The caller must ensure that the `compressed_buffer` and `output_buffer` are valid and properly sized.
pub fn decompress(
compressed_buffer: &[u8],
output_buffer: &mut Vec<u8>,
size: usize,
) -> Result<i32> {
let mut buffer = vec![0; size + 8]; // HACK: Ensures that pointer for memory buffer is aligned.
let result;
unsafe {
result = Kraken_Decompress(
compressed_buffer.as_ptr(),
compressed_buffer.len(),
buffer.as_mut_ptr(),
size,
);
if result < 0 {
return Err(Error::DecompressionError(
DecompressionError::DecompressionFailed(result),
));
}
let result_usize = usize::try_from(result)
.map_err(|_| Error::DecompressionError(DecompressionError::BufferSizeOverflow))?;
if result_usize > buffer.len() {
return Err(Error::DecompressionError(
DecompressionError::BufferSizeOverflow,
));
}
buffer.resize(result_usize, 0);
*output_buffer = buffer;
}
Ok(result)
}