// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use crate::bitwidth::BitWidth; use crate::flexbuffer_type::FlexBufferType; use crate::{Blob, Buffer}; use std::convert::{TryFrom, TryInto}; use std::fmt; use std::ops::Rem; use std::str::FromStr; mod de; mod iter; mod map; mod serialize; mod vector; pub use de::DeserializationError; pub use iter::ReaderIterator; pub use map::{MapReader, MapReaderIndexer}; pub use vector::VectorReader; /// All the possible errors when reading a flexbuffer. #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub enum Error { /// One of the following data errors occured: /// /// * The read flexbuffer had an offset that pointed outside the flexbuffer. /// * The 'negative indicies' where length and map keys are stored were out of bounds /// * The buffer was too small to contain a flexbuffer root. FlexbufferOutOfBounds, /// Failed to parse a valid FlexbufferType and Bitwidth from a type byte. InvalidPackedType, /// Flexbuffer type of the read data does not match function used. UnexpectedFlexbufferType { expected: FlexBufferType, actual: FlexBufferType, }, /// BitWidth type of the read data does not match function used. UnexpectedBitWidth { expected: BitWidth, actual: BitWidth, }, /// Read a flexbuffer offset or length that overflowed usize. ReadUsizeOverflowed, /// Tried to index a type that's not one of the Flexbuffer vector types. CannotIndexAsVector, /// Tried to index a Flexbuffer vector or map out of bounds. IndexOutOfBounds, /// A Map was indexed with a key that it did not contain. KeyNotFound, /// Failed to parse a Utf8 string. /// The Option will be `None` if and only if this Error was deserialized. // NOTE: std::str::Utf8Error does not implement Serialize, Deserialize, nor Default. We tell // serde to skip the field and default to None. We prefer to have the boxed error so it can be // used with std::error::Error::source, though another (worse) option could be to drop that // information. Utf8Error(#[serde(skip)] Option>), /// get_slice failed because the given data buffer is misaligned. AlignmentError, InvalidRootWidth, InvalidMapKeysVectorWidth, } impl std::convert::From for Error { fn from(e: std::str::Utf8Error) -> Self { Self::Utf8Error(Some(Box::new(e))) } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::UnexpectedBitWidth { expected, actual } => write!( f, "Error reading flexbuffer: Expected bitwidth: {:?}, found bitwidth: {:?}", expected, actual ), Self::UnexpectedFlexbufferType { expected, actual } => write!( f, "Error reading flexbuffer: Expected type: {:?}, found type: {:?}", expected, actual ), _ => write!(f, "Error reading flexbuffer: {:?}", self), } } } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { if let Self::Utf8Error(Some(e)) = self { Some(e) } else { None } } } pub trait ReadLE: crate::private::Sealed + std::marker::Sized { const VECTOR_TYPE: FlexBufferType; const WIDTH: BitWidth; } macro_rules! rle { ($T: ty, $VECTOR_TYPE: ident, $WIDTH: ident) => { impl ReadLE for $T { const VECTOR_TYPE: FlexBufferType = FlexBufferType::$VECTOR_TYPE; const WIDTH: BitWidth = BitWidth::$WIDTH; } }; } rle!(u8, VectorUInt, W8); rle!(u16, VectorUInt, W16); rle!(u32, VectorUInt, W32); rle!(u64, VectorUInt, W64); rle!(i8, VectorInt, W8); rle!(i16, VectorInt, W16); rle!(i32, VectorInt, W32); rle!(i64, VectorInt, W64); rle!(f32, VectorFloat, W32); rle!(f64, VectorFloat, W64); macro_rules! as_default { ($as: ident, $get: ident, $T: ty) => { pub fn $as(&self) -> $T { self.$get().unwrap_or_default() } }; } /// `Reader`s allow access to data stored in a Flexbuffer. /// /// Each reader represents a single address in the buffer so data is read lazily. Start a reader /// by calling `get_root` on your flexbuffer `&[u8]`. /// /// - The `get_T` methods return a `Result`. They return an OK value if and only if the /// flexbuffer type matches `T`. This is analogous to the behavior of Rust's json library, though /// with Result instead of Option. /// - The `as_T` methods will try their best to return to a value of type `T` /// (by casting or even parsing a string if necessary) but ultimately returns `T::default` if it /// fails. This behavior is analogous to that of flexbuffers C++. pub struct Reader { fxb_type: FlexBufferType, width: BitWidth, address: usize, buffer: B, } impl Clone for Reader { fn clone(&self) -> Self { Reader { fxb_type: self.fxb_type, width: self.width, address: self.address, buffer: self.buffer.shallow_copy(), } } } impl Default for Reader { fn default() -> Self { Reader { fxb_type: FlexBufferType::default(), width: BitWidth::default(), address: usize::default(), buffer: B::empty(), } } } // manual implementation of Debug because buffer slice can't be automatically displayed impl std::fmt::Debug for Reader { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // skips buffer field f.debug_struct("Reader") .field("fxb_type", &self.fxb_type) .field("width", &self.width) .field("address", &self.address) .finish() } } macro_rules! try_cast_fn { ($name: ident, $full_width: ident, $Ty: ident) => { pub fn $name(&self) -> $Ty { self.$full_width().try_into().unwrap_or_default() } }; } fn safe_sub(a: usize, b: usize) -> Result { a.checked_sub(b).ok_or(Error::FlexbufferOutOfBounds) } fn deref_offset(buffer: &[u8], address: usize, width: BitWidth) -> Result { let off = read_usize(buffer, address, width); safe_sub(address, off) } impl Reader { fn new( buffer: B, mut address: usize, mut fxb_type: FlexBufferType, width: BitWidth, parent_width: BitWidth, ) -> Result { if fxb_type.is_reference() { address = deref_offset(&buffer, address, parent_width)?; // Indirects were dereferenced. if let Some(t) = fxb_type.to_direct() { fxb_type = t; } } Ok(Reader { address, fxb_type, width, buffer, }) } /// Parses the flexbuffer from the given buffer. Assumes the flexbuffer root is the last byte /// of the buffer. pub fn get_root(buffer: B) -> Result { let end = buffer.len(); if end < 3 { return Err(Error::FlexbufferOutOfBounds); } // Last byte is the root width. let root_width = BitWidth::from_nbytes(buffer[end - 1]).ok_or(Error::InvalidRootWidth)?; // Second last byte is root type. let (fxb_type, width) = unpack_type(buffer[end - 2])?; // Location of root data. (BitWidth bits before root type) let address = safe_sub(end - 2, root_width.n_bytes())?; Self::new(buffer, address, fxb_type, width, root_width) } /// Convenience function to get the underlying buffer. By using `shallow_copy`, this preserves /// the lifetime that the underlying buffer has. pub fn buffer(&self) -> B { self.buffer.shallow_copy() } /// Returns the FlexBufferType of this Reader. pub fn flexbuffer_type(&self) -> FlexBufferType { self.fxb_type } /// Returns the bitwidth of this Reader. pub fn bitwidth(&self) -> BitWidth { self.width } /// Returns the length of the Flexbuffer. If the type has no length, or if an error occurs, /// 0 is returned. pub fn length(&self) -> usize { if let Some(len) = self.fxb_type.fixed_length_vector_length() { len } else if self.fxb_type.has_length_slot() && self.address >= self.width.n_bytes() { read_usize( &self.buffer, self.address - self.width.n_bytes(), self.width, ) } else { 0 } } /// Returns true if the flexbuffer is aligned to 8 bytes. This guarantees, for valid /// flexbuffers, that the data is correctly aligned in memory and slices can be read directly /// e.g. with `get_f64s` or `get_i16s`. #[inline] pub fn is_aligned(&self) -> bool { (self.buffer.as_ptr() as usize).rem(8) == 0 } as_default!(as_vector, get_vector, VectorReader); as_default!(as_map, get_map, MapReader); fn expect_type(&self, ty: FlexBufferType) -> Result<(), Error> { if self.fxb_type == ty { Ok(()) } else { Err(Error::UnexpectedFlexbufferType { expected: ty, actual: self.fxb_type, }) } } fn expect_bw(&self, bw: BitWidth) -> Result<(), Error> { if self.width == bw { Ok(()) } else { Err(Error::UnexpectedBitWidth { expected: bw, actual: self.width, }) } } /// Directly reads a slice of type `T` where `T` is one of `u8,u16,u32,u64,i8,i16,i32,i64,f32,f64`. /// Returns Err if the type, bitwidth, or memory alignment does not match. Since the bitwidth is /// dynamic, its better to use a VectorReader unless you know your data and performance is critical. #[cfg(target_endian = "little")] #[deprecated( since = "0.3.0", note = "This function is unsafe - if this functionality is needed use `Reader::buffer::align_to`" )] pub fn get_slice(&self) -> Result<&[T], Error> { if self.flexbuffer_type().typed_vector_type() != T::VECTOR_TYPE.typed_vector_type() { self.expect_type(T::VECTOR_TYPE)?; } if self.bitwidth().n_bytes() != std::mem::size_of::() { self.expect_bw(T::WIDTH)?; } let end = self.address + self.length() * std::mem::size_of::(); let slice: &[u8] = self .buffer .get(self.address..end) .ok_or(Error::FlexbufferOutOfBounds)?; // `align_to` is required because the point of this function is to directly hand back a // slice of scalars. This can fail because Rust's default allocator is not 16byte aligned // (though in practice this only happens for small buffers). let (pre, mid, suf) = unsafe { slice.align_to::() }; if pre.is_empty() && suf.is_empty() { Ok(mid) } else { Err(Error::AlignmentError) } } /// Returns the value of the reader if it is a boolean. /// Otherwise Returns error. pub fn get_bool(&self) -> Result { self.expect_type(FlexBufferType::Bool)?; Ok( self.buffer[self.address..self.address + self.width.n_bytes()] .iter() .any(|&b| b != 0), ) } /// Gets the length of the key if this type is a key. /// /// Otherwise, returns an error. #[inline] fn get_key_len(&self) -> Result { self.expect_type(FlexBufferType::Key)?; let (length, _) = self.buffer[self.address..] .iter() .enumerate() .find(|(_, &b)| b == b'\0') .unwrap_or((0, &0)); Ok(length) } /// Retrieves the string value up until the first `\0` character. pub fn get_key(&self) -> Result { let bytes = self .buffer .slice(self.address..self.address + self.get_key_len()?) .ok_or(Error::IndexOutOfBounds)?; Ok(bytes.buffer_str()?) } pub fn get_blob(&self) -> Result, Error> { self.expect_type(FlexBufferType::Blob)?; Ok(Blob( self.buffer .slice(self.address..self.address + self.length()) .ok_or(Error::IndexOutOfBounds)?, )) } pub fn as_blob(&self) -> Blob { self.get_blob().unwrap_or(Blob(B::empty())) } /// Retrieves str pointer, errors if invalid UTF-8, or the provided index /// is out of bounds. pub fn get_str(&self) -> Result { self.expect_type(FlexBufferType::String)?; let bytes = self .buffer .slice(self.address..self.address + self.length()); Ok(bytes.ok_or(Error::ReadUsizeOverflowed)?.buffer_str()?) } fn get_map_info(&self) -> Result<(usize, BitWidth), Error> { self.expect_type(FlexBufferType::Map)?; if 3 * self.width.n_bytes() >= self.address { return Err(Error::FlexbufferOutOfBounds); } let keys_offset_address = self.address - 3 * self.width.n_bytes(); let keys_width = { let kw_addr = self.address - 2 * self.width.n_bytes(); let kw = read_usize(&self.buffer, kw_addr, self.width); BitWidth::from_nbytes(kw).ok_or(Error::InvalidMapKeysVectorWidth) }?; Ok((keys_offset_address, keys_width)) } pub fn get_map(&self) -> Result, Error> { let (keys_offset_address, keys_width) = self.get_map_info()?; let keys_address = deref_offset(&self.buffer, keys_offset_address, self.width)?; // TODO(cneo): Check that vectors length equals keys length. Ok(MapReader { buffer: self.buffer.shallow_copy(), values_address: self.address, values_width: self.width, keys_address, keys_width, length: self.length(), }) } /// Tries to read a FlexBufferType::UInt. Returns Err if the type is not a UInt or if the /// address is out of bounds. pub fn get_u64(&self) -> Result { self.expect_type(FlexBufferType::UInt)?; let cursor = self .buffer .get(self.address..self.address + self.width.n_bytes()); match self.width { BitWidth::W8 => cursor.map(|s| s[0] as u8).map(Into::into), BitWidth::W16 => cursor .and_then(|s| s.try_into().ok()) .map(::from_le_bytes) .map(Into::into), BitWidth::W32 => cursor .and_then(|s| s.try_into().ok()) .map(::from_le_bytes) .map(Into::into), BitWidth::W64 => cursor .and_then(|s| s.try_into().ok()) .map(::from_le_bytes), } .ok_or(Error::FlexbufferOutOfBounds) } /// Tries to read a FlexBufferType::Int. Returns Err if the type is not a UInt or if the /// address is out of bounds. pub fn get_i64(&self) -> Result { self.expect_type(FlexBufferType::Int)?; let cursor = self .buffer .get(self.address..self.address + self.width.n_bytes()); match self.width { BitWidth::W8 => cursor.map(|s| s[0] as i8).map(Into::into), BitWidth::W16 => cursor .and_then(|s| s.try_into().ok()) .map(::from_le_bytes) .map(Into::into), BitWidth::W32 => cursor .and_then(|s| s.try_into().ok()) .map(::from_le_bytes) .map(Into::into), BitWidth::W64 => cursor .and_then(|s| s.try_into().ok()) .map(::from_le_bytes), } .ok_or(Error::FlexbufferOutOfBounds) } /// Tries to read a FlexBufferType::Float. Returns Err if the type is not a UInt, if the /// address is out of bounds, or if its a f16 or f8 (not currently supported). pub fn get_f64(&self) -> Result { self.expect_type(FlexBufferType::Float)?; let cursor = self .buffer .get(self.address..self.address + self.width.n_bytes()); match self.width { BitWidth::W8 | BitWidth::W16 => return Err(Error::InvalidPackedType), BitWidth::W32 => cursor .and_then(|s| s.try_into().ok()) .map(f32_from_le_bytes) .map(Into::into), BitWidth::W64 => cursor .and_then(|s| s.try_into().ok()) .map(f64_from_le_bytes), } .ok_or(Error::FlexbufferOutOfBounds) } pub fn as_bool(&self) -> bool { use FlexBufferType::*; match self.fxb_type { Bool => self.get_bool().unwrap_or_default(), UInt => self.as_u64() != 0, Int => self.as_i64() != 0, Float => self.as_f64().abs() > std::f64::EPSILON, String | Key => !self.as_str().is_empty(), Null => false, Blob => self.length() != 0, ty if ty.is_vector() => self.length() != 0, _ => unreachable!(), } } /// Returns a u64, casting if necessary. For Maps and Vectors, their length is /// returned. If anything fails, 0 is returned. pub fn as_u64(&self) -> u64 { match self.fxb_type { FlexBufferType::UInt => self.get_u64().unwrap_or_default(), FlexBufferType::Int => self .get_i64() .unwrap_or_default() .try_into() .unwrap_or_default(), FlexBufferType::Float => self.get_f64().unwrap_or_default() as u64, FlexBufferType::String => { if let Ok(s) = self.get_str() { if let Ok(f) = u64::from_str(&s) { return f; } } 0 } _ if self.fxb_type.is_vector() => self.length() as u64, _ => 0, } } try_cast_fn!(as_u32, as_u64, u32); try_cast_fn!(as_u16, as_u64, u16); try_cast_fn!(as_u8, as_u64, u8); /// Returns an i64, casting if necessary. For Maps and Vectors, their length is /// returned. If anything fails, 0 is returned. pub fn as_i64(&self) -> i64 { match self.fxb_type { FlexBufferType::Int => self.get_i64().unwrap_or_default(), FlexBufferType::UInt => self .get_u64() .unwrap_or_default() .try_into() .unwrap_or_default(), FlexBufferType::Float => self.get_f64().unwrap_or_default() as i64, FlexBufferType::String => { if let Ok(s) = self.get_str() { if let Ok(f) = i64::from_str(&s) { return f; } } 0 } _ if self.fxb_type.is_vector() => self.length() as i64, _ => 0, } } try_cast_fn!(as_i32, as_i64, i32); try_cast_fn!(as_i16, as_i64, i16); try_cast_fn!(as_i8, as_i64, i8); /// Returns an f64, casting if necessary. For Maps and Vectors, their length is /// returned. If anything fails, 0 is returned. pub fn as_f64(&self) -> f64 { match self.fxb_type { FlexBufferType::Int => self.get_i64().unwrap_or_default() as f64, FlexBufferType::UInt => self.get_u64().unwrap_or_default() as f64, FlexBufferType::Float => self.get_f64().unwrap_or_default(), FlexBufferType::String => { if let Ok(s) = self.get_str() { if let Ok(f) = f64::from_str(&s) { return f; } } 0.0 } _ if self.fxb_type.is_vector() => self.length() as f64, _ => 0.0, } } pub fn as_f32(&self) -> f32 { self.as_f64() as f32 } /// Returns empty string if you're not trying to read a string. pub fn as_str(&self) -> B::BufferString { match self.fxb_type { FlexBufferType::String => self.get_str().unwrap_or(B::empty_str()), FlexBufferType::Key => self.get_key().unwrap_or(B::empty_str()), _ => B::empty_str(), } } pub fn get_vector(&self) -> Result, Error> { if !self.fxb_type.is_vector() { self.expect_type(FlexBufferType::Vector)?; }; Ok(VectorReader { reader: self.clone(), length: self.length(), }) } } impl fmt::Display for Reader { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use FlexBufferType::*; match self.flexbuffer_type() { Null => write!(f, "null"), UInt => write!(f, "{}", self.as_u64()), Int => write!(f, "{}", self.as_i64()), Float => write!(f, "{}", self.as_f64()), Key | String => write!(f, "{:?}", &self.as_str() as &str), Bool => write!(f, "{}", self.as_bool()), Blob => write!(f, "blob"), Map => { write!(f, "{{")?; let m = self.as_map(); let mut pairs = m.iter_keys().zip(m.iter_values()); if let Some((k, v)) = pairs.next() { write!(f, "{:?}: {}", &k as &str, v)?; for (k, v) in pairs { write!(f, ", {:?}: {}", &k as &str, v)?; } } write!(f, "}}") } t if t.is_vector() => { write!(f, "[")?; let mut elems = self.as_vector().iter(); if let Some(first) = elems.next() { write!(f, "{}", first)?; for e in elems { write!(f, ", {}", e)?; } } write!(f, "]") } _ => unreachable!("Display not implemented for {:?}", self), } } } // TODO(cneo): Use ::from_le_bytes when we move past rustc 1.39. fn f32_from_le_bytes(bytes: [u8; 4]) -> f32 { let bits = ::from_le_bytes(bytes); ::from_bits(bits) } fn f64_from_le_bytes(bytes: [u8; 8]) -> f64 { let bits = ::from_le_bytes(bytes); ::from_bits(bits) } fn read_usize(buffer: &[u8], address: usize, width: BitWidth) -> usize { let cursor = &buffer[address..]; match width { BitWidth::W8 => cursor[0] as usize, BitWidth::W16 => cursor .get(0..2) .and_then(|s| s.try_into().ok()) .map(::from_le_bytes) .unwrap_or_default() as usize, BitWidth::W32 => cursor .get(0..4) .and_then(|s| s.try_into().ok()) .map(::from_le_bytes) .unwrap_or_default() as usize, BitWidth::W64 => cursor .get(0..8) .and_then(|s| s.try_into().ok()) .map(::from_le_bytes) .unwrap_or_default() as usize, } } fn unpack_type(ty: u8) -> Result<(FlexBufferType, BitWidth), Error> { let w = BitWidth::try_from(ty & 3u8).map_err(|_| Error::InvalidPackedType)?; let t = FlexBufferType::try_from(ty >> 2).map_err(|_| Error::InvalidPackedType)?; Ok((t, w)) }