use std::io::{Cursor, Read};
use byteorder::{BigEndian, ReadBytesExt};
use crate::node::attribute;
use crate::node::attribute::{
Attribute, AttributeInfo, ConstantValue, EnclosingMethod, Exceptions, ModuleMainClass,
ModulePackages, NestHost, NestMembers, PermittedSubclasses, Signature, SourceDebugExtension,
SourceFile,
};
use crate::node::constant::ConstantPool;
use crate::node::constant::Utf8;
use crate::parse::attribute::annotation::{
annotation_default, runtime_invisible_annotations, runtime_invisible_parameter_annotations,
runtime_invisible_type_annotations, runtime_visible_annotations,
runtime_visible_parameter_annotations, runtime_visible_type_annotations,
};
use crate::parse::attribute::bootstrap_methods::bootstrap_methods;
use crate::parse::attribute::code::code;
use crate::parse::attribute::inner_classes::inner_classes;
use crate::parse::attribute::line_number_table::line_number_table;
use crate::parse::attribute::local_variable_table::local_variable_table;
use crate::parse::attribute::local_variable_type_table::local_variable_type_table;
use crate::parse::attribute::method_parameters::method_parameters;
use crate::parse::attribute::module::module;
use crate::parse::attribute::record::record;
use crate::parse::attribute::stack_map_table::stack_map_table;
use crate::parse::error::{ParseError, ParseResult};
use crate::parse::ParsingOption;
mod annotation;
mod bootstrap_methods;
mod code;
mod inner_classes;
mod line_number_table;
mod local_variable_table;
mod local_variable_type_table;
mod method_parameters;
mod module;
mod record;
mod stack_map_table;
pub(super) fn attribute_info<'input: 'constant_pool, 'constant_pool, R: Read>(
input: &'input mut R,
constant_pool: &'constant_pool ConstantPool,
option: &ParsingOption,
) -> ParseResult<AttributeInfo> {
let attribute_name_index = input.read_u16::<BigEndian>()?;
let attribute_len = input.read_u32::<BigEndian>()?;
let mut info = vec![0; attribute_len as usize];
input.read_exact(&mut info)?;
let attribute = if !option.skip_attribute {
if let Some(Ok(attribute_name)) = constant_pool
.get_utf8(attribute_name_index)
.map(Utf8::string)
{
let mut info = Cursor::new(&mut info[..]);
let attribute = attribute(
&mut info,
constant_pool,
attribute_len,
&attribute_name,
option,
)?;
let mut remain = vec![];
info.read_to_end(&mut remain)?;
if !remain.is_empty() {
return Err(ParseError::Remains(remain.len()));
}
attribute
} else {
None
}
} else {
None
};
Ok(AttributeInfo {
attribute_name_index,
attribute_len,
info,
attribute,
})
}
fn attribute<'input: 'constant_pool, 'constant_pool: 'data, 'data, R: Read>(
input: &'input mut R,
constant_pool: &'constant_pool ConstantPool,
attribute_len: u32,
data: &'data str,
option: &ParsingOption,
) -> ParseResult<Option<Attribute>> {
let attribute = match data {
attribute::CONSTANT_VALUE => constant_value(input)?,
attribute::CODE => code(input, constant_pool, option)?,
attribute::STACK_MAP_TABLE => stack_map_table(input)?,
attribute::EXCEPTIONS => exceptions(input)?,
attribute::INNER_CLASSES => inner_classes(input)?,
attribute::ENCLOSING_METHOD => enclosing_method(input)?,
attribute::SYNTHETIC => Some(Attribute::Synthetic),
attribute::SIGNATURE => signature(input)?,
attribute::SOURCE_FILE => source_file(input)?,
attribute::SOURCE_DEBUG_EXTENSION => source_debug_extension(input, attribute_len)?,
attribute::LINE_NUMBER_TABLE => line_number_table(input)?,
attribute::LOCAL_VARIABLE_TABLE => local_variable_table(input)?,
attribute::LOCAL_VARIABLE_TYPE_TABLE => local_variable_type_table(input)?,
attribute::DEPRECATED => Some(Attribute::Deprecate),
attribute::RUNTIME_VISIBLE_ANNOTATIONS => runtime_visible_annotations(input)?,
attribute::RUNTIME_INVISIBLE_ANNOTATIONS => runtime_invisible_annotations(input)?,
attribute::RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS => {
runtime_visible_parameter_annotations(input)?
}
attribute::RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS => {
runtime_invisible_parameter_annotations(input)?
}
attribute::RUNTIME_VISIBLE_TYPE_ANNOTATIONS => runtime_visible_type_annotations(input)?,
attribute::RUNTIME_INVISIBLE_TYPE_ANNOTATIONS => runtime_invisible_type_annotations(input)?,
attribute::ANNOTATION_DEFAULT => annotation_default(input)?,
attribute::BOOTSTRAP_METHODS => bootstrap_methods(input)?,
attribute::METHOD_PARAMETERS => method_parameters(input)?,
attribute::MODULE => module(input)?,
attribute::MODULE_PACKAGES => module_packages(input)?,
attribute::MODULE_MAIN_CLASS => module_main_class(input)?,
attribute::NEST_HOST => nest_host(input)?,
attribute::NEST_MEMBERS => nest_members(input)?,
attribute::RECORD => record(input, constant_pool, option)?,
attribute::PERMITTED_SUBCLASSES => permitted_subclasses(input)?,
_ => None,
};
Ok(attribute)
}
#[inline]
fn constant_value<R: Read>(input: &mut R) -> ParseResult<Option<Attribute>> {
let constant_value_index = input.read_u16::<BigEndian>()?;
Ok(Some(Attribute::ConstantValue(ConstantValue {
constant_value_index,
})))
}
#[inline]
fn exceptions<R: Read>(input: &mut R) -> ParseResult<Option<Attribute>> {
let number_of_exceptions = input.read_u16::<BigEndian>()?;
let mut exception_index_table = vec![0; number_of_exceptions as usize];
for i in 0..number_of_exceptions {
exception_index_table[i as usize] = input.read_u16::<BigEndian>()?;
}
Ok(Some(Attribute::Exceptions(Exceptions {
number_of_exceptions,
exception_index_table,
})))
}
#[inline]
fn enclosing_method<R: Read>(input: &mut R) -> ParseResult<Option<Attribute>> {
let class_index = input.read_u16::<BigEndian>()?;
let method_index = input.read_u16::<BigEndian>()?;
Ok(Some(Attribute::EnclosingMethod(EnclosingMethod {
class_index,
method_index,
})))
}
#[inline]
fn signature<R: Read>(input: &mut R) -> ParseResult<Option<Attribute>> {
let signature_index = input.read_u16::<BigEndian>()?;
Ok(Some(Attribute::Signature(Signature { signature_index })))
}
#[inline]
fn source_file<R: Read>(input: &mut R) -> ParseResult<Option<Attribute>> {
let source_file_index = input.read_u16::<BigEndian>()?;
Ok(Some(Attribute::SourceFile(SourceFile {
source_file_index,
})))
}
#[inline]
fn source_debug_extension<R: Read>(
input: &mut R,
attribute_len: u32,
) -> ParseResult<Option<Attribute>> {
let mut debug_extension = vec![0; attribute_len as usize];
input.read_exact(&mut debug_extension)?;
Ok(Some(Attribute::SourceDebugExtension(
SourceDebugExtension { debug_extension },
)))
}
#[inline]
fn module_packages<R: Read>(input: &mut R) -> ParseResult<Option<Attribute>> {
let package_count = input.read_u16::<BigEndian>()?;
let mut package_index = vec![0; package_count as usize];
for i in 0..package_count {
package_index[i as usize] = input.read_u16::<BigEndian>()?;
}
Ok(Some(Attribute::ModulePackages(ModulePackages {
package_count,
package_index,
})))
}
#[inline]
fn module_main_class<R: Read>(input: &mut R) -> ParseResult<Option<Attribute>> {
let main_class_index = input.read_u16::<BigEndian>()?;
Ok(Some(Attribute::ModuleMainClass(ModuleMainClass {
main_class_index,
})))
}
#[inline]
fn nest_host<R: Read>(input: &mut R) -> ParseResult<Option<Attribute>> {
let host_class_index = input.read_u16::<BigEndian>()?;
Ok(Some(Attribute::NestHost(NestHost { host_class_index })))
}
#[inline]
fn nest_members<R: Read>(input: &mut R) -> ParseResult<Option<Attribute>> {
let number_of_classes = input.read_u16::<BigEndian>()?;
let mut classes = vec![0; number_of_classes as usize];
for i in 0..number_of_classes {
classes[i as usize] = input.read_u16::<BigEndian>()?;
}
Ok(Some(Attribute::NestMembers(NestMembers {
number_of_classes,
classes,
})))
}
#[inline]
fn permitted_subclasses<R: Read>(input: &mut R) -> ParseResult<Option<Attribute>> {
let number_of_classes = input.read_u16::<BigEndian>()?;
let mut classes = vec![0; number_of_classes as usize];
for i in 0..number_of_classes {
classes[i as usize] = input.read_u16::<BigEndian>()?;
}
Ok(Some(Attribute::PermittedSubclasses(PermittedSubclasses {
number_of_classes,
classes,
})))
}