use std::cmp::min;
use std::io::{Read, Seek, Write};
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
use crate::header::Header;
use crate::header::mode::Mode;
use crate::{RefPackError, RefPackResult, header};
pub enum Maxis {}
pub const FLAGS: u8 = 0x10;
impl Mode for Maxis {
fn length(_decompressed_size: usize) -> usize {
9
}
fn read<R: Read + Seek>(reader: &mut R) -> RefPackResult<Header> {
let compressed_length_prewrap = reader.read_u32::<LittleEndian>()?;
let compressed_length = if compressed_length_prewrap == 0 {
None
} else {
Some(compressed_length_prewrap)
};
let flags = reader.read_u8()?;
if flags != FLAGS {
return Err(RefPackError::BadFlags(flags));
}
let magic = reader.read_u8()?;
if magic != header::MAGIC {
return Err(RefPackError::BadMagic(magic));
}
let decompressed_length = reader.read_u24::<BigEndian>()?;
Ok(Header {
decompressed_length,
compressed_length,
})
}
fn write<W: Write + Seek>(header: Header, writer: &mut W) -> RefPackResult<()> {
writer.write_u32::<LittleEndian>(header.compressed_length.unwrap_or(0))?;
writer.write_u8(FLAGS)?;
writer.write_u8(header::MAGIC)?;
writer.write_u24::<BigEndian>(min(
header.decompressed_length,
0b1111_1111_1111_1111_1111_1111,
))?;
Ok(())
}
}
#[cfg(test)]
mod test {
use std::io::Cursor;
use proptest::prop_assert_eq;
use test_strategy::proptest;
use super::*;
use crate::header::Header;
#[proptest]
fn symmetrical_read_write(
#[any(decompressed_limit = 16_777_214, compressed_limit = Some(u32::MAX))] header: Header,
) {
let mut write_buf = vec![];
let mut write_cur = Cursor::new(&mut write_buf);
header.write::<Maxis>(&mut write_cur).unwrap();
let mut read_cur = Cursor::new(&mut write_buf);
let got = Header::read::<Maxis>(&mut read_cur).unwrap();
prop_assert_eq!(header, got);
}
#[test]
fn reads_correctly() {
let mut buf = vec![255, 0, 0, 0, FLAGS, header::MAGIC, 0, 0, 255];
let mut cur = Cursor::new(&mut buf);
let got = Header::read::<Maxis>(&mut cur).unwrap();
let want = Header {
decompressed_length: 255,
compressed_length: Some(255),
};
assert_eq!(got, want);
}
#[test]
fn writes_correctly() {
let header = Header {
decompressed_length: 255,
compressed_length: Some(255),
};
let mut buf = vec![];
let mut cur = Cursor::new(&mut buf);
header.write::<Maxis>(&mut cur).unwrap();
let want = vec![255, 0, 0, 0, FLAGS, header::MAGIC, 0, 0, 255];
assert_eq!(buf, want);
}
#[test]
fn rejects_bad_flags() {
let mut buf = vec![0, 0, 0, 0, 0x50, 0, 0, 0, 0];
let mut cur = Cursor::new(&mut buf);
let err = Header::read::<Maxis>(&mut cur).unwrap_err();
assert_eq!(err.to_string(), RefPackError::BadFlags(0x50).to_string());
}
#[test]
fn rejects_bad_magic() {
let mut buf = vec![0, 0, 0, 0, FLAGS, 0x50, 0, 0, 0];
let mut cur = Cursor::new(&mut buf);
let err = Header::read::<Maxis>(&mut cur).unwrap_err();
assert_eq!(err.to_string(), RefPackError::BadMagic(0x50).to_string());
}
}