diff --git a/crates/file-info/src/ui.rs b/crates/file-info/src/ui.rs index 4ac6629..158e210 100644 --- a/crates/file-info/src/ui.rs +++ b/crates/file-info/src/ui.rs @@ -1,8 +1,8 @@ -use file_parser::{ClassFile, ParseErr}; -use std::error::Error; +use file_parser::ClassFile; +use std::io; use std::io::Write; -pub fn display_class(mut w: W, class: &ClassFile) -> Result<(), Box> { +pub fn display_class(mut w: W, class: &ClassFile) -> Result<(), io::Error> { let cp = &class.constant_pool; writeln!( @@ -17,24 +17,21 @@ pub fn display_class(mut w: W, class: &ClassFile) -> Result<(), Box "", - Some(class) => &class.name_index.get(cp), - } + Some(class) => class.name_index.get(cp), + }, if class.interfaces.is_empty() { "".to_string() } else { format!( " implements {}", - // this is absolutely terrible but it works i guess class .interfaces .iter() .map(|i| i.get(cp)) - .collect::, ParseErr>>()? - .iter() .map(|i| i.name_index.get(cp)) - .collect::, ParseErr>>()? + .collect::>() .join(",") ) }, @@ -42,7 +39,7 @@ pub fn display_class(mut w: W, class: &ClassFile) -> Result<(), Box(mut w: W, class: &ClassFile) -> Result<(), Box(mut w: W, class: &ClassFile) -> Result<(), Box Data<'a> { } /// Parses a u2 and validates it in the constant pool - fn cp<'pool, T: FromCpInfo<'pool>>(&mut self, pool: &'pool [CpInfo]) -> Result> { + fn cp(&mut self, pool: &[CpInfo]) -> Result> { let index = self.u2()?; - let _ = T::try_from_cp_info(pool, index)?; + T::validate_cp_info(pool, index)?; Ok(index.into()) } @@ -117,9 +117,12 @@ macro_rules! parse_primitive { parse_primitive!(u1, u2, u4); -impl Parse for FromPool { +impl Parse for FromPool +where + T: ValidateCpInfo, +{ fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { - Ok(data.u2()?.into()) + data.cp(cp) } } @@ -129,7 +132,9 @@ impl Parse for ClassFile { assert_eq!(magic, 0xCAFEBABE); let minor_version = data.u2()?; let major_version = data.u2()?; + dbg!("reached constant pool"); let constant_pool = parse_vec(data.u2()? - 1, data, cp)?; // the minus one is important + dbg!("after constant pool"); let cp = &constant_pool; let access_flags = data.u2()?; let this_class = data.cp(cp)?; @@ -160,6 +165,7 @@ impl Parse for ClassFile { impl Parse for CpInfo { fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { let tag = data.u1()?; + dbg!(tag); Ok(match tag { 7 => Self { @@ -302,7 +308,7 @@ impl Parse for AttributeInfo { } impl Parse for AttributeCodeException { - fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { + fn parse(data: &mut Data, _cp: &[CpInfo]) -> Result { Ok(Self { start_pc: data.last_u2()?, end_pc: data.last_u2()?, @@ -357,7 +363,7 @@ impl Parse for StackMapFrame { } impl Parse for VerificationTypeInfo { - fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { + fn parse(data: &mut Data, _cp: &[CpInfo]) -> Result { let tag = data.u1()?; Ok(match tag { 0 => Self::Top { tag }, @@ -397,7 +403,7 @@ impl Parse for AttributeInnerClass { } impl Parse for AttributeLineNumber { - fn parse(data: &mut Data, cp: &[CpInfo]) -> Result { + fn parse(data: &mut Data, _cp: &[CpInfo]) -> Result { Ok(Self { start_pc: data.u2()?, line_number: data.u2()?, diff --git a/crates/file-parser/src/model/cp_info.rs b/crates/file-parser/src/model/cp_info.rs index 53aa005..101dd03 100644 --- a/crates/file-parser/src/model/cp_info.rs +++ b/crates/file-parser/src/model/cp_info.rs @@ -1,5 +1,5 @@ -use super::*; -use crate::ParseErr; +use crate::{u1, u2, u4, CpInfo, CpInfoInner, ParseErr}; +use std::marker::PhantomData; /// /// An index into the constant pool of the class @@ -18,6 +18,7 @@ pub struct FromPool { impl Copy for FromPool {} impl From for FromPool { + #[inline] fn from(n: u2) -> Self { Self { inner: n, @@ -39,7 +40,7 @@ where { #[inline] pub fn get(&self, pool: &'pool [CpInfo]) -> T::Target { - T::from_cp_info(&pool[self.inner as usize - 1]) + T::from_cp_info_with_index(pool, self.inner) } } @@ -52,15 +53,56 @@ where if self.inner == 0 { None } else { - Some(T::from_cp_info(&pool[self.inner as usize - 1])) + Some(T::from_cp_info_with_index(pool, self.inner)) } } } -pub trait FromCpInfo<'pool> { +pub trait ValidateCpInfo { + /// check that the constant pool entry has the correct type + /// `index` is the original, non-null index (it can be 0 optional constants) + fn validate_cp_info(info: &[CpInfo], index: u2) -> Result<(), ParseErr>; +} + +pub trait FromCpInfo<'pool>: ValidateCpInfo { type Target; fn from_cp_info(info: &'pool CpInfo) -> Self::Target; - fn try_from_cp_info(info: &'pool [CpInfo], index: u2) -> Result; + fn from_cp_info_with_index(info: &'pool [CpInfo], index: u2) -> Self::Target { + Self::from_cp_info(&info[index as usize - 1]) + } +} + +impl<'pool, T> FromCpInfo<'pool> for Option +where + T: FromCpInfo<'pool>, +{ + type Target = Option; + + #[inline] + fn from_cp_info(_info: &'pool CpInfo) -> Self::Target { + unreachable!("FromPool> should always be get through `from_cp_info_with_index`") + } + + fn from_cp_info_with_index(info: &'pool [CpInfo], index: u2) -> Self::Target { + if index == 0 { + None + } else { + Some(T::from_cp_info_with_index(info, index)) + } + } +} + +impl ValidateCpInfo for Option +where + T: ValidateCpInfo, +{ + fn validate_cp_info(info: &[CpInfo], index: u2) -> Result<(), ParseErr> { + if index == 0 { + Ok(()) + } else { + T::validate_cp_info(info, index) + } + } } macro_rules! impl_try_from_cp { @@ -76,14 +118,20 @@ macro_rules! impl_try_from_cp { _kind => unreachable!(), } } + } - #[inline] - fn try_from_cp_info(info: &'pool [CpInfo], index: u2) -> Result { + impl ValidateCpInfo for $name { + fn validate_cp_info(info: &[CpInfo], index: u2) -> Result<(), ParseErr> { if index == 0 { return Err(ParseErr("Index must not be 0".to_string())); } + // todo this here might actually be an empty constant pool depending on whether is is still parsing the constant pool + // it needs to be checked after testing + // not now + // pls + // i hate this match &info[index as usize - 1].inner { - CpInfoInner::$name(class) => Ok(class), + CpInfoInner::$name(_) => Ok(()), kind => Err(ParseErr(format!( concat!("Expected '", stringify!($name), "', found '{:?}'"), kind @@ -95,40 +143,54 @@ macro_rules! impl_try_from_cp { }; } +impl<'pool> FromCpInfo<'pool> for CpInfoInner { + type Target = &'pool Self; + + fn from_cp_info(info: &'pool CpInfo) -> Self::Target { + &info.inner + } +} + +impl ValidateCpInfo for CpInfoInner { + fn validate_cp_info(_info: &[CpInfo], _index: u2) -> Result<(), ParseErr> { + Ok(()) + } +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Class { /// Entry must be `Utf8` - pub name_index: FromPool, + 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, + pub class_index: FromPool, /// Entry must be `NameAndType` - pub name_and_type_index: FromPool, + pub name_and_type_index: FromPool, } #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct MethodRef { /// Must be a class type - pub class_index: FromPool, + pub class_index: FromPool, /// Entry must be `NameAndType` - pub name_and_type_index: FromPool, + 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, + pub class_index: FromPool, /// Entry must be `NameAndType` - pub name_and_type_index: FromPool, + pub name_and_type_index: FromPool, } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct String { /// Entry must be `Utf8` - pub string_index: FromPool, + pub string_index: FromPool, } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -165,9 +227,9 @@ pub struct Double { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct NameAndType { /// Entry must be `Utf8` - pub name_index: FromPool, + pub name_index: FromPool, /// Entry must be `Utf8` - pub descriptor_index: FromPool, + pub descriptor_index: FromPool, } #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -187,15 +249,15 @@ pub struct MethodHandle { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum MethodHandleIndex { - Field(FromPool), - Method(FromPool), - Interface(FromPool), + Field(FromPool), + Method(FromPool), + Interface(FromPool), } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct MethodType { /// Entry must be `Utf8` - pub descriptor_index: FromPool, + pub descriptor_index: FromPool, } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -203,7 +265,7 @@ 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` - pub name_and_type_index: FromPool, + pub name_and_type_index: FromPool, } // default implementations @@ -224,6 +286,21 @@ impl_try_from_cp!( InvokeDynamic ); +impl ValidateCpInfo for Utf8 { + fn validate_cp_info(info: &[CpInfo], index: u2) -> Result<(), ParseErr> { + if index == 0 { + return Err(ParseErr("Index must not be 0".to_string())); + } + match &info[index as usize - 1].inner { + CpInfoInner::Utf8(_) => Ok(()), + kind => Err(ParseErr(format!( + concat!("Expected '", stringify!($name), "', found '{:?}'"), + kind + ))), + } + } +} + // custom implementations impl<'pool> FromCpInfo<'pool> for Utf8 { type Target = &'pool str; @@ -235,18 +312,4 @@ impl<'pool> FromCpInfo<'pool> for Utf8 { _ => unreachable!(), } } - - #[inline] - fn try_from_cp_info(info: &'pool [CpInfo], index: u2) -> Result { - if index == 0 { - return Err(ParseErr("Index must not be 0".to_string())); - } - match &info[index as usize - 1].inner { - CpInfoInner::Utf8(class) => Ok(&class.bytes), - kind => Err(ParseErr(format!( - concat!("Expected '", stringify!($name), "', found '{:?}'"), - kind - ))), - } - } } diff --git a/crates/file-parser/src/model/mod.rs b/crates/file-parser/src/model/mod.rs index 3b5148e..73b3c7d 100644 --- a/crates/file-parser/src/model/mod.rs +++ b/crates/file-parser/src/model/mod.rs @@ -4,8 +4,6 @@ //! [The .class specs](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html) #![allow(dead_code)] -use std::marker::PhantomData; - /// All of the Constants in the Constant Pool pub mod cp_info; @@ -118,15 +116,6 @@ pub struct AttributeInfo { pub inner: AttributeInfoInner, } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum ConstantValueIndex { - Long(cp_info::Long), - Float(cp_info::Float), - Double(cp_info::Double), - Integer(cp_info::Integer), - String(cp_info::String), -} - /// The Attributes, without the two common fields #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum AttributeInfoInner { @@ -138,7 +127,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: FromPool, + constantvalue_index: FromPool, }, /// Only on methods, contains JVM instructions and auxiliary information for a single method Code {