A non-Unicode document path holding '..' (/a/../\xff/d.doc) was refused,
because the native join kept the '..' while the lexical result folded it.
join_native now folds the folder's components as normalize does, so such a
document resolves as a Unicode one would, and a '..' that leaves a Unix name
holding a backslash is still caught by the comparison.
- A VectorCraft or PhotoCraft `generator`, and a VectorCraft `preview` or
`pdf`, are read as they are parsed. A value of the wrong shape is
skipped element by element with `IgnoredAny` and none of it is kept;
before, serde's untagged enum buffered the whole value first, with no
limit on that buffer. The preview and PDF still read as `File::read`
reads them, the array form of `Image` included.
- A rendition after the JSON of a gzip file is counted against
`max_total` once, as it is decompressed. A 40 KiB PDF with `max_total`
at 64 KiB now reads compressed as it does uncompressed. A preview and
PDF that name the same bytes are counted as two copies.
- A repeated VectorCraft `version` is malformed, not too new, and
`renditions` refuses a missing or repeated `document`, as `File::read`
does.
- The README says that a VectorCraft file written as a JSON array is not
recognized by `sniff`.
std::path sees no \??\ or \\.\ prefix and no //server/share boundary on Unix,
so the native root check let those document roots through. Resolve the link
against the lossy document path with the Unicode rules, and return the native
join only when it names the same components.
An <include> naming a folder listed, collected and sorted the folder's
entries before any budget applied, and again for every repetition, so a
configuration repeating one include made a single discovery call walk
the same folder thousands of times. Include folders are now checked
against the depth and file budgets first, listed at most once (by
canonical path), and all listings share a cap on entries.
A relative link next to a document whose path is not Unicode was joined
to the document's folder natively, skipping the parsing that refuses
device and object-manager namespaces. On Windows a document path with an
unpaired surrogate under \\.\, \\?\GLOBALROOT or \??\ therefore let
the link resolve inside that namespace. The native join now refuses those
roots as resolve does for a Unicode path; drives and shares are kept.
Inverting a sampled curve scanned the whole table for its flat start and
end runs whenever the value fell at or beyond an end. A constant table
falls there for every input, so each pixel the exact pipeline evaluated
read the whole curve again. inverse64_many already cached the ends for
output tables; a Pipeline now caches them for every inverse-curve stage,
recomputed on extend and optimize.
Indexed, Separation, DeviceN, Pattern and an ICCBased /Alternate each build
their base space with a recursive ColorSpace::new call, and each level can be
a fresh indirect object. A long chain of indirect /Indexed arrays therefore
recursed once per object and could exhaust the stack.
The depth is now passed down through every child construction and a space
nested 8 or more levels deep is refused (the deepest legitimate nesting,
Pattern over Indexed over ICCBased with an /Alternate, is four).
An xref-stream entry can be a single decoded byte, so one xref stream at the
256 MiB decode limit could expand into hundreds of millions of map entries
(several gigabytes) while the document was opened. Every insert into the xref
map now goes through insert_entry, which refuses a new object past 8,388,607
entries (the PDF 32000-1 Annex C limit on indirect objects). This covers
xref tables, xref streams, merges of Prev/XRefStm sections and the repair
scan. Replacing an object already in the map is still allowed.
The JBIG2 filter ignored the limit every other filter gets, so a stream
decoded with decoded_within (an output intent's 16 MiB ICC profile in
craft-prepress) could still build a page up to 2^28 one-byte pixels. The
page header's size is now checked against the limit before any output is
allocated: the returned bytes when the stream has no image dimensions,
the 1-bit packed size for an image of known size.
The Ghostscript work directory had a predictable name under the shared
temporary directory, and a failed removal of an existing one was ignored.
Another local user could create it first with an in.pdf symlink, and
writing the input would follow it. The directory is now created with
tempfile (random name, owner-only permissions, fails if it exists), and
in.pdf is created with create_new.
A cmap can list 65535 encoding records that all name the same subtable,
and Cmap::ranges expanded that subtable's spans once per record before
merging them. Records naming a subtable already read are now skipped,
and at most 16 distinct Unicode subtables are read from one face.
A manifest file or licence_file that is absolute, climbs out with .., or
resolves through a symlink to a file outside the checkout is now an
Error::OutsideCheckout instead of being embedded with include_bytes! or
copied (and written) outside the directory given to Embed::serve.