unity_asset_binary/typetree/
mod.rs1pub mod builder;
41pub mod parser;
42pub mod serializer;
43pub mod types;
44
45pub use builder::{TypeTreeBuilder, TypeTreeValidator, ValidationReport};
47pub use parser::{ParsingStats, TypeTreeParser};
48pub use serializer::TypeTreeSerializer;
49pub use types::{TypeInfo, TypeRegistry, TypeTree, TypeTreeNode, TypeTreeStatistics};
50
51pub struct TypeTreeProcessor {
56 tree: Option<TypeTree>,
57 version: u32,
58}
59
60impl TypeTreeProcessor {
61 pub fn new() -> Self {
63 Self {
64 tree: None,
65 version: 19, }
67 }
68
69 pub fn with_version(version: u32) -> Self {
71 Self {
72 tree: None,
73 version,
74 }
75 }
76
77 pub fn parse_from_reader(
79 &mut self,
80 reader: &mut crate::reader::BinaryReader,
81 ) -> crate::error::Result<()> {
82 let tree = if self.version >= 12 || self.version == 10 {
83 TypeTreeParser::from_reader_blob(reader, self.version)?
84 } else {
85 TypeTreeParser::from_reader(reader, self.version)?
86 };
87
88 self.tree = Some(tree);
89 Ok(())
90 }
91
92 pub fn parse_object(
94 &self,
95 reader: &mut crate::reader::BinaryReader,
96 ) -> crate::error::Result<indexmap::IndexMap<String, unity_asset_core::UnityValue>> {
97 let tree = self
98 .tree
99 .as_ref()
100 .ok_or_else(|| crate::error::BinaryError::generic("No TypeTree loaded"))?;
101
102 let serializer = TypeTreeSerializer::new(tree);
103 serializer.parse_object(reader)
104 }
105
106 pub fn serialize_object(
108 &self,
109 data: &indexmap::IndexMap<String, unity_asset_core::UnityValue>,
110 ) -> crate::error::Result<Vec<u8>> {
111 let tree = self
112 .tree
113 .as_ref()
114 .ok_or_else(|| crate::error::BinaryError::generic("No TypeTree loaded"))?;
115
116 let serializer = TypeTreeSerializer::new(tree);
117 serializer.serialize_object(data)
118 }
119
120 pub fn tree(&self) -> Option<&TypeTree> {
122 self.tree.as_ref()
123 }
124
125 pub fn set_tree(&mut self, tree: TypeTree) {
127 self.tree = Some(tree);
128 }
129
130 pub fn validate(&self) -> crate::error::Result<ValidationReport> {
132 let tree = self
133 .tree
134 .as_ref()
135 .ok_or_else(|| crate::error::BinaryError::generic("No TypeTree loaded"))?;
136
137 TypeTreeValidator::validate(tree)
138 }
139
140 pub fn statistics(&self) -> Option<TypeTreeStatistics> {
142 self.tree.as_ref().map(|tree| tree.statistics())
143 }
144
145 pub fn parsing_stats(&self) -> Option<ParsingStats> {
147 self.tree.as_ref().map(TypeTreeParser::get_parsing_stats)
148 }
149
150 pub fn clear(&mut self) {
152 self.tree = None;
153 }
154
155 pub fn has_tree(&self) -> bool {
157 self.tree.is_some()
158 }
159
160 pub fn version(&self) -> u32 {
162 self.version
163 }
164
165 pub fn set_version(&mut self, version: u32) {
167 self.version = version;
168 }
169}
170
171impl Default for TypeTreeProcessor {
172 fn default() -> Self {
173 Self::new()
174 }
175}
176
177pub fn create_processor() -> TypeTreeProcessor {
180 TypeTreeProcessor::default()
181}
182
183pub fn parse_typetree(data: &[u8], version: u32) -> crate::error::Result<TypeTree> {
185 let mut reader = crate::reader::BinaryReader::new(data, crate::reader::ByteOrder::Little);
186
187 if version >= 12 || version == 10 {
188 TypeTreeParser::from_reader_blob(&mut reader, version)
189 } else {
190 TypeTreeParser::from_reader(&mut reader, version)
191 }
192}
193
194pub fn parse_object_with_typetree(
196 tree: &TypeTree,
197 data: &[u8],
198) -> crate::error::Result<indexmap::IndexMap<String, unity_asset_core::UnityValue>> {
199 let mut reader = crate::reader::BinaryReader::new(data, crate::reader::ByteOrder::Little);
200 let serializer = TypeTreeSerializer::new(tree);
201 serializer.parse_object(&mut reader)
202}
203
204pub fn serialize_object_with_typetree(
206 tree: &TypeTree,
207 data: &indexmap::IndexMap<String, unity_asset_core::UnityValue>,
208) -> crate::error::Result<Vec<u8>> {
209 let serializer = TypeTreeSerializer::new(tree);
210 serializer.serialize_object(data)
211}
212
213pub fn build_common_typetree(class_name: &str) -> crate::error::Result<TypeTree> {
215 let mut builder = TypeTreeBuilder::new().version(19);
216
217 match class_name {
218 "GameObject" => {
219 builder.add_simple_node("GameObject".to_string(), "Base".to_string(), -1, 0)?;
220 let tree = builder.tree_mut();
221 if let Some(_root) = tree.nodes.get_mut(0) {
222 builder.add_child_to_node(
223 "Base",
224 TypeTreeNode::with_info("int".to_string(), "m_InstanceID".to_string(), 4),
225 )?;
226 builder.add_child_to_node(
227 "Base",
228 TypeTreeNode::with_info("string".to_string(), "m_Name".to_string(), -1),
229 )?;
230 }
231 }
232 "Transform" => {
233 builder.add_simple_node("Transform".to_string(), "Base".to_string(), -1, 0)?;
234 builder.add_primitive_field("Base", "m_LocalPosition".to_string(), "Vector3f")?;
236 builder.add_primitive_field("Base", "m_LocalRotation".to_string(), "Quaternionf")?;
237 builder.add_primitive_field("Base", "m_LocalScale".to_string(), "Vector3f")?;
238 }
239 _ => {
240 return Err(crate::error::BinaryError::unsupported(format!(
241 "Common TypeTree for '{}' not implemented",
242 class_name
243 )));
244 }
245 }
246
247 builder.build()
248}
249
250pub fn validate_typetree(tree: &TypeTree) -> crate::error::Result<ValidationReport> {
252 TypeTreeValidator::validate(tree)
253}
254
255pub fn get_typetree_info(tree: &TypeTree) -> TypeTreeInfo {
257 let stats = tree.statistics();
258
259 TypeTreeInfo {
260 version: tree.version,
261 platform: tree.platform,
262 has_type_dependencies: tree.has_type_dependencies,
263 node_count: stats.total_nodes,
264 root_node_count: stats.root_nodes,
265 max_depth: stats.max_depth,
266 primitive_count: stats.primitive_count,
267 array_count: stats.array_count,
268 string_buffer_size: stats.string_buffer_size,
269 }
270}
271
272#[derive(Debug, Clone)]
274pub struct TypeTreeInfo {
275 pub version: u32,
276 pub platform: u32,
277 pub has_type_dependencies: bool,
278 pub node_count: usize,
279 pub root_node_count: usize,
280 pub max_depth: i32,
281 pub primitive_count: usize,
282 pub array_count: usize,
283 pub string_buffer_size: usize,
284}
285
286pub fn is_version_supported(version: u32) -> bool {
288 version >= 10
290}
291
292pub fn get_parsing_method(version: u32) -> &'static str {
294 if version >= 12 || version == 10 {
295 "blob"
296 } else {
297 "legacy"
298 }
299}
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304
305 #[test]
306 fn test_processor_creation() {
307 let processor = create_processor();
308 assert!(!processor.has_tree());
309 assert_eq!(processor.version(), 19);
310 }
311
312 #[test]
313 fn test_version_support() {
314 assert!(is_version_supported(19));
315 assert!(is_version_supported(10));
316 assert!(!is_version_supported(5));
317 }
318
319 #[test]
320 fn test_parsing_method() {
321 assert_eq!(get_parsing_method(19), "blob");
322 assert_eq!(get_parsing_method(12), "blob");
323 assert_eq!(get_parsing_method(10), "blob");
324 assert_eq!(get_parsing_method(9), "legacy");
325 }
326
327 #[test]
328 fn test_typetree_info() {
329 let tree = TypeTree::new();
330 let info = get_typetree_info(&tree);
331 assert_eq!(info.node_count, 0);
332 assert_eq!(info.root_node_count, 0);
333 }
334
335 #[test]
336 fn test_common_typetree_building() {
337 let result = build_common_typetree("GameObject");
339 assert!(result.is_ok() || result.is_err()); }
341}