1use std::collections::HashMap;
9
10use crate::R;
11
12pub const ANDROID_NS: &str = "http://schemas.android.com/apk/res/android";
13pub const TYPE_REFERENCE: u8 = 0x01;
14pub const TYPE_STRING: u8 = 0x03;
15pub const TYPE_INT_DEC: u8 = 0x10;
16pub const TYPE_INT_BOOLEAN: u8 = 0x12;
17
18pub mod attr {
20 pub const NAME: u32 = 0x0101_0003;
21 pub const PERMISSION: u32 = 0x0101_0006;
22 pub const EXPORTED: u32 = 0x0101_0010;
23 pub const PROCESS: u32 = 0x0101_0011;
24 pub const AUTHORITIES: u32 = 0x0101_0018;
25 pub const THEME: u32 = 0x0101_0000;
26 pub const HAS_CODE: u32 = 0x0101_000c;
27 pub const NO_HISTORY: u32 = 0x0101_022d;
28 pub const EXCLUDE_FROM_RECENTS: u32 = 0x0101_0017;
29 pub const GRANT_URI_PERMISSIONS: u32 = 0x0101_001b;
30 pub const EXTRACT_NATIVE_LIBS: u32 = 0x0101_04ea;
31 pub const APP_COMPONENT_FACTORY: u32 = 0x0101_057a;
32}
33
34#[derive(Debug, Clone, PartialEq)]
35pub enum Value {
36 Str(String),
38 Typed { dtype: u8, data: u32 },
40}
41
42#[derive(Debug, Clone, PartialEq)]
43pub struct Attr {
44 pub ns: Option<String>,
45 pub name: String,
46 pub res_id: Option<u32>,
47 pub value: Value,
48}
49
50#[derive(Debug, Clone, PartialEq)]
51pub enum Node {
52 Element(Element),
53 Text(String),
54}
55
56#[derive(Debug, Clone, PartialEq)]
57pub struct Element {
58 pub ns: Option<String>,
59 pub name: String,
60 pub attrs: Vec<Attr>,
61 pub children: Vec<Node>,
62}
63
64#[derive(Debug, Clone, PartialEq)]
65pub struct Doc {
66 pub namespaces: Vec<(String, String)>,
68 pub root: Element,
69}
70
71impl Attr {
72 pub fn android(name: &str, res_id: u32, value: Value) -> Attr {
73 Attr { ns: Some(ANDROID_NS.into()), name: name.into(), res_id: Some(res_id), value }
74 }
75 pub fn str(&self) -> Option<&str> {
76 if let Value::Str(s) = &self.value {
77 Some(s)
78 } else {
79 None
80 }
81 }
82}
83
84impl Element {
85 pub fn new(name: &str, attrs: Vec<Attr>) -> Element {
86 Element { ns: None, name: name.into(), attrs, children: vec![] }
87 }
88 pub fn attr(&self, res_id: u32) -> Option<&Attr> {
89 self.attrs.iter().find(|a| a.res_id == Some(res_id))
90 }
91 pub fn android_name(&self) -> Option<&str> {
92 self.attr(attr::NAME).and_then(|a| a.str())
93 }
94 pub fn set(&mut self, a: Attr) {
95 self.attrs.retain(|x| {
96 !(x.res_id.is_some() && x.res_id == a.res_id || x.res_id.is_none() && x.name == a.name && x.ns == a.ns)
97 });
98 self.attrs.push(a);
99 }
100 pub fn remove(&mut self, res_id: u32) {
101 self.attrs.retain(|x| x.res_id != Some(res_id));
102 }
103 pub fn elements(&self) -> impl Iterator<Item = &Element> {
104 self.children.iter().filter_map(|n| if let Node::Element(e) = n { Some(e) } else { None })
105 }
106 pub fn elements_mut(&mut self) -> impl Iterator<Item = &mut Element> {
107 self.children.iter_mut().filter_map(|n| if let Node::Element(e) = n { Some(e) } else { None })
108 }
109 pub fn child_mut(&mut self, name: &str) -> Option<&mut Element> {
110 self.elements_mut().find(|e| e.name == name)
111 }
112 pub fn push(&mut self, e: Element) {
113 self.children.push(Node::Element(e));
114 }
115}
116
117fn u16_at(b: &[u8], o: usize) -> R<u16> {
120 b.get(o..o + 2).map(|x| u16::from_le_bytes([x[0], x[1]])).ok_or_else(|| "AXML truncated".into())
121}
122fn u32_at(b: &[u8], o: usize) -> R<u32> {
123 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())
124}
125
126fn read_pool(b: &[u8], c: usize) -> R<Vec<String>> {
127 let count = u32_at(b, c + 8)? as usize;
128 let utf8 = u32_at(b, c + 16)? & 0x100 != 0;
129 let start = u32_at(b, c + 20)? as usize;
130 let hs = u16_at(b, c + 2)? as usize;
131 let mut out = Vec::with_capacity(count);
132 for i in 0..count {
133 let mut o = c + start + u32_at(b, c + hs + i * 4)? as usize;
134 let s = if utf8 {
135 o += if b.get(o).ok_or("AXML truncated")? & 0x80 != 0 { 2 } else { 1 };
136 let mut l = *b.get(o).ok_or("AXML truncated")? as usize;
137 if l & 0x80 != 0 {
138 l = ((l & 0x7f) << 8) | *b.get(o + 1).ok_or("AXML truncated")? as usize;
139 o += 2;
140 } else {
141 o += 1;
142 }
143 String::from_utf8_lossy(b.get(o..o + l).ok_or("AXML string out of range")?).to_string()
144 } else {
145 let mut l = u16_at(b, o)? as usize;
146 o += 2;
147 if l & 0x8000 != 0 {
148 l = ((l & 0x7fff) << 16) | u16_at(b, o)? as usize;
149 o += 2;
150 }
151 let units: Vec<u16> = (0..l).map(|k| u16_at(b, o + 2 * k)).collect::<R<_>>()?;
152 String::from_utf16_lossy(&units)
153 };
154 out.push(s);
155 }
156 Ok(out)
157}
158
159pub fn parse(b: &[u8]) -> R<Doc> {
160 if u16_at(b, 0)? != 0x0003 {
161 return Err("not a binary XML document".into());
162 }
163 let mut pos = u16_at(b, 2)? as usize;
164 let mut pool: Vec<String> = vec![];
165 let mut resmap: Vec<u32> = vec![];
166 let mut namespaces = vec![];
167 let mut stack: Vec<Element> = vec![];
168 let mut root: Option<Element> = None;
169 let s = |pool: &Vec<String>, i: u32| -> Option<String> {
170 if i == u32::MAX {
171 None
172 } else {
173 pool.get(i as usize).cloned()
174 }
175 };
176 while pos + 8 <= b.len() {
177 let ty = u16_at(b, pos)?;
178 let hs = u16_at(b, pos + 2)? as usize;
179 let size = u32_at(b, pos + 4)? as usize;
180 if size < 8 || pos + size > b.len() {
181 return Err("AXML chunk out of range".into());
182 }
183 match ty {
184 0x0001 => pool = read_pool(b, pos)?,
185 0x0180 => resmap = (0..(size - hs) / 4).map(|i| u32_at(b, pos + hs + i * 4)).collect::<R<_>>()?,
186 0x0100 => {
187 let prefix = s(&pool, u32_at(b, pos + hs)?).unwrap_or_default();
188 let uri = s(&pool, u32_at(b, pos + hs + 4)?).unwrap_or_default();
189 if !namespaces.iter().any(|(_, u)| *u == uri) {
190 namespaces.push((prefix, uri));
191 }
192 }
193 0x0102 => {
194 let x = pos + hs;
195 let ns = s(&pool, u32_at(b, x)?);
196 let name = s(&pool, u32_at(b, x + 4)?).ok_or("element without name")?;
197 let (astart, asize, acount) =
198 (u16_at(b, x + 8)? as usize, u16_at(b, x + 10)? as usize, u16_at(b, x + 12)? as usize);
199 let mut attrs = vec![];
200 for k in 0..acount {
201 let a = x + astart + k * asize;
202 let ni = u32_at(b, a + 4)?;
203 let raw = u32_at(b, a + 8)?;
204 let dtype = *b.get(a + 15).ok_or("AXML truncated")?;
205 let data = u32_at(b, a + 16)?;
206 let value = if raw != u32::MAX {
207 Value::Str(s(&pool, raw).unwrap_or_default())
208 } else if dtype == TYPE_STRING {
209 Value::Str(s(&pool, data).unwrap_or_default())
210 } else {
211 Value::Typed { dtype, data }
212 };
213 attrs.push(Attr {
214 ns: s(&pool, u32_at(b, a)?),
215 name: s(&pool, ni).unwrap_or_default(),
216 res_id: resmap.get(ni as usize).copied(),
217 value,
218 });
219 }
220 stack.push(Element { ns, name, attrs, children: vec![] });
221 }
222 0x0103 => {
223 let e = stack.pop().ok_or("unbalanced AXML")?;
224 match stack.last_mut() {
225 Some(p) => p.children.push(Node::Element(e)),
226 None => root = Some(e),
227 }
228 }
229 0x0104 => {
230 let t = s(&pool, u32_at(b, pos + hs)?).unwrap_or_default();
231 if let Some(p) = stack.last_mut() {
232 p.children.push(Node::Text(t));
233 }
234 }
235 _ => {}
236 }
237 pos += size;
238 }
239 Ok(Doc { namespaces, root: root.ok_or("AXML without a root element")? })
240}
241
242struct Pool {
245 strings: Vec<String>,
246 index: HashMap<String, u32>,
247}
248
249impl Pool {
250 fn idx(&self, s: &str) -> u32 {
251 self.index[s]
252 }
253 fn opt(&self, s: &Option<String>) -> u32 {
254 s.as_ref().map_or(u32::MAX, |x| self.idx(x))
255 }
256}
257
258fn collect(e: &Element, attr_names: &mut Vec<(String, u32)>, other: &mut Vec<String>) {
259 let push = |v: &mut Vec<String>, s: &str| {
260 if !v.iter().any(|x| x == s) {
261 v.push(s.to_string());
262 }
263 };
264 if let Some(n) = &e.ns {
265 push(other, n);
266 }
267 push(other, &e.name);
268 for a in &e.attrs {
269 match a.res_id {
270 Some(id) if !attr_names.iter().any(|(n, i)| n == &a.name && *i == id) => {
271 attr_names.push((a.name.clone(), id))
272 }
273 Some(_) => {}
274 None => push(other, &a.name),
275 }
276 if let Some(n) = &a.ns {
277 push(other, n);
278 }
279 if let Value::Str(s) = &a.value {
280 push(other, s);
281 }
282 }
283 for c in &e.children {
284 match c {
285 Node::Element(x) => collect(x, attr_names, other),
286 Node::Text(t) => push(other, t),
287 }
288 }
289}
290
291fn utf16_entry(s: &str) -> Vec<u8> {
292 let units: Vec<u16> = s.encode_utf16().collect();
293 let mut b = vec![];
294 if units.len() > 0x7fff {
295 b.extend((((units.len() >> 16) as u16) | 0x8000).to_le_bytes());
296 b.extend(((units.len() & 0xffff) as u16).to_le_bytes());
297 } else {
298 b.extend((units.len() as u16).to_le_bytes());
299 }
300 for u in units {
301 b.extend(u.to_le_bytes());
302 }
303 b.extend([0, 0]);
304 b
305}
306
307fn chunk(ty: u16, header: &[u8], body: &[u8]) -> Vec<u8> {
308 let hs = 8 + header.len();
309 let mut c = vec![];
310 c.extend(ty.to_le_bytes());
311 c.extend((hs as u16).to_le_bytes());
312 c.extend(((hs + body.len()) as u32).to_le_bytes());
313 c.extend(header);
314 c.extend(body);
315 c
316}
317
318fn write_el(e: &Element, p: &Pool, out: &mut Vec<u8>) {
319 let mut attrs = e.attrs.clone();
320 attrs.sort_by_key(|a| (a.res_id.is_none(), a.res_id.unwrap_or(0)));
322 let mut ext = vec![];
323 ext.extend(p.opt(&e.ns).to_le_bytes());
324 ext.extend(p.idx(&e.name).to_le_bytes());
325 ext.extend(20u16.to_le_bytes()); ext.extend(20u16.to_le_bytes()); ext.extend((attrs.len() as u16).to_le_bytes());
328 let id_index = attrs.iter().position(|a| a.ns.is_none() && a.name == "id").map_or(0, |i| i + 1) as u16;
329 ext.extend(id_index.to_le_bytes());
330 ext.extend(0u16.to_le_bytes()); ext.extend(0u16.to_le_bytes()); for a in &attrs {
333 ext.extend(p.opt(&a.ns).to_le_bytes());
334 ext.extend(p.idx(&a.name).to_le_bytes());
335 let (raw, dtype, data) = match &a.value {
336 Value::Str(s) => (p.idx(s), TYPE_STRING, p.idx(s)),
337 Value::Typed { dtype, data } => (u32::MAX, *dtype, *data),
338 };
339 ext.extend(raw.to_le_bytes());
340 ext.extend(8u16.to_le_bytes());
341 ext.push(0);
342 ext.push(dtype);
343 ext.extend(data.to_le_bytes());
344 }
345 let node_header = [1u32.to_le_bytes(), u32::MAX.to_le_bytes()].concat(); out.extend(chunk(0x0102, &node_header, &ext));
347 for c in &e.children {
348 match c {
349 Node::Element(x) => write_el(x, p, out),
350 Node::Text(t) => {
351 let mut body = p.idx(t).to_le_bytes().to_vec();
352 body.extend(8u16.to_le_bytes());
353 body.push(0);
354 body.push(0);
355 body.extend(0u32.to_le_bytes());
356 out.extend(chunk(0x0104, &node_header, &body));
357 }
358 }
359 }
360 let mut end = p.opt(&e.ns).to_le_bytes().to_vec();
361 end.extend(p.idx(&e.name).to_le_bytes());
362 out.extend(chunk(0x0103, &node_header, &end));
363}
364
365pub fn write(d: &Doc) -> Vec<u8> {
366 let mut attr_names = vec![];
367 let mut other = vec![];
368 for (pfx, uri) in &d.namespaces {
369 other.push(pfx.clone());
370 other.push(uri.clone());
371 }
372 collect(&d.root, &mut attr_names, &mut other);
373 let mut strings: Vec<String> = attr_names.iter().map(|(n, _)| n.clone()).collect();
376 let mut index: HashMap<String, u32> = HashMap::new();
377 for (i, s) in strings.iter().enumerate() {
378 index.entry(s.clone()).or_insert(i as u32);
379 }
380 for s in other {
381 if !index.contains_key(&s) {
382 index.insert(s.clone(), strings.len() as u32);
383 strings.push(s);
384 }
385 }
386 let pool = Pool { strings, index };
387
388 let mut offsets = vec![];
390 let mut data = vec![];
391 for s in &pool.strings {
392 offsets.push(data.len() as u32);
393 data.extend(utf16_entry(s));
394 }
395 while data.len() % 4 != 0 {
396 data.push(0);
397 }
398 let n = pool.strings.len() as u32;
399 let strings_start = 28 + 4 * n;
400 let mut ph = vec![];
401 ph.extend(n.to_le_bytes());
402 ph.extend(0u32.to_le_bytes()); ph.extend(0u32.to_le_bytes()); ph.extend(strings_start.to_le_bytes());
405 ph.extend(0u32.to_le_bytes());
406 let mut pb = vec![];
407 for o in offsets {
408 pb.extend(o.to_le_bytes());
409 }
410 pb.extend(data);
411 let mut body = chunk(0x0001, &ph, &pb);
412 let mut rm = vec![];
413 for (_, id) in &attr_names {
414 rm.extend(id.to_le_bytes());
415 }
416 body.extend(chunk(0x0180, &[], &rm));
417 let node_header = [1u32.to_le_bytes(), u32::MAX.to_le_bytes()].concat();
418 for (pfx, uri) in &d.namespaces {
419 let mut b = pool.idx(pfx).to_le_bytes().to_vec();
420 b.extend(pool.idx(uri).to_le_bytes());
421 body.extend(chunk(0x0100, &node_header, &b));
422 }
423 write_el(&d.root, &pool, &mut body);
424 for (pfx, uri) in d.namespaces.iter().rev() {
425 let mut b = pool.idx(pfx).to_le_bytes().to_vec();
426 b.extend(pool.idx(uri).to_le_bytes());
427 body.extend(chunk(0x0101, &node_header, &b));
428 }
429 chunk(0x0003, &[], &body)
430}
431
432#[cfg(test)]
433mod tests {
434 use super::*;
435
436 fn sample() -> Doc {
437 let mut app = Element::new("application", vec![Attr::android("name", attr::NAME, Value::Str("a.App".into()))]);
438 app.ns = None;
439 let mut act = Element::new(
440 "activity",
441 vec![
442 Attr::android("exported", attr::EXPORTED, Value::Typed { dtype: TYPE_INT_BOOLEAN, data: u32::MAX }),
443 Attr::android("name", attr::NAME, Value::Str("a.Main".into())),
444 ],
445 );
446 act.push(Element::new("intent-filter", vec![]));
447 app.push(act);
448 let mut root = Element::new(
449 "manifest",
450 vec![Attr { ns: None, name: "package".into(), res_id: None, value: Value::Str("a.b".into()) }],
451 );
452 root.push(app);
453 Doc { namespaces: vec![("android".into(), ANDROID_NS.into())], root }
454 }
455
456 #[test]
457 fn roundtrip_and_sorting() {
458 let d = sample();
459 let b = write(&d);
460 let p = parse(&b).unwrap();
461 let act = p.root.elements().next().unwrap().elements().next().unwrap();
463 assert_eq!(act.attrs[0].res_id, Some(attr::NAME));
464 assert_eq!(act.android_name(), Some("a.Main"));
465 assert_eq!(write(&p), b, "write is stable");
466 let mi = crate::apk::manifest_info(&b).unwrap();
468 assert_eq!(mi.package, "a.b");
469 assert_eq!(mi.activities, vec!["a.Main".to_string()]);
470 }
471}