1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
6use std::error::Error;
7use std::io::{Read, Seek, Write};
8
9mod enums;
10pub use enums::{
11 AccessFlag, Attribute, Constant, ElementValue, Instruction, StackMapFrameType, TargetInfo,
12 VerificationType,
13};
14
15mod structs;
16pub use structs::{
17 Annotation, BootstrapMethod, ElementValuePair, Field, InnerClass, LineNumber, LocalVar,
18 LocalVariable, LocalVariableType, LookupSwitchPair, MemberData, Method, MethodParameter,
19 ModuleExports, ModuleOpens, ModuleProvides, ModuleRequires, StackMapFrame, TypeAnnotation,
20 TypePath,
21};
22
23mod reader;
24use crate::reader::{
25 extract_class_flags, read_attributes, read_constant_pool, read_fields, read_interfaces,
26 read_methods,
27};
28
29mod writer;
30use crate::writer::{
31 compact_class_flags, write_attributes, write_constant_pool, write_fields, write_interfaces,
32 write_methods,
33};
34
35mod errors;
36pub use errors::JavaError;
37
38mod mapping;
39
40#[derive(Debug)]
41pub struct JVMClass {
42 pub major: u16,
43 pub minor: u16,
44 pub access_flags: Vec<AccessFlag>,
45 pub this_class: u16,
46 pub super_class: u16,
47 pub constants: Vec<Constant>,
48 pub interfaces: Vec<u16>,
49 pub fields: Vec<Field>,
50 pub methods: Vec<Method>,
51 pub attributes: Vec<Attribute>,
52}
53
54impl JVMClass {
55 pub fn new() -> Self {
56 Self {
57 major: 0,
58 minor: 0,
59 access_flags: vec![],
60 this_class: 0,
61 super_class: 0,
62 constants: vec![],
63 interfaces: vec![],
64 fields: vec![],
65 methods: vec![],
66 attributes: vec![],
67 }
68 }
69
70 pub fn load<R: Read>(&mut self, r: &mut R) -> Result<(), Box<dyn Error>> {
71 let magic = r.read_u32::<BigEndian>()?;
72 assert_eq!(magic, 0xCAFEBABE);
73
74 self.minor = r.read_u16::<BigEndian>()?;
75 self.major = r.read_u16::<BigEndian>()?;
76
77 self.constants = read_constant_pool(r)?;
78
79 let access_flags = r.read_u16::<BigEndian>()?;
80 self.access_flags = extract_class_flags(access_flags);
81
82 self.this_class = r.read_u16::<BigEndian>()?;
83 self.super_class = r.read_u16::<BigEndian>()?;
84
85 self.interfaces = read_interfaces(r)?;
86 self.fields = read_fields(&self, r)?;
87 self.methods = read_methods(&self, r)?;
88 self.attributes = read_attributes(&self, r)?;
89
90 Ok(())
91 }
92
93 pub fn store<W: Write + Seek>(&self, w: &mut W) -> Result<(), Box<dyn Error>> {
94 w.write_u32::<BigEndian>(0xCAFEBABE)?;
95
96 w.write_u16::<BigEndian>(self.minor)?;
97 w.write_u16::<BigEndian>(self.major)?;
98
99 write_constant_pool(w, &self.constants)?;
100
101 let access_flags = compact_class_flags(&self.access_flags);
102 w.write_u16::<BigEndian>(access_flags)?;
103
104 w.write_u16::<BigEndian>(self.this_class)?;
105 w.write_u16::<BigEndian>(self.super_class)?;
106
107 write_interfaces(w, &self.interfaces)?;
108 write_fields(w, &self.fields, self)?;
109 write_methods(w, &self.methods, self)?;
110 write_attributes(w, &self.attributes, self)?;
111
112 Ok(())
113 }
114
115 pub fn get_string(&self, id: u16) -> Result<&str, JavaError> {
116 let id = id as usize;
117
118 if let Some(constant) = self.constants.get(id) {
119 match constant {
120 Constant::Class { name_index } => self.get_string(*name_index),
121 Constant::Utf8(string) => Ok(string),
122 Constant::String { string_index } => self.get_string(*string_index),
123 _ => Err(JavaError::ConstantTypeError(format!(
124 "#{id} is not a string, but a {constant}"
125 ))),
126 }
127 } else {
128 Err(JavaError::InvalidConstantId)
129 }
130 }
131
132 pub fn get_string_index(&self, string: &str) -> Result<u16, JavaError> {
133 for (index, constant) in self.constants.iter().enumerate() {
134 if let Constant::Utf8(s) = constant {
135 if s == string {
136 return Ok(index as u16);
137 }
138 }
139 }
140
141 Err(JavaError::StringNotFound)
142 }
143}