2024-08-29 14:48:40 +02:00
use std ::io ::Read ;
use std ::error ::Error as ErrorTrait ;
use core ::fmt ::{ Display , Formatter , Debug } ;
use core ::str ::Utf8Error ;
2024-08-30 15:33:54 +02:00
use crate ::accessmasks ::* ;
2024-08-30 15:48:12 +02:00
use crate ::bytecode ::Bytecode ;
2024-09-05 00:33:14 +02:00
use crate ::constantpool ::{ ConstantFieldRefInfo , ConstantPoolInfo , ConstantUtf8Info , ConstantStringInfo , ConstantMethodRefInfo , ConstantClassInfo , ConstantNameAndTypeInfo , ConstantIntegerInfo , ConstantLongInfo } ;
2024-08-29 14:48:40 +02:00
#[ derive(Debug) ]
pub enum Error {
BadFileError ( String ) ,
IOError ( std ::io ::Error ) ,
Utf8Error ( Utf8Error ) ,
PlatformIntError ( core ::num ::TryFromIntError ) ,
BadEnumError ( String ) ,
}
impl ErrorTrait for Error { }
impl Display for Error {
fn fmt ( & self , formatter : & mut Formatter < '_ > ) -> Result < ( ) , std ::fmt ::Error > {
writeln! ( formatter , " {self} " ) ? ;
if let Some ( e ) = self . source ( ) {
writeln! ( formatter , " \t Caused by: {e:?} " ) ? ;
}
Ok ( ( ) )
}
}
impl From < std ::io ::Error > for Error {
fn from ( value : std ::io ::Error ) -> Self {
return Error ::IOError (
value
) ;
}
}
impl From < Utf8Error > for Error {
fn from ( value : Utf8Error ) -> Self {
return Error ::Utf8Error ( value ) ;
}
}
impl From < core ::num ::TryFromIntError > for Error {
fn from ( value : core ::num ::TryFromIntError ) -> Self {
return Error ::PlatformIntError ( value ) ;
}
}
#[ derive(Debug) ]
pub struct JavaClassFile {
2024-08-30 15:33:54 +02:00
pub minor_version : u16 ,
pub major_version : u16 ,
2024-08-29 14:48:40 +02:00
2024-08-30 15:33:54 +02:00
pub constant_pool : Box < [ ConstantPoolInfo ] > ,
pub access_flags : ClassAccessFlagMask ,
pub this_class : u16 ,
pub super_class : u16 ,
pub interfaces : Box < [ u16 ] > ,
pub fields : Box < [ FieldInfo ] > ,
2024-08-29 14:48:40 +02:00
2024-08-30 15:33:54 +02:00
pub methods : Box < [ MethodInfo ] > ,
pub attributes : Box < [ AttributeInfo ] > ,
2024-08-29 14:48:40 +02:00
}
impl JavaClassFile {
pub fn new ( reader : & mut dyn Read ) -> Result < Self , Error > {
{
let magic = read_u32 ( reader ) ? ;
if magic ! = 0xCAFEBABE {
return Err (
Error ::BadFileError (
format! ( " Expected magic bytes 0xCAFEBABE but found {:#X} " , magic )
)
)
}
}
let minor_version = read_u16 ( reader ) ? ;
let major_version = read_u16 ( reader ) ? ;
let constant_pool = {
let constant_pool_count = read_u16 ( reader ) ? ;
let constant_pool_size = constant_pool_count - 1 ;
let mut constant_pool_vec = Vec ::with_capacity ( constant_pool_size . into ( ) ) ;
let mut i = 0 ;
while i < constant_pool_size {
let cpinfo = ConstantPoolInfo ::from_reader ( reader ) ? ;
2024-08-29 19:32:05 +02:00
let delta_i = match cpinfo {
ConstantPoolInfo ::Double ( _ ) | ConstantPoolInfo ::Long ( _ ) = > 2 ,
2024-08-29 14:48:40 +02:00
_ = > 1
} ;
constant_pool_vec . push ( cpinfo ) ;
2024-08-29 19:32:05 +02:00
if delta_i = = 2 {
constant_pool_vec . push ( ConstantPoolInfo ::Nothing ( ) ) ;
}
i + = delta_i ;
2024-08-29 14:48:40 +02:00
}
constant_pool_vec . into_boxed_slice ( )
} ;
2024-08-29 19:32:05 +02:00
let access_flags = ClassAccessFlagMask { mask : read_u16 ( reader ) ? } ;
2024-08-29 14:48:40 +02:00
let this_class = read_u16 ( reader ) ? ;
let super_class = read_u16 ( reader ) ? ;
let interfaces = {
let length = read_u16 ( reader ) ? ;
let mut if_vec = Vec ::< u16 > ::with_capacity ( length . into ( ) ) ;
for _i in 0 .. length {
if_vec . push ( read_u16 ( reader ) ? ) ;
}
if_vec . into_boxed_slice ( )
} ;
let fields = {
let length = read_u16 ( reader ) ? ;
let mut fields_vec = Vec ::with_capacity ( length . into ( ) ) ;
for _i in 0 .. length {
fields_vec . push ( FieldInfo ::from_reader ( reader , & constant_pool ) ? ) ;
}
fields_vec . into_boxed_slice ( )
} ;
let methods = {
let length = read_u16 ( reader ) ? ;
let mut methods_vec = Vec ::with_capacity ( length . into ( ) ) ;
for _i in 0 .. length {
methods_vec . push ( MethodInfo ::from_reader ( reader , & constant_pool ) ? ) ;
}
methods_vec . into_boxed_slice ( )
} ;
2024-08-29 18:33:03 +02:00
let attributes = AttributeInfo ::array_from_reader ( reader , & constant_pool , true ) ? ;
2024-08-29 14:48:40 +02:00
Ok (
JavaClassFile {
minor_version ,
major_version ,
constant_pool ,
access_flags ,
this_class ,
super_class ,
interfaces ,
fields ,
methods ,
attributes ,
}
)
}
2024-08-30 15:33:54 +02:00
2024-09-03 00:49:28 +02:00
pub fn has_super_class ( & self ) -> bool {
return self . super_class ! = 0 ;
}
pub fn get_super_class_name ( & self ) -> Result < & String , Error > {
let super_class_entry = self . pool_class_entry ( self . super_class ) ? ;
let super_name_entry = self . pool_utf8_entry ( super_class_entry . name_index ) ? ;
return Ok ( & super_name_entry . utf8 ) ;
}
pub fn get_classname ( & self ) -> Result < & String , Error > {
2024-09-02 19:28:22 +02:00
let class_info_entry = self . pool_entry ( self . this_class ) ? ;
2024-08-30 15:33:54 +02:00
let class_info_entry = match class_info_entry {
ConstantPoolInfo ::Class ( data ) = > data ,
_ = > return Err ( Error ::BadFileError ( format! ( " Invalid this_class index, expected index to ClassInfo but found {:?} " , class_info_entry ) ) )
} ;
2024-09-02 19:28:22 +02:00
let name_entry = self . pool_entry ( class_info_entry . name_index . into ( ) ) ? ;
2024-08-30 15:33:54 +02:00
let name_entry = match name_entry {
ConstantPoolInfo ::Utf8 ( utf8data ) = > utf8data ,
2024-09-02 11:28:00 +02:00
_ = > return Err ( Error ::BadFileError ( format! ( " Invalid class_info.name_index from this_class, expected index to Utf8 but found {:?} " , name_entry ) ) )
2024-08-30 15:33:54 +02:00
} ;
2024-09-03 00:49:28 +02:00
return Ok ( & name_entry . utf8 ) ;
2024-08-30 15:33:54 +02:00
}
pub fn find_method_index ( & self , name : & String ) -> Option < usize > {
for ( index , method_info ) in self . methods . iter ( ) . enumerate ( ) {
if method_info . name = = * name {
return Some ( index ) ;
}
}
return None ;
}
2024-09-02 11:28:00 +02:00
2024-09-06 23:51:35 +02:00
pub fn pool_entry ( & self , index : u16 ) -> Result < & ConstantPoolInfo , Error > {
2024-09-02 19:28:22 +02:00
return pool_entry ( & self . constant_pool , index ) ;
2024-09-02 11:28:00 +02:00
}
pub fn pool_methodref_entry ( & self , index : u16 ) -> Result < & ConstantMethodRefInfo , Error > {
2024-09-02 19:28:22 +02:00
let pool_entry = self . pool_entry ( index ) ? ;
2024-09-02 11:28:00 +02:00
let methodref_entry = match pool_entry {
ConstantPoolInfo ::MethodRef ( data ) = > data ,
_ = > unreachable! ( ) ,
} ;
return Ok ( methodref_entry ) ;
}
2024-09-05 00:33:14 +02:00
pub fn pool_fieldref_entry ( & self , index : u16 ) -> Result < & ConstantFieldRefInfo , Error > {
let pool_entry = self . pool_entry ( index ) ? ;
let fieldref_entry = match pool_entry {
ConstantPoolInfo ::FieldRef ( data ) = > data ,
_ = > unreachable! ( ) ,
} ;
return Ok ( fieldref_entry ) ;
}
2024-09-02 11:28:00 +02:00
pub fn pool_class_entry ( & self , index : u16 ) -> Result < & ConstantClassInfo , Error > {
2024-09-02 19:28:22 +02:00
let pool_entry = self . pool_entry ( index ) ? ;
2024-09-02 11:28:00 +02:00
return match pool_entry {
ConstantPoolInfo ::Class ( data ) = > Ok ( data ) ,
2024-09-02 19:28:22 +02:00
_ = > Err ( Error ::BadFileError ( format! ( " Expected constant pool entry {} in class {} to be of type Class but found {:?} " , index , self . get_classname ( ) ? , pool_entry ) ) )
2024-09-02 11:28:00 +02:00
} ;
}
pub fn pool_utf8_entry ( & self , index : u16 ) -> Result < & ConstantUtf8Info , Error > {
2024-09-02 19:28:22 +02:00
let pool_entry = self . pool_entry ( index ) ? ;
2024-09-02 11:28:00 +02:00
return match pool_entry {
ConstantPoolInfo ::Utf8 ( data ) = > Ok ( data ) ,
2024-09-02 19:28:22 +02:00
_ = > Err ( Error ::BadFileError ( format! ( " Expected constant pool entry {} in class {} to be of type Utf8 but found {:?} " , index , self . get_classname ( ) ? , pool_entry ) ) )
} ;
}
2024-09-05 00:33:14 +02:00
pub fn pool_long_entry ( & self , index : u16 ) -> Result < & ConstantLongInfo , Error > {
let pool_entry = self . pool_entry ( index ) ? ;
return match pool_entry {
ConstantPoolInfo ::Long ( data ) = > Ok ( data ) ,
_ = > Err ( Error ::BadFileError ( format! ( " Expected constant pool entry {} in class {} to be of type Long but found {:?} " , index , self . get_classname ( ) ? , pool_entry ) ) )
} ;
}
2024-09-02 19:28:22 +02:00
pub fn pool_int_entry ( & self , index : u16 ) -> Result < & ConstantIntegerInfo , Error > {
let pool_entry = self . pool_entry ( index ) ? ;
return match pool_entry {
ConstantPoolInfo ::Integer ( data ) = > Ok ( data ) ,
_ = > Err ( Error ::BadFileError ( format! ( " Expected constant pool entry {} in class {} to be of type Integer but found {:?} " , index , self . get_classname ( ) ? , pool_entry ) ) )
2024-09-02 11:28:00 +02:00
} ;
}
pub fn pool_nameandtype_entry ( & self , index : u16 ) -> Result < & ConstantNameAndTypeInfo , Error > {
2024-09-02 19:28:22 +02:00
let pool_entry = self . pool_entry ( index ) ? ;
2024-09-02 11:28:00 +02:00
return match pool_entry {
ConstantPoolInfo ::NameAndType ( data ) = > Ok ( data ) ,
2024-09-02 19:28:22 +02:00
_ = > Err ( Error ::BadFileError ( format! ( " Expected constant pool entry {} in class {} to be of type NameAndType but found {:?} " , index , self . get_classname ( ) ? , pool_entry ) ) )
2024-09-02 11:28:00 +02:00
} ;
}
2024-09-05 00:33:14 +02:00
pub fn pool_string_entry ( & self , index : u16 ) -> Result < & ConstantStringInfo , Error > {
let pool_entry = self . pool_entry ( index ) ? ;
return match pool_entry {
ConstantPoolInfo ::String ( data ) = > Ok ( data ) ,
_ = > Err ( Error ::BadFileError ( format! ( " Expected constant pool entry {} in class {} to be of type String but found {:?} " , index , self . get_classname ( ) ? , pool_entry ) ) )
} ;
}
pub fn gather_string ( & self , index : u16 ) -> Result < & String , Error > {
let string = self . pool_string_entry ( index ) ? ;
return Ok ( & ( self . pool_utf8_entry ( string . string_index ) ? . utf8 ) ) ;
}
pub fn gather_nameandtype ( & self , index : u16 ) -> Result < ( & String , & String ) , Error > {
let nameandtype = self . pool_nameandtype_entry ( index ) ? ;
let name = & self . pool_utf8_entry ( nameandtype . name_index ) ? . utf8 ;
let descriptor = & self . pool_utf8_entry ( nameandtype . descriptor_index ) ? . utf8 ;
Ok ( ( name , descriptor ) )
}
pub fn gather_fieldref ( & self , index : u16 ) -> Result < ( & String , & String , & String ) , Error > {
let fieldref = self . pool_fieldref_entry ( index ) ? ;
let ( field_name , field_descriptor ) = self . gather_nameandtype ( fieldref . name_and_type_index ) ? ;
let class_name = self . gather_class ( fieldref . class_index ) ? ;
Ok ( ( class_name , field_name , field_descriptor ) )
}
pub fn gather_class ( & self , index : u16 ) -> Result < & String , Error > {
let class_entry = self . pool_class_entry ( index ) ? ;
let class_name_entry = self . pool_utf8_entry ( class_entry . name_index ) ? ;
let class_name = & class_name_entry . utf8 ;
Ok ( class_name )
}
2024-09-02 11:28:00 +02:00
pub fn gather_methodref ( & self , index : u16 ) -> Result < ( & String , & String , & String ) , Error > {
let methodref = self . pool_methodref_entry ( index ) ? ;
let class_entry = self . pool_class_entry ( methodref . class_index ) ? ;
let class_name_entry = self . pool_utf8_entry ( class_entry . name_index ) ? ;
let name_and_type_entry = self . pool_nameandtype_entry ( methodref . name_and_type_index ) ? ;
let class_name = & class_name_entry . utf8 ;
let method_name = & self . pool_utf8_entry ( name_and_type_entry . name_index ) ? . utf8 ;
let method_descriptor = & self . pool_utf8_entry ( name_and_type_entry . descriptor_index ) ? . utf8 ;
return Ok ( ( class_name , method_name , method_descriptor ) ) ;
}
2024-08-29 14:48:40 +02:00
}
#[ derive(Debug) ]
pub struct FieldInfo {
2024-09-02 17:44:59 +02:00
pub access_flags : FieldAccessFlagMask ,
pub name : String ,
pub descriptor : AbstractTypeDescription ,
pub attributes : Box < [ AttributeInfo ] > ,
2024-08-29 14:48:40 +02:00
}
impl FieldInfo {
fn from_reader ( reader : & mut dyn Read , pool : & Box < [ ConstantPoolInfo ] > ) -> Result < Self , Error > {
2024-08-30 15:33:54 +02:00
let access_flags = FieldAccessFlagMask { mask : read_u16 ( reader ) ? } ;
let name = {
let name_index = read_u16 ( reader ) ? ;
let name_entry = pool_entry ( pool , name_index . into ( ) ) ? ;
match name_entry {
ConstantPoolInfo ::Utf8 ( utf8info ) = > utf8info . utf8 . clone ( ) ,
_ = > return Err ( Error ::BadFileError ( format! ( " Bad index into constant pool, expected type Utf8 but found {:?} " , name_entry ) ) ) ,
}
} ;
let descriptor : AbstractTypeDescription = {
let descriptor_index = read_u16 ( reader ) ? ;
let descriptor_entry = pool_entry ( pool , descriptor_index . into ( ) ) ? ;
match descriptor_entry {
ConstantPoolInfo ::Utf8 ( utf8info ) = > {
let borrow = & utf8info . utf8 ;
let ( length_parsed , type_desc ) = AbstractTypeDescription ::parse_first ( borrow ) ? ;
if length_parsed ! = borrow . len ( ) {
Err ( Error ::BadFileError ( format! ( " Bad field descriptor found: {} " , borrow ) ) ) ?
}
type_desc
}
_ = > return Err ( Error ::BadFileError ( format! ( " Bad index into constant pool, expected type Utf8 but found {:?} " , descriptor_entry ) ) ) ,
}
} ;
let attributes = AttributeInfo ::array_from_reader ( reader , pool , true ) ? ;
2024-08-29 14:48:40 +02:00
Ok (
FieldInfo {
2024-08-30 15:33:54 +02:00
access_flags ,
name ,
descriptor ,
attributes
2024-08-29 14:48:40 +02:00
}
)
}
}
#[ derive(Debug) ]
pub struct ConstantValueAttributeData {
2024-09-02 19:28:22 +02:00
pub constant_value_index : u16 ,
2024-08-29 14:48:40 +02:00
}
#[ derive(Debug) ]
pub struct UnknownAttributeData {
info : Box < [ u8 ] >
}
#[ derive(Debug) ]
pub struct LineNumberTableEntry {
start_pc : u16 ,
line_number : u16 ,
}
impl LineNumberTableEntry {
fn from_reader ( reader : & mut dyn Read ) -> Result < Self , Error > {
let start_pc = read_u16 ( reader ) ? ;
let line_number = read_u16 ( reader ) ? ;
Ok (
LineNumberTableEntry {
start_pc ,
line_number
}
)
}
}
#[ derive(Debug) ]
pub struct LineNumberTableAttributeData {
entries : Box < [ LineNumberTableEntry ] >
}
impl LineNumberTableAttributeData {
fn from_reader ( reader : & mut dyn Read ) -> Result < Self , Error > {
let length = read_u16 ( reader ) ? ;
let mut entry_vec = Vec ::with_capacity ( length . into ( ) ) ;
for _i in 0 .. length {
entry_vec . push ( LineNumberTableEntry ::from_reader ( reader ) ? ) ;
}
Ok (
LineNumberTableAttributeData {
entries : entry_vec . into_boxed_slice ( )
}
)
}
}
2024-08-29 18:33:03 +02:00
#[ derive(Debug) ]
pub struct ExceptionTableEntry {
start_pc : u16 ,
end_pc : u16 ,
handler_pc : u16 ,
catch_type : u16 ,
}
impl ExceptionTableEntry {
fn from_reader ( reader : & mut dyn Read ) -> Result < Self , Error > {
Ok (
ExceptionTableEntry {
start_pc : read_u16 ( reader ) ? ,
end_pc : read_u16 ( reader ) ? ,
handler_pc : read_u16 ( reader ) ? ,
catch_type : read_u16 ( reader ) ? ,
}
)
}
}
#[ derive(Debug) ]
pub struct CodeAttributeData {
2024-08-30 15:33:54 +02:00
pub max_stack : u16 ,
pub max_locals : u16 ,
pub code : Bytecode ,
pub exception_table : Box < [ ExceptionTableEntry ] > ,
pub attributes : Box < [ AttributeInfo ] > ,
2024-08-29 18:33:03 +02:00
}
impl CodeAttributeData {
fn from_reader ( reader : & mut dyn Read , pool : & Box < [ ConstantPoolInfo ] > ) -> Result < Self , Error > {
let max_stack = read_u16 ( reader ) ? ;
let max_locals = read_u16 ( reader ) ? ;
let code_length = read_u32 ( reader ) ? ;
let code = read_buffer ( reader , code_length . try_into ( ) ? ) ? ;
let exception_length = read_u16 ( reader ) ? ;
let exception_table = {
let mut v = Vec ::with_capacity ( exception_length . into ( ) ) ;
for _i in 0 .. exception_length {
v . push ( ExceptionTableEntry ::from_reader ( reader ) ? ) ;
}
v . into_boxed_slice ( )
} ;
let attributes = AttributeInfo ::array_from_reader ( reader , pool , false ) ? ;
Ok (
CodeAttributeData {
max_stack ,
max_locals ,
2024-09-02 11:28:00 +02:00
code : Bytecode { bytes : code } ,
2024-08-29 18:33:03 +02:00
exception_table ,
attributes
}
)
}
}
#[ derive(Debug) ]
pub struct SourceFileAttributeData {
source_file_index : u16 ,
}
impl SourceFileAttributeData {
fn from_reader ( reader : & mut dyn Read ) -> Result < Self , Error > {
Ok (
SourceFileAttributeData {
source_file_index : read_u16 ( reader ) ? ,
}
)
}
}
#[ derive(Debug) ]
pub struct SignatureAttributeData {
signature_index : u16 ,
}
impl SignatureAttributeData {
fn from_reader ( reader : & mut dyn Read ) -> Result < Self , Error > {
Ok (
SignatureAttributeData {
signature_index : read_u16 ( reader ) ? ,
}
)
}
}
#[ derive(Debug) ]
pub struct InnerClassesAttributeEntry {
inner_class_info_index : u16 ,
outer_class_info_index : u16 ,
inner_name_index : u16 ,
outer_name_index : u16 ,
}
impl InnerClassesAttributeEntry {
fn from_reader ( reader : & mut dyn Read ) -> Result < Self , Error > {
Ok (
InnerClassesAttributeEntry {
inner_class_info_index : read_u16 ( reader ) ? ,
outer_class_info_index : read_u16 ( reader ) ? ,
inner_name_index : read_u16 ( reader ) ? ,
outer_name_index : read_u16 ( reader ) ? ,
}
)
}
}
#[ derive(Debug) ]
pub struct InnerClassesAttributeData {
classes : Box < [ InnerClassesAttributeEntry ] >
}
impl InnerClassesAttributeData {
fn from_reader ( reader : & mut dyn Read ) -> Result < Self , Error > {
Ok (
InnerClassesAttributeData {
classes : {
let length = read_u16 ( reader ) ? ;
let mut v = Vec ::with_capacity ( length . into ( ) ) ;
for _i in 0 .. length {
v . push ( InnerClassesAttributeEntry ::from_reader ( reader ) ? ) ;
}
v . into_boxed_slice ( )
}
}
)
}
}
#[ derive(Debug) ]
pub struct NestMembersAttributeData {
class_indices : Box < [ u16 ] >
}
impl NestMembersAttributeData {
fn from_reader ( reader : & mut dyn Read ) -> Result < Self , Error > {
Ok (
NestMembersAttributeData {
class_indices : {
let length = read_u16 ( reader ) ? ;
let mut v = Vec ::with_capacity ( length . into ( ) ) ;
for _i in 0 .. length {
v . push ( read_u16 ( reader ) ? ) ;
}
v . into_boxed_slice ( )
}
}
)
}
}
2024-08-29 14:48:40 +02:00
#[ derive(Debug) ]
pub enum AttributeData {
2024-08-29 18:33:03 +02:00
Code ( CodeAttributeData ) ,
Signature ( SignatureAttributeData ) ,
2024-09-02 17:44:59 +02:00
Synthetic ( ) ,
Exceptions ( ExceptionAttributeData ) ,
2024-08-29 18:33:03 +02:00
NestMembers ( NestMembersAttributeData ) ,
SourceFile ( SourceFileAttributeData ) ,
InnerClasses ( InnerClassesAttributeData ) ,
2024-08-29 14:48:40 +02:00
ConstantValue ( ConstantValueAttributeData ) ,
2024-09-02 17:44:59 +02:00
DebugExtension ( DebugExtensionAttributeData ) ,
2024-08-29 14:48:40 +02:00
LineNumberTable ( LineNumberTableAttributeData ) ,
2024-09-02 17:44:59 +02:00
EnclosingMethod ( EnclosingMethodAttributeData ) ,
2024-08-29 18:33:03 +02:00
Unknown ( UnknownAttributeData ) ,
2024-08-29 14:48:40 +02:00
}
#[ derive(Debug) ]
pub struct AttributeInfo {
2024-08-30 15:33:54 +02:00
pub attribute_name_index : u16 ,
pub data : AttributeData
2024-08-29 14:48:40 +02:00
}
impl AttributeInfo {
2024-08-29 18:33:03 +02:00
fn array_from_reader ( reader : & mut dyn Read , pool : & Box < [ ConstantPoolInfo ] > , allow_code_attr : bool ) -> Result < Box < [ Self ] > , Error > {
2024-08-29 14:48:40 +02:00
let length = read_u16 ( reader ) ? ;
let mut attr_vec = Vec ::with_capacity ( length . into ( ) ) ;
for _i in 0 .. length {
2024-08-29 18:33:03 +02:00
let attribute = AttributeInfo ::from_reader ( reader , & pool , allow_code_attr ) ? ;
2024-08-29 14:54:00 +02:00
attr_vec . push ( attribute ) ;
2024-08-29 14:48:40 +02:00
}
Ok ( attr_vec . into_boxed_slice ( ) )
}
2024-08-29 18:33:03 +02:00
fn from_reader ( reader : & mut dyn Read , pool : & Box < [ ConstantPoolInfo ] > , allow_code_attr : bool ) -> Result < Self , Error > {
let attribute_name_index : u16 = read_u16 ( reader ) ? - 1 ;
2024-09-02 17:44:59 +02:00
let attribute_byte_size : usize = read_u32 ( reader ) ? . try_into ( ) ? ;
2024-08-29 14:48:40 +02:00
let data = {
let name_entry = & pool [ attribute_name_index as usize ] ;
let utf8 = match name_entry {
2024-08-29 19:32:05 +02:00
ConstantPoolInfo ::Utf8 ( ConstantUtf8Info { utf8 } ) = > utf8 ,
2024-08-29 14:48:40 +02:00
_ = > return Err ( Error ::BadFileError ( format! ( " Bad name index for attribute info: {} " , attribute_name_index ) ) ) ,
} ;
match & utf8 [ .. ] {
2024-09-02 17:44:59 +02:00
" ConstantValue " = > AttributeData ::ConstantValue (
2024-08-29 18:33:03 +02:00
ConstantValueAttributeData {
constant_value_index : read_u16 ( reader ) ? ,
}
2024-09-02 17:44:59 +02:00
) ,
2024-08-29 18:33:03 +02:00
2024-09-02 17:44:59 +02:00
" LineNumberTable " = > AttributeData ::LineNumberTable (
2024-08-29 18:33:03 +02:00
LineNumberTableAttributeData ::from_reader ( reader ) ?
2024-09-02 17:44:59 +02:00
) ,
2024-08-29 18:33:03 +02:00
2024-09-02 17:44:59 +02:00
" Code " = > if allow_code_attr {
2024-08-29 18:33:03 +02:00
AttributeData ::Code (
CodeAttributeData ::from_reader ( reader , pool ) ?
)
2024-09-02 17:44:59 +02:00
} else {
2024-08-29 18:33:03 +02:00
return Err ( Error ::BadFileError ( " Nested Code attributes are forbidden. " . to_string ( ) ) ) ;
2024-09-02 17:44:59 +02:00
} ,
" SourceFile " = > AttributeData ::SourceFile ( SourceFileAttributeData ::from_reader ( reader ) ? ) ,
" Signature " = > AttributeData ::Signature ( SignatureAttributeData ::from_reader ( reader ) ? ) ,
" InnerClasses " = > AttributeData ::InnerClasses ( InnerClassesAttributeData ::from_reader ( reader ) ? ) ,
2024-08-29 18:33:03 +02:00
2024-09-02 17:44:59 +02:00
" NestMembers " = > AttributeData ::NestMembers ( NestMembersAttributeData ::from_reader ( reader ) ? ) ,
2024-08-29 18:33:03 +02:00
2024-09-02 17:44:59 +02:00
" Exceptions " = > AttributeData ::Exceptions ( ExceptionAttributeData ::from_reader ( reader ) ? ) ,
2024-08-29 18:33:03 +02:00
2024-09-02 17:44:59 +02:00
" EnclosingMethod " = > AttributeData ::EnclosingMethod ( EnclosingMethodAttributeData { class_index : read_u16 ( reader ) ? , method_index : read_u16 ( reader ) ? } ) ,
2024-08-29 18:33:03 +02:00
2024-09-02 17:44:59 +02:00
" Synthetic " = > AttributeData ::Synthetic ( ) ,
" DebugExtension " = > AttributeData ::DebugExtension (
DebugExtensionAttributeData {
utf8 : std ::str ::from_utf8 ( & ( read_buffer ( reader , attribute_byte_size ) ? ) ) ? . to_string ( ) ,
}
) ,
2024-08-29 18:33:03 +02:00
& _ = > AttributeData ::Unknown (
2024-08-29 14:48:40 +02:00
UnknownAttributeData {
2024-09-02 17:44:59 +02:00
info : read_buffer ( reader , attribute_byte_size ) ? ,
2024-08-29 14:48:40 +02:00
}
)
}
} ;
Ok (
AttributeInfo {
attribute_name_index ,
data
}
)
}
}
2024-09-02 17:44:59 +02:00
#[ derive(Debug) ]
pub struct DebugExtensionAttributeData {
utf8 : String ,
}
#[ derive(Debug) ]
pub struct EnclosingMethodAttributeData {
class_index : u16 ,
method_index : u16 ,
}
// for use on methods, what exception can be thrown by this
#[ derive(Debug) ]
pub struct ExceptionAttributeData {
exception_indices : Box < [ u16 ] > ,
}
impl ExceptionAttributeData {
fn from_reader ( reader : & mut dyn Read ) -> Result < Self , Error > {
let length = read_u16 ( reader ) ? ;
let mut exception_vector = Vec ::with_capacity ( length as usize ) ;
for _ in 0 .. length {
exception_vector . push ( read_u16 ( reader ) ? ) ;
}
Ok (
ExceptionAttributeData {
exception_indices : exception_vector . into_boxed_slice ( )
}
)
}
}
2024-08-30 15:33:54 +02:00
#[ repr(u8) ]
2024-09-05 00:33:14 +02:00
#[ derive(Debug, Eq, PartialEq, Clone, Hash) ]
2024-08-30 15:33:54 +02:00
pub enum AbstractTypeKind {
Void ( ) = b 'V' , // void
Byte ( ) = b 'B' , // signed byte
Char ( ) = b 'C' , // Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16
Double ( ) = b 'D' , // double-precision floating-point value
Float ( ) = b 'F' , // single-precision floating-point value
Int ( ) = b 'I' , // integer
Long ( ) = b 'J' , // long integer
Classname ( String ) = b 'L' , // an instance of class ClassName
Short ( ) = b 'S' , // signed short
Boolean ( ) = b 'Z' , // true or false
2024-08-29 14:48:40 +02:00
}
2024-09-02 11:28:00 +02:00
impl Into < String > for & AbstractTypeKind {
fn into ( self ) -> String {
match self {
AbstractTypeKind ::Void ( ) = > " V " . to_string ( ) ,
AbstractTypeKind ::Byte ( ) = > " B " . to_string ( ) ,
AbstractTypeKind ::Char ( ) = > " C " . to_string ( ) ,
AbstractTypeKind ::Double ( ) = > " D " . to_string ( ) ,
AbstractTypeKind ::Float ( ) = > " F " . to_string ( ) ,
AbstractTypeKind ::Int ( ) = > " I " . to_string ( ) ,
AbstractTypeKind ::Long ( ) = > " J " . to_string ( ) ,
AbstractTypeKind ::Classname ( name ) = > " L " . to_string ( ) + & name + " ; " ,
AbstractTypeKind ::Short ( ) = > " S " . to_string ( ) ,
AbstractTypeKind ::Boolean ( ) = > " Z " . to_string ( ) ,
}
}
}
2024-09-05 00:33:14 +02:00
#[ derive(Debug, Eq, PartialEq, Clone, Hash) ]
2024-08-30 15:33:54 +02:00
pub struct AbstractTypeDescription {
2024-09-02 11:28:00 +02:00
pub array_level : u8 ,
pub kind : AbstractTypeKind ,
}
impl Into < String > for & AbstractTypeDescription {
fn into ( self ) -> String {
let name_len = match self . kind {
AbstractTypeKind ::Classname ( ref s ) = > 2 + s . len ( ) ,
_ = > 1 ,
} ;
let mut s = String ::with_capacity ( self . array_level as usize + name_len ) ;
s . push_str ( & " [ " . repeat ( self . array_level as usize ) ) ;
let kind_string : String = ( & self . kind ) . into ( ) ;
s . push_str ( & kind_string ) ;
s
}
2024-08-30 15:33:54 +02:00
}
impl AbstractTypeDescription {
2024-09-06 21:11:03 +02:00
pub fn parse_full ( s : & str ) -> Result < Self , Error > {
let ( c , parsed ) = Self ::parse_first ( s ) ? ;
assert! ( c = = s . len ( ) ) ;
Ok ( parsed )
}
2024-09-05 00:33:14 +02:00
pub fn parse_first ( s : & str ) -> Result < ( usize , Self ) , Error > {
2024-08-30 15:33:54 +02:00
let mut offset : usize = 0 ;
let arrays_parsed = s . trim_start_matches ( " [ " ) ;
let array_level = ( s . len ( ) - arrays_parsed . len ( ) ) . try_into ( ) ;
let array_level : u8 = match array_level {
Ok ( s ) = > s ,
Err ( _e ) = > return Err ( Error ::BadFileError ( format! ( " Too many array levels in method descriptor! Max is 255 but found {} " , s . len ( ) - arrays_parsed . len ( ) ) ) ) ,
} ;
offset + = array_level as usize ;
let type_char = arrays_parsed . chars ( ) . nth ( 0 ) . ok_or ( Error ::BadFileError ( " Missing type char in method descriptor " . to_string ( ) ) ) ? ;
offset + = 1 ;
let kind = match type_char {
'B' = > AbstractTypeKind ::Byte ( ) ,
'C' = > AbstractTypeKind ::Char ( ) ,
'D' = > AbstractTypeKind ::Double ( ) ,
'F' = > AbstractTypeKind ::Float ( ) ,
'I' = > AbstractTypeKind ::Int ( ) ,
'J' = > AbstractTypeKind ::Long ( ) ,
'S' = > AbstractTypeKind ::Short ( ) ,
'Z' = > AbstractTypeKind ::Boolean ( ) ,
'V' = > AbstractTypeKind ::Void ( ) ,
'L' = > {
let semicolon_index = s . get ( offset .. ) . unwrap ( ) . find ( " ; " ) . ok_or ( Error ::BadFileError ( format! ( " Missing ';' in type descriptor: {} " , s ) ) ) ? ;
let classname_start = offset ;
let classname_end = offset + semicolon_index ;
let classname_string = s . get ( classname_start .. classname_end ) . unwrap ( ) ;
offset + = classname_string . len ( ) + 1 ;
AbstractTypeKind ::Classname ( classname_string . to_string ( ) )
2024-08-29 14:48:40 +02:00
}
2024-09-05 00:33:14 +02:00
_ = > return Err ( Error ::BadFileError ( format! ( " Invalid Type character: ' {} ' in string ' {} ' " , type_char , s ) ) ) ,
2024-08-30 15:33:54 +02:00
} ;
return Ok ( ( offset , AbstractTypeDescription { array_level , kind } ) )
2024-08-29 14:48:40 +02:00
}
}
2024-09-02 11:28:00 +02:00
#[ derive(Debug, Eq, PartialEq) ]
2024-08-30 15:33:54 +02:00
pub struct MethodDescriptor {
2024-09-02 11:28:00 +02:00
pub argument_types : Box < [ AbstractTypeDescription ] > ,
pub return_type : AbstractTypeDescription ,
}
impl MethodDescriptor {
pub fn source_string ( & self ) -> String {
let mut s = " " . to_string ( ) ;
s + = " ( " ;
for argument_type in & self . argument_types {
let arg_string : String = argument_type . into ( ) ;
s . push_str ( & arg_string ) ;
}
s + = " ) " ;
let return_string : String = ( & self . return_type ) . into ( ) ;
s . push_str ( & return_string ) ;
s
}
2024-08-29 19:32:05 +02:00
}
2024-08-30 15:33:54 +02:00
impl TryFrom < & String > for MethodDescriptor {
type Error = Error ;
2024-08-29 19:32:05 +02:00
2024-08-30 15:33:54 +02:00
fn try_from ( s : & String ) -> Result < Self , Error > {
2024-08-29 19:32:05 +02:00
2024-08-30 15:33:54 +02:00
let mut total_offset : usize = 0 ;
s . strip_prefix ( " ( " )
. ok_or ( Error ::BadFileError ( format! ( " Bad method descriptor: ' {} ' " , s ) ) ) ? ;
total_offset + = 1 ;
2024-08-29 19:32:05 +02:00
2024-08-30 15:33:54 +02:00
let mut args = Vec ::new ( ) ;
while ! s . get ( total_offset .. ) . unwrap ( ) . starts_with ( " ) " ) {
let ( offset , arg_type ) = AbstractTypeDescription ::parse_first ( s . get ( total_offset .. ) . unwrap ( ) ) ? ;
total_offset + = offset ;
args . push ( arg_type ) ;
}
s . get ( total_offset .. ) . unwrap ( )
. strip_prefix ( " ) " )
2024-09-05 00:33:14 +02:00
// unreachable?
2024-08-30 15:33:54 +02:00
. ok_or ( Error ::BadFileError ( format! ( " Bad method descriptor " ) ) ) ? ;
total_offset + = 1 ;
let ( offset , return_type ) = AbstractTypeDescription ::parse_first ( s . get ( total_offset .. ) . unwrap ( ) ) ? ;
if offset ! = s . get ( total_offset .. ) . unwrap ( ) . len ( ) {
2024-09-05 00:33:14 +02:00
return Err ( Error ::BadFileError ( format! ( " Trailing characters in method descriptor string: ' {} ' " , s ) ) )
2024-08-29 19:32:05 +02:00
}
2024-08-30 15:33:54 +02:00
Ok (
MethodDescriptor {
argument_types : args . into_boxed_slice ( ) ,
return_type ,
}
)
2024-08-29 19:32:05 +02:00
}
}
2024-09-02 11:28:00 +02:00
impl Into < String > for & MethodDescriptor {
fn into ( self ) -> String {
return self . source_string ( )
}
}
2024-08-30 15:33:54 +02:00
#[ derive(Debug) ]
pub struct MethodInfo {
pub access_flags : MethodAccessFlagMask ,
pub name : String ,
pub descriptor : MethodDescriptor ,
pub code_attribute_index : usize ,
pub attributes : Box < [ AttributeInfo ] > ,
2024-08-29 19:32:05 +02:00
}
2024-08-30 15:33:54 +02:00
impl MethodInfo {
fn from_reader ( reader : & mut dyn Read , pool : & Box < [ ConstantPoolInfo ] > ) -> Result < Self , Error > {
let access_flags = MethodAccessFlagMask { mask : read_u16 ( reader ) ? } ;
let name = {
let name_index = read_u16 ( reader ) ? ;
2024-08-29 19:32:05 +02:00
2024-08-30 15:33:54 +02:00
let name_entry = pool_entry ( pool , name_index . into ( ) ) ? ;
2024-08-29 19:32:05 +02:00
2024-08-30 15:33:54 +02:00
match name_entry {
ConstantPoolInfo ::Utf8 ( utf8info ) = > utf8info . utf8 . clone ( ) ,
_ = > return Err ( Error ::BadFileError ( format! ( " Bad index into constant pool, expected type Utf8 but found {:?} " , name_entry ) ) ) ,
2024-08-29 19:32:05 +02:00
}
2024-08-30 15:33:54 +02:00
} ;
let descriptor : MethodDescriptor = {
let descriptor_index = read_u16 ( reader ) ? ;
let descriptor_entry = pool_entry ( pool , descriptor_index . into ( ) ) ? ;
match descriptor_entry {
ConstantPoolInfo ::Utf8 ( utf8info ) = > {
let borrow = & utf8info . utf8 ;
borrow . try_into ( ) ?
}
_ = > return Err ( Error ::BadFileError ( format! ( " Bad index into constant pool, expected type Utf8 but found {:?} " , descriptor_entry ) ) ) ,
}
} ;
let attributes = AttributeInfo ::array_from_reader ( reader , pool , true ) ? ;
let code_attribute_index = attributes . iter ( )
. position ( | info | match info . data { AttributeData ::Code ( _ ) = > true , _ = > false } )
. unwrap_or ( attributes . len ( ) ) ;
2024-08-29 19:32:05 +02:00
2024-08-30 15:33:54 +02:00
Ok (
MethodInfo {
access_flags ,
name ,
descriptor ,
code_attribute_index ,
attributes
}
)
2024-08-29 19:32:05 +02:00
}
2024-09-02 11:28:00 +02:00
pub fn get_code_attribute ( & self ) -> Option < & CodeAttributeData > {
return if self . code_attribute_index ! = self . attributes . len ( ) {
match & self . attributes [ self . code_attribute_index ] . data {
AttributeData ::Code ( data ) = > Some ( data ) ,
_ = > None ,
}
} else {
None
} ;
}
2024-08-29 19:32:05 +02:00
}
2024-08-30 15:48:12 +02:00
pub fn read_buffer ( reader : & mut dyn Read , size : usize ) -> Result < Box < [ u8 ] > , Error > {
2024-08-29 14:54:00 +02:00
let mut buffer : Box < [ u8 ] > = vec! [ 0 ; size ] . into_boxed_slice ( ) ;
2024-08-29 14:48:40 +02:00
reader . read_exact ( & mut buffer ) ? ;
Ok ( buffer )
}
2024-08-30 15:48:12 +02:00
pub fn read_f64 ( reader : & mut dyn Read ) -> Result < f64 , std ::io ::Error > {
2024-08-29 14:48:40 +02:00
// let bytes = read_u64(reader)?;
//
// let sign = if (bytes >> 63) == 0 { 1 } else { -1 } as f64;
// let exponent: f64 = ((bytes >> 52) & 0x7FF) as f64;
// let mantissa: f64 = if exponent == 0.0 {
// (bytes & 0xfffffffffffff) << 1
// } else {
// (bytes & 0xfffffffffffff) | 0x10000000000000
// } as f64;
// let base: f64 = 2.0;
//
//
// return Ok(sign * mantissa * base.powf(exponent-1075.0));
let mut buffer : [ u8 ; 8 ] = [ 0 ; 8 ] ;
reader . read_exact ( & mut buffer ) ? ;
return Ok ( f64 ::from_be_bytes ( buffer ) ) ;
}
2024-08-30 15:48:12 +02:00
pub fn read_f32 ( reader : & mut dyn Read ) -> Result < f32 , std ::io ::Error > {
2024-08-29 14:48:40 +02:00
let mut buffer : [ u8 ; 4 ] = [ 0 ; 4 ] ;
reader . read_exact ( & mut buffer ) ? ;
return Ok ( f32 ::from_be_bytes ( buffer ) ) ;
}
2024-08-30 15:48:12 +02:00
pub fn read_i32 ( reader : & mut dyn Read ) -> Result < i32 , std ::io ::Error > {
2024-08-29 14:48:40 +02:00
let mut buffer : [ u8 ; 4 ] = [ 0 ; 4 ] ;
reader . read_exact ( & mut buffer ) ? ;
return Ok ( i32 ::from_be_bytes ( buffer ) ) ;
}
2024-09-05 00:33:14 +02:00
pub fn read_i64 ( reader : & mut dyn Read ) -> Result < i64 , std ::io ::Error > {
let mut buffer : [ u8 ; 8 ] = [ 0 ; 8 ] ;
reader . read_exact ( & mut buffer ) ? ;
2024-08-29 14:48:40 +02:00
2024-09-05 00:33:14 +02:00
return Ok ( i64 ::from_be_bytes ( buffer ) ) ;
2024-08-29 14:48:40 +02:00
}
2024-08-30 15:48:12 +02:00
pub fn read_u32 ( reader : & mut dyn Read ) -> Result < u32 , std ::io ::Error > {
2024-08-29 14:48:40 +02:00
let mut u32_buffer : [ u8 ; 4 ] = [ 0 ; 4 ] ;
reader . read_exact ( & mut u32_buffer ) ? ;
return Ok ( u32 ::from_be_bytes ( u32_buffer ) ) ;
}
2024-08-30 15:48:12 +02:00
pub fn read_u16 ( reader : & mut dyn Read ) -> Result < u16 , std ::io ::Error > {
2024-08-29 14:48:40 +02:00
let mut u16_buffer : [ u8 ; 2 ] = [ 0 ; 2 ] ;
reader . read_exact ( & mut u16_buffer ) ? ;
return Ok ( u16 ::from_be_bytes ( u16_buffer ) ) ;
}
2024-08-30 15:48:12 +02:00
pub fn read_u8 ( reader : & mut dyn Read ) -> Result < u8 , std ::io ::Error > {
2024-08-29 14:48:40 +02:00
let mut u8_buffer : [ u8 ; 1 ] = [ 0 ; 1 ] ;
reader . read_exact ( & mut u8_buffer ) ? ;
return Ok ( u8 ::from_be_bytes ( u8_buffer ) ) ;
}
2024-08-30 15:33:54 +02:00
2024-09-02 19:28:22 +02:00
fn pool_entry ( constant_pool : & Box < [ ConstantPoolInfo ] > , index : u16 ) -> Result < & ConstantPoolInfo , Error > {
2024-08-30 15:33:54 +02:00
if index = = 0 {
return Err ( Error ::BadFileError ( format! ( " Bad pool index: 0 " ) ) ) ;
}
2024-09-02 19:28:22 +02:00
if usize ::from ( index - 1 ) > = constant_pool . len ( ) {
2024-08-30 15:33:54 +02:00
return Err ( Error ::BadFileError ( format! ( " Bad pool index: {} " , index - 1 ) ) ) ;
}
2024-09-02 19:28:22 +02:00
return Ok ( & constant_pool [ usize ::from ( index - 1 ) ] ) ;
2024-08-30 15:33:54 +02:00
}