use scroll::{ctx, Pread, Uleb128};
use std::ops::Deref;
use getset::{CopyGetters, Getters};
use crate::{
encoded_value::EncodedValue,
error::Error,
field::FieldId,
jtype::{Type, TypeId},
method::MethodId,
string::{DexString, StringId},
ubyte, uint,
};
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
#[derive(Debug, Getters, PartialEq)]
#[get = "pub"]
pub struct EncodedAnnotation {
jtype: Type,
elements: Vec<AnnotationElement>,
}
impl EncodedAnnotation {
pub fn find_element(&self, name: &str) -> Option<&AnnotationElement> {
self.elements().iter().find(|e| e.name() == name)
}
}
impl Deref for EncodedAnnotation {
type Target = Vec<AnnotationElement>;
fn deref(&self) -> &Self::Target {
&self.elements
}
}
impl<'a, S> ctx::TryFromCtx<'a, &super::Dex<S>> for EncodedAnnotation
where
S: AsRef<[u8]>,
{
type Error = Error;
type Size = usize;
fn try_from_ctx(source: &'a [u8], ctx: &super::Dex<S>) -> super::Result<(Self, Self::Size)> {
let offset = &mut 0;
let type_idx = Uleb128::read(source, offset)?;
let jtype = ctx.get_type(type_idx as TypeId)?;
let size = Uleb128::read(source, offset)?;
debug!(target: "encoded-annotation", "type: {}, size: {}", jtype, size);
let elements = try_gread_vec_with!(source, offset, size, ctx);
Ok((Self { jtype, elements }, *offset))
}
}
#[derive(Debug, Getters, PartialEq)]
#[get = "pub"]
pub struct AnnotationElement {
name: DexString,
value: EncodedValue,
}
impl<'a, S> ctx::TryFromCtx<'a, &super::Dex<S>> for AnnotationElement
where
S: AsRef<[u8]>,
{
type Error = Error;
type Size = usize;
fn try_from_ctx(source: &'a [u8], ctx: &super::Dex<S>) -> super::Result<(Self, Self::Size)> {
let offset = &mut 0;
let name_idx = Uleb128::read(source, offset)?;
let name = ctx.get_string(name_idx as StringId)?;
debug!(target: "annotation-element", "annotation element: {}", name_idx);
let value = source.gread_with(offset, ctx)?;
Ok((Self { name, value }, *offset))
}
}
#[derive(Debug, FromPrimitive, Copy, Clone, PartialEq)]
pub enum Visibility {
Build = 0x0,
Runtime = 0x1,
System = 0x2,
}
#[derive(Debug, Getters, CopyGetters)]
pub struct AnnotationItem {
#[get_copy = "pub"]
visibility: Visibility,
#[get = "pub"]
annotation: EncodedAnnotation,
}
impl Deref for AnnotationItem {
type Target = EncodedAnnotation;
fn deref(&self) -> &Self::Target {
&self.annotation
}
}
impl<'a, S> ctx::TryFromCtx<'a, &super::Dex<S>> for AnnotationItem
where
S: AsRef<[u8]>,
{
type Error = Error;
type Size = usize;
fn try_from_ctx(source: &'a [u8], ctx: &super::Dex<S>) -> super::Result<(Self, Self::Size)> {
let offset = &mut 0;
let visibility: ubyte = source.gread_with(offset, ctx.get_endian())?;
debug!(target: "annotation-item", "visibility: {:?}", visibility);
let visibility: Visibility = FromPrimitive::from_u8(visibility)
.ok_or_else(|| Error::InvalidId("Invalid visibility for annotation".to_owned()))?;
let annotation = source.gread_with(offset, ctx)?;
Ok((
Self {
visibility,
annotation,
},
*offset,
))
}
}
#[derive(Debug, Default, Getters)]
#[get = "pub"]
pub struct AnnotationSetRefList {
annotation_set_list: Vec<AnnotationSetItem>,
}
impl Deref for AnnotationSetRefList {
type Target = Vec<AnnotationSetItem>;
fn deref(&self) -> &Self::Target {
&self.annotation_set_list
}
}
impl<'a, S> ctx::TryFromCtx<'a, &super::Dex<S>> for AnnotationSetRefList
where
S: AsRef<[u8]>,
{
type Error = Error;
type Size = usize;
fn try_from_ctx(source: &'a [u8], ctx: &super::Dex<S>) -> super::Result<(Self, Self::Size)> {
let offset = &mut 0;
let endian = ctx.get_endian();
let size: uint = source.gread_with(offset, endian)?;
debug!(target: "annotation-set-ref-list", "annotation set ref list size: {}", size);
let annotation_ref_items: Vec<uint> = try_gread_vec_with!(source, offset, size, endian);
Ok((
Self {
annotation_set_list: annotation_ref_items
.iter()
.map(|annotation_set_item_off| {
ctx.get_annotation_set_item(*annotation_set_item_off)
})
.collect::<super::Result<_>>()?,
},
*offset,
))
}
}
#[derive(Debug, Default, Getters)]
#[get = "pub"]
pub struct AnnotationSetItem {
annotations: Vec<AnnotationItem>,
}
impl Deref for AnnotationSetItem {
type Target = Vec<AnnotationItem>;
fn deref(&self) -> &Self::Target {
&self.annotations
}
}
impl<'a, S> ctx::TryFromCtx<'a, &super::Dex<S>> for AnnotationSetItem
where
S: AsRef<[u8]>,
{
type Error = Error;
type Size = usize;
fn try_from_ctx(source: &'a [u8], ctx: &super::Dex<S>) -> super::Result<(Self, Self::Size)> {
let offset = &mut 0;
let endian = ctx.get_endian();
let size: uint = source.gread_with(offset, endian)?;
debug!(target: "annotation-set-item", "annotation set items size: {}", size);
let annotation_items_offs: Vec<uint> = try_gread_vec_with!(source, offset, size, endian);
Ok((
Self {
annotations: annotation_items_offs
.iter()
.map(|annotation_off| ctx.get_annotation_item(*annotation_off))
.collect::<super::Result<_>>()?,
},
*offset,
))
}
}
#[derive(Debug, Getters, CopyGetters)]
pub struct ParameterAnnotations {
#[get_copy = "pub"]
method_idx: MethodId,
pub(crate) annotations: AnnotationSetRefList,
}
impl<'a, S> ctx::TryFromCtx<'a, &super::Dex<S>> for ParameterAnnotations
where
S: AsRef<[u8]>,
{
type Error = Error;
type Size = usize;
fn try_from_ctx(source: &'a [u8], ctx: &super::Dex<S>) -> super::Result<(Self, Self::Size)> {
let offset = &mut 0;
let endian = ctx.get_endian();
let method_idx: uint = source.gread_with(offset, endian)?;
let annotation_set_ref_list_off: uint = source.gread_with(offset, endian)?;
debug!(target: "parameter-annotation", "annotation set ref list offset: {}", annotation_set_ref_list_off);
Ok((
Self {
method_idx: MethodId::from(method_idx),
annotations: ctx.get_annotation_set_ref_list(annotation_set_ref_list_off)?,
},
*offset,
))
}
}
#[derive(Debug, Getters, CopyGetters)]
pub struct MethodAnnotations {
#[get_copy = "pub"]
method_idx: MethodId,
pub(crate) annotations: AnnotationSetItem,
}
impl<'a, S> ctx::TryFromCtx<'a, &super::Dex<S>> for MethodAnnotations
where
S: AsRef<[u8]>,
{
type Error = Error;
type Size = usize;
fn try_from_ctx(source: &'a [u8], ctx: &super::Dex<S>) -> super::Result<(Self, Self::Size)> {
let offset = &mut 0;
let method_idx: uint = source.gread_with(offset, ctx.get_endian())?;
let annotation_set_item_off: uint = source.gread_with(offset, ctx.get_endian())?;
debug!(target: "method-annotation", "annotation set item offset: {}", annotation_set_item_off);
Ok((
Self {
method_idx: MethodId::from(method_idx),
annotations: ctx.get_annotation_set_item(annotation_set_item_off)?,
},
*offset,
))
}
}
#[derive(Debug, Getters, CopyGetters)]
pub struct FieldAnnotations {
#[get_copy = "pub"]
field_idx: FieldId,
#[get = "pub"]
pub(crate) annotations: AnnotationSetItem,
}
impl<'a, S> ctx::TryFromCtx<'a, &super::Dex<S>> for FieldAnnotations
where
S: AsRef<[u8]>,
{
type Error = Error;
type Size = usize;
fn try_from_ctx(source: &'a [u8], ctx: &super::Dex<S>) -> super::Result<(Self, Self::Size)> {
let offset = &mut 0;
let field_idx: uint = source.gread_with(offset, ctx.get_endian())?;
let annotation_set_item_off: uint = source.gread_with(offset, ctx.get_endian())?;
debug!(target: "field-annotation", "annotation set item offset: {}", annotation_set_item_off);
Ok((
Self {
field_idx: FieldId::from(field_idx),
annotations: ctx.get_annotation_set_item(annotation_set_item_off)?,
},
*offset,
))
}
}
#[derive(Debug, Default, Getters)]
pub struct AnnotationsDirectoryItem {
pub(crate) class_annotations: AnnotationSetItem,
pub(crate) field_annotations: Vec<FieldAnnotations>,
pub(crate) method_annotations: Vec<MethodAnnotations>,
pub(crate) parameter_annotations: Vec<ParameterAnnotations>,
}
impl<'a, S> ctx::TryFromCtx<'a, &super::Dex<S>> for AnnotationsDirectoryItem
where
S: AsRef<[u8]>,
{
type Error = Error;
type Size = usize;
fn try_from_ctx(source: &'a [u8], ctx: &super::Dex<S>) -> super::Result<(Self, Self::Size)> {
let offset = &mut 0;
let endian = ctx.get_endian();
let class_annotations_off: uint = source.gread_with(offset, endian)?;
let fields_size: uint = source.gread_with(offset, endian)?;
let annotated_method_size: uint = source.gread_with(offset, endian)?;
let annotated_parameters_size: uint = source.gread_with(offset, endian)?;
debug!(target: "annotations directory", "fields size: {}, annotated method size: {}, annotated params size: {}",
fields_size, annotated_method_size, annotated_parameters_size);
let class_annotations = ctx.get_annotation_set_item(class_annotations_off)?;
let field_annotations = try_gread_vec_with!(source, offset, fields_size, ctx);
let method_annotations = try_gread_vec_with!(source, offset, annotated_method_size, ctx);
let parameter_annotations =
try_gread_vec_with!(source, offset, annotated_parameters_size, ctx);
Ok((
Self {
class_annotations,
field_annotations,
method_annotations,
parameter_annotations,
},
*offset,
))
}
}