1#[macro_use]
2extern crate nom;
3
4extern crate mutf8;
5
6#[macro_use]
7mod parsing;
8
9pub mod ops;
10pub mod attr;
11
12use nom::*;
13pub use mutf8::{MString, mstr};
14pub use nom::Err as Err;
15
16use crate::ops::*;
17use crate::attr::Attribute;
18
19#[derive(Debug, Eq, PartialEq, Hash, Clone)]
20pub struct ClassFile<'a> {
21 pub minor_version: u16,
22 pub major_version: u16,
23 pub constant_pool: ConstantPool<'a>,
24 pub access_flags: u16,
25 pub this_class: CPIndex<'a, ClassInfo<'a>>,
26 pub super_class: CPIndex<'a, ClassInfo<'a>>,
27 pub interfaces: Vec<CPIndex<'a, ClassInfo<'a>>>,
28 pub fields: Vec<FieldInfo<'a>>,
29 pub methods: Vec<MethodInfo<'a>>,
30 pub attributes: Attributes<'a>,
31}
32
33impl<'a> ClassFile<'a> {
34 named!(pub parse<ClassFile>, do_parse!(
35 tag!([0xCA, 0xFE, 0xBA, 0xBE]) >>
36 minor_version: be_u16 >>
37 major_version: be_u16 >>
38 constant_pool: pt!(ConstantPool) >>
39 access_flags: be_u16 >>
40 this_class: pt!(CPIndex) >>
41 super_class: pt!(CPIndex) >>
42 interfaces: length_count!(be_u16, pt!(CPIndex)) >>
43 fields: length_count!(be_u16, pt!(FieldInfo)) >>
44 methods: length_count!(be_u16, pt!(MethodInfo)) >>
45 attributes: pt!(Attributes) >>
46 (ClassFile {
47 minor_version,
48 major_version,
49 constant_pool,
50 access_flags,
51 this_class,
52 super_class,
53 interfaces,
54 fields,
55 methods,
56 attributes,
57 })
58 ));
59}
60
61
62#[derive(Debug, Eq, PartialEq, Hash, Clone)]
63pub struct ConstantPool<'a> {
64 pub entries: Vec<CPEntry<'a>>,
65}
66
67impl<'a> ConstantPool<'a> {
68 named!(pub parse<ConstantPool>, do_parse!(
69 entries: length_count!(do_parse!(
70 count: be_u16 >>
71 (count - 1)
72 ), pt!(CPEntry)) >>
73 (ConstantPool {
74 entries,
75 })
76 ));
77
78 pub fn index<T: 'a + CPType<'a>>(&'a self, index: CPIndex<'a, T>) -> Option<T::Output> {
79 let entry = &self.entries[(index.index - 1) as usize];
80 T::fetch(entry)
81 }
82}
83
84#[derive(Debug, Eq, PartialEq, Hash, Clone)]
85pub enum CPEntry<'a> {
86 Class(ClassInfo<'a>),
87 FieldRef(FieldRefInfo<'a>),
88 MethodRef(MethodRefInfo<'a>),
89 InterfaceMethodRef(InterfaceMethodRefInfo<'a>),
90 String(StringInfo<'a>),
91 Integer(IntegerInfo),
92 Float(FloatInfo),
93 Long(LongInfo),
94 Double(DoubleInfo),
95 NameAndType(NameAndTypeInfo<'a>),
96 UTF8(UTF8Info<'a>),
97 MethodHandle(MethodHandleInfo<'a>),
98 MethodType(MethodTypeInfo<'a>),
99 Dynamic(DynamicInfo<'a>),
100 InvokeDynamic(InvokeDynamicInfo<'a>),
101 Module(ModuleInfo<'a>),
102 Package(PackageInfo<'a>),
103}
104
105macro_rules! def_fetch {
106 ($type:ident <$first:lifetime $(,$rest:lifetime)*> => $deconstruct:ident) => {
107 impl <$first $(,$rest)*> CPType<$first> for $type <$first $(,$rest)*> {
108 type Output = & $first Self;
109
110 #[inline]
111 fn fetch(entry: & $first CPEntry< $first >) -> Option<Self::Output> {
112 if let CPEntry::$deconstruct(info) = entry {
113 Some(info)
114 } else {
115 None
116 }
117 }
118 }
119 };
120 ($type:ident => $deconstruct:ident) => {
121 impl <'a> CPType<'a> for $type {
122 type Output = &'a Self;
123
124 #[inline]
125 fn fetch(entry: &'a CPEntry<'a>) -> Option<Self::Output> {
126 if let CPEntry::$deconstruct(info) = entry {
127 Some(info)
128 } else {
129 None
130 }
131 }
132 }
133 };
134}
135
136macro_rules! cp_entry {
137 (struct $type:ident $(<$first:lifetime $(,$rest:lifetime)*>)? {
138 $($field_name:ident: $field_type:ty = ($($field_parser:tt)*)),* $(,)?
139 } => $deconstruct:ident) => {
140 parser! {
141 struct $type $(<$first $(,$rest)*>)? {
142 $($field_name: $field_type = ($($field_parser)*)),*
143 }
144 }
145 def_fetch!($type $(<$first $(,$rest)*>)? => $deconstruct);
146 };
147 (enum $type:ident $(<$first:lifetime $(,$rest:lifetime)*>)? = ($ident:ident: $($tag_parser:tt)*) {
148 $(
149 $variant:ident ($($variant_tag:tt)*) {
150 $($field_name:ident: $field_type:ty = ($($field_parser:tt)*)),* $(,)?
151 }
152 ),* $(,)?
153 } => $deconstruct:ident) => {
154 parser! {
155 enum $type $(<$first $(,$rest)*>)? = ($ident: $($tag_parser)*) {
156 $(
157 $variant ($($variant_tag)*) {
158 $($field_name: $field_type = ($($field_parser)*)),*
159 }
160 ),*
161 }
162 }
163
164 def_fetch!($type $(<$first $(,$rest)*>)? => $deconstruct);
165 }
166}
167
168cp_entry! {
169 struct ClassInfo<'a> {
170 name_index: CPIndex<'a, UTF8Info<'a>> = (pt!(CPIndex))
171 } => Class
172}
173
174cp_entry! {
175 struct FieldRefInfo<'a> {
176 class_index: CPIndex<'a, ClassInfo<'a>> = (pt!(CPIndex)),
177 name_and_type_index: CPIndex<'a, NameAndTypeInfo<'a>> = (pt!(CPIndex))
178 } => FieldRef
179}
180
181cp_entry! {
182 struct MethodRefInfo<'a> {
183 class_index: CPIndex<'a, ClassInfo<'a>> = (pt!(CPIndex)),
184 name_and_type_index: CPIndex<'a, NameAndTypeInfo<'a>> = (pt!(CPIndex))
185 } => MethodRef
186}
187
188cp_entry! {
189 struct InterfaceMethodRefInfo<'a> {
190 class_index: CPIndex<'a, ClassInfo<'a>> = (pt!(CPIndex)),
191 name_and_type_index: CPIndex<'a, NameAndTypeInfo<'a>> = (pt!(CPIndex))
192 } => InterfaceMethodRef
193}
194
195cp_entry! {
196 struct StringInfo<'a> {
197 string_index: CPIndex<'a, UTF8Info<'a>> = (pt!(CPIndex))
198 } => String
199}
200
201cp_entry! {
202 struct IntegerInfo {
203 bytes: u32 = (be_u32),
204 } => Integer
205}
206
207cp_entry! {
208 struct FloatInfo {
209 bytes: u32 = (be_u32),
210 } => Float
211}
212
213cp_entry! {
214 struct LongInfo {
215 high_bytes: u32 = (be_u32),
216 low_bytes: u32 = (be_u32),
217 } => Long
218}
219
220cp_entry! {
221 struct DoubleInfo {
222 high_bytes: u32 = (be_u32),
223 low_bytes: u32 = (be_u32),
224 } => Double
225}
226
227cp_entry! {
228 struct NameAndTypeInfo<'a> {
229 name_index: CPIndex<'a, UTF8Info<'a>> = (pt!(CPIndex)),
230 descriptor_index: CPIndex<'a, UTF8Info<'a>> = (pt!(CPIndex))
231 } => NameAndType
232}
233
234cp_entry! {
235 struct UTF8Info<'a> {
236 data: &'a mstr = (do_parse!(
237 bytes: length_data!(be_u16) >>
238 (mstr::from_mutf8_unchecked(bytes))
239 )),
240 } => UTF8
241}
242
243cp_entry! {
244 enum MethodHandleInfo<'a> = (reference_kind: be_u8) {
245 FieldRef (1 | 2 | 3 | 4) {
246 reference_kind: u8 = (value!(reference_kind)),
247 reference_index: CPIndex<'a, FieldRefInfo<'a>> = (pt!(CPIndex)),
248 },
249 MethodRef (5 | 8 | 6 | 7) {
250 reference_kind: u8 = (value!(reference_kind)),
251 reference_index: CPIndex<'a, MethodRefInfo<'a>> = (pt!(CPIndex)),
252 },
253 InterfaceMethodRef (9) {
254 reference_kind: u8 = (value!(reference_kind)),
255 reference_index: CPIndex<'a, InterfaceMethodRefInfo<'a>> = (pt!(CPIndex)),
256 },
257 } => MethodHandle
258}
259
260cp_entry! {
261 struct MethodTypeInfo<'a> {
262 descriptor_index: CPIndex<'a, UTF8Info<'a>> = (pt!(CPIndex))
263 } => MethodType
264}
265
266cp_entry! {
267 struct DynamicInfo<'a> {
268 bootstrap_method_attr_index: u16 = (be_u16),
269 name_and_type_index: CPIndex<'a, NameAndTypeInfo<'a>> = (pt!(CPIndex))
270 } => Dynamic
271}
272
273cp_entry! {
274 struct InvokeDynamicInfo<'a> {
275 bootstrap_method_attr_index: u16 = (be_u16),
276 name_and_type_index: CPIndex<'a, NameAndTypeInfo<'a>> = (pt!(CPIndex))
277 } => InvokeDynamic
278}
279
280cp_entry! {
281 struct ModuleInfo<'a> {
282 name_index: CPIndex<'a, UTF8Info<'a>> = (pt!(CPIndex))
283 } => Module
284}
285
286cp_entry! {
287 struct PackageInfo<'a> {
288 name_index: CPIndex<'a, UTF8Info<'a>> = (pt!(CPIndex))
289 } => Package
290}
291
292impl CPEntry<'_> {
293 pub fn tag(&self) -> u8 {
294 match self {
295 CPEntry::Class(_) => CONSTANT_CLASS_TAG,
296 CPEntry::FieldRef(_) => CONSTANT_FIELDREF_TAG,
297 CPEntry::MethodRef(_) => CONSTANT_METHODREF_TAG,
298 CPEntry::InterfaceMethodRef(_) => CONSTANT_INTERFACE_METHODREF_TAG,
299 CPEntry::String(_) => CONSTANT_STRING_TAG,
300 CPEntry::Integer(_) => CONSTANT_INTEGER_TAG,
301 CPEntry::Float(_) => CONSTANT_FLOAT_TAG,
302 CPEntry::Long(_) => CONSTANT_LONG_TAG,
303 CPEntry::Double(_) => CONSTANT_DOUBLE_TAG,
304 CPEntry::NameAndType(_) => CONSTANT_NAME_AND_TYPE_TAG,
305 CPEntry::UTF8(_) => CONSTANT_UTF8_TAG,
306 CPEntry::MethodHandle(_) => CONSTANT_METHOD_HANDLE_TAG,
307 CPEntry::MethodType(_) => CONSTANT_METHOD_TYPE_TAG,
308 CPEntry::Dynamic(_) => CONSTANT_DYNAMIC_TAG,
309 CPEntry::InvokeDynamic(_) => CONSTANT_INVOKE_DYNAMIC_TAG,
310 CPEntry::Module(_) => CONSTANT_MODULE_TAG,
311 CPEntry::Package(_) => CONSTANT_PACKAGE_TAG,
312 }
313 }
314
315 named!(pub parse<CPEntry>, switch!(be_u8,
316 CONSTANT_CLASS_TAG => do_parse!(
317 info: pt!(ClassInfo) >>
318 (CPEntry::Class(info))
319 )
320 |
321 CONSTANT_FIELDREF_TAG => do_parse!(
322 info: pt!(FieldRefInfo) >>
323 (CPEntry::FieldRef(info))
324 )
325 |
326 CONSTANT_METHODREF_TAG => do_parse!(
327 info: pt!(MethodRefInfo) >>
328 (CPEntry::MethodRef(info))
329 )
330 |
331 CONSTANT_INTERFACE_METHODREF_TAG => do_parse!(
332 info: pt!(InterfaceMethodRefInfo) >>
333 (CPEntry::InterfaceMethodRef(info))
334 )
335 |
336 CONSTANT_STRING_TAG => do_parse!(
337 info: pt!(StringInfo) >>
338 (CPEntry::String(info))
339 )
340 |
341 CONSTANT_INTEGER_TAG => do_parse!(
342 info: pt!(IntegerInfo) >>
343 (CPEntry::Integer(info))
344 )
345 |
346 CONSTANT_FLOAT_TAG => do_parse!(
347 info: pt!(FloatInfo) >>
348 (CPEntry::Float(info))
349 )
350 |
351 CONSTANT_LONG_TAG => do_parse!(
352 info: pt!(LongInfo) >>
353 (CPEntry::Long(info))
354 )
355 |
356 CONSTANT_DOUBLE_TAG => do_parse!(
357 info: pt!(DoubleInfo) >>
358 (CPEntry::Double(info))
359 )
360 |
361 CONSTANT_NAME_AND_TYPE_TAG => do_parse!(
362 info: pt!(NameAndTypeInfo) >>
363 (CPEntry::NameAndType(info))
364 )
365 |
366 CONSTANT_UTF8_TAG => do_parse!(
367 info: pt!(UTF8Info) >>
368 (CPEntry::UTF8(info))
369 )
370 |
371 CONSTANT_METHOD_HANDLE_TAG => do_parse!(
372 info: pt!(MethodHandleInfo) >>
373 (CPEntry::MethodHandle(info))
374 )
375 |
376 CONSTANT_METHOD_TYPE_TAG => do_parse!(
377 info: pt!(MethodTypeInfo) >>
378 (CPEntry::MethodType(info))
379 )
380 |
381 CONSTANT_DYNAMIC_TAG => do_parse!(
382 info: pt!(DynamicInfo) >>
383 (CPEntry::Dynamic(info))
384 )
385 |
386 CONSTANT_INVOKE_DYNAMIC_TAG => do_parse!(
387 info: pt!(InvokeDynamicInfo) >>
388 (CPEntry::InvokeDynamic(info))
389 )
390 |
391 CONSTANT_MODULE_TAG => do_parse!(
392 info: pt!(ModuleInfo) >>
393 (CPEntry::Module(info))
394 )
395 |
396 CONSTANT_PACKAGE_TAG => do_parse!(
397 info: pt!(PackageInfo) >>
398 (CPEntry::Package(info))
399 )
400 ));
401}
402
403parser! {
404 struct FieldInfo<'a> {
405 access_flags : u16 = (be_u16),
406 name_index : CPIndex<'a, UTF8Info<'a>> = (pt!(CPIndex)),
407 descriptor_index : CPIndex<'a, UTF8Info<'a>> = (pt!(CPIndex)),
408 attributes : Attributes<'a> = (pt!(Attributes))
409 }
410}
411
412parser! {
413 struct MethodInfo<'a> {
414 access_flags : u16 = (be_u16),
415 name_index : CPIndex<'a, UTF8Info<'a>> = (pt!(CPIndex)),
416 descriptor_index : CPIndex<'a, UTF8Info<'a>> = (pt!(CPIndex)),
417 attributes : Attributes<'a> = (pt!(Attributes))
418 }
419}
420
421parser! {
422 struct Attributes<'a> {
423 attributes : Vec<AttributeInfo<'a>> = (length_count!(be_u16, pt!(AttributeInfo)))
424 }
425}
426
427impl<'a> Attributes<'a> {
428 pub fn iter(&self) -> impl Iterator<Item = &AttributeInfo<'a>> {
429 self.attributes.iter()
430 }
431
432 pub fn named(&self, cp: &ConstantPool<'a>, name: &str) -> Option<&AttributeInfo<'a>> {
433 for attr in &self.attributes {
434 let info = cp.index(attr.attribute_name_index).expect("Unable to locate attribute_name_index in constant pool");
435 if info.data.to_utf8() == name {
436 return Some(attr);
437 }
438 }
439 None
440 }
441
442 pub fn get<T: Attribute<'a>>(&self, cp: &ConstantPool<'a>) -> Option<T> {
443 T::from_attributes(self, cp)
444 }
445}
446
447impl<'a> IntoIterator for Attributes<'a> {
448 type Item = AttributeInfo<'a>;
449 type IntoIter = ::std::vec::IntoIter<AttributeInfo<'a>>;
450
451 fn into_iter(self) -> <Self as IntoIterator>::IntoIter {
452 self.attributes.into_iter()
453 }
454}
455
456parser! {
457 struct AttributeInfo<'a> {
458 attribute_name_index: CPIndex<'a, UTF8Info<'a>> = (pt!(CPIndex)),
459 info: &'a [u8] = (length_data!(be_u32))
460 }
461}
462
463pub trait CPType<'a> {
464 type Output;
465
466 fn fetch(entry: &'a CPEntry<'a>) -> Option<Self::Output>;
467}
468
469use std::marker::PhantomData;
470
471#[derive(Debug, Eq, PartialEq, Hash)]
472pub struct CPIndex<'a, T: 'a + CPType<'a>> {
473 pub index: u16,
474 _marker: PhantomData<&'a T>,
475}
476
477impl<'a, T: 'a + CPType<'a>> Clone for CPIndex<'a, T> {
478 fn clone(&self) -> Self {
479 *self
480 }
481}
482
483impl<'a, T: 'a + CPType<'a>> Copy for CPIndex<'a, T> {
484}
485
486impl<'a, T: 'a + CPType<'a>> CPIndex<'a, T> {
487 named!(pub parse<CPIndex<'a, T>>, do_parse!(
488 index: be_u16 >>
489 (CPIndex {
490 index,
491 _marker: PhantomData,
492 })
493 ));
494
495 named!(pub parse_non_zero<Option<CPIndex<'a, T>>>, do_parse!(
496 index: be_u16 >>
497 (
498 if index == 0 {
499 None
500 } else {
501 Some(CPIndex {
502 index,
503 _marker: PhantomData,
504 })
505 }
506 )
507 ));
508}