diff --git a/src/classfile.rs b/src/classfile.rs index 1569e4c..0c015be 100644 --- a/src/classfile.rs +++ b/src/classfile.rs @@ -53,7 +53,7 @@ pub struct JavaClassFile { constant_pool: Box<[ConstantPoolInfo]>, - access_flags: AccessFlagMask, + access_flags: ClassAccessFlagMask, this_class: u16, super_class: u16, @@ -93,17 +93,24 @@ impl JavaClassFile { let mut i = 0; while i < constant_pool_size { let cpinfo = ConstantPoolInfo::from_reader(reader)?; - i += match cpinfo { - ConstantPoolInfo::ConstantDouble(_) | ConstantPoolInfo::ConstantLong(_) => 2, + + let delta_i = match cpinfo { + ConstantPoolInfo::Double(_) | ConstantPoolInfo::Long(_) => 2, _ => 1 }; constant_pool_vec.push(cpinfo); + + if delta_i == 2 { + constant_pool_vec.push(ConstantPoolInfo::Nothing()); + } + + i += delta_i; } constant_pool_vec.into_boxed_slice() }; - let access_flags = AccessFlagMask { mask: read_u16(reader)? }; + let access_flags = ClassAccessFlagMask { mask: read_u16(reader)? }; let this_class = read_u16(reader)?; let super_class = read_u16(reader)?; let interfaces = { @@ -270,20 +277,21 @@ pub struct ConstantInvokeDynamicInfo { #[derive(Debug)] #[repr(u8)] pub enum ConstantPoolInfo { - ConstantClass(ConstantClassInfo) = 7, - ConstantFieldRef(ConstantFieldRefInfo) = 9, - ConstantMethodRef(ConstantMethodRefInfo) = 10, - ConstantInterfaceMethodRef(ConstantInterfaceMethodRefInfo) = 11, - ConstantString(ConstantStringInfo) = 8, - ConstantInteger(ConstantIntegerInfo) = 3, - ConstantFloat(ConstantFloatInfo) = 4, - ConstantLong(ConstantLongInfo) = 5, - ConstantDouble(ConstantDoubleInfo) = 6, - ConstantNameAndType(ConstantNameAndTypeInfo) = 12, - ConstantUtf8(ConstantUtf8Info) = 1, - ConstantMethodHandle(ConstantMethodHandleInfo) = 15, - ConstantMethodType(ConstantMethodTypeInfo) = 16, - ConstantInvokeDynamic(ConstantInvokeDynamicInfo) = 18, + Class(ConstantClassInfo) = 7, + FieldRef(ConstantFieldRefInfo) = 9, + MethodRef(ConstantMethodRefInfo) = 10, + InterfaceMethodRef(ConstantInterfaceMethodRefInfo) = 11, + String(ConstantStringInfo) = 8, + Integer(ConstantIntegerInfo) = 3, + Float(ConstantFloatInfo) = 4, + Long(ConstantLongInfo) = 5, + Double(ConstantDoubleInfo) = 6, + NameAndType(ConstantNameAndTypeInfo) = 12, + Utf8(ConstantUtf8Info) = 1, + MethodHandle(ConstantMethodHandleInfo) = 15, + MethodType(ConstantMethodTypeInfo) = 16, + InvokeDynamic(ConstantInvokeDynamicInfo) = 18, + Nothing() = 255, } impl ConstantPoolInfo { @@ -294,7 +302,7 @@ impl ConstantPoolInfo { match tag { 1 => { - ConstantPoolInfo::ConstantUtf8( + ConstantPoolInfo::Utf8( ConstantUtf8Info { utf8: { let length = read_u16(reader)?; @@ -309,7 +317,7 @@ impl ConstantPoolInfo { } 3 => { - ConstantPoolInfo::ConstantInteger( + ConstantPoolInfo::Integer( ConstantIntegerInfo { value: read_i32(reader)? } @@ -317,7 +325,7 @@ impl ConstantPoolInfo { } 4 => { - ConstantPoolInfo::ConstantFloat( + ConstantPoolInfo::Float( ConstantFloatInfo { value: read_f32(reader)? } @@ -325,7 +333,7 @@ impl ConstantPoolInfo { } 5 => { - ConstantPoolInfo::ConstantLong( + ConstantPoolInfo::Long( ConstantLongInfo { value: read_u64(reader)? } @@ -333,7 +341,7 @@ impl ConstantPoolInfo { } 6 => { - ConstantPoolInfo::ConstantDouble( + ConstantPoolInfo::Double( ConstantDoubleInfo { value: read_f64(reader)? } @@ -341,7 +349,7 @@ impl ConstantPoolInfo { } 7 => { - ConstantPoolInfo::ConstantClass( + ConstantPoolInfo::Class( ConstantClassInfo { name_index: read_u16(reader)? } @@ -349,7 +357,7 @@ impl ConstantPoolInfo { } 8 => { - ConstantPoolInfo::ConstantString( + ConstantPoolInfo::String( ConstantStringInfo { string_index: read_u16(reader)? } @@ -357,7 +365,7 @@ impl ConstantPoolInfo { } 9 => { - ConstantPoolInfo::ConstantFieldRef( + ConstantPoolInfo::FieldRef( ConstantFieldRefInfo { class_index: read_u16(reader)?, name_and_type_index: read_u16(reader)? @@ -366,7 +374,7 @@ impl ConstantPoolInfo { } 10 => { - ConstantPoolInfo::ConstantMethodRef( + ConstantPoolInfo::MethodRef( ConstantMethodRefInfo { class_index: read_u16(reader)?, name_and_type_index: read_u16(reader)? @@ -375,7 +383,7 @@ impl ConstantPoolInfo { } 11 => { - ConstantPoolInfo::ConstantInterfaceMethodRef( + ConstantPoolInfo::InterfaceMethodRef( ConstantInterfaceMethodRefInfo { class_index: read_u16(reader)?, name_and_type_index: read_u16(reader)? @@ -384,7 +392,7 @@ impl ConstantPoolInfo { } 12 => { - ConstantPoolInfo::ConstantNameAndType( + ConstantPoolInfo::NameAndType( ConstantNameAndTypeInfo { name_index: read_u16(reader)?, descriptor_index: read_u16(reader)? @@ -393,7 +401,7 @@ impl ConstantPoolInfo { } 15 => { - ConstantPoolInfo::ConstantMethodHandle( + ConstantPoolInfo::MethodHandle( ConstantMethodHandleInfo { reference_kind: ConstantMethodHandleType::try_from(read_u8(reader)?)?, reference_index: read_u16(reader)?, @@ -402,7 +410,7 @@ impl ConstantPoolInfo { } 16 => { - ConstantPoolInfo::ConstantMethodType( + ConstantPoolInfo::MethodType( ConstantMethodTypeInfo { descriptor_index: read_u16(reader)?, } @@ -410,7 +418,7 @@ impl ConstantPoolInfo { } 18 => { - ConstantPoolInfo::ConstantInvokeDynamic( + ConstantPoolInfo::InvokeDynamic( ConstantInvokeDynamicInfo { bootstrap_method_attr_index: read_u16(reader)?, name_and_type_index: read_u16(reader)?, @@ -426,26 +434,27 @@ impl ConstantPoolInfo { #[derive(Debug, Clone, Copy)] #[repr(u16)] -pub enum AccessFlag { - AccessPublic = 0x0001, // Declared public; may be accessed from outside its package. - AccessFinal = 0x0010, // Declared final; no subclasses allowed. - AccessSuper = 0x0020, // Treat superclass methods specially when invoked by the invokespecial instruction. - AccessInterface = 0x0200, // Is an interface, not a class. - AccessAbstract = 0x0400, // Declared abstract; must not be instantiated. - AccessSynthetic = 0x1000, // Declared synthetic; not present in the source code. - AccessAnnotation = 0x2000, // Declared as an annotation type. - AccessEnum = 0x4000, // Declared as an enum type. -} +pub enum FieldAccessFlag { + Public = 0x0001, // Declared public; may be accessed from outside its package. + Private = 0x0002, // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4). + Protected = 0x0004, // Declared protected; may be accessed within subclasses. + Static = 0x0008, // Declared static. + Final = 0x0010, // Declared final; never directly assigned to after object construction (JLS §17.5). + Volatile = 0x0040, // Declared volatile; cannot be cached. + Transient = 0x0080, // Declared transient; not written or read by a persistent object manager. + Synthetic = 0x1000, // Declared synthetic; not present in the source code. + Enum = 0x4000, // Declared as an element of an enum class. + } -pub struct AccessFlagMask { - mask: u16 -} + pub struct FieldAccessFlagMask { + mask: u16 + } -impl Debug for AccessFlagMask { +impl Debug for FieldAccessFlagMask { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - let mut flag_vec = Vec::::new(); + let mut flag_vec = Vec::new(); - let flags = [AccessFlag::AccessPublic,AccessFlag::AccessFinal,AccessFlag::AccessSuper,AccessFlag::AccessInterface,AccessFlag::AccessAbstract,AccessFlag::AccessSynthetic,AccessFlag::AccessAnnotation,AccessFlag::AccessEnum]; + let flags = [FieldAccessFlag::Public,FieldAccessFlag::Private,FieldAccessFlag::Protected,FieldAccessFlag::Static,FieldAccessFlag::Final,FieldAccessFlag::Volatile,FieldAccessFlag::Transient,FieldAccessFlag::Synthetic,FieldAccessFlag::Enum,]; for flag in flags { if (flag as u16 & self.mask) != 0 { @@ -460,7 +469,7 @@ impl Debug for AccessFlagMask { #[derive(Debug)] pub struct FieldInfo { - access_flags: AccessFlagMask, + access_flags: FieldAccessFlagMask, name_index: u16, descriptor_index: u16, attributes: Box<[AttributeInfo]>, @@ -470,7 +479,7 @@ impl FieldInfo { fn from_reader(reader: &mut dyn Read, pool: &Box<[ConstantPoolInfo]>) -> Result { Ok( FieldInfo { - access_flags: AccessFlagMask { mask: read_u16(reader)? }, + access_flags: FieldAccessFlagMask { mask: read_u16(reader)? }, name_index: read_u16(reader)?, descriptor_index: read_u16(reader)?, attributes: AttributeInfo::array_from_reader(reader, pool, true)?, @@ -731,7 +740,7 @@ impl AttributeInfo { let data = { let name_entry = &pool[attribute_name_index as usize]; let utf8 = match name_entry { - ConstantPoolInfo::ConstantUtf8( ConstantUtf8Info { utf8 } ) => utf8, + ConstantPoolInfo::Utf8( ConstantUtf8Info { utf8 } ) => utf8, _ => return Err(Error::BadFileError(format!("Bad name index for attribute info: {}", attribute_name_index))), }; @@ -781,7 +790,7 @@ impl AttributeInfo { #[derive(Debug)] pub struct MethodInfo { - access_flags: AccessFlagMask, + access_flags: MethodAccessFlagMask, name_index: u16, descriptor_index: u16, attributes: Box<[AttributeInfo]>, @@ -791,7 +800,7 @@ impl MethodInfo { fn from_reader(reader: &mut dyn Read, pool: &Box<[ConstantPoolInfo]>) -> Result { Ok( MethodInfo { - access_flags: AccessFlagMask { mask: read_u16(reader)? }, + access_flags: MethodAccessFlagMask { mask: read_u16(reader)? }, name_index: read_u16(reader)?, descriptor_index: read_u16(reader)?, attributes: AttributeInfo::array_from_reader(reader, pool, true)? @@ -800,6 +809,77 @@ impl MethodInfo { } } +#[derive(Debug, Copy, Clone)] +pub enum MethodAccessFlag { + Public = 0x0001, // Declared public; may be accessed from outside its package. + Private = 0x0002, // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4). + Protected = 0x0004, // Declared protected; may be accessed within subclasses. + Static = 0x0008, // Declared static. + Final = 0x0010, // Declared final; must not be overridden (§5.4.5). + Synchronized = 0x0020, // Declared synchronized; invocation is wrapped by a monitor use. + Bridge = 0x0040, // A bridge method, generated by the compiler. + Varargs = 0x0080, // Declared with variable number of arguments. + Native = 0x0100, // Declared native; implemented in a language other than the Java programming language. + Abstract = 0x0400, // Declared abstract; no implementation is provided. + Strict = 0x0800, // In a class file whose major version number is at least 46 and at most 60: Declared strictfp. + Synthetic = 0x1000, // Declared synthetic; not present in the source code. +} + +pub struct MethodAccessFlagMask { + mask: u16, +} + +impl Debug for MethodAccessFlagMask { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + let mut flag_vec = Vec::new(); + + let flags = [MethodAccessFlag::Public,MethodAccessFlag::Private,MethodAccessFlag::Protected,MethodAccessFlag::Static,MethodAccessFlag::Final,MethodAccessFlag::Synchronized,MethodAccessFlag::Bridge,MethodAccessFlag::Varargs,MethodAccessFlag::Native,MethodAccessFlag::Abstract,MethodAccessFlag::Strict,MethodAccessFlag::Synthetic]; + + for flag in flags { + if (flag as u16 & self.mask) != 0 { + flag_vec.push(flag) + } + } + + f.debug_list().entries(flag_vec) + .finish() + } +} + +#[derive(Debug, Copy, Clone)] +pub enum ClassAccessFlag { + Public = 0x0001, // Declared public; may be accessed from outside its package. + Final = 0x0010, // Declared final; no subclasses allowed. + Super = 0x0020, // Treat superclass methods specially when invoked by the invokespecial instruction. + Interface = 0x0200, // Is an interface, not a class. + Abstract = 0x0400, // Declared abstract; must not be instantiated. + Synthetic = 0x1000, // Declared synthetic; not present in the source code. + Annotation = 0x2000, // Declared as an annotation interface. + Enum = 0x4000, // Declared as an enum class. + Module = 0x8000, // Is a module, not a class or interface. +} + +pub struct ClassAccessFlagMask { + mask: u16, +} + +impl Debug for ClassAccessFlagMask { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + let mut flag_vec = Vec::new(); + + let flags = [ClassAccessFlag::Public,ClassAccessFlag::Final,ClassAccessFlag::Super,ClassAccessFlag::Interface,ClassAccessFlag::Abstract,ClassAccessFlag::Synthetic,ClassAccessFlag::Annotation,ClassAccessFlag::Enum,ClassAccessFlag::Module]; + for flag in flags { + if (flag as u16 & self.mask) != 0 { + flag_vec.push(flag) + } + } + + f.debug_list().entries(flag_vec) + .finish() + } +} + + fn read_buffer(reader: &mut dyn Read, size: usize) -> Result, Error> { let mut buffer: Box<[u8]> = vec![0; size].into_boxed_slice(); diff --git a/src/main.rs b/src/main.rs index 8a84f78..48d3164 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ mod classfile; mod bytecode; fn main() { - let class_file = classfile::JavaClassFile::new(&mut File::open("class/HashMap.class").unwrap()).unwrap(); + let class_file = classfile::JavaClassFile::new(&mut File::open("class/Enumerator$EnumeratorIterator.class").unwrap()).unwrap(); println!("{:#?}", class_file); }