* fix(io): make four DXF/SVG passes linear in their input
Preserving foreign objects looked each root-owned object's key up by scanning the root dictionary; applying annotation scales searched every layout for each handle model space lacked; writing CLASS instance counts inserted each missing group into the middle of the tag list; and SVG attribute lookup resumed after a malformed attribute, re-running the parser's duplicate scan each time. Each is now one indexed or single pass with the same results.
* address review: first layout wins for duplicate handles; move tags instead of cloning in class count pass
* address review: reserve room for the added class counts, correct the peak-memory note
* fix(lisp): charge READ text, EQUAL string bytes, SETVAR and ENTMAKE copies, and nested callbacks against one budget
* address review: charge callback steps live and reject completion past the shared allowance
* fix: bound MOCORO copies, array EXPLODE, COMPARE bounds, attribute extraction, PDF links and control-server parsing
* address review: key extract cache by exact block, count live MOCORO objects, PDF link budget
* review: select extraction columns before copying values, count live objects for MOCORO copies
* address review: count exploded array objects before cloning; scan each block's constants once
The bridge picked the token by port alone and sent it to whatever the address resolved to, so a listener another account opened on ::1 with the same port received the desktop's credential. The token is now attached only when the connected peer is exactly 127.0.0.1:PORT, where the app listens. Reading the token refuses a symlink, a non-plain file and a file others can read, and the shared temporary directory is no longer a fallback location for it.
* fix: index or bound array replacements, DIM field spellings, path samples, hatch refills and broken tables
* address review: index placeable array replacements, search past zero-length DIVIDE runs, per-part broken-table outlines
* fix: bound region grid registrations, island containment tests, snap_ends visits, inference duplicate searches and font name decoding
* address review: charge empty curves only in snap_ends search
* fix(geom): report a spent containment budget instead of partial islands
* address review: count pending point candidates in the perpendicular cap
A path naming an endless device or a FIFO was buffered to EOF before any size check ran, so one short command could exhaust memory or block. These paths now go through capped_read::read_capped, which refuses non-regular files and enforces the byte limit while reading.
lisp_flush drained each line from the front of the output buffer, shifting everything after it every time, so newline-dense PRINC output cost quadratic time outside the interpreter's step budget. It now walks the buffer once and drops the printed prefix once.
* fix(geom): bound the points one polyline tessellation samples
Polyline::tessellate sampled every arc segment (up to 4096 points each) with no total limit, and hatch boundary preparation did this for every loop, so compact curved vertices expanded into gigabytes. tessellate_within takes a point budget; once spent, remaining arcs are drawn as chords. Hatch loops share one budget.
* address review: correct tessellate_within doc
* fix: index or bound four small lookups (DOF selection, xref palette, QSELECT colours, log lines)
DOF scanned the selection list per slot; the xref palette scanned the xref list per INSERT; QSELECT parsed a possibly long layer name as a colour for every entity; and a log message could carry CR/LF or other control characters that started apparent extra records. Each now uses a set or map, a length bound, or escaping, with the same results for ordinary input.
* address review: trim colour text before length limit
On macOS the Open and Save panels ran modally inside winit's event handler, and resizing one aborted the app (#1527). Every file dialog now goes through CadApp::pick_then / pick_then_open. On macOS, Services::start_pick shows the dialog as a sheet on the window and the answer is acted on in a later frame. The answer is bound to the drawing that asked for it. Windows and Linux are unchanged.
Fixes#1527
Co-authored-by: mocenigo <4894657+mocenigo@users.noreply.github.com>
strips_formatting expected `\U+12` to strip to nothing. plain_mtext
dropped every unknown code up to the next `;` when that assertion was
written. #1036 limits this to the codes in takes_arg, and `\U` is not
one of them, so plain_mtext returns `+12`. The layout and paragraph
paths give the same text, and
unicode_escapes_are_decoded_in_every_parser already expects it.
The test has failed on main since both changes merged, and the failure
stops the gate at its test step. The test module now also checks the
short escape in both layout paths.
craft-update moves from craft-libs c5a1cbfb to c7c84230, a branch that is
craft-libs main at 0a9d1f48 with storytold/craft-libs#687 and #696 merged
in. Cargo.lock changes the craft-update entry and drops zopfli from zip.
The check result window now shows whenever the updater's status is not
idle, not only after Help > Check for Updates, and never over the startup
prompt. At the first start after an update it reports that the update
installed or why it failed. Restart to Update calls
Updater::restart_to_update. The install helper starts when the app exits
and drops the updater, so a canceled close keeps the update ready.
Main now has its own proxy class handling for DWG saves (`proxy_classes`, from bf137e2c,
31935157 and 946af874) and the application object conversion of #2917. This branch is
brought onto that:
- Cargo.lock, crates/dwg/Cargo.toml and xtask/src/layers.rs are main's. `dwg` no longer
depends on `dxf`: the source classes are read from the bridge's ASCII DXF by a bounded
scan in `proxy_transport::source_classes`, as main's `dxf_class_names` reads their names.
- Saving as DWG 2013 or later restores the source classes in their places (duplicate
names and metadata kept) when every CLASS record can be written back. Otherwise (before
2013, a binary DXF, a malformed or unused bad CLASS) main's `proxy_classes` runs: proxies
are matched by name or left out and counted as unwritten. Nothing returns an error any
more, so a drawing with proxies saves in its own pre-2013 version, without them, as the
save report says. A proxy whose number names no source class is left out and counted.
- The loss report is main's `not_saved_as` (`Foreign::proxy_class`);
`preserves_proxy_entity` and this branch's report test are gone.
- On DWG read, `prepare` runs after `application_objects`, so the proxy objects that makes
are numbered as the DXF numbers them. It uses main's `proxy_dwg_version`. A registered
entity with decoded properties and opaque data now stays as read, as on main, and a read
note names it, instead of being dropped.
Tests: `cargo test -p cadcraft-dwg` 37 passed, `-p cadcraft-io` all passed (25 ignored),
`-p cadcraft-doc`, `-p cadcraft-engine --test save_reports_not_saved` and `--test it`
passed; clippy `-p cadcraft-dwg -p cadcraft-io -p cadcraft-doc -p cadcraft-engine
--all-targets -D warnings`, fmt, `cargo xtask layers` and the wasm32 check of cadcraft-io
pass. `registered_proxy` now checks that a pre-2013 DWG save leaves the proxy out and
keeps the rest; main's proxy tests in crates/io/src/tests.rs pass unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H43qQA41CJLauqXnPgBQ7r
hard_owners took the first object naming a null-owner object in a 360 as its owner, kept or not.
When an object that is left out named it first, the reader dropped the object, though a kept one
held it too, and the save wrote the kept holder's 360 as 0.
hard_owners now lists every object naming it, in file order, and owner_of takes the first of
them that is kept, else the first. The read (retained_objects) and the write liveness pass in
finish run until what they keep settles; a file where no object has two hard owners takes one
pass, as before. The write pass no longer keeps a converted copy of every object's groups.
The test adds an object nothing keeps that names the held record before its holder does: the
held record stays with the holder and the stray object is dropped, DXF and DWG, twice. It fails
before this change ("DXF 1: no record held").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H43qQA41CJLauqXnPgBQ7r
About > Contributors still showed an old snapshot, because nothing
regenerated contributors/contributors.json before a release. Opt in to
the shared refresh from craft-common-actions: a read-only credits job
regenerates the snapshot for the release commit, and the shared release
workflow installs it before every source build. The snapshot is not
committed back.
An object whose owner (group 330) is null but which another kept object
holds by a hard owner reference (group 360), as one application's proxy
object held by another, broke the owner chain the reader and writer follow
to decide what to keep: it was dropped, and the holder kept a reference to
nothing. Such an object's owner is now the object that hard-owns it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H43qQA41CJLauqXnPgBQ7r
An object of another application's class that acadrust has no model for is
read only as its DWG record (ObjectType::Unknown), which its DXF writer
leaves out. The DWG to DXF bridge lost every such object with no note, and
the references to it went too (an extension dictionary entry naming the
object, say).
Each one is now carried as a proxy object of its class (ACAD_PROXY_OBJECT):
the record is split into its common object data (owner, reactors, extension
dictionary) and the streams after it (data bits, R2007+ strings, object
references), as the Open Design Specification for .dwg describes them. The
references are read to the end of the handle stream (to its exact length
from R2010 on), null ones too: a null reference is an empty field, and the
references after it belong to the next fields. Objects of the drawing
database's own classes, and records that don't split, stay as they were and
are named in a note.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H43qQA41CJLauqXnPgBQ7r