1use std::collections::HashMap;
2
3use crate::field::Field;
4use crate::method::Method;
5
6use crate::{error, string::ABCString, uint32_t};
7use getset::Getters;
8use scroll::ctx;
9use scroll::Pread;
10use scroll::Uleb128;
11use tracing::debug;
12
13#[derive(Debug, Getters)]
14#[get = "pub"]
15pub struct ForeignClass {
16 name: ABCString,
17}
18
19impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for ForeignClass {
20 type Error = error::Error;
21 fn try_from_ctx(source: &'a [u8], _: scroll::Endian) -> Result<(Self, usize), Self::Error> {
22 let name = source.pread::<ABCString>(0).unwrap();
23
24 Ok((ForeignClass { name }, source.len()))
25 }
26}
27
28#[derive(Debug, Getters)]
29#[get = "pub"]
30pub struct Class {
31 offset: usize,
32 #[get = "pub"]
34 name: ABCString,
35 supper_class: String,
36 access_flags: Vec<String>,
38 num_fields: u64,
39 num_methods: u64,
40 fields: Vec<Field>,
42 method_map: HashMap<usize, Method>,
44}
45
46impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Class {
47 type Error = error::Error;
48 fn try_from_ctx(source: &'a [u8], _: scroll::Endian) -> Result<(Self, usize), Self::Error> {
49 let mut off = 0;
50 let name = source.pread::<ABCString>(0).unwrap();
51 off += name.length();
52
53 let supper_class_off = source.pread::<uint32_t>(off).unwrap();
54 let mut supper_class = String::new();
55 if supper_class_off != 0 {
56 let str = source
57 .pread::<ABCString>(supper_class_off as usize)
58 .unwrap();
59 supper_class = str.str();
60 }
61 off += 4;
62
63 let off = &mut off;
64 let access_flags = Uleb128::read(source, off).unwrap();
65 let access_flags = ClassAccessFlags::parse(access_flags);
66 let num_fields = Uleb128::read(source, off).unwrap();
67 let num_methods = Uleb128::read(source, off).unwrap();
68
69 'l: loop {
72 let tag_value = source.pread::<u8>(*off).unwrap();
73 *off += 1;
74 match tag_value {
75 0x00 => {
76 debug!("NOTHING: exit");
77 break 'l;
78 }
79 0x01 => {
80 debug!("INTERFACES");
81 }
82 0x02 => {
83 let data = source.pread::<u8>(*off).unwrap();
84 *off += 1;
85 debug!("SOURCE_LANG -> {}", data);
86 }
87 0x03 => {
88 debug!("RUNTIME_ANNOTATION");
89 }
90 0x04 => {
91 debug!("ANNOTATION");
92 }
93 0x05 => {
94 debug!("RUNTIME_TYPE_ANNOTATION");
95 }
96 0x06 => {
97 debug!("TYPE_ANNOTATION");
98 }
99 0x07 => {
100 debug!("SOURCE_FILE");
101 }
102 _ => {
103 tracing::error!("Error! -> UNKNOWN: {}", tag_value);
104 break 'l;
105 }
106 }
107 }
108
109 let mut offset = *off;
110 let mut fields = Vec::new();
111 for _ in 0..num_fields {
112 let field = source.pread::<Field>(offset).unwrap();
113 let size = *field.size();
114 offset += size;
115 fields.push(field);
116 }
117
118 let mut method_map = HashMap::new();
120 for _ in 0..num_methods {
121 let method = source.pread::<Method>(offset).unwrap();
123
124 let size = *method.size();
125 offset += size;
126
127 method_map.insert(offset, method);
128 }
130
131 Ok((
132 Class {
133 offset,
134 name,
135 supper_class,
136 access_flags,
137 num_fields,
138 num_methods,
139 fields,
140 method_map,
142 },
143 source.len(),
144 ))
145 }
146}
147
148impl Class {
149 pub fn has_method(&self, offset: usize) -> bool {
150 self.method_map.contains_key(&offset)
151 }
152
153 pub fn get_method(&self, offset: usize) -> Option<&Method> {
154 self.method_map.get(&offset)
155 }
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
159enum ClassAccessFlags {
160 Public = 0x0001,
161 Final = 0x0010,
162 Super = 0x0020,
163 Interface = 0x0200,
164 Abstract = 0x0400,
165 Synthetic = 0x1000,
166 Annotation = 0x2000,
167 Enum = 0x4000,
168}
169
170impl ClassAccessFlags {
171 pub fn parse(value: u64) -> Vec<String> {
172 let mut access_flags: Vec<String> = Vec::new();
173
174 let flags = [
175 ClassAccessFlags::Public,
176 ClassAccessFlags::Final,
177 ClassAccessFlags::Super,
178 ClassAccessFlags::Interface,
179 ClassAccessFlags::Abstract,
180 ClassAccessFlags::Synthetic,
181 ClassAccessFlags::Annotation,
182 ClassAccessFlags::Enum,
183 ]
184 .to_vec();
185
186 for flag in flags {
187 let x = flag as u64;
188 if value & x != 0 {
189 access_flags.push(format!("{:?}", flag));
191 }
192 }
193
194 access_flags
195 }
196}