* fix(render): bound xref streams, JBIG2 referred-to counts, saved graphics states and /W2 runs
Input bounds and crash fixes in the vendored hayro crates, ported from
the snapshot craft-libs carries (storytold/craft-libs#176, #239, #241):
- hayro-syntax: an xref stream subsection must be backed by its decoded
data. All-zero /W widths and a count longer than the data are refused
before any entry is inserted; a tiny stream with a large /Size or
/Index count inserted that many entries.
- hayro-syntax: a subsection running past object number u32::MAX is
refused; start + i overflowed.
- hayro-syntax: the xref stream type field is read big-endian at its
full /W[0] width, and /W[0] over 8 bytes is refused like /W[1].
- hayro-jbig2: the long-form referred-to segment count is capped at
u16::MAX before its retention bytes are read; the 29-bit count went
straight to Vec::with_capacity (about 2 GiB) and aborted the process.
- hayro-interpret: at most 4096 saved graphics states holding at most
64 MiB together. A q past either limit is counted but not copied, and
its Q still removes the clips added since.
- hayro-interpret: a /W2 run whose first CID is past MAX_CID stops there,
as /W does; a first CID of 4294967295 discarded the whole /W2 table.
Each patch is marked in the source, has a regression test in its crate,
and is listed in vendor/README.md.
* fix(render): a binary usecmap counts against the CMap nesting limit; /W2 checks the CID first
- hayro-cmap: a binary CMap's usecmap passed its own depth to the nested
parse, so a self-referencing binary CMap recursed until the stack
overflowed. It now counts like a text usecmap (ledger hayro-cmap 2).
- hayro-interpret: the /W2 first-CID check runs before the run's metrics
are read, so an incomplete run past MAX_CID no longer discards the rest
of the table (ledger 52).
* fix(render): refuse xref-stream object numbers past i32::MAX
ObjectIdentifier stores an i32; a number between i32::MAX and u32::MAX
was cast to a negative object number (ledger hayro-syntax 26).
A begin… block cut off at the end of the stream returned None through ? and discarded the whole map; it now ends the scan like any other unparseable tail. Test: stream_cut_off_inside_a_block_keeps_the_entries_before_it.
Character-collection metadata is not a mapping: a truncated stream that
parsed only /Registry //Ordering //Supplement produced an empty CMap,
which callers accept and which then blocks the encoding fallback paths.
Drop the metadata exemption so a truncated stream with no mappings
returns no CMap, exactly as a full parse failure did before.
Signed-off-by: Charan Rathore <180254320+charan-rathore@users.noreply.github.com>
- The truncated-stream guard was dead: completed was set on the break
path too. Detect truncation from the scanner position so a stream
that yields nothing still reports failure and callers fall back to
the font encoding.
- A skipped bfchar/bfrange entry consumed a different number of
objects than a parsed one, shifting every later pair onto the wrong
code. Skip the entry's remaining objects as well.
- A bfrange array that runs out or breaks cannot be resynced to a
member boundary; stop the loop instead of spinning over the rest of
the range.
Signed-off-by: Charan Rathore <180254320+charan-rathore@users.noreply.github.com>
A /ToUnicode CMap with any unparsable part made the reading path
discard the whole map and fall back to the font encoding, so search
and redaction missed text the edit layer could read. Vendor
hayro-cmap 0.1.0 and patch it to skip malformed bfchar/bfrange
entries, unresolvable usecmap references and unparseable tails,
keeping every readable entry, matching MuPDF/pdftotext and
PdfCraft's own edit-layer parser.
Fixes#3177.
Signed-off-by: Charan Rathore <180254320+charan-rathore@users.noreply.github.com>