From 860346a91074cc9619b3e6891eb7bcce8b4b1d79 Mon Sep 17 00:00:00 2001 From: Nilstrieb Date: Sat, 21 Aug 2021 16:50:20 +0200 Subject: [PATCH] Refactored CpInfo to be more nested So I can only refer to a single variant --- src/lib.rs | 8 ++ src/main.rs | 25 ++++- src/parse/mod.rs | 250 ++++++++++++++++++++++++++++-------------- src/parse/model.rs | 266 +++++++++++++++++++++++++++------------------ src/parse/test.rs | 100 ++++++++++------- 5 files changed, 418 insertions(+), 231 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6619e4b..f850713 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,15 @@ use crate::parse::{ClassFile, ParseErr}; mod execute; mod parse; +mod ui; pub fn parse_class_file(file: &[u8]) -> Result { parse::parse_class_file(file) } + +pub fn display_class(w: W, class: &ClassFile) -> std::io::Result<()> +where + W: std::io::Write, +{ + ui::display_class(w, class) +} diff --git a/src/main.rs b/src/main.rs index a679f1d..05f2977 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,25 @@ -use coldsquare::parse_class_file; +use coldsquare::{display_class, parse_class_file}; fn main() { - let file = "Test.class"; - let file = std::fs::read(file).unwrap(); + let file = std::env::args().nth(1).unwrap_or_else(|| { + eprintln!("No file provided"); + std::process::exit(1); + }); + let file = std::fs::read(file).unwrap_or_else(|_| { + eprintln!("Could not read file"); + std::process::exit(1); + }); - let class_file = parse_class_file(&file).unwrap(); + let class_file = match parse_class_file(&file) { + Ok(file) => file, + Err(err) => { + eprintln!("{}", err); + return; + } + }; + let stdout = std::io::stdout(); - println!("{:?}", class_file); + if let Err(why) = display_class(stdout.lock(), &class_file) { + eprintln!("{}", why); + } } diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 32eb3fc..228c8c4 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -3,10 +3,19 @@ mod model; mod test; pub use model::*; +use std::fmt::{Display, Formatter}; #[derive(Debug)] pub struct ParseErr(String); +impl Display for ParseErr { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "Could not parse class file: {}", self.0) + } +} + +impl std::error::Error for ParseErr {} + pub type Result = std::result::Result; #[derive(Clone)] @@ -35,6 +44,10 @@ impl<'a> Data<'a> { Ok(((self.u1()? as u2) << 8) | self.u1()? as u2) } + fn cp(&mut self) -> Result { + Ok(self.u2()?.into()) + } + fn u4(&mut self) -> Result { Ok(((self.u2()? as u4) << 16) | self.u2()? as u4) } @@ -100,6 +113,12 @@ macro_rules! parse_primitive { parse_primitive!(u1, u2, u4); +impl Parse for FromPool { + fn parse(data: &mut Data) -> Result { + Ok(data.u2()?.into()) + } +} + impl Parse for ClassFile { fn parse(data: &mut Data) -> Result { let magic = data.u4()?; @@ -109,8 +128,8 @@ impl Parse for ClassFile { let constant_pool_count = data.u2()?; let constant_pool = parse_vec(data, constant_pool_count - 1)?; // the minus one is important let access_flags = data.u2()?; - let this_class = data.u2()?; - let super_class = data.u2()?; + let this_class = data.cp()?; + let super_class = data.cp()?; let interfaces_count = data.u2()?; let interfaces = parse_vec(data, interfaces_count)?; let fields_count = data.u2()?; @@ -148,71 +167,96 @@ impl Parse for CpInfo { let tag = data.u1()?; Ok(match tag { - 7 => Self::Class { + 7 => Self { tag, - name_index: data.u2()?, + inner: CpInfoInner::Class(cp_info::Class { + name_index: data.cp()?, + }), }, - 9 => Self::Fieldref { + 9 => Self { tag, - class_index: data.u2()?, - name_and_type_index: data.u2()?, + inner: CpInfoInner::Fieldref(cp_info::Fieldref { + class_index: data.cp()?, + name_and_type_index: data.cp()?, + }), }, - 10 => Self::MethodRef { + 10 => Self { tag, - class_index: data.u2()?, - name_and_type_index: data.u2()?, + inner: CpInfoInner::MethodRef(cp_info::MethodRef { + class_index: data.cp()?, + name_and_type_index: data.cp()?, + }), }, - 11 => Self::InterfaceMethodref { + 11 => Self { tag, - class_index: data.u2()?, - name_and_type_index: data.u2()?, + inner: CpInfoInner::InterfaceMethodref(cp_info::InterfaceMethodref { + class_index: data.cp()?, + name_and_type_index: data.cp()?, + }), }, - 8 => Self::String { + 8 => Self { tag, - string_index: data.u2()?, + inner: CpInfoInner::String(cp_info::String { + string_index: data.cp()?, + }), }, - 3 => Self::Integer { + 3 => Self { tag, - bytes: data.u4()?, + inner: CpInfoInner::Integer(cp_info::Integer { bytes: data.u4()? }), }, - 4 => Self::Float { + 4 => Self { tag, - bytes: data.u4()?, + inner: CpInfoInner::Float(cp_info::Float { bytes: data.u4()? }), }, - 5 => Self::Long { + 5 => Self { tag, - high_bytes: data.u4()?, - low_bytes: data.u4()?, + inner: CpInfoInner::Long(cp_info::Long { + high_bytes: data.u4()?, + low_bytes: data.u4()?, + }), }, - 6 => Self::Double { + 6 => Self { tag, - high_bytes: data.u4()?, - low_bytes: data.u4()?, + inner: CpInfoInner::Double(cp_info::Double { + high_bytes: data.u4()?, + low_bytes: data.u4()?, + }), }, - 12 => Self::NameAndType { + 12 => Self { tag, - name_index: data.u2()?, - descriptor_index: data.u2()?, + inner: CpInfoInner::NameAndType(cp_info::NameAndType { + name_index: data.cp()?, + descriptor_index: data.cp()?, + }), }, - 1 => Self::Utf8 { + 1 => Self { tag, - length: data.u2()?, - bytes: String::from_utf8(parse_vec(data, data.last_u2()?)?) - .map_err(|err| ParseErr(format!("Invalid utf8 in CpInfo::Utf8: {}", err)))?, + inner: CpInfoInner::Utf8(cp_info::Utf8 { + length: data.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 { + 15 => Self { tag, - reference_kind: data.u1()?, - reference_index: data.u2()?, + inner: CpInfoInner::MethodHandle(cp_info::MethodHandle { + reference_kind: data.u1()?, + reference_index: data.cp()?, + }), }, - 16 => Self::MethodType { + 16 => Self { tag, - descriptor_index: data.u2()?, + inner: CpInfoInner::MethodType(cp_info::MethodType { + descriptor_index: data.cp()?, + }), }, - 18 => Self::InvokeDynamic { + 18 => Self { tag, - bootstrap_method_attr_index: data.u2()?, - name_and_type_index: data.u2()?, + inner: CpInfoInner::InvokeDynamic(cp_info::InvokeDynamic { + bootstrap_method_attr_index: data.u2()?, + name_and_type_index: data.cp()?, + }), }, _ => Err(ParseErr(format!("Invalid CPInfo tag: {}", tag)))?, }) @@ -223,8 +267,8 @@ impl Parse for FieldInfo { fn parse(data: &mut Data) -> Result { Ok(Self { access_flags: data.u2()?, - name_index: data.u2()?, - descriptor_index: data.u2()?, + name_index: data.cp()?, + descriptor_index: data.cp()?, attributes_count: data.u2()?, attributes: parse_vec(data, data.last_u2()?)?, }) @@ -235,8 +279,8 @@ impl Parse for MethodInfo { fn parse(data: &mut Data) -> Result { Ok(Self { access_flags: data.u2()?, - name_index: data.u2()?, - descriptor_index: data.u2()?, + name_index: data.cp()?, + descriptor_index: data.cp()?, attributes_count: data.u2()?, attributes: parse_vec(data, data.last_u2()?)?, }) @@ -246,7 +290,7 @@ impl Parse for MethodInfo { impl Parse for AttributeInfo { fn parse(data: &mut Data) -> Result { Ok(Self { - attribute_name_index: data.u2()?, + attribute_name_index: data.cp()?, attribute_length: data.u4()?, inner: AttributeInfoInner::Unknown { attribute_content: parse_vec(data, data.last_u4()? as usize)?, @@ -340,9 +384,9 @@ impl Parse for VerificationTypeInfo { impl Parse for AttributeInnerClass { fn parse(data: &mut Data) -> Result { Ok(Self { - inner_class_info_index: data.u2()?, - outer_class_info_index: data.u2()?, - inner_class_name_index: data.u2()?, + inner_class_info_index: data.cp()?, + outer_class_info_index: data.cp()?, + inner_class_name_index: data.cp()?, inner_class_access_flags: data.u2()?, }) } @@ -362,8 +406,8 @@ impl Parse for AttributeLocalVariableTable { Ok(Self { start_pc: data.u2()?, length: data.u2()?, - name_index: data.u2()?, - descriptor_or_signature_index: data.u2()?, + name_index: data.cp()?, + descriptor_or_signature_index: data.cp()?, index: data.u2()?, }) } @@ -372,7 +416,7 @@ impl Parse for AttributeLocalVariableTable { impl Parse for Annotation { fn parse(data: &mut Data) -> Result { Ok(Self { - type_index: data.u2()?, + type_index: data.cp()?, num_element_value_pairs: data.u2()?, element_value_pairs: parse_vec(data, data.last_u2()?)?, }) @@ -382,7 +426,7 @@ impl Parse for Annotation { impl Parse for AnnotationElementValuePair { fn parse(data: &mut Data) -> Result { Ok(Self { - element_name_index: data.u2()?, + element_name_index: data.cp()?, element_name_name: AnnotationElementValue::parse(data)?, }) } @@ -402,13 +446,13 @@ impl Parse for AnnotationElementValueValue { let tag = data.last_u1()? as char; Ok(match tag { 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' | 's' => { - Self::ConstValueIndex { index: data.u2()? } + Self::ConstValueIndex { index: data.cp()? } } 'e' => Self::EnumConstValue { - type_name_index: data.u2()?, - const_name_index: data.u2()?, + type_name_index: data.cp()?, + const_name_index: data.cp()?, }, - 'c' => Self::ClassInfoIndex { index: data.u2()? }, + 'c' => Self::ClassInfoIndex { index: data.cp()? }, '@' => Self::AnnotationValue { annotation: Box::new(Annotation::parse(data)?), }, @@ -436,7 +480,7 @@ impl Parse for ParameterAnnotation { impl Parse for BootstrapMethod { fn parse(data: &mut Data) -> Result { Ok(Self { - bootstrap_method_ref: data.u2()?, + bootstrap_method_ref: data.cp()?, num_bootstrap_arguments: data.u2()?, bootstrap_arguments: parse_vec(data, data.last_u2()?)?, }) @@ -449,9 +493,33 @@ fn resolve_attributes(class: &mut ClassFile) -> Result<()> { class .attributes .iter_mut() - .map(|attr| AttributeInfo::resolve_attribute(attr, pool)) + .map(|attr| attr.resolve_attribute(pool)) .collect::>>()?; + class + .methods + .iter_mut() + .map(|method| { + method + .attributes + .iter_mut() + .map(|attr| attr.resolve_attribute(pool)) + .collect::>>() + }) + .collect::>>()?; + + class + .fields + .iter_mut() + .map(|method| { + method + .attributes + .iter_mut() + .map(|attr| attr.resolve_attribute(pool)) + .collect::>>() + }) + .collect::>>()?; + Ok(()) } @@ -461,7 +529,7 @@ impl AttributeInfo { let attr = std::mem::replace( self, AttributeInfo { - attribute_name_index: 0, + attribute_name_index: 0.into(), attribute_length: 0, inner: AttributeInfoInner::__Empty, }, @@ -475,22 +543,26 @@ impl AttributeInfo { } => (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, + let info = match pool.get((*index) as usize - 1) { + Some(CpInfo { + inner: CpInfoInner::Utf8(cp_info::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) + self.resolve_attribute_inner(index, len, info, &mut data, pool) } fn resolve_attribute_inner( &mut self, - attribute_name_index: u16, + attribute_name_index: FromPool, attribute_length: u32, name: &str, data: &mut Data, + pool: &[CpInfo], ) -> Result<()> { let _ = std::mem::replace( self, @@ -499,23 +571,37 @@ impl AttributeInfo { attribute_name_index, attribute_length, inner: AttributeInfoInner::ConstantValue { - constantvalue_index: data.u2()?, - }, - }, - "Code" => Self { - attribute_name_index, - attribute_length, - inner: AttributeInfoInner::Code { - 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()?)?, + constantvalue_index: data.cp()?, }, }, + "Code" => { + let mut code = Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::Code { + 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()?)?, + }, + }; + if let AttributeInfoInner::Code { + ref mut attributes, .. + } = code.inner + { + attributes + .iter_mut() + .map(|attr| attr.resolve_attribute(pool)) + .collect::>>()?; + } else { + unreachable!() + } + code + } "StackMapTable" => Self { attribute_name_index, attribute_length, @@ -544,8 +630,8 @@ impl AttributeInfo { attribute_name_index, attribute_length, inner: AttributeInfoInner::EnclosingMethod { - class_index: data.u2()?, - method_index: data.u2()?, + class_index: data.cp()?, + method_index: data.cp()?, }, }, "Synthetic" => Self { @@ -557,14 +643,14 @@ impl AttributeInfo { attribute_name_index, attribute_length, inner: AttributeInfoInner::Signature { - signature_index: data.u2()?, + signature_index: data.cp()?, }, }, "SourceFile" => Self { attribute_name_index, attribute_length, inner: AttributeInfoInner::SourceFile { - sourcefile_index: data.u2()?, + sourcefile_index: data.cp()?, }, }, "SourceDebugExtension" => Self { diff --git a/src/parse/model.rs b/src/parse/model.rs index 9809ee2..005ecd8 100644 --- a/src/parse/model.rs +++ b/src/parse/model.rs @@ -12,6 +12,32 @@ pub type u2 = u16; #[allow(non_camel_case_types)] pub type u4 = u32; +/// +/// An index into the constant pool of the class +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct FromPool(u2); + +impl std::ops::Deref for FromPool { + type Target = u2; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From for FromPool { + fn from(n: u2) -> Self { + Self(n) + } +} + +impl FromPool { + pub fn get<'a>(&self, pool: &'a [CpInfo]) -> &'a CpInfo { + &pool[self.0 as usize - 1] + } +} + /// /// # Represents a .class file /// @@ -30,9 +56,9 @@ pub struct ClassFile { /// Mask of `ClassAccessFlag` used to denote access permissions pub access_flags: u2, /// A valid index into the `constant_pool` table. The entry must be a `ConstantClassInfo` - pub this_class: u2, + pub this_class: FromPool, /// Zero or a valid index into the `constant_pool` table - pub super_class: u2, + pub super_class: FromPool, /// The number if direct superinterfaces of this class or interface type pub interfaces_count: u2, /// Each entry must be a valid index into the `constant_pool` table. The entry must be a `ConstantClassInfo` @@ -55,107 +81,135 @@ pub struct ClassFile { /// May have indices back to the constant pool, with expected types /// _index: A valid index into the `constant_pool` table. #[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub enum CpInfo { - Class { - tag: u1, // 7 - /// Entry must be `Utf8` - name_index: u2, - }, - Fieldref { - tag: u1, // 9 - /// May be a class or interface type - class_index: u2, - /// Entry must be `NameAndType` - name_and_type_index: u2, - }, - MethodRef { - tag: u1, // 10 - /// Must be a class type - class_index: u2, - /// Entry must be `NameAndType` - name_and_type_index: u2, - }, - InterfaceMethodref { - tag: u1, // 11 - /// Must be an interface type - class_index: u2, - /// Entry must be `NameAndType` - name_and_type_index: u2, - }, - String { - tag: u1, // 8 - /// Entry must be `Utf8` - string_index: u2, - }, - Integer { - tag: u1, // 3 - // Big endian - bytes: u4, - }, - Float { - tag: u1, // 4 - /// IEEE 754 floating-point single format, big endian - bytes: u4, - }, +pub struct CpInfo { + pub tag: u1, + pub inner: CpInfoInner, +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub enum CpInfoInner { + Class(cp_info::Class), + Fieldref(cp_info::Fieldref), + MethodRef(cp_info::MethodRef), + InterfaceMethodref(cp_info::InterfaceMethodref), + String(cp_info::String), + Integer(cp_info::Integer), + Float(cp_info::Float), /// 8 byte constants take up two spaces in the constant pool - Long { - tag: u1, // 5 - /// Big endian - high_bytes: u4, - /// Big endian - low_bytes: u4, - }, + Long(cp_info::Long), /// 8 byte constants take up two spaces in the constant pool - Double { - tag: u1, // 6 - /// IEEE 754 floating-point double format, big endian - high_bytes: u4, - /// IEEE 754 floating-point double format, big endian - low_bytes: u4, - }, + Double(cp_info::Double), /// Any field or method, without the class it belongs to - NameAndType { - tag: u1, // 12 + NameAndType(cp_info::NameAndType), + Utf8(cp_info::Utf8), + MethodHandle(cp_info::MethodHandle), + MethodType(cp_info::MethodType), + InvokeDynamic(cp_info::InvokeDynamic), +} + +pub mod cp_info { + use super::*; + + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + pub struct Class { /// Entry must be `Utf8` - name_index: u2, + pub name_index: FromPool, + } + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + pub struct Fieldref { + /// May be a class or interface type + pub class_index: FromPool, + /// Entry must be `NameAndType` + pub name_and_type_index: FromPool, + } + #[derive(Debug, Clone, Hash, PartialEq, Eq)] + pub struct MethodRef { + /// Must be a class type + pub class_index: FromPool, + /// Entry must be `NameAndType` + pub name_and_type_index: FromPool, + } + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + pub struct InterfaceMethodref { + /// Must be an interface type + pub class_index: FromPool, + /// Entry must be `NameAndType` + pub name_and_type_index: FromPool, + } + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + pub struct String { /// Entry must be `Utf8` - descriptor_index: u2, - }, - Utf8 { - tag: u1, // 1 + pub string_index: FromPool, + } + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + pub struct Integer { + // Big endian + pub bytes: u4, + } + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + pub struct Float { + /// IEEE 754 floating-point single format, big endian + pub bytes: u4, + } + /// 8 byte constants take up two spaces in the constant pool + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + pub struct Long { + /// Big endian + pub high_bytes: u4, + /// Big endian + pub low_bytes: u4, + } + /// 8 byte constants take up two spaces in the constant pool + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + pub struct Double { + /// IEEE 754 floating-point double format, big endian + pub high_bytes: u4, + /// IEEE 754 floating-point double format, big endian + pub low_bytes: u4, + } + /// Any field or method, without the class it belongs to + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + pub struct NameAndType { + /// Entry must be `Utf8` + pub name_index: FromPool, + /// Entry must be `Utf8` + pub descriptor_index: FromPool, + } + #[derive(Debug, Clone, Hash, PartialEq, Eq)] + pub struct Utf8 { /// The length of the String. Not null-terminated. - length: u2, + pub length: u2, /// Contains modified UTF-8 - bytes: String, - }, - MethodHandle { - tag: u1, // 15 + pub bytes: std::string::String, + } + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + pub struct MethodHandle { /// The kind of method handle (0-9) - reference_kind: u1, + pub reference_kind: u1, /// If the kind is 1-4, the entry must be `FieldRef`. If the kind is 5-8, the entry must be `MethodRef` /// If the kind is 9, the entry must be `InterfaceMethodRef` - reference_index: u2, - }, - MethodType { - tag: u1, // 16 + pub reference_index: FromPool, + } + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + pub struct MethodType { /// Entry must be `Utf8` - descriptor_index: u2, - }, - InvokeDynamic { - tag: u1, // 18 - /// Must be a valid index into the `bootstrap_methods` array of the bootstrap method table of this class fiel - bootstrap_method_attr_index: u2, + pub descriptor_index: FromPool, + } + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] + pub struct InvokeDynamic { + /// Must be a valid index into the `bootstrap_methods` array of the bootstrap method table of this class field + pub bootstrap_method_attr_index: u2, /// Entry must `NameAndType` - name_and_type_index: u2, - }, + pub name_and_type_index: FromPool, + } } /// Information about a field #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct FieldInfo { pub access_flags: u2, - pub name_index: u2, - pub descriptor_index: u2, + pub name_index: FromPool, + pub descriptor_index: FromPool, pub attributes_count: u2, pub attributes: Vec, } @@ -166,9 +220,9 @@ pub struct MethodInfo { /// Mask of `MethodAccessFlag` used to denote access permissions pub access_flags: u2, /// Index to the `constant_pool` of the method name, must be `Utf8` - pub name_index: u2, + pub name_index: FromPool, /// Index to the `constant_pool` of the method descriptor, must be `Utf8` - pub descriptor_index: u2, + pub descriptor_index: FromPool, /// The amount of attributes for this method pub attributes_count: u2, /// The attributes for this method @@ -183,7 +237,7 @@ pub struct MethodInfo { /// _index: Index to the `constant_pool` table of any type #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct AttributeInfo { - pub attribute_name_index: u2, + pub attribute_name_index: FromPool, pub attribute_length: u4, /// The attribute value pub inner: AttributeInfoInner, @@ -200,7 +254,7 @@ pub enum AttributeInfoInner { /// Only on fields, the constant value of that field ConstantValue { /// Must be of type `Long`/`Float`/`Double`/`Integer`/`String` - constantvalue_index: u2, + constantvalue_index: FromPool, }, /// Only on methods, contains JVM instructions and auxiliary information for a single method Code { @@ -240,9 +294,9 @@ pub enum AttributeInfoInner { /// Only on a `ClassFile`, required if it is local or anonymous EnclosingMethod { /// Must be a `Class` constant, the innermost enclosing class - class_index: u2, + class_index: FromPool, /// Must be zero or `NameAndType` - method_index: u2, + method_index: FromPool, }, /// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. /// Every generated class has to have this attribute or the `Synthetic` Accessor modifier @@ -250,12 +304,12 @@ pub enum AttributeInfoInner { /// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Records generic signature information Signature { /// Must be `Utf8`, and a Class/Method/Field signature - signature_index: u2, + signature_index: FromPool, }, /// Only on a `ClassFile` SourceFile { /// Must be `Utf8`, the name of the source filed - sourcefile_index: u2, + sourcefile_index: FromPool, }, /// Only on a `ClassFile` SourceDebugExtension { @@ -414,11 +468,11 @@ pub enum VerificationTypeInfo { #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub struct AttributeInnerClass { /// Must be a `Class` - pub inner_class_info_index: u2, + pub inner_class_info_index: FromPool, /// Must be 0 or a `Class` - pub outer_class_info_index: u2, + pub outer_class_info_index: FromPool, /// Must be 0 or `Utf8` - pub inner_class_name_index: u2, + pub inner_class_name_index: FromPool, /// Must be a mask of `InnerClassAccessFlags` pub inner_class_access_flags: u2, } @@ -440,9 +494,9 @@ pub struct AttributeLocalVariableTable { /// The local variable must have a value between `start_pc` and `start_pc + length` pub length: u2, /// Must be `Utf8` - pub name_index: u2, + pub name_index: FromPool, /// Must be `Utf8`, field descriptor or field signature encoding the type - pub descriptor_or_signature_index: u2, + pub descriptor_or_signature_index: FromPool, /// The variable must be at `index` in the local variable array pub index: u2, } @@ -451,7 +505,7 @@ pub struct AttributeLocalVariableTable { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Annotation { /// Must be `Utf8` - pub type_index: u2, + pub type_index: FromPool, pub num_element_value_pairs: u2, pub element_value_pairs: Vec, } @@ -462,7 +516,7 @@ pub struct Annotation { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct AnnotationElementValuePair { /// Must be `Utf8` - pub element_name_index: u2, + pub element_name_index: FromPool, pub element_name_name: AnnotationElementValue, } @@ -480,19 +534,19 @@ pub enum AnnotationElementValueValue { /// If the tag is B, C, D, F, I, J, S, Z, or s. ConstValueIndex { /// Must be the matching constant pool entry - index: u2, + index: FromPool, }, /// If the tag is e EnumConstValue { /// Must be `Utf8` - type_name_index: u2, + type_name_index: FromPool, /// Must be `Utf8` - const_name_index: u2, + const_name_index: FromPool, }, /// If the tag is c ClassInfoIndex { /// Must be `Utf8`, for example Ljava/lang/Object; for Object - index: u2, + index: FromPool, }, /// If the tag is @ AnnotationValue { @@ -517,10 +571,10 @@ pub struct ParameterAnnotation { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct BootstrapMethod { /// Must be a `MethodHandle` - pub bootstrap_method_ref: u2, + pub bootstrap_method_ref: FromPool, pub num_bootstrap_arguments: u2, /// Each argument is a cpool entry. The constants must be `String, Class, Integer, Long, Float, Double, MethodHandle, or MethodType` - pub bootstrap_arguments: Vec, + pub bootstrap_arguments: Vec, } /////// Access Flags diff --git a/src/parse/test.rs b/src/parse/test.rs index a893373..3119378 100644 --- a/src/parse/test.rs +++ b/src/parse/test.rs @@ -47,77 +47,101 @@ fn parse_empty_class() { assert_eq!( parsed.constant_pool, vec![ - CpInfo::MethodRef { + CpInfo { tag: 0x0a, - class_index: 2, - name_and_type_index: 3 + inner: CpInfoInner::MethodRef(cp_info::MethodRef { + class_index: 2.into(), + name_and_type_index: 3.into(), + }) }, - CpInfo::Class { + CpInfo { tag: 7, - name_index: 4 + inner: CpInfoInner::Class(cp_info::Class { + name_index: 4.into(), + }) }, - CpInfo::NameAndType { + CpInfo { tag: 0xc, - name_index: 5, - descriptor_index: 6 + inner: CpInfoInner::NameAndType(cp_info::NameAndType { + name_index: 5.into(), + descriptor_index: 6.into(), + }) }, - CpInfo::Utf8 { + CpInfo { tag: 1, - length: 0x10, - bytes: "java/lang/Object".to_string() + inner: CpInfoInner::Utf8(cp_info::Utf8 { + length: 0x10, + bytes: "java/lang/Object".to_string() + }) }, - CpInfo::Utf8 { + CpInfo { tag: 1, - length: 6, - bytes: "".to_string() + inner: CpInfoInner::Utf8(cp_info::Utf8 { + length: 6, + bytes: "".to_string() + }) }, - CpInfo::Utf8 { + CpInfo { tag: 1, - length: 3, - bytes: "()V".to_string() + inner: CpInfoInner::Utf8(cp_info::Utf8 { + length: 3, + bytes: "()V".to_string() + }) }, - CpInfo::Class { + CpInfo { tag: 7, - name_index: 8 + inner: CpInfoInner::Class(cp_info::Class { + name_index: 8.into(), + }) }, - CpInfo::Utf8 { + CpInfo { tag: 1, - length: 4, - bytes: "Test".to_string() + inner: CpInfoInner::Utf8(cp_info::Utf8 { + length: 4, + bytes: "Test".to_string() + }) }, - CpInfo::Utf8 { + CpInfo { tag: 1, - length: 4, - bytes: "Code".to_string() + inner: CpInfoInner::Utf8(cp_info::Utf8 { + length: 4, + bytes: "Code".to_string() + }) }, - CpInfo::Utf8 { + CpInfo { tag: 1, - length: 15, - bytes: "LineNumberTable".to_string() + inner: CpInfoInner::Utf8(cp_info::Utf8 { + length: 15, + bytes: "LineNumberTable".to_string() + }) }, - CpInfo::Utf8 { + CpInfo { tag: 1, - length: 10, - bytes: "SourceFile".to_string() + inner: CpInfoInner::Utf8(cp_info::Utf8 { + length: 10, + bytes: "SourceFile".to_string() + }) }, - CpInfo::Utf8 { + CpInfo { tag: 1, - length: 9, - bytes: "Test.java".to_string() + inner: CpInfoInner::Utf8(cp_info::Utf8 { + length: 9, + bytes: "Test.java".to_string() + }) } ] ); assert_eq!(parsed.access_flags, 0x0021); - assert_eq!(parsed.this_class, 7); - assert_eq!(parsed.super_class, 2); + assert_eq!(parsed.this_class, 7.into()); + assert_eq!(parsed.super_class, 2.into()); assert_eq!(parsed.interfaces_count, 0); assert_eq!(parsed.interfaces, vec![]); assert_eq!(parsed.fields_count, 0); assert_eq!(parsed.fields, vec![]); assert_eq!(parsed.method_count, 1); assert_eq!(parsed.methods[0].access_flags, 1); - assert_eq!(parsed.methods[0].name_index, 5); - assert_eq!(parsed.methods[0].descriptor_index, 6); + assert_eq!(parsed.methods[0].name_index, 5.into()); + assert_eq!(parsed.methods[0].descriptor_index, 6.into()); 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);