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