use crate::compression::{
CodecImplementation, CompressionCodec, CompressionCodecType, DecompressResult,
};
use crate::error::{Error, Result};
use crate::header::CodecType;
use lzma_rs::decompress::raw::{LzmaDecoder, LzmaParams, LzmaProperties};
use std::io::Cursor;
pub struct LzmaCodec {
engine: LzmaDecoder,
}
impl CompressionCodec for LzmaCodec {}
fn get_lzma_dict_size(level: u32, reduce_size: u32) -> u32 {
let mut dict_size = if level <= 5 {
1 << (level * 2 + 14)
} else if level <= 7 {
1 << 25
} else {
1 << 26
};
if dict_size > reduce_size {
for i in 11..=30 {
if reduce_size <= (2u32 << i) {
dict_size = 2u32 << i;
break;
}
if reduce_size <= (3u32 << i) {
dict_size = 3u32 << i;
break;
}
}
}
dict_size
}
impl CompressionCodecType for LzmaCodec {
fn codec_type(&self) -> CodecType
where
Self: Sized,
{
CodecType::LzmaV5
}
}
#[cfg(not(feature = "fast_lzma"))]
impl CodecImplementation for LzmaCodec {
fn new(hunk_size: u32) -> Result<Self> {
Ok(LzmaCodec {
engine: LzmaDecoder::new(
LzmaParams::new(
LzmaProperties {
lc: 3,
lp: 0,
pb: 2,
},
get_lzma_dict_size(9, hunk_size),
None,
),
None,
)
.map_err(|_| Error::DecompressionError)?,
})
}
fn decompress(&mut self, input: &[u8], mut output: &mut [u8]) -> Result<DecompressResult> {
let mut read = Cursor::new(input);
let len = output.len();
self.engine.reset(Some(Some(len as u64)));
self.engine
.decompress(&mut read, &mut output)
.map_err(|_| Error::DecompressionError)?;
Ok(DecompressResult::new(len, read.position() as usize))
}
}
#[cfg(feature = "fast_lzma")]
impl CodecImplementation for LzmaCodec {
fn new(hunk_size: u32) -> Result<Self> {
let dict_size = get_lzma_dict_size(9, hunk_size);
Ok(LzmaCodec {
engine: LzmaDecoder::new_with_buffer(
LzmaParams::new(
LzmaProperties {
lc: 3,
lp: 0,
pb: 2,
},
dict_size,
None,
),
None,
vec![0; dict_size as usize],
)
.map_err(|_| Error::DecompressionError)?,
})
}
fn decompress(&mut self, input: &[u8], mut output: &mut [u8]) -> Result<DecompressResult> {
use lzma_rs::decompress::raw::LzAccumBuffer;
let mut read = Cursor::new(input);
let len = output.len();
self.engine.reset(Some(Some(len as u64)));
self.engine
.decompress_with_buffer::<LzAccumBuffer<_>, _, _>(&mut read, &mut output)
.map_err(|_| Error::DecompressionError)?;
Ok(DecompressResult::new(len, read.position() as usize))
}
}