factorize value parsing

This commit is contained in:
Jean-Marie Mineau 2023-10-02 16:58:33 +02:00
parent cdf68c506a
commit 77be653786
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
4 changed files with 123 additions and 67 deletions

View file

@ -133,6 +133,72 @@ impl Apk {
})
}
/// Return a [`IdType`] from its idx.
pub fn get_id_type_from_idx(idx: usize, dex: &DexFileReader) -> Result<IdType> {
Ok(IdType(
dex.get_string(dex.get_type_id(idx)?.descriptor_idx)?.into(),
))
}
/// Return a [`IdMethodType`] from its idx.
pub fn get_id_method_type_from_idx(idx: usize, dex: &DexFileReader) -> Result<IdMethodType> {
let proto = dex.get_proto_id(idx)?;
let shorty: DexString = dex.get_string(proto.shorty_idx)?.into();
let return_type: IdType = Self::get_id_type_from_idx(proto.return_type_idx as usize, dex)?;
let parameters: Vec<IdType> = if proto.parameters_off == 0 {
vec![]
} else {
dex.get_struct_at_offset::<TypeList>(proto.parameters_off)?
.list
.iter()
.map(|ty| Self::get_id_type_from_idx(ty.type_idx as usize, dex).clone())
.collect::<Result<_>>()?
};
Ok(IdMethodType {
shorty,
return_type,
parameters,
})
}
/// Return a [`IdField`] from its idx.
pub fn get_id_field_from_idx(idx: usize, dex: &DexFileReader) -> Result<IdField> {
let field = dex.get_field_id(idx)?;
let name = dex.get_string(field.name_idx)?.into();
let type_ = IdType(
dex.get_string(dex.get_type_id(field.type_idx as usize)?.descriptor_idx)?
.into(),
);
let class_ = IdType(
dex.get_string(dex.get_type_id(field.class_idx as usize)?.descriptor_idx)?
.into(),
);
Ok(IdField {
name,
type_,
class_,
})
}
/// Return a [`IdMethod`] from its idx.
pub fn get_id_method_from_idx(idx: usize, dex: &DexFileReader) -> Result<IdMethod> {
let method_id = dex.get_method_id(idx)?;
let class_ = IdType(
dex.get_string(
dex.get_type_id(method_id.class_idx as usize)?
.descriptor_idx,
)?
.into(),
);
let proto = Self::get_id_method_type_from_idx(method_id.proto_idx as usize, dex)?;
let name = dex.get_string(method_id.name_idx)?.into();
Ok(IdMethod {
class_,
proto,
name,
})
}
pub fn encoded_value_to_dex_value(
encoded_value: &EncodedValue,
dex: &DexFileReader,
@ -145,60 +211,24 @@ impl Apk {
EncodedValue::Long(val) => Ok(DexValue::Long(DexLong(*val))),
EncodedValue::Float(val) => Ok(DexValue::Float(DexFloat(*val))),
EncodedValue::Double(val) => Ok(DexValue::Double(DexDouble(*val))),
EncodedValue::MethodType(val) => {
let proto = dex.get_proto_id(*val as usize)?;
let shorty: DexString = dex.get_string(proto.shorty_idx)?.into();
let return_type: IdType = IdType(
dex.get_string(
dex.get_type_id(proto.return_type_idx as usize)?
.descriptor_idx,
)?
.into(),
);
let parameters = if proto.parameters_off == 0 {
vec![]
} else {
let type_list = dex.get_struct_at_offset::<TypeList>(proto.parameters_off)?;
let mut parameters: Vec<IdType> = vec![];
for ty in type_list.list {
parameters.push(IdType(
dex.get_string(dex.get_type_id(ty.type_idx as usize)?.descriptor_idx)?
.into(),
));
}
parameters
};
Ok(DexValue::MethodType(IdMethodType {
shorty,
return_type,
parameters,
}))
}
EncodedValue::MethodType(val) => Ok(DexValue::MethodType(
Self::get_id_method_type_from_idx(*val as usize, dex)?,
)),
// TODO: need method to be implemented first
EncodedValue::MethodHandle(_val) => todo!(), //Ok(DexValue::MethodHandle(DexMethodHandle(*val))),
EncodedValue::String(val) => Ok(DexValue::String(dex.get_string(*val)?.into())),
EncodedValue::Type(val) => Ok(DexValue::Type(IdType(
dex.get_string(dex.get_type_id(*val as usize)?.descriptor_idx)?
.into(),
))),
EncodedValue::Field(val) => {
let field = dex.get_field_id(*val as usize)?;
let name = dex.get_string(field.name_idx)?.into();
let type_ = IdType(
dex.get_string(dex.get_type_id(field.type_idx as usize)?.descriptor_idx)?
.into(),
);
let class_ = IdType(
dex.get_string(dex.get_type_id(field.class_idx as usize)?.descriptor_idx)?
.into(),
);
Ok(DexValue::Field(IdField {
name,
type_,
class_,
}))
}
EncodedValue::Method(val) => Ok(DexValue::Method(IdMethod(*val))),
EncodedValue::Type(val) => Ok(DexValue::Type(Self::get_id_type_from_idx(
*val as usize,
dex,
)?)),
EncodedValue::Field(val) => Ok(DexValue::Field(Self::get_id_field_from_idx(
*val as usize,
dex,
)?)),
EncodedValue::Method(val) => Ok(DexValue::Method(Self::get_id_method_from_idx(
*val as usize,
dex,
)?)),
EncodedValue::Enum(val) => Ok(DexValue::Enum(IdEnum(*val))),
EncodedValue::Array(_val) => todo!(), //Ok(DexValue::Array(DexArray(*val))),
EncodedValue::Annotation(_val) => todo!(), //Ok(DexValue::Annotation(DexAnnotation(*val))),

View file

@ -369,25 +369,41 @@ impl IdField {
}
#[pyclass]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IdMethod(pub u32);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IdMethod {
pub class_: IdType,
pub proto: IdMethodType,
pub name: DexString,
}
#[pymethods]
impl IdMethod {
#[new]
pub fn new(val: u32) -> Self {
Self(val)
}
pub fn get_value(&self) -> u32 {
self.0
pub fn new(class_: IdType, proto: IdMethodType, name: DexString) -> Self {
Self {
class_,
proto,
name,
}
}
pub fn __str__(&self) -> String {
self.__repr__()
format!(
"{}.{}({}){}",
self.class_.__str__(),
self.name.__str__(),
self.proto
.parameters
.iter()
.map(|param| param.__str__())
.collect::<Vec<String>>()
.join(", "),
self.proto.return_type.__str__()
)
}
pub fn __repr__(&self) -> String {
format!("DexMethod({})", self.0)
format!("DexMethod({})", self.__str__())
}
}

View file

@ -16,7 +16,7 @@ pub use field::*;
pub use scalar::*;
pub use value::*;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Error {
InputTooSmall(String),
SerializationError(String),

View file

@ -154,6 +154,16 @@ impl<'a> DexFileReader<'a> {
)))
}
/// Return a [`ProtoIdItem`] reference from its idx.
pub fn get_proto_id(&self, idx: usize) -> Result<&ProtoIdItem> {
self.proto_ids
.get(idx)
.ok_or(Error::InconsistantStruct(format!(
"prototype idx {idx} is out of bound (|proto_ids|={})",
self.proto_ids.len()
)))
}
/// Return a [`FieldIdItem`] reference from its idx.
pub fn get_field_id(&self, idx: usize) -> Result<&FieldIdItem> {
self.field_ids
@ -164,13 +174,13 @@ impl<'a> DexFileReader<'a> {
)))
}
/// Return a [`ProtoIdItem`] reference from its idx.
pub fn get_proto_id(&self, idx: usize) -> Result<&ProtoIdItem> {
self.proto_ids
/// Return a [`MethodIdItem`] reference from its idx.
pub fn get_method_id(&self, idx: usize) -> Result<&MethodIdItem> {
self.method_ids
.get(idx)
.ok_or(Error::InconsistantStruct(format!(
"prototype idx {idx} is out of bound (|proto_ids|={})",
self.proto_ids.len()
"method idx {idx} is out of bound (|method_ids|={})",
self.method_ids.len()
)))
}