unity_asset/environment/imp/
pptr.rs1use super::*;
2
3impl Environment {
4 fn find_loaded_serialized_source_by_external_path(
5 &self,
6 external_path: &str,
7 ) -> Option<BinarySource> {
8 if external_path.is_empty() {
9 return None;
10 }
11
12 let direct = Path::new(external_path);
13 let direct_key = BinarySource::Path(direct.to_path_buf());
14 if self.binary_assets.contains_key(&direct_key) {
15 return Some(direct_key);
16 }
17
18 if !direct.is_absolute() {
19 let joined = self.base_path.join(direct);
20 let joined_key = BinarySource::Path(joined);
21 if self.binary_assets.contains_key(&joined_key) {
22 return Some(joined_key);
23 }
24 }
25
26 let target_file_name = direct.file_name().and_then(|n| n.to_str());
27 let mut by_name: Vec<&PathBuf> = Vec::new();
28 if let Some(name) = target_file_name {
29 by_name.extend(
30 self.binary_assets
31 .keys()
32 .filter_map(|k| k.as_path())
33 .filter(|p| p.file_name().and_then(|n| n.to_str()) == Some(name)),
34 );
35 }
36 by_name.sort();
37 if let Some(found) = by_name.first() {
38 return Some(BinarySource::Path((*found).clone()));
39 }
40
41 let external_norm = external_path.replace('\\', "/");
42 let mut by_suffix: Vec<&PathBuf> = self
43 .binary_assets
44 .keys()
45 .filter_map(|k| k.as_path())
46 .filter(|p| {
47 let p_str = p.to_string_lossy().replace('\\', "/");
48 p_str.ends_with(&external_norm) || external_norm.ends_with(&p_str)
49 })
50 .collect();
51 by_suffix.sort();
52 by_suffix.first().cloned().cloned().map(BinarySource::Path)
53 }
54
55 pub fn resolve_binary_pptr(
62 &self,
63 context: &BinaryObjectRef<'_>,
64 file_id: i32,
65 path_id: i64,
66 ) -> Option<BinaryObjectKey> {
67 if file_id == 0 {
68 return Some(BinaryObjectKey {
69 source: context.source.clone(),
70 source_kind: context.source_kind,
71 asset_index: context.asset_index,
72 path_id,
73 });
74 }
75
76 if file_id < 0 {
77 return None;
78 }
79
80 let idx: usize = (file_id - 1).try_into().ok()?;
81 let external = context.object.file().externals.get(idx)?;
82
83 if context.source_kind == BinarySourceKind::AssetBundle
86 && let Some(bundle) = self.bundles.get(context.source)
87 {
88 let external_norm = external.path.replace('\\', "/");
89 let external_file_name = std::path::Path::new(&external_norm)
90 .file_name()
91 .and_then(|n| n.to_str());
92
93 let mut candidates: Vec<(usize, &String)> =
94 bundle.asset_names.iter().enumerate().collect();
95 candidates.sort_by(|a, b| a.1.cmp(b.1));
96
97 if let Some((asset_index, _)) = candidates.into_iter().find(|(_, name)| {
98 let name_norm = name.replace('\\', "/");
99 if name_norm == external_norm {
100 return true;
101 }
102 if name_norm.ends_with(&external_norm) || external_norm.ends_with(&name_norm) {
103 return true;
104 }
105 match external_file_name {
106 Some(file_name) => {
107 std::path::Path::new(&name_norm)
108 .file_name()
109 .and_then(|n| n.to_str())
110 == Some(file_name)
111 }
112 None => false,
113 }
114 }) {
115 return Some(BinaryObjectKey {
116 source: context.source.clone(),
117 source_kind: BinarySourceKind::AssetBundle,
118 asset_index: Some(asset_index),
119 path_id,
120 });
121 }
122 }
123
124 let resolved_source =
126 self.find_loaded_serialized_source_by_external_path(&external.path)?;
127 Some(BinaryObjectKey {
128 source: resolved_source,
129 source_kind: BinarySourceKind::SerializedFile,
130 asset_index: None,
131 path_id,
132 })
133 }
134
135 pub fn read_binary_pptr(
137 &self,
138 context: &BinaryObjectRef<'_>,
139 file_id: i32,
140 path_id: i64,
141 ) -> Result<UnityObject> {
142 let key = self
143 .resolve_binary_pptr(context, file_id, path_id)
144 .ok_or_else(|| {
145 UnityAssetError::format(format!(
146 "Failed to resolve PPtr: file_id={}, path_id={}",
147 file_id, path_id
148 ))
149 })?;
150 self.read_binary_object_key(&key)
151 }
152}