use std::io::Cursor;
use byteorder::{
LittleEndian,
ReadBytesExt,
};
use crate::{
chunks::chunk_types::ChunkType,
errors::AxmlError
};
#[derive(Debug)]
pub struct ChunkHeader {
pub chunk_type: ChunkType,
pub header_size: u16,
pub chunk_size: u32,
}
impl ChunkHeader {
pub fn from_buff(axml_buff: &mut Cursor<Vec<u8>>, expected_type: ChunkType) -> Result<Self, AxmlError> {
let minimum_size = 8;
let chunk_type = ChunkType::parse_block_type(axml_buff)?;
if chunk_type != expected_type {
panic!("Error: unexpected XML chunk type");
}
let header_size = axml_buff.read_u16::<LittleEndian>()?;
let chunk_size = axml_buff.read_u32::<LittleEndian>()?;
if header_size < minimum_size {
panic!("Error: parsed header size is smaller than the minimum");
}
if chunk_size < minimum_size.into() {
panic!("Error: parsed total size is smaller than the minimum");
}
if chunk_size < header_size.into() {
panic!("Error: parsed total size is smaller than parsed header size");
}
Ok(ChunkHeader {
chunk_type,
header_size,
chunk_size,
})
}
pub fn print(&self) {
println!("----- Chunk header -----");
println!("Header chunk_type: {:02X}", self.chunk_type);
println!("Header header_size: {:02X}", self.header_size);
println!("Chunk size: {:04X}", self.chunk_size);
println!("----- End chunk header -----");
}
}
#[cfg(test)]
mod tests {
use super::*;
use ChunkType;
#[test]
fn test_valid_case() {
let valid_data = vec![1, 0, 8, 0, 16, 0, 0, 0];
let mut cursor = Cursor::new(valid_data);
let expected_type = ChunkType::ResStringPoolType;
let result = ChunkHeader::from_buff(&mut cursor, expected_type);
assert!(result.is_ok());
let chunk_header = result.unwrap();
assert_eq!(chunk_header.chunk_type, expected_type);
assert_eq!(chunk_header.header_size, 8);
assert_eq!(chunk_header.chunk_size, 16);
}
#[test]
#[should_panic(expected = "Error: unexpected XML chunk type")]
fn test_unexpected_chunk_type() {
let invalid_data = vec![2, 0, 8, 0, 16, 0, 0, 0];
let mut cursor = Cursor::new(invalid_data);
let expected_type = ChunkType::ResStringPoolType;
let _ = ChunkHeader::from_buff(&mut cursor, expected_type);
}
#[test]
#[should_panic(expected = "Error: parsed header size is smaller than the minimum")]
fn test_invalid_header_size() {
let invalid_data = vec![1, 0, 4, 0, 16, 0, 0, 0];
let mut cursor = Cursor::new(invalid_data);
let expected_type = ChunkType::ResStringPoolType;
let _ = ChunkHeader::from_buff(&mut cursor, expected_type);
}
#[test]
#[should_panic(expected = "Error: parsed total size is smaller than the minimum")]
fn test_invalid_chunk_size() {
let invalid_data = vec![1, 0, 8, 0, 4, 0, 0, 0];
let mut cursor = Cursor::new(invalid_data);
let expected_type = ChunkType::ResStringPoolType;
let _ = ChunkHeader::from_buff(&mut cursor, expected_type);
}
#[test]
#[should_panic(expected = "Error: parsed total size is smaller than parsed header size")]
fn test_invalid_chunk_size_smaller_than_header() {
let invalid_data = vec![1, 0, 16, 0, 8, 0, 0, 0];
let mut cursor = Cursor::new(invalid_data);
let expected_type = ChunkType::ResStringPoolType;
let _ = ChunkHeader::from_buff(&mut cursor, expected_type);
}
}