classfile_parser/constant_info/
parser.rs

1use nom::{
2    bytes::complete::take,
3    combinator::map,
4    error::{Error, ErrorKind},
5    number::complete::{be_f32, be_f64, be_i32, be_i64, be_u16, be_u8},
6    Err,
7};
8
9use constant_info::*;
10
11fn utf8_constant(input: &[u8]) -> Utf8Constant {
12    let utf8_string =
13        cesu8::from_java_cesu8(input).unwrap_or_else(|_| String::from_utf8_lossy(input));
14    Utf8Constant {
15        utf8_string: utf8_string.to_string(),
16        bytes: input.to_owned(),
17    }
18}
19
20fn const_utf8(input: &[u8]) -> ConstantInfoResult {
21    let (input, length) = be_u16(input)?;
22    let (input, constant) = map(take(length), utf8_constant)(input)?;
23    Ok((input, ConstantInfo::Utf8(constant)))
24}
25
26fn const_integer(input: &[u8]) -> ConstantInfoResult {
27    let (input, value) = be_i32(input)?;
28    Ok((input, ConstantInfo::Integer(IntegerConstant { value })))
29}
30
31fn const_float(input: &[u8]) -> ConstantInfoResult {
32    let (input, value) = be_f32(input)?;
33    Ok((input, ConstantInfo::Float(FloatConstant { value })))
34}
35
36fn const_long(input: &[u8]) -> ConstantInfoResult {
37    let (input, value) = be_i64(input)?;
38    Ok((input, ConstantInfo::Long(LongConstant { value })))
39}
40
41fn const_double(input: &[u8]) -> ConstantInfoResult {
42    let (input, value) = be_f64(input)?;
43    Ok((input, ConstantInfo::Double(DoubleConstant { value })))
44}
45
46fn const_class(input: &[u8]) -> ConstantInfoResult {
47    let (input, name_index) = be_u16(input)?;
48    Ok((input, ConstantInfo::Class(ClassConstant { name_index })))
49}
50
51fn const_string(input: &[u8]) -> ConstantInfoResult {
52    let (input, string_index) = be_u16(input)?;
53    Ok((input, ConstantInfo::String(StringConstant { string_index })))
54}
55
56fn const_field_ref(input: &[u8]) -> ConstantInfoResult {
57    let (input, class_index) = be_u16(input)?;
58    let (input, name_and_type_index) = be_u16(input)?;
59    Ok((
60        input,
61        ConstantInfo::FieldRef(FieldRefConstant {
62            class_index,
63            name_and_type_index,
64        }),
65    ))
66}
67
68fn const_method_ref(input: &[u8]) -> ConstantInfoResult {
69    let (input, class_index) = be_u16(input)?;
70    let (input, name_and_type_index) = be_u16(input)?;
71    Ok((
72        input,
73        ConstantInfo::MethodRef(MethodRefConstant {
74            class_index,
75            name_and_type_index,
76        }),
77    ))
78}
79
80fn const_interface_method_ref(input: &[u8]) -> ConstantInfoResult {
81    let (input, class_index) = be_u16(input)?;
82    let (input, name_and_type_index) = be_u16(input)?;
83    Ok((
84        input,
85        ConstantInfo::InterfaceMethodRef(InterfaceMethodRefConstant {
86            class_index,
87            name_and_type_index,
88        }),
89    ))
90}
91
92fn const_name_and_type(input: &[u8]) -> ConstantInfoResult {
93    let (input, name_index) = be_u16(input)?;
94    let (input, descriptor_index) = be_u16(input)?;
95    Ok((
96        input,
97        ConstantInfo::NameAndType(NameAndTypeConstant {
98            name_index,
99            descriptor_index,
100        }),
101    ))
102}
103
104fn const_method_handle(input: &[u8]) -> ConstantInfoResult {
105    let (input, reference_kind) = be_u8(input)?;
106    let (input, reference_index) = be_u16(input)?;
107    Ok((
108        input,
109        ConstantInfo::MethodHandle(MethodHandleConstant {
110            reference_kind,
111            reference_index,
112        }),
113    ))
114}
115
116fn const_method_type(input: &[u8]) -> ConstantInfoResult {
117    let (input, descriptor_index) = be_u16(input)?;
118    Ok((
119        input,
120        ConstantInfo::MethodType(MethodTypeConstant { descriptor_index }),
121    ))
122}
123
124fn const_invoke_dynamic(input: &[u8]) -> ConstantInfoResult {
125    let (input, bootstrap_method_attr_index) = be_u16(input)?;
126    let (input, name_and_type_index) = be_u16(input)?;
127    Ok((
128        input,
129        ConstantInfo::InvokeDynamic(InvokeDynamicConstant {
130            bootstrap_method_attr_index,
131            name_and_type_index,
132        }),
133    ))
134}
135
136type ConstantInfoResult<'a> = Result<(&'a [u8], ConstantInfo), Err<Error<&'a [u8]>>>;
137type ConstantInfoVecResult<'a> = Result<(&'a [u8], Vec<ConstantInfo>), Err<Error<&'a [u8]>>>;
138
139fn const_block_parser(input: &[u8], const_type: u8) -> ConstantInfoResult {
140    match const_type {
141        1 => const_utf8(input),
142        3 => const_integer(input),
143        4 => const_float(input),
144        5 => const_long(input),
145        6 => const_double(input),
146        7 => const_class(input),
147        8 => const_string(input),
148        9 => const_field_ref(input),
149        10 => const_method_ref(input),
150        11 => const_interface_method_ref(input),
151        12 => const_name_and_type(input),
152        15 => const_method_handle(input),
153        16 => const_method_type(input),
154        18 => const_invoke_dynamic(input),
155        _ => Result::Err(Err::Error(error_position!(input, ErrorKind::Alt))),
156    }
157}
158
159fn single_constant_parser(input: &[u8]) -> ConstantInfoResult {
160    let (input, const_type) = be_u8(input)?;
161    let (input, const_block) = const_block_parser(input, const_type)?;
162    Ok((input, const_block))
163}
164
165pub fn constant_parser(i: &[u8], const_pool_size: usize) -> ConstantInfoVecResult {
166    let mut index = 0;
167    let mut input = i;
168    let mut res = Vec::with_capacity(const_pool_size);
169    while index < const_pool_size {
170        match single_constant_parser(input) {
171            Ok((i, o)) => {
172                // Long and Double Entries have twice the size
173                // see https://docs.oracle.com/javase/specs/jvms/se6/html/ClassFile.doc.html#1348
174                let uses_two_entries =
175                    matches!(o, ConstantInfo::Long(..) | ConstantInfo::Double(..));
176
177                res.push(o);
178                if uses_two_entries {
179                    res.push(ConstantInfo::Unusable);
180                    index += 1;
181                }
182                input = i;
183                index += 1;
184            }
185            _ => return Result::Err(Err::Error(error_position!(input, ErrorKind::Alt))),
186        }
187    }
188    Ok((input, res))
189}