Skip to main content

ddc_dex/
annotations.rs

1//! `encoded_value`, annotations and static-value arrays.
2//!
3//! Only what the decompiler needs: static field initializers and the
4//! dalvik nesting annotations (`EnclosingClass`, `InnerClass`,
5//! `EnclosingMethod`, `MemberClasses`).
6
7use crate::reader::Cursor;
8
9#[derive(Debug, Clone)]
10pub enum EncodedValue {
11    Byte(i8),
12    Short(i16),
13    Char(u16),
14    Int(i32),
15    Long(i64),
16    Float(f32),
17    Double(f64),
18    MethodType(u32),
19    MethodHandle(u32),
20    String(u32),
21    Type(u32),
22    Field(u32),
23    Method(u32),
24    Enum(u32),
25    Array(Vec<EncodedValue>),
26    Annotation(EncodedAnnotation),
27    Null,
28    Boolean(bool),
29}
30
31#[derive(Debug, Clone)]
32pub struct EncodedAnnotation {
33    pub type_idx: u32,
34    /// (name string idx, value)
35    pub elements: Vec<(u32, EncodedValue)>,
36}
37
38fn little_extend(bytes: &[u8], signed: bool, size: usize) -> i64 {
39    let mut v: u64 = 0;
40    for (i, &b) in bytes.iter().enumerate() {
41        v |= (b as u64) << (8 * i);
42    }
43    if signed {
44        let shift = 64 - 8 * size;
45        v = (v << shift) as i64 as u64 >> shift;
46    }
47    v as i64
48}
49
50pub fn read_encoded_value(data: &[u8], pos: usize) -> Option<(EncodedValue, usize)> {
51    let mut c = Cursor::at(data, pos);
52    let header = c.u1()?;
53    let vtype = header & 0x1f;
54    let varg = (header >> 5) as usize;
55    match vtype {
56        0x00 => {
57            let v = little_extend(take(data, c.pos, varg + 1)?, true, varg + 1);
58            Some((EncodedValue::Byte(v as i8), c.pos + varg + 1 - pos))
59        }
60        0x02 => {
61            let v = little_extend(take(data, c.pos, varg + 1)?, true, varg + 1);
62            Some((EncodedValue::Short(v as i16), c.pos + varg + 1 - pos))
63        }
64        0x03 => {
65            let v = little_extend(take(data, c.pos, varg + 1)?, false, varg + 1);
66            Some((EncodedValue::Char(v as u16), c.pos + varg + 1 - pos))
67        }
68        0x04 => {
69            let v = little_extend(take(data, c.pos, varg + 1)?, true, varg + 1);
70            Some((EncodedValue::Int(v as i32), c.pos + varg + 1 - pos))
71        }
72        0x06 => {
73            let v = little_extend(take(data, c.pos, varg + 1)?, true, varg + 1);
74            Some((EncodedValue::Long(v), c.pos + varg + 1 - pos))
75        }
76        0x10 => {
77            let v = little_extend(take(data, c.pos, varg + 1)?, false, varg + 1);
78            Some((
79                EncodedValue::Float(f32::from_bits(v as u32)),
80                c.pos + varg + 1 - pos,
81            ))
82        }
83        0x11 => {
84            let v = little_extend(take(data, c.pos, varg + 1)?, false, varg + 1);
85            Some((
86                EncodedValue::Double(f64::from_bits(v as u64)),
87                c.pos + varg + 1 - pos,
88            ))
89        }
90        0x15..=0x1b => {
91            let v = little_extend(take(data, c.pos, varg + 1)?, false, varg + 1);
92            let ev = match vtype {
93                0x15 => EncodedValue::MethodType(v as u32),
94                0x16 => EncodedValue::MethodHandle(v as u32),
95                0x17 => EncodedValue::String(v as u32),
96                0x18 => EncodedValue::Type(v as u32),
97                0x19 => EncodedValue::Field(v as u32),
98                0x1a => EncodedValue::Method(v as u32),
99                _ => EncodedValue::Enum(v as u32),
100            };
101            Some((ev, c.pos + varg + 1 - pos))
102        }
103        0x1c => {
104            let n = c.read_uleb128()? as usize;
105            let mut items = Vec::with_capacity(n);
106            let mut p = c.pos;
107            for _ in 0..n {
108                let (v, used) = read_encoded_value(data, p)?;
109                p += used;
110                items.push(v);
111            }
112            Some((EncodedValue::Array(items), p - pos))
113        }
114        0x1d => {
115            let (a, used) = read_encoded_annotation(data, c.pos)?;
116            Some((EncodedValue::Annotation(a), c.pos - pos + used))
117        }
118        0x1e => Some((EncodedValue::Null, 1)),
119        0x1f => Some((EncodedValue::Boolean(varg != 0), 1)),
120        _ => Some((EncodedValue::Null, 1)),
121    }
122}
123
124fn take(data: &[u8], pos: usize, n: usize) -> Option<&[u8]> {
125    if pos + n > data.len() {
126        return None;
127    }
128    Some(&data[pos..pos + n])
129}
130
131pub fn read_encoded_annotation(data: &[u8], pos: usize) -> Option<(EncodedAnnotation, usize)> {
132    let mut c = Cursor::at(data, pos);
133    let type_idx = c.read_uleb128()? as u32;
134    let n = c.read_uleb128()? as usize;
135    let mut elements = Vec::with_capacity(n);
136    let mut p = c.pos;
137    for _ in 0..n {
138        let mut cc = Cursor::at(data, p);
139        let name = cc.read_uleb128()? as u32;
140        p = cc.pos;
141        let (v, used) = read_encoded_value(data, p)?;
142        p += used;
143        elements.push((name, v));
144    }
145    Some((EncodedAnnotation { type_idx, elements }, p - pos))
146}
147
148pub fn read_encoded_array(data: &[u8], pos: usize) -> Option<Vec<EncodedValue>> {
149    let mut c = Cursor::at(data, pos);
150    let n = c.read_uleb128()? as usize;
151    let mut out = Vec::with_capacity(n);
152    let mut p = c.pos;
153    for _ in 0..n {
154        let (v, used) = read_encoded_value(data, p)?;
155        p += used;
156        out.push(v);
157    }
158    Some(out)
159}
160
161/// `annotation_directory_item` → `class_annotations_off` → annotation set:
162/// all annotations attached to a class.
163pub fn read_class_annotations(data: &[u8], annotations_off: u32) -> Vec<EncodedAnnotation> {
164    let off = annotations_off as usize;
165    if off == 0 || off + 4 > data.len() {
166        return Vec::new();
167    }
168    let set_off = u32::from_le_bytes(data[off..off + 4].try_into().unwrap()) as usize;
169    if set_off == 0 || set_off + 4 > data.len() {
170        return Vec::new();
171    }
172    let n = u32::from_le_bytes(data[set_off..set_off + 4].try_into().unwrap()) as usize;
173    let mut out = Vec::with_capacity(n);
174    for i in 0..n {
175        let p = set_off + 4 + 4 * i;
176        if p + 4 > data.len() {
177            break;
178        }
179        let item_off = u32::from_le_bytes(data[p..p + 4].try_into().unwrap()) as usize;
180        // annotation_item: u1 visibility + encoded_annotation.
181        if item_off >= data.len() {
182            continue;
183        }
184        if let Some((a, _)) = read_encoded_annotation(data, item_off + 1) {
185            out.push(a);
186        }
187    }
188    out
189}
190
191/// Nesting evidence recorded by d8 in dalvik annotations.
192#[derive(Debug, Clone, Default)]
193pub struct NestingInfo {
194    /// `Ldalvik/annotation/EnclosingClass;` → outer type idx.
195    pub enclosing_class: Option<u32>,
196    /// `Ldalvik/annotation/EnclosingMethod;` → method idx.
197    pub enclosing_method: Option<u32>,
198    /// `Ldalvik/annotation/InnerClass;` → simple name.
199    pub inner_name: Option<u32>,
200    /// `Ldalvik/annotation/MemberClasses;` → member type idxs.
201    pub member_classes: Vec<u32>,
202}
203
204const DALVIK_ENCLOSING_CLASS: &str = "Ldalvik/annotation/EnclosingClass;";
205const DALVIK_ENCLOSING_METHOD: &str = "Ldalvik/annotation/EnclosingMethod;";
206const DALVIK_INNER_CLASS: &str = "Ldalvik/annotation/InnerClass;";
207const DALVIK_MEMBER_CLASSES: &str = "Ldalvik/annotation/MemberClasses;";
208
209/// Resolve nesting from class annotations given a dex string resolver.
210pub fn nesting_from(
211    annotations: &[EncodedAnnotation],
212    type_name: &dyn Fn(u32) -> String,
213) -> NestingInfo {
214    let mut info = NestingInfo::default();
215    for a in annotations {
216        let tname = type_name(a.type_idx);
217        match tname.as_str() {
218            DALVIK_ENCLOSING_CLASS => {
219                for (_, v) in &a.elements {
220                    if let EncodedValue::Type(t) = v {
221                        info.enclosing_class = Some(*t);
222                    }
223                }
224            }
225            DALVIK_ENCLOSING_METHOD => {
226                for (_, v) in &a.elements {
227                    if let EncodedValue::Method(m) = v {
228                        info.enclosing_method = Some(*m);
229                    }
230                }
231            }
232            DALVIK_INNER_CLASS => {
233                for (_, v) in &a.elements {
234                    if let EncodedValue::String(s) = v {
235                        info.inner_name = Some(*s);
236                    }
237                }
238            }
239            DALVIK_MEMBER_CLASSES => {
240                for (_, v) in &a.elements {
241                    if let EncodedValue::Array(items) = v {
242                        for it in items {
243                            if let EncodedValue::Type(t) = it {
244                                info.member_classes.push(*t);
245                            }
246                        }
247                    }
248                }
249            }
250            _ => {}
251        }
252    }
253    info
254}