1use crate::classfile::consts::{
2 CONSTANT_INTERFACE_METHOD_REF_TAG, CONSTANT_METHOD_REF_TAG, METHOD_NAME_CLINIT,
3 METHOD_NAME_INIT,
4};
5use fmt::Debug;
6use std::fmt;
7use std::sync::Arc;
8use crate::{ConstantPool, BytesRef};
9
10pub fn get_class_name(cp: &ConstantPool, idx: usize) -> Option<BytesRef> {
11 match cp.get(idx) {
12 Some(Type::Class { name_index }) => get_utf8(cp, *name_index as usize),
13 _ => None,
14 }
15}
16
17pub fn get_field_ref(cp: &ConstantPool, idx: usize) -> (u16, u16) {
18 match cp.get(idx) {
19 Some(Type::FieldRef {
20 class_index,
21 name_and_type_index,
22 }) => (*class_index, *name_and_type_index),
23 _ => unreachable!(),
24 }
25}
26
27pub fn get_method_ref(cp: &ConstantPool, idx: usize) -> (u8, u16, u16) {
28 match cp.get(idx) {
29 Some(Type::MethodRef {
30 class_index,
31 name_and_type_index,
32 }) => (CONSTANT_METHOD_REF_TAG, *class_index, *name_and_type_index),
33 Some(Type::InterfaceMethodRef {
34 class_index,
35 name_and_type_index,
36 }) => (
37 CONSTANT_INTERFACE_METHOD_REF_TAG,
38 *class_index,
39 *name_and_type_index,
40 ),
41 _ => unreachable!(),
42 }
43}
44
45pub fn get_name_and_type(cp: &ConstantPool, idx: usize) -> (Option<BytesRef>, Option<BytesRef>) {
46 match cp.get(idx) {
47 Some(Type::NameAndType {
48 name_index,
49 desc_index,
50 }) => (
51 get_utf8(cp, *name_index as usize),
52 get_utf8(cp, *desc_index as usize),
53 ),
54 _ => (None, None),
55 }
56}
57
58pub fn get_utf8(cp: &ConstantPool, idx: usize) -> Option<BytesRef> {
59 match cp.get(idx) {
60 Some(Type::Utf8 { bytes }) => Some(bytes.clone()),
61 _ => None,
62 }
63}
64
65pub fn get_string(cp: &ConstantPool, idx: usize) -> Option<String> {
66 match cp.get(idx) {
67 Some(Type::String { string_index }) => {
68 let v = get_utf8(cp, *string_index as usize).unwrap();
69 let raw = construct_string_raw(v.as_slice());
70 Some(String::from_utf16_lossy(raw.as_slice()))
71 }
72 _ => None,
73 }
74}
75
76pub fn construct_string_raw(bs: &[u8]) -> Vec<u16> {
77 let length = bs.len();
78 let mut buffer: Vec<u16> = Vec::with_capacity(length);
79 let mut pos = 0;
80 while pos < length {
81 if bs[pos] & 0x80 == 0 {
82 let v = bs[pos] as u16;
83 buffer.push(v);
84 pos += 1;
85 } else if bs[pos] & 0xE0 == 0xC0 && (bs[pos + 1] & 0xC0) == 0x80 {
86 let x = bs[pos] as u16;
87 let y = bs[pos + 1] as u16;
88 let v = ((x & 0x1f) << 6) + (y & 0x3f);
89 buffer.push(v);
90 pos += 2;
91 } else if bs[pos] & 0xF0 == 0xE0
92 && (bs[pos + 1] & 0xC0) == 0x80
93 && (bs[pos + 2] & 0xC0) == 0x80
94 {
95 let x = bs[pos] as u16;
96 let y = bs[pos + 1] as u16;
97 let z = bs[pos + 2] as u16;
98 let v = ((x & 0xf) << 12) + ((y & 0x3f) << 6) + (z & 0x3f);
99 buffer.push(v);
100 pos += 3;
101 } else if bs[pos] == 0xED
102 && (bs[pos + 1] & 0xF0 == 0xA0)
103 && (bs[pos + 2] & 0xC0 == 0x80)
104 && (bs[pos + 3] == 0xED)
105 && (bs[pos + 4] & 0xF0 == 0xB0)
106 && (bs[pos + 5] & 0xC0 == 0x80)
107 {
108 let v = bs[pos + 1] as u32;
109 let w = bs[pos + 2] as u32;
110 let y = bs[pos + 4] as u32;
111 let z = bs[pos + 5] as u32;
112 let vv =
113 0x10000 + ((v & 0x0f) << 16) + ((w & 0x3f) << 10) + ((y & 0x0f) << 6) + (z & 0x3f);
114 buffer.push(vv as u16);
115
116 pos += 6;
117 } else {
118 unreachable!()
119 }
120 }
121
122 buffer
123}
124
125#[derive(Debug, Clone)]
126pub enum Type {
127 Nop,
128 Class {
129 name_index: u16,
130 },
131 FieldRef {
132 class_index: u16,
133 name_and_type_index: u16,
134 },
135 MethodRef {
136 class_index: u16,
137 name_and_type_index: u16,
138 },
139 InterfaceMethodRef {
140 class_index: u16,
141 name_and_type_index: u16,
142 },
143 String {
144 string_index: u16,
145 },
146 Integer {
147 v: [u8; 4],
148 },
149 Float {
150 v: [u8; 4],
151 },
152 Long {
153 v: [u8; 8],
154 },
155 Double {
156 v: [u8; 8],
157 },
158 NameAndType {
159 name_index: u16,
160 desc_index: u16,
161 },
162 Utf8 {
163 bytes: BytesRef,
164 },
165 MethodHandle {
166 ref_kind: u8,
167 ref_index: u16,
168 },
169 MethodType {
170 desc_index: u16,
171 },
172 InvokeDynamic {
173 bootstrap_method_attr_index: u16,
174 name_and_type_index: u16,
175 },
176 Unknown,
177}
178
179#[derive(Debug, Clone, Copy)]
180pub enum Tag {
181 Class,
182 FieldRef,
183 MethodRef,
184 InterfaceMethodRef,
185 String,
186 Integer,
187 Float,
188 Long,
189 Double,
190 NameAndType,
191 Utf8,
192 MethodHandle,
193 MethodType,
194 InvokeDynamic,
195}
196
197impl From<u8> for Tag {
198 fn from(tag: u8) -> Self {
199 match tag {
200 7 => Tag::Class,
201 9 => Tag::FieldRef,
202 10 => Tag::MethodRef,
203 11 => Tag::InterfaceMethodRef,
204 8 => Tag::String,
205 3 => Tag::Integer,
206 4 => Tag::Float,
207 5 => Tag::Long,
208 6 => Tag::Double,
209 12 => Tag::NameAndType,
210 1 => Tag::Utf8,
211 15 => Tag::MethodHandle,
212 16 => Tag::MethodType,
213 18 => Tag::InvokeDynamic,
214 _ => unreachable!(),
215 }
216 }
217}
218
219impl Type {
220 pub fn as_cp_item<'a, 'b>(&'a self, cp: &'b ConstantPool) -> ConstantPoolItem<'a, 'b> {
221 ConstantPoolItem { cp, item: self }
222 }
223}
224
225pub struct ConstantPoolItem<'item, 'cp> {
226 cp: &'cp ConstantPool,
227 item: &'item Type,
228}
229
230impl Debug for ConstantPoolItem<'_, '_> {
231 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232 match self.item {
233 Type::Nop => f.debug_struct("Nop").finish(),
234 Type::Class { name_index } => f
235 .debug_struct("Class")
236 .field("name_index", name_index)
237 .field(
238 "name",
239 &self
240 .cp
241 .get(*name_index as usize)
242 .map(|t| t.as_cp_item(self.cp)),
243 )
244 .finish(),
245 Type::Utf8 { bytes } => f
246 .debug_struct("Utf8")
247 .field("string", &std::str::from_utf8(bytes))
248 .finish(),
249 _ => write!(f, "TODO debug for: {:?}", self.item),
250 }
251 }
252}