From 9b92730858a683b057421d32be4b80fe181f633a Mon Sep 17 00:00:00 2001 From: Sander Hautvast Date: Thu, 21 Sep 2023 20:41:48 +0200 Subject: [PATCH] added getName on fields and listened to clippy --- Dummy.class | Bin 0 -> 517 bytes Dummy.java | 19 +++++++ MetaField.class | Bin 639 -> 0 bytes MetaField.java | 20 ------- src/lib.rs | 93 ++++++++++++++++++------------- src/main.rs | 4 +- src/types.rs | 111 ++++++++++++++++++++----------------- tests/class_tests.rs | 127 ++++++++++++++++++++++--------------------- 8 files changed, 204 insertions(+), 170 deletions(-) create mode 100644 Dummy.class create mode 100644 Dummy.java delete mode 100644 MetaField.class delete mode 100644 MetaField.java diff --git a/Dummy.class b/Dummy.class new file mode 100644 index 0000000000000000000000000000000000000000..fff6eba7323c5451d7fe3f36628d6955c1f22e3f GIT binary patch literal 517 zcmZWl%SyvQ6g`u+iJ3;5zI@lm$~J;ox=`FGu1Xau?$b7ulqQjy2>mM+AK=0d@T0^t zDOjZp+?l!eoO{l_U*8{}0FJRIp`&V|fSQRqRwdT3ZeYW}ra(UOLSLZL9(fO*JNBZX z+f61xG&~W|PlG5(&IIbs#d7PGmE+rl zWGwRMK;r?V^A6!0zCwG-&=%tgu^=l?p2;Jy%-oFE;4N4!I4{s1e<^yFv=~dU8I{BV b1r)USjGRKhAwSoUnYv9sWrE6tX{h`F8Fpbc literal 0 HcmV?d00001 diff --git a/Dummy.java b/Dummy.java new file mode 100644 index 0000000..d83a15a --- /dev/null +++ b/Dummy.java @@ -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); + } + +} diff --git a/MetaField.class b/MetaField.class deleted file mode 100644 index 0be7be0df56687ca2d76457d1a100e495ac19498..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 639 zcma)3OG^S#6#nk`7`5@yWcD(soukk!TNrHuK~P&5Ld&aO^~N{@>v4bV-u55FKrtk*q%YMq zL#*QT(nuj~B4c3(7K1YgrtVm($-M8*CVZ|Ie5Tw`j652Z3*okf;teUhAw%5fQ^8=j zHWXbIN`G9}pg9Y96d2OeU?@jYgfj-#WGGd(`E27^Tn?TubK5Gl@dgLya*4XMTCz7KGr z*Ty-mYS85k*!qGL*?MpCF)(_9U9vW1_xf4L=c}(^)!GtfwY)_3nMwxs$l8dLO_5F0 zmqCu;ic~pUjbR@p$_OB$VNs-s3?ewd;hM%Jum2^gFEF1dSb-;_VlD!-Rt;-Fh9ewP UMQi*yoPGQ?Z2viY5_Ofo0O>h)Q2+n{ diff --git a/MetaField.java b/MetaField.java deleted file mode 100644 index 9a05530..0000000 --- a/MetaField.java +++ /dev/null @@ -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; - } -} diff --git a/src/lib.rs b/src/lib.rs index 13cf038..8393fea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ pub mod types; 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) -> Option { check_magic(&bytecode); @@ -31,7 +31,7 @@ pub fn get_class(bytecode: Vec) -> Option { index += 2; let mut fields = vec![]; 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); @@ -62,13 +62,13 @@ pub fn get_class(bytecode: Vec) -> Option { }) } -fn check_magic(bytecode: &Vec) { - if &bytecode[0..4] != [0xCA, 0xFE, 0xBA, 0xBE] { +fn check_magic(bytecode: &[u8]) { + if bytecode[0..4] != [0xCA, 0xFE, 0xBA, 0xBE] { panic!("Invalid class file"); } } -fn read_constant_pool_entry(index: &mut usize, bytecode: &Vec) -> CpEntry { +fn read_constant_pool_entry(index: &mut usize, bytecode: &[u8]) -> CpEntry { let tag = bytecode[*index]; match tag { 1 => { @@ -130,7 +130,7 @@ fn read_constant_pool_entry(index: &mut usize, bytecode: &Vec) -> CpEntry { let descriptor_index = get_u16(bytecode, *index + 3); *index += 5; CpEntry::NameAndType(name_index, descriptor_index) - }, + } // 15 MethodHandle, // 16 MethodType, // 17 Dynamic, @@ -141,26 +141,7 @@ fn read_constant_pool_entry(index: &mut usize, bytecode: &Vec) -> CpEntry { } } -fn read_field(index: &mut usize, bytecode: &Vec) -> 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>, index: &mut usize, bytecode: &Vec) -> Method { +fn read_field(constant_pool: Rc>, index: &mut usize, bytecode: &[u8]) -> Field { 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; @@ -170,17 +151,35 @@ fn read_method(constant_pool: Rc>, index: &mut usize, bytecode: &Ve for _ in 0..attributes_count { attributes.push(read_attribute(bytecode, index)); } - Method { + Field::new( constant_pool, access_flags, name_index, descriptor_index, - attributes_count, attributes, - } + ) } -fn read_attribute(bytecode: &Vec, index: &mut usize) -> Attribute { +fn read_method(constant_pool: Rc>, 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); *index += 2; let attribute_length = read_u32(bytecode, *index) as usize; @@ -194,26 +193,46 @@ fn read_attribute(bytecode: &Vec, index: &mut usize) -> Attribute { } } -fn get_u16(data: &Vec, 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")) } -fn get_i32(data: &Vec, 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")) } -fn read_u32(data: &Vec, 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")) } -fn get_f32(data: &Vec, 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")) } -fn get_i64(data: &Vec, 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")) } -fn get_f64(data: &Vec, 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")) -} \ No newline at end of file +} + +#[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), +} + + + + + diff --git a/src/main.rs b/src/main.rs index 7bbe8f3..113026a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use std::fs::{self, File}; use std::io::Read; 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){ println!("{:?}", class); } @@ -12,6 +12,6 @@ fn read_class_file(name: &str) -> Vec { let mut f = File::open(name).expect("no file found"); let metadata = fs::metadata(name).expect("unable to read metadata"); 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 } diff --git a/src/types.rs b/src/types.rs index c8ced20..8627b42 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,5 @@ -use std::borrow::ToOwned; use std::rc::Rc; -use crate::types::CpEntry::*; +use crate::CpEntry; #[derive(Debug)] //TODO create factory function @@ -17,64 +16,36 @@ pub struct Class { pub attributes: Vec, } -impl<'a> Class { +impl Class { pub fn get_version(&self) -> (u16, u16) { (self.major_version, self.minor_version) } - - pub fn get_methods(&self) -> &Vec { - &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, -} - -#[derive(Debug)] -pub struct Attribute { - pub attribute_name_index: u16, - pub info: Vec, } #[derive(Debug)] pub struct Method { - pub constant_pool: Rc>, - pub access_flags: u16, - pub name_index: usize, - pub descriptor_index: usize, - pub attributes_count: u16, - pub attributes: Vec, + constant_pool: Rc>, + access_flags: u16, + name_index: usize, + descriptor_index: usize, + _attributes: Vec, } impl Method { + pub fn new(constant_pool: Rc>, + access_flags: u16, + name_index: usize, + descriptor_index: usize, + attributes: Vec, ) -> Self { + Method { 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 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); } - 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); } @@ -83,7 +54,47 @@ impl Method { } } -const MODIFIERS: [(u16, &'static str); 12] = [ +#[derive(Debug)] +pub struct Field { + constant_pool: Rc>, + access_flags: u16, + name_index: usize, + descriptor_index: usize, + _attributes: Vec, +} + +impl Field { + pub fn new(constant_pool: Rc>, + access_flags: u16, + name_index: usize, + descriptor_index: usize, + attributes: Vec, ) -> 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, +} + + +const MODIFIERS: [(u16, &str); 12] = [ (0x0001, "public "), (0x0002, "private "), (0x0004, "protected "), @@ -97,10 +108,10 @@ const MODIFIERS: [(u16, &'static str); 12] = [ (0x0400, "interface "), (0x0800, "strict ")]; -pub fn get_modifier (value: u16) -> String { +pub fn get_modifier(value: u16) -> String { let mut output = String::new(); 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 -} +} \ No newline at end of file diff --git a/tests/class_tests.rs b/tests/class_tests.rs index 9c6529d..d93cede 100644 --- a/tests/class_tests.rs +++ b/tests/class_tests.rs @@ -1,7 +1,7 @@ mod test { use std::rc::Rc; + use classfile_reader::CpEntry::*; use classfile_reader::types::{Attribute, Class, Field, Method}; - use classfile_reader::types::CpEntry::*; #[test] fn get_version() { @@ -10,80 +10,85 @@ mod test { #[test] fn get_methods() { - for m in get_class().get_methods() { - println!("{}", m.name()); - } + let class = get_class(); + assert_eq!("public (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 { - let cp = Rc::new(vec![MethodRef(2, 3), - ClassRef(4), - NameAndType(5, 6), - Utf8("java/lang/Object".to_owned()), - Utf8("".to_owned()), - Utf8("()V".to_owned()), - Fieldref(8, 9), - ClassRef(10), - NameAndType(11, 12), - Utf8("com/github/shautvast/reflective/MetaField".to_owned()), - Utf8("name".to_owned()), - Utf8("Ljava/lang/String;".to_owned()), - Fieldref(8, 14), - NameAndType(15, 16), - Utf8("modifiers".to_owned()), - Utf8("I".to_owned()), - Utf8("(Ljava/lang/String;I)V".to_owned()), - Utf8("Code".to_owned()), - Utf8("LineNumberTable".to_owned()), - Utf8("LocalVariableTable".to_owned()), - Utf8("this".to_owned()), - Utf8("Lcom/github/shautvast/reflective/MetaField;".to_owned()), - Utf8("getName".to_owned()), - Utf8("()Ljava/lang/String;".to_owned()), - Utf8("getModifiers".to_owned()), - Utf8("()I".to_owned()), - Utf8("SourceFile".to_owned()), - Utf8("MetaField.java".to_owned())]); + let cp = Rc::new(vec![ + MethodRef(6, 19), + Fieldref(5, 20), + Fieldref(21, 22), + MethodRef(23, 24), + ClassRef(25), + ClassRef(26), + Utf8("name".to_owned()), + Utf8("Ljava/lang/String;".to_owned()), + Utf8("".to_owned()), + Utf8("(Ljava/lang/String;)V".to_owned()), //10 + Utf8("Code".to_owned()), + Utf8("LineNumberTable".to_owned()), + Utf8("getName".to_owned()), + Utf8("()Ljava/lang/String;".to_owned()), + Utf8("print".to_owned()), + Utf8("()V".to_owned()), + Utf8("SourceFile".to_owned()), + Utf8("Dummy.java".to_owned()), + NameAndType(9, 16), + NameAndType(7, 8), //20 + ClassRef(27), + NameAndType(28, 29), + ClassRef(30), + NameAndType(31, 10), + Utf8("dummy/Dummy".to_owned()), + Utf8("java/lang/Object".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 { minor_version: 0, major_version: 55, constant_pool: cp.clone(), - interfaces: vec![], - super_class: 2, access_flags: 33, - this_class: 8, + this_class: 5, + super_class: 6, + interfaces: vec![], methods: vec![ - Method { - constant_pool: cp.clone(), - access_flags: 1, - name_index: 5, - descriptor_index: 17, - attributes_count: 1, - attributes: vec![Attribute { + Method::new( + cp.clone(), 1, 9, 10, vec![Attribute { 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, - 181, 0, 13, 177, 0, 0, 0, 2, 0, 19, 0, 0, 0, - 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], + info: vec![0, 2, 0, 2, 0, 0, 0, 10, 42, 183, 0, 1, 42, 43, 181, 0, 2, 177, 0, + 0, 0, 1, 0, 12, 0, 0, 0, 14, 0, 3, 0, 0, 0, 7, 0, 4, 0, 8, 0, 9, 0, 9], }], - }, - Method { - constant_pool: cp, - access_flags: 1, - name_index: 23, - descriptor_index: 24, - attributes_count: 1, - attributes: vec![Attribute { + ), + Method::new( + cp.clone(), 1, 13, 14, vec![Attribute { 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, - 1, 0, 0, 0, 14, 0, 20, 0, 0, 0, 12, 0, 1, 0, 0, 0, 5, 0, 21, 0, 22, 0, 0], + info: vec![0, 1, 0, 1, 0, 0, 0, 5, 42, 180, 0, 2, 176, 0, 0, 0, 1, 0, 12, 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![] }, - Field { access_flags: 18, name_index: 15, descriptor_index: 16, attributes_count: 0, attributes: vec![] }], - attributes: vec![Attribute { attribute_name_index: 27, info: vec![0, 28] }], + ), + Method::new(cp.clone(), 1, 15, 16, vec![Attribute { + attribute_name_index: 11, + 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] }], } } } \ No newline at end of file