A number read stops at the first byte that can't be part of a number,
which may be inside the token: `parse_object_or_skip` then read the rest
(`beginbfchar` in `1beginbfchar`) as a token of its own, and the pairs
after it became mappings. The rest of the token is now skipped with the
failed number, one failure per token, as PostScript reads a run of
regular characters as one token.
The render test's run of unreadable tokens before the mappings is spaced:
a run of `-` with nothing between them is one token now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
- `Scanner::parse_object_or_skip` skips whitespace and comments before
taking its start offset, so a token after a space fails once, not
twice, whoever calls it. (The CMap scan already skipped whitespace in
`at_end`, so CMap results do not change.)
- Unit tests in hayro-postscript (stepping over a token, a failed read
not read again, never past the end of the data) and in hayro-cmap
(bfchar and bfrange after a stray `>` or a spaced name, the 1,024-token
limit at its boundary, a CMap of unreadable tokens only failing).
- The render test checks a bfrange entry after the bad token, a run past
the limit before the mappings, and a CMap of unreadable tokens only;
its wall-clock assertion is gone, the no-re-read property is the
deterministic hayro-postscript test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
parse_object_or_skip reads on from where a failed read stopped, stepping
one byte only when the read made no progress, so unclosed strings, each
reading to the end of the data, cost one pass over it instead of one each.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
The CMap scan stopped at the first token the scanner couldn't read, so a
stray `>` after a CMap name, or a CMap name with spaces in it, ended it
before any bfchar entry: such fonts had no text to copy or find. The
scanner steps one byte past an unreadable token (hayro-postscript patch 2)
and the scan goes on, at most 1,024 times per CMap.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
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.