diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 49acf82..32eb3fc 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -245,10 +245,12 @@ impl Parse for MethodInfo { impl Parse for AttributeInfo { fn parse(data: &mut Data) -> Result { - Ok(Self::Unknown { + Ok(Self { attribute_name_index: data.u2()?, attribute_length: data.u4()?, - attribute_content: parse_vec(data, data.last_u4()? as usize)?, + inner: AttributeInfoInner::Unknown { + attribute_content: parse_vec(data, data.last_u4()? as usize)?, + }, }) } } @@ -456,13 +458,20 @@ fn resolve_attributes(class: &mut ClassFile) -> Result<()> { 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 attr = std::mem::replace( + self, + AttributeInfo { + attribute_name_index: 0, + attribute_length: 0, + inner: AttributeInfoInner::__Empty, + }, + ); let (&index, &len, content) = match &attr { - AttributeInfo::Unknown { + AttributeInfo { attribute_name_index, attribute_length, - attribute_content, + inner: AttributeInfoInner::Unknown { attribute_content }, } => (attribute_name_index, attribute_length, attribute_content), _ => unreachable!("Attribute already resolved"), }; @@ -486,127 +495,163 @@ impl AttributeInfo { let _ = std::mem::replace( self, match name { - "ConstantValue" => Self::ConstantValue { + "ConstantValue" => Self { 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)?, + inner: AttributeInfoInner::ConstantValue { + constantvalue_index: data.u2()?, }, }, - "BootstrapMethods" => Self::BootstrapMethods { + "Code" => Self { attribute_name_index, attribute_length, - num_bootstrap_methods: data.u2()?, - bootstrap_methods: parse_vec(data, data.last_u2()?)?, + 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()?)?, + }, + }, + "StackMapTable" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::StackMapTable { + number_of_entries: data.u2()?, + entries: parse_vec(data, data.last_u2()?)?, + }, + }, + "Exceptions" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::Exceptions { + number_of_exceptions: data.u2()?, + exception_index_table: parse_vec(data, data.last_u2()?)?, + }, + }, + "InnerClasses" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::InnerClasses { + number_of_classes: data.u2()?, + classes: parse_vec(data, data.last_u2()?)?, + }, + }, + "EnclosingMethod" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::EnclosingMethod { + class_index: data.u2()?, + method_index: data.u2()?, + }, + }, + "Synthetic" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::Synthetic, + }, + "Signature" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::Signature { + signature_index: data.u2()?, + }, + }, + "SourceFile" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::SourceFile { + sourcefile_index: data.u2()?, + }, + }, + "SourceDebugExtension" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::SourceDebugExtension { + debug_extension: parse_vec(data, data.last_u2()?)?, + }, + }, + "LineNumberTable" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::LineNumberTable { + line_number_table_length: data.u2()?, + line_number_table: parse_vec(data, data.last_u2()?)?, + }, + }, + "LocalVariableTable" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::LocalVariableTable { + local_variable_table_length: data.u2()?, + local_variable_table: parse_vec(data, data.last_u2()?)?, + }, + }, + "LocalVariableTypeTable" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::LocalVariableTypeTable { + local_variable_table_length: data.u2()?, + local_variable_table: parse_vec(data, data.last_u2()?)?, + }, + }, + "Deprecated" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::Deprecated, + }, + "RuntimeVisibleAnnotations" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::RuntimeVisibleAnnotations { + num_annotations: data.u2()?, + annotations: parse_vec(data, data.last_u2()?)?, + }, + }, + "RuntimeInvisibleAnnotations" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::RuntimeInvisibleAnnotations { + num_annotations: data.u2()?, + annotations: parse_vec(data, data.last_u2()?)?, + }, + }, + "RuntimeVisibleParameterAnnotations" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::RuntimeVisibleParameterAnnotations { + num_parameters: data.u1()?, + parameter_annotations: parse_vec(data, data.last_u1()?)?, + }, + }, + "RuntimeInvisibleParameterAnnotations" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::RuntimeInvisibleParameterAnnotations { + num_parameters: data.u1()?, + parameter_annotations: parse_vec(data, data.last_u1()?)?, + }, + }, + "AnnotationDefault" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::AnnotationDefault { + default_value: AnnotationElementValue { + tag: data.u1()?, + value: AnnotationElementValueValue::parse(data)?, + }, + }, + }, + "BootstrapMethods" => Self { + attribute_name_index, + attribute_length, + inner: AttributeInfoInner::BootstrapMethods { + num_bootstrap_methods: data.u2()?, + bootstrap_methods: parse_vec(data, data.last_u2()?)?, + }, }, name => return Err(ParseErr(format!("Invalid Attribute name: {}", name))), }, diff --git a/src/parse/model.rs b/src/parse/model.rs index e36f85e..9809ee2 100644 --- a/src/parse/model.rs +++ b/src/parse/model.rs @@ -182,26 +182,28 @@ pub struct MethodInfo { /// /// _index: Index to the `constant_pool` table of any type #[derive(Debug, Clone, Hash, PartialEq, Eq)] -// todo refactor this into a struct + enum -pub enum AttributeInfo { +pub struct AttributeInfo { + pub attribute_name_index: u2, + pub attribute_length: u4, + /// The attribute value + pub inner: AttributeInfoInner, +} + +/// The Attributes, without the two common fields +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub enum AttributeInfoInner { __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, }, /// Only on fields, the constant value of that field ConstantValue { - attribute_name_index: u2, // "ConstantValue" - attribute_length: u4, /// Must be of type `Long`/`Float`/`Double`/`Integer`/`String` constantvalue_index: u2, }, /// Only on methods, contains JVM instructions and auxiliary information for a single method Code { - attribute_name_index: u2, - attribute_length: u4, /// The maximum depth of the operand stack for this method max_stack: u2, /// The number of the local variables array, including the parameters @@ -221,31 +223,22 @@ pub enum AttributeInfo { /// Only on the `Code` attribute, used for verification /// May be implicit on version >= 50.0, with no entries StackMapTable { - /// Must be `Utf8` - attribute_name_index: u2, - attribute_length: u4, number_of_entries: u2, entries: Vec, }, /// Only on `MethodInfo`, indicates which checked exceptions might be thrown Exceptions { - attribute_name_index: u2, - attribute_length: u4, number_of_exceptions: u2, /// Must be a `Class` constant exception_index_table: Vec, }, /// Only on a `ClassFile`. Specifies the inner classes of a class InnerClasses { - attribute_name_index: u2, - attribute_length: u4, number_of_classes: u2, classes: Vec, }, /// Only on a `ClassFile`, required if it is local or anonymous EnclosingMethod { - attribute_name_index: u2, - attribute_length: u4, // 4 /// Must be a `Class` constant, the innermost enclosing class class_index: u2, /// Must be zero or `NameAndType` @@ -253,97 +246,67 @@ pub enum AttributeInfo { }, /// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. /// Every generated class has to have this attribute or the `Synthetic` Accessor modifier - Synthetic { - attribute_name_index: u2, - attribute_length: u4, // 0 - }, + Synthetic, /// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Records generic signature information Signature { - attribute_name_index: u2, - attribute_length: u4, // 2 /// Must be `Utf8`, and a Class/Method/Field signature signature_index: u2, }, /// Only on a `ClassFile` SourceFile { - attribute_name_index: u2, - attribute_length: u4, // 2 /// Must be `Utf8`, the name of the source filed sourcefile_index: u2, }, /// Only on a `ClassFile` SourceDebugExtension { - attribute_name_index: u2, - attribute_length: u4, // number of items in `debug_extension` - /// A modified UTF-8 of additional debugging information + /// A modified UTF-8 of additional debugging information, `attribute_length`: number of items in `debug_extension` debug_extension: Vec, }, /// Only on the `Code` attribute. It includes line number information used by debuggers LineNumberTable { - attribute_name_index: u2, - attribute_length: u4, line_number_table_length: u2, line_number_table: Vec, }, /// Only on the `Code` attribute. It may be used to determine the value of local variables by debuggers LocalVariableTable { - attribute_name_index: u2, - attribute_length: u4, local_variable_table_length: u2, /// Note: the 3rd field is called `descriptor_index` and represents an field descriptor local_variable_table: Vec, }, /// Only on the `Code` attribute. It provides signature information instead of descriptor information LocalVariableTypeTable { - attribute_name_index: u2, - attribute_length: u4, local_variable_table_length: u2, /// Note: the 3rd field is called `signature_index` and represents a field type signature local_variable_table: Vec, }, /// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Marks a class/field/method as deprecated - Deprecated { - attribute_name_index: u2, - attribute_length: u4, // 0 - }, + Deprecated, /// Can be on `ClassFile`, `FieldInfo`,or `MethodInfo`. Contains all Runtime visible annotations RuntimeVisibleAnnotations { - attribute_name_index: u2, - attribute_length: u4, num_annotations: u2, annotations: Vec, }, /// Same as `RuntimeVisibleAnnotations`, but invisible to reflection RuntimeInvisibleAnnotations { - attribute_name_index: u2, - attribute_length: u4, num_annotations: u2, annotations: Vec, }, /// Only on `MethodInfo`, parameter annotations visible during runtime RuntimeVisibleParameterAnnotations { - attribute_name_index: u2, - attribute_length: u4, num_parameters: u1, parameter_annotations: Vec, }, /// Same as `RuntimeVisibleParameterAnnotations`, but invisible to reflection RuntimeInvisibleParameterAnnotations { - attribute_name_index: u2, - attribute_length: u4, num_parameters: u1, parameter_annotations: Vec, }, /// Only on `MethodInfo`, on those representing elements of annotation types, the default value of the element AnnotationDefault { - attribute_name_index: u2, - attribute_length: u4, default_value: AnnotationElementValue, }, /// Only on `ClassFile`. Records bootstrap method specifiers for `invokedynamic` BootstrapMethods { - attribute_name_index: u2, - attribute_length: u4, num_bootstrap_methods: u2, bootstrap_methods: Vec, },