use std::{
ffi::c_void,
fmt,
io::{Cursor, Read, Write},
mem::size_of,
mem::transmute,
os::unix::io::RawFd,
slice,
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use crate::{Binder, BinderFlatObject, BinderTransactionData, BinderType};
const STRICT_MODE_PENALTY_GATHER: i32 = 1 << 31;
const HEADER: i32 = 0x53595354;
pub struct Parcel {
cursor: Cursor<Vec<u8>>,
object_offsets: Vec<usize>,
objects_position: usize,
}
impl fmt::Debug for Parcel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Parcel")
.field("data", &self.cursor.get_ref())
.field("offsets", &self.object_offsets)
.finish()
}
}
impl Parcel {
pub fn empty() -> Self {
let data = vec![];
Self {
cursor: Cursor::new(data),
object_offsets: vec![],
objects_position: 0,
}
}
pub fn from_slice(data: &[u8]) -> Self {
Self {
cursor: Cursor::new(data.to_vec()),
object_offsets: vec![],
objects_position: 0,
}
}
pub fn from_data_and_offsets(
data: *mut u8,
data_size: usize,
offsets: *mut usize,
offsets_size: usize,
) -> Self {
unsafe {
Self {
cursor: Cursor::new(slice::from_raw_parts(data, data_size).to_vec()),
object_offsets: slice::from_raw_parts(offsets, offsets_size).to_vec(),
objects_position: 0,
}
}
}
pub fn reset(&mut self) {
self.cursor.set_position(0);
self.cursor.get_mut().resize(0, 0);
self.objects_position = 0;
self.object_offsets.resize(0, 0);
}
pub fn position(&self) -> u64 {
self.cursor.position()
}
pub fn set_position(&mut self, pos: u64) {
self.cursor.set_position(pos)
}
pub fn append_parcel(&mut self, other: &mut Parcel) {
let current_position = self.cursor.position();
self.cursor.write(other.to_slice());
for offset in &other.object_offsets {
self.object_offsets.push(offset + current_position as usize);
}
}
pub fn as_ptr(&self) -> *const u8 {
self.cursor.get_ref().as_ptr()
}
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.cursor.get_mut().as_mut_ptr()
}
pub fn to_slice(&self) -> &[u8] {
self.cursor.get_ref()
}
pub fn len(&self) -> usize {
self.cursor.get_ref().len()
}
pub fn offsets_len(&self) -> usize {
self.object_offsets.len()
}
pub fn offsets(&mut self) -> &mut Vec<usize> {
&mut self.object_offsets
}
pub fn has_unread_data(&self) -> bool {
self.cursor.position() != self.len() as u64
}
pub fn write_i32(&mut self, data: i32) {
self.cursor.write_i32::<LittleEndian>(data);
}
pub fn write_u32(&mut self, data: u32) {
self.cursor.write_u32::<LittleEndian>(data);
}
pub fn write_u16(&mut self, data: u16) {
self.cursor.write_u16::<LittleEndian>(data);
}
pub fn write_bool(&mut self, data: bool) {
self.cursor.write_u32::<LittleEndian>(data as u32);
}
pub fn read_i32(&mut self) -> i32 {
self.cursor.read_i32::<LittleEndian>().unwrap()
}
pub fn write(&mut self, data: &[u8]) {
let padded_len = (data.len() + 3) & !3;
let mut data = data.to_vec();
if padded_len > data.len() {
data.resize(padded_len, 0);
};
self.cursor
.write(data.as_slice())
.expect("Coudn't write to parcel data");
}
pub fn write_transaction_data(&mut self, data: &BinderTransactionData) {
self.write(unsafe {
slice::from_raw_parts(
data as *const _ as *const u8,
size_of::<BinderTransactionData>(),
)
});
}
pub fn read_u32(&mut self) -> u32 {
self.cursor.read_u32::<LittleEndian>().unwrap()
}
pub fn read_u64(&mut self) -> u64 {
self.cursor.read_u64::<LittleEndian>().unwrap()
}
pub fn read_usize(&mut self) -> usize {
if size_of::<usize>() == size_of::<u32>() {
self.read_u32() as usize
} else {
self.read_u64() as usize
}
}
pub fn read_pointer(&mut self) -> *const c_void {
self.read_usize() as *const c_void
}
pub fn read(&mut self, size: usize) -> Vec<u8> {
let size = if (size % 4) != 0 {
size + 4 - (size % 4)
} else {
size
};
let mut data = vec![0u8; size];
self.cursor.read(&mut data);
data
}
pub fn read_without_alignment(&mut self, size: usize) -> Vec<u8> {
let mut data = vec![0u8; size];
self.cursor.read(&mut data);
data
}
pub fn read_transaction_data(&mut self) -> BinderTransactionData {
self.read_object()
}
pub fn read_object<T>(&mut self) -> T {
unsafe {
let data = slice::from_raw_parts(
self.cursor
.get_ref()
.as_ptr()
.offset(self.cursor.position() as isize),
size_of::<T>(),
);
self.cursor.set_position(self.cursor.position() + size_of::<T>() as u64);
(data.as_ptr() as *const T).read()
}
}
pub fn write_object<T>(&mut self, object: T) {
self.object_offsets.push(self.cursor.position() as usize);
self.cursor.write(unsafe {
slice::from_raw_parts(&object as *const _ as *const u8, size_of::<T>())
});
}
pub fn write_str16(&mut self, string: &str) {
let mut s16: Vec<u8> = vec![];
self.write_i32(string.len() as i32);
for c in string.encode_utf16() {
s16.write_u16::<LittleEndian>(c);
}
s16.write_u16::<LittleEndian>(0);
if s16.len() % 4 != 0 {
s16.resize(s16.len() + 4 - (s16.len() % 4), 0)
}
self.cursor.write(s16.as_slice());
}
pub fn write_binder(&mut self, object: *const c_void) {
self.write_object(BinderFlatObject::new(BinderType::Binder, object as usize, 0, 0));
self.write_u32(0xc); }
pub fn write_file_descriptor(&mut self, fd: RawFd, take_ownership: bool) {
self.write_object(BinderFlatObject::new(BinderType::Fd, fd as usize, if take_ownership { 1 } else { 0 }, 0x17f));
}
pub fn read_file_descriptor(&mut self) -> RawFd {
let flat_object: BinderFlatObject = self.read_object();
assert!(flat_object.binder_type == BinderType::Fd);
flat_object.handle as RawFd
}
pub fn read_str16(&mut self) -> String {
let len = ((self.read_i32() + 1) * 2) as usize;
if len == 0 {
return "".to_string()
}
unsafe {
let u16_array = slice::from_raw_parts(self.read(len).as_mut_ptr() as *mut u16, len);
let mut res = String::from_utf16(u16_array).unwrap();
res.truncate(len / 2 - 1);
res
}
}
pub fn read_str(&mut self) -> String {
let len = (self.read_i32() + 1) as usize;
if len == 0 {
return "".to_string()
}
unsafe {
let u8_array = slice::from_raw_parts(self.read(len).as_mut_ptr() as *mut u8, len);
let mut res = String::from_utf8(u8_array.to_vec()).unwrap();
res.truncate(len - 1);
res
}
}
pub fn read_interface_token(&mut self) -> String {
assert!(self.read_i32() == STRICT_MODE_PENALTY_GATHER);
assert!(self.read_i32() == -1);
assert!(self.read_i32() == HEADER);
self.read_str16()
}
pub fn write_interface_token(&mut self, name: &str) {
self.write_i32(STRICT_MODE_PENALTY_GATHER);
self.write_i32(-1);
self.write_i32(HEADER);
self.write_str16(name);
}
}