diff --git a/androscalpel_serializer/src/annotation.rs b/androscalpel_serializer/src/annotation.rs index 9d3ae2d..74208da 100644 --- a/androscalpel_serializer/src/annotation.rs +++ b/androscalpel_serializer/src/annotation.rs @@ -1,18 +1,69 @@ -use crate::{ReadSeek, Result, Serializable}; +use crate::{EncodedValue, Error, ReadSeek, Result, Serializable, Uleb128}; use std::io::Write; +// To derive Serializable +use crate as androscalpel_serializer; + +/// Encoded Annotation https://source.android.com/docs/core/runtime/dex-format#encoded-annotation #[derive(Debug, Clone, PartialEq, Eq)] -pub struct EncodedAnnotation; +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, +} + +impl EncodedAnnotation { + /// Return the size field + pub fn size_field(&self) -> Uleb128 { + Uleb128(self.elements.len() as u32) + } +} + +/// Annotation: 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<()> { - todo!() + 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 { - todo!() + fn deserialize(input: &mut dyn ReadSeek) -> Result { + 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)?); + } + Ok(Self { type_idx, elements }) } fn size(&self) -> usize { - todo!() + self.type_idx.size() + + self.size_field().size() + + self.elements.iter().map(|val| val.size()).sum::() } } + +// TODO: add tests diff --git a/androscalpel_serializer/src/array.rs b/androscalpel_serializer/src/array.rs index ec9a327..44b7222 100644 --- a/androscalpel_serializer/src/array.rs +++ b/androscalpel_serializer/src/array.rs @@ -11,15 +11,15 @@ pub struct EncodedArray { impl EncodedArray { /// Return the size field - pub fn size(&self) -> Uleb128 { + pub fn size_field(&self) -> Uleb128 { Uleb128(self.values.len() as u32) } } impl Serializable for EncodedArray { fn serialize(&self, output: &mut dyn Write) -> Result<()> { - self.size().serialize(output)?; - for value in self.values { + self.size_field().serialize(output)?; + for value in &self.values { value.serialize(output)?; } Ok(()) @@ -38,6 +38,6 @@ impl Serializable for EncodedArray { } fn size(&self) -> usize { - self.size().size() + self.values.iter().map(|val| val.size()).sum::() + self.size_field().size() + self.values.iter().map(|val| val.size()).sum::() } } diff --git a/androscalpel_serializer/src/core/leb.rs b/androscalpel_serializer/src/core/leb.rs index 348d816..822b4dc 100644 --- a/androscalpel_serializer/src/core/leb.rs +++ b/androscalpel_serializer/src/core/leb.rs @@ -5,15 +5,15 @@ use std::io::Write; use crate::{Error, ReadSeek, Result, Serializable}; /// Signed LEB128, variable-length -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Sleb128(pub i32); /// Unsigned LEB128, variable-length -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Uleb128(pub u32); /// Unsigned LEB128 plus 1, variable-length -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Uleb128p1(pub u32); impl Sleb128 {