1use std::io::Read;
4use std::path::Path;
5
6use crate::R;
7
8#[derive(Debug, Clone, PartialEq)]
9pub enum Val {
10 Str(String),
11 Int(i64),
12 Bool(bool),
13 Ref(u32),
14 Other(u32),
15}
16
17impl Val {
18 pub fn as_str(&self) -> Option<&str> {
19 if let Val::Str(s) = self {
20 Some(s)
21 } else {
22 None
23 }
24 }
25}
26
27#[derive(Debug, Clone)]
28pub struct Element {
29 pub name: String,
30 pub depth: usize,
31 pub attrs: Vec<(String, Val)>,
32}
33
34impl Element {
35 pub fn attr(&self, name: &str) -> Option<&Val> {
36 self.attrs.iter().find(|(n, _)| n == name).map(|(_, v)| v)
37 }
38}
39
40fn u16_at(b: &[u8], o: usize) -> R<u16> {
41 b.get(o..o + 2).map(|x| u16::from_le_bytes([x[0], x[1]])).ok_or_else(|| "AXML truncated".into())
42}
43
44fn u32_at(b: &[u8], o: usize) -> R<u32> {
45 b.get(o..o + 4).map(|x| u32::from_le_bytes([x[0], x[1], x[2], x[3]])).ok_or_else(|| "AXML truncated".into())
46}
47
48fn string_pool(b: &[u8], c: usize) -> R<Vec<String>> {
49 let count = u32_at(b, c + 8)? as usize;
50 let utf8 = u32_at(b, c + 16)? & 0x100 != 0;
51 let strings_start = u32_at(b, c + 20)? as usize;
52 let header = u16_at(b, c + 2)? as usize;
53 let mut out = Vec::with_capacity(count);
54 for i in 0..count {
55 let off = c + strings_start + u32_at(b, c + header + i * 4)? as usize;
56 let s = if utf8 {
57 let mut o = off;
58 let l16 = b[o] as usize;
59 o += if l16 & 0x80 != 0 { 2 } else { 1 };
60 let mut l8 = b[o] as usize;
61 if l8 & 0x80 != 0 {
62 l8 = ((l8 & 0x7f) << 8) | b[o + 1] as usize;
63 o += 2;
64 } else {
65 o += 1;
66 }
67 String::from_utf8_lossy(b.get(o..o + l8).ok_or("AXML string out of range")?).to_string()
68 } else {
69 let mut o = off;
70 let mut l = u16_at(b, o)? as usize;
71 o += 2;
72 if l & 0x8000 != 0 {
73 l = ((l & 0x7fff) << 16) | u16_at(b, o)? as usize;
74 o += 2;
75 }
76 let units: Vec<u16> = (0..l).map(|k| u16_at(b, o + 2 * k)).collect::<R<_>>()?;
77 String::from_utf16_lossy(&units)
78 };
79 out.push(s);
80 }
81 Ok(out)
82}
83
84pub fn parse_axml(b: &[u8]) -> R<Vec<Element>> {
86 if u16_at(b, 0)? != 0x0003 {
87 return Err("not a binary XML file".into());
88 }
89 let mut pos = u16_at(b, 2)? as usize;
90 let mut strings = vec![];
91 let mut depth = 0usize;
92 let mut out = vec![];
93 let s = |strings: &Vec<String>, i: u32| -> String {
94 if i == u32::MAX {
95 String::new()
96 } else {
97 strings.get(i as usize).cloned().unwrap_or_default()
98 }
99 };
100 while pos + 8 <= b.len() {
101 let ty = u16_at(b, pos)?;
102 let size = u32_at(b, pos + 4)? as usize;
103 if size < 8 {
104 return Err("AXML chunk with bad size".into());
105 }
106 match ty {
107 0x0001 => strings = string_pool(b, pos)?,
108 0x0102 => {
109 let hs = u16_at(b, pos + 2)? as usize;
110 let ext = pos + hs;
111 let name = s(&strings, u32_at(b, ext + 4)?);
112 let astart = u16_at(b, ext + 8)? as usize;
113 let asize = u16_at(b, ext + 10)? as usize;
114 let acount = u16_at(b, ext + 12)? as usize;
115 let mut attrs = vec![];
116 for k in 0..acount {
117 let a = ext + astart + k * asize;
118 let an = s(&strings, u32_at(b, a + 4)?);
119 let raw = u32_at(b, a + 8)?;
120 let dtype = b[a + 15];
121 let data = u32_at(b, a + 16)?;
122 let v = if raw != u32::MAX {
123 Val::Str(s(&strings, raw))
124 } else {
125 match dtype {
126 0x03 => Val::Str(s(&strings, data)),
127 0x10 | 0x11 => Val::Int(data as i32 as i64),
128 0x12 => Val::Bool(data != 0),
129 0x01 => Val::Ref(data),
130 _ => Val::Other(data),
131 }
132 };
133 attrs.push((an, v));
134 }
135 out.push(Element { name, depth, attrs });
136 depth += 1;
137 }
138 0x0103 => depth = depth.saturating_sub(1),
139 _ => {}
140 }
141 pos += size;
142 }
143 Ok(out)
144}
145
146#[derive(Debug, Clone, Default, serde::Serialize)]
148pub struct ManifestInfo {
149 pub package: String,
150 pub version_code: i64,
151 pub version_name: Option<String>,
152 pub min_sdk: i64,
153 pub permissions: Vec<String>,
154 pub activities: Vec<String>,
155 pub services: Vec<String>,
156 pub receivers: Vec<String>,
157 pub providers: Vec<String>,
158 pub features: Vec<String>,
159 pub application_class: Option<String>,
160 pub native_activity_lib: Option<String>,
161}
162
163pub fn manifest_info(axml: &[u8]) -> R<ManifestInfo> {
164 let els = parse_axml(axml)?;
165 let mut m = ManifestInfo::default();
166 let mut in_native_activity = false;
167 for e in &els {
168 let name = || e.attr("name").and_then(|v| v.as_str()).map(String::from);
169 match e.name.as_str() {
170 "manifest" => {
171 m.package = e.attr("package").and_then(|v| v.as_str()).unwrap_or_default().to_string();
172 m.version_code = match e.attr("versionCode") {
173 Some(Val::Int(i)) => *i,
174 Some(Val::Str(s)) => s.parse().unwrap_or(0),
175 _ => 0,
176 };
177 m.version_name = e.attr("versionName").and_then(|v| v.as_str()).map(String::from);
178 }
179 "uses-sdk" => {
180 if let Some(Val::Int(i)) = e.attr("minSdkVersion") {
181 m.min_sdk = *i;
182 }
183 }
184 "uses-permission" | "uses-permission-sdk-23" => m.permissions.extend(name()),
185 "uses-feature" => {
186 let required = !matches!(e.attr("required"), Some(Val::Bool(false)));
187 if required {
188 m.features.extend(name());
189 }
190 }
191 "application" => m.application_class = name(),
192 "activity" | "activity-alias" => {
193 let n = name().unwrap_or_default();
194 in_native_activity = n == "android.app.NativeActivity";
195 m.activities.push(n);
196 }
197 "service" => m.services.extend(name()),
198 "receiver" => m.receivers.extend(name()),
199 "provider" => m.providers.extend(name()),
200 "meta-data" if in_native_activity && name().as_deref() == Some("android.app.lib_name") => {
201 m.native_activity_lib = e.attr("value").and_then(|v| v.as_str()).map(String::from);
202 }
203 _ => {}
204 }
205 }
206 Ok(m)
207}
208
209pub struct Apk {
210 zip: zip::ZipArchive<std::fs::File>,
211}
212
213impl Apk {
214 pub fn open(p: &Path) -> R<Apk> {
215 let f = std::fs::File::open(p).map_err(|e| format!("{}: {e}", p.display()))?;
216 Ok(Apk { zip: zip::ZipArchive::new(f).map_err(|e| format!("{}: {e}", p.display()))? })
217 }
218
219 pub fn names(&self) -> Vec<String> {
220 self.zip.file_names().map(String::from).collect()
221 }
222
223 pub fn read(&mut self, name: &str) -> R<Vec<u8>> {
224 let mut e = self.zip.by_name(name).map_err(|e| format!("{name}: {e}"))?;
225 let mut v = Vec::with_capacity(e.size() as usize);
226 e.read_to_end(&mut v).map_err(|e| e.to_string())?;
227 Ok(v)
228 }
229
230 pub fn manifest(&mut self) -> R<ManifestInfo> {
231 manifest_info(&self.read("AndroidManifest.xml")?)
232 }
233}