commonlibsse_ng\rel\id\id_database/
header.rs1use crate::rel::version::Version;
12
13#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct Header {
16 pub version: Version,
18
19 pointer_size: u32,
21
22 address_count: u32,
24}
25
26impl Header {
27 pub fn from_reader<R>(reader: &mut R, expected_fmt_ver: u8) -> Result<Self, HeaderError>
38 where
39 R: std::io::Read + std::io::Seek,
40 {
41 use snafu::ResultExt as _;
42
43 {
45 let mut format = [0_u8; 4];
46 reader
47 .read_exact(&mut format)
48 .context(ReadFormatVersionSnafu)?;
49 let format = i32::from_le_bytes(format);
50
51 if format != expected_fmt_ver as i32 {
52 return Err(HeaderError::UnexpectedFormat {
53 expected: expected_fmt_ver,
54 actual_format: format,
55 });
56 }
57 }
58
59 let version = {
61 let mut version = [0_u8; 16];
62 reader.read_exact(&mut version).context(ReadVersionSnafu)?;
63 let version = u32_to_u16_array(u8_to_le_u32_array(version));
64 Version::new(version[0], version[1], version[2], version[3])
65 };
66
67 {
70 let mut name_len = [0_u8; 4];
71 reader
72 .read_exact(&mut name_len)
73 .context(ReadNameLengthSnafu)?;
74 let name_len = i32::from_le_bytes(name_len) as i64;
75 reader
76 .seek(std::io::SeekFrom::Current(name_len))
77 .context(SeekAfterNameLengthSnafu)?;
78 }
79
80 let pointer_size = {
83 let mut pointer_size = [0_u8; 4];
84 reader
85 .read_exact(&mut pointer_size)
86 .context(ReadPointerSizeSnafu)?;
87 u32::from_le_bytes(pointer_size)
88 };
89
90 let address_count = {
92 let mut address_count = [0_u8; 4];
93 reader
94 .read_exact(&mut address_count)
95 .context(ReadAddressCountSnafu)?;
96 u32::from_le_bytes(address_count)
97 };
98
99 Ok(Self {
100 version,
101 address_count,
102 pointer_size,
103 })
104 }
105
106 pub const fn address_count(&self) -> usize {
108 self.address_count as usize
109 }
110
111 pub const fn pointer_size(&self) -> u64 {
113 self.pointer_size as u64
114 }
115}
116
117#[derive(Debug, snafu::Snafu)] pub enum HeaderError {
120 #[snafu(display("Failed to read format version: {}", source))]
122 ReadFormatVersion { source: std::io::Error },
123
124 UnexpectedFormat { expected: u8, actual_format: i32 },
126
127 #[snafu(display("Failed to read version: {}", source))]
128 ReadVersion { source: std::io::Error },
129
130 #[snafu(display("Failed to read name length: {}", source))]
132 ReadNameLength { source: std::io::Error },
133
134 #[snafu(display("Failed to seek after name length: {}", source))]
136 SeekAfterNameLength { source: std::io::Error },
137
138 #[snafu(display("Failed to read pointer size: {}", source))]
140 ReadPointerSize { source: std::io::Error },
141
142 #[snafu(display("Failed to read address count: {}", source))]
144 ReadAddressCount { source: std::io::Error },
145}
146
147impl Clone for HeaderError {
149 fn clone(&self) -> Self {
150 match self {
151 Self::ReadFormatVersion { source } => Self::ReadFormatVersion {
152 source: std::io::Error::new(source.kind(), source.to_string()),
153 },
154 Self::UnexpectedFormat {
155 expected,
156 actual_format,
157 } => Self::UnexpectedFormat {
158 expected: *expected,
159 actual_format: *actual_format,
160 },
161 Self::ReadVersion { source } => Self::ReadVersion {
162 source: std::io::Error::new(source.kind(), source.to_string()),
163 },
164 Self::ReadNameLength { source } => Self::ReadNameLength {
165 source: std::io::Error::new(source.kind(), source.to_string()),
166 },
167 Self::SeekAfterNameLength { source } => Self::SeekAfterNameLength {
168 source: std::io::Error::new(source.kind(), source.to_string()),
169 },
170 Self::ReadPointerSize { source } => Self::ReadPointerSize {
171 source: std::io::Error::new(source.kind(), source.to_string()),
172 },
173 Self::ReadAddressCount { source } => Self::ReadAddressCount {
174 source: std::io::Error::new(source.kind(), source.to_string()),
175 },
176 }
177 }
178}
179
180const fn u8_to_le_u32_array(input: [u8; 16]) -> [u32; 4] {
182 [
183 u32::from_le_bytes([input[0], input[1], input[2], input[3]]),
184 u32::from_le_bytes([input[4], input[5], input[6], input[7]]),
185 u32::from_le_bytes([input[8], input[9], input[10], input[11]]),
186 u32::from_le_bytes([input[12], input[13], input[14], input[15]]),
187 ]
188}
189
190const fn u32_to_u16_array(input: [u32; 4]) -> [u16; 4] {
191 [
192 input[0] as u16,
193 input[1] as u16,
194 input[2] as u16,
195 input[3] as u16,
196 ]
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202 use std::io::Cursor;
203 #[test]
207 fn test_parse_header() {
208 #[rustfmt::skip]
209 let binary_data: &[u8] = &[
210 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x53, 0x6B, 0x79, 0x72, 0x69, 0x6D, 0x53, 0x45, 0x2E, 0x65, 0x78, 0x65, 0x08, 0x00, 0x00, 0x00, 0xB2, 0xE1, 0x0B, 0x00, ];
229
230 let mut cursor = Cursor::new(binary_data);
231 let header = Header::from_reader(&mut cursor, 1).expect("Failed to read header");
232 assert_eq!(header.version, Version::new(1, 5, 97, 0));
233 assert_eq!(header.pointer_size(), 8);
234 assert_eq!(header.address_count(), 778674);
235 }
236}