commonlibsse_ng\rel\id\id_database/
unpack.rs1use crate::rel::id::id_database::byte_reader::{read_le_u16, read_le_u32, read_le_u64, read_u8};
2use crate::rel::id::Mapping;
3use std::io::Read;
4
5pub(crate) fn unpack_file<R>(
11 mem_map: &mut [Mapping],
12 reader: &mut R,
13 ptr_size: u64,
14) -> Result<(), UnpackError>
15where
16 R: Read,
17{
18 let mut offset: u64;
20 let mut prev_id: u64 = 0;
21 let mut prev_offset: u64 = 0;
22
23 let mappings = mem_map;
24 for mapping in &mut *mappings {
25 let type_byte = read_u8(reader)?;
26
27 let low = type_byte & 0xF;
28 let high = type_byte >> 4;
29
30 let id = parse_id(low, reader, prev_id)?;
31
32 let tmp = if (high & 8) != 0 {
33 prev_offset / ptr_size
34 } else {
35 prev_offset
36 };
37
38 offset = parse_offset(high, reader, tmp)?;
39
40 if (high & 8) != 0 {
41 offset *= ptr_size;
42 }
43
44 *mapping = Mapping { id, offset };
45 prev_id = id;
46 prev_offset = offset;
47 }
48
49 mappings.sort_by(|a, b| a.id.cmp(&b.id));
50
51 Ok(())
52}
53
54fn parse_id<R>(low: u8, reader: &mut R, prev_id: u64) -> Result<u64, UnpackError>
55where
56 R: Read,
57{
58 Ok(match low {
59 0 => read_le_u64(reader)?,
60 1 => prev_id + 1,
61 2 => prev_id + read_u8(reader)? as u64,
62 3 => prev_id - read_u8(reader)? as u64,
63 4 => prev_id + read_le_u16(reader)? as u64,
64 5 => prev_id - read_le_u16(reader)? as u64,
65 6 => read_le_u16(reader)? as u64,
66 7 => read_le_u32(reader)? as u64,
67 _ => return Err(UnpackError::InvalidId { id: low }),
68 })
69}
70
71fn parse_offset<R>(high: u8, reader: &mut R, prev_offset: u64) -> Result<u64, UnpackError>
72where
73 R: Read,
74{
75 Ok(match high & 7 {
76 0 => read_le_u64(reader)?,
77 1 => prev_offset + 1,
78 2 => prev_offset + read_u8(reader)? as u64,
79 3 => prev_offset - read_u8(reader)? as u64,
80 4 => prev_offset + read_le_u16(reader)? as u64,
81 5 => prev_offset - read_le_u16(reader)? as u64,
82 6 => read_le_u16(reader)? as u64,
83 7 => read_le_u32(reader)? as u64,
84 _ => {
85 return Err(UnpackError::InvalidOffset {
86 offset: prev_offset,
87 })
88 }
89 })
90}
91
92#[derive(Debug, snafu::Snafu)]
93pub enum UnpackError {
94 #[snafu(display("Invalid ID encountered: {}", id))]
96 InvalidId { id: u8 },
97
98 #[snafu(display("Invalid offset encountered: {}", offset))]
100 InvalidOffset { offset: u64 },
101
102 #[snafu(transparent)]
104 Io { source: std::io::Error },
105}
106
107impl Clone for UnpackError {
109 fn clone(&self) -> Self {
110 match self {
111 Self::InvalidId { id } => Self::InvalidId { id: *id },
112 Self::InvalidOffset { offset } => Self::InvalidOffset { offset: *offset },
113 Self::Io { source: err } => Self::Io {
114 source: std::io::Error::new(err.kind(), err.to_string()),
115 },
116 }
117 }
118}