196 lines
6.7 KiB
Rust
196 lines
6.7 KiB
Rust
use crate::{EncodedValue, Error, ReadSeek, Result, Serializable, Uleb128};
|
|
use log::warn;
|
|
use std::io::Write;
|
|
|
|
// To derive Serializable
|
|
use crate as androscalpel_serializer;
|
|
|
|
/// <https://source.android.com/docs/core/runtime/dex-format#encoded-annotation>
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct EncodedAnnotation {
|
|
/// Type of the annotation. This must be a class (not array or primitive) type.
|
|
pub type_idx: Uleb128, // TODO: check it's a class
|
|
//pub size: Uleb128,
|
|
pub elements: Vec<AnnotationElement>,
|
|
}
|
|
|
|
impl EncodedAnnotation {
|
|
/// Return the size field
|
|
pub fn size_field(&self) -> Uleb128 {
|
|
Uleb128(self.elements.len() as u32)
|
|
}
|
|
}
|
|
|
|
/// <https://source.android.com/docs/core/runtime/dex-format#annotation-element>
|
|
#[derive(Serializable, Debug, Clone, PartialEq, Eq)]
|
|
pub struct AnnotationElement {
|
|
pub name_idx: Uleb128,
|
|
pub value: EncodedValue,
|
|
}
|
|
|
|
impl Serializable for EncodedAnnotation {
|
|
fn serialize(&self, output: &mut dyn Write) -> Result<()> {
|
|
let Self { type_idx, elements } = self;
|
|
// Check if the element are sorted
|
|
if !elements.is_empty() {
|
|
let mut idx_0 = elements[0].name_idx;
|
|
for idx_1 in elements.iter().map(|elt| elt.name_idx).skip(1) {
|
|
if idx_0 > idx_1 {
|
|
return Err(Error::SerializationError(format!(
|
|
"Failed to serialize EncodedAnnotation: element must be sorted in increasing order by string_id index, found {idx_0:?} before {idx_1:?}"
|
|
)));
|
|
}
|
|
idx_0 = idx_1;
|
|
}
|
|
}
|
|
type_idx.serialize(output)?;
|
|
self.size_field().serialize(output)?;
|
|
for elt in elements {
|
|
elt.serialize(output)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
|
|
let type_idx = Uleb128::deserialize(input)?;
|
|
let Uleb128(size) = Uleb128::deserialize(input)?;
|
|
let mut elements = vec![];
|
|
for _ in 0..size {
|
|
elements.push(AnnotationElement::deserialize(input)?);
|
|
}
|
|
if !elements.is_empty() {
|
|
let mut idx_0 = elements[0].name_idx;
|
|
for idx_1 in elements.iter().map(|elt| elt.name_idx).skip(1) {
|
|
if idx_0 > idx_1 {
|
|
warn!(
|
|
"while deserializing EncodedAnnotation: element must be sorted in increasing order by string_id index, found {idx_0:?} before {idx_1:?}"
|
|
);
|
|
}
|
|
idx_0 = idx_1;
|
|
}
|
|
}
|
|
Ok(Self { type_idx, elements })
|
|
}
|
|
|
|
fn size(&self) -> usize {
|
|
self.type_idx.size()
|
|
+ self.size_field().size()
|
|
+ self.elements.iter().map(|val| val.size()).sum::<usize>()
|
|
}
|
|
}
|
|
|
|
// TODO: add more tests
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
|
|
const ENCODED_ANNOTATION_RAW: &[u8] = &[
|
|
0xbe, 0x37, 0x01, 0xa8, 0x9f, 0x03, 0x1d, 0xf6, 0x33, 0x01, 0xd3, 0xe8, 0x02, 0x3f,
|
|
];
|
|
const ENCODED_ANNOTATION_RAW_2: &[u8] = &[0xf6, 0x33, 0x01, 0xd3, 0xe8, 0x02, 0x3f];
|
|
const ENCODED_ANNOTATION_RAW_3: &[u8] = &[0xbf, 0x37, 0x01, 0xa8, 0x9f, 0x03, 0x38, 0x38, 0x02];
|
|
const ANNOTATION_ELEMENT_RAW: &[u8] = &[
|
|
0xa8, 0x9f, 0x03, 0x1d, 0xf6, 0x33, 0x01, 0xd3, 0xe8, 0x02, 0x3f,
|
|
];
|
|
const ENCODED_VALUE_RAW: &[u8] = &[0x1d, 0xf6, 0x33, 0x01, 0xd3, 0xe8, 0x02, 0x3f];
|
|
|
|
#[test]
|
|
fn deserialize_encoded_annotation() {
|
|
assert_eq!(
|
|
EncodedAnnotation::deserialize_from_slice(ENCODED_ANNOTATION_RAW_3).unwrap(),
|
|
EncodedAnnotation {
|
|
type_idx: Uleb128(7103),
|
|
elements: vec![AnnotationElement {
|
|
name_idx: Uleb128(53160),
|
|
value: EncodedValue::Type(0x0238)
|
|
}],
|
|
}
|
|
);
|
|
assert_eq!(
|
|
EncodedAnnotation::deserialize_from_slice(ENCODED_ANNOTATION_RAW_2).unwrap(),
|
|
EncodedAnnotation {
|
|
type_idx: Uleb128(6646),
|
|
elements: vec![AnnotationElement {
|
|
name_idx: Uleb128(46163),
|
|
value: EncodedValue::Boolean(true)
|
|
}],
|
|
}
|
|
);
|
|
assert_eq!(
|
|
EncodedAnnotation::deserialize_from_slice(ENCODED_ANNOTATION_RAW).unwrap(),
|
|
EncodedAnnotation {
|
|
type_idx: Uleb128(7102),
|
|
elements: vec![AnnotationElement {
|
|
name_idx: Uleb128(53160),
|
|
value: EncodedValue::Annotation(EncodedAnnotation {
|
|
type_idx: Uleb128(6646),
|
|
elements: vec![AnnotationElement {
|
|
name_idx: Uleb128(46163),
|
|
value: EncodedValue::Boolean(true)
|
|
}]
|
|
})
|
|
}],
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn serialize_encoded_annotation() {
|
|
assert_eq!(
|
|
ENCODED_ANNOTATION_RAW_2,
|
|
EncodedAnnotation {
|
|
type_idx: Uleb128(6646),
|
|
elements: vec![AnnotationElement {
|
|
name_idx: Uleb128(46163),
|
|
value: EncodedValue::Boolean(true)
|
|
}],
|
|
}
|
|
.serialize_to_vec()
|
|
.unwrap()
|
|
.as_slice()
|
|
);
|
|
assert_eq!(
|
|
ENCODED_ANNOTATION_RAW,
|
|
EncodedAnnotation {
|
|
type_idx: Uleb128(7102),
|
|
elements: vec![AnnotationElement {
|
|
name_idx: Uleb128(53160),
|
|
value: EncodedValue::Annotation(EncodedAnnotation {
|
|
type_idx: Uleb128(6646),
|
|
elements: vec![AnnotationElement {
|
|
name_idx: Uleb128(46163),
|
|
value: EncodedValue::Boolean(true)
|
|
}]
|
|
})
|
|
}],
|
|
}
|
|
.serialize_to_vec()
|
|
.unwrap()
|
|
.as_slice()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_annotation_element() {
|
|
assert_eq!(
|
|
AnnotationElement::deserialize_from_slice(ANNOTATION_ELEMENT_RAW).unwrap(),
|
|
AnnotationElement {
|
|
name_idx: Uleb128(53160),
|
|
value: EncodedValue::deserialize_from_slice(ENCODED_VALUE_RAW).unwrap(),
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn serialize_annotation_element() {
|
|
assert_eq!(
|
|
ANNOTATION_ELEMENT_RAW,
|
|
AnnotationElement {
|
|
name_idx: Uleb128(53160),
|
|
value: EncodedValue::deserialize_from_slice(ENCODED_VALUE_RAW).unwrap(),
|
|
}
|
|
.serialize_to_vec()
|
|
.unwrap()
|
|
.as_slice(),
|
|
);
|
|
}
|
|
}
|