add flags and DexString cmp

This commit is contained in:
Jean-Marie 'Histausse' Mineau 2023-09-01 12:22:24 +02:00
parent 9788d77b74
commit 625420c5f6
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
3 changed files with 108 additions and 4 deletions

View file

@ -1,8 +1,8 @@
//! Representation of an apk.
use pyo3::prelude::*;
use crate::{Class, Error, Result};
use androscalpel_serializer::{ClassDefItem, DexFileReader, TypeList, NO_INDEX};
use crate::{Class, DexString, Error, Result};
use androscalpel_serializer::*;
/// Represent an apk.
#[pyclass]
@ -37,7 +37,7 @@ impl Apk {
dex.get_type_ids().len()
)))?
.descriptor_idx;
let name = dex.get_string(name_idx)?.into();
let name: DexString = dex.get_string(name_idx)?.into();
let superclass = if class_item.class_idx == NO_INDEX.0 {
None
} else {
@ -75,11 +75,41 @@ impl Apk {
} else {
Some(dex.get_string(class_item.source_file_idx)?.into())
};
let is_public = (class_item.access_flags & ACC_PUBLIC) != 0;
let is_final = (class_item.access_flags & ACC_FINAL) != 0;
let is_interface = (class_item.access_flags & ACC_INTERFACE) != 0;
let is_abstract = (class_item.access_flags & ACC_ABSTRACT) != 0;
let is_synthetic = (class_item.access_flags & ACC_SYNTHETIC) != 0;
let is_annotation = (class_item.access_flags & ACC_ANNOTATION) != 0;
let is_enum = (class_item.access_flags & ACC_ENUM) != 0;
if (class_item.access_flags
& !(ACC_PUBLIC
| ACC_FINAL
| ACC_INTERFACE
| ACC_ABSTRACT
| ACC_SYNTHETIC
| ACC_ANNOTATION
| ACC_ENUM))
!= 0
{
println!(
"Unexpected flags found in class_def_item.access_flags for {}: 0x{:x}",
<&DexString as Into<String>>::into(&name),
class_item.access_flags
); // TODO: better logging
}
self.classes.push(Class {
name,
superclass,
interfaces,
source_file,
is_public,
is_final,
is_interface,
is_abstract,
is_synthetic,
is_annotation,
is_enum,
});
Ok(())
}

View file

@ -8,13 +8,41 @@ use crate::DexString;
#[pyclass]
#[derive(Debug, Clone)]
pub struct Class {
/// Type name, format described at
/// <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
#[pyo3(get, set)]
pub name: DexString,
// pub access_flags: // TODO
/// If the class is visible everywhere
#[pyo3(get, set)]
pub is_public: bool, // TODO: is it possible to not be public non a non inner class?
/// If the class is subclassable
#[pyo3(get, set)]
pub is_final: bool,
/// If the class is a 'multipy-implementable abstract class' AKA an interface
#[pyo3(get, set)]
pub is_interface: bool,
/// If the class is instanciable
#[pyo3(get, set)]
pub is_abstract: bool,
/// If the class is not directly defined in the source code
#[pyo3(get, set)]
pub is_synthetic: bool,
/// If the class is an annotation
#[pyo3(get, set)]
pub is_annotation: bool,
/// If the class is an enum
#[pyo3(get, set)]
pub is_enum: bool,
/// Name of the superclass, format described at
/// <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
#[pyo3(get, set)]
pub superclass: Option<DexString>,
/// List of the interfaces that class implement, format of the interfaces
/// name is discribed at
/// <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
#[pyo3(get, set)]
pub interfaces: Vec<DexString>,
/// Name of the source file where this class is defined.
#[pyo3(get, set)]
pub source_file: Option<DexString>,
// pub annotations: Option<()> // TODO
@ -32,6 +60,13 @@ impl Class {
superclass: None,
interfaces: vec![],
source_file: None,
is_public: true,
is_final: false,
is_interface: false,
is_abstract: false,
is_synthetic: false,
is_annotation: false,
is_enum: false,
}
}

View file

@ -1,3 +1,4 @@
use pyo3::class::basic::CompareOp;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
@ -93,11 +94,49 @@ impl From<DexString> for String {
}
}
impl From<&str> for DexString {
fn from(string: &str) -> Self {
Self(string.into())
}
}
impl From<String> for DexString {
fn from(string: String) -> Self {
Self(string.as_str().into())
}
}
#[pymethods]
impl DexString {
#[new]
pub fn new(s: &str) -> Self {
s.into()
}
/// Return the binary mutf-8 encoded string (minus the trailling 0)
pub fn get_bytes(&self) -> &[u8] {
&self.0.data
}
/// Return the 'utf-16' size of the string (number of unicode code point, ie its lenght in 'java-land')
pub fn get_utf16_size(&self) -> u32 {
self.0.utf16_size.0
}
pub fn __str__(&self) -> String {
self.into()
}
fn __richcmp__(&self, other: &PyAny, op: CompareOp, py: Python<'_>) -> PyResult<PyObject> {
let other: Self = other
.extract()
.or(<String as FromPyObject>::extract(other).map(|string| string.into()))?;
match op {
CompareOp::Eq => Ok((self == &other).into_py(py)),
_ => Ok(py.NotImplemented()),
}
}
pub fn __repr__(&self) -> String {
self.into()
}