rusty_dex/dex/
methods.rs

1//! Methods identifiers
2//!
3//! This module deals with method identifiers. Each DEX file contains a list
4//! of identifiers for all methods reffered to in the code. The list is sorted
5//! by the defining type (by `type_id` index), method name (by `string_id`
6//! index), and method prototype (by `proto_id` index), and cannot contain
7//! duplicates.
8
9use std::io::{Seek, SeekFrom};
10use std::cmp::Ordering;
11
12use crate::dex::reader::DexReader;
13use crate::dex::types::DexTypes;
14use crate::dex::protos::DexProtos;
15use crate::dex::strings::DexStrings;
16
17/// Identifier of a method
18#[derive(Debug)]
19struct MethodIdItem {
20    class_idx: u16,
21    proto_idx: u16,
22    name_idx: u32,
23    decoded: String
24}
25
26/// Sorted list of method IDs
27#[derive(Debug)]
28pub struct DexMethods {
29    pub items: Vec<String>
30}
31
32impl DexMethods {
33    /// Implement correct sorting method for method identifiers
34    fn sort(a: &MethodIdItem, b: &MethodIdItem) -> Ordering {
35        // First sort by defining type
36        let mut order = a.class_idx.cmp(&b.class_idx);
37
38        if order == Ordering::Equal {
39            // If that fails, sort by method name
40            order = a.name_idx.cmp(&b.name_idx);
41        }
42
43        if order == Ordering::Equal {
44            // If that fails too, sort by prototype
45            order = a.proto_idx.cmp(&b.proto_idx);
46        }
47
48        order
49    }
50
51    /// Build the list of method identifiers from a file
52    pub fn build(dex_reader: &mut DexReader,
53                 offset: u32,
54                 size: u32,
55                 types_list: &DexTypes,
56                 protos_list: &DexProtos,
57                 strings_list: &DexStrings) -> Self {
58        dex_reader.bytes.seek(SeekFrom::Start(offset.into())).unwrap();
59
60        let mut methods = Vec::new();
61
62        for _ in 0..size {
63            let class_idx = dex_reader.read_u16().unwrap();
64            let proto_idx = dex_reader.read_u16().unwrap();
65            let name_idx = dex_reader.read_u32().unwrap();
66
67            let mut decoded = String::new();
68            decoded.push_str(types_list.items.get(class_idx as usize).unwrap());
69            decoded.push_str("->");
70            decoded.push_str(&strings_list.strings.get(name_idx as usize).unwrap());
71            decoded.push_str(protos_list.items.get(proto_idx as usize).unwrap());
72
73            methods.push(MethodIdItem {
74                class_idx,
75                proto_idx,
76                name_idx,
77                decoded
78            });
79        }
80
81        methods.sort_by(DexMethods::sort);
82
83        let mut items = Vec::new();
84        for dex_method in methods.into_iter() {
85            items.push(dex_method.decoded);
86        }
87        items.dedup();
88
89        DexMethods { items }
90    }
91}