mirror of
https://github.com/Noratrieb/coldsquare.git
synced 2026-01-14 16:35:10 +01:00
resolves attributes now
This commit is contained in:
parent
750508714a
commit
55c1107be5
3 changed files with 211 additions and 30 deletions
194
src/parse/mod.rs
194
src/parse/mod.rs
|
|
@ -16,11 +16,15 @@ struct Data<'a> {
|
|||
}
|
||||
|
||||
pub fn parse_class_file(data: &[u1]) -> Result<ClassFile> {
|
||||
let mut data = Data { data, pointer: 0 };
|
||||
let mut data = Data::new(data);
|
||||
ClassFile::parse(&mut data)
|
||||
}
|
||||
|
||||
impl<'a> Data<'a> {
|
||||
fn new(data: &'a [u1]) -> Self {
|
||||
Data { data, pointer: 0 }
|
||||
}
|
||||
|
||||
fn u1(&mut self) -> Result<u1> {
|
||||
let item = self.data.get(self.pointer).cloned();
|
||||
self.pointer += 1;
|
||||
|
|
@ -116,7 +120,7 @@ impl Parse for ClassFile {
|
|||
let attributes_count = data.u2()?;
|
||||
let attributes = parse_vec(data, attributes_count)?;
|
||||
|
||||
Ok(Self {
|
||||
let mut class = Self {
|
||||
magic,
|
||||
minor_version,
|
||||
major_version,
|
||||
|
|
@ -133,7 +137,9 @@ impl Parse for ClassFile {
|
|||
methods,
|
||||
attributes_count,
|
||||
attributes,
|
||||
})
|
||||
};
|
||||
resolve_attributes(&mut class)?;
|
||||
Ok(class)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -191,7 +197,8 @@ impl Parse for CpInfo {
|
|||
1 => Self::Utf8 {
|
||||
tag,
|
||||
length: data.u2()?,
|
||||
bytes: parse_vec(data, data.last_u2()?)?,
|
||||
bytes: String::from_utf8(parse_vec(data, data.last_u2()?)?)
|
||||
.map_err(|err| ParseErr(format!("Invalid utf8 in CpInfo::Utf8: {}", err)))?,
|
||||
},
|
||||
15 => Self::MethodHandle {
|
||||
tag,
|
||||
|
|
@ -236,9 +243,9 @@ impl Parse for MethodInfo {
|
|||
}
|
||||
}
|
||||
|
||||
impl Parse for Attribute {
|
||||
impl Parse for AttributeInfo {
|
||||
fn parse(data: &mut Data) -> Result<Self> {
|
||||
Ok(Self {
|
||||
Ok(Self::Unknown {
|
||||
attribute_name_index: data.u2()?,
|
||||
attribute_length: data.u4()?,
|
||||
attribute_content: parse_vec(data, data.last_u4()? as usize)?,
|
||||
|
|
@ -433,3 +440,178 @@ impl Parse for BootstrapMethod {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_attributes(class: &mut ClassFile) -> Result<()> {
|
||||
let pool = &class.constant_pool;
|
||||
|
||||
class
|
||||
.attributes
|
||||
.iter_mut()
|
||||
.map(|attr| AttributeInfo::resolve_attribute(attr, pool))
|
||||
.collect::<Result<Vec<()>>>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl AttributeInfo {
|
||||
fn resolve_attribute(&mut self, pool: &[CpInfo]) -> Result<()> {
|
||||
// this is a borrow checker hack, but it works :(
|
||||
let attr = std::mem::replace(self, AttributeInfo::__Empty);
|
||||
|
||||
let (&index, &len, content) = match &attr {
|
||||
AttributeInfo::Unknown {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
attribute_content,
|
||||
} => (attribute_name_index, attribute_length, attribute_content),
|
||||
_ => unreachable!("Attribute already resolved"),
|
||||
};
|
||||
let info = match pool.get(index as usize - 1) {
|
||||
Some(CpInfo::Utf8 { bytes, .. }) => bytes,
|
||||
Some(_) => return Err(ParseErr("Attribute name is not CpInfo::Utf8".to_string())),
|
||||
_ => return Err(ParseErr("Constant Pool index out of Bounds".to_string())),
|
||||
};
|
||||
|
||||
let mut data = Data::new(&content);
|
||||
self.resolve_attribute_inner(index, len, info, &mut data)
|
||||
}
|
||||
|
||||
fn resolve_attribute_inner(
|
||||
&mut self,
|
||||
attribute_name_index: u16,
|
||||
attribute_length: u32,
|
||||
name: &str,
|
||||
data: &mut Data,
|
||||
) -> Result<()> {
|
||||
let _ = std::mem::replace(
|
||||
self,
|
||||
match name {
|
||||
"ConstantValue" => Self::ConstantValue {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
constantvalue_index: data.u2()?,
|
||||
},
|
||||
"Code" => Self::Code {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
max_stack: data.u2()?,
|
||||
max_locals: data.u2()?,
|
||||
code_length: data.u4()?,
|
||||
code: parse_vec(data, data.last_u4()? as usize)?,
|
||||
exception_table_length: data.u2()?,
|
||||
exception_table: parse_vec(data, data.last_u2()?)?,
|
||||
attributes_count: data.u2()?,
|
||||
attributes: parse_vec(data, data.last_u2()?)?,
|
||||
},
|
||||
"StackMapTable" => Self::StackMapTable {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
number_of_entries: data.u2()?,
|
||||
entries: parse_vec(data, data.last_u2()?)?,
|
||||
},
|
||||
"Exceptions" => Self::Exceptions {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
number_of_exceptions: data.u2()?,
|
||||
exception_index_table: parse_vec(data, data.last_u2()?)?,
|
||||
},
|
||||
"InnerClasses" => Self::InnerClasses {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
number_of_classes: data.u2()?,
|
||||
classes: parse_vec(data, data.last_u2()?)?,
|
||||
},
|
||||
"EnclosingMethod" => Self::EnclosingMethod {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
class_index: data.u2()?,
|
||||
method_index: data.u2()?,
|
||||
},
|
||||
"Synthetic" => Self::Synthetic {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
},
|
||||
"Signature" => Self::Signature {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
signature_index: data.u2()?,
|
||||
},
|
||||
"SourceFile" => Self::SourceFile {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
sourcefile_index: data.u2()?,
|
||||
},
|
||||
"SourceDebugExtension" => Self::SourceDebugExtension {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
debug_extension: parse_vec(data, data.last_u2()?)?,
|
||||
},
|
||||
"LineNumberTable" => Self::LineNumberTable {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
line_number_table_length: data.u2()?,
|
||||
line_number_table: parse_vec(data, data.last_u2()?)?,
|
||||
},
|
||||
"LocalVariableTable" => Self::LocalVariableTable {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
local_variable_table_length: data.u2()?,
|
||||
local_variable_table: parse_vec(data, data.last_u2()?)?,
|
||||
},
|
||||
"LocalVariableTypeTable" => Self::LocalVariableTypeTable {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
local_variable_table_length: data.u2()?,
|
||||
local_variable_table: parse_vec(data, data.last_u2()?)?,
|
||||
},
|
||||
"Deprecated" => Self::Deprecated {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
},
|
||||
"RuntimeVisibleAnnotations" => Self::RuntimeVisibleAnnotations {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
num_annotations: data.u2()?,
|
||||
annotations: parse_vec(data, data.last_u2()?)?,
|
||||
},
|
||||
"RuntimeInvisibleAnnotations" => Self::RuntimeInvisibleAnnotations {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
num_annotations: data.u2()?,
|
||||
annotations: parse_vec(data, data.last_u2()?)?,
|
||||
},
|
||||
"RuntimeVisibleParameterAnnotations" => Self::RuntimeVisibleParameterAnnotations {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
num_parameters: data.u1()?,
|
||||
parameter_annotations: parse_vec(data, data.last_u1()?)?,
|
||||
},
|
||||
"RuntimeInvisibleParameterAnnotations" => {
|
||||
Self::RuntimeInvisibleParameterAnnotations {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
num_parameters: data.u1()?,
|
||||
parameter_annotations: parse_vec(data, data.last_u1()?)?,
|
||||
}
|
||||
}
|
||||
"AnnotationDefault" => Self::AnnotationDefault {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
default_value: AnnotationElementValue {
|
||||
tag: data.u1()?,
|
||||
value: AnnotationElementValueValue::parse(data)?,
|
||||
},
|
||||
},
|
||||
"BootstrapMethods" => Self::BootstrapMethods {
|
||||
attribute_name_index,
|
||||
attribute_length,
|
||||
num_bootstrap_methods: data.u2()?,
|
||||
bootstrap_methods: parse_vec(data, data.last_u2()?)?,
|
||||
},
|
||||
name => return Err(ParseErr(format!("Invalid Attribute name: {}", name))),
|
||||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ pub struct ClassFile {
|
|||
/// The number of attributes in `attributes`
|
||||
pub attributes_count: u2,
|
||||
/// All attributes of the class
|
||||
pub attributes: Vec<Attribute>,
|
||||
pub attributes: Vec<AttributeInfo>,
|
||||
}
|
||||
|
||||
/// A constant from the constant pool
|
||||
|
|
@ -126,7 +126,7 @@ pub enum CpInfo {
|
|||
/// The length of the String. Not null-terminated.
|
||||
length: u2,
|
||||
/// Contains modified UTF-8
|
||||
bytes: Vec<u1>,
|
||||
bytes: String,
|
||||
},
|
||||
MethodHandle {
|
||||
tag: u1, // 15
|
||||
|
|
@ -157,7 +157,7 @@ pub struct FieldInfo {
|
|||
pub name_index: u2,
|
||||
pub descriptor_index: u2,
|
||||
pub attributes_count: u2,
|
||||
pub attributes: Vec<Attribute>,
|
||||
pub attributes: Vec<AttributeInfo>,
|
||||
}
|
||||
|
||||
/// Information about a method
|
||||
|
|
@ -172,15 +172,7 @@ pub struct MethodInfo {
|
|||
/// The amount of attributes for this method
|
||||
pub attributes_count: u2,
|
||||
/// The attributes for this method
|
||||
pub attributes: Vec<Attribute>,
|
||||
}
|
||||
|
||||
/// See `AttributeInfo`
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Attribute {
|
||||
pub attribute_name_index: u2,
|
||||
pub attribute_length: u4,
|
||||
pub attribute_content: Vec<u1>,
|
||||
pub attributes: Vec<AttributeInfo>,
|
||||
}
|
||||
|
||||
/// Information about an attribute
|
||||
|
|
@ -190,8 +182,15 @@ pub struct Attribute {
|
|||
///
|
||||
/// _index: Index to the `constant_pool` table of any type
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
#[allow(dead_code)] // todo yeah lol
|
||||
// todo refactor this into a struct + enum
|
||||
pub enum AttributeInfo {
|
||||
__Empty,
|
||||
/// The exact kind of attribute is not known yet and will be resolved later in the process
|
||||
Unknown {
|
||||
attribute_name_index: u2,
|
||||
attribute_length: u4,
|
||||
attribute_content: Vec<u1>,
|
||||
},
|
||||
/// Only on fields, the constant value of that field
|
||||
ConstantValue {
|
||||
attribute_name_index: u2, // "ConstantValue"
|
||||
|
|
@ -217,7 +216,7 @@ pub enum AttributeInfo {
|
|||
exception_table: Vec<AttributeCodeException>,
|
||||
attributes_count: u2,
|
||||
/// The attributes of the code
|
||||
attributes: Vec<Attribute>,
|
||||
attributes: Vec<AttributeInfo>,
|
||||
},
|
||||
/// Only on the `Code` attribute, used for verification
|
||||
/// May be implicit on version >= 50.0, with no entries
|
||||
|
|
|
|||
|
|
@ -64,17 +64,17 @@ fn parse_empty_class() {
|
|||
CpInfo::Utf8 {
|
||||
tag: 1,
|
||||
length: 0x10,
|
||||
bytes: "java/lang/Object".bytes().collect()
|
||||
bytes: "java/lang/Object".to_string()
|
||||
},
|
||||
CpInfo::Utf8 {
|
||||
tag: 1,
|
||||
length: 6,
|
||||
bytes: "<init>".bytes().collect()
|
||||
bytes: "<init>".to_string()
|
||||
},
|
||||
CpInfo::Utf8 {
|
||||
tag: 1,
|
||||
length: 3,
|
||||
bytes: "()V".bytes().collect()
|
||||
bytes: "()V".to_string()
|
||||
},
|
||||
CpInfo::Class {
|
||||
tag: 7,
|
||||
|
|
@ -83,27 +83,27 @@ fn parse_empty_class() {
|
|||
CpInfo::Utf8 {
|
||||
tag: 1,
|
||||
length: 4,
|
||||
bytes: "Test".bytes().collect()
|
||||
bytes: "Test".to_string()
|
||||
},
|
||||
CpInfo::Utf8 {
|
||||
tag: 1,
|
||||
length: 4,
|
||||
bytes: "Code".bytes().collect()
|
||||
bytes: "Code".to_string()
|
||||
},
|
||||
CpInfo::Utf8 {
|
||||
tag: 1,
|
||||
length: 15,
|
||||
bytes: "LineNumberTable".bytes().collect()
|
||||
bytes: "LineNumberTable".to_string()
|
||||
},
|
||||
CpInfo::Utf8 {
|
||||
tag: 1,
|
||||
length: 10,
|
||||
bytes: "SourceFile".bytes().collect()
|
||||
bytes: "SourceFile".to_string()
|
||||
},
|
||||
CpInfo::Utf8 {
|
||||
tag: 1,
|
||||
length: 9,
|
||||
bytes: "Test.java".bytes().collect()
|
||||
bytes: "Test.java".to_string()
|
||||
}
|
||||
]
|
||||
);
|
||||
|
|
@ -119,8 +119,8 @@ fn parse_empty_class() {
|
|||
assert_eq!(parsed.methods[0].name_index, 5);
|
||||
assert_eq!(parsed.methods[0].descriptor_index, 6);
|
||||
assert_eq!(parsed.methods[0].attributes_count, 1);
|
||||
assert_eq!(parsed.methods[0].attributes[0].attribute_name_index, 9);
|
||||
assert_eq!(parsed.methods[0].attributes[0].attribute_length, 0x1d);
|
||||
//assert_eq!(parsed.methods[0].attributes[0].attribute_name_index, 9);
|
||||
//assert_eq!(parsed.methods[0].attributes[0].attribute_length, 0x1d);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue