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()] |
- } |
-} |