291 lines
9.4 KiB
Rust
291 lines
9.4 KiB
Rust
//! Annotation items.
|
|
|
|
pub mod encoded_annotation;
|
|
pub use encoded_annotation::*;
|
|
|
|
use crate as androscalpel_serializer;
|
|
use crate::{ReadSeek, Result, Serializable};
|
|
use std::io::Write;
|
|
|
|
/// <https://source.android.com/docs/core/runtime/dex-format#referenced-from-class_def_item_1>
|
|
/// alignment: 4 bytes
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct AnnotationDirectoryItem {
|
|
/// 0 if they are no annotation, else offset of an [`crate::AnnotationSetItem`].
|
|
pub class_annotations_off: u32,
|
|
// pub fields_size: u32,
|
|
// pub annotated_methods_size: u32,
|
|
// pub annotated_parameters_size: u32,
|
|
/// List of field annotation. The field annotations must be sorted by
|
|
/// increasing order of [`crate::FieldAnnotation.field_idx`].
|
|
pub field_annotations: Vec<FieldAnnotation>,
|
|
/// List of method annotation. The method annotations must be sorted by
|
|
/// increasing order of [`crate::MethodAnnotation.method_idx`].
|
|
pub method_annotation: Vec<MethodAnnotation>,
|
|
/// List of associated method parameter annotation. The parameter annotations
|
|
/// must be sorted by increasing order of [`crate::ParameterAnnotation.parameter_size`].
|
|
pub parameter_annotations: Vec<ParameterAnnotation>,
|
|
}
|
|
|
|
impl AnnotationDirectoryItem {
|
|
pub fn fields_size_field(&self) -> u32 {
|
|
self.field_annotations.len() as u32
|
|
}
|
|
pub fn annotated_methods_size_field(&self) -> u32 {
|
|
self.method_annotation.len() as u32
|
|
}
|
|
pub fn parameter_annotations_field(&self) -> u32 {
|
|
self.parameter_annotations.len() as u32
|
|
}
|
|
}
|
|
|
|
impl Serializable for AnnotationDirectoryItem {
|
|
fn serialize(&self, output: &mut dyn Write) -> Result<()> {
|
|
self.class_annotations_off.serialize(output)?;
|
|
self.fields_size_field().serialize(output)?;
|
|
self.annotated_methods_size_field().serialize(output)?;
|
|
self.parameter_annotations_field().serialize(output)?;
|
|
|
|
for item in &self.field_annotations {
|
|
item.serialize(output)?;
|
|
}
|
|
for item in &self.method_annotation {
|
|
item.serialize(output)?;
|
|
}
|
|
for item in &self.parameter_annotations {
|
|
item.serialize(output)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
|
|
let class_annotations_off = u32::deserialize(input)?;
|
|
let fields_size = u32::deserialize(input)?;
|
|
let annotated_methods_size = u32::deserialize(input)?;
|
|
let annotated_parameters_size = u32::deserialize(input)?;
|
|
let mut field_annotations = vec![];
|
|
for _ in 0..fields_size {
|
|
field_annotations.push(FieldAnnotation::deserialize(input)?);
|
|
}
|
|
let mut method_annotation = vec![];
|
|
for _ in 0..annotated_methods_size {
|
|
method_annotation.push(MethodAnnotation::deserialize(input)?);
|
|
}
|
|
let mut parameter_annotations = vec![];
|
|
for _ in 0..annotated_parameters_size {
|
|
parameter_annotations.push(ParameterAnnotation::deserialize(input)?);
|
|
}
|
|
|
|
Ok(Self {
|
|
class_annotations_off,
|
|
field_annotations,
|
|
method_annotation,
|
|
parameter_annotations,
|
|
})
|
|
}
|
|
fn size(&self) -> usize {
|
|
self.class_annotations_off.size()
|
|
+ self.fields_size_field().size()
|
|
+ self.annotated_methods_size_field().size()
|
|
+ self.parameter_annotations_field().size()
|
|
+ self
|
|
.field_annotations
|
|
.iter()
|
|
.map(|val| val.size())
|
|
.sum::<usize>()
|
|
+ self
|
|
.method_annotation
|
|
.iter()
|
|
.map(|val| val.size())
|
|
.sum::<usize>()
|
|
+ self
|
|
.parameter_annotations
|
|
.iter()
|
|
.map(|val| val.size())
|
|
.sum::<usize>()
|
|
}
|
|
}
|
|
|
|
/// <https://source.android.com/docs/core/runtime/dex-format#field-annotation>
|
|
#[derive(Serializable, Debug, Clone, PartialEq, Eq)]
|
|
pub struct FieldAnnotation {
|
|
pub field_idx: u32,
|
|
/// Offset to a [`AnnotationSetItem`]
|
|
pub annotation_off: u32,
|
|
}
|
|
|
|
/// <https://source.android.com/docs/core/runtime/dex-format#method-annotation>
|
|
#[derive(Serializable, Debug, Clone, PartialEq, Eq)]
|
|
pub struct MethodAnnotation {
|
|
pub method_idx: u32,
|
|
/// Offset to a [`AnnotationSetItem`]
|
|
pub annotation_off: u32,
|
|
}
|
|
|
|
/// <https://source.android.com/docs/core/runtime/dex-format#parameter-annotation>
|
|
#[derive(Serializable, Debug, Clone, PartialEq, Eq)]
|
|
pub struct ParameterAnnotation {
|
|
pub field_idx: u32,
|
|
/// Offset of a [`AnnotationSetRefList`]
|
|
pub annotation_off: u32,
|
|
}
|
|
|
|
/// <https://source.android.com/docs/core/runtime/dex-format#set-ref-list>
|
|
/// alignment: 4 bytes
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct AnnotationSetRefList {
|
|
// pub size: u32,
|
|
pub list: Vec<AnnotationSetRefItem>,
|
|
}
|
|
|
|
impl AnnotationSetRefList {
|
|
pub fn size_field(&self) -> u32 {
|
|
self.list.len() as u32
|
|
}
|
|
}
|
|
|
|
impl Serializable for AnnotationSetRefList {
|
|
fn serialize(&self, output: &mut dyn Write) -> Result<()> {
|
|
self.size_field().serialize(output)?;
|
|
for item in &self.list {
|
|
item.serialize(output)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
|
|
let size = u32::deserialize(input)?;
|
|
let mut list = vec![];
|
|
for _ in 0..size {
|
|
list.push(AnnotationSetRefItem::deserialize(input)?);
|
|
}
|
|
Ok(Self { list })
|
|
}
|
|
fn size(&self) -> usize {
|
|
self.size_field().size() + self.list.iter().map(|val| val.size()).sum::<usize>()
|
|
}
|
|
}
|
|
|
|
/// <https://source.android.com/docs/core/runtime/dex-format#set-ref-item>
|
|
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub struct AnnotationSetRefItem {
|
|
/// 0 if there are no annotation, offset to a [`AnnotationSetItem`] else.
|
|
pub annotations_off: u32,
|
|
}
|
|
|
|
/// <https://source.android.com/docs/core/runtime/dex-format#annotation-set-item>
|
|
/// alignment: 4
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct AnnotationSetItem {
|
|
// pub size: u32,
|
|
/// Must be sorted by increasing [`AnnotationOffItem.type_idx`].
|
|
pub entries: Vec<AnnotationOffItem>,
|
|
}
|
|
|
|
impl AnnotationSetItem {
|
|
pub fn size_field(&self) -> u32 {
|
|
self.entries.len() as u32
|
|
}
|
|
}
|
|
|
|
impl Serializable for AnnotationSetItem {
|
|
fn serialize(&self, output: &mut dyn Write) -> Result<()> {
|
|
self.size_field().serialize(output)?;
|
|
for item in &self.entries {
|
|
item.serialize(output)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
|
|
let size = u32::deserialize(input)?;
|
|
let mut entries = vec![];
|
|
for _ in 0..size {
|
|
entries.push(AnnotationOffItem::deserialize(input)?);
|
|
}
|
|
Ok(Self { entries })
|
|
}
|
|
fn size(&self) -> usize {
|
|
self.size_field().size() + self.entries.iter().map(|val| val.size()).sum::<usize>()
|
|
}
|
|
}
|
|
|
|
/// <https://source.android.com/docs/core/runtime/dex-format#off-item>
|
|
#[derive(Serializable, Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub struct AnnotationOffItem {
|
|
/// Offset to a [`crate::AnnotationItem`]
|
|
pub annotation_off: u32,
|
|
}
|
|
|
|
/// <https://source.android.com/docs/core/runtime/dex-format#annotation-item>
|
|
#[derive(Serializable, Debug, Clone, PartialEq, Eq)]
|
|
pub struct AnnotationItem {
|
|
pub visibility: AnnotationVisibility,
|
|
pub annotation: EncodedAnnotation,
|
|
}
|
|
|
|
// TODO: Enum or flags ?
|
|
/// <https://source.android.com/docs/core/runtime/dex-format#annotation-item>
|
|
#[derive(Serializable, Debug, Clone, PartialEq, Eq)]
|
|
#[prefix_type(u8)]
|
|
pub enum AnnotationVisibility {
|
|
#[prefix(0x00)]
|
|
Build,
|
|
#[prefix(0x01)]
|
|
Runtime,
|
|
#[prefix(0x02)]
|
|
System,
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
|
|
const ANNOTATION_ITEM: &[u8] = &[
|
|
0x02, 0xbe, 0x37, 0x01, 0xa8, 0x9f, 0x03, 0x1d, 0xf6, 0x33, 0x01, 0xd3, 0xe8, 0x02, 0x3f,
|
|
];
|
|
const ANNOTATION_ITEM_2: &[u8] = &[0x02, 0xbf, 0x37, 0x01, 0xa8, 0x9f, 0x03, 0x38, 0x38, 0x02];
|
|
|
|
#[test]
|
|
fn deserialize_annotation_item() {
|
|
assert_eq!(
|
|
AnnotationItem::deserialize_from_slice(ANNOTATION_ITEM).unwrap(),
|
|
AnnotationItem {
|
|
visibility: AnnotationVisibility::System,
|
|
annotation: EncodedAnnotation::deserialize_from_slice(&ANNOTATION_ITEM[1..])
|
|
.unwrap(),
|
|
}
|
|
);
|
|
assert_eq!(
|
|
AnnotationItem::deserialize_from_slice(ANNOTATION_ITEM_2).unwrap(),
|
|
AnnotationItem {
|
|
visibility: AnnotationVisibility::System,
|
|
annotation: EncodedAnnotation::deserialize_from_slice(&ANNOTATION_ITEM_2[1..])
|
|
.unwrap(),
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn serialize_annotation_item() {
|
|
assert_eq!(
|
|
ANNOTATION_ITEM,
|
|
AnnotationItem {
|
|
visibility: AnnotationVisibility::System,
|
|
annotation: EncodedAnnotation::deserialize_from_slice(&ANNOTATION_ITEM[1..])
|
|
.unwrap(),
|
|
}
|
|
.serialize_to_vec()
|
|
.unwrap()
|
|
.as_slice()
|
|
);
|
|
assert_eq!(
|
|
ANNOTATION_ITEM_2,
|
|
AnnotationItem {
|
|
visibility: AnnotationVisibility::System,
|
|
annotation: EncodedAnnotation::deserialize_from_slice(&ANNOTATION_ITEM_2[1..])
|
|
.unwrap(),
|
|
}
|
|
.serialize_to_vec()
|
|
.unwrap()
|
|
.as_slice()
|
|
);
|
|
}
|
|
}
|