use crate::types::{AcbError, AcbResult};
pub fn compress(data: &[u8]) -> Vec<u8> {
lz4_flex::compress_prepend_size(data)
}
pub fn decompress(data: &[u8]) -> AcbResult<Vec<u8>> {
lz4_flex::decompress_size_prepended(data)
.map_err(|e| AcbError::Compression(format!("LZ4 decompression failed: {}", e)))
}
#[derive(Debug, Default)]
pub struct StringPoolBuilder {
data: Vec<u8>,
}
impl StringPoolBuilder {
pub fn new() -> Self {
Self { data: Vec::new() }
}
pub fn add(&mut self, s: &str) -> (u32, u16) {
let offset = self.data.len() as u32;
let len = s.len() as u16;
self.data.extend_from_slice(s.as_bytes());
(offset, len)
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub fn uncompressed_size(&self) -> usize {
self.data.len()
}
pub fn compress(&self) -> Vec<u8> {
compress(&self.data)
}
}
#[derive(Debug, Clone)]
pub struct StringPool {
data: Vec<u8>,
}
impl StringPool {
pub fn from_data(data: Vec<u8>) -> Self {
Self { data }
}
pub fn from_compressed(compressed: &[u8]) -> AcbResult<Self> {
let data = decompress(compressed)?;
Ok(Self { data })
}
pub fn get(&self, offset: u32, len: u16) -> AcbResult<&str> {
let start = offset as usize;
let end = start + len as usize;
if end > self.data.len() {
return Err(AcbError::Corrupt(offset as u64));
}
std::str::from_utf8(&self.data[start..end]).map_err(|_| AcbError::Corrupt(offset as u64))
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
}