Files
aiongg 2eca9b3a53 pdf: vendor hayro-postscript and skip << and >> runs without recursion (#263)
hayro-postscript 0.1.0 is the token scanner hayro-cmap uses for the
CMap streams PDFs embed. Its object reader skipped each `<<` or `>>`
by calling itself again, so a stream holding a long run of `<` or `>`
bytes recursed once per pair and aborted the process with a stack
overflow.

Vendor the crates.io package unchanged and patch `object::read` to
skip those runs in a loop, returning the same next object as before.
Wire it in like the other Hayro crates: workspace exclude,
[patch.crates-io] entry, SOURCE.json with registry and local hashes,
the backend test script, NOTICE, ATTRIBUTION.md and the reader README.

Tests cover a million `<` and a million `>` bytes, `<< /A 1 >>` and
nested `<<<< /X >>>>` runs.
2026-10-23 23:31:35 -04:00

75 lines
2.0 KiB
Rust

//! A small example that shows how to tokenize a PostScript program.
#![allow(missing_docs)]
use hayro_postscript::{Number, Object, Scanner};
use std::env;
use std::fs;
use std::process;
fn main() {
let path = match env::args().nth(1) {
Some(p) => p,
None => {
eprintln!("Usage: tokenize <file>");
process::exit(1);
}
};
let data = match fs::read(&path) {
Ok(d) => d,
Err(e) => {
eprintln!("Error reading {path}: {e}");
process::exit(1);
}
};
let mut scanner = Scanner::new(&data);
while !scanner.at_end() {
match scanner.parse_object() {
Ok(object) => {
print_object(&object);
println!();
}
Err(e) => eprintln!("Error: {e}"),
}
}
}
fn print_object(object: &Object<'_>) {
match object {
Object::Number(Number::Integer(n)) => print!("Integer({n})"),
Object::Number(Number::Real(n)) => print!("Real({n})"),
Object::Name(name) => {
let kind = if name.is_literal() {
"literal"
} else {
"executable"
};
let text = name.as_str().unwrap_or("<non-ascii name>");
print!("Name({text}, {kind})");
}
Object::String(s) => {
let decoded = s.decode().unwrap_or_else(|_| Vec::new());
print!("String({})", String::from_utf8_lossy(&decoded));
}
Object::Array(arr) => {
print!("[");
let mut inner = arr.objects();
let mut first = true;
while !inner.at_end() {
if !first {
print!(" ");
}
first = false;
match inner.parse_object() {
Ok(obj) => print_object(&obj),
Err(e) => print!("Error({e})"),
}
}
print!("]");
}
}
}