Illustrator 6/8 EPS files whose PostScript can't be run (the Adobe_level2_AI5
procset is provided by the RIP, not embedded) are read through their private
layer data instead. That reader aborted the whole file when a text object
carried the hyphenation/tab-ruler operators `Th` (hyphen control), `XL`
(hyphenation language) and `Xb`/`XB` (a tab definition, with `Xe` descriptions
between them), reporting them as operators it doesn't know.
These carry no geometry, so drop them like the sibling type attributes the
reader already discards (§22 of the Illustrator File Format Specification)
rather than failing the import.
A .ai in PostScript form went only to the PostScript interpreter, which
stopped on the first operator its missing prolog would define
(`Adobe_packedarray`, `Lb`, `Np`): files from Rhino and other CAD apps name
the procsets without including them.
- Such a program is its own editing data: when it has layers
(`%AI5_BeginLayer`) and no private data, the editing-data reader reads it,
compared with the page when the program runs, from the layers alone when
it can't be run. If the layers can't be read either, the error says why.
- The reader takes the legacy ten-operand `Lb`, ignores flatness `i`, and
uses the bounding box as the page when nothing else says where it is.
- Tests on synthetic files; fuzz fixture and hostile-program layers added.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
# ROADMAP.md
# docs/file-format-parity.md
# docs/gaps.md
Two EPS import tests become programs written from the PostScript Language
Reference (3rd ed.), with their own names and structure, covering the
interpreter features the importer relies on:
- `level_2_and_3_probes_read_as_vectors`: a resource category made from
Generic, resources defined and found in it (§3.9), local and global VM
(`currentglobal`, `setglobal`, `gcheck`, §3.7.2), `internaldict` probed
through `stopped`, a halftone dictionary set and restored, `cachestatus`,
`rootfont` and `currentcolorrendering`, drawing with its own procedures.
- `executable_strings_and_integer_keys`: shading dictionaries closed by an
executable string (`(>>) cvx`, or a Level 1 builder with `counttomark`),
procedures kept under integer keys run with `load` through `stopped`,
`cvx`/`cvlit`/`xcheck` on strings.
Each was mutation-checked: making any of findresource, defineresource,
currentglobal, setglobal, gcheck, internaldict, sethalftone,
currenthalftone, currentcolorrendering, cachestatus, rootfont, stopped,
cvx, load, counttomark, cvlit or xcheck unknown fails a test, and so do
strings that `cvx` leaves literal, `load` refusing integer keys and
`gcheck` answering true.
The ROADMAP's EPS paragraph, file-formats row and last-updated line state
the PostScript features the reader supports; the legacy `.ai` comments in
the import module and the interpreter cite that format's published
specification (PRONOM fmt/423) for the `%AI` header comments and `u`/`U`
group operators the reader keys on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Legacy PostScript .ai files (Illustrator 3-8, and their EPS) open through
the EPS interpreter, which only recorded what was drawn: every group came
in flattened. In a file in Illustrator's format (its %AI comments, or
Illustrator named as the creator) the `u` ... `U` it writes at the top
level now open and close groups, whatever its prolog defines them as, so
groups come in nested as they were, between and inside clipping groups.
clipnest's Clip carries an optional region: without one it is a plain
group, nested in the same chain as the clips (ids given in opening order,
so a chain of clips and groups sorts by id).
Clips nested without end used to nest clipping groups past the stack
(a stack overflow in EPS and EMF/WMF import): clips and groups now nest
at most 128 deep with a warning, and each object's chain counts against
the EPS reader's drawing budget.
PDF-compatible .ai (Illustrator 9+) can't get the same: its PDF content
draws each object on its own and doesn't mark plain groups (only layers,
clipping groups and groups with opacity, blending or a mask, which
already come back); the groups live only in the private data, which is
out of scope. Documented in ROADMAP and docs/mcp.md.
Addresses Discord feedback.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>