1use 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#[derive(Debug)]
14struct ProtoIdItem {
15 shorty_idx: u32,
16 return_type_idx: u32,
17 parameters_off: u32,
18 parameters_off_list: Vec<u16>, proto: String,
20}
21
22#[derive(Debug)]
24pub struct DexProtos {
25 pub items: Vec<String>
26}
27
28impl DexProtos {
29 fn sort(a: &ProtoIdItem, b: &ProtoIdItem) -> Ordering {
31 let sort_return = a.return_type_idx.cmp(&b.return_type_idx);
33
34 if sort_return == Ordering::Equal {
35 return a.parameters_off_list.cmp(&b.parameters_off_list);
37 }
38
39 sort_return
40 }
41
42 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 let mut proto = String::new();
58 let mut parameters_off_list = Vec::new();
59 if parameters_off == 0 {
60 proto.push_str("()");
62 } else {
63 let current_pos = dex_reader.bytes.position();
65
66 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 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}