use crate::*;
use crate::io::be::*;
pub use field::BasicType;
pub use field::Descriptor as Type;
use bitflags::bitflags;
use std::io::{self, Read};
bitflags! {
#[derive(Default)]
pub struct Flags : u16 {
const PUBLIC = 0x0001;
const PRIVATE = 0x0002;
const PROTECTED = 0x0004;
const STATIC = 0x0008;
const FINAL = 0x0010;
const SYNCRONIZED = 0x0020;
const BRIDGE = 0x0040;
const VARARGS = 0x0080;
const NATIVE = 0x0100;
const ABSTRACT = 0x0400;
const STRICT = 0x0800;
const SYNTHETIC = 0x1000;
}
}
impl Flags {
pub fn read(r: &mut impl Read) -> io::Result<Self> {
Ok(Self::from_bits_truncate(read_u2(r)?))
}
}
#[derive(Clone, Debug)]
pub struct Method {
pub flags: Flags,
pub name: String,
descriptor: String,
pub deprecated: bool,
_incomplete: (),
}
#[allow(dead_code)]
impl Method {
pub fn new(flags: Flags, name: String, descriptor: String) -> io::Result<Self> {
method::Descriptor::new(descriptor.as_str())?;
Ok(Self {
flags,
name,
descriptor,
deprecated: false,
_incomplete: (),
})
}
pub fn descriptor_str(&self) -> &str { self.descriptor.as_str() }
pub fn descriptor(&self) -> Descriptor { Descriptor::new(self.descriptor.as_str()).unwrap() }
pub fn is_public (&self) -> bool { self.flags.contains(Flags::PUBLIC ) }
pub fn is_private (&self) -> bool { self.flags.contains(Flags::PRIVATE ) }
pub fn is_protected (&self) -> bool { self.flags.contains(Flags::PROTECTED ) }
pub fn is_static (&self) -> bool { self.flags.contains(Flags::STATIC ) }
pub fn is_final (&self) -> bool { self.flags.contains(Flags::FINAL ) }
pub fn is_syncronized (&self) -> bool { self.flags.contains(Flags::SYNCRONIZED ) }
pub fn is_bridge (&self) -> bool { self.flags.contains(Flags::BRIDGE ) }
pub fn is_varargs (&self) -> bool { self.flags.contains(Flags::VARARGS ) }
pub fn is_native (&self) -> bool { self.flags.contains(Flags::NATIVE ) }
pub fn is_abstract (&self) -> bool { self.flags.contains(Flags::ABSTRACT ) }
pub fn is_strict (&self) -> bool { self.flags.contains(Flags::STRICT ) }
pub fn is_synthetic (&self) -> bool { self.flags.contains(Flags::SYNTHETIC ) }
pub fn is_constructor (&self) -> bool { self.name == "<init>" }
pub fn is_static_init (&self) -> bool { self.name == "<clinit>" }
pub fn access(&self) -> Option<&'static str> {
if self.is_private() { Some("private") }
else if self.is_protected() { Some("protected") }
else if self.is_public() { Some("public") }
else { None }
}
pub(crate) fn read_one(read: &mut impl Read, constants: &Constants) -> io::Result<Self> {
let flags = Flags::read(read)?;
let name = constants.get_utf8(read_u2(read)?)?.to_owned();
let descriptor = constants.get_utf8(read_u2(read)?)?.to_owned();
let attributes_count = read_u2(read)? as usize;
method::Descriptor::new(descriptor.as_str())?;
let mut deprecated = false;
for _ in 0..attributes_count {
match Attribute::read(read, constants)? {
Attribute::Deprecated { .. } => { deprecated = true; },
_ => {},
}
}
Ok(Self{
flags,
name,
descriptor,
deprecated,
_incomplete: (),
})
}
pub(crate) fn read_list(read: &mut impl Read, constants: &Constants) -> io::Result<Vec<Self>> {
let n = read_u2(read)? as usize;
let mut methods = Vec::with_capacity(n);
for _ in 0..n {
methods.push(Self::read_one(read, constants)?);
}
Ok(methods)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Descriptor<'a> {
string: &'a str,
end_paren: usize,
}
impl<'a> Descriptor<'a> {
pub fn new(desc: &'a str) -> io::Result<Descriptor<'a>> {
if !desc.starts_with('(') { return io_data_err!("Method descriptor didn't start with '(': {:?}", desc); }
let end_paren = if let Some(i) = desc.rfind(')') { i } else { return io_data_err!("Method descriptor doesn't contain a ')' terminating the arguments list: {:?}", desc); };
let (arguments, return_) = desc.split_at(end_paren);
Type::from_str(&return_[1..])?; let mut args = &arguments[1..]; while !args.is_empty() {
Type::read_next(&mut args)?;
}
Ok(Descriptor { string: desc, end_paren })
}
#[allow(dead_code)]
pub fn as_str(&self) -> &'a str { self.string }
pub fn return_type(&self) -> Type<'a> { Type::from_str(&self.string[(1+self.end_paren)..]).unwrap() } pub fn arguments(&self) -> ArgumentsIter { ArgumentsIter(&self.string[1..self.end_paren]) }
}
pub struct ArgumentsIter<'a>(&'a str);
impl<'a> Iterator for ArgumentsIter<'a> {
type Item = Type<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.0.is_empty() {
None
} else {
Some(Type::read_next(&mut self.0).unwrap()) }
}
}
#[test] fn jni_descriptor_from_str() {
let d = Descriptor::new("(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;").unwrap();
assert_eq!(d.return_type(), Type::Single(BasicType::Class(class::Id("android/database/Cursor"))));
let mut d = d.arguments();
assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("android/net/Uri")))));
assert_eq!(d.next(), Some(Type::Array { levels: 1, inner: BasicType::Class(class::Id("java/lang/String")) }));
assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("java/lang/String")))));
assert_eq!(d.next(), Some(Type::Array { levels: 1, inner: BasicType::Class(class::Id("java/lang/String")) }));
assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("java/lang/String")))));
assert_eq!(d.next(), None);
assert_eq!(d.next(), None);
let d = Descriptor::new("(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/database/Cursor;").unwrap();
assert_eq!(d.return_type(), Type::Single(BasicType::Class(class::Id("android/database/Cursor"))));
let mut d = d.arguments();
assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("android/net/Uri")))));
assert_eq!(d.next(), Some(Type::Array { levels: 1, inner: BasicType::Class(class::Id("java/lang/String")) }));
assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("java/lang/String")))));
assert_eq!(d.next(), Some(Type::Array { levels: 1, inner: BasicType::Class(class::Id("java/lang/String")) }));
assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("java/lang/String")))));
assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("android/os/CancellationSignal")))));
assert_eq!(d.next(), None);
assert_eq!(d.next(), None);
let d = Descriptor::new("(Landroid/net/Uri;[Ljava/lang/String;Landroid/os/Bundle;Landroid/os/CancellationSignal;)Landroid/database/Cursor;").unwrap();
assert_eq!(d.return_type(), Type::Single(BasicType::Class(class::Id("android/database/Cursor"))));
let mut d = d.arguments();
assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("android/net/Uri")))));
assert_eq!(d.next(), Some(Type::Array { levels: 1, inner: BasicType::Class(class::Id("java/lang/String")) }));
assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("android/os/Bundle")))));
assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("android/os/CancellationSignal")))));
assert_eq!(d.next(), None);
assert_eq!(d.next(), None);
let d = Descriptor::new("([Ljava/lang/String;)V").unwrap();
assert_eq!(d.return_type(), Type::Single(BasicType::Void));
let mut d = d.arguments();
assert_eq!(d.next(), Some(Type::Array { levels: 1, inner: BasicType::Class(class::Id("java/lang/String")) }));
assert_eq!(d.next(), None);
assert_eq!(d.next(), None);
let d = Descriptor::new("()V").unwrap();
assert_eq!(d.return_type(), Type::Single(BasicType::Void));
let mut d = d.arguments();
assert_eq!(d.next(), None);
assert_eq!(d.next(), None);
}