pclass_parser/classfile/
constant_pool.rs

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}