mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-31 05:28:09 -06:00
hayro-cmap reads CMap streams with hayro-postscript's token scanner, whose object::read skipped each `<<` and `>>` by calling itself again. A CMap holding a long run of `<` or `>` used one stack frame per pair, overflowed the stack and aborted the process. Vendor hayro-postscript 0.1.0 with read() looping over the delimiters instead (from storytold/craft-libs#263), patched in beside hayro-cmap. Four object::tests cover long `<<` and `>>` runs and the skipped delimiters, plain and nested.
137 lines
2.9 KiB
Rust
137 lines
2.9 KiB
Rust
use core::ops::Range;
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub(crate) struct Reader<'a> {
|
|
pub(crate) data: &'a [u8],
|
|
pub(crate) offset: usize,
|
|
}
|
|
|
|
impl<'a> Reader<'a> {
|
|
#[inline]
|
|
pub(crate) fn new(data: &'a [u8]) -> Self {
|
|
Self { data, offset: 0 }
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn jump(&mut self, offset: usize) {
|
|
self.offset = offset;
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn range(&self, range: Range<usize>) -> Option<&'a [u8]> {
|
|
self.data.get(range)
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn offset(&self) -> usize {
|
|
self.offset
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn read_bytes(&mut self, len: usize) -> Option<&'a [u8]> {
|
|
let v = self.peek_bytes(len)?;
|
|
self.offset += len;
|
|
Some(v)
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn read_byte(&mut self) -> Option<u8> {
|
|
let v = self.peek_byte()?;
|
|
self.offset += 1;
|
|
Some(v)
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn peek_bytes(&self, len: usize) -> Option<&'a [u8]> {
|
|
self.data.get(self.offset..self.offset + len)
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn peek_byte(&self) -> Option<u8> {
|
|
self.data.get(self.offset).copied()
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn eat(&mut self, f: impl Fn(u8) -> bool) -> Option<u8> {
|
|
let val = self.peek_byte()?;
|
|
if f(val) {
|
|
self.forward();
|
|
Some(val)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn forward(&mut self) {
|
|
self.offset += 1;
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn forward_while(&mut self, f: impl Fn(u8) -> bool) {
|
|
while let Some(b) = self.peek_byte() {
|
|
if f(b) {
|
|
self.forward();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn forward_tag(&mut self, tag: &[u8]) -> Option<()> {
|
|
self.peek_tag(tag)?;
|
|
self.offset += tag.len();
|
|
Some(())
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) 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(())
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) fn skip_eol(&mut self) {
|
|
while let Some(b) = self.peek_byte() {
|
|
if is_eol(b) {
|
|
self.forward();
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn is_whitespace(b: u8) -> bool {
|
|
matches!(b, 0x00 | 0x09 | 0x0a | 0x0c | 0x0d | 0x20)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn is_delimiter(b: u8) -> bool {
|
|
matches!(
|
|
b,
|
|
b'(' | b')' | b'<' | b'>' | b'[' | b']' | b'{' | b'}' | b'/' | b'%'
|
|
)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn is_regular(b: u8) -> bool {
|
|
!is_whitespace(b) && !is_delimiter(b)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn is_eol(b: u8) -> bool {
|
|
matches!(b, 0x0a | 0x0d)
|
|
}
|