143 lines
4.3 KiB
Rust
143 lines
4.3 KiB
Rust
use {
|
|
crate::{
|
|
types::{Bool, ObjectPath, Signature, Variant, FALSE, TRUE},
|
|
DbusError, DbusType, DynamicType, Parser,
|
|
},
|
|
bstr::ByteSlice,
|
|
std::{borrow::Cow, rc::Rc},
|
|
uapi::{OwnedFd, Pod},
|
|
};
|
|
|
|
impl<'a> Parser<'a> {
|
|
pub fn new(buf: &'a [u8], fds: &'a [Rc<OwnedFd>]) -> Self {
|
|
Self::new_at(buf, 0, fds)
|
|
}
|
|
|
|
pub fn new_at(buf: &'a [u8], pos: usize, fds: &'a [Rc<OwnedFd>]) -> Self {
|
|
Self { buf, pos, fds }
|
|
}
|
|
|
|
pub fn eof(&self) -> bool {
|
|
self.pos == self.buf.len()
|
|
}
|
|
|
|
pub fn unmarshal<T: DbusType<'a>>(&mut self) -> Result<T, DbusError> {
|
|
T::unmarshal(self)
|
|
}
|
|
|
|
pub fn align_to(&mut self, n: usize) -> Result<(), DbusError> {
|
|
let new = self.pos + (self.pos.wrapping_neg() & (n - 1));
|
|
if new > self.buf.len() {
|
|
return Err(DbusError::UnexpectedEof);
|
|
}
|
|
self.pos = new;
|
|
Ok(())
|
|
}
|
|
|
|
pub fn read_fd(&mut self) -> Result<Rc<OwnedFd>, DbusError> {
|
|
let idx: u32 = self.read_pod()?;
|
|
let idx = idx as usize;
|
|
if idx >= self.fds.len() {
|
|
return Err(DbusError::OobFds);
|
|
}
|
|
Ok(self.fds[idx].clone())
|
|
}
|
|
|
|
pub fn read_pod<'b, T: DbusType<'b> + Pod>(&mut self) -> Result<T, DbusError> {
|
|
self.align_to(T::ALIGNMENT)?;
|
|
match uapi::pod_read_init(&self.buf[self.pos..]) {
|
|
Ok(v) => {
|
|
self.pos += size_of::<T>();
|
|
Ok(v)
|
|
}
|
|
_ => Err(DbusError::UnexpectedEof),
|
|
}
|
|
}
|
|
|
|
pub fn read_bool(&mut self) -> Result<Bool, DbusError> {
|
|
let v: u32 = self.read_pod()?;
|
|
match v {
|
|
0 => Ok(FALSE),
|
|
1 => Ok(TRUE),
|
|
_ => Err(DbusError::InvalidBoolValue),
|
|
}
|
|
}
|
|
|
|
pub fn read_object_path(&mut self) -> Result<ObjectPath<'a>, DbusError> {
|
|
self.read_string().map(ObjectPath)
|
|
}
|
|
|
|
pub fn read_string(&mut self) -> Result<Cow<'a, str>, DbusError> {
|
|
let len: u32 = self.read_pod()?;
|
|
let s = self.read_string_(len as usize)?;
|
|
Ok(Cow::Borrowed(s))
|
|
}
|
|
|
|
pub fn read_signature(&mut self) -> Result<Signature<'a>, DbusError> {
|
|
let len: u8 = self.read_pod()?;
|
|
let s = self.read_string_(len as usize)?;
|
|
Ok(Signature(Cow::Borrowed(s)))
|
|
}
|
|
|
|
fn read_string_(&mut self, len: usize) -> Result<&'a str, DbusError> {
|
|
if len == usize::MAX || self.buf.len() - self.pos < len + 1 {
|
|
return Err(DbusError::UnexpectedEof);
|
|
}
|
|
let s = &self.buf[self.pos..self.pos + len];
|
|
self.pos += len + 1;
|
|
match s.to_str() {
|
|
Ok(s) => Ok(s),
|
|
_ => Err(DbusError::InvalidUtf8),
|
|
}
|
|
}
|
|
|
|
pub fn read_array<T: DbusType<'a>>(&mut self) -> Result<Cow<'a, [T]>, DbusError> {
|
|
let len: u32 = self.read_pod()?;
|
|
let len = len as usize;
|
|
self.align_to(T::ALIGNMENT)?;
|
|
if self.buf.len() - self.pos < len {
|
|
return Err(DbusError::UnexpectedEof);
|
|
}
|
|
if T::IS_POD {
|
|
if len % size_of::<T>() != 0 {
|
|
return Err(DbusError::PodArrayLength);
|
|
}
|
|
let slice = unsafe {
|
|
std::slice::from_raw_parts(
|
|
self.buf[self.pos..].as_ptr() as *const T,
|
|
len / size_of::<T>(),
|
|
)
|
|
};
|
|
self.pos += len;
|
|
Ok(Cow::Borrowed(slice))
|
|
} else {
|
|
let mut parser = Parser::new_at(&self.buf[..self.pos + len], self.pos, self.fds);
|
|
self.pos += len;
|
|
let mut res = vec![];
|
|
while !parser.eof() {
|
|
res.push(T::unmarshal(&mut parser)?);
|
|
}
|
|
Ok(Cow::Owned(res))
|
|
}
|
|
}
|
|
|
|
pub fn read_variant(&mut self) -> Result<Variant<'a>, DbusError> {
|
|
let sig = self.read_signature()?;
|
|
let sig = sig.0.as_bytes();
|
|
let (parser, rem) = DynamicType::from_signature(sig)?;
|
|
if rem.len() > 0 {
|
|
return Err(DbusError::TrailingVariantSignature);
|
|
}
|
|
parser.parse(self)
|
|
}
|
|
|
|
pub fn read_variant_as<T: DbusType<'a>>(&mut self) -> Result<T, DbusError> {
|
|
let sig = self.read_signature()?;
|
|
let mut sig = sig.0.as_bytes();
|
|
T::consume_signature(&mut sig)?;
|
|
if sig.len() > 0 {
|
|
return Err(DbusError::TrailingVariantSignature);
|
|
}
|
|
T::unmarshal(self)
|
|
}
|
|
}
|