* 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).
hayro-interpret
A crate for interpreting PDF files.
This crate provides an abstraction to interpret the content of a PDF file and render them
into an abstract [Device], which clients can implement as needed. This allows you, for
example, to render PDF files to bitmaps (which is what the hayro crate does), or other formats
such as SVG.
It should be noted that this crate is still very much in development. Therefore it currently lacks pretty much any documentation on how to use it. It's current API also only really makes it useful for rendering to PNG or SVG, though this will be improved upon in the future.
Examples
See the examples folder on the GitHub repository. Apart from that, you can also consult
the implementation of hayro and hayro-svg to get an idea on how to use this crate.
Safety
This crate forbids unsafe code via a crate-level attribute.
Cargo features
This crate has one optional feature:
embed-fonts: PDF processors are required to support 14 predefined fonts that do not need to be embedded into a PDF file. If you enable this feature, hayro will embed a (permissively-licensed) substitute for each font, so that you don't have to implement your custom font loading logic. This will add around ~240KB to your binary.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
PdfCraft function limits
The PdfCraft patch rejects function construction after 64 nested functions or 10,000 total
function nodes, including repeated references, and detects cycles on the current path. Shared
children in different branches remain valid. Stitching functions reject empty or unresolved
child lists instead of silently truncating them. Calculator functions have a shared limit of 64
procedure levels and 10,000 parsed tokens (operators and procedure openings); evaluation has
its own 10,000-operator limit across selected branches. These are implementation resource
limits rather than PDF format limits. Rejection returns the existing None, and the optional
logging feature reports the reason and limit; no new interface warning is introduced.
Calculator integer division without an integer result is also rejected. Bit shifting discards bits beyond the 32-bit word and fills with zeroes, including logical right shifts of negative words; rotation accepts the full signed shift range without negating the minimum integer. Fixed-size operand and procedure-stack overflow errors propagate instead of truncating work. Normal function signatures and supported color/transfer-function behavior remain unchanged.