added getName on fields and listened to clippy

This commit is contained in:
Sander Hautvast 2023-09-21 20:41:48 +02:00
parent c2cebaedad
commit 9b92730858
8 changed files with 204 additions and 170 deletions

BIN
Dummy.class Normal file

Binary file not shown.

19
Dummy.java Normal file
View file

@ -0,0 +1,19 @@
package dummy;
public class Dummy {
private final String name;
public Dummy(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void print(){
System.out.println(name);
}
}

Binary file not shown.

View file

@ -1,20 +0,0 @@
package com.github.shautvast.reflective;
public class MetaField {
private final String name;
private final int modifiers;
public MetaField(String name, int modifiers) {
this.name = name;
this.modifiers = modifiers;
}
public String getName() {
return name;
}
public int getModifiers() {
return modifiers;
}
}

View file

@ -1,7 +1,7 @@
pub mod types; pub mod types;
use std::rc::Rc; use std::rc::Rc;
use crate::types::{CpEntry, Class, Field, Attribute, Method}; use crate::types::{Attribute, Class, Field, Method};
pub fn get_class(bytecode: Vec<u8>) -> Option<Class> { pub fn get_class(bytecode: Vec<u8>) -> Option<Class> {
check_magic(&bytecode); check_magic(&bytecode);
@ -31,7 +31,7 @@ pub fn get_class(bytecode: Vec<u8>) -> Option<Class> {
index += 2; index += 2;
let mut fields = vec![]; let mut fields = vec![];
for _ in 0..fields_count { for _ in 0..fields_count {
fields.push(read_field(&mut index, &bytecode)); fields.push(read_field(constant_pool.clone(), &mut index, &bytecode));
} }
let methods_count = get_u16(&bytecode, index); let methods_count = get_u16(&bytecode, index);
@ -62,13 +62,13 @@ pub fn get_class(bytecode: Vec<u8>) -> Option<Class> {
}) })
} }
fn check_magic(bytecode: &Vec<u8>) { fn check_magic(bytecode: &[u8]) {
if &bytecode[0..4] != [0xCA, 0xFE, 0xBA, 0xBE] { if bytecode[0..4] != [0xCA, 0xFE, 0xBA, 0xBE] {
panic!("Invalid class file"); panic!("Invalid class file");
} }
} }
fn read_constant_pool_entry(index: &mut usize, bytecode: &Vec<u8>) -> CpEntry { fn read_constant_pool_entry(index: &mut usize, bytecode: &[u8]) -> CpEntry {
let tag = bytecode[*index]; let tag = bytecode[*index];
match tag { match tag {
1 => { 1 => {
@ -130,7 +130,7 @@ fn read_constant_pool_entry(index: &mut usize, bytecode: &Vec<u8>) -> CpEntry {
let descriptor_index = get_u16(bytecode, *index + 3); let descriptor_index = get_u16(bytecode, *index + 3);
*index += 5; *index += 5;
CpEntry::NameAndType(name_index, descriptor_index) CpEntry::NameAndType(name_index, descriptor_index)
}, }
// 15 MethodHandle, // 15 MethodHandle,
// 16 MethodType, // 16 MethodType,
// 17 Dynamic, // 17 Dynamic,
@ -141,26 +141,7 @@ fn read_constant_pool_entry(index: &mut usize, bytecode: &Vec<u8>) -> CpEntry {
} }
} }
fn read_field(index: &mut usize, bytecode: &Vec<u8>) -> Field { fn read_field(constant_pool: Rc<Vec<CpEntry>>, index: &mut usize, bytecode: &[u8]) -> Field {
let access_flags = get_u16(bytecode, *index);
let name_index = get_u16(bytecode, *index + 2);
let descriptor_index = get_u16(bytecode, *index + 4);
let attributes_count = get_u16(bytecode, *index + 6);
*index += 8;
let mut attributes = vec![];
for _ in 0..attributes_count {
attributes.push(read_attribute(bytecode, index));
}
Field {
access_flags,
name_index,
descriptor_index,
attributes_count,
attributes,
}
}
fn read_method(constant_pool: Rc<Vec<CpEntry>>, index: &mut usize, bytecode: &Vec<u8>) -> Method {
let access_flags = get_u16(bytecode, *index); let access_flags = get_u16(bytecode, *index);
let name_index = get_u16(bytecode, *index + 2) as usize; let name_index = get_u16(bytecode, *index + 2) as usize;
let descriptor_index = get_u16(bytecode, *index + 4) as usize; let descriptor_index = get_u16(bytecode, *index + 4) as usize;
@ -170,17 +151,35 @@ fn read_method(constant_pool: Rc<Vec<CpEntry>>, index: &mut usize, bytecode: &Ve
for _ in 0..attributes_count { for _ in 0..attributes_count {
attributes.push(read_attribute(bytecode, index)); attributes.push(read_attribute(bytecode, index));
} }
Method { Field::new(
constant_pool, constant_pool,
access_flags, access_flags,
name_index, name_index,
descriptor_index, descriptor_index,
attributes_count,
attributes, attributes,
} )
} }
fn read_attribute(bytecode: &Vec<u8>, index: &mut usize) -> Attribute { fn read_method(constant_pool: Rc<Vec<CpEntry>>, index: &mut usize, bytecode: &[u8]) -> Method {
let access_flags = get_u16(bytecode, *index);
let name_index = get_u16(bytecode, *index + 2) as usize;
let descriptor_index = get_u16(bytecode, *index + 4) as usize;
let attributes_count = get_u16(bytecode, *index + 6);
*index += 8;
let mut attributes = vec![];
for _ in 0..attributes_count {
attributes.push(read_attribute(bytecode, index));
}
Method::new (
constant_pool,
access_flags,
name_index,
descriptor_index,
attributes,
)
}
fn read_attribute(bytecode: &[u8], index: &mut usize) -> Attribute {
let attribute_name_index = get_u16(bytecode, *index); let attribute_name_index = get_u16(bytecode, *index);
*index += 2; *index += 2;
let attribute_length = read_u32(bytecode, *index) as usize; let attribute_length = read_u32(bytecode, *index) as usize;
@ -194,26 +193,46 @@ fn read_attribute(bytecode: &Vec<u8>, index: &mut usize) -> Attribute {
} }
} }
fn get_u16(data: &Vec<u8>, pos: usize) -> u16 { fn get_u16(data: &[u8], pos: usize) -> u16 {
u16::from_be_bytes(data[pos..pos + 2].try_into().expect("slice with incorrect length")) u16::from_be_bytes(data[pos..pos + 2].try_into().expect("slice with incorrect length"))
} }
fn get_i32(data: &Vec<u8>, pos: usize) -> i32 { fn get_i32(data: &[u8], pos: usize) -> i32 {
i32::from_be_bytes(data[pos..pos + 4].try_into().expect("slice with incorrect length")) i32::from_be_bytes(data[pos..pos + 4].try_into().expect("slice with incorrect length"))
} }
fn read_u32(data: &Vec<u8>, pos: usize) -> u32 { fn read_u32(data: &[u8], pos: usize) -> u32 {
u32::from_be_bytes(data[pos..pos + 4].try_into().expect("slice with incorrect length")) u32::from_be_bytes(data[pos..pos + 4].try_into().expect("slice with incorrect length"))
} }
fn get_f32(data: &Vec<u8>, pos: usize) -> f32 { fn get_f32(data: &[u8], pos: usize) -> f32 {
f32::from_be_bytes(data[pos..pos + 4].try_into().expect("slice with incorrect length")) f32::from_be_bytes(data[pos..pos + 4].try_into().expect("slice with incorrect length"))
} }
fn get_i64(data: &Vec<u8>, pos: usize) -> i64 { fn get_i64(data: &[u8], pos: usize) -> i64 {
i64::from_be_bytes(data[pos..pos + 8].try_into().expect("slice with incorrect length")) i64::from_be_bytes(data[pos..pos + 8].try_into().expect("slice with incorrect length"))
} }
fn get_f64(data: &Vec<u8>, pos: usize) -> f64 { fn get_f64(data: &[u8], pos: usize) -> f64 {
f64::from_be_bytes(data[pos..pos + 8].try_into().expect("slice with incorrect length")) f64::from_be_bytes(data[pos..pos + 8].try_into().expect("slice with incorrect length"))
} }
#[derive(Debug)]
pub enum CpEntry {
Utf8(String),
Integer(i32),
Float(f32),
Long(i64),
Double(f64),
ClassRef(u16),
StringRef(u16),
Fieldref(u16, u16),
MethodRef(u16, u16),
InterfaceMethodref(u16, u16),
NameAndType(u16, u16),
}

View file

@ -2,7 +2,7 @@ use std::fs::{self, File};
use std::io::Read; use std::io::Read;
fn main() { fn main() {
let bytecode = read_class_file("./MetaField.class"); let bytecode = read_class_file("./Dummy.class");
if let Some(class) = classfile_reader::get_class(bytecode){ if let Some(class) = classfile_reader::get_class(bytecode){
println!("{:?}", class); println!("{:?}", class);
} }
@ -12,6 +12,6 @@ fn read_class_file(name: &str) -> Vec<u8> {
let mut f = File::open(name).expect("no file found"); let mut f = File::open(name).expect("no file found");
let metadata = fs::metadata(name).expect("unable to read metadata"); let metadata = fs::metadata(name).expect("unable to read metadata");
let mut buffer = vec![0; metadata.len() as usize]; let mut buffer = vec![0; metadata.len() as usize];
f.read(&mut buffer).expect("buffer overflow"); let _ = f.read(&mut buffer).expect("buffer overflow");
buffer buffer
} }

View file

@ -1,6 +1,5 @@
use std::borrow::ToOwned;
use std::rc::Rc; use std::rc::Rc;
use crate::types::CpEntry::*; use crate::CpEntry;
#[derive(Debug)] #[derive(Debug)]
//TODO create factory function //TODO create factory function
@ -17,64 +16,36 @@ pub struct Class {
pub attributes: Vec<Attribute>, pub attributes: Vec<Attribute>,
} }
impl<'a> Class { impl Class {
pub fn get_version(&self) -> (u16, u16) { pub fn get_version(&self) -> (u16, u16) {
(self.major_version, self.minor_version) (self.major_version, self.minor_version)
} }
pub fn get_methods(&self) -> &Vec<Method> {
&self.methods
}
}
#[derive(Debug)]
pub enum CpEntry {
Utf8(String),
Integer(i32),
Float(f32),
Long(i64),
Double(f64),
ClassRef(u16),
StringRef(u16),
Fieldref(u16, u16),
MethodRef(u16, u16),
InterfaceMethodref(u16, u16),
NameAndType(u16, u16),
}
#[derive(Debug)]
pub struct Field {
pub access_flags: u16,
pub name_index: u16,
pub descriptor_index: u16,
pub attributes_count: u16,
pub attributes: Vec<Attribute>,
}
#[derive(Debug)]
pub struct Attribute {
pub attribute_name_index: u16,
pub info: Vec<u8>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Method { pub struct Method {
pub constant_pool: Rc<Vec<CpEntry>>, constant_pool: Rc<Vec<CpEntry>>,
pub access_flags: u16, access_flags: u16,
pub name_index: usize, name_index: usize,
pub descriptor_index: usize, descriptor_index: usize,
pub attributes_count: u16, _attributes: Vec<Attribute>,
pub attributes: Vec<Attribute>,
} }
impl Method { impl Method {
pub fn new(constant_pool: Rc<Vec<CpEntry>>,
access_flags: u16,
name_index: usize,
descriptor_index: usize,
attributes: Vec<Attribute>, ) -> Self {
Method { constant_pool, access_flags, name_index, descriptor_index, _attributes:attributes }
}
pub fn name(&self) -> String { pub fn name(&self) -> String {
let mut full_name = get_modifier(self.access_flags); let mut full_name = get_modifier(self.access_flags);
if let Utf8(s) = &self.constant_pool[&self.name_index - 1] { if let CpEntry::Utf8(s) = &self.constant_pool[&self.name_index - 1] {
full_name.push_str(s); full_name.push_str(s);
} }
if let Utf8(s) = &self.constant_pool[&self.descriptor_index - 1] { if let CpEntry::Utf8(s) = &self.constant_pool[&self.descriptor_index - 1] {
full_name.push_str(s); full_name.push_str(s);
} }
@ -83,7 +54,47 @@ impl Method {
} }
} }
const MODIFIERS: [(u16, &'static str); 12] = [ #[derive(Debug)]
pub struct Field {
constant_pool: Rc<Vec<CpEntry>>,
access_flags: u16,
name_index: usize,
descriptor_index: usize,
_attributes: Vec<Attribute>,
}
impl Field {
pub fn new(constant_pool: Rc<Vec<CpEntry>>,
access_flags: u16,
name_index: usize,
descriptor_index: usize,
attributes: Vec<Attribute>, ) -> Self {
Field { constant_pool, access_flags, name_index, descriptor_index, _attributes:attributes }
}
pub fn name(&self) -> String {
let mut full_name = get_modifier(self.access_flags);
if let CpEntry::Utf8(s) = &self.constant_pool[&self.descriptor_index - 1] {
full_name.push_str(s);
}
full_name.push(' ');
if let CpEntry::Utf8(s) = &self.constant_pool[&self.name_index - 1] {
full_name.push_str(s);
}
full_name
}
}
#[derive(Debug)]
pub struct Attribute {
pub attribute_name_index: u16,
pub info: Vec<u8>,
}
const MODIFIERS: [(u16, &str); 12] = [
(0x0001, "public "), (0x0001, "public "),
(0x0002, "private "), (0x0002, "private "),
(0x0004, "protected "), (0x0004, "protected "),
@ -97,10 +108,10 @@ const MODIFIERS: [(u16, &'static str); 12] = [
(0x0400, "interface "), (0x0400, "interface "),
(0x0800, "strict ")]; (0x0800, "strict ")];
pub fn get_modifier (value: u16) -> String { pub fn get_modifier(value: u16) -> String {
let mut output = String::new(); let mut output = String::new();
for m in MODIFIERS { for m in MODIFIERS {
if value & m.0 == m.0 { output.push_str(&m.1) } if value & m.0 == m.0 { output.push_str(m.1) }
} }
output output
} }

View file

@ -1,7 +1,7 @@
mod test { mod test {
use std::rc::Rc; use std::rc::Rc;
use classfile_reader::CpEntry::*;
use classfile_reader::types::{Attribute, Class, Field, Method}; use classfile_reader::types::{Attribute, Class, Field, Method};
use classfile_reader::types::CpEntry::*;
#[test] #[test]
fn get_version() { fn get_version() {
@ -10,80 +10,85 @@ mod test {
#[test] #[test]
fn get_methods() { fn get_methods() {
for m in get_class().get_methods() { let class = get_class();
println!("{}", m.name()); assert_eq!("public <init>(Ljava/lang/String;)V", &class.methods[0].name());
} assert_eq!("public getName()Ljava/lang/String;", &class.methods[1].name());
assert_eq!("public print()V", &class.methods[2].name());
}
#[test]
fn get_fields() {
let class = get_class();
assert_eq!("private final Ljava/lang/String; name", &class.fields[0].name())
} }
fn get_class() -> Class { fn get_class() -> Class {
let cp = Rc::new(vec![MethodRef(2, 3), let cp = Rc::new(vec![
ClassRef(4), MethodRef(6, 19),
NameAndType(5, 6), Fieldref(5, 20),
Utf8("java/lang/Object".to_owned()), Fieldref(21, 22),
Utf8("<init>".to_owned()), MethodRef(23, 24),
Utf8("()V".to_owned()), ClassRef(25),
Fieldref(8, 9), ClassRef(26),
ClassRef(10), Utf8("name".to_owned()),
NameAndType(11, 12), Utf8("Ljava/lang/String;".to_owned()),
Utf8("com/github/shautvast/reflective/MetaField".to_owned()), Utf8("<init>".to_owned()),
Utf8("name".to_owned()), Utf8("(Ljava/lang/String;)V".to_owned()), //10
Utf8("Ljava/lang/String;".to_owned()), Utf8("Code".to_owned()),
Fieldref(8, 14), Utf8("LineNumberTable".to_owned()),
NameAndType(15, 16), Utf8("getName".to_owned()),
Utf8("modifiers".to_owned()), Utf8("()Ljava/lang/String;".to_owned()),
Utf8("I".to_owned()), Utf8("print".to_owned()),
Utf8("(Ljava/lang/String;I)V".to_owned()), Utf8("()V".to_owned()),
Utf8("Code".to_owned()), Utf8("SourceFile".to_owned()),
Utf8("LineNumberTable".to_owned()), Utf8("Dummy.java".to_owned()),
Utf8("LocalVariableTable".to_owned()), NameAndType(9, 16),
Utf8("this".to_owned()), NameAndType(7, 8), //20
Utf8("Lcom/github/shautvast/reflective/MetaField;".to_owned()), ClassRef(27),
Utf8("getName".to_owned()), NameAndType(28, 29),
Utf8("()Ljava/lang/String;".to_owned()), ClassRef(30),
Utf8("getModifiers".to_owned()), NameAndType(31, 10),
Utf8("()I".to_owned()), Utf8("dummy/Dummy".to_owned()),
Utf8("SourceFile".to_owned()), Utf8("java/lang/Object".to_owned()),
Utf8("MetaField.java".to_owned())]); Utf8("java/lang/System".to_owned()),
Utf8("out".to_owned()),
Utf8("Ljava/io/PrintStream;".to_owned()),
Utf8("java/io/PrintStream".to_owned()),
Utf8("println".to_owned()),
]);
Class { Class {
minor_version: 0, minor_version: 0,
major_version: 55, major_version: 55,
constant_pool: cp.clone(), constant_pool: cp.clone(),
interfaces: vec![],
super_class: 2,
access_flags: 33, access_flags: 33,
this_class: 8, this_class: 5,
super_class: 6,
interfaces: vec![],
methods: vec![ methods: vec![
Method { Method::new(
constant_pool: cp.clone(), cp.clone(), 1, 9, 10, vec![Attribute {
access_flags: 1,
name_index: 5,
descriptor_index: 17,
attributes_count: 1,
attributes: vec![Attribute {
attribute_name_index: 18, attribute_name_index: 18,
info: vec![0, 2, 0, 3, 0, 0, 0, 15, 42, 183, 0, 1, 42, 43, 181, 0, 7, 42, 28, info: vec![0, 2, 0, 2, 0, 0, 0, 10, 42, 183, 0, 1, 42, 43, 181, 0, 2, 177, 0,
181, 0, 13, 177, 0, 0, 0, 2, 0, 19, 0, 0, 0, 0, 0, 1, 0, 12, 0, 0, 0, 14, 0, 3, 0, 0, 0, 7, 0, 4, 0, 8, 0, 9, 0, 9],
18, 0, 4, 0, 0, 0, 8, 0, 4, 0, 9, 0, 9, 0, 10, 0, 14, 0, 11, 0, 20, 0, 0,
0, 32, 0, 3, 0, 0, 0, 15, 0, 21, 0, 22, 0, 0, 0, 0, 0, 15, 0, 11,
0, 12, 0, 1, 0, 0, 0, 15, 0, 15, 0, 16, 0, 2],
}], }],
}, ),
Method { Method::new(
constant_pool: cp, cp.clone(), 1, 13, 14, vec![Attribute {
access_flags: 1,
name_index: 23,
descriptor_index: 24,
attributes_count: 1,
attributes: vec![Attribute {
attribute_name_index: 18, attribute_name_index: 18,
info: vec![0, 1, 0, 1, 0, 0, 0, 5, 42, 180, 0, 7, 176, 0, 0, 0, 2, 0, 19, 0, 0, 0, 6, 0, info: vec![0, 1, 0, 1, 0, 0, 0, 5, 42, 180, 0, 2, 176, 0, 0, 0, 1, 0, 12, 0,
1, 0, 0, 0, 14, 0, 20, 0, 0, 0, 12, 0, 1, 0, 0, 0, 5, 0, 21, 0, 22, 0, 0], 0, 0, 6, 0, 1, 0, 0, 0, 12],
}], }],
}], ),
fields: vec![Field { access_flags: 18, name_index: 11, descriptor_index: 12, attributes_count: 0, attributes: vec![] }, Method::new(cp.clone(), 1, 15, 16, vec![Attribute {
Field { access_flags: 18, name_index: 15, descriptor_index: 16, attributes_count: 0, attributes: vec![] }], attribute_name_index: 11,
attributes: vec![Attribute { attribute_name_index: 27, info: vec![0, 28] }], info: vec![0, 2, 0, 1, 0, 0, 0, 11, 178, 0, 3, 42, 180, 0, 2, 182, 0, 4, 177, 0,
0, 0, 1, 0, 12, 0, 0, 0, 10, 0, 2, 0, 0, 0, 16, 0, 10, 0, 17],
}]),
],
fields: vec![Field::new(cp, 18, 7, 8, vec![])],
attributes: vec![Attribute { attribute_name_index: 17, info: vec![0, 18] }],
} }
} }
} }