rjvm 0.3.0

Parse JVM class files with Rust
Documentation
use crate::bytecode::flags::{ClassAccessFlags, FieldAccessFlags, MethodAccessFlags};
use crate::bytecode::pool::{ConstantPool, ConstantPoolIndex};
use crate::bytecode::reader::attributes::read_attribute;
use crate::bytecode::reader::constants::read_constant_pool_entry;
use crate::bytecode::reader::BufferedReader;
use crate::bytecode::{
    BaseType, BytecodeError, ClassFile, ClassFileVersion, Descriptor, DescriptorKind, Field,
    FieldType, Interface, Method,
};

pub fn read_classfile(
    reader: &mut BufferedReader,
    cp: &mut ConstantPool,
) -> Result<ClassFile, BytecodeError> {
    let magic_number = reader.take::<u32>()?;
    if magic_number != 0xCAFEBABE {
        return Err(BytecodeError::InvalidClassFile);
    }

    let minor_version = reader.take::<u16>()?;
    let major_version = reader.take::<u16>()?;
    let version = ClassFileVersion {
        minor: minor_version,
        major: major_version,
    };

    let constant_pool_count = reader.take::<u16>()?;
    for idx in 1..=constant_pool_count - 1 {
        let entry = read_constant_pool_entry(reader, cp)?;
        cp.insert(idx.into(), entry)?;
    }

    let access_flags = reader.take::<u16>()?;
    let access_flags = match ClassAccessFlags::from_bits(access_flags) {
        Some(flags) => flags,
        None => return Err(BytecodeError::InvalidClassFile),
    };

    let this_class = reader.take::<u16>()?;
    let this_class = ConstantPoolIndex::new(this_class);
    let super_class = reader.take::<u16>()?;
    let super_class = ConstantPoolIndex::new(super_class);

    let interfaces_count = reader.take::<u16>()?;
    let mut interfaces = Vec::with_capacity(interfaces_count as usize);
    for _ in 0..interfaces_count {
        let interface = read_interface(reader, cp)?;
        interfaces.push(interface);
    }

    let fields_count = reader.take::<u16>()?;
    let mut fields = Vec::with_capacity(fields_count as usize);
    for _ in 0..fields_count {
        let field = read_field(reader, cp)?;
        fields.push(field);
    }

    let methods_count = reader.take::<u16>()?;
    let mut methods = Vec::with_capacity(methods_count as usize);
    for _ in 0..methods_count {
        let method = read_method(reader, cp)?;
        methods.push(method);
    }

    let attributes_count = reader.take::<u16>()?;
    let mut attributes = Vec::with_capacity(attributes_count as usize);
    for _ in 0..attributes_count {
        let attribute = read_attribute(reader, cp)?;
        attributes.push(attribute);
    }

    Ok(ClassFile {
        magic_number,
        version,
        constant_pool_count,
        constant_pool: cp.clone(),
        access_flags,
        this_class,
        super_class,
        interfaces_count,
        interfaces,
        fields_count,
        fields,
        methods_count,
        methods,
        attributes_count,
        attributes,
    })
}

pub fn read_interface(
    reader: &mut BufferedReader,
    _cp: &mut ConstantPool,
) -> Result<Interface, BytecodeError> {
    let name_index = reader.take::<u16>()?;

    Ok(Interface {
        name_index: ConstantPoolIndex::new(name_index),
    })
}

pub fn read_field(
    reader: &mut BufferedReader,
    cp: &mut ConstantPool,
) -> Result<Field, BytecodeError> {
    let access_flags = reader.take::<u16>()?;
    let Some(access_flags) = FieldAccessFlags::from_bits(access_flags) else {
        return Err(BytecodeError::InvalidClassFile);
    };

    let name_index = reader.take::<u16>()?;
    let Some(name) = cp.text_of(name_index.into()) else {
        return Err(BytecodeError::InvalidClassFile);
    };

    let descriptor_index = reader.take::<u16>()?;
    let Some(descriptor) = cp.text_of(descriptor_index.into()) else {
        return Err(BytecodeError::InvalidClassFile);
    };
    let descriptor = Descriptor::parse_from_field(descriptor).unwrap_or(Descriptor {
        kind: DescriptorKind::Type,
        ty: FieldType::Base(BaseType::Void),
    });

    let attributes_count = reader.take::<u16>()?;
    let mut attributes = Vec::with_capacity(attributes_count as usize);
    for _ in 0..attributes_count {
        let attribute = read_attribute(reader, cp)?;
        attributes.push(attribute);
    }

    Ok(Field {
        name,
        descriptor,
        access_flags,
        attributes,
    })
}

pub fn read_method(
    reader: &mut BufferedReader,
    cp: &mut ConstantPool,
) -> Result<Method, BytecodeError> {
    let access_flags = reader.take::<u16>()?;
    let Some(access_flags) = MethodAccessFlags::from_bits(access_flags) else {
        return Err(BytecodeError::InvalidClassFile);
    };

    let name_index = reader.take::<u16>()?;
    let Some(name) = cp.text_of(name_index.into()) else {
        return Err(BytecodeError::InvalidClassFile);
    };

    let descriptor_index = reader.take::<u16>()?;
    let Some(descriptor) = cp.text_of(descriptor_index.into()) else {
        return Err(BytecodeError::InvalidClassFile);
    };
    let descriptor = Descriptor::parse_from_method(descriptor);

    let attributes_count = reader.take::<u16>()?;
    let mut attributes = Vec::with_capacity(attributes_count as usize);
    for _ in 0..attributes_count {
        let attribute = read_attribute(reader, cp)?;
        attributes.push(attribute);
    }

    Ok(Method {
        access_flags,
        name,
        descriptor,
        attributes,
    })
}