unity_asset_binary/typetree/
parser.rs1use super::types::{TypeTree, TypeTreeNode};
7use crate::error::{BinaryError, Result};
8use crate::reader::BinaryReader;
9
10pub struct TypeTreeParser;
15
16impl TypeTreeParser {
17 pub fn from_reader(reader: &mut BinaryReader, version: u32) -> Result<TypeTree> {
19 let mut tree = TypeTree::new();
20 tree.version = version;
21
22 let node_count = reader.read_u32()? as usize;
24
25 let string_buffer_size = reader.read_u32()? as usize;
27
28 for _ in 0..node_count {
30 let node = Self::read_node(reader, version)?;
31 tree.nodes.push(node);
32 }
33
34 tree.string_buffer = reader.read_bytes(string_buffer_size)?;
36
37 Self::resolve_strings(&mut tree)?;
39
40 Self::build_hierarchy(&mut tree)?;
42
43 Ok(tree)
44 }
45
46 pub fn from_reader_blob(reader: &mut BinaryReader, version: u32) -> Result<TypeTree> {
48 let mut tree = TypeTree::new();
49 tree.version = version;
50
51 let node_count = reader.read_i32()? as usize;
53
54 let string_buffer_size = reader.read_i32()? as usize;
56
57 for _ in 0..node_count {
59 let mut node = TypeTreeNode::new();
60
61 node.version = reader.read_u16()? as i32;
63 node.level = reader.read_u8()? as i32;
64 node.type_flags = reader.read_u8()? as i32;
65 node.type_str_offset = reader.read_u32()?;
66 node.name_str_offset = reader.read_u32()?;
67 node.byte_size = reader.read_i32()?;
68 node.index = reader.read_i32()?;
69 node.meta_flags = reader.read_i32()?;
70
71 if version >= 19 {
72 node.ref_type_hash = reader.read_u64()?;
73 }
74
75 tree.nodes.push(node);
76 }
77
78 tree.string_buffer = reader.read_bytes(string_buffer_size)?;
80
81 Self::resolve_strings(&mut tree)?;
83
84 Self::build_hierarchy(&mut tree)?;
86
87 Ok(tree)
88 }
89
90 fn read_node(reader: &mut BinaryReader, version: u32) -> Result<TypeTreeNode> {
92 let mut node = TypeTreeNode::new();
93
94 if version >= 10 {
95 node.version = reader.read_i16()? as i32;
96 node.level = reader.read_u8()? as i32;
97 node.type_flags = reader.read_u8()? as i32;
98 node.type_str_offset = reader.read_u32()?;
99 node.name_str_offset = reader.read_u32()?;
100 node.byte_size = reader.read_i32()?;
101 node.index = reader.read_i32()?;
102 node.meta_flags = reader.read_i32()?;
103
104 if version >= 12 {
105 node.ref_type_hash = reader.read_u64()?;
106 }
107 } else {
108 node.type_str_offset = reader.read_u32()?;
110 node.name_str_offset = reader.read_u32()?;
111 node.byte_size = reader.read_i32()?;
112 node.index = reader.read_i32()?;
113 node.type_flags = reader.read_i32()?;
114 node.version = reader.read_i32()?;
115 node.meta_flags = reader.read_i32()?;
116 node.level = reader.read_i32()?;
117 }
118
119 Ok(node)
120 }
121
122 fn resolve_strings(tree: &mut TypeTree) -> Result<()> {
124 for node in &mut tree.nodes {
125 Self::resolve_node_strings(node, &tree.string_buffer)?;
126 }
127 Ok(())
128 }
129
130 fn resolve_node_strings(node: &mut TypeTreeNode, string_buffer: &[u8]) -> Result<()> {
132 node.type_name = Self::get_string_from_buffer(string_buffer, node.type_str_offset)?;
134
135 node.name = Self::get_string_from_buffer(string_buffer, node.name_str_offset)?;
137
138 for child in &mut node.children {
140 Self::resolve_node_strings(child, string_buffer)?;
141 }
142
143 Ok(())
144 }
145
146 fn get_string_from_buffer(buffer: &[u8], offset: u32) -> Result<String> {
148 if offset as usize >= buffer.len() {
149 return Ok(String::new());
150 }
151
152 let start = offset as usize;
153 let end = buffer[start..]
154 .iter()
155 .position(|&b| b == 0)
156 .map(|pos| start + pos)
157 .unwrap_or(buffer.len());
158
159 String::from_utf8(buffer[start..end].to_vec())
160 .map_err(|e| BinaryError::generic(format!("Invalid UTF-8 string: {}", e)))
161 }
162
163 fn build_hierarchy(tree: &mut TypeTree) -> Result<()> {
165 if tree.nodes.is_empty() {
166 return Ok(());
167 }
168
169 let mut nodes = std::mem::take(&mut tree.nodes);
171
172 let mut stack: Vec<(i32, usize)> = Vec::new(); let mut root_nodes = Vec::new();
175
176 for (i, node) in nodes.iter().enumerate() {
177 let current_level = node.level;
178
179 while let Some(&(level, _)) = stack.last() {
181 if level < current_level {
182 break;
183 }
184 stack.pop();
185 }
186
187 if let Some(&(_, _parent_idx)) = stack.last() {
188 } else {
191 root_nodes.push(i);
193 }
194
195 stack.push((current_level, i));
196 }
197
198 let mut processed = vec![false; nodes.len()];
200 let mut result_nodes = Vec::new();
201
202 for &root_idx in &root_nodes {
203 if !processed[root_idx] {
204 let root_node = Self::build_node_hierarchy(&mut nodes, &mut processed, root_idx)?;
205 result_nodes.push(root_node);
206 }
207 }
208
209 tree.nodes = result_nodes;
210 Ok(())
211 }
212
213 fn build_node_hierarchy(
215 nodes: &mut [TypeTreeNode],
216 processed: &mut [bool],
217 node_idx: usize,
218 ) -> Result<TypeTreeNode> {
219 if processed[node_idx] {
220 return Err(BinaryError::generic("Node already processed"));
221 }
222
223 let mut node = nodes[node_idx].clone();
224 processed[node_idx] = true;
225
226 let current_level = node.level;
227 node.children.clear();
228
229 for i in (node_idx + 1)..nodes.len() {
231 if processed[i] {
232 continue;
233 }
234
235 let child_level = nodes[i].level;
236
237 if child_level <= current_level {
238 break;
240 }
241
242 if child_level == current_level + 1 {
243 let child_node = Self::build_node_hierarchy(nodes, processed, i)?;
245 node.children.push(child_node);
246 }
247 }
248
249 Ok(node)
250 }
251
252 pub fn validate(tree: &TypeTree) -> Result<()> {
254 if tree.nodes.is_empty() {
255 return Err(BinaryError::invalid_data("TypeTree has no nodes"));
256 }
257
258 for (i, node) in tree.nodes.iter().enumerate() {
259 Self::validate_node(node, 0).map_err(|e| {
260 BinaryError::generic(format!("Node {} validation failed: {}", i, e))
261 })?;
262 }
263
264 Ok(())
265 }
266
267 fn validate_node(node: &TypeTreeNode, expected_level: i32) -> Result<()> {
269 if node.type_name.is_empty() {
270 return Err(BinaryError::invalid_data("Node has empty type name"));
271 }
272
273 if node.level != expected_level {
274 return Err(BinaryError::invalid_data(format!(
275 "Node level mismatch: expected {}, got {}",
276 expected_level, node.level
277 )));
278 }
279
280 if node.byte_size < -1 {
281 return Err(BinaryError::invalid_data("Invalid byte size"));
282 }
283
284 for child in &node.children {
286 Self::validate_node(child, expected_level + 1)?;
287 }
288
289 Ok(())
290 }
291
292 pub fn get_parsing_stats(tree: &TypeTree) -> ParsingStats {
294 let mut stats = (0usize, 0i32, 0usize, 0usize); fn count_nodes(node: &TypeTreeNode, depth: i32, stats: &mut (usize, i32, usize, usize)) {
297 stats.0 += 1; stats.1 = stats.1.max(depth); if node.is_primitive() {
301 stats.2 += 1; }
303 if node.is_array() {
304 stats.3 += 1; }
306
307 for child in &node.children {
308 count_nodes(child, depth + 1, stats);
309 }
310 }
311
312 for node in &tree.nodes {
313 count_nodes(node, 0, &mut stats);
314 }
315
316 ParsingStats {
317 total_nodes: stats.0,
318 root_nodes: tree.nodes.len(),
319 max_depth: stats.1,
320 primitive_count: stats.2,
321 array_count: stats.3,
322 string_buffer_size: tree.string_buffer.len(),
323 version: tree.version,
324 }
325 }
326}
327
328#[derive(Debug, Clone)]
330pub struct ParsingStats {
331 pub total_nodes: usize,
332 pub root_nodes: usize,
333 pub max_depth: i32,
334 pub primitive_count: usize,
335 pub array_count: usize,
336 pub string_buffer_size: usize,
337 pub version: u32,
338}
339
340#[cfg(test)]
341mod tests {
342 use super::*;
343
344 #[test]
345 fn test_parser_creation() {
346 let _dummy = 1 + 1;
348 assert_eq!(_dummy, 2);
349 }
350
351 #[test]
352 fn test_string_buffer_parsing() {
353 let buffer = b"hello\0world\0test\0";
354 let result = TypeTreeParser::get_string_from_buffer(buffer, 0).unwrap();
355 assert_eq!(result, "hello");
356
357 let result = TypeTreeParser::get_string_from_buffer(buffer, 6).unwrap();
358 assert_eq!(result, "world");
359
360 let result = TypeTreeParser::get_string_from_buffer(buffer, 12).unwrap();
361 assert_eq!(result, "test");
362 }
363}