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