Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,4 @@ fn main() {
- [x] LocalVariableTable
- [x] LocalVariableTypeTable
- [x] Deprecated
- [x] Module
1 change: 1 addition & 0 deletions java-assets/compile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ javac -d java-assets/compiled-classes/ java-assets/src/UnicodeStrings.java
javac -d java-assets/compiled-classes/ java-assets/src/DeprecatedAnnotation.java
javac -d java-assets/compiled-classes/ java-assets/src/InnerClasses.java
javac -d java-assets/compiled-classes/ java-assets/src/Annotations.java
javac -d java-assets/compiled-classes/ java-assets/src/module-info.java java-assets/src/com/some/Thing.java

javac -g -d java-assets/compiled-classes/ java-assets/src/LocalVariableTable.java
javac -d java-assets/compiled-classes/ java-assets/src/HelloWorld.java
Expand Down
Binary file added java-assets/compiled-classes/com/some/Thing.class
Binary file not shown.
Binary file added java-assets/compiled-classes/module-info.class
Binary file not shown.
3 changes: 3 additions & 0 deletions java-assets/src/com/some/Thing.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.some;

public class Thing {}
3 changes: 3 additions & 0 deletions java-assets/src/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module my.module {
exports com.some;
}
1 change: 1 addition & 0 deletions src/attribute_info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub use self::parser::exceptions_attribute_parser;
pub use self::parser::inner_classes_attribute_parser;
pub use self::parser::line_number_table_attribute_parser;
pub use self::parser::method_parameters_attribute_parser;
pub use self::parser::module_attribute_parser;
pub use self::parser::runtime_invisible_annotations_attribute_parser;
pub use self::parser::runtime_invisible_parameter_annotations_attribute_parser;
pub use self::parser::runtime_invisible_type_annotations_attribute_parser;
Expand Down
107 changes: 107 additions & 0 deletions src/attribute_info/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,3 +697,110 @@ pub fn sourcefile_attribute_parser(
let (input, sourcefile_index) = be_u16(input)?;
Ok((input, SourceFileAttribute { sourcefile_index }))
}

pub fn module_attribute_parser(input: &[u8]) -> Result<(&[u8], ModuleAttribute), Err<&[u8]>> {
let (input, module_name_index) = be_u16(input)?;
let (input, module_flags) = be_u16(input)?;
let (input, module_version_index) = be_u16(input)?;

let (input, requires_count) = be_u16(input)?;
let (input, requires) =
count(module_requires_attribute_parser, requires_count as usize)(input)?;

let (input, exports_count) = be_u16(input)?;
let (input, exports) = count(module_exports_attribute_parser, exports_count as usize)(input)?;

let (input, opens_count) = be_u16(input)?;
let (input, opens) = count(module_opens_attribute_parser, opens_count as usize)(input)?;

let (input, uses_count) = be_u16(input)?;
let (input, uses) = count(be_u16, uses_count as usize)(input)?;

let (input, provides_count) = be_u16(input)?;
let (input, provides) =
count(module_provides_attribute_parser, provides_count as usize)(input)?;

Ok((
input,
ModuleAttribute {
module_name_index,
module_flags,
module_version_index,
requires,
exports,
opens,
uses,
provides,
},
))
}

pub fn module_requires_attribute_parser(
input: &[u8],
) -> Result<(&[u8], ModuleRequiresAttribute), Err<&[u8]>> {
let (input, requires_index) = be_u16(input)?;
let (input, requires_flags) = be_u16(input)?;
let (input, requires_version_index) = be_u16(input)?;

Ok((
input,
ModuleRequiresAttribute {
requires_index,
requires_flags,
requires_version_index,
},
))
}

pub fn module_exports_attribute_parser(
input: &[u8],
) -> Result<(&[u8], ModuleExportsAttribute), Err<&[u8]>> {
let (input, exports_index) = be_u16(input)?;
let (input, exports_flags) = be_u16(input)?;
let (input, exports_to_count) = be_u16(input)?;

let (input, exports_to_index) = count(be_u16, exports_to_count as usize)(input)?;

Ok((
input,
ModuleExportsAttribute {
exports_index,
exports_flags,
exports_to_index,
},
))
}

pub fn module_opens_attribute_parser(
input: &[u8],
) -> Result<(&[u8], ModuleOpensAttribute), Err<&[u8]>> {
let (input, opens_index) = be_u16(input)?;
let (input, opens_flags) = be_u16(input)?;
let (input, opens_to_count) = be_u16(input)?;
let (input, opens_to_index) = count(be_u16, opens_to_count as usize)(input)?;

Ok((
input,
ModuleOpensAttribute {
opens_index,
opens_flags,
opens_to_index,
},
))
}

pub fn module_provides_attribute_parser(
input: &[u8],
) -> Result<(&[u8], ModuleProvidesAttribute), Err<&[u8]>> {
let (input, provides_index) = be_u16(input)?;
let (input, provides_with_count) = be_u16(input)?;
let (input, provides_with_index) = count(be_u16, provides_with_count as usize)(input)?;

Ok((
input,
ModuleProvidesAttribute {
provides_index,
provides_with_index,
},
))
}
36 changes: 36 additions & 0 deletions src/attribute_info/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,39 @@ pub struct SourceFileAttribute {
/// The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing a string.
pub sourcefile_index: u16,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ModuleAttribute {
pub module_name_index: u16,
pub module_flags: u16,
pub module_version_index: u16,
pub requires: Vec<ModuleRequiresAttribute>,
pub exports: Vec<ModuleExportsAttribute>,
pub opens: Vec<ModuleOpensAttribute>,
pub uses: Vec<u16>,
pub provides: Vec<ModuleProvidesAttribute>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ModuleRequiresAttribute {
pub requires_index: u16,
pub requires_flags: u16,
pub requires_version_index: u16,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ModuleExportsAttribute {
pub exports_index: u16,
pub exports_flags: u16,
pub exports_to_index: Vec<u16>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ModuleOpensAttribute {
pub opens_index: u16,
pub opens_flags: u16,
pub opens_to_index: Vec<u16>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ModuleProvidesAttribute {
pub provides_index: u16,
pub provides_with_index: Vec<u16>,
}
12 changes: 12 additions & 0 deletions src/constant_info/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,16 @@ fn const_invoke_dynamic(input: &[u8]) -> ConstantInfoResult<'_> {
))
}

fn const_module(input: &[u8]) -> ConstantInfoResult<'_> {
let (input, name_index) = be_u16(input)?;
Ok((input, ConstantInfo::Module(ModuleConstant { name_index })))
}

fn const_package(input: &[u8]) -> ConstantInfoResult<'_> {
let (input, name_index) = be_u16(input)?;
Ok((input, ConstantInfo::Package(PackageConstant { name_index })))
}

type ConstantInfoResult<'a> = Result<(&'a [u8], ConstantInfo), Err<Error<&'a [u8]>>>;
type ConstantInfoVecResult<'a> = Result<(&'a [u8], Vec<ConstantInfo>), Err<Error<&'a [u8]>>>;

Expand All @@ -150,6 +160,8 @@ fn const_block_parser(input: &[u8], const_type: u8) -> ConstantInfoResult<'_> {
15 => const_method_handle(input),
16 => const_method_type(input),
18 => const_invoke_dynamic(input),
19 => const_module(input),
20 => const_package(input),
_ => Result::Err(Err::Error(error_position!(input, ErrorKind::Alt))),
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/constant_info/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub enum ConstantInfo {
MethodHandle(MethodHandleConstant),
MethodType(MethodTypeConstant),
InvokeDynamic(InvokeDynamicConstant),
Module(ModuleConstant),
Package(PackageConstant),
Unusable,
}

Expand Down Expand Up @@ -110,3 +112,15 @@ pub struct InvokeDynamicConstant {
pub bootstrap_method_attr_index: u16,
pub name_and_type_index: u16,
}

#[derive(Clone, Debug)]
#[binrw]
pub struct ModuleConstant {
pub name_index: u16,
}

#[derive(Clone, Debug)]
#[binrw]
pub struct PackageConstant {
pub name_index: u16,
}
77 changes: 70 additions & 7 deletions tests/code_attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ extern crate classfile_parser;
//use std::assert_matches::assert_matches;

use classfile_parser::attribute_info::{
DefaultAnnotation, ElementValue, InnerClassAccessFlags, TargetInfo, code_attribute_parser,
element_value_parser, enclosing_method_attribute_parser, inner_classes_attribute_parser,
DefaultAnnotation, ElementValue, InnerClassAccessFlags, ModuleAttribute,
ModuleExportsAttribute, ModuleRequiresAttribute, code_attribute_parser, element_value_parser,
enclosing_method_attribute_parser, inner_classes_attribute_parser,
line_number_table_attribute_parser, method_parameters_attribute_parser,
runtime_invisible_annotations_attribute_parser,
module_attribute_parser, runtime_invisible_annotations_attribute_parser,
runtime_invisible_parameter_annotations_attribute_parser,
runtime_visible_annotations_attribute_parser,
runtime_visible_parameter_annotations_attribute_parser,
Expand All @@ -21,7 +22,7 @@ use classfile_parser::code_attribute::{
Instruction, LocalVariableTableAttribute, code_parser, instruction_parser,
local_variable_type_table_parser,
};
use classfile_parser::constant_info::{ConstantInfo, Utf8Constant};
use classfile_parser::constant_info::ConstantInfo;
use classfile_parser::method_info::MethodAccessFlags;

#[test]
Expand Down Expand Up @@ -102,9 +103,9 @@ fn test_class() {
fn lookup_string(c: &classfile_parser::ClassFile, index: u16) -> Option<String> {
let con = &c.const_pool[(index - 1) as usize];
match con {
classfile_parser::constant_info::ConstantInfo::Utf8(utf8) => {
Some(utf8.utf8_string.to_string())
}
ConstantInfo::Utf8(utf8) => Some(utf8.utf8_string.to_string()),
ConstantInfo::Module(m) => lookup_string(c, m.name_index),
ConstantInfo::Package(p) => lookup_string(c, p.name_index),
_ => None,
}
}
Expand Down Expand Up @@ -864,3 +865,65 @@ fn deprecated() {

assert_eq!(deprecated_field_attribute.len(), 1);
}

#[test]
fn module_info() {
let class_bytes = include_bytes!("../java-assets/compiled-classes/module-info.class");
let (_, class) = class_parser(class_bytes).unwrap();

let module = class
.attributes
.iter()
.find(|attribute_info| {
matches!(
lookup_string(&class, attribute_info.attribute_name_index)
.unwrap()
.as_str(),
"Module"
)
})
.unwrap();

let (rest, module) = module_attribute_parser(&module.info).unwrap();
assert_eq!(rest.len(), 0);

let exptected = ModuleAttribute {
module_name_index: 6,
module_flags: 0,
module_version_index: 0,
requires: vec![ModuleRequiresAttribute {
requires_index: 8,
requires_flags: 32768,
requires_version_index: 10,
}],
exports: vec![ModuleExportsAttribute {
exports_index: 11,
exports_flags: 0,
exports_to_index: vec![],
}],
opens: vec![],
uses: vec![],
provides: vec![],
};

assert_eq!(module, exptected);

assert_eq!(
lookup_string(&class, exptected.module_name_index)
.unwrap()
.as_str(),
"my.module"
);
assert_eq!(
lookup_string(&class, exptected.requires.first().unwrap().requires_index)
.unwrap()
.as_str(),
"java.base"
);
assert_eq!(
lookup_string(&class, exptected.exports.first().unwrap().exports_index)
.unwrap()
.as_str(),
"com/some"
);
}