1use std::io::{self, BufReader, Cursor, Read, Seek, SeekFrom, Write};
8
9use adler::Adler32;
10use byteorder::{LittleEndian, WriteBytesExt};
11use flate2::{Compression, bufread::ZlibEncoder};
12
13use crate::{PSB_MDF_SIGNATURE, PSB_SIGNATURE, PsbError, PsbRefs, VirtualPsb, header::MdfHeader, offsets::{PsbOffsets, PsbResourcesOffset, PsbStringOffset}, types::{PsbValue, binary_tree::PsbBinaryTree, collection::PsbUintArray}};
14
15pub struct PsbWriter<T> {
16
17 pub psb: VirtualPsb,
18
19 stream: T
20
21}
22
23impl<T: Write> PsbWriter<T> {
24
25 pub fn write_names(names: &Vec<String>, stream: &mut T) -> Result<u64, PsbError> {
26 let mut buffer_list = Vec::<Vec<u8>>::new();
27
28 for name in names.iter() {
29 buffer_list.push(name.as_bytes().into());
30 }
31
32 PsbBinaryTree::from(buffer_list).write_bytes(stream)
33 }
34
35}
36
37impl<T: Write + Seek> PsbWriter<T> {
38
39 pub fn new(
40 psb: VirtualPsb,
41 stream: T
42 ) -> Self {
43 Self {
44 psb,
45 stream
46 }
47 }
48
49 pub fn finish(mut self) -> Result<u64, PsbError> {
51 let file_start = self.stream.seek(SeekFrom::Current(0)).unwrap();
52
53 let (header, resources, extra, root) = self.psb.unwrap();
54
55 self.stream.write_u32::<LittleEndian>(PSB_SIGNATURE)?;
56 header.write_bytes(&mut self.stream)?;
57
58 let offsets_end_pos = self.stream.seek(SeekFrom::Current(0)).unwrap() - file_start;
59 self.stream.write_u32::<LittleEndian>(0)?;
60
61 let offset_start_pos = self.stream.seek(SeekFrom::Current(0)).unwrap() - file_start;
63 let mut offsets = PsbOffsets::default();
64
65 offsets.write_bytes(header.version, &mut self.stream)?;
67
68 let offsets_end = self.stream.seek(SeekFrom::Current(0)).unwrap() - file_start;
69
70 let refs = {
71 let mut names = Vec::new();
72 let mut strings = Vec::new();
73
74 root.collect_names(&mut names);
75 root.collect_strings(&mut strings);
76
77 names.sort();
78 strings.sort();
79
80 PsbRefs::new(names, strings)
81 };
82
83 {
85 offsets.name_offset = (self.stream.seek(SeekFrom::Current(0)).unwrap() - file_start) as u32;
86 Self::write_names(refs.names(), &mut self.stream)?;
87 }
88
89 {
91 offsets.entry_point = (self.stream.seek(SeekFrom::Current(0)).unwrap() - file_start) as u32;
92 PsbValue::Object(root).write_bytes_refs(&mut self.stream, &refs)?;
93 }
94
95 {
97 let (_, strings) = Self::write_strings(refs.strings(), &mut self.stream)?;
98
99 offsets.strings = strings;
100 }
101
102 {
104 let (_, res_offsets) = Self::write_resources(&resources, &mut self.stream)?;
105 offsets.resources = res_offsets;
106 }
107
108 if header.version > 3 {
110 let (_, extra_offsets) = Self::write_resources(&extra, &mut self.stream)?;
111 offsets.extra = Some(extra_offsets);
112 }
113
114 let file_end = self.stream.seek(SeekFrom::Current(0)).unwrap();
116
117 self.stream.seek(SeekFrom::Start(offsets_end_pos))?;
118 self.stream.write_u32::<LittleEndian>(offsets_end as u32)?;
119
120 if header.version > 2 {
121 let mut adler = Adler32::new();
122
123 adler.write_slice(&(offset_start_pos as u32).to_le_bytes());
124 adler.write_slice(&offsets.name_offset.to_le_bytes());
125 adler.write_slice(&offsets.strings.offset_pos.to_le_bytes());
126 adler.write_slice(&offsets.strings.data_pos.to_le_bytes());
127 adler.write_slice(&offsets.resources.offset_pos.to_le_bytes());
128 adler.write_slice(&offsets.resources.lengths_pos.to_le_bytes());
129 adler.write_slice(&offsets.resources.data_pos.to_le_bytes());
130 adler.write_slice(&offsets.entry_point.to_le_bytes());
131
132 offsets.checksum = Some(adler.checksum());
133 }
134
135 self.stream.seek(SeekFrom::Start(offset_start_pos))?;
136 offsets.write_bytes(header.version, &mut self.stream)?;
137
138 self.stream.seek(SeekFrom::Start(file_end))?;
139
140 Ok(file_end - file_start)
141 }
142
143 pub fn write_resources(resources: &Vec<Vec<u8>>, stream: &mut T) -> Result<(u64, PsbResourcesOffset), PsbError> {
145 let mut offset_list = Vec::<u64>::new();
146 let mut length_list = Vec::<u64>::new();
147
148 let mut total_len = 0_u64;
149 for res in resources.iter() {
150 let len = res.len() as u64;
151
152 offset_list.push(total_len);
153 length_list.push(len);
154
155 total_len += len;
156 }
157
158 let offset_pos = (stream.seek(SeekFrom::Current(0)).unwrap()) as u32;
159 let offsets_written = PsbValue::IntArray(PsbUintArray::from(offset_list)).write_bytes(stream)?;
160
161 let lengths_pos = (stream.seek(SeekFrom::Current(0)).unwrap()) as u32;
162 let lengths_written = PsbValue::IntArray(PsbUintArray::from(length_list)).write_bytes(stream)?;
163
164 let data_pos = (stream.seek(SeekFrom::Current(0)).unwrap()) as u32;
165 let mut data_written = 0_u64;
166 for res in resources.iter() {
167 data_written += res.len() as u64;
168 stream.write_all(res)?;
169 }
170
171 Ok((offsets_written + lengths_written + data_written, PsbResourcesOffset {
172 offset_pos,
173 lengths_pos,
174 data_pos
175 }))
176 }
177
178 pub fn write_strings(strings: &Vec<String>, stream: &mut T) -> Result<(u64, PsbStringOffset), PsbError> {
180 let mut offset_list = Vec::<u64>::new();
181
182 let mut total_len = 0_u64;
183 for string in strings.iter() {
184 let len = string.as_bytes().len() as u64;
185
186 offset_list.push(total_len);
187
188 total_len += len + 1;
189 }
190
191 let offset_pos = stream.seek(SeekFrom::Current(0)).unwrap() as u32;
192 let offset_written = PsbValue::IntArray(PsbUintArray::from(offset_list)).write_bytes(stream)?;
193
194 let data_pos = stream.seek(SeekFrom::Current(0)).unwrap() as u32;
195 for string in strings.iter() {
196 stream.write_all(string.as_bytes())?;
197 stream.write_u8(0)?;
198 }
199
200 Ok((offset_written + total_len as u64, PsbStringOffset {
201 offset_pos,
202 data_pos
203 }))
204 }
205
206}
207
208pub struct MdfWriter<R, W> {
209
210 read: R,
211 stream: W
212
213}
214
215impl<R: Read, W: Write + Seek> MdfWriter<R, W> {
216
217 pub fn new(read: R, stream: W) -> Self {
218 Self {
219 read,
220 stream
221 }
222 }
223
224 pub fn finish(mut self) -> Result<u64, PsbError> {
227 let mut reader = BufReader::new(self.read);
228
229 let mut encoder = ZlibEncoder::new(&mut reader, Compression::best());
230
231 self.stream.write_u32::<LittleEndian>(PSB_MDF_SIGNATURE)?;
233
234 let header_pos = self.stream.seek(SeekFrom::Current(0)).unwrap();
235 MdfHeader { size: 0 }.write_bytes(&mut self.stream)?;
237
238 io::copy(&mut encoder, &mut self.stream)?;
239 let total_out = encoder.total_out();
240
241 let end_pos = self.stream.seek(SeekFrom::Current(0)).unwrap();
242
243 self.stream.seek(SeekFrom::Start(header_pos)).unwrap();
245 MdfHeader { size: total_out as u32 }.write_bytes(&mut self.stream)?;
246
247 self.stream.seek(SeekFrom::Start(end_pos)).unwrap();
248 Ok(total_out + 8)
249 }
250
251}
252
253pub struct PsbMdfWriter<T> {
254
255 buffer: Cursor<Vec<u8>>,
256 psb: VirtualPsb,
257 stream: T
258
259}
260
261impl<T: Write + Seek> PsbMdfWriter<T> {
262
263 pub fn new(psb: VirtualPsb, stream: T) -> Self {
264 Self {
265 buffer: Default::default(),
266 psb,
267 stream
268 }
269 }
270
271 pub fn finish(mut self) -> Result<u64, PsbError> {
274 let psb_writer = PsbWriter::new(self.psb, &mut self.buffer);
275 psb_writer.finish()?;
276
277 let mdf_writer = MdfWriter::new(self.buffer, self.stream);
278
279 mdf_writer.finish()
280 }
281}