reads complete class file
This commit is contained in:
commit
ecf7158e13
8 changed files with 327 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/.idea
|
||||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "classfile_reader"
|
||||||
|
version = "0.1.0"
|
||||||
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "classfile_reader"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
BIN
MetaField.class
Normal file
BIN
MetaField.class
Normal file
Binary file not shown.
20
MetaField.java
Normal file
20
MetaField.java
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
209
src/lib.rs
Normal file
209
src/lib.rs
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
|
use crate::types::{CpEntry, Class, Field, Attribute, Method};
|
||||||
|
|
||||||
|
pub fn get_class(bytecode: Vec<u8>) -> Option<Class> {
|
||||||
|
check_magic(&bytecode);
|
||||||
|
|
||||||
|
let constant_pool_count = get_u16(&bytecode, 8);
|
||||||
|
let mut index = 10;
|
||||||
|
let mut constant_pool: Vec<CpEntry> = vec![];
|
||||||
|
for _ in 0..constant_pool_count - 1 {
|
||||||
|
constant_pool.push(read_constant_pool_entry(&mut index, &bytecode));
|
||||||
|
}
|
||||||
|
|
||||||
|
let access_flags = get_u16(&bytecode, index);
|
||||||
|
let this_class = get_u16(&bytecode, index + 2);
|
||||||
|
let super_class = get_u16(&bytecode, index + 4);
|
||||||
|
|
||||||
|
let interfaces_count = get_u16(&bytecode, index + 6);
|
||||||
|
index += 8;
|
||||||
|
let mut interfaces = vec![];
|
||||||
|
for _ in 0..interfaces_count {
|
||||||
|
interfaces.push(get_u16(&bytecode, index));
|
||||||
|
index += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fields_count = get_u16(&bytecode, index);
|
||||||
|
index += 2;
|
||||||
|
let mut fields = vec![];
|
||||||
|
for _ in 0..fields_count {
|
||||||
|
fields.push(read_field(&mut index, &bytecode));
|
||||||
|
}
|
||||||
|
|
||||||
|
let methods_count = get_u16(&bytecode, index);
|
||||||
|
index += 2;
|
||||||
|
let mut methods = vec![];
|
||||||
|
for _ in 0..methods_count {
|
||||||
|
methods.push(read_method(&mut index, &bytecode));
|
||||||
|
}
|
||||||
|
|
||||||
|
let attributes_count = get_u16(&bytecode, index);
|
||||||
|
index += 2;
|
||||||
|
let mut attributes = vec![];
|
||||||
|
for _ in 0..attributes_count {
|
||||||
|
attributes.push(read_attribute(&bytecode, &mut index));
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Class {
|
||||||
|
minor_version: get_u16(&bytecode, 4),
|
||||||
|
major_version: get_u16(&bytecode, 6),
|
||||||
|
constant_pool,
|
||||||
|
access_flags,
|
||||||
|
this_class,
|
||||||
|
super_class,
|
||||||
|
interfaces,
|
||||||
|
fields,
|
||||||
|
methods,
|
||||||
|
attributes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_magic(bytecode: &Vec<u8>) {
|
||||||
|
if &bytecode[0..4] != [0xCA, 0xFE, 0xBA, 0xBE] {
|
||||||
|
panic!(); //must never happen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_constant_pool_entry(index: &mut usize, bytecode: &Vec<u8>) -> CpEntry {
|
||||||
|
let tag = bytecode[*index];
|
||||||
|
match tag {
|
||||||
|
1 => {
|
||||||
|
let len = get_u16(bytecode, *index + 1) as usize;
|
||||||
|
let utf: Vec<u8> = Vec::from(&bytecode[*index + 3..*index + 3 + len]);
|
||||||
|
*index += len + 3;
|
||||||
|
CpEntry::Utf8(String::from_utf8(utf).unwrap())
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
let value = get_i32(bytecode, *index + 1);
|
||||||
|
*index += 5;
|
||||||
|
CpEntry::Integer(value)
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
let value = get_f32(bytecode, *index + 1);
|
||||||
|
*index += 5;
|
||||||
|
CpEntry::Float(value)
|
||||||
|
}
|
||||||
|
5 => {
|
||||||
|
let value = get_i64(bytecode, *index + 1);
|
||||||
|
*index += 9;
|
||||||
|
CpEntry::Long(value)
|
||||||
|
}
|
||||||
|
6 => {
|
||||||
|
let value = get_f64(bytecode, *index + 1);
|
||||||
|
*index += 9;
|
||||||
|
CpEntry::Double(value)
|
||||||
|
}
|
||||||
|
7 => {
|
||||||
|
let name_index = get_u16(bytecode, *index + 1);
|
||||||
|
*index += 3;
|
||||||
|
CpEntry::Class(name_index)
|
||||||
|
}
|
||||||
|
8 => {
|
||||||
|
let string_index = get_u16(bytecode, *index + 1);
|
||||||
|
*index += 3;
|
||||||
|
CpEntry::String(string_index)
|
||||||
|
}
|
||||||
|
9 => {
|
||||||
|
let class_index = get_u16(bytecode, *index + 1);
|
||||||
|
let name_and_type_index = get_u16(bytecode, *index + 3);
|
||||||
|
*index += 5;
|
||||||
|
CpEntry::Fieldref(class_index, name_and_type_index)
|
||||||
|
}
|
||||||
|
10 => {
|
||||||
|
let class_index = get_u16(bytecode, *index + 1);
|
||||||
|
let name_and_type_index = get_u16(bytecode, *index + 3);
|
||||||
|
*index += 5;
|
||||||
|
CpEntry::MethodRef(class_index, name_and_type_index)
|
||||||
|
}
|
||||||
|
11 => {
|
||||||
|
let class_index = get_u16(bytecode, *index + 1);
|
||||||
|
let name_and_type_index = get_u16(bytecode, *index + 3);
|
||||||
|
*index += 5;
|
||||||
|
CpEntry::InterfaceMethodref(class_index, name_and_type_index)
|
||||||
|
}
|
||||||
|
12 => {
|
||||||
|
let name_index = get_u16(bytecode, *index + 1);
|
||||||
|
let descriptor_index = get_u16(bytecode, *index + 3);
|
||||||
|
*index += 5;
|
||||||
|
CpEntry::NameAndType(name_index, descriptor_index)
|
||||||
|
}
|
||||||
|
_ => panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_field(index: &mut usize, bytecode: &Vec<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(index: &mut usize, bytecode: &Vec<u8>) -> Method {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
Method {
|
||||||
|
access_flags,
|
||||||
|
name_index,
|
||||||
|
descriptor_index,
|
||||||
|
attributes_count,
|
||||||
|
attributes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_attribute(bytecode: &Vec<u8>, index: &mut usize) -> Attribute {
|
||||||
|
let attribute_name_index = get_u16(bytecode, *index);
|
||||||
|
*index += 2;
|
||||||
|
let attribute_length = read_u32(bytecode, *index) as usize;
|
||||||
|
*index += 4;
|
||||||
|
let info: Vec<u8> = Vec::from(&bytecode[*index..*index + attribute_length]);
|
||||||
|
*index += attribute_length;
|
||||||
|
|
||||||
|
Attribute {
|
||||||
|
attribute_name_index,
|
||||||
|
info,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_u16(data: &Vec<u8>, pos: usize) -> u16 {
|
||||||
|
u16::from_be_bytes(data[pos..pos + 2].try_into().expect("slice with incorrect length"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_i32(data: &Vec<u8>, pos: usize) -> i32 {
|
||||||
|
i32::from_be_bytes(data[pos..pos + 4].try_into().expect("slice with incorrect length"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u32(data: &Vec<u8>, pos: usize) -> u32 {
|
||||||
|
u32::from_be_bytes(data[pos..pos + 4].try_into().expect("slice with incorrect length"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_f32(data: &Vec<u8>, pos: usize) -> f32 {
|
||||||
|
f32::from_be_bytes(data[pos..pos + 4].try_into().expect("slice with incorrect length"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_i64(data: &Vec<u8>, pos: usize) -> i64 {
|
||||||
|
i64::from_be_bytes(data[pos..pos + 8].try_into().expect("slice with incorrect length"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_f64(data: &Vec<u8>, pos: usize) -> f64 {
|
||||||
|
f64::from_be_bytes(data[pos..pos + 8].try_into().expect("slice with incorrect length"))
|
||||||
|
}
|
||||||
17
src/main.rs
Normal file
17
src/main.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
use std::fs::{self, File};
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let bytecode = read_class_file("/Users/FJ19WK/RustroverProjects/classfile_reader/MetaField.class");
|
||||||
|
if let Some(class) = classfile_reader::get_class(bytecode){
|
||||||
|
println!("{:?}", class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_class_file(name: &str) -> Vec<u8> {
|
||||||
|
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");
|
||||||
|
buffer
|
||||||
|
}
|
||||||
64
src/types.rs
Normal file
64
src/types.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
#[derive(Debug)]
|
||||||
|
//TODO create factory function
|
||||||
|
pub struct Class {
|
||||||
|
pub minor_version: u16,
|
||||||
|
pub major_version: u16,
|
||||||
|
pub constant_pool: Vec<CpEntry>,
|
||||||
|
pub access_flags: u16,
|
||||||
|
pub this_class: u16,
|
||||||
|
pub super_class: u16,
|
||||||
|
pub interfaces: Vec<u16>,
|
||||||
|
pub fields: Vec<Field>,
|
||||||
|
pub methods: Vec<Method>,
|
||||||
|
pub attributes: Vec<Attribute>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum CpEntry {
|
||||||
|
Utf8(String),
|
||||||
|
//1
|
||||||
|
Integer(i32),
|
||||||
|
//3
|
||||||
|
Float(f32),
|
||||||
|
//4
|
||||||
|
Long(i64),
|
||||||
|
//5
|
||||||
|
Double(f64),
|
||||||
|
//6
|
||||||
|
Class(u16),
|
||||||
|
//7
|
||||||
|
String(u16),
|
||||||
|
//8
|
||||||
|
Fieldref(u16, u16),
|
||||||
|
//9
|
||||||
|
MethodRef(u16, u16),
|
||||||
|
//10
|
||||||
|
InterfaceMethodref(u16, u16),
|
||||||
|
//11
|
||||||
|
NameAndType(u16, u16), //12
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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)]
|
||||||
|
pub struct Method{
|
||||||
|
pub access_flags: u16,
|
||||||
|
pub name_index: u16,
|
||||||
|
pub descriptor_index: u16,
|
||||||
|
pub attributes_count: u16,
|
||||||
|
pub attributes: Vec<Attribute>,
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue