Files
pdfcraft/vendor/hayro-postscript/examples/tokenize.rs
T
aiongg fc1372a64c fix(render): vendor hayro-postscript so a run of << in a CMap can't overflow the stack (#4363)
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.
2026-10-24 09:38:10 -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!("]");
}
}
}