use super::super::blocks::literals_section::LiteralsSection;
use super::super::blocks::literals_section::LiteralsSectionType;
use super::bit_reader_reverse::BitReaderReversed;
use super::scratch::HuffmanScratch;
use crate::huff0::HuffmanDecoder;
pub fn decode_literals(
section: &LiteralsSection,
scratch: &mut HuffmanScratch,
source: &[u8],
target: &mut Vec<u8>,
) -> Result<u32, String> {
match section.ls_type {
LiteralsSectionType::Raw => {
target.extend(&source[0..section.regenerated_size as usize]);
Ok(section.regenerated_size)
}
LiteralsSectionType::RLE => {
target.resize(target.len() + section.regenerated_size as usize, source[0]);
Ok(1)
}
LiteralsSectionType::Compressed | LiteralsSectionType::Treeless => {
let bytes_read = decompress_literals(section, scratch, source, target)?;
Ok(bytes_read)
}
}
}
fn decompress_literals(
section: &LiteralsSection,
scratch: &mut HuffmanScratch,
source: &[u8],
target: &mut Vec<u8>,
) -> Result<u32, String> {
if section.compressed_size.is_none() {
return Err("compressed size was none even though it must be set to something for compressed literals".to_owned());
}
if section.num_streams.is_none() {
return Err("num_streams was none even though it must be set to something (1 or 4) for compressed literals".to_owned());
}
target.reserve(section.regenerated_size as usize);
let source = &source[0..section.compressed_size.unwrap() as usize];
let mut bytes_read = 0;
match section.ls_type {
LiteralsSectionType::Compressed => {
bytes_read += scratch.table.build_decoder(source)?;
if crate::VERBOSE {
println!("Built huffman table using {} bytes", bytes_read);
}
}
LiteralsSectionType::Treeless => {
if scratch.table.max_num_bits == 0 {
return Err("Tried to reuse huffman table but it was never initialized".to_owned());
}
}
_ => { }
}
let source = &source[bytes_read as usize..];
if section.num_streams.unwrap() == 4 {
if source.len() < 6 {
return Err("Need 6 byte to decode jump header".to_owned());
}
let jump1 = source[0] as usize + ((source[1] as usize) << 8);
let jump2 = jump1 + source[2] as usize + ((source[3] as usize) << 8);
let jump3 = jump2 + source[4] as usize + ((source[5] as usize) << 8);
bytes_read += 6;
let source = &source[6..];
if source.len() < jump3 {
return Err(format!(
"Need at least {} byte to decode literals. Have: {}",
jump3,
source.len()
));
}
let stream1 = &source[..jump1];
let stream2 = &source[jump1..jump2];
let stream3 = &source[jump2..jump3];
let stream4 = &source[jump3..];
for stream in &[stream1, stream2, stream3, stream4] {
let mut decoder = HuffmanDecoder::new(&scratch.table);
let mut br = BitReaderReversed::new(stream);
let mut skipped_bits = 0;
loop {
let val = br.get_bits(1)?;
skipped_bits += 1;
if val == 1 || skipped_bits > 8 {
break;
}
}
if skipped_bits > 8 {
return Err(format!("Padding at the end of the sequence_section was more than a byte long: {}. Probably cause by data corruption", skipped_bits));
}
decoder.init_state(&mut br)?;
while br.bits_remaining() > -(scratch.table.max_num_bits as isize) {
target.push(decoder.decode_symbol());
decoder.next_state(&mut br)?;
}
if br.bits_remaining() != -(scratch.table.max_num_bits as isize) {
return Err(format!(
"Bitstream was read till: {}, should have been: {}",
br.bits_remaining(),
-(scratch.table.max_num_bits as isize)
));
}
}
bytes_read += source.len() as u32;
} else {
assert!(section.num_streams.unwrap() == 1);
let mut decoder = HuffmanDecoder::new(&scratch.table);
let mut br = BitReaderReversed::new(source);
let mut skipped_bits = 0;
loop {
let val = br.get_bits(1)?;
skipped_bits += 1;
if val == 1 || skipped_bits > 8 {
break;
}
}
if skipped_bits > 8 {
return Err(format!("Padding at the end of the sequence_section was more than a byte long: {}. Probably cause by data corruption", skipped_bits));
}
decoder.init_state(&mut br)?;
while br.bits_remaining() > -(scratch.table.max_num_bits as isize) {
target.push(decoder.decode_symbol());
decoder.next_state(&mut br)?;
}
bytes_read += source.len() as u32;
}
if target.len() != section.regenerated_size as usize {
return Err(format!(
"Did not decode enough literals: {}, Should have been: {}",
target.len(),
section.regenerated_size
));
}
Ok(bytes_read)
}