#![cfg_attr(docsrs, doc(cfg(feature = "lha")))]
extern crate alloc;
use alloc::vec::Vec;
mod bits;
mod huffman;
pub mod lzhuf;
pub mod static_huff;
use crate::error::Error;
use crate::traits::{Algorithm, RawDecoder, RawEncoder, RawProgress};
use static_huff::Params;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Method {
Lh1,
Lh4,
Lh5,
Lh6,
Lh7,
}
impl Method {
fn name(self) -> &'static str {
match self {
Method::Lh1 => "lh1",
Method::Lh4 => "lh4",
Method::Lh5 => "lh5",
Method::Lh6 => "lh6",
Method::Lh7 => "lh7",
}
}
fn is_static(self) -> bool {
!matches!(self, Method::Lh1)
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct DecoderConfig {
pub expected_len: Option<usize>,
}
impl DecoderConfig {
pub fn with_len(expected_len: usize) -> Self {
Self {
expected_len: Some(expected_len),
}
}
}
macro_rules! define_method {
($marker:ident, $variant:ident, $name:literal, $doc:literal) => {
#[doc = $doc]
#[derive(Debug, Clone, Copy, Default)]
pub struct $marker;
impl Algorithm for $marker {
const NAME: &'static str = $name;
type Encoder = Encoder;
type Decoder = Decoder;
type EncoderConfig = ();
type DecoderConfig = DecoderConfig;
fn encoder_with(_: ()) -> Encoder {
Encoder::new(Method::$variant)
}
fn decoder_with(config: DecoderConfig) -> Decoder {
Decoder::with_config(Method::$variant, config)
}
}
};
}
define_method!(
Lh1,
Lh1,
"lh1",
"LHA `-lh1-`: 4 KiB dictionary, adaptive Huffman (LZHUF)."
);
define_method!(
Lh4,
Lh4,
"lh4",
"LHA `-lh4-`: 4 KiB dictionary, static Huffman."
);
define_method!(
Lh5,
Lh5,
"lh5",
"LHA `-lh5-`: 16 KiB dictionary, static Huffman."
);
define_method!(
Lh6,
Lh6,
"lh6",
"LHA `-lh6-`: 64 KiB dictionary, static Huffman."
);
define_method!(
Lh7,
Lh7,
"lh7",
"LHA `-lh7-`: 128 KiB dictionary, static Huffman."
);
#[derive(Debug)]
pub struct Encoder {
method: Method,
input: Vec<u8>,
output: Vec<u8>,
out_cursor: usize,
finalized: bool,
}
impl Encoder {
fn new(method: Method) -> Self {
Self {
method,
input: Vec::new(),
output: Vec::new(),
out_cursor: 0,
finalized: false,
}
}
fn finalize(&mut self) {
let payload = if self.method.is_static() {
let params = Params::for_method(self.method.name());
static_huff::encode_payload(&self.input, params)
} else {
lzhuf::encode_payload(&self.input)
};
self.output.extend_from_slice(&payload);
}
}
impl RawEncoder for Encoder {
fn raw_encode(&mut self, input: &[u8], _output: &mut [u8]) -> Result<RawProgress, Error> {
self.input.extend_from_slice(input);
Ok(RawProgress {
consumed: input.len(),
written: 0,
done: false,
})
}
fn raw_finish(&mut self, output: &mut [u8]) -> Result<RawProgress, Error> {
if !self.finalized {
self.finalize();
self.finalized = true;
}
let remaining = self.output.len() - self.out_cursor;
let take = remaining.min(output.len());
output[..take].copy_from_slice(&self.output[self.out_cursor..self.out_cursor + take]);
self.out_cursor += take;
Ok(RawProgress {
consumed: 0,
written: take,
done: self.out_cursor >= self.output.len(),
})
}
fn raw_reset(&mut self) {
self.input.clear();
self.output.clear();
self.out_cursor = 0;
self.finalized = false;
}
}
#[derive(Debug)]
pub struct Decoder {
method: Method,
expected_len: Option<usize>,
input: Vec<u8>,
output: Vec<u8>,
out_cursor: usize,
decoded: bool,
}
impl Decoder {
fn with_config(method: Method, config: DecoderConfig) -> Self {
Self {
method,
expected_len: config.expected_len,
input: Vec::new(),
output: Vec::new(),
out_cursor: 0,
decoded: false,
}
}
fn decode_all(&mut self) -> Result<(), Error> {
if self.decoded {
return Ok(());
}
let payload = &self.input[..];
self.output = if self.method.is_static() {
let params = Params::for_method(self.method.name());
static_huff::decode_payload(payload, self.expected_len, params)?
} else {
match self.expected_len {
Some(n) => lzhuf::decode_payload(payload, n)?,
None if payload.is_empty() => Vec::new(),
None => return Err(Error::Unsupported),
}
};
self.decoded = true;
Ok(())
}
fn drain(&mut self, output: &mut [u8]) -> RawProgress {
let remaining = self.output.len() - self.out_cursor;
let take = remaining.min(output.len());
output[..take].copy_from_slice(&self.output[self.out_cursor..self.out_cursor + take]);
self.out_cursor += take;
RawProgress {
consumed: 0,
written: take,
done: self.out_cursor >= self.output.len(),
}
}
}
impl RawDecoder for Decoder {
fn raw_decode(&mut self, input: &[u8], output: &mut [u8]) -> Result<RawProgress, Error> {
if !self.decoded {
self.input.extend_from_slice(input);
return Ok(RawProgress {
consumed: input.len(),
written: 0,
done: false,
});
}
let p = self.drain(output);
Ok(RawProgress {
consumed: 0,
written: p.written,
done: p.done,
})
}
fn raw_finish(&mut self, output: &mut [u8]) -> Result<RawProgress, Error> {
if !self.decoded && self.input.is_empty() {
self.decoded = true;
}
self.decode_all()?;
Ok(self.drain(output))
}
fn raw_reset(&mut self) {
self.input.clear();
self.output.clear();
self.out_cursor = 0;
self.decoded = false;
}
}