| Index: mojo/public/rust/src/bindings/decoding.rs
|
| diff --git a/mojo/public/rust/src/bindings/decoding.rs b/mojo/public/rust/src/bindings/decoding.rs
|
| deleted file mode 100644
|
| index 81c7ee769f06c88bc45039821007bdd11880ba1a..0000000000000000000000000000000000000000
|
| --- a/mojo/public/rust/src/bindings/decoding.rs
|
| +++ /dev/null
|
| @@ -1,381 +0,0 @@
|
| -// Copyright 2016 The Chromium 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 bindings::encoding::{Bits, Context, DataHeader, DataHeaderValue, DATA_HEADER_SIZE,
|
| - MojomNumeric};
|
| -use bindings::mojom::{MojomEncodable, MOJOM_NULL_POINTER, UNION_SIZE};
|
| -use bindings::util;
|
| -
|
| -use std::mem;
|
| -use std::ptr;
|
| -use std::vec::Vec;
|
| -
|
| -use system;
|
| -use system::{Handle, CastHandle, UntypedHandle};
|
| -
|
| -#[derive(Debug, Eq, PartialEq)]
|
| -pub enum ValidationError {
|
| - DifferentSizedArraysInMap,
|
| - IllegalHandle,
|
| - IllegalMemoryRange,
|
| - IllegalPointer,
|
| - MessageHeaderInvalidFlags,
|
| - MessageHeaderMissingRequestId,
|
| - MessageHeaderUnknownMethod,
|
| - MisalignedObject,
|
| - UnexpectedArrayHeader,
|
| - UnexpectedInvalidHandle,
|
| - UnexpectedNullPointer,
|
| - UnexpectedNullUnion,
|
| - UnexpectedStructHeader,
|
| -}
|
| -
|
| -impl ValidationError {
|
| - pub fn as_str(self) -> &'static str {
|
| - match self {
|
| - ValidationError::DifferentSizedArraysInMap => "VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP",
|
| - ValidationError::IllegalHandle => "VALIDATION_ERROR_ILLEGAL_HANDLE",
|
| - ValidationError::IllegalMemoryRange => "VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE",
|
| - ValidationError::IllegalPointer => "VALIDATION_ERROR_ILLEGAL_POINTER",
|
| - ValidationError::MessageHeaderInvalidFlags => "VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS",
|
| - ValidationError::MessageHeaderMissingRequestId => "VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID",
|
| - ValidationError::MessageHeaderUnknownMethod => "VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD",
|
| - ValidationError::MisalignedObject => "VALIDATION_ERROR_MISALIGNED_OBJECT",
|
| - ValidationError::UnexpectedArrayHeader => "VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER",
|
| - ValidationError::UnexpectedInvalidHandle => "VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE",
|
| - ValidationError::UnexpectedNullPointer => "VALIDATION_ERROR_UNEXPECTED_NULL_POINTER",
|
| - ValidationError::UnexpectedNullUnion => "VALIDATION_ERROR_UNEXPECTED_NULL_UNION",
|
| - ValidationError::UnexpectedStructHeader => "VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER",
|
| - }
|
| - }
|
| -}
|
| -
|
| -/// An decoding state represents the decoding logic for a single
|
| -/// Mojom object that is NOT inlined, such as a struct or an array.
|
| -pub struct DecodingState<'slice> {
|
| - /// The buffer the state may write to.
|
| - data: &'slice [u8],
|
| -
|
| - /// The offset of this serialized object into the overall buffer.
|
| - global_offset: usize,
|
| -
|
| - /// The current offset within 'data'.
|
| - offset: usize,
|
| -
|
| - /// The current bit offset within 'data'.
|
| - bit_offset: Bits,
|
| -}
|
| -
|
| -impl<'slice> DecodingState<'slice> {
|
| - /// Create a new decoding state.
|
| - pub fn new(buffer: &'slice [u8], offset: usize) -> DecodingState<'slice> {
|
| - DecodingState {
|
| - data: buffer,
|
| - global_offset: offset,
|
| - offset: 0,
|
| - bit_offset: Bits(0),
|
| - }
|
| - }
|
| -
|
| - /// Align the decoding state to the next byte.
|
| - pub fn align_to_byte(&mut self) {
|
| - if self.bit_offset > Bits(0) {
|
| - self.offset += 1;
|
| - self.bit_offset = Bits(0);
|
| - }
|
| - }
|
| -
|
| - /// Align the decoding state to the next 'bytes' boundary.
|
| - pub fn align_to_bytes(&mut self, bytes: usize) {
|
| - if self.offset != 0 {
|
| - self.offset = util::align_bytes(self.offset, bytes);
|
| - }
|
| - }
|
| -
|
| - /// Read a primitive from the buffer without incrementing the offset.
|
| - fn read_in_place<T: MojomNumeric>(&mut self) -> T {
|
| - let mut value: T = Default::default();
|
| - debug_assert!(mem::size_of::<T>() + self.offset <= self.data.len());
|
| - let ptr = (&self.data[self.offset..]).as_ptr();
|
| - unsafe {
|
| - ptr::copy_nonoverlapping(mem::transmute::<*const u8, *const T>(ptr),
|
| - &mut value as *mut T,
|
| - 1);
|
| - }
|
| - value
|
| - }
|
| -
|
| - /// Read a primitive from the buffer and increment the offset.
|
| - fn read<T: MojomNumeric>(&mut self) -> T {
|
| - let value = self.read_in_place::<T>();
|
| - self.bit_offset = Bits(0);
|
| - self.offset += mem::size_of::<T>();
|
| - value
|
| - }
|
| -
|
| - /// Decode a primitive from the buffer, naturally aligning before we read.
|
| - pub fn decode<T: MojomNumeric>(&mut self) -> T {
|
| - self.align_to_byte();
|
| - self.align_to_bytes(mem::size_of::<T>());
|
| - self.read::<T>()
|
| - }
|
| -
|
| - /// Decode a boolean value from the buffer as one bit.
|
| - pub fn decode_bool(&mut self) -> bool {
|
| - let offset = self.offset;
|
| - // Check the bit by getting the set bit and checking if its non-zero
|
| - let value = (self.data[offset] & self.bit_offset.as_set_bit()) > 0;
|
| - self.bit_offset += Bits(1);
|
| - let (bits, bytes) = self.bit_offset.as_bits_and_bytes();
|
| - self.offset += bytes;
|
| - self.bit_offset = bits;
|
| - value
|
| - }
|
| -
|
| - /// If we encounter a null pointer, increment past it.
|
| - ///
|
| - /// Returns if we skipped or not.
|
| - pub fn skip_if_null_pointer(&mut self) -> bool {
|
| - self.align_to_byte();
|
| - self.align_to_bytes(8);
|
| - let ptr = self.read_in_place::<u64>();
|
| - if ptr == MOJOM_NULL_POINTER {
|
| - self.offset += 8;
|
| - }
|
| - (ptr == MOJOM_NULL_POINTER)
|
| - }
|
| -
|
| - /// If we encounter a null union, increment past it.
|
| - ///
|
| - /// Returns if we skipped or not.
|
| - pub fn skip_if_null_union(&mut self) -> bool {
|
| - self.align_to_byte();
|
| - self.align_to_bytes(8);
|
| - let size = self.read_in_place::<u32>();
|
| - if size == 0 {
|
| - self.offset += UNION_SIZE;
|
| - }
|
| - (size == 0)
|
| - }
|
| -
|
| - /// If we encounter a null handle, increment past it.
|
| - ///
|
| - /// Returns if we skipped or not.
|
| - pub fn skip_if_null_handle(&mut self) -> bool {
|
| - self.align_to_byte();
|
| - self.align_to_bytes(4);
|
| - let index = self.read_in_place::<i32>();
|
| - if index < 0 {
|
| - self.offset += 4;
|
| - }
|
| - (index < 0)
|
| - }
|
| -
|
| - /// If we encounter a null interface, increment past it.
|
| - ///
|
| - /// Returns if we skipped or not.
|
| - pub fn skip_if_null_interface(&mut self) -> bool {
|
| - self.align_to_byte();
|
| - self.align_to_bytes(4);
|
| - let index = self.read_in_place::<i32>();
|
| - if index < 0 {
|
| - self.offset += 8;
|
| - }
|
| - (index < 0)
|
| - }
|
| -
|
| - /// Decode a pointer from the buffer as a global offset into the buffer.
|
| - ///
|
| - /// The pointer in the buffer is an offset relative to the pointer to another
|
| - /// location in the buffer. We convert that to an absolute offset with respect
|
| - /// to the buffer before returning. This is our defintion of a pointer.
|
| - pub fn decode_pointer(&mut self) -> Option<u64> {
|
| - self.align_to_byte();
|
| - self.align_to_bytes(8);
|
| - let current_location = (self.global_offset + self.offset) as u64;
|
| - let offset = self.read::<u64>();
|
| - if offset == MOJOM_NULL_POINTER {
|
| - Some(MOJOM_NULL_POINTER)
|
| - } else {
|
| - offset.checked_add(current_location)
|
| - }
|
| - }
|
| -
|
| - /// A routine for decoding an array header.
|
| - ///
|
| - /// Must be called with offset zero (that is, it must be the first thing
|
| - /// decoded). Performs numerous validation checks.
|
| - pub fn decode_array_header<T>(&mut self) -> Result<DataHeader, ValidationError>
|
| - where T: MojomEncodable
|
| - {
|
| - debug_assert_eq!(self.offset, 0);
|
| - // Make sure we can read the size first...
|
| - if self.data.len() < mem::size_of::<u32>() {
|
| - return Err(ValidationError::UnexpectedArrayHeader);
|
| - }
|
| - let bytes = self.decode::<u32>();
|
| - if (bytes as usize) < DATA_HEADER_SIZE {
|
| - return Err(ValidationError::UnexpectedArrayHeader);
|
| - }
|
| - let elems = self.decode::<u32>();
|
| - match T::embed_size(&Default::default()).checked_mul(elems as usize) {
|
| - Some(value) => {
|
| - if (bytes as usize) < value.as_bytes() + DATA_HEADER_SIZE {
|
| - return Err(ValidationError::UnexpectedArrayHeader);
|
| - }
|
| - }
|
| - None => return Err(ValidationError::UnexpectedArrayHeader),
|
| - }
|
| - Ok(DataHeader::new(bytes as usize, DataHeaderValue::Elements(elems)))
|
| - }
|
| -
|
| - /// A routine for decoding an struct header.
|
| - ///
|
| - /// Must be called with offset zero (that is, it must be the first thing
|
| - /// decoded). Performs numerous validation checks.
|
| - pub fn decode_struct_header(&mut self,
|
| - versions: &[(u32, u32)])
|
| - -> Result<DataHeader, ValidationError> {
|
| - debug_assert_eq!(self.offset, 0);
|
| - // Make sure we can read the size first...
|
| - if self.data.len() < mem::size_of::<u32>() {
|
| - return Err(ValidationError::UnexpectedStructHeader);
|
| - }
|
| - let bytes = self.decode::<u32>();
|
| - if (bytes as usize) < DATA_HEADER_SIZE {
|
| - return Err(ValidationError::UnexpectedStructHeader);
|
| - }
|
| - let version = self.decode::<u32>();
|
| - // Versioning validation: versions are generated as a sorted array of tuples, so
|
| - // to find the version we are given by the header we use a binary search.
|
| - match versions.binary_search_by(|val| val.0.cmp(&version)) {
|
| - Ok(idx) => {
|
| - let (_, size) = versions[idx];
|
| - if bytes != size {
|
| - return Err(ValidationError::UnexpectedStructHeader);
|
| - }
|
| - }
|
| - Err(idx) => {
|
| - if idx == 0 {
|
| - panic!("Should be earliest version? \
|
| - Versions: {:?}, \
|
| - Version: {}, \
|
| - Size: {}", versions, version, bytes);
|
| - }
|
| - let len = versions.len();
|
| - let (latest_version, _) = versions[len - 1];
|
| - let (_, size) = versions[idx - 1];
|
| - // If this is higher than any version we know, its okay for the size to be bigger,
|
| - // but if its a version we know about, it must match the size.
|
| - if (version > latest_version && bytes < size) ||
|
| - (version <= latest_version && bytes != size) {
|
| - return Err(ValidationError::UnexpectedStructHeader);
|
| - }
|
| - }
|
| - }
|
| - Ok(DataHeader::new(bytes as usize, DataHeaderValue::Version(version)))
|
| - }
|
| -}
|
| -
|
| -/// A struct that will encode a given Mojom object and convert it into
|
| -/// bytes and a vector of handles.
|
| -pub struct Decoder<'slice> {
|
| - bytes: usize,
|
| - buffer: Option<&'slice [u8]>,
|
| - states: Vec<DecodingState<'slice>>,
|
| - handles: Vec<UntypedHandle>,
|
| - handles_claimed: usize, // A length that claims all handles were claimed up to this index
|
| - max_offset: usize, // Represents the maximum value an offset may have
|
| -}
|
| -
|
| -impl<'slice> Decoder<'slice> {
|
| - /// Create a new Decoder.
|
| - pub fn new(buffer: &'slice [u8], handles: Vec<UntypedHandle>) -> Decoder<'slice> {
|
| - let max_offset = buffer.len();
|
| - Decoder {
|
| - bytes: 0,
|
| - buffer: Some(buffer),
|
| - states: Vec::new(),
|
| - handles: handles,
|
| - handles_claimed: 0,
|
| - max_offset: max_offset,
|
| - }
|
| - }
|
| -
|
| - /// Claim space in the buffer to start decoding some object.
|
| - ///
|
| - /// Creates a new decoding state for the object and returns a context.
|
| - pub fn claim(&mut self, offset: usize) -> Result<Context, ValidationError> {
|
| - // Check if the layout order is sane
|
| - if offset < self.bytes {
|
| - return Err(ValidationError::IllegalMemoryRange);
|
| - }
|
| - // Check for 8-byte alignment
|
| - if offset & 7 != 0 {
|
| - return Err(ValidationError::MisalignedObject);
|
| - }
|
| - // Bounds check on offset
|
| - if offset > self.max_offset {
|
| - return Err(ValidationError::IllegalPointer);
|
| - }
|
| - let mut buffer = self.buffer.take().expect("No buffer?");
|
| - let space = offset - self.bytes;
|
| - buffer = &buffer[space..];
|
| - // Make sure we can even read the bytes in the header
|
| - if buffer.len() < mem::size_of::<u32>() {
|
| - return Err(ValidationError::IllegalMemoryRange);
|
| - }
|
| - // Read the number of bytes in the memory region according to the data header
|
| - let mut read_size: u32 = 0;
|
| - unsafe {
|
| - ptr::copy_nonoverlapping(mem::transmute::<*const u8, *const u32>(buffer.as_ptr()),
|
| - &mut read_size as *mut u32,
|
| - mem::size_of::<u32>());
|
| - }
|
| - let size = u32::from_le(read_size) as usize;
|
| - // Make sure the size we read is sane...
|
| - if size > buffer.len() {
|
| - return Err(ValidationError::IllegalMemoryRange);
|
| - }
|
| - // TODO(mknyszek): Check size for validation
|
| - let (claimed, unclaimed) = buffer.split_at(size);
|
| - self.states.push(DecodingState::new(claimed, offset));
|
| - self.buffer = Some(unclaimed);
|
| - self.bytes += space + size;
|
| - Ok(Context::new(self.states.len() - 1))
|
| - }
|
| -
|
| - /// Claims a handle at some particular index in the given handles array.
|
| - ///
|
| - /// Returns the handle with all type information in-tact.
|
| - pub fn claim_handle<T: Handle + CastHandle>(&mut self,
|
| - index: i32)
|
| - -> Result<T, ValidationError> {
|
| - let real_index = if index >= 0 {
|
| - index as usize
|
| - } else {
|
| - return Err(ValidationError::UnexpectedInvalidHandle);
|
| - };
|
| - // If the index exceeds our number of handles or if we have already claimed that handle
|
| - if real_index >= self.handles.len() || real_index < self.handles_claimed {
|
| - return Err(ValidationError::IllegalHandle);
|
| - }
|
| - self.handles_claimed = real_index + 1;
|
| - let raw_handle = self.handles[real_index].get_native_handle();
|
| - unsafe {
|
| - self.handles[real_index].invalidate();
|
| - Ok(T::from_untyped(system::acquire(raw_handle)))
|
| - }
|
| - }
|
| -
|
| - /// Immutably borrow a decoding state via Context.
|
| - pub fn get(&self, context: &Context) -> &DecodingState<'slice> {
|
| - &self.states[context.id()]
|
| - }
|
| -
|
| - /// Mutably borrow a decoding state via Context.
|
| - pub fn get_mut(&mut self, context: &Context) -> &mut DecodingState<'slice> {
|
| - &mut self.states[context.id()]
|
| - }
|
| -}
|
|
|