unity_asset_binary/asset/
mod.rs1pub mod header;
32pub mod parser;
33pub mod types;
34
35pub use header::{HeaderFormatInfo, HeaderValidation, SerializedFileHeader, validate_header};
37pub use parser::{FileStatistics, ParsingStats, SerializedFile, SerializedFileParser};
38pub use types::{FileIdentifier, ObjectInfo, SerializedType, TypeRegistry, class_ids};
39
40pub type Asset = SerializedFile;
42
43pub struct AssetProcessor {
48 file: Option<SerializedFile>,
49}
50
51impl AssetProcessor {
52 pub fn new() -> Self {
54 Self { file: None }
55 }
56
57 pub fn parse_from_bytes(&mut self, data: Vec<u8>) -> crate::error::Result<()> {
59 let file = SerializedFileParser::from_bytes(data)?;
60 self.file = Some(file);
61 Ok(())
62 }
63
64 pub fn parse_from_file<P: AsRef<std::path::Path>>(
66 &mut self,
67 path: P,
68 ) -> crate::error::Result<()> {
69 let data = std::fs::read(path).map_err(|e| {
70 crate::error::BinaryError::generic(format!("Failed to read file: {}", e))
71 })?;
72 self.parse_from_bytes(data)
73 }
74
75 #[cfg(feature = "async")]
77 pub async fn parse_from_bytes_async(&mut self, data: Vec<u8>) -> crate::error::Result<()> {
78 let file = SerializedFileParser::from_bytes_async(data).await?;
79 self.file = Some(file);
80 Ok(())
81 }
82
83 pub fn file(&self) -> Option<&SerializedFile> {
85 self.file.as_ref()
86 }
87
88 pub fn file_mut(&mut self) -> Option<&mut SerializedFile> {
90 self.file.as_mut()
91 }
92
93 pub fn objects_of_type(&self, type_id: i32) -> Vec<&ObjectInfo> {
95 self.file
96 .as_ref()
97 .map(|f| f.objects_of_type(type_id))
98 .unwrap_or_default()
99 }
100
101 pub fn find_object(&self, path_id: i64) -> Option<&ObjectInfo> {
103 self.file.as_ref().and_then(|f| f.find_object(path_id))
104 }
105
106 pub fn find_type(&self, class_id: i32) -> Option<&SerializedType> {
108 self.file.as_ref().and_then(|f| f.find_type(class_id))
109 }
110
111 pub fn statistics(&self) -> Option<FileStatistics> {
113 self.file.as_ref().map(|f| f.statistics())
114 }
115
116 pub fn validate(&self) -> crate::error::Result<()> {
118 self.file
119 .as_ref()
120 .ok_or_else(|| crate::error::BinaryError::generic("No file loaded"))?
121 .validate()
122 }
123
124 pub fn create_type_registry(&self) -> Option<TypeRegistry> {
126 self.file.as_ref().map(|f| f.create_type_registry())
127 }
128
129 pub fn clear(&mut self) {
131 self.file = None;
132 }
133
134 pub fn has_file(&self) -> bool {
136 self.file.is_some()
137 }
138
139 pub fn unity_version(&self) -> Option<&str> {
141 self.file.as_ref().map(|f| f.unity_version.as_str())
142 }
143
144 pub fn format_version(&self) -> Option<u32> {
146 self.file.as_ref().map(|f| f.header.version)
147 }
148
149 pub fn target_platform(&self) -> Option<i32> {
151 self.file.as_ref().map(|f| f.target_platform)
152 }
153}
154
155impl Default for AssetProcessor {
156 fn default() -> Self {
157 Self::new()
158 }
159}
160
161pub fn create_processor() -> AssetProcessor {
164 AssetProcessor::default()
165}
166
167pub fn parse_serialized_file(data: Vec<u8>) -> crate::error::Result<SerializedFile> {
169 SerializedFileParser::from_bytes(data)
170}
171
172pub fn parse_serialized_file_from_path<P: AsRef<std::path::Path>>(
174 path: P,
175) -> crate::error::Result<SerializedFile> {
176 let data = std::fs::read(path)
177 .map_err(|e| crate::error::BinaryError::generic(format!("Failed to read file: {}", e)))?;
178 SerializedFileParser::from_bytes(data)
179}
180
181#[cfg(feature = "async")]
183pub async fn parse_serialized_file_async(data: Vec<u8>) -> crate::error::Result<SerializedFile> {
184 SerializedFileParser::from_bytes_async(data).await
185}
186
187pub fn get_file_info<P: AsRef<std::path::Path>>(path: P) -> crate::error::Result<AssetFileInfo> {
189 let data = std::fs::read(&path)
190 .map_err(|e| crate::error::BinaryError::generic(format!("Failed to read file: {}", e)))?;
191
192 let mut reader = crate::reader::BinaryReader::new(&data, crate::reader::ByteOrder::Big);
194 let header = SerializedFileHeader::from_reader(&mut reader)?;
195
196 reader.set_byte_order(header.byte_order());
197
198 let unity_version = if header.version >= 7 {
200 reader.read_cstring().unwrap_or_default()
201 } else {
202 String::new()
203 };
204
205 let target_platform = if header.version >= 8 {
207 reader.read_i32().unwrap_or(0)
208 } else {
209 0
210 };
211
212 Ok(AssetFileInfo {
213 path: path.as_ref().to_string_lossy().to_string(),
214 format_version: header.version,
215 unity_version,
216 target_platform,
217 file_size: header.file_size,
218 is_big_endian: header.endian != 0,
219 supports_type_tree: header.supports_type_trees(),
220 })
221}
222
223pub fn is_valid_serialized_file<P: AsRef<std::path::Path>>(path: P) -> bool {
225 match std::fs::read(path) {
226 Ok(data) => {
227 if data.len() < 20 {
228 return false;
229 }
230
231 let mut reader = crate::reader::BinaryReader::new(&data, crate::reader::ByteOrder::Big);
232 match SerializedFileHeader::from_reader(&mut reader) {
233 Ok(header) => header.is_valid(),
234 Err(_) => false,
235 }
236 }
237 Err(_) => false,
238 }
239}
240
241#[derive(Debug, Clone)]
243pub struct AssetFileInfo {
244 pub path: String,
245 pub format_version: u32,
246 pub unity_version: String,
247 pub target_platform: i32,
248 pub file_size: u64,
249 pub is_big_endian: bool,
250 pub supports_type_tree: bool,
251}
252
253pub fn get_supported_versions() -> Vec<u32> {
255 (5..=50).collect() }
257
258pub fn is_version_supported(version: u32) -> bool {
260 (5..=50).contains(&version)
261}
262
263pub fn get_parsing_options(version: u32) -> ParsingOptions {
265 ParsingOptions {
266 enable_type_tree: version >= 13,
267 use_big_ids: version >= 14,
268 supports_script_types: version >= 11,
269 supports_ref_types: version >= 20,
270 uses_extended_format: version >= 22,
271 }
272}
273
274#[derive(Debug, Clone)]
276pub struct ParsingOptions {
277 pub enable_type_tree: bool,
278 pub use_big_ids: bool,
279 pub supports_script_types: bool,
280 pub supports_ref_types: bool,
281 pub uses_extended_format: bool,
282}
283
284#[cfg(test)]
285mod tests {
286 use super::*;
287
288 #[test]
289 fn test_processor_creation() {
290 let processor = create_processor();
291 assert!(!processor.has_file());
292 }
293
294 #[test]
295 fn test_version_support() {
296 assert!(is_version_supported(19));
297 assert!(is_version_supported(5));
298 assert!(!is_version_supported(100));
299 }
300
301 #[test]
302 fn test_parsing_options() {
303 let options = get_parsing_options(19);
304 assert!(options.enable_type_tree);
305 assert!(options.use_big_ids);
306 assert!(options.supports_script_types);
307
308 let old_options = get_parsing_options(10);
309 assert!(!old_options.enable_type_tree);
310 assert!(!old_options.use_big_ids);
311 }
312
313 #[test]
314 fn test_supported_versions() {
315 let versions = get_supported_versions();
316 assert!(versions.contains(&19));
317 assert!(versions.contains(&5));
318 assert!(!versions.is_empty());
319 }
320}