use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
use crate::error::Error;
use crate::traits::{RawDecoder, RawProgress};
use super::audio::{AudioState, decode_sample};
use super::bitreader::BitReader;
use super::huffman::Rar2Huffman;
use super::tables::{
AUDIO_TREE_SIZE, LENGTH_BASE, LENGTH_EXTRA, LENGTH_TABLE_SIZE, LENGTH_TREE_SIZE,
MAIN_TREE_SIZE, NON_AUDIO_LENGTHS, OFFSET_BASE, OFFSET_EXTRA, OFFSET_TREE_SIZE, PRETREE_SIZE,
SHORT_BASE, SHORT_EXTRA, SYM_LONG_FIRST, SYM_OLD_OFFSET_END, SYM_REPEAT_LAST, SYM_REREAD_TREES,
SYM_SHORT_FIRST, SYM_SHORT_LAST, WINDOW_MASK, WINDOW_SIZE,
};
pub struct Decoder {
unpack_size: u64,
have_unpack_size: bool,
input_buf: Vec<u8>,
output: Vec<u8>,
drained: usize,
decoded: bool,
poisoned: bool,
}
impl Decoder {
pub const fn new() -> Self {
Self {
unpack_size: 0,
have_unpack_size: false,
input_buf: Vec::new(),
output: Vec::new(),
drained: 0,
decoded: false,
poisoned: false,
}
}
pub fn with_unpack_size(n: u64) -> Self {
let mut d = Self::new();
d.set_unpack_size(n);
d
}
pub fn set_unpack_size(&mut self, n: u64) {
self.unpack_size = n;
self.have_unpack_size = true;
}
}
impl Default for Decoder {
fn default() -> Self {
Self::new()
}
}
impl RawDecoder for Decoder {
fn raw_decode(&mut self, input: &[u8], _output: &mut [u8]) -> Result<RawProgress, Error> {
if self.poisoned {
return Err(Error::Corrupt);
}
if self.decoded {
if !input.is_empty() {
return Err(self.poison(Error::Corrupt));
}
return Ok(RawProgress::default());
}
self.input_buf.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.poisoned {
return Err(Error::Corrupt);
}
if !self.decoded {
self.run_decode()?;
self.decoded = true;
}
let remaining = self.output.len() - self.drained;
let n = remaining.min(output.len());
if n > 0 {
output[..n].copy_from_slice(&self.output[self.drained..self.drained + n]);
self.drained += n;
}
let done = self.drained == self.output.len();
Ok(RawProgress {
consumed: 0,
written: n,
done,
})
}
fn raw_reset(&mut self) {
self.input_buf.clear();
self.output.clear();
self.drained = 0;
self.decoded = false;
self.poisoned = false;
}
}
impl Decoder {
fn poison(&mut self, e: Error) -> Error {
self.poisoned = true;
e
}
fn run_decode(&mut self) -> Result<(), Error> {
if self.unpack_size == 0 {
return Ok(());
}
if self.unpack_size > usize::MAX as u64 {
return Err(self.poison(Error::Unsupported));
}
let target = self.unpack_size as usize;
self.output.reserve_exact(target);
let mut ctx = Box::new(RunCtx::new(target));
let input = core::mem::take(&mut self.input_buf);
let result = ctx.run(&input, &mut self.output);
self.input_buf = input;
if let Err(e) = result {
return Err(self.poison(e));
}
if self.output.len() != target {
return Err(self.poison(Error::UnexpectedEnd));
}
Ok(())
}
}
struct RunCtx {
target: usize,
bit: BitReader,
window: Vec<u8>,
window_pos: usize,
lengths: [u8; LENGTH_TABLE_SIZE],
last_length: u16,
last_offset: u32,
old_offset: [u32; 4],
old_offset_index: usize,
in_audio_block: bool,
num_channels: usize,
channel: usize,
channel_delta: i32,
audio_state: [AudioState; 4],
main_code: Option<Box<Rar2Huffman<MAIN_TREE_SIZE>>>,
offset_code: Option<Box<Rar2Huffman<OFFSET_TREE_SIZE>>>,
length_code: Option<Box<Rar2Huffman<LENGTH_TREE_SIZE>>>,
audio_code: [Option<Box<Rar2Huffman<AUDIO_TREE_SIZE>>>; 4],
}
impl RunCtx {
fn new(target: usize) -> Self {
Self {
target,
bit: BitReader::new(),
window: vec![0u8; WINDOW_SIZE],
window_pos: 0,
lengths: [0u8; LENGTH_TABLE_SIZE],
last_length: 0,
last_offset: 0,
old_offset: [0u32; 4],
old_offset_index: 0,
in_audio_block: false,
num_channels: 0,
channel: 0,
channel_delta: 0,
audio_state: [
AudioState::new(),
AudioState::new(),
AudioState::new(),
AudioState::new(),
],
main_code: None,
offset_code: None,
length_code: None,
audio_code: [None, None, None, None],
}
}
fn run(&mut self, input: &[u8], output: &mut Vec<u8>) -> Result<(), Error> {
self.read_block_header(input)?;
while output.len() < self.target {
if self.in_audio_block {
let tree = self.audio_code[self.channel]
.as_ref()
.ok_or(Error::Corrupt)?;
let sym = tree.decode(&mut self.bit, input)?;
if sym == 256 {
self.read_block_header(input)?;
continue;
}
if sym > 255 {
return Err(Error::Corrupt);
}
let byte = decode_sample(
&mut self.audio_state[self.channel],
&mut self.channel_delta,
sym as u8,
);
self.emit_literal(byte, output);
self.channel += 1;
if self.channel >= self.num_channels {
self.channel = 0;
}
} else {
let tree = self.main_code.as_ref().ok_or(Error::Corrupt)?;
let sym = tree.decode(&mut self.bit, input)?;
if sym < 256 {
self.emit_literal(sym as u8, output);
continue;
}
if sym == SYM_REPEAT_LAST {
let len = self.last_length;
let off = self.last_offset;
if len == 0 || off == 0 {
return Err(Error::Corrupt);
}
self.emit_match(off, len, output)?;
} else if sym <= SYM_OLD_OFFSET_END {
let slot = (self
.old_offset_index
.wrapping_sub((sym - SYM_REPEAT_LAST) as usize))
& 3;
let off = self.old_offset[slot];
if off == 0 {
return Err(Error::Corrupt);
}
let length_tree = self.length_code.as_ref().ok_or(Error::Corrupt)?;
let len_sym = length_tree.decode(&mut self.bit, input)? as usize;
if len_sym >= LENGTH_BASE.len() {
return Err(Error::Corrupt);
}
let mut len = LENGTH_BASE[len_sym] as u32 + 2;
let extra = LENGTH_EXTRA[len_sym] as u32;
if extra > 0 {
len += self.bit.read_bits(extra, input)?;
}
if off >= 0x40000 {
len += 1;
}
if off >= 0x2000 {
len += 1;
}
if off >= 0x101 {
len += 1;
}
self.commit_match_offset(off);
self.last_length = len as u16;
self.emit_match(self.last_offset, len as u16, output)?;
} else if sym <= SYM_SHORT_LAST {
let idx = (sym - SYM_SHORT_FIRST) as usize;
let mut off = SHORT_BASE[idx] + 1;
let extra = SHORT_EXTRA[idx] as u32;
if extra > 0 {
off += self.bit.read_bits(extra, input)?;
}
self.commit_match_offset(off);
self.last_length = 2;
self.emit_match(off, 2, output)?;
} else if sym == SYM_REREAD_TREES {
self.read_block_header(input)?;
continue;
} else if (SYM_LONG_FIRST..(SYM_LONG_FIRST + LENGTH_BASE.len() as u16))
.contains(&sym)
{
let len_idx = (sym - SYM_LONG_FIRST) as usize;
let mut len = LENGTH_BASE[len_idx] as u32 + 3;
let extra = LENGTH_EXTRA[len_idx] as u32;
if extra > 0 {
len += self.bit.read_bits(extra, input)?;
}
let offset_tree = self.offset_code.as_ref().ok_or(Error::Corrupt)?;
let off_sym = offset_tree.decode(&mut self.bit, input)? as usize;
if off_sym >= OFFSET_BASE.len() {
return Err(Error::Corrupt);
}
let mut off = OFFSET_BASE[off_sym] + 1;
let off_extra = OFFSET_EXTRA[off_sym] as u32;
if off_extra > 0 {
off += self.bit.read_bits(off_extra, input)?;
}
if off >= 0x40000 {
len += 1;
}
if off >= 0x2000 {
len += 1;
}
self.commit_match_offset(off);
self.last_length = len as u16;
self.emit_match(off, len as u16, output)?;
} else {
return Err(Error::Corrupt);
}
}
}
Ok(())
}
fn read_block_header(&mut self, input: &[u8]) -> Result<(), Error> {
self.in_audio_block = self.bit.read_bits(1, input)? == 1;
let keep_lengths = self.bit.read_bits(1, input)? == 1;
if !keep_lengths {
self.lengths = [0u8; LENGTH_TABLE_SIZE];
}
let count: usize = if self.in_audio_block {
self.num_channels = self.bit.read_bits(2, input)? as usize + 1;
if self.channel >= self.num_channels {
self.channel = 0;
}
self.num_channels * AUDIO_TREE_SIZE
} else {
NON_AUDIO_LENGTHS
};
if count > LENGTH_TABLE_SIZE {
return Err(Error::Corrupt);
}
let mut pre_lens = [0u8; PRETREE_SIZE];
for slot in pre_lens.iter_mut() {
*slot = self.bit.read_bits(4, input)? as u8;
}
let pre = Rar2Huffman::<PRETREE_SIZE>::from_lengths(&pre_lens)?;
let mut i = 0usize;
while i < count {
let val = pre.decode(&mut self.bit, input)?;
if val < 16 {
self.lengths[i] = (self.lengths[i].wrapping_add(val as u8)) & 0x0F;
i += 1;
} else if val == 16 {
if i == 0 {
return Err(Error::Corrupt);
}
let n = self.bit.read_bits(2, input)? as usize + 3;
let v = self.lengths[i - 1];
let stop = (i + n).min(count);
while i < stop {
self.lengths[i] = v;
i += 1;
}
} else {
let n: usize = if val == 17 {
self.bit.read_bits(3, input)? as usize + 3
} else {
self.bit.read_bits(7, input)? as usize + 11
};
let stop = (i + n).min(count);
while i < stop {
self.lengths[i] = 0;
i += 1;
}
}
}
if self.in_audio_block {
for c in 0..self.num_channels {
let start = c * AUDIO_TREE_SIZE;
let slice = &self.lengths[start..start + AUDIO_TREE_SIZE];
self.audio_code[c] = Some(Box::new(Rar2Huffman::from_lengths(slice)?));
}
for c in self.num_channels..4 {
self.audio_code[c] = None;
}
self.main_code = None;
self.offset_code = None;
self.length_code = None;
} else {
let main =
Rar2Huffman::<MAIN_TREE_SIZE>::from_lengths(&self.lengths[0..MAIN_TREE_SIZE])?;
let offset = Rar2Huffman::<OFFSET_TREE_SIZE>::from_lengths(
&self.lengths[MAIN_TREE_SIZE..MAIN_TREE_SIZE + OFFSET_TREE_SIZE],
)?;
let length = Rar2Huffman::<LENGTH_TREE_SIZE>::from_lengths(
&self.lengths[MAIN_TREE_SIZE + OFFSET_TREE_SIZE
..MAIN_TREE_SIZE + OFFSET_TREE_SIZE + LENGTH_TREE_SIZE],
)?;
self.main_code = Some(Box::new(main));
self.offset_code = Some(Box::new(offset));
self.length_code = Some(Box::new(length));
for c in 0..4 {
self.audio_code[c] = None;
}
}
Ok(())
}
fn commit_match_offset(&mut self, off: u32) {
let slot = self.old_offset_index & 3;
self.old_offset[slot] = off;
self.last_offset = off;
self.old_offset_index = self.old_offset_index.wrapping_add(1);
}
fn emit_literal(&mut self, byte: u8, output: &mut Vec<u8>) {
self.window[self.window_pos] = byte;
self.window_pos = (self.window_pos + 1) & WINDOW_MASK;
output.push(byte);
}
fn emit_match(&mut self, offset: u32, length: u16, output: &mut Vec<u8>) -> Result<(), Error> {
if length == 0 {
return Err(Error::Corrupt);
}
let off = offset as usize;
if off == 0 || off > WINDOW_SIZE {
return Err(Error::InvalidDistance);
}
let mut remaining = length as usize;
let cap = self.target - output.len();
if remaining > cap {
remaining = cap;
}
while remaining > 0 {
let src = (self.window_pos + WINDOW_SIZE - off) & WINDOW_MASK;
let b = self.window[src];
self.window[self.window_pos] = b;
self.window_pos = (self.window_pos + 1) & WINDOW_MASK;
output.push(b);
remaining -= 1;
}
Ok(())
}
}