me3_coalesced_parser/
de.rs1use crate::{
2 crc32::hash_crc32,
3 error::{DecodeError, DecodeResult},
4 huffman::Huffman,
5 invert_huffman_tree,
6 shared::{CoalFile, Coalesced, Property, Section, Value, ValueType, ME3_MAGIC},
7 Tlk, TlkString, TLK_MAGIC,
8};
9use std::borrow::Cow;
10
11pub struct ReadBuffer<'de> {
13 buffer: &'de [u8],
15 cursor: usize,
17}
18
19impl<'de> ReadBuffer<'de> {
20 pub fn new(buffer: &'de [u8]) -> Self {
22 Self { buffer, cursor: 0 }
23 }
24
25 pub fn remaining(&self) -> usize {
28 self.buffer.len() - self.cursor
29 }
30
31 pub(crate) fn read_bytes(&mut self, length: usize) -> DecodeResult<&'de [u8]> {
33 if self.cursor + length > self.buffer.len() {
34 return Err(DecodeError::UnexpectedEof {
35 cursor: self.cursor,
36 wanted: length,
37 remaining: self.remaining(),
38 });
39 }
40
41 let slice: &[u8] = &self.buffer[self.cursor..self.cursor + length];
42 self.cursor += length;
43 Ok(slice)
44 }
45
46 pub(crate) fn seek(&mut self, cursor: usize) -> DecodeResult<()> {
47 if cursor >= self.buffer.len() {
48 return Err(DecodeError::UnexpectedEof {
49 cursor: self.cursor,
50 wanted: cursor,
51 remaining: self.remaining(),
52 });
53 }
54
55 self.cursor = cursor;
56
57 Ok(())
58 }
59
60 pub(crate) fn read_fixed<const S: usize>(&mut self) -> DecodeResult<[u8; S]> {
62 let slice = self.read_bytes(S)?;
63
64 let mut bytes: [u8; S] = [0u8; S];
66 bytes.copy_from_slice(slice);
67
68 Ok(bytes)
69 }
70
71 pub fn take_slice(&mut self, length: usize) -> DecodeResult<ReadBuffer<'de>> {
72 Ok(Self::new(self.read_bytes(length)?))
73 }
74
75 pub fn read_u32(&mut self) -> DecodeResult<u32> {
76 let bytes = self.read_fixed::<4>()?;
77 Ok(u32::from_le_bytes(bytes))
78 }
79
80 pub fn read_u16(&mut self) -> DecodeResult<u16> {
81 let bytes = self.read_fixed::<2>()?;
82 Ok(u16::from_le_bytes(bytes))
83 }
84
85 pub fn read_i32(&mut self) -> DecodeResult<i32> {
86 let bytes = self.read_fixed::<4>()?;
87 Ok(i32::from_le_bytes(bytes))
88 }
89}
90
91pub fn deserialize_coalesced(input: &[u8]) -> DecodeResult<Coalesced> {
92 let mut r = ReadBuffer::new(input);
93 let magic = r.read_u32()?;
95
96 if magic != ME3_MAGIC {
97 return Err(DecodeError::UnknownFileMagic);
98 }
99
100 let version = r.read_u32()?;
101 let _max_field_name_length = r.read_u32()?;
102 let max_value_length = r.read_u32()?;
103 let string_table_size = r.read_u32()?;
104 let huffman_size = r.read_u32()?;
105 let index_size = r.read_u32()?;
106 let data_size = r.read_u32()?;
107
108 let string_table: Vec<String> = {
110 let mut string_table_block = r.take_slice(string_table_size as usize)?;
111
112 let local_size = string_table_block.read_u32()?;
113
114 if local_size != string_table_size {
115 return Err(DecodeError::StringTableSizeMismatch);
116 }
117
118 let count = string_table_block.read_u32()?;
119
120 let mut offsets: Vec<(u32, u32)> = Vec::new();
121
122 for _ in 0..count {
123 let hash = string_table_block.read_u32()?;
124 let offset = string_table_block.read_u32()?;
125 offsets.push((offset, hash))
126 }
127
128 let mut values = Vec::new();
129 for (offset, hash) in offsets {
130 string_table_block.seek((8 + offset) as usize)?;
131
132 let length = string_table_block.read_u16()?;
133 let bytes = string_table_block.read_bytes(length as usize)?;
134 let text: Cow<str> = String::from_utf8_lossy(bytes);
135 let text: String = text.to_string();
136
137 if hash_crc32(text.as_bytes()) != hash {
138 return Err(DecodeError::StringTableHashMismatch);
139 }
140
141 values.push(text);
142 }
143
144 values
145 };
146
147 let huffman_tree: Vec<(i32, i32)> = {
149 let mut huffman_tree_block = r.take_slice(huffman_size as usize)?;
150
151 let count = huffman_tree_block.read_u16()?;
153
154 let mut values = Vec::with_capacity(count as usize);
155
156 for _ in 0..count {
157 let left = huffman_tree_block.read_i32()?;
158 let right = huffman_tree_block.read_i32()?;
159 values.push((left, right))
160 }
161
162 values
163 };
164
165 let mut index_block: ReadBuffer = r.take_slice(index_size as usize)?;
167
168 let data_block: &[u8] = {
169 let _total_bits = r.read_u32()?;
171
172 let block = r.take_slice(data_size as usize)?;
174 block.buffer
175 };
176
177 let files_count = index_block.read_u16()?;
179
180 let mut files: Vec<CoalFile> = Vec::with_capacity(files_count as usize);
181
182 let mut file_offsets: Vec<(String, usize)> = Vec::with_capacity(files_count as usize);
184
185 for _ in 0..files_count {
186 let file_name_index = index_block.read_u16()?;
188 let file_name = string_table
189 .get(file_name_index as usize)
190 .ok_or(DecodeError::InvalidNameOffset)?;
191
192 let file_offset = index_block.read_u32()?;
194
195 file_offsets.push((file_name.to_string(), file_offset as usize));
196 }
197
198 for (file_name, file_offset) in file_offsets {
199 index_block.seek(file_offset)?;
201
202 let sections_count = index_block.read_u16()?;
204
205 let mut sections: Vec<Section> = Vec::with_capacity(sections_count as usize);
206 let mut section_offsets: Vec<(String, usize)> = Vec::with_capacity(sections_count as usize);
207
208 for _ in 0..sections_count {
209 let section_name_index = index_block.read_u16()?;
211 let section_name = string_table
212 .get(section_name_index as usize)
213 .ok_or(DecodeError::InvalidNameOffset)?;
214
215 let section_offset = index_block.read_u32()?;
217
218 section_offsets.push((section_name.to_string(), section_offset as usize));
219 }
220
221 for (section_name, section_offset) in section_offsets {
222 index_block.seek(file_offset + section_offset)?;
224
225 let values_count = index_block.read_u16()? as usize;
226 let mut properties: Vec<Property> = Vec::with_capacity(values_count);
227 let mut value_offsets: Vec<(String, usize)> = Vec::with_capacity(values_count);
228
229 for _ in 0..values_count {
230 let value_name_index = index_block.read_u16()?;
232 let value_name = string_table
233 .get(value_name_index as usize)
234 .ok_or(DecodeError::InvalidNameOffset)?;
235
236 let value_offset = index_block.read_u32()?;
238 value_offsets.push((value_name.to_string(), value_offset as usize));
239 }
240
241 for (property_name, value_offset) in value_offsets {
242 index_block.seek(file_offset + section_offset + value_offset)?;
244
245 let item_count = index_block.read_u16()? as usize;
246 let mut items: Vec<Value> = Vec::with_capacity(values_count);
247
248 for _ in 0..item_count {
249 let item_offset = index_block.read_u32()?;
251
252 let ty = (item_offset & 0xE0000000) >> 29;
254 let item_offset = item_offset & 0x1fffffff;
255
256 let ty =
257 ValueType::try_from(ty as u8).map_err(|_| DecodeError::UnknownValueType)?;
258
259 let text = match ty {
260 ValueType::RemoveProperty => None,
261 _ => {
262 let text = Huffman::decode(
263 data_block,
264 &huffman_tree,
265 item_offset as usize,
266 max_value_length as usize,
267 )?;
268
269 Some(text)
270 }
271 };
272
273 items.push(Value { ty, text });
274 }
275
276 properties.push(Property {
277 name: property_name,
278 values: items,
279 });
280 }
281
282 sections.push(Section {
283 name: section_name,
284 properties,
285 });
286 }
287
288 files.push(CoalFile {
289 path: file_name,
290 sections,
291 })
292 }
293
294 let coalesced = Coalesced { version, files };
295
296 Ok(coalesced)
297}
298
299pub fn deserialize_tlk(input: &[u8]) -> DecodeResult<Tlk> {
300 let mut r = ReadBuffer::new(input);
301
302 let magic = r.read_u32()?;
303
304 if magic != TLK_MAGIC {
305 return Err(DecodeError::UnknownFileMagic);
306 }
307
308 let version = r.read_u32()?;
310 let min_version = r.read_u32()?;
311 let male_entry_count = r.read_u32()?;
312 let female_entry_count = r.read_u32()?;
313 let tree_node_count = r.read_u32()?;
314 let data_length = r.read_u32()?;
315
316 let mut male_refs = Vec::<(u32, u32)>::with_capacity(male_entry_count as usize);
317 let mut female_refs = Vec::<(u32, u32)>::with_capacity(female_entry_count as usize);
318
319 for _ in 0..male_entry_count {
321 let left = r.read_u32()?;
322 let right = r.read_u32()?;
323
324 male_refs.push((left, right));
325 }
326
327 for _ in 0..female_entry_count {
329 let left = r.read_u32()?;
330 let right = r.read_u32()?;
331
332 female_refs.push((left, right));
333 }
334
335 let mut huffman_tree: Vec<(i32, i32)> = Vec::with_capacity(tree_node_count as usize);
336
337 for _ in 0..tree_node_count {
339 let left = r.read_i32()?;
340 let right = r.read_i32()?;
341 huffman_tree.push((left, right))
342 }
343
344 invert_huffman_tree(&mut huffman_tree);
345
346 let data_block: &[u8] = r.take_slice(data_length as usize)?.buffer;
348
349 let mut male_values: Vec<TlkString> = Vec::with_capacity(male_refs.len());
350 let mut female_values: Vec<TlkString> = Vec::with_capacity(female_refs.len());
351
352 for (key, offset) in male_refs {
354 let text = Huffman::decode(data_block, &huffman_tree, offset as usize, usize::MAX)?;
355 male_values.push(TlkString {
356 id: key,
357 value: text,
358 })
359 }
360
361 for (key, offset) in female_refs {
363 let text = Huffman::decode(data_block, &huffman_tree, offset as usize, usize::MAX)?;
364 female_values.push(TlkString {
365 id: key,
366 value: text,
367 })
368 }
369
370 Ok(Tlk {
371 version,
372 min_version,
373 male_values,
374 female_values,
375 })
376}