unity_asset_binary/typetree/
parser.rs1use super::common_strings;
7use super::types::{TypeTree, TypeTreeNode};
8use crate::error::{BinaryError, Result};
9use crate::reader::BinaryReader;
10
11pub struct TypeTreeParser;
16
17impl TypeTreeParser {
18 pub fn from_reader(reader: &mut BinaryReader, version: u32) -> Result<TypeTree> {
20 let mut tree = TypeTree::new();
21 tree.version = version;
22
23 let node_count = reader.read_u32()? as usize;
25
26 let string_buffer_size = reader.read_u32()? as usize;
28
29 for _ in 0..node_count {
31 let node = Self::read_node(reader, version)?;
32 tree.nodes.push(node);
33 }
34
35 tree.string_buffer = reader.read_bytes(string_buffer_size)?;
37
38 Self::resolve_strings(&mut tree)?;
40
41 Self::build_hierarchy(&mut tree)?;
43
44 Ok(tree)
45 }
46
47 pub fn from_reader_blob(reader: &mut BinaryReader, version: u32) -> Result<TypeTree> {
49 let mut tree = TypeTree::new();
50 tree.version = version;
51
52 let node_count = reader.read_i32()? as usize;
54
55 let string_buffer_size = reader.read_i32()? as usize;
57
58 for _ in 0..node_count {
60 let mut node = TypeTreeNode::new();
61
62 node.version = reader.read_u16()? as i32;
64 node.level = reader.read_u8()? as i32;
65 node.type_flags = reader.read_u8()? as i32;
66 node.type_str_offset = reader.read_u32()?;
67 node.name_str_offset = reader.read_u32()?;
68 node.byte_size = reader.read_i32()?;
69 node.index = reader.read_i32()?;
70 node.meta_flags = reader.read_i32()?;
71
72 if version >= 19 {
73 node.ref_type_hash = reader.read_u64()?;
74 }
75
76 tree.nodes.push(node);
77 }
78
79 tree.string_buffer = reader.read_bytes(string_buffer_size)?;
81
82 Self::resolve_strings(&mut tree)?;
84
85 Self::build_hierarchy(&mut tree)?;
87
88 Ok(tree)
89 }
90
91 fn read_node(reader: &mut BinaryReader, version: u32) -> Result<TypeTreeNode> {
93 let mut node = TypeTreeNode::new();
94
95 if version >= 10 {
96 node.version = reader.read_i16()? as i32;
97 node.level = reader.read_u8()? as i32;
98 node.type_flags = reader.read_u8()? as i32;
99 node.type_str_offset = reader.read_u32()?;
100 node.name_str_offset = reader.read_u32()?;
101 node.byte_size = reader.read_i32()?;
102 node.index = reader.read_i32()?;
103 node.meta_flags = reader.read_i32()?;
104
105 if version >= 12 {
106 node.ref_type_hash = reader.read_u64()?;
107 }
108 } else {
109 node.type_str_offset = reader.read_u32()?;
111 node.name_str_offset = reader.read_u32()?;
112 node.byte_size = reader.read_i32()?;
113 node.index = reader.read_i32()?;
114 node.type_flags = reader.read_i32()?;
115 node.version = reader.read_i32()?;
116 node.meta_flags = reader.read_i32()?;
117 node.level = reader.read_i32()?;
118 }
119
120 Ok(node)
121 }
122
123 fn resolve_strings(tree: &mut TypeTree) -> Result<()> {
125 for node in &mut tree.nodes {
126 Self::resolve_node_strings(node, &tree.string_buffer)?;
127 }
128 Ok(())
129 }
130
131 fn resolve_node_strings(node: &mut TypeTreeNode, string_buffer: &[u8]) -> Result<()> {
133 node.type_name = Self::resolve_string(string_buffer, node.type_str_offset)?;
135
136 node.name = Self::resolve_string(string_buffer, node.name_str_offset)?;
138
139 for child in &mut node.children {
141 Self::resolve_node_strings(child, string_buffer)?;
142 }
143
144 Ok(())
145 }
146
147 fn resolve_string(buffer: &[u8], offset: u32) -> Result<String> {
150 const COMMON_STRING_FLAG: u32 = 0x8000_0000;
151
152 if (offset & COMMON_STRING_FLAG) != 0 {
153 let common_offset = offset & !COMMON_STRING_FLAG;
154 return Ok(common_strings::get_common_string(common_offset)
155 .unwrap_or_default()
156 .to_string());
157 }
158
159 Self::get_string_from_buffer(buffer, offset)
160 }
161
162 fn get_string_from_buffer(buffer: &[u8], offset: u32) -> Result<String> {
164 if offset as usize >= buffer.len() {
165 return Ok(String::new());
166 }
167
168 let start = offset as usize;
169 let end = buffer[start..]
170 .iter()
171 .position(|&b| b == 0)
172 .map(|pos| start + pos)
173 .unwrap_or(buffer.len());
174
175 String::from_utf8(buffer[start..end].to_vec())
176 .map_err(|e| BinaryError::generic(format!("Invalid UTF-8 string: {}", e)))
177 }
178
179 fn build_hierarchy(tree: &mut TypeTree) -> Result<()> {
181 if tree.nodes.is_empty() {
182 return Ok(());
183 }
184
185 let mut nodes = std::mem::take(&mut tree.nodes);
187
188 let mut stack: Vec<(i32, usize)> = Vec::new(); let mut root_nodes = Vec::new();
191
192 for (i, node) in nodes.iter().enumerate() {
193 let current_level = node.level;
194
195 while let Some(&(level, _)) = stack.last() {
197 if level < current_level {
198 break;
199 }
200 stack.pop();
201 }
202
203 if let Some(&(_, _parent_idx)) = stack.last() {
204 } else {
207 root_nodes.push(i);
209 }
210
211 stack.push((current_level, i));
212 }
213
214 let mut processed = vec![false; nodes.len()];
216 let mut result_nodes = Vec::new();
217
218 for &root_idx in &root_nodes {
219 if !processed[root_idx] {
220 let root_node = Self::build_node_hierarchy(&mut nodes, &mut processed, root_idx)?;
221 result_nodes.push(root_node);
222 }
223 }
224
225 tree.nodes = result_nodes;
226 Ok(())
227 }
228
229 fn build_node_hierarchy(
231 nodes: &mut [TypeTreeNode],
232 processed: &mut [bool],
233 node_idx: usize,
234 ) -> Result<TypeTreeNode> {
235 if processed[node_idx] {
236 return Err(BinaryError::generic("Node already processed"));
237 }
238
239 let mut node = nodes[node_idx].clone();
240 processed[node_idx] = true;
241
242 let current_level = node.level;
243 node.children.clear();
244
245 for i in (node_idx + 1)..nodes.len() {
247 if processed[i] {
248 continue;
249 }
250
251 let child_level = nodes[i].level;
252
253 if child_level <= current_level {
254 break;
256 }
257
258 if child_level == current_level + 1 {
259 let child_node = Self::build_node_hierarchy(nodes, processed, i)?;
261 node.children.push(child_node);
262 }
263 }
264
265 Ok(node)
266 }
267
268 pub fn validate(tree: &TypeTree) -> Result<()> {
270 if tree.nodes.is_empty() {
271 return Err(BinaryError::invalid_data("TypeTree has no nodes"));
272 }
273
274 for (i, node) in tree.nodes.iter().enumerate() {
275 Self::validate_node(node, 0).map_err(|e| {
276 BinaryError::generic(format!("Node {} validation failed: {}", i, e))
277 })?;
278 }
279
280 Ok(())
281 }
282
283 fn validate_node(node: &TypeTreeNode, expected_level: i32) -> Result<()> {
285 if node.type_name.is_empty() {
286 return Err(BinaryError::invalid_data("Node has empty type name"));
287 }
288
289 if node.level != expected_level {
290 return Err(BinaryError::invalid_data(format!(
291 "Node level mismatch: expected {}, got {}",
292 expected_level, node.level
293 )));
294 }
295
296 if node.byte_size < -1 {
297 return Err(BinaryError::invalid_data("Invalid byte size"));
298 }
299
300 for child in &node.children {
302 Self::validate_node(child, expected_level + 1)?;
303 }
304
305 Ok(())
306 }
307
308 pub fn get_parsing_stats(tree: &TypeTree) -> ParsingStats {
310 let mut stats = (0usize, 0i32, 0usize, 0usize); fn count_nodes(node: &TypeTreeNode, depth: i32, stats: &mut (usize, i32, usize, usize)) {
313 stats.0 += 1; stats.1 = stats.1.max(depth); if node.is_primitive() {
317 stats.2 += 1; }
319 if node.is_array() {
320 stats.3 += 1; }
322
323 for child in &node.children {
324 count_nodes(child, depth + 1, stats);
325 }
326 }
327
328 for node in &tree.nodes {
329 count_nodes(node, 0, &mut stats);
330 }
331
332 ParsingStats {
333 total_nodes: stats.0,
334 root_nodes: tree.nodes.len(),
335 max_depth: stats.1,
336 primitive_count: stats.2,
337 array_count: stats.3,
338 string_buffer_size: tree.string_buffer.len(),
339 version: tree.version,
340 }
341 }
342}
343
344#[derive(Debug, Clone)]
346pub struct ParsingStats {
347 pub total_nodes: usize,
348 pub root_nodes: usize,
349 pub max_depth: i32,
350 pub primitive_count: usize,
351 pub array_count: usize,
352 pub string_buffer_size: usize,
353 pub version: u32,
354}
355
356#[cfg(test)]
357mod tests {
358 use super::*;
359 use crate::reader::{BinaryReader, ByteOrder};
360
361 #[test]
362 fn test_parser_creation() {
363 let _dummy = 1 + 1;
365 assert_eq!(_dummy, 2);
366 }
367
368 #[test]
369 fn test_string_buffer_parsing() {
370 let buffer = b"hello\0world\0test\0";
371 let result = TypeTreeParser::get_string_from_buffer(buffer, 0).unwrap();
372 assert_eq!(result, "hello");
373
374 let result = TypeTreeParser::get_string_from_buffer(buffer, 6).unwrap();
375 assert_eq!(result, "world");
376
377 let result = TypeTreeParser::get_string_from_buffer(buffer, 12).unwrap();
378 assert_eq!(result, "test");
379 }
380
381 #[test]
382 fn test_common_string_flag_resolves_known_offsets() {
383 const COMMON_STRING_FLAG: u32 = 0x8000_0000;
384
385 let local = b"ignored\0";
386
387 let result = TypeTreeParser::resolve_string(local, COMMON_STRING_FLAG).unwrap();
389 assert_eq!(result, "AABB");
390
391 let result = TypeTreeParser::resolve_string(local, COMMON_STRING_FLAG | 123_456).unwrap();
393 assert_eq!(result, "");
394 }
395
396 #[test]
397 fn test_blob_typetree_parsing_resolves_common_strings() {
398 const COMMON_STRING_FLAG: u32 = 0x8000_0000;
399
400 let mut data = Vec::new();
401 data.extend_from_slice(&(1i32).to_le_bytes()); data.extend_from_slice(&(0i32).to_le_bytes()); data.extend_from_slice(&(1u16).to_le_bytes()); data.push(0u8); data.push(0u8); data.extend_from_slice(&COMMON_STRING_FLAG.to_le_bytes()); data.extend_from_slice(&COMMON_STRING_FLAG.to_le_bytes()); data.extend_from_slice(&(0i32).to_le_bytes()); data.extend_from_slice(&(0i32).to_le_bytes()); data.extend_from_slice(&(0i32).to_le_bytes()); data.extend_from_slice(&(0u64).to_le_bytes()); let mut reader = BinaryReader::new(&data, ByteOrder::Little);
416 let tree = TypeTreeParser::from_reader_blob(&mut reader, 19).unwrap();
417
418 assert_eq!(tree.nodes.len(), 1);
419 assert_eq!(tree.nodes[0].type_name, "AABB");
420 assert_eq!(tree.nodes[0].name, "AABB");
421 }
422}