unity_asset_binary/typetree/
serializer.rs1use super::types::{TypeTree, TypeTreeNode};
7use crate::error::{BinaryError, Result};
8use crate::reader::BinaryReader;
9use indexmap::IndexMap;
10use unity_asset_core::UnityValue;
11
12pub struct TypeTreeSerializer<'a> {
17 tree: &'a TypeTree,
18}
19
20impl<'a> TypeTreeSerializer<'a> {
21 pub fn new(tree: &'a TypeTree) -> Self {
23 Self { tree }
24 }
25
26 pub fn parse_object(&self, reader: &mut BinaryReader) -> Result<IndexMap<String, UnityValue>> {
28 let mut properties = IndexMap::new();
29
30 if let Some(root) = self.tree.nodes.first() {
31 for child in &root.children {
33 if !child.name.is_empty() {
34 match self.parse_value_by_type(reader, child) {
35 Ok(value) => {
36 properties.insert(child.name.clone(), value);
37 }
38 Err(e) => {
39 if reader.remaining() == 0 {
41 break;
43 }
44 eprintln!("Warning: Failed to parse field '{}': {}", child.name, e);
47 continue;
48 }
49 }
50 }
51 }
52 }
53
54 Ok(properties)
55 }
56
57 fn parse_value_by_type(
59 &self,
60 reader: &mut BinaryReader,
61 node: &TypeTreeNode,
62 ) -> Result<UnityValue> {
63 if node.is_aligned() {
65 reader.align_to(4)?;
66 }
67
68 let value = match node.type_name.as_str() {
69 "SInt8" | "char" => {
71 let val = reader.read_i8()?;
72 reader.align_to(4)?;
74 UnityValue::Integer(val as i64)
75 }
76 "SInt16" | "short" => {
77 let val = reader.read_i16()?;
78 reader.align_to(4)?;
80 UnityValue::Integer(val as i64)
81 }
82 "SInt32" | "int" => {
83 let val = reader.read_i32()?;
84 UnityValue::Integer(val as i64)
85 }
86 "SInt64" | "long long" => {
87 let val = reader.read_i64()?;
88 UnityValue::Integer(val)
89 }
90
91 "UInt8" => {
93 let val = reader.read_u8()?;
94 reader.align_to(4)?;
96 UnityValue::Integer(val as i64)
97 }
98 "UInt16" | "unsigned short" => {
99 let val = reader.read_u16()?;
100 reader.align_to(4)?;
102 UnityValue::Integer(val as i64)
103 }
104 "UInt32" | "unsigned int" | "Type*" => {
105 let val = reader.read_u32()?;
106 UnityValue::Integer(val as i64)
107 }
108 "UInt64" | "unsigned long long" | "FileSize" => {
109 let val = reader.read_u64()?;
110 UnityValue::Integer(val as i64)
111 }
112
113 "float" => {
115 let val = reader.read_f32()?;
116 UnityValue::Float(val as f64)
117 }
118 "double" => {
119 let val = reader.read_f64()?;
120 UnityValue::Float(val)
121 }
122
123 "bool" => {
125 let val = reader.read_u8()? != 0;
126 reader.align_to(4)?;
128 UnityValue::Bool(val)
129 }
130
131 "string" => {
133 let val = reader.read_string()?;
134 reader.align_to(4)?;
136 UnityValue::String(val)
137 }
138
139 _ if !node.children.is_empty()
141 && node.children.iter().any(|c| c.type_name == "Array") =>
142 {
143 self.parse_array(reader, node)?
144 }
145
146 "pair" if node.children.len() == 2 => {
148 let first = self.parse_value_by_type(reader, &node.children[0])?;
149 let second = self.parse_value_by_type(reader, &node.children[1])?;
150 UnityValue::Array(vec![first, second])
151 }
152
153 _ => {
155 if !node.children.is_empty() {
156 let mut nested_props = IndexMap::new();
157 for child in &node.children {
158 if !child.name.is_empty() {
159 let child_value = self.parse_value_by_type(reader, child)?;
160 nested_props.insert(child.name.clone(), child_value);
161 }
162 }
163 UnityValue::Object(nested_props)
164 } else {
165 if node.byte_size > 0 {
167 let _data = reader.read_bytes(node.byte_size as usize)?;
168 UnityValue::Null
169 } else {
170 UnityValue::Null
171 }
172 }
173 }
174 };
175
176 Ok(value)
177 }
178
179 fn parse_array(&self, reader: &mut BinaryReader, node: &TypeTreeNode) -> Result<UnityValue> {
181 let array_node = node
183 .children
184 .iter()
185 .find(|child| child.type_name == "Array")
186 .ok_or_else(|| BinaryError::invalid_data("Array node not found in array type"))?;
187
188 let size = reader.read_i32()? as usize;
190 if size > 1_000_000 {
191 return Err(BinaryError::invalid_data(format!(
193 "Array size too large: {}",
194 size
195 )));
196 }
197
198 let mut elements = Vec::with_capacity(size);
199
200 let element_node = array_node
202 .children
203 .get(1)
204 .ok_or_else(|| BinaryError::invalid_data("Array element type not found"))?;
205
206 for _ in 0..size {
207 let element = self.parse_value_by_type(reader, element_node)?;
208 elements.push(element);
209 }
210
211 Ok(UnityValue::Array(elements))
212 }
213
214 pub fn serialize_object(&self, data: &IndexMap<String, UnityValue>) -> Result<Vec<u8>> {
216 let mut buffer = Vec::new();
217
218 if let Some(root) = self.tree.nodes.first() {
219 for child in &root.children {
220 if !child.name.is_empty()
221 && let Some(value) = data.get(&child.name)
222 {
223 self.serialize_value(&mut buffer, value, child)?;
224 }
225 }
226 }
227
228 Ok(buffer)
229 }
230
231 fn serialize_value(
233 &self,
234 buffer: &mut Vec<u8>,
235 value: &UnityValue,
236 node: &TypeTreeNode,
237 ) -> Result<()> {
238 match node.type_name.as_str() {
239 "SInt8" | "char" => {
240 if let UnityValue::Integer(val) = value {
241 buffer.push(*val as u8);
242 self.align_buffer(buffer, 4);
243 }
244 }
245 "SInt16" | "short" => {
246 if let UnityValue::Integer(val) = value {
247 buffer.extend_from_slice(&(*val as i16).to_le_bytes());
248 self.align_buffer(buffer, 4);
249 }
250 }
251 "SInt32" | "int" => {
252 if let UnityValue::Integer(val) = value {
253 buffer.extend_from_slice(&(*val as i32).to_le_bytes());
254 }
255 }
256 "SInt64" | "long long" => {
257 if let UnityValue::Integer(val) = value {
258 buffer.extend_from_slice(&val.to_le_bytes());
259 }
260 }
261 "UInt8" => {
262 if let UnityValue::Integer(val) = value {
263 buffer.push(*val as u8);
264 self.align_buffer(buffer, 4);
265 }
266 }
267 "UInt16" | "unsigned short" => {
268 if let UnityValue::Integer(val) = value {
269 buffer.extend_from_slice(&(*val as u16).to_le_bytes());
270 self.align_buffer(buffer, 4);
271 }
272 }
273 "UInt32" | "unsigned int" | "Type*" => {
274 if let UnityValue::Integer(val) = value {
275 buffer.extend_from_slice(&(*val as u32).to_le_bytes());
276 }
277 }
278 "UInt64" | "unsigned long long" | "FileSize" => {
279 if let UnityValue::Integer(val) = value {
280 buffer.extend_from_slice(&(*val as u64).to_le_bytes());
281 }
282 }
283 "float" => {
284 if let UnityValue::Float(val) = value {
285 buffer.extend_from_slice(&(*val as f32).to_le_bytes());
286 }
287 }
288 "double" => {
289 if let UnityValue::Float(val) = value {
290 buffer.extend_from_slice(&val.to_le_bytes());
291 }
292 }
293 "bool" => {
294 if let UnityValue::Bool(val) = value {
295 buffer.push(if *val { 1 } else { 0 });
296 self.align_buffer(buffer, 4);
297 }
298 }
299 "string" => {
300 if let UnityValue::String(val) = value {
301 buffer.extend_from_slice(&(val.len() as u32).to_le_bytes());
303 buffer.extend_from_slice(val.as_bytes());
305 self.align_buffer(buffer, 4);
306 }
307 }
308 _ if node.is_array() => {
309 if let UnityValue::Array(elements) = value {
310 buffer.extend_from_slice(&(elements.len() as i32).to_le_bytes());
312
313 if let Some(array_node) = node.children.iter().find(|c| c.type_name == "Array")
315 && let Some(element_node) = array_node.children.get(1)
316 {
317 for element in elements {
318 self.serialize_value(buffer, element, element_node)?;
319 }
320 }
321 }
322 }
323 _ => {
324 if let UnityValue::Object(obj) = value {
326 for child in &node.children {
327 if !child.name.is_empty()
328 && let Some(child_value) = obj.get(&child.name)
329 {
330 self.serialize_value(buffer, child_value, child)?;
331 }
332 }
333 }
334 }
335 }
336
337 Ok(())
338 }
339
340 fn align_buffer(&self, buffer: &mut Vec<u8>, alignment: usize) {
342 let remainder = buffer.len() % alignment;
343 if remainder != 0 {
344 let padding = alignment - remainder;
345 buffer.resize(buffer.len() + padding, 0);
346 }
347 }
348
349 pub fn tree(&self) -> &TypeTree {
351 self.tree
352 }
353
354 pub fn estimate_size(&self, data: &IndexMap<String, UnityValue>) -> usize {
356 let mut size = 0;
357
358 if let Some(root) = self.tree.nodes.first() {
359 for child in &root.children {
360 if !child.name.is_empty()
361 && let Some(value) = data.get(&child.name)
362 {
363 size += Self::estimate_value_size(value, child);
364 }
365 }
366 }
367
368 size
369 }
370
371 fn estimate_value_size(value: &UnityValue, node: &TypeTreeNode) -> usize {
373 match node.type_name.as_str() {
374 "SInt8" | "UInt8" | "char" | "bool" => 4, "SInt16" | "UInt16" | "short" | "unsigned short" => 4, "SInt32" | "UInt32" | "int" | "unsigned int" | "float" | "Type*" => 4,
377 "SInt64" | "UInt64" | "long long" | "unsigned long long" | "double" | "FileSize" => 8,
378 "string" => {
379 if let UnityValue::String(s) = value {
380 4 + s.len() + (4 - (s.len() % 4)) % 4 } else {
382 4
383 }
384 }
385 _ if node.is_array() => {
386 if let UnityValue::Array(elements) = value {
387 let mut size = 4; if let Some(array_node) = node.children.iter().find(|c| c.type_name == "Array")
389 && let Some(element_node) = array_node.children.get(1)
390 {
391 for element in elements {
392 size += Self::estimate_value_size(element, element_node);
393 }
394 }
395 size
396 } else {
397 4
398 }
399 }
400 _ => {
401 if let UnityValue::Object(obj) = value {
403 let mut size = 0;
404 for child in &node.children {
405 if !child.name.is_empty()
406 && let Some(child_value) = obj.get(&child.name)
407 {
408 size += Self::estimate_value_size(child_value, child);
409 }
410 }
411 size
412 } else {
413 node.byte_size.max(0) as usize
414 }
415 }
416 }
417 }
418}
419
420#[cfg(test)]
421mod tests {
422 use super::*;
423
424 #[test]
425 fn test_serializer_creation() {
426 let tree = TypeTree::new();
427 let serializer = TypeTreeSerializer::new(&tree);
428 assert!(serializer.tree().is_empty());
429 }
430
431 #[test]
432 fn test_buffer_alignment() {
433 let tree = TypeTree::new();
434 let serializer = TypeTreeSerializer::new(&tree);
435
436 let mut buffer = vec![1, 2, 3]; serializer.align_buffer(&mut buffer, 4);
438 assert_eq!(buffer.len(), 4); assert_eq!(buffer[3], 0); }
441}