rusty_dex/dex/
protos.rs

1//! Representation of method prototypes
2//!
3//! This module contains the logic to decode method prototypes from a DEX file.
4
5use std::io::{Seek, SeekFrom};
6use std::cmp::Ordering;
7
8use crate::dex::reader::DexReader;
9use crate::dex::types::DexTypes;
10use crate::error::DexError;
11
12/// Internal representation of a prototype index
13#[derive(Debug)]
14struct ProtoIdItem {
15    shorty_idx: u32,
16    return_type_idx: u32,
17    parameters_off: u32,
18    parameters_off_list: Vec<u16>,  // used to sort items
19    proto: String,
20}
21
22/// List of decoded prototypes in the DEX files
23#[derive(Debug)]
24pub struct DexProtos {
25    pub items: Vec<String>
26}
27
28impl DexProtos {
29    /// Sorting method for prototypes
30    fn sort(a: &ProtoIdItem, b: &ProtoIdItem) -> Ordering {
31        // First sort by return type
32        let sort_return = a.return_type_idx.cmp(&b.return_type_idx);
33
34        if sort_return == Ordering::Equal {
35            // Same return type, sort by params offsets
36            return a.parameters_off_list.cmp(&b.parameters_off_list);
37        }
38
39        sort_return
40    }
41
42    /// Parse the prototypes from the reader
43    pub fn build(dex_reader: &mut DexReader,
44                 offset: u32,
45                 size: u32,
46                 types_list: &DexTypes) -> Result<Self, DexError> {
47        dex_reader.bytes.seek(SeekFrom::Start(offset.into()))?;
48
49        let mut protos = Vec::new();
50
51        for _ in 0..size {
52            let shorty_idx = dex_reader.read_u32()?;
53            let return_type_idx = dex_reader.read_u32()?;
54            let parameters_off = dex_reader.read_u32()?;
55
56            // Decode the prototype
57            let mut proto = String::new();
58            let mut parameters_off_list = Vec::new();
59            if parameters_off == 0 {
60                // No parameters in this prototype
61                proto.push_str("()");
62            } else {
63                // Save current stream position
64                let current_pos = dex_reader.bytes.position();
65
66                // Decode the parameters
67                dex_reader.bytes.seek(SeekFrom::Start(parameters_off.into()))?;
68
69                proto.push('(');
70                let params_size = dex_reader.read_u32()?;
71                for idx in 0..params_size {
72                    let offset = dex_reader.read_u16()?;
73                    parameters_off_list.push(offset);
74
75                    proto.push_str(types_list.items.get(offset as usize).ok_or(DexError::InvalidTypeIdx)?);
76                    if idx < params_size - 1 {
77                        proto.push(' ');
78                    }
79                }
80                proto.push(')');
81
82                // Go back to the previous position
83                dex_reader.bytes.seek(SeekFrom::Start(current_pos))?;
84            }
85            proto.push_str(types_list.items.get(return_type_idx as usize).ok_or(DexError::InvalidTypeIdx)?);
86
87            protos.push(ProtoIdItem {
88                shorty_idx,
89                return_type_idx,
90                parameters_off,
91                parameters_off_list,
92                proto
93            });
94        }
95
96
97        protos.sort_by(DexProtos::sort);
98
99        let mut items = Vec::new();
100        for dex_proto in protos.into_iter() {
101            items.push(dex_proto.proto);
102        }
103        items.dedup();
104
105        Ok(DexProtos { items })
106    }
107}