use std::cell::RefCell;
use flate2::Compression;
use flate2::read::ZlibDecoder;
use flate2::write::ZlibEncoder;
use crate::Result;
use crate::error::SlowError;
use crate::header::SignalCompression;
pub(crate) fn decompress_signal(bytes: &[u8], method: SignalCompression) -> Result<Vec<i16>> {
match method {
SignalCompression::None => decompress_signal_none(bytes),
SignalCompression::SvbZd => decompress_signal_svb_zd(bytes),
SignalCompression::ExZd => decompress_signal_ex_zd(bytes),
}
}
pub(crate) const MAX_RECORD_DECOMP: usize = 256 * 1024 * 1024;
pub(crate) fn decompress_record_zstd(bytes: &[u8]) -> Result<Vec<u8>> {
thread_local! {
static DECOMP: RefCell<Option<zstd::bulk::Decompressor<'static>>> =
const { RefCell::new(None) };
}
DECOMP.with(|cell| {
let mut opt = cell.borrow_mut();
let d = opt.get_or_insert_with(|| {
zstd::bulk::Decompressor::new().expect("zstd decompressor init")
});
d.decompress(bytes, MAX_RECORD_DECOMP)
.map_err(|e| SlowError::Decompression(e.to_string()))
})
}
pub(crate) fn decompress_record_zlib(bytes: &[u8]) -> Result<Vec<u8>> {
use std::io::Read;
let mut out = Vec::new();
ZlibDecoder::new(bytes)
.take(MAX_RECORD_DECOMP as u64 + 1)
.read_to_end(&mut out)
.map_err(|e| SlowError::Decompression(e.to_string()))?;
if out.len() > MAX_RECORD_DECOMP {
return Err(SlowError::Decompression(
"decompressed record exceeds 256 MiB limit".into(),
));
}
Ok(out)
}
pub(crate) fn compress_record_zstd_tl(bytes: &[u8]) -> Result<Vec<u8>> {
thread_local! {
static COMP: RefCell<Option<zstd::bulk::Compressor<'static>>> =
const { RefCell::new(None) };
}
COMP.with(|cell| {
let mut opt = cell.borrow_mut();
let c = opt
.get_or_insert_with(|| zstd::bulk::Compressor::new(1).expect("zstd compressor init"));
c.compress(bytes)
.map_err(|e| SlowError::Decompression(e.to_string()))
})
}
pub(crate) fn compress_record_zlib(bytes: &[u8]) -> Result<Vec<u8>> {
use std::io::Write;
let mut enc = ZlibEncoder::new(Vec::new(), Compression::new(1));
enc.write_all(bytes)
.map_err(|e| SlowError::Decompression(e.to_string()))?;
enc.finish()
.map_err(|e| SlowError::Decompression(e.to_string()))
}
fn decompress_signal_none(bytes: &[u8]) -> Result<Vec<i16>> {
if !bytes.len().is_multiple_of(2) {
return Err(SlowError::Decompression(format!(
"uncompressed signal byte count {} is not a multiple of 2",
bytes.len()
)));
}
Ok(bytes
.chunks_exact(2)
.map(|c| i16::from_le_bytes([c[0], c[1]]))
.collect())
}
fn decompress_signal_svb_zd(data: &[u8]) -> Result<Vec<i16>> {
if data.len() < 4 {
return Err(SlowError::Decompression(
"SVB-ZD data shorter than 4-byte length prefix".into(),
));
}
let n = u32::from_le_bytes(data[..4].try_into().unwrap()) as usize;
const MAX_SIGNAL_SAMPLES: usize = 128 * 1024 * 1024;
if n > MAX_SIGNAL_SAMPLES {
return Err(SlowError::Decompression(format!(
"signal sample count {n} exceeds {MAX_SIGNAL_SAMPLES} limit"
)));
}
svb::decode_svbzd_fused(&data[4..], n).map_err(|e| SlowError::Decompression(e.to_string()))
}
fn decompress_signal_ex_zd(data: &[u8]) -> Result<Vec<i16>> {
thread_local! {
static DECODER: RefCell<svb::ExzdDecoder> = RefCell::new(svb::ExzdDecoder::new());
}
DECODER.with(|cell| {
let mut decoder = cell.borrow_mut();
let mut out = Vec::new();
decoder
.decode_into(data, &mut out)
.map_err(|e| SlowError::Decompression(e.to_string()))?;
Ok(out)
})
}
pub(crate) fn compress_signal_ex_zd(samples: &[i16]) -> Result<Vec<u8>> {
Ok(svb::encode_exzd(samples))
}
pub(crate) fn compress_signal_svb_zd(samples: &[i16]) -> Result<Vec<u8>> {
let n = samples.len() as u32;
let svb_bytes = svb::encode_svbzd(samples);
let mut out = Vec::with_capacity(4 + svb_bytes.len());
out.extend_from_slice(&n.to_le_bytes());
out.extend_from_slice(&svb_bytes);
Ok(out)
}