1use std::io::{Read, Write};
8
9use crate::{PsbError, PsbErrorKind};
10
11use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};
12
13#[derive(Debug, Clone, Copy)]
14pub struct PsbOffsets {
15
16 pub name_offset: u32,
17 pub strings: PsbStringOffset,
18
19 pub resources: PsbResourcesOffset,
20
21 pub entry_point: u32,
22
23 pub checksum: Option<u32>,
24 pub extra: Option<PsbResourcesOffset>
25
26}
27
28impl PsbOffsets {
29
30 pub fn from_bytes(version: u16, stream: &mut impl Read) -> Result<(u64, Self), PsbError> {
31 let name_offset = stream.read_u32::<LittleEndian>()?;
32 let (strings_read, strings) = PsbStringOffset::from_bytes(stream)?;
33 let (resources_read, resources) = PsbResourcesOffset::from_bytes(stream)?;
34
35 let entry_point = stream.read_u32::<LittleEndian>()?;
36
37 let (checksum_read, checksum) = if version > 2 {
38 (4, Some(stream.read_u32::<LittleEndian>()?))
39 } else {
40 (0, None)
41 };
42
43 let (extra_read, extra) = if version > 3 {
44 let (read, extra) = PsbResourcesOffset::from_bytes(stream)?;
45 (read, Some(extra))
46 } else {
47 (0, None)
48 };
49
50 Ok((8 + strings_read + resources_read + checksum_read + extra_read, Self {
51 name_offset,
52 strings,
53 resources,
54 entry_point,
55 checksum,
56 extra
57 }))
58 }
59
60 pub fn write_bytes(&self, version: u16, stream: &mut impl Write) -> Result<u64, PsbError> {
61 stream.write_u32::<LittleEndian>(self.name_offset)?;
62 let strings_written = self.strings.write_bytes(stream)?;
63 let resources_written = self.resources.write_bytes(stream)?;
64 stream.write_u32::<LittleEndian>(self.entry_point)?;
65
66 let checksum_written: u64;
67 let extra_written: u64;
68 if version > 2 {
69 stream.write_u32::<LittleEndian>(self.checksum.unwrap_or(0))?;
70 checksum_written = 4;
71
72 if version > 3 {
73 if self.extra.is_none() {
74 return Err(PsbError::new(PsbErrorKind::InvalidOffsetTable, None));
75 }
76
77 extra_written = self.extra.unwrap().write_bytes(stream)?;
78 } else {
79 extra_written = 0;
80 }
81 } else {
82 checksum_written = 0;
83 extra_written = 0;
84 }
85
86 Ok(8 + strings_written + resources_written + checksum_written + extra_written)
87 }
88
89}
90
91impl Default for PsbOffsets {
92 fn default() -> Self {
93 Self {
94 name_offset: 0,
95 strings: PsbStringOffset::default(),
96 resources: PsbResourcesOffset::default(),
97 entry_point: 0,
98 checksum: Some(0),
99 extra: Some(PsbResourcesOffset::default())
100 }
101 }
102}
103
104#[derive(Debug, Clone, Copy)]
105pub struct PsbResourcesOffset {
106
107 pub offset_pos: u32,
108 pub lengths_pos: u32,
109 pub data_pos: u32
110
111}
112
113impl PsbResourcesOffset {
114
115 pub fn from_bytes(stream: &mut impl Read) -> Result<(u64, Self), PsbError> {
116 Ok((12, Self {
117 offset_pos: stream.read_u32::<LittleEndian>()?,
118 lengths_pos: stream.read_u32::<LittleEndian>()?,
119 data_pos: stream.read_u32::<LittleEndian>()?,
120 }))
121 }
122
123 pub fn write_bytes(&self, stream: &mut impl Write) -> Result<u64, PsbError> {
124 stream.write_u32::<LittleEndian>(self.offset_pos)?;
125 stream.write_u32::<LittleEndian>(self.lengths_pos)?;
126 stream.write_u32::<LittleEndian>(self.data_pos)?;
127
128 Ok(12)
129 }
130
131}
132
133impl Default for PsbResourcesOffset {
134 fn default() -> Self {
135 Self {
136 offset_pos: 0,
137 lengths_pos: 0,
138 data_pos: 0,
139 }
140 }
141}
142
143#[derive(Debug, Clone, Copy)]
144pub struct PsbStringOffset {
145
146 pub offset_pos: u32,
147 pub data_pos: u32
148
149}
150
151impl PsbStringOffset {
152
153 pub fn from_bytes(stream: &mut impl Read) -> Result<(u64, Self), PsbError> {
154 Ok((8, Self {
155 offset_pos: stream.read_u32::<LittleEndian>()?,
156 data_pos: stream.read_u32::<LittleEndian>()?,
157 }))
158 }
159
160 pub fn write_bytes(&self, stream: &mut impl Write) -> Result<u64, PsbError> {
161 stream.write_u32::<LittleEndian>(self.offset_pos)?;
162 stream.write_u32::<LittleEndian>(self.data_pos)?;
163
164 Ok(8)
165 }
166
167}
168
169impl Default for PsbStringOffset {
170 fn default() -> Self {
171 Self {
172 offset_pos: 0,
173 data_pos: 0
174 }
175 }
176}