refpack/header/mode/
maxis.rs1use std::cmp::min;
9use std::io::{Read, Seek, Write};
10
11use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
12
13use crate::header::Header;
14use crate::header::mode::Mode;
15use crate::{RefPackError, RefPackResult, header};
16
17pub enum Maxis {}
25
26pub const FLAGS: u8 = 0x10;
27
28impl Mode for Maxis {
29 fn length(_decompressed_size: usize) -> usize {
30 9
31 }
32
33 fn read<R: Read + Seek>(reader: &mut R) -> RefPackResult<Header> {
34 let compressed_length_prewrap = reader.read_u32::<LittleEndian>()?;
35 let compressed_length = if compressed_length_prewrap == 0 {
36 None
37 } else {
38 Some(compressed_length_prewrap)
39 };
40 let flags = reader.read_u8()?;
41 if flags != FLAGS {
42 return Err(RefPackError::BadFlags(flags));
43 }
44 let magic = reader.read_u8()?;
45 if magic != header::MAGIC {
46 return Err(RefPackError::BadMagic(magic));
47 }
48 let decompressed_length = reader.read_u24::<BigEndian>()?;
50 Ok(Header {
51 decompressed_length,
52 compressed_length,
53 })
54 }
55
56 fn write<W: Write + Seek>(header: Header, writer: &mut W) -> RefPackResult<()> {
57 writer.write_u32::<LittleEndian>(header.compressed_length.unwrap_or(0))?;
58 writer.write_u8(FLAGS)?;
59 writer.write_u8(header::MAGIC)?;
60 writer.write_u24::<BigEndian>(min(
63 header.decompressed_length,
64 0b1111_1111_1111_1111_1111_1111,
65 ))?;
66 Ok(())
67 }
68}
69
70#[cfg(test)]
71mod test {
72 use std::io::Cursor;
73
74 use proptest::prop_assert_eq;
75 use test_strategy::proptest;
76
77 use super::*;
78 use crate::header::Header;
79
80 #[proptest]
81 fn symmetrical_read_write(
82 #[any(decompressed_limit = 16_777_214, compressed_limit = Some(u32::MAX))] header: Header,
83 ) {
84 let mut write_buf = vec![];
85 let mut write_cur = Cursor::new(&mut write_buf);
86 header.write::<Maxis>(&mut write_cur).unwrap();
87 let mut read_cur = Cursor::new(&mut write_buf);
88 let got = Header::read::<Maxis>(&mut read_cur).unwrap();
89
90 prop_assert_eq!(header, got);
91 }
92
93 #[test]
94 fn reads_correctly() {
95 let mut buf = vec![255, 0, 0, 0, FLAGS, header::MAGIC, 0, 0, 255];
96 let mut cur = Cursor::new(&mut buf);
97 let got = Header::read::<Maxis>(&mut cur).unwrap();
98 let want = Header {
99 decompressed_length: 255,
100 compressed_length: Some(255),
101 };
102 assert_eq!(got, want);
103 }
104
105 #[test]
106 fn writes_correctly() {
107 let header = Header {
108 decompressed_length: 255,
109 compressed_length: Some(255),
110 };
111 let mut buf = vec![];
112 let mut cur = Cursor::new(&mut buf);
113 header.write::<Maxis>(&mut cur).unwrap();
114 let want = vec![255, 0, 0, 0, FLAGS, header::MAGIC, 0, 0, 255];
115 assert_eq!(buf, want);
116 }
117
118 #[test]
119 fn rejects_bad_flags() {
120 let mut buf = vec![0, 0, 0, 0, 0x50, 0, 0, 0, 0];
121 let mut cur = Cursor::new(&mut buf);
122 let err = Header::read::<Maxis>(&mut cur).unwrap_err();
123 assert_eq!(err.to_string(), RefPackError::BadFlags(0x50).to_string());
124 }
125
126 #[test]
127 fn rejects_bad_magic() {
128 let mut buf = vec![0, 0, 0, 0, FLAGS, 0x50, 0, 0, 0];
129 let mut cur = Cursor::new(&mut buf);
130 let err = Header::read::<Maxis>(&mut cur).unwrap_err();
131 assert_eq!(err.to_string(), RefPackError::BadMagic(0x50).to_string());
132 }
133}