use crate::bit_io::BitReader;
use crate::decoding::errors::LiteralsSectionParseError;
pub struct LiteralsSection {
pub regenerated_size: u32,
pub compressed_size: Option<u32>,
pub num_streams: Option<u8>,
pub ls_type: LiteralsSectionType,
}
pub enum LiteralsSectionType {
Raw,
#[allow(clippy::upper_case_acronyms)]
RLE,
Compressed,
Treeless,
}
impl Default for LiteralsSection {
fn default() -> Self {
Self::new()
}
}
impl LiteralsSection {
pub fn new() -> LiteralsSection {
LiteralsSection {
regenerated_size: 0,
compressed_size: None,
num_streams: None,
ls_type: LiteralsSectionType::Raw,
}
}
pub fn header_bytes_needed(&self, first_byte: u8) -> Result<u8, LiteralsSectionParseError> {
let ls_type: LiteralsSectionType = Self::section_type(first_byte)?;
let size_format = (first_byte >> 2) & 0x3;
match ls_type {
LiteralsSectionType::RLE | LiteralsSectionType::Raw => {
match size_format {
0 | 2 => {
Ok(1)
}
1 => {
Ok(2)
}
3 => {
Ok(3)
}
_ => panic!(
"This is a bug in the program. There should only be values between 0..3"
),
}
}
LiteralsSectionType::Compressed | LiteralsSectionType::Treeless => {
match size_format {
0 | 1 => {
Ok(3)
}
2 => {
Ok(4)
}
3 => {
Ok(5)
}
_ => panic!(
"This is a bug in the program. There should only be values between 0..3"
),
}
}
}
}
pub fn parse_from_header(&mut self, raw: &[u8]) -> Result<u8, LiteralsSectionParseError> {
let mut br: BitReader<'_> = BitReader::new(raw);
let block_type = br.get_bits(2)? as u8;
self.ls_type = Self::section_type(block_type)?;
let size_format = br.get_bits(2)? as u8;
let byte_needed = self.header_bytes_needed(raw[0])?;
if raw.len() < byte_needed as usize {
return Err(LiteralsSectionParseError::NotEnoughBytes {
have: raw.len(),
need: byte_needed,
});
}
match self.ls_type {
LiteralsSectionType::RLE | LiteralsSectionType::Raw => {
self.compressed_size = None;
match size_format {
0 | 2 => {
self.regenerated_size = u32::from(raw[0]) >> 3;
Ok(1)
}
1 => {
self.regenerated_size = (u32::from(raw[0]) >> 4) + (u32::from(raw[1]) << 4);
Ok(2)
}
3 => {
self.regenerated_size = (u32::from(raw[0]) >> 4)
+ (u32::from(raw[1]) << 4)
+ (u32::from(raw[2]) << 12);
Ok(3)
}
_ => panic!(
"This is a bug in the program. There should only be values between 0..3"
),
}
}
LiteralsSectionType::Compressed | LiteralsSectionType::Treeless => {
match size_format {
0 => {
self.num_streams = Some(1);
}
1..=3 => {
self.num_streams = Some(4);
}
_ => panic!(
"This is a bug in the program. There should only be values between 0..3"
),
};
match size_format {
0 | 1 => {
self.regenerated_size =
(u32::from(raw[0]) >> 4) + ((u32::from(raw[1]) & 0x3f) << 4);
self.compressed_size =
Some(u32::from(raw[1] >> 6) + (u32::from(raw[2]) << 2));
Ok(3)
}
2 => {
self.regenerated_size = (u32::from(raw[0]) >> 4)
+ (u32::from(raw[1]) << 4)
+ ((u32::from(raw[2]) & 0x3) << 12);
self.compressed_size =
Some((u32::from(raw[2]) >> 2) + (u32::from(raw[3]) << 6));
Ok(4)
}
3 => {
self.regenerated_size = (u32::from(raw[0]) >> 4)
+ (u32::from(raw[1]) << 4)
+ ((u32::from(raw[2]) & 0x3F) << 12);
self.compressed_size = Some(
(u32::from(raw[2]) >> 6)
+ (u32::from(raw[3]) << 2)
+ (u32::from(raw[4]) << 10),
);
Ok(5)
}
_ => panic!(
"This is a bug in the program. There should only be values between 0..3"
),
}
}
}
}
fn section_type(raw: u8) -> Result<LiteralsSectionType, LiteralsSectionParseError> {
let t = raw & 0x3;
match t {
0 => Ok(LiteralsSectionType::Raw),
1 => Ok(LiteralsSectionType::RLE),
2 => Ok(LiteralsSectionType::Compressed),
3 => Ok(LiteralsSectionType::Treeless),
other => Err(LiteralsSectionParseError::IllegalLiteralSectionType { got: other }),
}
}
}