use super::{state::ExplodeState, *};
use crate::{CompressionMode, Result};
use std::io::Read;
impl ExplodeState {
pub fn waste_bits<R: Read>(&mut self, reader: &mut R, n_bits: u32) -> Result<u32> {
if n_bits <= self.extra_bits {
self.extra_bits -= n_bits;
self.bit_buff >>= n_bits;
return Ok(PKDCL_OK);
}
self.bit_buff >>= self.extra_bits;
if self.in_pos >= self.in_bytes {
self.in_pos = 0;
self.in_bytes = reader.read(&mut self.in_buff)?;
if self.in_bytes == 0 {
return Ok(PKDCL_STREAM_END);
}
}
if self.in_pos < self.in_bytes {
self.bit_buff |= (self.in_buff[self.in_pos] as u32) << 8;
self.in_pos += 1;
}
self.bit_buff >>= n_bits - self.extra_bits;
self.extra_bits = (self.extra_bits + 8) - n_bits;
Ok(PKDCL_OK)
}
pub fn decode_lit<R: Read>(&mut self, reader: &mut R) -> Result<u32> {
if (self.bit_buff & 1) != 0 {
if self.waste_bits(reader, 1)? != PKDCL_OK {
return Ok(LITERAL_ERROR);
}
let length_code = self.length_codes[(self.bit_buff & 0xFF) as usize] as usize;
if self.waste_bits(reader, self.len_bits[length_code] as u32)? != PKDCL_OK {
return Ok(LITERAL_ERROR);
}
let extra_length_bits = self.ex_len_bits[length_code];
let mut final_length_code = length_code;
if extra_length_bits != 0 {
let extra_length = self.bit_buff & ((1 << extra_length_bits) - 1);
if self.waste_bits(reader, extra_length_bits as u32)? != PKDCL_OK
&& (length_code + extra_length as usize) != 0x10E
{
return Ok(LITERAL_ERROR);
}
final_length_code = (self.len_base[length_code] as usize) + (extra_length as usize);
}
return Ok(final_length_code as u32 + 0x100);
}
if self.waste_bits(reader, 1)? != PKDCL_OK {
return Ok(LITERAL_ERROR);
}
if matches!(self.ctype, CompressionMode::Binary) {
let uncompressed_byte = self.bit_buff & 0xFF;
if self.waste_bits(reader, 8)? != PKDCL_OK {
return Ok(LITERAL_ERROR);
}
return Ok(uncompressed_byte);
}
let value = if (self.bit_buff & 0xFF) != 0 {
let mut val = self.offs_2c34[(self.bit_buff & 0xFF) as usize] as u32;
if val == 0xFF {
if (self.bit_buff & 0x3F) != 0 {
if self.waste_bits(reader, 4)? != PKDCL_OK {
return Ok(LITERAL_ERROR);
}
val = self.offs_2d34[(self.bit_buff & 0xFF) as usize] as u32;
} else {
if self.waste_bits(reader, 6)? != PKDCL_OK {
return Ok(LITERAL_ERROR);
}
val = self.offs_2e34[(self.bit_buff & 0x7F) as usize] as u32;
}
}
val
} else {
if self.waste_bits(reader, 8)? != PKDCL_OK {
return Ok(LITERAL_ERROR);
}
self.offs_2eb4[(self.bit_buff & 0xFF) as usize] as u32
};
if self.waste_bits(reader, self.ch_bits_asc[value as usize] as u32)? != PKDCL_OK {
Ok(LITERAL_ERROR)
} else {
Ok(value)
}
}
pub fn decode_dist<R: Read>(&mut self, reader: &mut R, rep_length: u32) -> Result<u32> {
let dist_pos_code = self.dist_pos_codes[(self.bit_buff & 0xFF) as usize];
let dist_pos_bits = self.dist_bits[dist_pos_code as usize];
if self.waste_bits(reader, dist_pos_bits as u32)? != PKDCL_OK {
return Ok(0);
}
let distance = if rep_length == 2 {
let dist = ((dist_pos_code as u32) << 2) | (self.bit_buff & 0x03);
if self.waste_bits(reader, 2)? != PKDCL_OK {
return Ok(0);
}
dist
} else {
let dist =
((dist_pos_code as u32) << self.dsize_bits) | (self.bit_buff & self.dsize_mask);
if self.waste_bits(reader, self.dsize_bits)? != PKDCL_OK {
return Ok(0);
}
dist
};
Ok(distance + 1)
}
}