diff options
Diffstat (limited to 'vendor/object/src/read/util.rs')
-rw-r--r-- | vendor/object/src/read/util.rs | 425 |
1 files changed, 0 insertions, 425 deletions
diff --git a/vendor/object/src/read/util.rs b/vendor/object/src/read/util.rs deleted file mode 100644 index 7d85b27..0000000 --- a/vendor/object/src/read/util.rs +++ /dev/null @@ -1,425 +0,0 @@ -use alloc::string::String; -use core::convert::TryInto; -use core::fmt; -use core::marker::PhantomData; - -use crate::pod::{from_bytes, slice_from_bytes, Pod}; -use crate::ReadRef; - -/// A newtype for byte slices. -/// -/// It has these important features: -/// - no methods that can panic, such as `Index` -/// - convenience methods for `Pod` types -/// - a useful `Debug` implementation -#[derive(Default, Clone, Copy, PartialEq, Eq)] -pub struct Bytes<'data>(pub &'data [u8]); - -impl<'data> fmt::Debug for Bytes<'data> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - debug_list_bytes(self.0, fmt) - } -} - -impl<'data> Bytes<'data> { - /// Return the length of the byte slice. - #[inline] - pub fn len(&self) -> usize { - self.0.len() - } - - /// Return true if the byte slice is empty. - #[inline] - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Skip over the given number of bytes at the start of the byte slice. - /// - /// Modifies the byte slice to start after the bytes. - /// - /// Returns an error if there are too few bytes. - #[inline] - pub fn skip(&mut self, offset: usize) -> Result<(), ()> { - match self.0.get(offset..) { - Some(tail) => { - self.0 = tail; - Ok(()) - } - None => { - self.0 = &[]; - Err(()) - } - } - } - - /// Return a reference to the given number of bytes at the start of the byte slice. - /// - /// Modifies the byte slice to start after the bytes. - /// - /// Returns an error if there are too few bytes. - #[inline] - pub fn read_bytes(&mut self, count: usize) -> Result<Bytes<'data>, ()> { - match (self.0.get(..count), self.0.get(count..)) { - (Some(head), Some(tail)) => { - self.0 = tail; - Ok(Bytes(head)) - } - _ => { - self.0 = &[]; - Err(()) - } - } - } - - /// Return a reference to the given number of bytes at the given offset of the byte slice. - /// - /// Returns an error if the offset is invalid or there are too few bytes. - #[inline] - pub fn read_bytes_at(mut self, offset: usize, count: usize) -> Result<Bytes<'data>, ()> { - self.skip(offset)?; - self.read_bytes(count) - } - - /// Return a reference to a `Pod` struct at the start of the byte slice. - /// - /// Modifies the byte slice to start after the bytes. - /// - /// Returns an error if there are too few bytes or the slice is incorrectly aligned. - #[inline] - pub fn read<T: Pod>(&mut self) -> Result<&'data T, ()> { - match from_bytes(self.0) { - Ok((value, tail)) => { - self.0 = tail; - Ok(value) - } - Err(()) => { - self.0 = &[]; - Err(()) - } - } - } - - /// Return a reference to a `Pod` struct at the given offset of the byte slice. - /// - /// Returns an error if there are too few bytes or the offset is incorrectly aligned. - #[inline] - pub fn read_at<T: Pod>(mut self, offset: usize) -> Result<&'data T, ()> { - self.skip(offset)?; - self.read() - } - - /// Return a reference to a slice of `Pod` structs at the start of the byte slice. - /// - /// Modifies the byte slice to start after the bytes. - /// - /// Returns an error if there are too few bytes or the offset is incorrectly aligned. - #[inline] - pub fn read_slice<T: Pod>(&mut self, count: usize) -> Result<&'data [T], ()> { - match slice_from_bytes(self.0, count) { - Ok((value, tail)) => { - self.0 = tail; - Ok(value) - } - Err(()) => { - self.0 = &[]; - Err(()) - } - } - } - - /// Return a reference to a slice of `Pod` structs at the given offset of the byte slice. - /// - /// Returns an error if there are too few bytes or the offset is incorrectly aligned. - #[inline] - pub fn read_slice_at<T: Pod>(mut self, offset: usize, count: usize) -> Result<&'data [T], ()> { - self.skip(offset)?; - self.read_slice(count) - } - - /// Read a null terminated string. - /// - /// Does not assume any encoding. - /// Reads past the null byte, but doesn't return it. - #[inline] - pub fn read_string(&mut self) -> Result<&'data [u8], ()> { - match memchr::memchr(b'\0', self.0) { - Some(null) => { - // These will never fail. - let bytes = self.read_bytes(null)?; - self.skip(1)?; - Ok(bytes.0) - } - None => { - self.0 = &[]; - Err(()) - } - } - } - - /// Read a null terminated string at an offset. - /// - /// Does not assume any encoding. Does not return the null byte. - #[inline] - pub fn read_string_at(mut self, offset: usize) -> Result<&'data [u8], ()> { - self.skip(offset)?; - self.read_string() - } - - /// Read an unsigned LEB128 number. - pub fn read_uleb128(&mut self) -> Result<u64, ()> { - let mut result = 0; - let mut shift = 0; - - loop { - let byte = *self.read::<u8>()?; - if shift == 63 && byte != 0x00 && byte != 0x01 { - return Err(()); - } - result |= u64::from(byte & 0x7f) << shift; - shift += 7; - - if byte & 0x80 == 0 { - return Ok(result); - } - } - } - - /// Read a signed LEB128 number. - pub fn read_sleb128(&mut self) -> Result<i64, ()> { - let mut result = 0; - let mut shift = 0; - - loop { - let byte = *self.read::<u8>()?; - if shift == 63 && byte != 0x00 && byte != 0x7f { - return Err(()); - } - result |= i64::from(byte & 0x7f) << shift; - shift += 7; - - if byte & 0x80 == 0 { - if shift < 64 && (byte & 0x40) != 0 { - // Sign extend the result. - result |= !0 << shift; - } - return Ok(result); - } - } - } -} - -// Only for Debug impl of `Bytes`. -fn debug_list_bytes(bytes: &[u8], fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut list = fmt.debug_list(); - list.entries(bytes.iter().take(8).copied().map(DebugByte)); - if bytes.len() > 8 { - list.entry(&DebugLen(bytes.len())); - } - list.finish() -} - -struct DebugByte(u8); - -impl fmt::Debug for DebugByte { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "0x{:02x}", self.0) - } -} - -struct DebugLen(usize); - -impl fmt::Debug for DebugLen { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "...; {}", self.0) - } -} - -/// A newtype for byte strings. -/// -/// For byte slices that are strings of an unknown encoding. -/// -/// Provides a `Debug` implementation that interprets the bytes as UTF-8. -#[derive(Default, Clone, Copy, PartialEq, Eq)] -pub(crate) struct ByteString<'data>(pub &'data [u8]); - -impl<'data> fmt::Debug for ByteString<'data> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "\"{}\"", String::from_utf8_lossy(self.0)) - } -} - -#[allow(dead_code)] -#[inline] -pub(crate) fn align(offset: usize, size: usize) -> usize { - (offset + (size - 1)) & !(size - 1) -} - -#[allow(dead_code)] -pub(crate) fn data_range( - data: &[u8], - data_address: u64, - range_address: u64, - size: u64, -) -> Option<&[u8]> { - let offset = range_address.checked_sub(data_address)?; - data.get(offset.try_into().ok()?..)? - .get(..size.try_into().ok()?) -} - -/// A table of zero-terminated strings. -/// -/// This is used by most file formats for strings such as section names and symbol names. -#[derive(Debug, Clone, Copy)] -pub struct StringTable<'data, R = &'data [u8]> -where - R: ReadRef<'data>, -{ - data: Option<R>, - start: u64, - end: u64, - marker: PhantomData<&'data ()>, -} - -impl<'data, R: ReadRef<'data>> StringTable<'data, R> { - /// Interpret the given data as a string table. - pub fn new(data: R, start: u64, end: u64) -> Self { - StringTable { - data: Some(data), - start, - end, - marker: PhantomData, - } - } - - /// Return the string at the given offset. - pub fn get(&self, offset: u32) -> Result<&'data [u8], ()> { - match self.data { - Some(data) => { - let r_start = self.start.checked_add(offset.into()).ok_or(())?; - data.read_bytes_at_until(r_start..self.end, 0) - } - None => Err(()), - } - } -} - -impl<'data, R: ReadRef<'data>> Default for StringTable<'data, R> { - fn default() -> Self { - StringTable { - data: None, - start: 0, - end: 0, - marker: PhantomData, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::pod::bytes_of; - - #[test] - fn bytes() { - let x = u32::to_be(0x0123_4567); - let data = Bytes(bytes_of(&x)); - - let mut bytes = data; - assert_eq!(bytes.skip(0), Ok(())); - assert_eq!(bytes, data); - - let mut bytes = data; - assert_eq!(bytes.skip(4), Ok(())); - assert_eq!(bytes, Bytes(&[])); - - let mut bytes = data; - assert_eq!(bytes.skip(5), Err(())); - assert_eq!(bytes, Bytes(&[])); - - let mut bytes = data; - assert_eq!(bytes.read_bytes(0), Ok(Bytes(&[]))); - assert_eq!(bytes, data); - - let mut bytes = data; - assert_eq!(bytes.read_bytes(4), Ok(data)); - assert_eq!(bytes, Bytes(&[])); - - let mut bytes = data; - assert_eq!(bytes.read_bytes(5), Err(())); - assert_eq!(bytes, Bytes(&[])); - - assert_eq!(data.read_bytes_at(0, 0), Ok(Bytes(&[]))); - assert_eq!(data.read_bytes_at(4, 0), Ok(Bytes(&[]))); - assert_eq!(data.read_bytes_at(0, 4), Ok(data)); - assert_eq!(data.read_bytes_at(1, 4), Err(())); - - let mut bytes = data; - assert_eq!(bytes.read::<u16>(), Ok(&u16::to_be(0x0123))); - assert_eq!(bytes, Bytes(&[0x45, 0x67])); - assert_eq!(data.read_at::<u16>(2), Ok(&u16::to_be(0x4567))); - assert_eq!(data.read_at::<u16>(3), Err(())); - assert_eq!(data.read_at::<u16>(4), Err(())); - - let mut bytes = data; - assert_eq!(bytes.read::<u32>(), Ok(&x)); - assert_eq!(bytes, Bytes(&[])); - - let mut bytes = data; - assert_eq!(bytes.read::<u64>(), Err(())); - assert_eq!(bytes, Bytes(&[])); - - let mut bytes = data; - assert_eq!(bytes.read_slice::<u8>(0), Ok(&[][..])); - assert_eq!(bytes, data); - - let mut bytes = data; - assert_eq!(bytes.read_slice::<u8>(4), Ok(data.0)); - assert_eq!(bytes, Bytes(&[])); - - let mut bytes = data; - assert_eq!(bytes.read_slice::<u8>(5), Err(())); - assert_eq!(bytes, Bytes(&[])); - - assert_eq!(data.read_slice_at::<u8>(0, 0), Ok(&[][..])); - assert_eq!(data.read_slice_at::<u8>(4, 0), Ok(&[][..])); - assert_eq!(data.read_slice_at::<u8>(0, 4), Ok(data.0)); - assert_eq!(data.read_slice_at::<u8>(1, 4), Err(())); - - let data = Bytes(&[0x01, 0x02, 0x00, 0x04]); - - let mut bytes = data; - assert_eq!(bytes.read_string(), Ok(&data.0[..2])); - assert_eq!(bytes.0, &data.0[3..]); - - let mut bytes = data; - bytes.skip(3).unwrap(); - assert_eq!(bytes.read_string(), Err(())); - assert_eq!(bytes.0, &[]); - - assert_eq!(data.read_string_at(0), Ok(&data.0[..2])); - assert_eq!(data.read_string_at(1), Ok(&data.0[1..2])); - assert_eq!(data.read_string_at(2), Ok(&[][..])); - assert_eq!(data.read_string_at(3), Err(())); - } - - #[test] - fn bytes_debug() { - assert_eq!(format!("{:?}", Bytes(&[])), "[]"); - assert_eq!(format!("{:?}", Bytes(&[0x01])), "[0x01]"); - assert_eq!( - format!( - "{:?}", - Bytes(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]) - ), - "[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]" - ); - assert_eq!( - format!( - "{:?}", - Bytes(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09]) - ), - "[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, ...; 9]" - ); - } -} |