blob: 02a944814e169d658d180281bf793e567660f73f [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use fidl::encoding::{TransactionHeader, ALLOC_PRESENT_U32, ALLOC_PRESENT_U64};
use nom::bytes::complete::take;
use nom::combinator::{map, value, verify};
use nom::multi::count;
use nom::sequence::{pair, preceded, terminated, tuple};
use nom::IResult;
use crate::error::{Error, Result};
use crate::library;
use crate::util::*;
use crate::value::Value;
use std::str;
type DResult<'a, R> = IResult<&'a [u8], R, Error>;
/// This represents an action that will yield a Value when given further bytes to process and
/// handles to potentially consume. This is how we implement out-of-line data. The initial parse
/// takes the inline data, and when we're ready, the Defer can be fed the remaining bytes to take
/// the out of line data.
enum Defer<'d> {
/// This Defer doesn't need any further processing. We can just offer up the value right now.
Complete(Value),
/// This Defer implements the actual deferred processing pattern described.
Action(
Box<
dyn for<'a> FnOnce(
&'a [u8],
&mut Vec<fidl::HandleInfo>,
RecursionCounter,
) -> DResult<'a, Value>
+ 'd,
>,
),
}
impl<'d> Defer<'d> {
/// Completes a deferred parse and returns the result.
fn complete<'a>(
self,
data: &'a [u8],
handles: &mut Vec<fidl::HandleInfo>,
counter: RecursionCounter,
) -> DResult<'a, Value> {
match self {
Defer::Complete(v) => Ok((data, v)),
Defer::Action(act) => act(data, handles, counter),
}
}
}
impl<'d> From<Value> for Defer<'d> {
fn from(v: Value) -> Defer<'d> {
Defer::Complete(v)
}
}
fn take_u8(data: &[u8]) -> DResult<'_, u8> {
map(take(1usize), |x: &[u8]| x[0])(data)
}
fn value_u8(data: &[u8]) -> DResult<'_, Value> {
map(take_u8, Value::U8)(data)
}
fn value_bool(data: &[u8]) -> DResult<'_, Value> {
map(verify(take_u8, |&x| x == 0 || x == 1), |x| Value::Bool(x != 0))(data)
}
fn take_u16(data: &[u8]) -> DResult<'_, u16> {
map(take(2usize), |x: &[u8]| u16::from_le_bytes(x.try_into().unwrap()))(data)
}
fn value_u16(data: &[u8]) -> DResult<'_, Value> {
map(take_u16, Value::U16)(data)
}
fn take_u32(data: &[u8]) -> DResult<'_, u32> {
map(take(4usize), |x: &[u8]| u32::from_le_bytes(x.try_into().unwrap()))(data)
}
fn value_u32(data: &[u8]) -> DResult<'_, Value> {
map(take_u32, Value::U32)(data)
}
fn take_u64(data: &[u8]) -> DResult<'_, u64> {
map(take(8usize), |x: &[u8]| u64::from_le_bytes(x.try_into().unwrap()))(data)
}
fn value_u64(data: &[u8]) -> DResult<'_, Value> {
map(take_u64, Value::U64)(data)
}
fn take_i8(data: &[u8]) -> DResult<'_, i8> {
map(take(1usize), |x: &[u8]| i8::from_le_bytes([x[0]]))(data)
}
fn value_i8(data: &[u8]) -> DResult<'_, Value> {
map(take_i8, Value::I8)(data)
}
fn take_i16(data: &[u8]) -> DResult<'_, i16> {
map(take(2usize), |x: &[u8]| i16::from_le_bytes(x.try_into().unwrap()))(data)
}
fn value_i16(data: &[u8]) -> DResult<'_, Value> {
map(take_i16, Value::I16)(data)
}
fn take_i32(data: &[u8]) -> DResult<'_, i32> {
map(take(4usize), |x: &[u8]| i32::from_le_bytes(x.try_into().unwrap()))(data)
}
fn value_i32(data: &[u8]) -> DResult<'_, Value> {
map(take_i32, Value::I32)(data)
}
fn take_i64(data: &[u8]) -> DResult<'_, i64> {
map(take(8usize), |x: &[u8]| i64::from_le_bytes(x.try_into().unwrap()))(data)
}
fn value_i64(data: &[u8]) -> DResult<'_, Value> {
map(take_i64, Value::I64)(data)
}
fn take_f32(data: &[u8]) -> DResult<'_, f32> {
map(take(4usize), |x: &[u8]| f32::from_le_bytes(x.try_into().unwrap()))(data)
}
fn value_f32(data: &[u8]) -> DResult<'_, Value> {
map(take_f32, Value::F32)(data)
}
fn take_f64(data: &[u8]) -> DResult<'_, f64> {
map(take(8usize), |x: &[u8]| f64::from_le_bytes(x.try_into().unwrap()))(data)
}
fn value_f64(data: &[u8]) -> DResult<'_, Value> {
map(take_f64, Value::F64)(data)
}
fn transaction_header(data: &[u8]) -> DResult<'_, TransactionHeader> {
fidl::encoding::decode_transaction_header(data)
.map(|(a, b)| (b, a))
.map_err(|e| Error::DecodeError(format!("Invalid FIDL transaction header ({e:?})")).into())
}
fn take_padding(amount: usize) -> impl Fn(&[u8]) -> DResult<'_, ()> {
move |bytes| value((), verify(take(amount), |x: &[u8]| x.iter().all(|&x| x == 0)))(bytes)
}
fn decode_struct<'s>(
ns: &'s library::Namespace,
st: &'s library::Struct,
nullable: bool,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'s>> {
move |bytes: &[u8]| {
if !nullable {
return decode_struct_nonnull(ns, st)(bytes);
}
let (bytes, presence) = take_u64(bytes)?;
if presence == 0 {
Ok((bytes, Defer::Complete(Value::Null)))
} else if presence != ALLOC_PRESENT_U64 {
Err(Error::DecodeError("Bad presence indicator".to_owned()).into())
} else {
Ok((
bytes,
Defer::Action(Box::new(
move |bytes: &[u8],
handles: &mut Vec<fidl::HandleInfo>,
counter: RecursionCounter| {
let counter = counter.next()?;
let align = alignment_padding_for_size(st.size);
let (bytes, defer) =
terminated(decode_struct_nonnull(ns, st), take_padding(align))(bytes)?;
defer.complete(bytes, handles, counter)
},
)),
))
}
}
}
fn decode_struct_nonnull<'s>(
ns: &'s library::Namespace,
st: &'s library::Struct,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'s>> {
move |mut bytes: &[u8]| {
let mut offset = 0;
let mut fields = Vec::new();
for member in &st.members {
let (remaining, result) =
preceded(take_padding(member.offset - offset), decode_type(ns, &member.ty))(bytes)?;
fields.push((member.name.clone(), result));
bytes = remaining;
offset = member.offset + member.ty.inline_size(ns)?;
}
if offset < st.size {
let (remaining, _) = take_padding(st.size - offset)(bytes)?;
bytes = remaining;
}
Ok((
bytes,
Defer::Action(Box::new(
move |mut bytes: &[u8],
handles: &mut Vec<fidl::HandleInfo>,
counter: RecursionCounter| {
let mut complete_fields = Vec::new();
for (name, defer) in fields {
let (remaining, value) = defer.complete(bytes, handles, counter)?;
bytes = remaining;
complete_fields.push((name, value))
}
Ok((bytes, Value::Object(complete_fields)))
},
)),
))
}
}
fn decode_type<'t>(
ns: &'t library::Namespace,
ty: &'t library::Type,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'t>> {
use library::Type;
move |b: &[u8]| {
match ty {
Type::Bool => value_bool(b),
Type::U8 => value_u8(b),
Type::U16 => value_u16(b),
Type::U32 => value_u32(b),
Type::U64 => value_u64(b),
Type::I8 => value_i8(b),
Type::I16 => value_i16(b),
Type::I32 => value_i32(b),
Type::I64 => value_i64(b),
Type::F32 => value_f32(b),
Type::F64 => value_f64(b),
Type::Array(ty, size) => return decode_array(ns, ty, *size)(b),
Type::Vector { ty, nullable, element_count } => {
return decode_vector(ns, ty, *nullable, *element_count)(b)
}
Type::String { nullable, byte_count } => {
return decode_string(*nullable, *byte_count)(b)
}
Type::Identifier { name, nullable } => {
return decode_identifier(ns, name, *nullable)(b)
}
Type::Handle { object_type, nullable, rights } => {
return decode_handle(*object_type, *nullable, *rights)(b)
}
Type::Request { identifier, rights, nullable } => {
return decode_server_end(identifier.clone(), *nullable, *rights)(b)
}
Type::UnknownString(s) => {
Err(Error::LibraryError(format!("Unresolved Type: {}", s)).into())
}
Type::Unknown(library::TypeInfo { identifier: s, .. }) => {
return Err(Error::LibraryError(format!(
"Unresolved Type: {}",
s.as_ref().unwrap_or(&"<unidentified>".to_owned())
))
.into())
}
Type::FrameworkError => map(take_u32, |_| Value::Null)(b),
}
.map(|(x, y)| (x, Defer::Complete(y)))
}
}
/// Given a list of defers, complete them all and turn them into a list of complete values.
fn complete_deferred_list<'a>(
bytes: &'a [u8],
handles: &mut Vec<fidl::HandleInfo>,
defers: Vec<Defer<'_>>,
counter: RecursionCounter,
) -> DResult<'a, Value> {
let mut bytes = bytes;
let mut values = Vec::new();
for defer in defers {
let (next_bytes, value) = defer.complete(bytes, handles, counter)?;
bytes = next_bytes;
values.push(value)
}
Ok((bytes, Value::List(values)))
}
fn decode_array<'t>(
ns: &'t library::Namespace,
ty: &'t library::Type,
size: usize,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'t>> {
move |bytes: &[u8]| {
let (bytes, defers) = count(decode_type(ns, ty), size)(bytes)?;
Ok((
bytes,
Defer::Action(Box::new(
move |bytes: &[u8],
handles: &mut Vec<fidl::HandleInfo>,
counter: RecursionCounter| {
complete_deferred_list(bytes, handles, defers, counter)
},
)),
))
}
}
fn decode_vector<'t>(
ns: &'t library::Namespace,
ty: &'t library::Type,
nullable: bool,
element_count: Option<usize>,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'t>> {
move |bytes: &[u8]| {
let (bytes, (size, presence)) = pair(take_u64, take_u64)(bytes)?;
let size = size as usize;
let align = alignment_padding_for_size(size * ty.inline_size(ns)?);
if presence == 0 {
if nullable {
if size == 0 {
Ok((bytes, Defer::Complete(Value::Null)))
} else {
Err(Error::DecodeError("Absent vector had a size".to_owned()).into())
}
} else {
Err(Error::DecodeError("Missing non-nullable vector".to_owned()).into())
}
} else if presence != ALLOC_PRESENT_U64 {
Err(Error::DecodeError("Bad presence indicator".to_owned()).into())
} else if element_count.map(|x| x < size).unwrap_or(false) {
Err(Error::DecodeError("Vector too long".to_owned()).into())
} else {
Ok((
bytes,
Defer::Action(Box::new(
move |bytes: &[u8],
handles: &mut Vec<fidl::HandleInfo>,
counter: RecursionCounter| {
let counter = counter.next()?;
let (bytes, defers) = terminated(
count(decode_type(ns, ty), size),
take_padding(align),
)(bytes)?;
complete_deferred_list(bytes, handles, defers, counter)
},
)),
))
}
}
}
fn decode_string(
nullable: bool,
byte_count: Option<usize>,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'static>> {
move |bytes: &[u8]| {
let (bytes, (size, presence)) = pair(take_u64, take_u64)(bytes)?;
let size = size as usize;
let align = alignment_padding_for_size(size);
if presence == 0 {
if nullable {
if size == 0 {
Ok((bytes, Defer::Complete(Value::Null)))
} else {
Err(Error::DecodeError("Absent string had a size".to_owned()).into())
}
} else {
Err(Error::DecodeError("Missing non-nullable string".to_owned()).into())
}
} else if presence != ALLOC_PRESENT_U64 {
Err(Error::DecodeError("Bad presence indicator".to_owned()).into())
} else if byte_count.map(|x| x < size).unwrap_or(false) {
Err(Error::DecodeError("String too long".to_owned()).into())
} else {
Ok((
bytes,
Defer::Action(Box::new(
move |bytes: &[u8],
_: &mut Vec<fidl::HandleInfo>,
counter: RecursionCounter| {
let _counter = counter.next()?;
let (bytes, data) = terminated(take(size), take_padding(align))(bytes)?;
match str::from_utf8(data) {
Ok(x) => Ok((bytes, Value::String(x.to_owned()))),
Err(x) => Err(Error::Utf8Error(x).into()),
}
},
)),
))
}
}
}
fn decode_server_end(
interface: String,
nullable: bool,
rights: fidl::Rights,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'static>> {
decode_handle_with(
interface,
nullable,
&|x, y| Value::ServerEnd(x.into(), y),
Some(fidl::ObjectType::CHANNEL),
rights,
)
}
fn decode_client_end(
interface: String,
nullable: bool,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'static>> {
decode_handle_with(
interface,
nullable,
&|x, y| Value::ClientEnd(x.into(), y),
Some(fidl::ObjectType::CHANNEL),
fidl::Rights::CHANNEL_DEFAULT,
)
}
fn decode_handle(
handle_type: fidl::ObjectType,
nullable: bool,
rights: fidl::Rights,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'static>> {
decode_handle_with(handle_type, nullable, &Value::Handle, None, rights)
}
fn decode_handle_with<T: Clone + 'static>(
handle_type: T,
nullable: bool,
value_builder: &'static (impl Fn(fidl::Handle, T) -> Value + 'static),
constrain_type: Option<fidl::ObjectType>,
rights: fidl::Rights,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'static>> {
move |bytes: &[u8]| {
let handle_type = handle_type.clone();
let (bytes, presence) = take_u32(bytes)?;
if presence == 0 {
if nullable {
Ok((bytes, Defer::Complete(Value::Null)))
} else {
Err(Error::DecodeError("Missing non-nullable handle".to_owned()).into())
}
} else if presence != ALLOC_PRESENT_U32 {
Err(Error::DecodeError("Bad presence indicator".to_owned()).into())
} else {
Ok((
bytes,
Defer::Action(Box::new(
move |bytes: &[u8],
handles: &mut Vec<fidl::HandleInfo>,
_: RecursionCounter| {
if !handles.is_empty() {
if constrain_type.map(|x| x == handles[0].object_type).unwrap_or(true) {
let handle = handles.remove(0);
if !handle.rights.contains(rights)
&& handle.rights != fidl::Rights::SAME_RIGHTS
{
let missing = rights.clone().remove(handle.rights);
Err(Error::DecodeError(format!(
"Insufficient handle rights, need {missing:?}"
))
.into())
} else {
Ok((bytes, value_builder(handle.handle, handle_type)))
}
} else {
Err(Error::DecodeError("Wrong handle type".to_owned()).into())
}
} else {
Err(Error::DecodeError("Too few handles".to_owned()).into())
}
},
)),
))
}
}
}
fn decode_enum<'e>(
ns: &'e library::Namespace,
en: &'e library::Enum,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'e>> {
move |bytes: &[u8]| {
let (bytes, defer) = decode_type(ns, &en.ty)(bytes)?;
Ok((
bytes,
Defer::Action(Box::new(
move |bytes: &[u8],
handles: &mut Vec<fidl::HandleInfo>,
counter: RecursionCounter| {
let (bytes, value) = defer.complete(bytes, handles, counter)?;
for member in &en.members {
if value == member.value || !en.strict {
return Ok((bytes, Value::Enum(en.name.to_owned(), Box::new(value))));
}
}
if en.strict {
Err(Error::DecodeError("Unknown Enum Variant.".to_owned()).into())
} else {
Ok((bytes, Value::Enum(en.name.to_owned(), Box::new(value))))
}
},
)),
))
}
}
fn decode_bits<'b>(
ns: &'b library::Namespace,
bits: &'b library::Bits,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'b>> {
move |bytes: &[u8]| {
let (bytes, defer) = decode_type(ns, &bits.ty)(bytes)?;
Ok((
bytes,
Defer::Action(Box::new(
move |bytes: &[u8],
handles: &mut Vec<fidl::HandleInfo>,
counter: RecursionCounter| {
let (bytes, value) = defer.complete(bytes, handles, counter)?;
let data = value
.bits()
.ok_or(Error::LibraryError("Bits with non-integer type.".to_owned()))?;
if bits.strict && data != data & bits.mask {
Err(Error::DecodeError("Invalid value for bits field.".to_owned()).into())
} else {
Ok((bytes, Value::Bits(bits.name.to_owned(), Box::new(value))))
}
},
)),
))
}
}
/// Contents of an envelope header.
enum Envelope {
Present { bytes: u32, handles: u16 },
Inline { bytes: [u8; 4], handles: u16 },
Empty,
}
impl Envelope {
fn skip(&self) -> Defer<'static> {
let (envelope_bytes, envelope_handles) = match self {
Envelope::Present { bytes, handles } => (*bytes, *handles),
Envelope::Inline { handles, .. } => (0, *handles),
Envelope::Empty => return Defer::Complete(Value::Null),
};
Defer::Action(Box::new(
move |bytes: &[u8], handles: &mut Vec<fidl::HandleInfo>, counter: RecursionCounter| {
let _counter = counter.next()?;
if (envelope_bytes & 7u32) != 0 {
return Err(Error::DecodeError("Invalid envelope size".to_owned()).into());
}
let envelope_bytes = envelope_bytes as usize;
let envelope_handles = envelope_handles as usize;
if envelope_handles > handles.len() {
Err(Error::DecodeError("Insufficient handles for envelope".to_owned()).into())
} else if envelope_bytes > bytes.len() {
Err(Error::DecodeError("Insufficient bytes for envelope".to_owned()).into())
} else {
*handles = handles.split_off(envelope_handles);
Ok((&bytes[envelope_bytes as usize..], Value::Null))
}
},
))
}
fn decode_type<'s>(
&self,
ns: &'s library::Namespace,
ty: &'s library::Type,
) -> Result<Defer<'s>> {
if let &Envelope::Empty = self {
Ok(self.skip())
} else if !ty.is_resolved(ns) {
Ok(self.skip())
} else if let Envelope::Inline { bytes, handles } = self {
let (padding, ret) = decode_type(ns, ty)(bytes)?;
take_padding(padding.len())(padding)?;
let expect_handles = *handles as usize;
Ok(Defer::Action(Box::new(
move |bytes: &[u8],
handles: &mut Vec<fidl::HandleInfo>,
counter: RecursionCounter| {
let handle_count = handles.len();
let v = ret.complete(bytes, handles, counter)?;
let handles_used = handle_count - handles.len();
if handles_used != expect_handles {
Err(Error::DecodeError("Wrong number of handles in envelope".to_owned())
.into())
} else {
Ok(v)
}
},
)))
} else if ty.inline_size(ns)? <= 4 {
Err(Error::DecodeError("Envelope should be inline".to_owned()))
} else {
let Envelope::Present { bytes, handles } = self else { unreachable!() };
let expect_bytes = *bytes as usize;
let expect_handles = *handles as usize;
Ok(Defer::Action(Box::new(
move |bytes: &[u8],
handles: &mut Vec<fidl::HandleInfo>,
counter: RecursionCounter| {
let counter = counter.next()?;
let bytes_start = bytes.len();
let align = alignment_padding_for_size(ty.inline_size(ns)?);
let (bytes, defer) =
terminated(decode_type(ns, ty), take_padding(align))(bytes)?;
let handle_count = handles.len();
let (bytes, value) = defer.complete(bytes, handles, counter)?;
let handles_used = handle_count - handles.len();
let bytes_used = bytes_start - bytes.len();
if handles_used != expect_handles {
Err(Error::DecodeError("Wrong number of handles in envelope".to_owned())
.into())
} else if bytes_used != expect_bytes {
Err(Error::DecodeError("Wrong number of bytes in envelope".to_owned())
.into())
} else {
Ok((bytes, value))
}
},
)))
}
}
fn take<'a>(empty_ok: bool) -> impl Fn(&'a [u8]) -> DResult<'a, Envelope> {
move |bytes: &[u8]| {
let (bytes, (envelope_bytes, envelope_handles, envelope_flags)) =
tuple((take_u32, take_u16, take_u16))(bytes)?;
if envelope_bytes == 0 && envelope_handles == 0 && envelope_flags == 0 {
if !empty_ok {
Err(Error::DecodeError("Unexpected empty envelope.".to_owned()).into())
} else {
Ok((bytes, Envelope::Empty))
}
} else if envelope_flags == 0 {
Ok((bytes, Envelope::Present { bytes: envelope_bytes, handles: envelope_handles }))
} else if envelope_flags == 1 {
Ok((
bytes,
Envelope::Inline {
bytes: envelope_bytes.to_le_bytes(),
handles: envelope_handles,
},
))
} else {
Err(Error::DecodeError("Unknown evelope flags.".to_owned()).into())
}
}
}
}
fn decode_union<'u>(
ns: &'u library::Namespace,
union: &'u library::TableOrUnion,
nullable: bool,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'u>> {
move |bytes: &[u8]| {
let (bytes, (ordinal, envelope)) = tuple((take_u64, Envelope::take(nullable)))(bytes)?;
match (ordinal, &envelope) {
(0, Envelope::Empty) => return Ok((bytes, envelope.skip())),
(0, _) => return Err(Error::DecodeError("Invalid Union block.".to_owned()).into()),
_ => (),
};
match union.members.get(&ordinal) {
None if union.strict => {
Err(Error::DecodeError("Invalid Union ordinal.".to_owned()).into())
}
None => Ok((bytes, envelope.skip())),
Some(member) => Ok((
bytes,
Defer::Action(Box::new(
move |bytes: &[u8],
handles: &mut Vec<fidl::HandleInfo>,
counter: RecursionCounter| {
let (bytes, inner) = envelope
.decode_type(ns, &member.ty)?
.complete(bytes, handles, counter)?;
Ok((
bytes,
Value::Union(
union.name.to_owned(),
member.name.to_owned(),
Box::new(inner),
),
))
},
)),
)),
}
}
}
fn decode_table<'t>(
ns: &'t library::Namespace,
table: &'t library::TableOrUnion,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'t>> {
move |bytes: &[u8]| {
let (bytes, (size, data_ptr)) = pair(take_u64, take_u64)(bytes)?;
if data_ptr != ALLOC_PRESENT_U64 {
return Err(Error::DecodeError("Bad presence indicator.".to_owned()).into());
}
Ok((
bytes,
Defer::Action(Box::new(
move |bytes: &[u8],
handles: &mut Vec<fidl::HandleInfo>,
counter: RecursionCounter| {
let counter = counter.next()?;
let (mut bytes, envelopes) = count(Envelope::take(true), size as usize)(bytes)?;
let mut result = Vec::new();
let mut expect_ord = 1u64;
for envelope in envelopes {
let member = table.members.get(&expect_ord);
expect_ord += 1;
let next_bytes = if let Some(member) = member {
let (next_bytes, val) = envelope
.decode_type(ns, &member.ty)?
.complete(bytes, handles, counter)?;
if !matches!(val, Value::Null) {
result.push((member.name.clone(), val));
}
next_bytes
} else {
envelope.skip().complete(bytes, handles, counter)?.0
};
bytes = next_bytes;
}
Ok((bytes, Value::Object(result)))
},
)),
))
}
}
fn decode_identifier<'s>(
ns: &'s library::Namespace,
name: &'s str,
nullable: bool,
) -> impl Fn(&[u8]) -> DResult<'_, Defer<'s>> {
move |bytes: &[u8]| match ns.lookup(name)? {
library::LookupResult::Bits(b) => decode_bits(ns, b)(bytes),
library::LookupResult::Enum(e) => decode_enum(ns, e)(bytes),
library::LookupResult::Struct(s) => decode_struct(ns, s, nullable)(bytes),
library::LookupResult::Union(u) => decode_union(ns, u, nullable)(bytes),
library::LookupResult::Table(t) => decode_table(ns, t)(bytes),
library::LookupResult::Protocol(i) => decode_client_end(i.name.clone(), nullable)(bytes),
}
}
/// Decode a FIDL request or response, depending on the direction header.
fn decode_message<'a>(
ns: &library::Namespace,
direction: Direction,
bytes: &'a [u8],
mut handles: Vec<fidl::HandleInfo>,
) -> Result<(TransactionHeader, Value)> {
let (bytes, header) = transaction_header(bytes)?;
let (_, method) = ns.lookup_method_ordinal(header.ordinal)?;
let (message, has) = match direction {
Direction::Request => (method.request.as_ref(), method.has_request),
Direction::Response => (method.response.as_ref(), method.has_response),
};
if let Some(message) = message {
let (bytes, defer) = decode_type(ns, message)(bytes)?;
let (bytes, value) = defer.complete(bytes, &mut handles, RecursionCounter::new())?;
if !bytes.is_empty() && (bytes.len() >= 8 || bytes.iter().any(|x| *x != 0)) {
Err(Error::DecodeError(format!("{} bytes left over.", bytes.len())))
} else if !handles.is_empty() {
Err(Error::DecodeError(format!("{} handles left over.", handles.len())))
} else {
Ok((header, value))
}
} else if !has {
Err(Error::DecodeError(format!(
"Header indicates method {}, which has no {}.",
method.name,
direction.to_string()
)))
} else {
Ok((header, Value::Null))
}
}
/// Decode a FIDL request from a byte buffer and a list of handles.
pub fn decode_request(
ns: &library::Namespace,
bytes: &[u8],
handles: Vec<fidl::HandleInfo>,
) -> Result<(TransactionHeader, Value)> {
decode_message(ns, Direction::Request, bytes, handles)
}
/// Decode a FIDL response from a byte buffer and a list of handles.
pub fn decode_response(
ns: &library::Namespace,
bytes: &[u8],
handles: Vec<fidl::HandleInfo>,
) -> Result<(TransactionHeader, Value)> {
decode_message(ns, Direction::Response, bytes, handles)
}
/// Decode a FIDL value.
pub fn decode<'a>(
ns: &library::Namespace,
ty: &str,
bytes: &'a [u8],
mut handles: Vec<fidl::HandleInfo>,
) -> Result<Value> {
if bytes.len() % 8 != 0 {
return Err(Error::DecodeError("Unaligned encoded object".to_owned()));
}
let (bytes, defer) = decode_identifier(ns, ty, false)(bytes)?;
let (bytes, value) = defer.complete(bytes, &mut handles, RecursionCounter::new())?;
take_padding(bytes.len())(bytes)?;
if !bytes.is_empty() && (bytes.len() >= 8 || bytes.iter().any(|x| *x != 0)) {
Err(Error::DecodeError(format!("{} bytes left over.", bytes.len())))
} else if !handles.is_empty() {
Err(Error::DecodeError(format!("{} handles left over.", handles.len())))
} else {
Ok(value)
}
}