Skip to content

fix: parser, project and worker items from #34 - #54

Open
Jozkah wants to merge 10 commits into
CNCKitchen:mainfrom
Jozkah:review/parsers-core
Open

Jozkah wants to merge 10 commits into
CNCKitchen:mainfrom
Jozkah:review/parsers-core

Conversation

@Jozkah

@Jozkah Jozkah commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

The parser, project and worker items from #34, rebased on 0.9.3, one commit per item, each with a regression test that fails without it:

  • fix: refuse PLY properties of an unknown type
  • fix: validate PLY header counts against the file before reading
  • feat: read per-vertex colours from PLY and OBJ
  • fix: give clean 3MF errors for out-of-range entities and Object member names
  • perf: mark PrusaSlicer modifier runs once instead of per triangle
  • fix: count stored project members by their real size against the limits
  • fix: hold project settings to their ranges and enums when opening
  • fix: stop a fit that is still queued when Stop is pressed
  • fix: drop errors from superseded edge detection requests

Left out, as you asked: decodeText. I also left out the STL fallback that tried a binary read when the ASCII read found no triangles. With Chrome returning an empty string above 512 MiB, it would read a huge ASCII STL as binary and open garbage.

Notes:

  • PLY header counts are checked against the file before anything is allocated, so a 188-byte header asking for 10^8 faces is refused at once instead of spinning.
  • Project values are checked against their ranges and enums when the file is opened, e.g. thickness coneRays 0 to 256 and bands 2 to 256, so a crafted project can't hang the thickness worker.
  • Stored zip members count by the larger of their two sizes, and compression methods other than 0 and 8 are refused.

Build: npm run build passes. npm test (3127), npm --prefix mcp test (127), the plugin boundary and units checks, and npm run e2e:ci all pass.

A property type missing from the size table made strides and offsets NaN, which DataView reads as offset 0, so a file with an int64 property turned into garbage geometry. Header types are now checked against the table, and list counts must be integer types.
Element counts were parsed without checks, so a crafted header could make the worker loop for seconds over an element with no properties, step backwards on a negative list length, run past the end of an ASCII body, or allocate arrays sized by a count no file backs up. Counts must now be non-negative safe integers, each element must fit in what is left of the file before anything is allocated, list lengths must be non-negative, and running out of data is an error.
PLY red/green/blue properties and the OBJ v x y z r g b extension were dropped, so colour scans in the two most common formats showed grey. Both are now read into the mesh colours, floats as 0 to 1 and integers as bytes, and as for 3MF a single colour on every vertex is left off as an exporter default.
…r names

A numeric entity past U+10FFFF made String.fromCodePoint throw a bare RangeError, and package lookups on a plain object resolved names such as constructor or toString to Object members. Out-of-range entities now read as the replacement character, and the package's parts are kept in an object without a prototype.
Each triangle was checked against every modifier run, so a slicer project with many runs took time in proportion to triangles times runs. The runs are now marked into a per-triangle flag array once, clamped to the triangle count, and each triangle reads its flag.
The archive limits summed each member's declared uncompressed size, but a stored member yields its compressed bytes whatever it declares, so a member declaring 0 skipped both limits. The larger of the compressed and declared sizes now counts, methods other than stored and deflate are refused, and the unpacked sizes are checked again after decompression.
Project validation only checked that numbers were finite, so a crafted project could set a billion thickness rays that are measured again on open, a zero deviation range, an unknown thickness method or malformed alignment pairs. The thickness, deviation and flat settings are now checked for integer-ness, sign, bounds and allowed values, and pairs must hold two 3-vectors.
The abort only set a flag, and a fit waiting in the worker queue behind a held request cleared that flag when it started, so it ran to the end and applied. An abort now also takes any queued fit out of the queue and answers it as stopped.
WorkerRpc rejects error answers, so the edge client's check for an error answer never ran and a superseded request's failure surfaced as an error while a newer detection was running. A rejection now resolves to null unless it belongs to the latest request.
The OBJ and PLY readers now read a word or a line at a time. The PLY header
checks, list-length checks and vertex colours are carried over onto them;
the ASCII room check is bounded by the body's size, as there is no token
array to count, and running out of words names the element being read.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant