//! A byte reader. use core::ops::Range; /// A reader for reading bytes and PDF objects. #[derive(Clone, Debug)] pub struct Reader<'a> { /// The underlying data of the reader. pub data: &'a [u8], /// The current byte-offset. pub offset: usize, } impl<'a> Reader<'a> { /// Create a new reader. #[inline] pub fn new(data: &'a [u8]) -> Self { Self { data, offset: 0 } } /// Create a new reader at the given offset. #[inline] pub fn new_with(data: &'a [u8], offset: usize) -> Self { Self { data, offset } } /// Returns `true` if the reader has reached the end of the data. #[inline] pub fn at_end(&self) -> bool { self.offset >= self.data.len() } /// Moves the reader offset to the end of the data. #[inline] pub fn jump_to_end(&mut self) { self.offset = self.data.len(); } /// Moves the reader to the specified offset. #[inline] pub fn jump(&mut self, offset: usize) { self.offset = offset; } /// Returns the remaining data from the current offset to the end. #[inline] pub fn tail(&mut self) -> Option<&'a [u8]> { self.data.get(self.offset..) } /// Returns the total length of the underlying data. #[inline] pub fn len(&self) -> usize { self.data.len() } /// Returns `true` if the underlying data is empty. #[inline] pub fn is_empty(&self) -> bool { self.data.is_empty() } /// Returns a slice of the data for the specified range. #[inline] pub fn range(&self, range: Range) -> Option<&'a [u8]> { self.data.get(range) } /// Returns the current offset of the reader. #[inline] pub fn offset(&self) -> usize { self.offset } /// Reads the specified number of bytes and advances the offset. #[inline] pub fn read_bytes(&mut self, len: usize) -> Option<&'a [u8]> { let v = self.peek_bytes(len)?; self.offset += len; Some(v) } /// Reads a single byte and advances the offset. #[inline] pub fn read_byte(&mut self) -> Option { let v = self.peek_byte()?; self.offset += 1; Some(v) } /// Skips the specified number of bytes by advancing the offset. #[inline] pub fn skip_bytes(&mut self, len: usize) -> Option<()> { self.read_bytes(len).map(|_| {}) } /// Peeks the specified number of bytes. #[inline] pub fn peek_bytes(&self, len: usize) -> Option<&'a [u8]> { self.offset .checked_add(len) .and_then(|end| self.data.get(self.offset..end)) } /// Peeks a single byte. #[inline] pub fn peek_byte(&self) -> Option { self.data.get(self.offset).copied() } /// Eat the next byte if it satisfies the condition. #[inline] pub fn eat(&mut self, f: impl Fn(u8) -> bool) -> Option { let val = self.peek_byte()?; if f(val) { self.forward(); Some(val) } else { None } } /// Advances the offset by one byte. #[inline] pub fn forward(&mut self) { self.offset += 1; } /// Advances the offset by one byte if the current byte satisfies the predicate. #[inline] pub fn forward_if(&mut self, f: impl Fn(u8) -> bool) -> Option<()> { if f(self.peek_byte()?) { self.forward(); Some(()) } else { None } } /// Advances the offset while bytes satisfy the predicate, at least one time. #[inline] pub fn forward_while_1(&mut self, f: impl Fn(u8) -> bool) -> Option<()> { self.eat(&f)?; self.forward_while(f); Some(()) } /// Advances the offset if the next bytes match the specified tag. #[inline] pub fn forward_tag(&mut self, tag: &[u8]) -> Option<()> { self.peek_tag(tag)?; self.offset += tag.len(); Some(()) } /// Advances the offset while the given byte satisfies the predicate. #[inline] pub fn forward_while(&mut self, f: impl Fn(u8) -> bool) { while let Some(b) = self.peek_byte() { if f(b) { self.forward(); } else { break; } } } /// Checks if the next bytes match the specified tag. #[inline] pub fn peek_tag(&self, tag: &[u8]) -> Option<()> { let mut cloned = self.clone(); for b in tag.iter().copied() { if cloned.peek_byte() == Some(b) { cloned.forward(); } else { return None; } } Some(()) } /// Read a u16 integer (in big endian order). #[inline] pub fn read_u16(&mut self) -> Option { let bytes = self.read_bytes(2)?; Some(u16::from_be_bytes([bytes[0], bytes[1]])) } /// Read a u32 integer (in big endian order). #[inline] pub fn read_u32(&mut self) -> Option { let bytes = self.read_bytes(4)?; Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])) } /// Read a u64 integer (in big endian order). #[inline] pub fn read_u64(&mut self) -> Option { let bytes = self.read_bytes(8)?; Some(u64::from_be_bytes([ bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], ])) } } #[cfg(test)] mod tests { use super::Reader; #[test] fn peek_bytes_rejects_overflowing_len() { let reader = Reader::new(b"abc"); assert!(reader.peek_bytes(usize::MAX).is_none()); } }