rusty_dex/dex/fields.rs
1//! Representation of class fields
2//!
3//! This module decodes fields from a DEX file and returns them in the correct order. Fields must
4//! be ordered by the class they belong to, then their name, and finally their type.
5//! Each field can represent a static field initialized in the `<cinit>` pseudo-method or a class
6//! field that is initialized when the class is instantiated.
7
8use std::io::{Seek, SeekFrom};
9use std::cmp::Ordering;
10
11use crate::error::DexError;
12use crate::dex::reader::DexReader;
13use crate::dex::types::DexTypes;
14use crate::dex::strings::DexStrings;
15
16/// Internal representation of a field.
17///
18/// The index fields are read from the DEX file and are then used to decode the field, which is
19/// what we actually return to the user.
20#[derive(Debug)]
21struct FieldIdItem {
22 /// Index into the list of types representing the defining class of the field
23 class_idx: u16,
24 /// Index into the list of types representing the type of the field
25 type_idx: u16,
26 /// Index into the list of strings representing the name of the field
27 name_idx: u32,
28 /// Decoded field name
29 decoded: String,
30}
31
32/// Representation of the fields in a DEX file. Only the decoded fields are present in the correct
33/// order.
34#[derive(Debug)]
35pub struct DexFields {
36 /// Vector of decoded field names
37 pub items: Vec<String>
38}
39
40impl DexFields {
41 /// Function to sort the field items in the order defined in the Dalvik documentation
42 fn sort(a: &FieldIdItem, b: &FieldIdItem) -> Ordering {
43 // First sort by defining type
44 let mut order = a.class_idx.cmp(&b.class_idx);
45
46 if order == Ordering::Equal {
47 // If that fails, sort by field name
48 order = a.name_idx.cmp(&b.name_idx);
49 }
50
51 if order == Ordering::Equal {
52 // If that fails too, sort by type
53 order = a.type_idx.cmp(&b.type_idx);
54 }
55
56 order
57 }
58
59 /// Parse the fields from the DEX file
60 ///
61 /// This function returns a vector of decoded field names in the correct order
62 pub fn build(dex_reader: &mut DexReader,
63 offset: u32,
64 size: u32,
65 types_list: &DexTypes,
66 strings_list: &DexStrings) -> Result<Self, DexError> {
67 dex_reader.bytes.seek(SeekFrom::Start(offset.into()))?;
68
69 let mut fields = Vec::new();
70
71 for _ in 0..size {
72 let class_idx = dex_reader.read_u16()?;
73 let type_idx = dex_reader.read_u16()?;
74 let name_idx = dex_reader.read_u32()?;
75
76 let mut decoded = String::new();
77 decoded.push_str(types_list.items.get(class_idx as usize).ok_or(DexError::InvalidTypeIdx)?);
78 decoded.push_str("->");
79 decoded.push_str(strings_list.strings.get(name_idx as usize).ok_or(DexError::InvalidStringIdx)?);
80 decoded.push(':');
81 decoded.push_str(types_list.items.get(type_idx as usize).ok_or(DexError::InvalidTypeIdx)?);
82
83 fields.push(FieldIdItem {
84 class_idx,
85 type_idx,
86 name_idx,
87 decoded
88 });
89 }
90
91 fields.sort_by(DexFields::sort);
92
93 let mut items = Vec::new();
94 for dex_field in fields.into_iter() {
95 items.push(dex_field.decoded);
96 }
97 items.dedup();
98
99 Ok(DexFields { items })
100 }
101}