use crate::{LzssError, Read, Write};
mod compress;
mod decompress;
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct LzssDyn {
ei: usize,
ej: usize,
c: u8,
}
impl LzssDyn {
pub fn new(ei: usize, ej: usize, c: u8) -> Result<Self, LzssDynError> {
if ej == 0 {
Err(LzssDynError::EjIsZero)
} else if ej >= ei {
Err(LzssDynError::EiNotLargerThanEj)
} else if ei + ej < 8 {
Err(LzssDynError::EiEjToSmall)
} else if ei + ej > 24 {
Err(LzssDynError::EiEjToLarge)
} else {
Ok(LzssDyn { ei, ej, c })
}
}
#[inline(always)]
pub const fn ei(&self) -> usize {
self.ei
}
#[inline(always)]
pub const fn ej(&self) -> usize {
self.ej
}
#[inline(always)]
pub const fn c(&self) -> u8 {
self.c
}
#[inline(always)]
pub(crate) const fn n(&self) -> usize {
1 << self.ei
}
#[inline(always)]
pub(crate) const fn p(&self) -> usize {
(1 + self.ei + self.ej) / 9
}
#[inline(always)]
pub(crate) const fn f(&self) -> usize {
(1 << self.ej) + self.p()
}
#[cfg(any(test, feature = "alloc"))]
pub fn compress<R: Read, W: Write>(
&self,
mut reader: R,
mut writer: W,
) -> Result<W::Output, LzssError<R::Error, W::Error>> {
let mut buffer = vec![self.c; 2 * self.n()];
self.compress_internal(&mut reader, &mut writer, &mut buffer)?;
writer.finish().map_err(LzssError::WriteError)
}
pub fn compress_with_buffer<R: Read, W: Write>(
&self,
mut reader: R,
mut writer: W,
buffer: &mut [u8],
) -> Result<W::Output, LzssError<R::Error, W::Error>> {
assert!(buffer.len() >= 2 * self.n());
unsafe { ::core::ptr::write_bytes(buffer.as_mut_ptr(), self.c, self.n() - self.f()) };
self.compress_internal(&mut reader, &mut writer, buffer)?;
writer.finish().map_err(LzssError::WriteError)
}
#[cfg(any(test, feature = "alloc"))]
pub fn decompress<R: Read, W: Write>(
&self,
mut reader: R,
mut writer: W,
) -> Result<W::Output, LzssError<R::Error, W::Error>> {
let mut buffer = vec![self.c; self.n()];
self.decompress_internal(&mut reader, &mut writer, &mut buffer)?;
writer.finish().map_err(LzssError::WriteError)
}
pub fn decompress_with_buffer<R: Read, W: Write>(
&self,
mut reader: R,
mut writer: W,
buffer: &mut [u8],
) -> Result<W::Output, LzssError<R::Error, W::Error>> {
assert!(buffer.len() >= self.n());
unsafe { ::core::ptr::write_bytes(buffer.as_mut_ptr(), self.c, self.n()) };
self.decompress_internal(&mut reader, &mut writer, buffer)?;
writer.finish().map_err(LzssError::WriteError)
}
}
#[derive(Debug)]
pub enum LzssDynError {
EjIsZero,
EiNotLargerThanEj,
EiEjToSmall,
EiEjToLarge,
}
impl core::fmt::Display for LzssDynError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
LzssDynError::EjIsZero => f.write_str("Invalid EJ, must be larger than 0"),
LzssDynError::EiNotLargerThanEj => f.write_str("Invalid EI, must be larger than EJ"),
LzssDynError::EiEjToSmall => f.write_str("Invalid EI, EJ, both together must be 8 or more"),
LzssDynError::EiEjToLarge => f.write_str("Invalid EI, EJ, both together must be 24 or less"),
}
}
}
#[cfg(any(test, feature = "std"))]
impl std::error::Error for LzssDynError {}
#[cfg(test)]
mod tests {
use crate::dynamic::LzssDyn;
use crate::slice::SliceReader;
use crate::vec::VecWriter;
use crate::ResultLzssErrorVoidExt;
fn test_lzss() -> LzssDyn {
LzssDyn::new(10, 4, 0x20).unwrap()
}
const TEST_DATA: &[u8; 27] = b"Sample Data 11221233123";
const COMPRESSED_DATA: [u8; 26] = [
169, 216, 109, 183, 11, 101, 149, 246, 13, 18, 195, 116, 176, 191, 81, 152, 204, 102, 83, 32,
0, 19, 57, 152, 3, 16,
];
#[test]
fn test_decompress() {
let output = test_lzss()
.decompress(
SliceReader::new(&COMPRESSED_DATA),
VecWriter::with_capacity(TEST_DATA.len()),
)
.void_unwrap();
assert_eq!(output.as_slice(), TEST_DATA);
}
#[test]
fn test_compress() {
let output = test_lzss()
.compress(
SliceReader::new(TEST_DATA),
VecWriter::with_capacity(COMPRESSED_DATA.len()),
)
.void_unwrap();
assert_eq!(output.as_slice(), COMPRESSED_DATA);
}
#[test]
fn test_compress_big() {
let big_test_data = include_bytes!("mod.rs");
let output1 = test_lzss()
.compress(
SliceReader::new(big_test_data),
VecWriter::with_capacity(big_test_data.len()),
)
.void_unwrap();
let output2 = test_lzss()
.decompress(
SliceReader::new(&output1),
VecWriter::with_capacity(big_test_data.len()),
)
.void_unwrap();
assert_eq!(output2.as_slice(), big_test_data);
}
#[test]
fn test_decompress_with_buffer() {
let mut buffer = [0u8; 1111];
let output = test_lzss()
.decompress_with_buffer(
SliceReader::new(&COMPRESSED_DATA),
VecWriter::with_capacity(TEST_DATA.len()),
&mut buffer,
)
.void_unwrap();
assert_eq!(output.as_slice(), TEST_DATA);
}
#[test]
fn test_compress_with_buffer() {
let mut buffer = [0u8; 2222];
let output = test_lzss()
.compress_with_buffer(
SliceReader::new(TEST_DATA),
VecWriter::with_capacity(COMPRESSED_DATA.len()),
&mut buffer,
)
.void_unwrap();
assert_eq!(output.as_slice(), COMPRESSED_DATA);
}
}