unity_asset_binary/typetree/
serializer.rs

1//! TypeTree serialization and deserialization
2//!
3//! This module provides functionality for serializing and deserializing
4//! Unity objects using TypeTree information.
5
6use super::types::{TypeTree, TypeTreeNode};
7use crate::error::{BinaryError, Result};
8use crate::reader::BinaryReader;
9use indexmap::IndexMap;
10use unity_asset_core::UnityValue;
11
12/// TypeTree serializer
13///
14/// This struct provides methods for serializing and deserializing Unity objects
15/// using TypeTree structure information.
16pub struct TypeTreeSerializer<'a> {
17    tree: &'a TypeTree,
18}
19
20impl<'a> TypeTreeSerializer<'a> {
21    /// Create a new serializer with a TypeTree
22    pub fn new(tree: &'a TypeTree) -> Self {
23        Self { tree }
24    }
25
26    /// Parse object data using the TypeTree structure
27    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 root node, parse its children as top-level properties
32            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                            // Check if this is a critical error (insufficient data)
40                            if reader.remaining() == 0 {
41                                // No more data to read, this is expected for some objects
42                                break;
43                            }
44                            // For other errors, we might want to continue or fail
45                            // depending on the use case. For now, we'll continue.
46                            eprintln!("Warning: Failed to parse field '{}': {}", child.name, e);
47                            continue;
48                        }
49                    }
50                }
51            }
52        }
53
54        Ok(properties)
55    }
56
57    /// Parse value based on TypeTree node type
58    fn parse_value_by_type(
59        &self,
60        reader: &mut BinaryReader,
61        node: &TypeTreeNode,
62    ) -> Result<UnityValue> {
63        // Handle alignment if needed
64        if node.is_aligned() {
65            reader.align_to(4)?;
66        }
67
68        let value = match node.type_name.as_str() {
69            // Signed integers
70            "SInt8" | "char" => {
71                let val = reader.read_i8()?;
72                // Align after reading 1-byte values
73                reader.align_to(4)?;
74                UnityValue::Integer(val as i64)
75            }
76            "SInt16" | "short" => {
77                let val = reader.read_i16()?;
78                // Align after reading 2-byte values
79                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            // Unsigned integers
92            "UInt8" => {
93                let val = reader.read_u8()?;
94                // Align after reading 1-byte values
95                reader.align_to(4)?;
96                UnityValue::Integer(val as i64)
97            }
98            "UInt16" | "unsigned short" => {
99                let val = reader.read_u16()?;
100                // Align after reading 2-byte values
101                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            // Floating point
114            "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            // Boolean
124            "bool" => {
125                let val = reader.read_u8()? != 0;
126                // Align after reading boolean
127                reader.align_to(4)?;
128                UnityValue::Bool(val)
129            }
130
131            // String
132            "string" => {
133                let val = reader.read_string()?;
134                // Align after reading string
135                reader.align_to(4)?;
136                UnityValue::String(val)
137            }
138
139            // Array types
140            _ 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 type
147            "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            // Complex object types
154            _ => {
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                    // Unknown type with no children, skip bytes if size is known
166                    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    /// Parse array from TypeTree node
180    fn parse_array(&self, reader: &mut BinaryReader, node: &TypeTreeNode) -> Result<UnityValue> {
181        // Find the Array child node
182        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        // Read array size (first child is size)
189        let size = reader.read_i32()? as usize;
190        if size > 1_000_000 {
191            // Sanity check to prevent memory exhaustion
192            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        // Find the element type (usually the second child of Array node)
201        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    /// Serialize object data using the TypeTree structure
215    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    /// Serialize a single value based on TypeTree node type
232    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                    // Write string length
302                    buffer.extend_from_slice(&(val.len() as u32).to_le_bytes());
303                    // Write string data
304                    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                    // Write array size
311                    buffer.extend_from_slice(&(elements.len() as i32).to_le_bytes());
312
313                    // Find element type
314                    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                // Complex object
325                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    /// Align buffer to specified boundary
341    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    /// Get the TypeTree being used
350    pub fn tree(&self) -> &TypeTree {
351        self.tree
352    }
353
354    /// Estimate serialized size
355    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    /// Estimate size of a single value
372    fn estimate_value_size(value: &UnityValue, node: &TypeTreeNode) -> usize {
373        match node.type_name.as_str() {
374            "SInt8" | "UInt8" | "char" | "bool" => 4, // Including alignment
375            "SInt16" | "UInt16" | "short" | "unsigned short" => 4, // Including alignment
376            "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 // Length + data + alignment
381                } else {
382                    4
383                }
384            }
385            _ if node.is_array() => {
386                if let UnityValue::Array(elements) = value {
387                    let mut size = 4; // Array size
388                    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                // Complex object
402                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]; // 3 bytes
437        serializer.align_buffer(&mut buffer, 4);
438        assert_eq!(buffer.len(), 4); // Should be padded to 4 bytes
439        assert_eq!(buffer[3], 0); // Padding should be zero
440    }
441}