use std::clone::Clone;
use getset::{CopyGetters, Getters};
use scroll::ctx;
use scroll::{Pread, Uleb128};
use crate::annotation::AnnotationsDirectoryItem;
use crate::cache::Ref;
use crate::encoded_item::EncodedItemArrayCtx;
use crate::encoded_value::EncodedArray;
use crate::error::Error;
use crate::field::EncodedFieldArray;
use crate::field::Field;
use crate::jtype::Type;
use crate::method::EncodedMethodArray;
use crate::method::Method;
use crate::source::Source;
use crate::string::JString;
use crate::uint;
pub type ClassId = uint;
bitflags! {
pub struct AccessFlags: uint {
const PUBLIC = 0x1;
const PRIVATE = 0x2;
const PROTECTED = 0x4;
const STATIC = 0x8;
const FINAL = 0x10;
const INTERFACE = 0x200;
const ABSTRACT = 0x400;
const SYNTHETIC = 0x1000;
const ANNOTATION = 0x2000;
const ENUM = 0x4000;
}
}
#[derive(Debug, Getters, CopyGetters)]
pub struct Class {
#[get_copy = "pub"]
pub(crate) id: ClassId,
#[get = "pub"]
pub(crate) jtype: Type,
#[get_copy = "pub"]
pub(crate) access_flags: AccessFlags,
#[get_copy = "pub"]
pub(crate) super_class: Option<ClassId>,
#[get = "pub"]
pub(crate) interfaces: Option<Vec<Type>>,
#[get = "pub"]
pub(crate) annotations: Option<AnnotationsDirectoryItem>,
#[get = "pub"]
pub(crate) source_file: Option<Ref<JString>>,
pub(crate) static_fields: Vec<Field>,
pub(crate) instance_fields: Vec<Field>,
pub(crate) direct_methods: Vec<Method>,
pub(crate) virtual_methods: Vec<Method>,
#[get = "pub"]
pub(crate) static_values: EncodedArray,
}
impl Class {
pub fn static_fields(&self) -> impl Iterator<Item = &Field> + '_ {
self.static_fields.iter()
}
pub fn instance_fields(&self) -> impl Iterator<Item = &Field> + '_ {
self.instance_fields.iter()
}
pub fn direct_methods(&self) -> impl Iterator<Item = &Method> + '_ {
self.direct_methods.iter()
}
pub fn virtual_methods(&self) -> impl Iterator<Item = &Method> + '_ {
self.virtual_methods.iter()
}
pub fn fields(&self) -> impl Iterator<Item = &Field> + '_ {
self.static_fields().chain(self.instance_fields())
}
pub fn methods(&self) -> impl Iterator<Item = &Method> + '_ {
self.direct_methods().chain(self.virtual_methods())
}
pub(crate) fn try_from_dex<T: AsRef<[u8]>>(
dex: &super::Dex<T>,
class_def: &ClassDefItem,
) -> super::Result<Self> {
debug!(target: "class", "trying to load class: {}", class_def.class_idx);
let jtype = dex.get_type(class_def.class_idx)?;
debug!(target: "class", "class: {}, jtype: {}", class_def.class_idx, jtype);
let data_off = class_def.class_data_off;
let (static_fields, instance_fields, direct_methods, virtual_methods) = dex
.get_class_data(data_off)?
.map(|c| {
let ef = |encoded_field| dex.get_field(&encoded_field);
let em = |encoded_method| dex.get_method(&encoded_method);
Ok((
try_from_item!(c.static_fields, ef),
try_from_item!(c.instance_fields, ef),
try_from_item!(c.direct_methods, em),
try_from_item!(c.virtual_methods, em),
))
})
.unwrap_or_else(|| Ok::<_, Error>((Vec::new(), Vec::new(), Vec::new(), Vec::new())))?;
let static_values = dex.get_static_values(class_def.static_values_off)?;
let annotations = dex.get_annotations_directory_item(class_def.annotations_off)?;
debug!(target: "class", "super class id: {}", class_def.superclass_idx);
let super_class = if class_def.superclass_idx == super::NO_INDEX {
Some(class_def.superclass_idx)
} else {
None
};
debug!(target: "class", "access flags: {}", class_def.access_flags);
Ok(Class {
id: class_def.class_idx,
jtype,
super_class,
interfaces: dex.get_interfaces(class_def.interfaces_off)?,
access_flags: AccessFlags::from_bits(class_def.access_flags).ok_or_else(|| {
Error::InvalidId(format!(
"Invalid Access flags in class {}",
class_def.class_idx
))
})?,
source_file: dex.get_source_file(class_def.source_file_idx)?,
annotations,
static_fields,
instance_fields,
direct_methods,
virtual_methods,
static_values,
})
}
}
#[derive(Getters)]
#[get = "pub"]
pub struct ClassDataItem {
static_fields: Option<EncodedFieldArray>,
instance_fields: Option<EncodedFieldArray>,
direct_methods: Option<EncodedMethodArray>,
virtual_methods: Option<EncodedMethodArray>,
}
impl<'a, S> ctx::TryFromCtx<'a, &super::Dex<S>> for ClassDataItem
where
S: AsRef<[u8]>,
{
type Error = Error;
type Size = usize;
fn try_from_ctx(source: &'a [u8], dex: &super::Dex<S>) -> super::Result<(Self, Self::Size)> {
let offset = &mut 0;
let static_field_size = Uleb128::read(source, offset)?;
let instance_field_size = Uleb128::read(source, offset)?;
let direct_methods_size = Uleb128::read(source, offset)?;
let virtual_methods_size = Uleb128::read(source, offset)?;
debug!(target: "class data", "static-fields: {}, instance-fields: {}, direct-methods: {}, virtual-methods: {}",
static_field_size, instance_field_size, direct_methods_size, virtual_methods_size);
Ok((
ClassDataItem {
static_fields: encoded_array!(source, dex, offset, static_field_size),
instance_fields: encoded_array!(source, dex, offset, instance_field_size),
direct_methods: encoded_array!(source, dex, offset, direct_methods_size),
virtual_methods: encoded_array!(source, dex, offset, virtual_methods_size),
},
*offset,
))
}
}
#[derive(Copy, Clone, Debug, Pread, CopyGetters)]
#[get_copy = "pub"]
pub struct ClassDefItem {
pub(crate) class_idx: uint,
pub(crate) access_flags: uint,
pub(crate) superclass_idx: uint,
pub(crate) interfaces_off: uint,
pub(crate) source_file_idx: uint,
pub(crate) annotations_off: uint,
pub(crate) class_data_off: uint,
pub(crate) static_values_off: uint,
}
pub(crate) struct ClassDefItemIter<T> {
source: Source<T>,
offset: usize,
len: uint,
endian: super::Endian,
}
impl<T> ClassDefItemIter<T> {
pub(crate) fn new(source: Source<T>, offset: uint, len: uint, endian: super::Endian) -> Self {
Self {
source,
offset: offset as usize,
len,
endian,
}
}
}
impl<T: AsRef<[u8]>> Iterator for ClassDefItemIter<T> {
type Item = super::Result<ClassDefItem>;
fn next(&mut self) -> Option<Self::Item> {
if self.len == 0 {
return None;
}
let class_item: super::Result<ClassDefItem> = self
.source
.as_ref()
.gread_with(&mut self.offset, self.endian)
.map_err(Error::from);
self.len -= 1;
Some(class_item)
}
}