class_file/
lib.rs

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}