emote_psb/
offsets.rs

1/*
2 * Created on Tue Jan 12 2021
3 *
4 * Copyright (c) storycraft. Licensed under the MIT Licence.
5 */
6
7use 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}