classfile_parser/
parser.rs

1use nom::*;
2
3use attribute_info::attribute_parser;
4use constant_info::constant_parser;
5use field_info::field_parser;
6use method_info::method_parser;
7use nom::bytes::complete::tag;
8use nom::multi::count;
9use types::{ClassAccessFlags, ClassFile};
10
11fn magic_parser(input: &[u8]) -> IResult<&[u8], &[u8]> {
12    tag(&[0xCA, 0xFE, 0xBA, 0xBE])(input)
13}
14
15/// Parse a byte array into a ClassFile. This will probably be deprecated in 0.4.0 in as it returns
16/// a nom IResult type, which exposes the internal parsing library and not a good idea.
17///
18/// If you want to call it directly, as it is the only way to parse a byte slice directly, you must
19/// unwrap the result yourself.
20///
21/// ```rust
22/// let classfile_bytes = include_bytes!("../java-assets/compiled-classes/BasicClass.class");
23///
24/// match classfile_parser::class_parser(classfile_bytes) {
25///     Ok((_, class_file)) => {
26///         println!("version {},{}", class_file.major_version, class_file.minor_version);
27///     }
28///     Err(_) => panic!("Failed to parse"),
29/// };
30/// ```
31pub fn class_parser(input: &[u8]) -> IResult<&[u8], ClassFile> {
32    use nom::number::complete::be_u16;
33    let (input, _) = magic_parser(input)?;
34    let (input, minor_version) = be_u16(input)?;
35    let (input, major_version) = be_u16(input)?;
36    let (input, const_pool_size) = be_u16(input)?;
37    let (input, const_pool) = constant_parser(input, (const_pool_size - 1) as usize)?;
38    let (input, access_flags) = be_u16(input)?;
39    let (input, this_class) = be_u16(input)?;
40    let (input, super_class) = be_u16(input)?;
41    let (input, interfaces_count) = be_u16(input)?;
42    let (input, interfaces) = count(be_u16, interfaces_count as usize)(input)?;
43    let (input, fields_count) = be_u16(input)?;
44    let (input, fields) = count(field_parser, fields_count as usize)(input)?;
45    let (input, methods_count) = be_u16(input)?;
46    let (input, methods) = count(method_parser, methods_count as usize)(input)?;
47    let (input, attributes_count) = be_u16(input)?;
48    let (input, attributes) = count(attribute_parser, attributes_count as usize)(input)?;
49    Ok((
50        input,
51        ClassFile {
52            minor_version,
53            major_version,
54            const_pool_size,
55            const_pool,
56            access_flags: ClassAccessFlags::from_bits_truncate(access_flags),
57            this_class,
58            super_class,
59            interfaces_count,
60            interfaces,
61            fields_count,
62            fields,
63            methods_count,
64            methods,
65            attributes_count,
66            attributes,
67        },
68    ))
69}