1use getset::Getters;
2use scroll::Uleb128;
3use tracing::debug;
4
5use crate::error;
6use crate::region::Region;
7use crate::string::ABCString;
8use crate::uint16_t;
9use crate::uint32_t;
10use crate::uint8_t;
11
12use scroll::ctx;
13use scroll::Pread;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16enum MethodAccessFlags {
17 Public = 0x0001,
18 Private = 0x0002,
19 Protected = 0x0004,
20 Static = 0x0008,
21 Final = 0x0010,
22 Synchronized = 0x0020,
23 Bridge = 0x0040,
24 Varargs = 0x0080,
25 Native = 0x0100,
26 Abstract = 0x0400,
27 Strict = 0x0800,
28 Synthetic = 0x1000,
29}
30
31impl MethodAccessFlags {
32 pub fn parse(value: u64) -> Vec<String> {
33 let mut access_flags: Vec<String> = Vec::new();
34
35 let flags = [
36 MethodAccessFlags::Public,
37 MethodAccessFlags::Private,
38 MethodAccessFlags::Protected,
39 MethodAccessFlags::Static,
40 MethodAccessFlags::Final,
41 MethodAccessFlags::Synchronized,
42 MethodAccessFlags::Bridge,
43 MethodAccessFlags::Varargs,
44 MethodAccessFlags::Native,
45 MethodAccessFlags::Abstract,
46 MethodAccessFlags::Strict,
47 MethodAccessFlags::Synthetic,
48 ]
49 .to_vec();
50
51 for flag in flags {
52 let x = flag as u64;
53 if value & x != 0 {
54 access_flags.push(format!("{:?}", flag));
55 }
56 }
57
58 access_flags
59 }
60}
61
62#[derive(Debug, Getters, Default)]
63#[get = "pub"]
64pub struct MethodData {
65 code_off: uint32_t,
67 source_lang: uint8_t,
68 runtime_annotation_off: uint32_t,
69 runtime_param_annotation_off: uint32_t,
70 debug_info_off: uint32_t,
71 annotation_off: uint32_t,
72 param_annotation_off: uint32_t,
73 type_annotation_off: uint32_t,
74 runtime_type_annotation_off: uint32_t,
75}
76
77#[derive(Debug, Getters, Default)]
78#[get = "pub"]
79pub struct Method {
80 class_idx: uint16_t,
82 proto_idx: uint16_t,
83 name_off: uint32_t,
85
86 access_flags: Vec<String>,
88 size: usize,
90 method_data: MethodData,
91}
92
93impl Method {}
94
95pub fn get_method_sign(source: &[u8], offset: usize, region: &Region) -> String {
97 let mut name = String::new();
98 let mut off = offset;
99 let class_idx = source.pread::<uint16_t>(off).unwrap();
100 off += 2;
101 let class_name = region.get_class_name(class_idx as usize).to_string();
102 name += &class_name;
103 name += "->";
104
105 let _proto_idx = source.pread::<uint16_t>(off).unwrap();
107 off += 2;
108
109 let name_idx = source.pread::<uint32_t>(off).unwrap();
110 let method_name = source
111 .pread::<ABCString>(name_idx as usize)
112 .unwrap()
113 .to_string();
114
115 name += &method_name;
116
117 name
118}
119
120impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Method {
121 type Error = error::Error;
122 fn try_from_ctx(source: &'a [u8], _: scroll::Endian) -> Result<(Self, usize), Self::Error> {
123 let class_idx = source.pread::<uint16_t>(0).unwrap();
124 let proto_idx = source.pread::<uint16_t>(2).unwrap();
125 let name_off = source.pread::<uint32_t>(4).unwrap();
126
127 let off = &mut 8;
128 let access_flags = Uleb128::read(source, off).unwrap();
129 let access_flags = MethodAccessFlags::parse(access_flags);
130
131 let mut method_data = MethodData::default();
134 'l: loop {
136 let tag_value = source.pread::<u8>(*off).unwrap();
137 *off += 1;
138
139 match tag_value {
140 0x00 => {
141 tracing::debug!("NOTHING");
142 break 'l;
143 }
144 0x01 => {
145 let code_off = source.pread::<uint32_t>(*off).unwrap();
146 *off += 4;
147 method_data.code_off = code_off;
148 debug!("CODE {:?}", code_off);
149 }
150 0x02 => {
151 let data = source.pread::<u8>(*off).unwrap();
152 *off += 1;
153 method_data.source_lang = data;
154 debug!("SOURCE_LANG {:?}", data);
155 }
156 0x03 => {
157 let data = source.pread::<uint32_t>(*off).unwrap();
158 *off += 4;
159 method_data.runtime_annotation_off = data;
160 debug!("RUNTIME_ANNOTATION {:?}", data);
161 }
162 0x04 => {
163 let data = source.pread::<uint32_t>(*off).unwrap();
164 *off += 4;
165 method_data.runtime_param_annotation_off = data;
166 debug!("RUNTIME_PARAM_ANNOTATION {:?}", data);
167 }
168 0x05 => {
169 let data = source.pread::<uint32_t>(*off).unwrap();
170 *off += 4;
171 method_data.debug_info_off = data;
172 debug!("DEBUG_INFO {:?}", data);
173 }
174 0x06 => {
175 let data = source.pread::<uint32_t>(*off).unwrap();
176 *off += 4;
177 method_data.annotation_off = data;
178 debug!("ANNOTATION {:?}", data);
179 }
180 0x07 => {
181 let data = source.pread::<uint32_t>(*off).unwrap();
182 *off += 4;
183 method_data.param_annotation_off = data;
184 debug!("PARAM_ANNOTATION {:?}", data);
185 }
186 0x08 => {
187 let data = source.pread::<uint32_t>(*off).unwrap();
188 *off += 4;
189 method_data.type_annotation_off = data;
190 debug!("TYPE_ANNOTATION {:?}", data);
191 }
192 0x09 => {
193 let data = source.pread::<uint32_t>(*off).unwrap();
194 *off += 4;
195 method_data.runtime_type_annotation_off = data;
196 debug!("RUNTIME_TYPE_ANNOTATION {:?}", data);
197 }
198 _ => {
199 tracing::error!("Method Data: UNKNOWN 0x{:02X}", tag_value);
201 }
202 }
203 }
204
205 let size = *off;
206
207 Ok((
208 Method {
209 class_idx,
210 proto_idx,
211 name_off,
212 access_flags,
213 method_data,
214 size,
215 },
216 source.len(),
217 ))
218 }
219}