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}