From 78242d67d1d35924ccba36142e2baf5625cafb80 Mon Sep 17 00:00:00 2001 From: Jackson Oursland Date: Thu, 15 Oct 2026 16:30:03 -0700 Subject: [PATCH] Import FreeCAD and Rhino files through cadmpeg (#1435) FreeCAD .FCStd and Rhino .3dm files open, insert and drop like STEP and IGES: cadmpeg (Apache-2.0, pinned =0.6.1, native builds only) detects the format, decodes it under its service resource caps, validates the model and writes it as STEP AP214, which becomes an Import feature in a new component named after the file, with the up and names options. Only the fcstd, rhino and step codecs are compiled in (no default features). ACIS is left out: cadmpeg's sat codec is a ShapeManager stream decoder. native_cad.rs is the single importer seam. Self-made FreeCAD and Rhino box fixtures, hostile-input, ZIP-bomb and cap tests, engine tests for the component path; the browser build reports these formats as not supported. A note under design format 23 says an Import's file can name these formats. Co-authored-by: Jacob Oursland Co-Authored-By: Claude Opus 5.5 --- ATTRIBUTION.md | 12 + Cargo.lock | 349 +++++- Cargo.toml | 8 + README.md | 4 +- ROADMAP.md | 4 +- THIRD-PARTY-LICENSES.txt | 1065 ++++++++++++----- apps/solidcraft/src/main.rs | 7 +- crates/doc/src/format.rs | 4 + crates/engine/src/cmd/file.rs | 6 +- crates/engine/src/tests.rs | 2 + crates/engine/src/tests/native_cad_import.rs | 94 ++ crates/io/Cargo.toml | 8 +- crates/io/src/lib.rs | 26 +- crates/io/src/native_cad.rs | 156 +++ crates/io/src/native_cad/fixtures/block.3dm | Bin 0 -> 19497 bytes crates/io/src/native_cad/fixtures/block.FCStd | Bin 0 -> 2485 bytes .../src/native_cad/fixtures/make_block_3dm.py | 11 + .../native_cad/fixtures/make_block_fcstd.py | 12 + crates/io/src/native_cad/tests.rs | 126 ++ crates/ui-egui/src/file_load.rs | 8 +- docs/book/src/guide/files.md | 3 +- docs/step-import.md | 6 + xtask/src/assets.rs | 2 + 23 files changed, 1585 insertions(+), 328 deletions(-) create mode 100644 crates/engine/src/tests/native_cad_import.rs create mode 100644 crates/io/src/native_cad.rs create mode 100644 crates/io/src/native_cad/fixtures/block.3dm create mode 100644 crates/io/src/native_cad/fixtures/block.FCStd create mode 100644 crates/io/src/native_cad/fixtures/make_block_3dm.py create mode 100644 crates/io/src/native_cad/fixtures/make_block_fcstd.py create mode 100644 crates/io/src/native_cad/tests.rs diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index d3419e47..9c7c0876 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -110,6 +110,8 @@ Editable drawing code, native projects and shipped exports are collected under ` | assets/shaders/viewport.wgsl | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 | | assets/styles/ui/palettes.rs | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 | | assets/styles/web/loading.css | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 | +| crates/io/src/native_cad/fixtures/block.FCStd | SolidCraft contributors | original 10 × 20 × 30 mm test box saved by FreeCAD 1.1.4 run as an external program (`make_block_fcstd.py` beside it); no third-party geometry | MIT OR Apache-2.0 | +| crates/io/src/native_cad/fixtures/block.3dm | SolidCraft contributors | original 10 × 20 × 30 mm test box written with McNeel's MIT-licensed rhino3dm Python package (`make_block_3dm.py` beside it); no third-party geometry | MIT OR Apache-2.0 | | docs/book/src/og.png | SolidCraft contributors | copy of assets/branding/web/source/og.png staged by cargo xtask book (gitignored) | MIT OR Apache-2.0 | @@ -151,6 +153,16 @@ in THIRD-PARTY-LICENSES.txt; no images or artwork from that project are copied. The glTF test files are built by the tests themselves (crates/io/src/gltf_in_tests.rs, crates/engine/src/tests/gltf_import.rs); no third-party models are committed. +## FreeCAD and Rhino import library + +FreeCAD `.FCStd` and Rhino `.3dm` files are read with [cadmpeg](https://github.com/cadmpeg/cadmpeg) +0.6.1 (Apache-2.0), linked as the crates `cadmpeg-core`, `cadmpeg-ir`, `cadmpeg-registry`, +`cadmpeg-container`, `cadmpeg-codec-freecad`, `cadmpeg-codec-rhino` and `cadmpeg-codec-step` +in native builds (`crates/io/src/native_cad.rs`). Only those open-format codecs are built: no +default features, so cadmpeg's codecs for commercial CAD formats and its ShapeManager/ACIS +codec are not compiled in. Its licence text is in THIRD-PARTY-LICENSES.txt; no code from it is +copied into SolidCraft. + ## Recovered contributions | SolidCraft file | Original contribution | Licence | diff --git a/Cargo.lock b/Cargo.lock index e8312e2d..6862c0be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,7 +131,7 @@ checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] @@ -489,6 +489,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "block-padding" version = "0.3.3" @@ -582,6 +591,117 @@ version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +[[package]] +name = "cadmpeg-codec-freecad" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a5257265c2549cf59a8457b3c7aadcc96c95abe20205232553766993a808812" +dependencies = [ + "cadmpeg-container", + "cadmpeg-core", + "cadmpeg-ir", + "roxmltree", + "serde", + "serde_json", + "tempfile", + "zip 8.6.0", +] + +[[package]] +name = "cadmpeg-codec-rhino" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d88b42fb91c7e5af4c75c0433029771f7e3233a0b72ec3d0b2e5ff2c72bed07" +dependencies = [ + "cadmpeg-container", + "cadmpeg-core", + "cadmpeg-ir", + "crc32fast", + "flate2", + "roxmltree", + "serde", + "serde_json", + "sha1 0.11.0", + "sha2 0.11.1", + "tempfile", +] + +[[package]] +name = "cadmpeg-codec-step" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83a52258c129a683f77fb360ca30af54ae34339625ad890be12621128a5811c" +dependencies = [ + "base64", + "cadmpeg-container", + "cadmpeg-core", + "cadmpeg-ir", + "encoding_rs", + "serde_json", + "thiserror 2.0.21", + "zip 8.6.0", +] + +[[package]] +name = "cadmpeg-container" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c110508cd9155e905f52906de505dfd42dc70a0321f5e90b5f68c28ba207686e" +dependencies = [ + "cadmpeg-core", + "crc32fast", + "flate2", + "zip 8.6.0", + "zstd 0.14.2", +] + +[[package]] +name = "cadmpeg-core" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b1147e51a74e7c52da5b393a0344597238cdc622fac6443eb2fd526759f6fa" +dependencies = [ + "flate2", + "memchr", + "roxmltree", + "serde", + "serde_json", + "thiserror 2.0.21", + "zstd 0.14.2", +] + +[[package]] +name = "cadmpeg-ir" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71ff19f019f013d97e353bb802c5d2e253c2859aaa5422009aa933dc2f2e7dbc" +dependencies = [ + "base64", + "cadmpeg-core", + "serde", + "serde-value", + "serde_json", + "sha2 0.11.1", + "thiserror 2.0.21", +] + +[[package]] +name = "cadmpeg-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66046f1a694926707bea8944f861e699964b04c68972708588f97e14ccee3c5d" +dependencies = [ + "cadmpeg-codec-freecad", + "cadmpeg-codec-rhino", + "cadmpeg-codec-step", + "cadmpeg-container", + "cadmpeg-core", + "cadmpeg-ir", + "serde", + "thiserror 2.0.21", + "toml", +] + [[package]] name = "calloop" version = "0.13.0" @@ -704,7 +824,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "inout", ] @@ -756,6 +876,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "convert_case" version = "0.4.0" @@ -812,6 +938,12 @@ dependencies = [ "libc", ] +[[package]] +name = "core_detect" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -821,6 +953,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.5.2" @@ -871,6 +1012,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "cursor-icon" version = "1.2.0" @@ -902,7 +1052,7 @@ dependencies = [ "hkdf", "num", "once_cell", - "sha2", + "sha2 0.10.9", "zeroize", ] @@ -936,11 +1086,22 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid", + "crypto-common 0.2.2", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -1155,6 +1316,20 @@ dependencies = [ "winreg", ] +[[package]] +name = "encoding_rs" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e985e0451871ad22fb8d2b6b076e2028a502a0d3950998c2c5c0a4f9b5d9679" +dependencies = [ + "cfg-if", + "core_detect", + "multiversion_no_op", + "rustversion", + "scopeguard", + "simdutf8", +] + [[package]] name = "endi" version = "1.1.1" @@ -1740,7 +1915,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -1759,6 +1934,15 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -2252,6 +2436,12 @@ dependencies = [ "pxfm", ] +[[package]] +name = "multiversion_no_op" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" + [[package]] name = "naga" version = "30.0.1" @@ -2767,6 +2957,15 @@ dependencies = [ "libredox", ] +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-float" version = "5.5.0" @@ -3291,6 +3490,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "roxmltree" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb" +dependencies = [ + "memchr", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -3463,7 +3671,7 @@ dependencies = [ "once_cell", "rand", "serde", - "sha2", + "sha2 0.10.9", "zbus 4.4.0", ] @@ -3525,6 +3733,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float 2.10.1", + "serde", +] + [[package]] name = "serde_core" version = "1.0.229" @@ -3585,8 +3803,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", ] [[package]] @@ -3596,8 +3825,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d7069beb7d6ac7b9acd1039986e73443f24234f41074da099d6f994ac9ad19" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", ] [[package]] @@ -3804,7 +4044,7 @@ dependencies = [ "log", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "solidcraft-derive", "solidcraft-geom", "solidcraft-kernel", @@ -3856,16 +4096,19 @@ dependencies = [ name = "solidcraft-io" version = "0.13.1" dependencies = [ + "cadmpeg-core", + "cadmpeg-ir", + "cadmpeg-registry", "gltf", "quick-xml", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "solidcraft-doc", "solidcraft-geom", "solidcraft-kernel", "thiserror 2.0.21", - "zip", + "zip 3.0.0", ] [[package]] @@ -3903,7 +4146,7 @@ dependencies = [ "png", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "solidcraft-geom", ] @@ -3931,12 +4174,12 @@ dependencies = [ "semver", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "solidcraft-engine", "solidcraft-gpu", "ttf-parser", "web-time", - "zip", + "zip 3.0.0", ] [[package]] @@ -4370,6 +4613,12 @@ dependencies = [ "rustc-hash 2.1.3", ] +[[package]] +name = "typed-path" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" + [[package]] name = "typeid" version = "1.0.3" @@ -4941,7 +5190,7 @@ dependencies = [ "objc2-metal 0.3.2", "objc2-quartz-core 0.3.2", "once_cell", - "ordered-float", + "ordered-float 5.5.0", "parking_lot", "portable-atomic", "portable-atomic-util", @@ -5433,7 +5682,7 @@ name = "xtask" version = "0.13.1" dependencies = [ "serde_json", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -5486,7 +5735,7 @@ dependencies = [ "rand", "serde", "serde_repr", - "sha1", + "sha1 0.10.7", "static_assertions", "tracing", "uds_windows", @@ -5735,6 +5984,20 @@ dependencies = [ "zopfli", ] +[[package]] +name = "zip" +version = "8.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" +dependencies = [ + "crc32fast", + "flate2", + "indexmap", + "memchr", + "typed-path", + "zstd 0.13.3", +] + [[package]] name = "zlib-rs" version = "0.6.8" @@ -5759,6 +6022,52 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe 7.3.0", +] + +[[package]] +name = "zstd" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057cfd910cfac363a0ada849592624b4c9ff2e10bef504c3433810d78ed96f93" +dependencies = [ + "zstd-safe 8.1.0", +] + +[[package]] +name = "zstd-safe" +version = "7.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-safe" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd44c6a7284e91f3717755b24315a302edd9153a01f753c3cba3d765e8eafac" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.1.1+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeec9eaf2dffbbd09201e23bd0ffcbaa33bb8e9266a10734fd7ed90a85eca078" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "zune-core" version = "0.5.3" diff --git a/Cargo.toml b/Cargo.toml index b669ad90..1066b71b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,14 @@ quick-xml = "0.41" # read by crates/io itself, so no image decoding or file access comes with it. gltf = { version = "1.4", default-features = false, features = ["names"] } +# FreeCAD and Rhino import (Apache-2.0, pure Rust apart from zstd; native builds only). +# Pinned: its IR and codec APIs change between minor versions. Open formats only: no default +# features, so cadmpeg's codecs for commercial formats (f3d, sldprt, inventor, catia, creo, nx) +# and its ShapeManager/ACIS `sat` codec are not compiled in. `step` is the writer we restate through. +cadmpeg-core = "=0.6.1" +cadmpeg-ir = "=0.6.1" +cadmpeg-registry = { version = "=0.6.1", default-features = false, features = ["fcstd", "rhino", "step"] } + # fonts (sketch text outlines; MIT OR Apache-2.0, pure Rust) ttf-parser = { version = "0.25", default-features = false, features = ["std"] } diff --git a/README.md b/README.md index 54759d7a..daaf675a 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,9 @@ rebuild with no errors, replayed here at 2× speed. STEP import (AP203/AP214/AP242 solids, assemblies, units, names, colours) and IGES import (manifold solid B-reps, or trimmed and bounded surfaces sewn into solids) as a base feature that later features build on — open a `.step`/`.stp`/`.igs`/`.iges` file, insert one into a - design, or drop it on the window ([docs/step-import.md](docs/step-import.md)). + design, or drop it on the window ([docs/step-import.md](docs/step-import.md)); FreeCAD + `.FCStd` and Rhino `.3dm` solids import the same way through + [cadmpeg](https://github.com/cadmpeg/cadmpeg) in the desktop app and CLI. - **Render:** opaque surfaces can use metal fraction, roughness and dielectric IOR in the integrated product viewport and CPU preview PNGs. Existing simple colors remain supported. Fixed direct lighting is a preview; HDRI, refraction and texture maps are not implemented. diff --git a/ROADMAP.md b/ROADMAP.md index 2cae5667..c9a64dbb 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -7,7 +7,7 @@ features → parametric timeline) as an open, pure-Rust, agent-drivable applicat | Question | Answer | |---|---| -| Where are we? | **M0 and M13 done; M1, M2, M5–M7, M9, M10, M14 in progress.** Sketch with solver and the full SKETCH create/modify set; extrude, revolve (two sides, symmetric, to object), fillet/chamfer (variable radius, chord length, a radius per edge, corner patches), holes, threads (cosmetic and modelled), patterns, mirror, shell (inside/outside/both), draft, loft, sweep, coil, split body and split face, delete face, construction planes, axes and points; persistent naming of faces and edges; parameters and configurations; components, joints, motion studies, exploded views; sheet metal and a plastic enclosure subset; STEP/IGES/3MF/STL/OBJ/DXF; autosave and crash recovery; desktop and browser (wasm) app, CLI, MCP server. | +| Where are we? | **M0 and M13 done; M1, M2, M5–M7, M9, M10, M14 in progress.** Sketch with solver and the full SKETCH create/modify set; extrude, revolve (two sides, symmetric, to object), fillet/chamfer (variable radius, chord length, a radius per edge, corner patches), holes, threads (cosmetic and modelled), patterns, mirror, shell (inside/outside/both), draft, loft, sweep, coil, split body and split face, delete face, construction planes, axes and points; persistent naming of faces and edges; parameters and configurations; components, joints, motion studies, exploded views; sheet metal and a plastic enclosure subset; STEP/IGES/3MF/STL/OBJ/DXF; FreeCAD/Rhino import; autosave and crash recovery; desktop and browser (wasm) app, CLI, MCP server. | | Features | Every registered command by area — [docs/features.md](docs/features.md) (`cargo xtask features`); registry breadth does not establish workflow or geometric depth | | Reference tests | **82 / 82 parts match** — [docs/oracle.md](docs/oracle.md): public cases in `tests/oracle/` with analytic (61) or FreeCAD-computed (21) expected values, run by CI on every PR. | | Tests | Solver, profiles, kernel booleans/blends/measures, expressions, timeline, persistent naming, file formats and migrations, assemblies, sheet metal, engine end-to-end, hostile-input fuzz over every command and headless UI scenarios. `cargo xtask ci` reports the current passing counts. | @@ -49,7 +49,7 @@ PCB / Package, Render, Animation, Simulation, Manufacture/CAM, Drawings. | M1 | Sketch depth: command coverage implemented — projection/intersect/include as linked geometry (auto-project on faces, lost-reference warnings, break link), full SKETCH create/modify set (slots, polygons, tangent arcs/circles, ellipse, fit/control splines, conic, text, trim/extend/break, fillet/chamfer, offset, mirror, patterns, move/scale, blend curve, centerline), constraints incl. curvature and polygon with over-constraint refusal, driven/arc-length/linear-diameter dimensions, AutoConstrain, DXF/SVG insert, 3D sketch curves (Project To Surface, Intersection Curve, Isoparametric Curve, Spun Profile), exact free-form profiles (B-spline/NURBS edges, any spline degree, curves cut by crossings), sweeps and pipes along 3D sketch curves, canvases and decals, curvature combs. Exact free-form Extend and certified associative offsets now preserve geometry and IDs through edits, deletion and reopen. Occurrence-frame 3D wires now store explicit coordinate spaces and retain points and analytic fits through moves, refresh, undo and reopen. Constructive sketch solving (Owen 1991, Fudos & Hoffmann 1997) ahead of the numerical solver: points and rigid clusters are placed on the branch the sketch had, so dimension edits and drags keep their solution; edits that would turn a sketch over are refused; drags re-solve only the sketch per frame. Remaining workflow repairs: mixed offset junctions, legacy natural-spline seams, and damaged legacy wire links lacking frame provenance | in progress | 4 | | M2 | Robust modelling: coplanar booleans in the kernel, holes (placed on faces and on sketch points), threads (cosmetic, then modelled), patterns, mirror, shell, draft, split, construction geometry | in progress | 16 | | M3 | General fillets and chamfers (curved edges, chains, vertex blends); saddle rolling-ball surfaces now use continuous seam sections and arc-length fitting with shared contact boundaries and bounded accuracy checks | in progress | 30 | -| M4 | Files: STEP import (done — [docs/step-import.md](docs/step-import.md)), 3MF export and 3MF/STL import as mesh bodies (done), 3MF with B-rep face tags ([docs/formats/3mf-face-tags.md](docs/formats/3mf-face-tags.md), done), constant-section parametric mesh reconstruction, DXF sketches, OBJ import | in progress | 6 | +| M4 | Files: STEP import (done — [docs/step-import.md](docs/step-import.md)), FreeCAD/Rhino solids through cadmpeg (done, desktop and CLI), 3MF export and 3MF/STL import as mesh bodies (done), 3MF with B-rep face tags ([docs/formats/3mf-face-tags.md](docs/formats/3mf-face-tags.md), done), constant-section parametric mesh reconstruction, DXF sketches, OBJ import | in progress | 6 | | M5 | Persistent naming of faces and edges (docs/book/src/dev/naming.md): faces named from their exact kernel-reported history (sketch curve sides, caps, revolve sections, primitive sides, blends, shell inner walls, pattern/mirror copies; split pieces told apart by the faces around them, lumps of a cut body named after their faces), edges by their faces; fillets/chamfers, sketches on faces, shell/draft/offset/replace faces, hole placements, joint origins and face appearances resolve by name first and warn when the entity split or vanished: done. sheet metal edges by base sketch line and flange side, shell inner faces, sweep and loft roles: done. kernel-reported face history: done (merged faces answer to every name; operations without history yet fall back to geometric names, flagged unverified; format 14 keeps older designs' geometric names). Left: history through sheet metal, plastic, surface and emboss features; FaceSource certificates through history | in progress | 20 | | M6 | UI depth: selection feedback and origin (done), timeline editing (done: hover and selection highlight modifier faces, including fillets and chamfers; edit feature, history marker drag, dependency-checked single and multi-item reorder, suppress, rename, delete with dependents, re-resolved references; redefining selections refreshes persistent edge/face references while retaining feature identity and dimension names; optional compact named left feature history with rollback bar, multi-selection and persistent folders above the parts browser), right-docked dialogs (done), live previews for every feature dialog (done), keyboard-first commands with on-canvas value boxes and sketch inline dimensions (done), drag manipulators with automatic join/cut (done: extrude incl. two sides, fillet, shell, hole depth, move, pattern spacing, revolve rotator; taper handle open), dark theme (done), right-click menu with Repeat (done), measure tool (done), section analysis (done), selection filter (done), drag-solve of sketch points (done); appearance controls now preserve body/face/component targeting, named transparent looks, reuse/search and override removal; preferences | in progress | 6 | | M7 | Thin extrude (walls along open or closed curves: centre, inside, outside or two sides; mitred corners, crossing walls joined; #721), sweep, loft (incl. to a point), rib and web (to next / depth), emboss (planar faces and exact radial emboss/deboss of bounded orthogonal profiles on complete exterior cylinders/sleeves), thread (cosmetic, and modelled M3–M20 outside and inside: the ISO profile screwed in as a faceted cut), coil (smooth B-spline helical walls), pipe, pattern on path, patterns of bodies and components, replace face (parallel), align, remove, feature copy/paste: done. Unique eligible cylindrical targets are inferred for new Emboss features. Left: general curved-face emboss and exact (unfaceted) modelled threads | in progress | 12 | diff --git a/THIRD-PARTY-LICENSES.txt b/THIRD-PARTY-LICENSES.txt index a1ae0e02..86cbc1af 100644 --- a/THIRD-PARTY-LICENSES.txt +++ b/THIRD-PARTY-LICENSES.txt @@ -1,6 +1,6 @@ Third-party software in SolidCraft -SolidCraft (the desktop app, solidcraft-cli and the web app) is built from the 513 crates below. +SolidCraft (the desktop app, solidcraft-cli and the web app) is built from the 544 crates below. Generated by `cargo xtask licences` from Cargo.lock and the crates' own licence files. SolidCraft's own licence is in LICENSE-MIT and LICENSE-APACHE, and NOTICE. @@ -48,6 +48,7 @@ bit-vec 0.9.1 (Apache-2.0 OR MIT) bitflags 1.3.2 (MIT/Apache-2.0) bitflags 2.13.2 (MIT OR Apache-2.0) block-buffer 0.10.4 (MIT OR Apache-2.0) +block-buffer 0.12.1 (MIT OR Apache-2.0) block-padding 0.3.3 (MIT OR Apache-2.0) block2 0.5.1 (MIT) block2 0.6.2 (MIT) @@ -59,6 +60,13 @@ bytemuck_derive 1.12.1 (Zlib OR Apache-2.0 OR MIT) byteorder 1.5.0 (Unlicense OR MIT) byteorder-lite 0.1.0 (Unlicense OR MIT) bytes 1.12.1 (MIT) +cadmpeg-codec-freecad 0.6.1 (Apache-2.0) +cadmpeg-codec-rhino 0.6.1 (Apache-2.0) +cadmpeg-codec-step 0.6.1 (Apache-2.0) +cadmpeg-container 0.6.1 (Apache-2.0) +cadmpeg-core 0.6.1 (Apache-2.0) +cadmpeg-ir 0.6.1 (Apache-2.0) +cadmpeg-registry 0.6.1 (Apache-2.0) calloop 0.13.0 (MIT) calloop 0.14.5 (MIT) calloop-wayland-source 0.3.0 (MIT) @@ -74,25 +82,30 @@ codespan-reporting 0.13.1 (Apache-2.0) color 0.3.3 (Apache-2.0 OR MIT) combine 4.6.8 (MIT) concurrent-queue 2.5.0 (Apache-2.0 OR MIT) +const-oid 0.10.2 (Apache-2.0 OR MIT) convert_case 0.4.0 (MIT) core-foundation 0.10.1 (MIT OR Apache-2.0) core-foundation 0.9.4 (MIT OR Apache-2.0) core-foundation-sys 0.8.7 (MIT OR Apache-2.0) core-graphics 0.23.2 (MIT OR Apache-2.0) core-graphics-types 0.1.3 (MIT OR Apache-2.0) +core_detect 1.0.0 (MIT/Apache-2.0) cpufeatures 0.2.17 (MIT OR Apache-2.0) +cpufeatures 0.3.1 (MIT OR Apache-2.0) crc32fast 1.5.2 (MIT OR Apache-2.0) crossbeam-deque 0.8.8 (MIT OR Apache-2.0) crossbeam-epoch 0.9.21 (MIT OR Apache-2.0) crossbeam-utils 0.8.23 (MIT OR Apache-2.0) crunchy 0.2.4 (MIT) crypto-common 0.1.7 (MIT OR Apache-2.0) +crypto-common 0.2.2 (MIT OR Apache-2.0) cursor-icon 1.2.0 (MIT OR Apache-2.0 OR Zlib) dbus 0.9.12 (Apache-2.0/MIT) dbus-secret-service 4.1.0 (MIT OR Apache-2.0) derive_arbitrary 1.5.0 (MIT OR Apache-2.0) derive_more 0.99.20 (MIT) digest 0.10.7 (MIT OR Apache-2.0) +digest 0.11.3 (MIT OR Apache-2.0) dispatch 0.2.0 (MIT) dispatch2 0.3.1 (Zlib OR Apache-2.0 OR MIT) displaydoc 0.2.7 (MIT OR Apache-2.0) @@ -108,6 +121,7 @@ egui-winit 0.36.2 (MIT OR Apache-2.0) egui_glow 0.36.2 (MIT OR Apache-2.0) either 1.19.0 (MIT OR Apache-2.0) emath 0.36.2 (MIT OR Apache-2.0) +encoding_rs 0.8.42 ((Apache-2.0 OR MIT) AND BSD-3-Clause) endi 1.1.1 (MIT) enumflags2 0.7.12 (MIT OR Apache-2.0) enumflags2_derive 0.7.12 (MIT OR Apache-2.0) @@ -166,6 +180,7 @@ hkdf 0.12.4 (MIT OR Apache-2.0) hmac 0.12.1 (MIT OR Apache-2.0) http 1.5.0 (MIT OR Apache-2.0) httparse 1.10.1 (MIT OR Apache-2.0) +hybrid-array 0.4.15 (MIT OR Apache-2.0) iana-time-zone 0.1.65 (MIT OR Apache-2.0) iana-time-zone-haiku 0.1.2 (MIT OR Apache-2.0) icu_collections 2.3.0 (Unicode-3.0) @@ -215,6 +230,7 @@ minisign-verify 0.3.0 (MIT) miniz_oxide 0.8.9 (MIT OR Zlib OR Apache-2.0) miniz_oxide 0.9.1 (MIT OR Zlib OR Apache-2.0) moxcms 0.8.1 (BSD-3-Clause OR Apache-2.0) +multiversion_no_op 1.0.0 (Apache-2.0 OR MIT) naga 30.0.1 (MIT OR Apache-2.0) naga-types 30.0.1 (MIT OR Apache-2.0) ndk 0.9.0 (MIT OR Apache-2.0) @@ -260,6 +276,7 @@ objc2-user-notifications 0.2.2 (MIT) once_cell 1.21.4 (MIT OR Apache-2.0) openssl-probe 0.2.1 (MIT OR Apache-2.0) orbclient 0.3.55 (MIT) +ordered-float 2.10.1 (MIT) ordered-float 5.5.0 (MIT) ordered-stream 0.2.0 (MIT OR Apache-2.0) parking 2.2.1 (Apache-2.0 OR MIT) @@ -315,6 +332,7 @@ rfd 0.17.2 (MIT) ring 0.17.14 (Apache-2.0 AND ISC) robust 1.2.0 (MIT OR Apache-2.0) ron 0.12.2 (MIT OR Apache-2.0) +roxmltree 0.21.1 (MIT OR Apache-2.0) rustc-hash 1.1.0 (Apache-2.0/MIT) rustc-hash 2.1.3 (Apache-2.0 OR MIT) rustix 0.38.44 (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) @@ -336,12 +354,16 @@ security-framework-sys 2.17.0 (MIT OR Apache-2.0) self_cell 1.3.0 (Apache-2.0 OR GPL-2.0-only) semver 1.0.28 (MIT OR Apache-2.0) serde 1.0.229 (MIT OR Apache-2.0) +serde-value 0.7.0 (MIT) serde_core 1.0.229 (MIT OR Apache-2.0) serde_derive 1.0.229 (MIT OR Apache-2.0) serde_json 1.0.151 (MIT OR Apache-2.0) serde_repr 0.1.21 (MIT OR Apache-2.0) +serde_spanned 1.1.2 (MIT OR Apache-2.0) sha1 0.10.7 (MIT OR Apache-2.0) +sha1 0.11.0 (MIT OR Apache-2.0) sha2 0.10.9 (MIT OR Apache-2.0) +sha2 0.11.1 (MIT OR Apache-2.0) signal-hook-registry 1.4.8 (MIT OR Apache-2.0) simd-adler32 0.3.10 (MIT) simd_cesu8 1.2.0 (Apache-2.0 OR MIT) @@ -373,9 +395,11 @@ thiserror-impl 2.0.21 (MIT OR Apache-2.0) tiff 0.11.3 (MIT) tinystr 0.8.4 (Unicode-3.0) tokio 1.53.2 (MIT) +toml 1.1.8+spec-1.1.0 (MIT OR Apache-2.0) toml_datetime 1.1.2+spec-1.1.0 (MIT OR Apache-2.0) toml_edit 0.25.15+spec-1.1.0 (MIT OR Apache-2.0) toml_parser 1.1.5+spec-1.1.0 (MIT OR Apache-2.0) +toml_writer 1.1.3+spec-1.1.0 (MIT OR Apache-2.0) tracing 0.1.44 (MIT) tracing-attributes 0.1.31 (MIT) tracing-core 0.1.36 (MIT) @@ -391,6 +415,7 @@ truck-stepio 0.3.0 (Apache-2.0) truck-topology 0.6.0 (Apache-2.0) ttf-parser 0.25.1 (MIT OR Apache-2.0) type-map 0.5.1 (MIT/Apache-2.0) +typed-path 0.12.3 (MIT OR Apache-2.0) typeid 1.0.3 (MIT OR Apache-2.0) typenum 1.20.1 (MIT OR Apache-2.0) uds_windows 1.2.1 (MIT) @@ -506,9 +531,15 @@ zerotrie 0.2.5 (Unicode-3.0) zerovec 0.11.8 (Unicode-3.0) zerovec-derive 0.11.6 (Unicode-3.0) zip 3.0.0 (MIT) +zip 8.6.0 (MIT) zlib-rs 0.6.8 (Zlib) zmij 1.0.23 (MIT) zopfli 0.8.3 (Apache-2.0) +zstd 0.13.3 (MIT) +zstd 0.14.2 (BSD-3-Clause) +zstd-safe 7.3.0 (BSD-3-Clause) +zstd-safe 8.1.0 (BSD-3-Clause) +zstd-sys 2.1.1+zstd.1.5.7 (BSD-3-Clause) zune-core 0.5.3 (MIT OR Apache-2.0 OR Zlib) zune-jpeg 0.5.15 (MIT OR Apache-2.0 OR Zlib) zvariant 4.2.0 (MIT) @@ -548,10 +579,10 @@ pin-project-internal 1.1.13, pin-project-lite 0.2.17, piper 0.2.5, polling 3.11. rustc-hash 1.1.0, rustc-hash 2.1.3, rustix 0.38.44, rustix 1.1.5, rustversion 1.0.23, semver 1.0.28, serde 1.0.229, serde_core 1.0.229, serde_derive 1.0.229, serde_json 1.0.151, serde_repr 0.1.21, simd_cesu8 1.2.0, smol_str 0.2.2, syn 1.0.109, syn 2.0.119, syn 3.0.6, thiserror 1.0.69, thiserror -2.0.21, thiserror-impl 1.0.69, thiserror-impl 2.0.21, typeid 1.0.3, unicode-ident 1.0.26, utf8-zero -0.8.1, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wit-bindgen 0.57.1, x11-dl -2.21.0, xdg-home 1.3.0, zbus-lockstep 0.5.2, zbus-lockstep-macros 0.5.2, zbus_names 3.0.0, zmij -1.0.23, zvariant_utils 2.1.0, zvariant_utils 4.2.0 +2.0.21, thiserror-impl 1.0.69, thiserror-impl 2.0.21, typed-path 0.12.3, typeid 1.0.3, unicode-ident +1.0.26, utf8-zero 0.8.1, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wit-bindgen +0.57.1, x11-dl 2.21.0, xdg-home 1.3.0, zbus-lockstep 0.5.2, zbus-lockstep-macros 0.5.2, zbus_names +3.0.0, zmij 1.0.23, zvariant_utils 2.1.0, zvariant_utils 4.2.0 ================================================================================ Permission is hereby granted, free of charge, to any @@ -815,8 +846,10 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================================================ -aes 0.8.4, block-buffer 0.10.4, block-padding 0.3.3, cbc 0.1.2, cipher 0.4.4, cpufeatures 0.2.17, -crypto-common 0.1.7, digest 0.10.7, hkdf 0.12.4, hmac 0.12.1, inout 0.1.4, sha1 0.10.7, sha2 0.10.9 +aes 0.8.4, block-buffer 0.10.4, block-buffer 0.12.1, block-padding 0.3.3, cbc 0.1.2, cipher 0.4.4, +const-oid 0.10.2, cpufeatures 0.2.17, cpufeatures 0.3.1, crypto-common 0.1.7, crypto-common 0.2.2, +digest 0.10.7, digest 0.11.3, hkdf 0.12.4, hmac 0.12.1, hybrid-array 0.4.15, inout 0.1.4, sha1 +0.10.7, sha1 0.11.0, sha2 0.10.9, sha2 0.11.1 ================================================================================ Apache License @@ -1057,20 +1090,21 @@ ahash 0.8.12, arbitrary 1.5.0, arrayvec 0.7.8, async-channel 2.5.0, async-execut 0.2.14, async-task 4.7.1, atomic-waker 1.1.2, base64 0.23.1, bitflags 1.3.2, bitflags 2.13.2, blocking 1.7.0, bumpalo 3.20.3, cfg-if 1.0.5, cgl 0.3.2, concurrent-queue 2.5.0, core-foundation 0.10.1, core-foundation 0.9.4, core-foundation-sys 0.8.7, core-graphics 0.23.2, core-graphics-types -0.1.3, crossbeam-deque 0.8.8, crossbeam-epoch 0.9.21, crossbeam-utils 0.8.23, dbus-secret-service -4.1.0, derive_arbitrary 1.5.0, displaydoc 0.2.7, either 1.19.0, equivalent 1.0.2, errno 0.3.14, -euclid 0.22.14, event-listener 5.4.2, event-listener-strategy 0.5.4, fastrand 2.5.0, flate2 1.1.10, -form_urlencoded 1.2.2, futures-lite 2.6.1, gethostname 1.1.0, glow 0.17.0, gltf 1.4.1, gltf-derive -1.4.1, gltf-json 1.4.1, hashbrown 0.16.1, hashbrown 0.17.1, hermit-abi 0.5.3, httparse 1.10.1, idna -1.1.0, idna_adapter 1.2.2, indexmap 2.14.2, itertools 0.13.0, itertools 0.15.0, js-sys 0.3.106, -khronos-egl 6.0.0, lazy_static 1.5.1, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, lock_api 0.4.14, -log 0.4.34, num 0.4.3, num-bigint 0.4.8, num-complex 0.4.6, num-integer 0.1.47, num-iter 0.1.46, -num-rational 0.4.2, num-traits 0.2.19, once_cell 1.21.4, openssl-probe 0.2.1, ordered-stream 0.2.0, -parking 2.2.1, parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, piper 0.2.5, -plain 0.2.3, png 0.18.1, polling 3.11.0, pollster 0.4.0, pollster 1.0.1, rayon 1.12.0, rayon-core -1.13.0, renderdoc-sys 1.1.0, robust 1.2.0, ron 0.12.2, rustc-hash 1.1.0, rustix 0.38.44, rustix -1.1.5, rustls 0.23.46, rustls-native-certs 0.8.5, scoped-tls 1.0.1, scopeguard 1.2.0, secret-service -4.0.0, security-framework 2.11.1, security-framework 3.7.0, security-framework-sys 2.17.0, +0.1.3, core_detect 1.0.0, crossbeam-deque 0.8.8, crossbeam-epoch 0.9.21, crossbeam-utils 0.8.23, +dbus-secret-service 4.1.0, derive_arbitrary 1.5.0, displaydoc 0.2.7, either 1.19.0, equivalent +1.0.2, errno 0.3.14, euclid 0.22.14, event-listener 5.4.2, event-listener-strategy 0.5.4, fastrand +2.5.0, flate2 1.1.10, form_urlencoded 1.2.2, futures-lite 2.6.1, gethostname 1.1.0, glow 0.17.0, +gltf 1.4.1, gltf-derive 1.4.1, gltf-json 1.4.1, hashbrown 0.16.1, hashbrown 0.17.1, hermit-abi +0.5.3, httparse 1.10.1, idna 1.1.0, idna_adapter 1.2.2, indexmap 2.14.2, itertools 0.13.0, itertools +0.15.0, js-sys 0.3.106, khronos-egl 6.0.0, lazy_static 1.5.1, linux-raw-sys 0.12.1, linux-raw-sys +0.4.15, lock_api 0.4.14, log 0.4.34, num 0.4.3, num-bigint 0.4.8, num-complex 0.4.6, num-integer +0.1.47, num-iter 0.1.46, num-rational 0.4.2, num-traits 0.2.19, once_cell 1.21.4, openssl-probe +0.2.1, ordered-stream 0.2.0, parking 2.2.1, parking_lot 0.12.5, parking_lot_core 0.9.12, +percent-encoding 2.3.2, piper 0.2.5, plain 0.2.3, png 0.18.1, polling 3.11.0, pollster 0.4.0, +pollster 1.0.1, rayon 1.12.0, rayon-core 1.13.0, renderdoc-sys 1.1.0, robust 1.2.0, ron 0.12.2, +roxmltree 0.21.1, rustc-hash 1.1.0, rustix 0.38.44, rustix 1.1.5, rustls 0.23.46, +rustls-native-certs 0.8.5, scoped-tls 1.0.1, scopeguard 1.2.0, secret-service 4.0.0, +security-framework 2.11.1, security-framework 3.7.0, security-framework-sys 2.17.0, signal-hook-registry 1.4.8, simd_cesu8 1.2.0, smallvec 1.16.2, smol_str 0.2.2, stable_deref_trait 1.2.1, syn 1.0.109, tempfile 3.27.0, ttf-parser 0.25.1, unicode-segmentation 1.13.3, unicode-width 0.2.2, url 2.5.8, uuid 1.27.0, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, @@ -1286,7 +1320,8 @@ allocator-api2 0.2.21, async-trait 0.1.92, enumn 0.1.14, glifo 0.2.0, itoa 1.0.1 litrs 1.0.0, num_enum 0.7.6, num_enum_derive 0.7.6, proc-macro2 1.0.107, quote 1.0.47, rustc-hash 2.1.3, rustversion 1.0.23, semver 1.0.28, serde 1.0.229, serde_core 1.0.229, serde_derive 1.0.229, serde_json 1.0.151, serde_repr 0.1.21, syn 2.0.119, syn 3.0.6, thiserror 1.0.69, thiserror 2.0.21, -thiserror-impl 1.0.69, thiserror-impl 2.0.21, typeid 1.0.3, unicode-ident 1.0.26, utf8-zero 0.8.1 +thiserror-impl 1.0.69, thiserror-impl 2.0.21, typed-path 0.12.3, typeid 1.0.3, unicode-ident 1.0.26, +utf8-zero 0.8.1 ================================================================================ Apache License @@ -1778,10 +1813,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================================================ approx 0.4.0, as-raw-xcb-connection 1.0.1, atspi 0.29.0, atspi-common 0.13.0, atspi-proxies 0.13.0, -cgmath 0.18.0, codespan-reporting 0.13.1, kurbo 0.13.1, nohash-hasher 0.2.0, peniko 0.6.1, polycool -0.4.0, raw-window-metal 1.1.0, rustls-platform-verifier 0.7.1, self_cell 1.3.0, siphasher 1.0.4, -spade 2.15.1, static_assertions 1.1.0, ureq 3.4.2, ureq-proto 0.6.4, utf8_iter 1.0.4, x11rb 0.13.2, -x11rb-protocol 0.13.2, zeroize 1.9.1, zeroize_derive 1.5.0, zune-core 0.5.3, zune-jpeg 0.5.15 +cgmath 0.18.0, codespan-reporting 0.13.1, encoding_rs 0.8.42, kurbo 0.13.1, multiversion_no_op +1.0.0, nohash-hasher 0.2.0, peniko 0.6.1, polycool 0.4.0, raw-window-metal 1.1.0, +rustls-platform-verifier 0.7.1, self_cell 1.3.0, siphasher 1.0.4, spade 2.15.1, static_assertions +1.1.0, ureq 3.4.2, ureq-proto 0.6.4, utf8_iter 1.0.4, x11rb 0.13.2, x11rb-protocol 0.13.2, zeroize +1.9.1, zeroize_derive 1.5.0, zune-core 0.5.3, zune-jpeg 0.5.15 ================================================================================ Apache License @@ -2854,6 +2890,36 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +================================================================================ +block-buffer 0.12.1 +================================================================================ + +Copyright (c) 2018-2025 The RustCrypto Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + ================================================================================ branches 0.3.0, rclite 0.2.8 ================================================================================ @@ -3551,6 +3617,66 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +================================================================================ +const-oid 0.10.2, cpufeatures 0.3.1 +================================================================================ + +Copyright (c) 2020-2026 The RustCrypto Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +================================================================================ +core_detect 1.0.0 +================================================================================ + +Copyright (c) 2017-2020 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + ================================================================================ cpufeatures 0.2.17 ================================================================================ @@ -3903,6 +4029,36 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +================================================================================ +crypto-common 0.2.2 +================================================================================ + +Copyright (c) 2021-2026 RustCrypto Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + ================================================================================ cursor-icon 1.2.0 ================================================================================ @@ -4465,6 +4621,37 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +================================================================================ +digest 0.11.3 +================================================================================ + +Copyright (c) 2017-2025 RustCrypto Developers +Copyright (c) 2017 Artyom Pavlov + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + ================================================================================ dlib 0.5.3 ================================================================================ @@ -4737,6 +4924,89 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +================================================================================ +encoding_rs 0.8.42 +================================================================================ + +Copyright © WHATWG (Apple, Google, Mozilla, Microsoft). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +================================================================================ +encoding_rs 0.8.42 +================================================================================ + +encoding_rs is copyright Mozilla Foundation. + +Licensed under the Apache License, Version 2.0 + or the MIT +license , +at your option. All files in the project carrying such +notice may not be copied, modified, or distributed except +according to those terms. + +This crate includes data derived from the data files supplied +with the WHATWG Encoding Standard, which, when incorporated into +source code, are licensed under the BSD 3-Clause License +. + +Test code within encoding_rs is dedicated to the Public Domain when so +designated (see the individual files for PD/CC0-dedicated sections). + +================================================================================ +encoding_rs 0.8.42, multiversion_no_op 1.0.0, utf8_iter 1.0.4 +================================================================================ + +Copyright Mozilla Foundation + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + ================================================================================ enumflags2 0.7.12 ================================================================================ @@ -6872,6 +7142,36 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +================================================================================ +hybrid-array 0.4.15 +================================================================================ + +Copyright (c) 2022-2026 The RustCrypto Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + ================================================================================ iana-time-zone 0.1.65, iana-time-zone-haiku 0.1.2 ================================================================================ @@ -9068,6 +9368,26 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +================================================================================ +multiversion_no_op 1.0.0 +================================================================================ + +Copyright Mozilla Foundation + +Licensed under the Apache License (Version 2.0), or the MIT license, +(the "Licenses") at your option. You may not use this file except in +compliance with one of the Licenses. You may obtain copies of the +Licenses at: + + https://www.apache.org/licenses/LICENSE-2.0 + https://opensource.org/licenses/MIT + +Unless required by applicable law or agreed to in writing, software +distributed under the Licenses is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the Licenses for the specific language governing permissions and +limitations under the Licenses. + ================================================================================ naga 30.0.1, naga-types 30.0.1, wgpu 30.0.1, wgpu-core 30.0.1, wgpu-core-deps-apple 30.0.1, wgpu-core-deps-emscripten 30.0.1, wgpu-core-deps-wasm 30.0.1, wgpu-core-deps-windows-linux-android @@ -9204,7 +9524,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================================================ -ordered-float 5.5.0 +ordered-float 2.10.1, ordered-float 5.5.0 ================================================================================ Copyright (c) 2015 Jonathan Reem @@ -10923,6 +11243,32 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +================================================================================ +roxmltree 0.21.1 +================================================================================ + +The MIT License (MIT) + +Copyright (c) 2018 Yevhenii Reizner + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + ================================================================================ rustix 0.38.44, rustix 1.1.5 ================================================================================ @@ -11718,6 +12064,262 @@ consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. +================================================================================ +serde-value 0.7.0 +================================================================================ + +Copyright (c) 2016 arcnmx + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +================================================================================ +serde_spanned 1.1.2, toml 1.1.8+spec-1.1.0, toml_datetime 1.1.2+spec-1.1.0, toml_edit +0.25.15+spec-1.1.0, toml_parser 1.1.5+spec-1.1.0, toml_writer 1.1.3+spec-1.1.0 +================================================================================ + +Copyright (c) Individual contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +================================================================================ +serde_spanned 1.1.2, toml 1.1.8+spec-1.1.0, toml_datetime 1.1.2+spec-1.1.0, toml_parser +1.1.5+spec-1.1.0, toml_writer 1.1.3+spec-1.1.0 +================================================================================ + +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright Individual contributors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ================================================================================ sha1 0.10.7, sha2 0.10.9 ================================================================================ @@ -11750,6 +12352,39 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +================================================================================ +sha1 0.11.0, sha2 0.11.1 +================================================================================ + +Copyright (c) 2016-2026 The RustCrypto Project Developers +Copyright (c) 2016 Artyom Pavlov +Copyright (c) 2009-2013 Mozilla Foundation +Copyright (c) 2006-2009 Graydon Hoare + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + ================================================================================ signal-hook-registry 1.4.8 ================================================================================ @@ -12140,236 +12775,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -================================================================================ -toml_datetime 1.1.2+spec-1.1.0, toml_edit 0.25.15+spec-1.1.0, toml_parser 1.1.5+spec-1.1.0 -================================================================================ - -Copyright (c) Individual contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -================================================================================ -toml_datetime 1.1.2+spec-1.1.0, toml_parser 1.1.5+spec-1.1.0 -================================================================================ - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright Individual contributors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ================================================================================ tracing 0.1.44, tracing-attributes 0.1.31, tracing-core 0.1.36 ================================================================================ @@ -13371,36 +13776,6 @@ licensed under the Apache License, Version 2.0 or or the MIT license or , at your option. -================================================================================ -utf8_iter 1.0.4 -================================================================================ - -Copyright Mozilla Foundation - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - ================================================================================ uuid 1.27.0 ================================================================================ @@ -15079,6 +15454,32 @@ SOFTWARE. Some files in the "tests/data" subdirectory of this repository are under other licences; see files named LICENSE.*.txt for details. +================================================================================ +zip 8.6.0 +================================================================================ + +The MIT License (MIT) + +Copyright (c) 2014 Mathijs van de Nes + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + ================================================================================ zlib-rs 0.6.8 ================================================================================ @@ -15309,6 +15710,89 @@ Apache License See the License for the specific language governing permissions and limitations under the License. +================================================================================ +zstd 0.13.3 +================================================================================ + +The MIT License (MIT) +Copyright (c) 2016 Alexandre Bury + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +================================================================================ +zstd 0.14.2, zstd-safe 7.3.0, zstd-safe 8.1.0, zstd-sys 2.1.1+zstd.1.5.7 +================================================================================ + +BSD 3-Clause License + +Copyright (c) 2026, Alexandre Bury + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +================================================================================ +zstd-sys 2.1.1+zstd.1.5.7 +================================================================================ + +The auto-generated bindings are under the 3-clause BSD license: + +BSD License + +For Zstandard software + +Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook, nor Meta, nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ================================================================================ zune-core 0.5.3, zune-jpeg 0.5.15 ================================================================================ @@ -15376,6 +15860,13 @@ accesskit_winit 0.32.2: Apache-2.0 (https://github.com/AccessKit/accesskit) array-macro 2.1.8: MIT OR Apache-2.0 (https://codeberg.org/xfix/array-macro) block2 0.5.1: MIT (https://github.com/madsmtm/objc2) block2 0.6.2: MIT (https://github.com/madsmtm/objc2) +cadmpeg-codec-freecad 0.6.1: Apache-2.0 (https://github.com/cadmpeg/cadmpeg) +cadmpeg-codec-rhino 0.6.1: Apache-2.0 (https://github.com/cadmpeg/cadmpeg) +cadmpeg-codec-step 0.6.1: Apache-2.0 (https://github.com/cadmpeg/cadmpeg) +cadmpeg-container 0.6.1: Apache-2.0 (https://github.com/cadmpeg/cadmpeg) +cadmpeg-core 0.6.1: Apache-2.0 (https://github.com/cadmpeg/cadmpeg) +cadmpeg-ir 0.6.1: Apache-2.0 (https://github.com/cadmpeg/cadmpeg) +cadmpeg-registry 0.6.1: Apache-2.0 (https://github.com/cadmpeg/cadmpeg) clipboard-win 5.4.1: BSL-1.0 (https://github.com/DoumanAsh/clipboard-win) convert_case 0.4.0: MIT (https://github.com/rutrum/convert-case) dispatch 0.2.0: MIT (http://github.com/SSheldon/rust-dispatch) diff --git a/apps/solidcraft/src/main.rs b/apps/solidcraft/src/main.rs index c2c8cfee..0a43b95b 100644 --- a/apps/solidcraft/src/main.rs +++ b/apps/solidcraft/src/main.rs @@ -108,7 +108,7 @@ fn services(cc: &eframe::CreationContext<'_>) -> Services { let future = open_parent .clone() .add_filter( - "Designs, STEP, IGES and meshes", + "Designs, CAD files and meshes", &[ io::DESIGN_EXT, io::LEGACY_DESIGN_EXT, @@ -121,6 +121,10 @@ fn services(cc: &eframe::CreationContext<'_>) -> Services { "iges", "IGS", "IGES", + "FCStd", + "fcstd", + "3dm", + "3DM", "3mf", "3MF", "stl", @@ -136,6 +140,7 @@ fn services(cc: &eframe::CreationContext<'_>) -> Services { .add_filter("SolidCraft design (container or JSON)", &[io::DESIGN_EXT, io::LEGACY_DESIGN_EXT, "json"]) .add_filter("STEP", &["step", "stp", "STEP", "STP"]) .add_filter("IGES", &["igs", "iges", "IGS", "IGES"]) + .add_filter("FreeCAD and Rhino", &["FCStd", "fcstd", "3dm", "3DM"]) .add_filter("Mesh (3MF, STL, OBJ, glTF)", &["3mf", "3MF", "stl", "STL", "obj", "OBJ", "glb", "GLB", "gltf", "GLTF"]) .add_filter("Sketch drawings (DXF, SVG)", &["dxf", "DXF", "svg", "SVG"]) .add_filter("All files", &["*"]) diff --git a/crates/doc/src/format.rs b/crates/doc/src/format.rs index 16a4500a..284d9bf5 100644 --- a/crates/doc/src/format.rs +++ b/crates/doc/src/format.rs @@ -229,6 +229,10 @@ //! transformation: a link without `coupling` is a plain motion link, as it always was; 0.13.0 //! (which reads up to 22) asks for an update instead of keeping a gear's ratio when its radius //! changes. +//! Also under 23, an Import's `file` can name a FreeCAD `.FCStd` or Rhino `.3dm` file (#1435, +//! read through cadmpeg); its `step` is still the STEP text the file was restated as, so the +//! feature's fields are unchanged and version 22 designs need no transformation; 0.13.x asks +//! for an update before it meets these imports. use serde_json::Value; diff --git a/crates/engine/src/cmd/file.rs b/crates/engine/src/cmd/file.rs index 4424794d..6a05824d 100644 --- a/crates/engine/src/cmd/file.rs +++ b/crates/engine/src/cmd/file.rs @@ -20,11 +20,11 @@ pub static COMMANDS: &[CommandSpec] = &[ .icon("open") .key("Ctrl+O") .noundo() - .params("path: .solidcraft design, or a .step/.stp/.igs/.3mf/.stl/.obj/.glb/.gltf file (opens as a new design holding the file as a component named after it, as file.insert_step and file.insert_mesh make); up?: z|y for a STEP, IGES or glTF file (see file.insert_step and file.insert_mesh); names?: solid|product|instance for a STEP or IGES file (see file.insert_step)"), + .params("path: .solidcraft design, or a .step/.stp/.igs/.fcstd/.3dm/.3mf/.stl/.obj/.glb/.gltf file (STEP, IGES, FreeCAD, Rhino, 3MF, STL, OBJ or glTF; opens as a new design holding the file as a component named after it, as file.insert_step and file.insert_mesh make); up?: z|y for a STEP, IGES, FreeCAD, Rhino or glTF file (see file.insert_step and file.insert_mesh); names?: solid|product|instance for a STEP, IGES, FreeCAD or Rhino file (see file.insert_step)"), CommandSpec::new("file.insert_step", "Insert STEP", insert_step) .at("SOLID", "INSERT") .icon("import") - .params("path: .step/.stp file (its bodies join the design as an Import base feature in a new component named after the file, placed in the active component; an assembly's products become nested components, a repeated part one component with an occurrence per placement, all held as one rigid group until component.unlock → component, component_name, occurrence, subcomponents?, rigid_joints?); name? (the feature's and the component's); up?: z|y (default z: the file's axes are kept; y: the file has Y up, so the import's component is turned a quarter turn about X, Y becoming Z → stand_up: its occurrence); names?: solid|product|instance (what the bodies are named after: the solid's own name, else the product's (default); the name of the product (part) that holds the body; the name of the assembly occurrence (instance), else the product's)"), + .params("path: STEP, IGES, FreeCAD .FCStd or Rhino .3dm file (its bodies join the design as an Import base feature in a new component named after the file, placed in the active component; an assembly's products become nested components, a repeated part one component with an occurrence per placement, all held as one rigid group until component.unlock → component, component_name, occurrence, subcomponents?, rigid_joints?); name? (the feature's and the component's); up?: z|y (default z: the file's axes are kept; y: the file has Y up, so the import's component is turned a quarter turn about X, Y becoming Z → stand_up: its occurrence); names?: solid|product|instance (what the bodies are named after: the solid's own name, else the product's (default); the name of the product (part) that holds the body; the name of the assembly occurrence (instance), else the product's)"), CommandSpec::new("file.insert_mesh", "Insert Mesh", insert_mesh) .at("SOLID", "INSERT") .icon("import") @@ -215,7 +215,7 @@ fn insert_step(s: &mut Session, p: &Value) -> Result { let cmd = "file.insert_step"; let path = path_arg(p, cmd)?; if !solidcraft_io::is_step_path(path) { - return Err(bad(cmd, "only STEP files (.step, .stp) can be inserted")); + return Err(bad(cmd, "only STEP, IGES, FreeCAD and Rhino files (.step, .stp, .igs, .iges, .fcstd, .3dm) can be inserted")); } let options = step_options(p, cmd)?; add_step(s, path, str_(p, "name"), &options) diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index 8e188328..c39a5148 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -314,6 +314,8 @@ mod loft_cut; mod loft_ring; mod loft_spacing; mod mirror_planes; +#[cfg(not(target_arch = "wasm32"))] +mod native_cad_import; mod path_scope; mod primitive_points; mod rim_cut; diff --git a/crates/engine/src/tests/native_cad_import.rs b/crates/engine/src/tests/native_cad_import.rs new file mode 100644 index 00000000..0e0b2ce4 --- /dev/null +++ b/crates/engine/src/tests/native_cad_import.rs @@ -0,0 +1,94 @@ +//! FreeCAD and Rhino files (read through cadmpeg) go the same way as STEP files: a new rigid +//! component named after the file (#1426), with the `up` and `names` options (#1312). + +use serde_json::{Value, json}; + +use super::run; +use crate::*; + +const BLOCK_FCSTD: &[u8] = include_bytes!("../../../io/src/native_cad/fixtures/block.FCStd"); +const BLOCK_3DM: &[u8] = include_bytes!("../../../io/src/native_cad/fixtures/block.3dm"); + +/// `bytes` saved as `name` in a fresh temp directory. +fn file(tag: &str, name: &str, bytes: &[u8]) -> (std::path::PathBuf, String) { + let dir = std::env::temp_dir().join(format!("solidcraft-native-cad-{tag}-{}", std::process::id())); + std::fs::create_dir_all(&dir).unwrap(); + let path = dir.join(name); + std::fs::write(&path, bytes).unwrap(); + (dir, path.to_string_lossy().to_string()) +} + +fn extent(s: &Session) -> ([f64; 3], [f64; 3]) { + let b = crate::view::bounds(s); + ([b.min.x, b.min.y, b.min.z], [b.max.x, b.max.y, b.max.z]) +} + +fn near(a: [f64; 3], b: [f64; 3]) -> bool { + a.iter().zip(&b).all(|(x, y)| (x - y).abs() < 1e-6) +} + +fn volume(s: &mut Session) -> f64 { + run(s, "inspect.measure", json!({}))["total"]["volume_mm3"].as_f64().unwrap() +} + +fn body_names(s: &Session) -> Vec { + s.model.state().bodies.iter().map(|b| b.name.clone()).collect() +} + +#[test] +fn freecad_and_rhino_files_come_in_as_a_component_named_after_the_file() { + for (tag, name, bytes) in [("fc", "block.FCStd", BLOCK_FCSTD), ("rh", "block.3dm", BLOCK_3DM)] { + let (dir, path) = file(tag, name, bytes); + let mut s = Session::default(); + run(&mut s, "solid.box", json!({"length": 5, "width": 5, "height": 5, "corner": [100, 0, 0]})); + let r = run(&mut s, "file.insert_step", json!({"path": path})); + assert_eq!(r["component_name"], "block", "{name}: {r}"); + let feature = r["feature"].as_u64().unwrap(); + assert_eq!(s.doc.feature(feature).unwrap().kind.type_name(), "BaseFeature", "{name}"); + assert_eq!(s.doc.feature(feature).unwrap().component, r["component"].as_u64().unwrap(), "{name}"); + assert!((volume(&mut s) - (6000.0 + 125.0)).abs() < 1e-6, "{name}"); + // Rhino keeps the object's name; cadmpeg leaves FreeCAD's label out, so it is the file's. + assert!(body_names(&s).iter().any(|n| n == "Block" || n == "block"), "{name}: {:?}", body_names(&s)); + assert_eq!(s.active_component, 0, "{name}: the active component is unchanged"); + + // As written the block spans 10 × 20 × 30; up: y stands it up, (x, y, z) → (x, -z, y). + let mut d = Session::default(); + let r = run(&mut d, "doc.open", json!({"path": path})); + assert_eq!((r["features"].clone(), r["component_name"].clone()), (json!(1), json!("block")), "{name}: {r}"); + assert!(near(extent(&d).1, [10.0, 20.0, 30.0]), "{name}: {:?}", extent(&d)); + let mut d = Session::default(); + let r = run(&mut d, "file.insert_step", json!({"path": path, "up": "y"})); + assert_eq!(r["stand_up"], r["occurrence"], "{name}: {r}"); + let (lo, hi) = extent(&d); + assert!(near(lo, [0.0, -30.0, 0.0]) && near(hi, [10.0, 0.0, 20.0]), "{name}: stood up: {lo:?} {hi:?}"); + + // Every names choice is taken, and the body is named something. + for names in ["solid", "product", "instance"] { + let mut d = Session::default(); + run(&mut d, "file.insert_step", json!({"path": path, "names": names})); + let got = body_names(&d); + assert!(got.len() == 1 && !got[0].is_empty(), "{name} names={names}: {got:?}"); + } + let _ = std::fs::remove_dir_all(&dir); + } +} + +/// A broken file is refused with a message naming it, and the design is left as it was. +#[test] +fn a_broken_freecad_or_rhino_file_is_refused_cleanly() { + let mut cut = BLOCK_FCSTD[..BLOCK_FCSTD.len() / 2].to_vec(); + cut.extend_from_slice(b"garbage"); + for (tag, name, bytes) in + [("bad-fc", "broken.FCStd", cut.as_slice()), ("bad-rh", "broken.3dm", &BLOCK_3DM[..200]), ("acis", "cube.sat", b"700 0 1 0\n")] + { + let (dir, path) = file(tag, name, bytes); + let mut s = Session::default(); + run(&mut s, "solid.box", json!({"length": 5, "width": 5, "height": 5})); + let before = s.doc.clone(); + let e: Result = s.execute("file.insert_step", &json!({"path": path})); + let e = e.expect_err(name).to_string(); + assert!(!e.contains("internal"), "{name}: a clean error, not a caught panic: {e}"); + assert_eq!(s.doc, before, "{name}: the design is unchanged"); + let _ = std::fs::remove_dir_all(&dir); + } +} diff --git a/crates/io/Cargo.toml b/crates/io/Cargo.toml index fc9a7030..7afd3eeb 100644 --- a/crates/io/Cargo.toml +++ b/crates/io/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "solidcraft-io" -description = "SolidCraft file formats: designs (JSON), STL, OBJ, STEP, 3MF and glTF" +description = "SolidCraft file formats: designs (JSON), STL, OBJ, STEP, IGES, 3MF and glTF, and FreeCAD/Rhino import" version.workspace = true edition.workspace = true license.workspace = true @@ -19,3 +19,9 @@ gltf = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } sha2 = { workspace = true } + +# FreeCAD and Rhino import. Not in the browser build: it compiles the zstd C library. +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +cadmpeg-core = { workspace = true } +cadmpeg-ir = { workspace = true } +cadmpeg-registry = { workspace = true } diff --git a/crates/io/src/lib.rs b/crates/io/src/lib.rs index 8d1db8e9..be8ae3be 100644 --- a/crates/io/src/lib.rs +++ b/crates/io/src/lib.rs @@ -1,8 +1,8 @@ //! File formats. Designs use JSON or versioned containers (`.solidcraft`); the authoritative //! document rebuilds on load and optional display caches remain provisional. Bodies export -//! as STL (binary or ASCII), OBJ, STEP and 3MF, and assemblies as URDF ([`urdf()`]); STEP -//! files import as a base feature (see [`step_import_feature`]), 3MF and STL files as mesh bodies -//! (see [`mesh_import_feature`]). +//! as STL (binary or ASCII), OBJ, STEP and 3MF, and assemblies as URDF ([`urdf()`]); STEP, IGES, +//! FreeCAD and Rhino files import as a base feature (see [`step_import_feature`]), 3MF and +//! STL files as mesh bodies (see [`mesh_import_feature`]). #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] #![forbid(unsafe_code)] @@ -18,6 +18,8 @@ pub use design::{ write_design_container_with_thumbnail, }; mod legacy_dir; +mod native_cad; +pub use native_cad::{NATIVE_CAD_EXTS, is_native_cad_path, native_cad_to_step}; pub mod safe_write; mod sketch2d; mod svg; @@ -78,13 +80,14 @@ pub type Result = std::result::Result; /// Largest STEP file we read. pub const MAX_STEP_BYTES: usize = 512 << 20; -/// Is this a CAD exchange file read as an Import base feature: STEP (`.step` / `.stp`) or IGES -/// (`.igs` / `.iges`), any case? +/// Is this a CAD file read as an Import base feature: STEP (`.step` / `.stp`), IGES +/// (`.igs` / `.iges`) or a format read through cadmpeg ([`is_native_cad_path`]), any case? pub fn is_step_path(path: &str) -> bool { std::path::Path::new(path) .extension() .and_then(|e| e.to_str()) .is_some_and(|e| ["step", "stp", "igs", "iges"].iter().any(|x| e.eq_ignore_ascii_case(x))) + || is_native_cad_path(path) } /// Is this an IGES file name (`.igs` / `.iges`, any case)? @@ -162,11 +165,14 @@ pub fn step_import_feature_named(bytes: &[u8], file: &str, names: StepNames) -> if bytes.len() > MAX_STEP_BYTES { return Err(IoError::Invalid(format!("STEP file too large ({} MB, limit {} MB)", bytes.len() >> 20, MAX_STEP_BYTES >> 20))); } - // STEP is 7-bit text with escapes; tolerate stray 8-bit bytes. IGES is restated as STEP - // (the feature keeps that STEP text). - let text = String::from_utf8_lossy(bytes).into_owned(); - let (text, iges_warnings) = - if is_iges_path(file) { solidcraft_kernel::iges_to_step(&text).map_err(IoError::Invalid)? } else { (text, Vec::new()) }; + // STEP is 7-bit text with escapes; tolerate stray 8-bit bytes. IGES and the cadmpeg formats + // are restated as STEP (the feature keeps that STEP text). + let (text, iges_warnings) = if is_native_cad_path(file) { + native_cad_to_step(bytes, file).map_err(IoError::Invalid)? + } else { + let text = String::from_utf8_lossy(bytes).into_owned(); + if is_iges_path(file) { solidcraft_kernel::iges_to_step(&text).map_err(IoError::Invalid)? } else { (text, Vec::new()) } + }; let imp = solidcraft_kernel::step_import_shared(&text)?; let stem = std::path::Path::new(file) .file_stem() diff --git a/crates/io/src/native_cad.rs b/crates/io/src/native_cad.rs new file mode 100644 index 00000000..97aa26d5 --- /dev/null +++ b/crates/io/src/native_cad.rs @@ -0,0 +1,156 @@ +//! Other CAD formats read through [cadmpeg](https://github.com/cadmpeg/cadmpeg): FreeCAD +//! `.FCStd` and Rhino `.3dm`. cadmpeg decodes the file into its neutral model and writes that as +//! STEP, which the Import feature then reads and keeps like any STEP file. +//! +//! Only codecs for open formats are compiled in (the workspace enables cadmpeg-registry's +//! `fcstd`, `rhino` and `step` features alone). cadmpeg's codecs for commercial formats, and its +//! `sat` codec (a ShapeManager stream decoder that reads ACIS as one dialect), are not built. +//! +//! This module is the importer seam: the one place cadmpeg is called, returning STEP text plus +//! warnings. A cadmpeg-based STEP reader could be added here later and chosen by a setting, to +//! compare with our own STEP reader, without changing that reader. +//! +//! cadmpeg is not built for the browser (it compiles the zstd C library); there these formats +//! return "not supported in the browser yet". + +/// File extensions read through cadmpeg (lower case). +pub const NATIVE_CAD_EXTS: [&str; 2] = ["fcstd", "3dm"]; + +/// Is this a FreeCAD or Rhino file name (any case)? +pub fn is_native_cad_path(path: &str) -> bool { + std::path::Path::new(path).extension().and_then(|e| e.to_str()).is_some_and(|e| NATIVE_CAD_EXTS.iter().any(|x| e.eq_ignore_ascii_case(x))) +} + +/// Restate a FreeCAD or Rhino file (`file` is its name) as STEP text, with the losses +/// and warnings cadmpeg reported. Panics inside cadmpeg become errors. +#[cfg(not(target_arch = "wasm32"))] +pub fn native_cad_to_step(bytes: &[u8], file: &str) -> Result<(String, Vec), String> { + let name = std::path::Path::new(file).file_name().map(|s| s.to_string_lossy().to_string()).unwrap_or_else(|| file.to_string()); + solidcraft_kernel::guard("cadmpeg import", || convert::to_step(&name, bytes).map_err(solidcraft_kernel::KernelError::Invalid)).map_err( + |e| match e { + solidcraft_kernel::KernelError::Invalid(m) => m, + e => e.to_string(), + }, + ) +} + +/// Restate a FreeCAD or Rhino file as STEP: not available in the browser yet. +#[cfg(target_arch = "wasm32")] +pub fn native_cad_to_step(_bytes: &[u8], file: &str) -> Result<(String, Vec), String> { + Err(format!("{file}: not supported in the browser yet (FreeCAD and Rhino files open in the desktop app)")) +} + +#[cfg(not(target_arch = "wasm32"))] +mod convert { + use std::io::Cursor; + + use cadmpeg_core::decode::{DecodeArena, DecodeContext, DecodeMode, DecodePolicy, ResourceLimits, View}; + use cadmpeg_ir::codec::write::{EncodeInput, target::TargetRequest}; + use cadmpeg_ir::codec::{DecodeFailure, DecodeOptions, DecodeResult}; + use cadmpeg_ir::validate::validate_neutral_for_decode; + use cadmpeg_registry::{DETECTION_PREFIX_LEN, Format, InputCatalog, ResolveSourceError, ResolvedSource, build_encoder, forced_input}; + + /// The codecs we accept (cadmpeg codec ids), whatever else the registry recognises. + const ACCEPTED: [&str; 2] = ["fcstd", "rhino"]; + + /// Caps for hostile input: cadmpeg's tight `service` profile, with our STEP size limit. + pub(super) fn policy() -> DecodePolicy { + DecodePolicy { + mode: DecodeMode::Salvage, + limits: ResourceLimits { max_input_bytes: crate::MAX_STEP_BYTES as u64, ..ResourceLimits::service() }, + } + } + + /// Decode `bytes` (a file called `name`, extension `ext`) with the codec cadmpeg detects from + /// the bytes, else the one the extension names, if it is one of `accepted`. Returns the codec id + /// and the decoded model. + pub(super) fn decode(name: &str, ext: &str, bytes: &[u8], accepted: &[&str]) -> Result<(String, DecodeResult), String> { + let policy = policy(); + let catalog = InputCatalog::with_builtins(); + let codec = { + let arena = DecodeArena::new(); + let (ctx, _) = DecodeContext::from_root_bytes(&[], &arena, &policy).map_err(|e| e.to_string())?; + let prefix = bytes.get(..DETECTION_PREFIX_LEN).unwrap_or(bytes); + let resolved = catalog.resolve_seekable_source(&ctx, View::over_retained(prefix), &mut Cursor::new(bytes), None); + let resolved = match resolved { + Ok(ResolvedSource::Unrecognized | ResolvedSource::Cadir) | Err(ResolveSourceError::Ambiguous(_)) => { + match forced_input(ext).map_err(|e| e.to_string())? { + Some(forced) => catalog.resolve_source(&ctx, View::over_retained(prefix), Some(forced)), + None => Ok(ResolvedSource::Unrecognized), + } + } + other => other, + }; + ctx.finish_session().map_err(|e| e.to_string())?; + match resolved.map_err(|e| format!("{name}: {e}"))? { + ResolvedSource::Native { codec, .. } => codec, + _ => return Err(format!("{name}: unrecognised file contents")), + } + }; + let format = codec.id().as_str().to_string(); + if !accepted.contains(&format.as_str()) { + return Err(format!("{name}: {format} files are not supported (FreeCAD .FCStd and Rhino .3dm only)")); + } + + // Decode in memory under the caps. + let options = DecodeOptions { container_only: false, policy }; + let decoded = codec.decode(&mut Cursor::new(bytes), &options).map_err(|e| match e { + DecodeFailure::Codec(e) => format!("{name}: could not read this {format} file: {e}"), + other => format!("{name}: {other}"), + })?; + Ok((format, decoded)) + } + + pub(super) fn to_step(name: &str, bytes: &[u8]) -> Result<(String, Vec), String> { + let ext = name.rsplit_once('.').map(|(_, e)| e.to_ascii_lowercase()).unwrap_or_default(); + if !super::NATIVE_CAD_EXTS.contains(&ext.as_str()) { + return Err(format!("{name}: not supported (FreeCAD .FCStd and Rhino .3dm only)")); + } + let (format, decoded) = decode(name, &ext, bytes, &ACCEPTED)?; + let policy = policy(); + let (ir, report, fidelity) = decoded.into_parts(); + if !report.geometry_transferred() { + return Err(format!("{name}: no geometry could be read from this {format} file")); + } + let mut warnings: Vec = report.losses.iter().map(|l| format!("{}: {}", l.code, l.message)).collect(); + + // Validate the neutral model, as cadmpeg's own conversion does. + let arena = DecodeArena::new(); + let ctx = DecodeContext::for_loaded_input(&arena, &policy, bytes.len() as u64).map_err(|e| e.to_string())?; + let validation = validate_neutral_for_decode(&ctx, &ir, Vec::new()).map_err(|e| e.to_string())?; + ctx.finish_session().map_err(|e| e.to_string())?; + warnings.extend(validation.findings.iter().map(|f| format!("{}: {}", f.severity, f.message))); + if !validation.is_ok() { + return Err(format!("{name}: the {format} model is invalid ({} errors)", validation.error_count())); + } + + // Write it as STEP AP214. + let plan = build_encoder(Format::Step) + .plan(EncodeInput::new(&ir, Some(&fidelity)), TargetRequest::Explicit("ap214")) + .map_err(|e| format!("{name}: could not restate as STEP: {e}"))?; + let losses = &plan.report().losses; + if losses.iter().any(|l| l.code.to_string() == "step/export.no-exportable-solids") { + return Err(format!("{name}: this {format} file has no solids that can be imported")); + } + warnings.extend(losses.iter().map(|l| format!("{}: {}", l.code, l.message))); + let mut out = Vec::new(); + plan.write_to(&mut out).map_err(|e| e.to_string())?; + let step = String::from_utf8(out).map_err(|e| e.to_string())?; + Ok((super::name_unnamed_products(step, name), warnings)) + } +} + +/// cadmpeg's STEP writer calls a product it has no name for `cadmpeg_model`; name it after the +/// file instead (as plain STEP text: letters, digits, spaces, `-`, `_` and `.` only). +#[cfg(not(target_arch = "wasm32"))] +fn name_unnamed_products(step: String, file: &str) -> String { + const PLACEHOLDER: &str = "'cadmpeg_model'"; + let stem: String = std::path::Path::new(file) + .file_stem() + .map(|s| s.to_string_lossy().chars().filter(|c| c.is_ascii_alphanumeric() || matches!(c, ' ' | '-' | '_' | '.')).collect()) + .unwrap_or_default(); + if stem.trim().is_empty() || !step.contains(PLACEHOLDER) { step } else { step.replace(PLACEHOLDER, &format!("'{stem}'")) } +} + +#[cfg(test)] +mod tests; diff --git a/crates/io/src/native_cad/fixtures/block.3dm b/crates/io/src/native_cad/fixtures/block.3dm new file mode 100644 index 0000000000000000000000000000000000000000..715f1f05a5d1f9651870f2db62392521eba4800d GIT binary patch literal 19497 zcmeHPeT*DOmG3o)&BT{u9fHZ{FSrw zUG=)FtGhir+?q?Il+;^Y@4Mc6^{TpOW((8Vtxl`qc%Av|mRjA(ZfSKIwwD!cd}P2d zjN9l!%kJzpy;{RrpS@xG`t@?Kxw)s-X*C;8(_6p(x>~clFI$+tKD#YJUTQX>Nb#&W-QLdaYJ{cg@T0aXN0T)y(FL`E{d(LSb|)d*y7a(Iy)zS%SaAX=g{* zW%DEXu{GyhWSnmpgP#&+7?&Hy!LuIx&_^)5V!_B>BH`yyKV#I5mN9GWHr5&iqhd4& zcH6=gU%ZUyZj^L`=rOU2=sJ(C*U^=s>-}_{Mc12vq}GcD_{WbtvGNo(pMn0ofebx< zwiu0)(g}&EQooF@KOFkcr>>vbF*W(AouA!u?Eb0uo&VLX&+Wf!3S_TQ@EE)2ee3Kz z$@mxs)JV2y(mo#gy}9XuZN7lTSB~X9KvFXdk z5@6#AFv_Nb%sNT;K73+Lt~lfas7%|af$XTB_VGv3)qgbh~T%Uuw-NHL;rBk)c{VBk!vJY=13T} zErh@_W3A}#I`QQ5`GL?w1?9eYyOG@>C-g=k^yC!Wg?sLiPGx}%ruC;R-06#Uu8?AS zcck;9icZ-0)TM<_fA4q4PjTN{h)TguVwgT=c<=t+pMT+y0jI2zwD7Xua5M9}Ti^Tg zD@oG8GuHif>z6+q|N))kljf$*P~_&3SkPkMDC3=jL0Q&{%X zhGSF>+vw8P>d|-rOlSe&&dR+XxMTaahab9j#fJLo_y1FXkT-sr<|-eg5RiY@{<)+H zyWP*dYuBj*%N9b2vOo!VL5ia;Oo3-p;I#8624W}$epw3q^#m`E2y5FEpeyD5-x$Un zJZS{$a8A&u!FuA^Z@%X}|3<<3r3lu?Z#;Yi!Mb147O?mpI#)0b(#-v`1ZlSmn4wC0 z_UKQyZ&gD7-=943W=Pv6Y1tY%)Vtxb4vCJ3%cxE7JNTvh)$kym|3`z;6f?Y3jvB(F zl5fzV?LU0_3>lQJm`#ZG!b8g&t3I&A2C^ydc4AK=A%Q_@FF8U$+ z@Qwd`#S$BorkLSro)aEg`N@l)IYS1eD~@`GN5Vrpw|!x1i49@}X$CP~@Bi#M#LHec zgvYPeA@)RCC||8ZyzJRidjD!2VvnTd(5rRmWt&531yU^gX7L8|7|bhkVefh3=y)Qee;*&OY9*I zRk~u`6fqVa`q7vE@rO%n5UWcwi1B(aJk)&TzNTu>W!IfJiifqIEEn|tqvaAj8|m74 z%*gZxz)`;$@fi>BY%M zqjdbSqzV;h2Nhx%rSe%(z#>NMAr7U^qQgt&xd)$oLG|9t+)?686P=doD1CxVsl#vo?!aK86$d~p0Nxsm3Q3oiGf#;qk3hOK0zLHA5NSh zi|b3}|9brX6|Znd4KJcbai*oYg&oLvrVrsSJd(FxL5@mVdd1T?ifa)&fG5syb_nBj zcu2qFyU&iOj>>%Y+a|WcLvq&}RKFd;;?$mZI`k^7^o~B?omr_(FzgY#Wb59?+=sS=n|Tk06P-|^f_-z8!m$mSG*N{93OAs zG<@SMxrv$?23VyM*$>-+htv5x87h^y7f&VepaUx&5O4=M_~JtPr@~@&B`1O?Q3wvt zjn91q(%NttbhzTJ=;IJD$Uz@`r6fjNECY`#-iCb~f(|)Imep}02^lVfE}ld{7kwP& z3^{*Em;AO6-RZ69e=SN~03n5_CM*ZBke}j*B*9&&j0K@CiU38&Rpb@>8TZL{gQHZ& zyw!yQsA%F-JoYo>sf&ZDm=?HXyjYa%XV{EyPbRlg`Rko)?lu-^(aCSf_+Md2CLS&` zoEH)Tkeqx>$$iMn5WVMbQgII*tS6)ufdHJ76*lmFNSAcS+eZ>kz*sl;kc}(a!i9yo z!xqpaCw-JNX&2EcSU2}b%y^+F`H9WGXB*;lx^#^D_XG5>u27;VoU9vg_t%a-+t9xsk_)3)7p$LSf_&(0 zL;rq2L5&wxu>oT4oQJqaKA=B+>%TrE7vxeIMG^YB2tzmg(%Xjq{g7PD!;KEP!m+@8 zZyWmeL-Ix-)&=Wi8{n7THuUcY>>d0KOS+X!9Ar2b0EBMjg9-yY-uhn`*u3K#xTuqm z&-Dv7ARl_$(7zvW7{L{7;eiD?$+19edfU*yAF$cSH+-=!pdUKf2Hf|yp?^Q%z#2ca zh6h{K2E>J9L$@ide?Q>x9Y26a59#a&yMu9?&LJ2(Mz>mU(!hwa0 zg#$e6M2|#9A|a4)B=E53-#>l+DuX8VBHg2%#~B3zy#c0PjEC0&M~{me3R$hVv52K;qL zzn8pkZ*yDj8|~cfhLO!kVP_G+OO%h+zDB)t?l~E&<1{Ny$DD07J^D$f*|3}T9E~fj z*)D$L37U*0vHl=qIpI%0a{`}J39O1!wYzmMkm)+J9{u!F(z=f4)tYmz6xOsGPQ~0) zbM{I|#-d-4k|C{%llA7?&NV}>*CB=>!Jn~mF&0ZeX4`eU>GUZk!XyQ?TW$>&_bEza zlfvAl-FA1iygr3#Y*wS@&N_8Wu+e>sYzdkc()L?;AFp?{r8Yyh=f=*K7FYuIYB$5Y5UnR;|&dNF^x}7%4MjwQbkq zU`7n`5v)45Xx&yW!5fydZ?@j8P%_DscA9fFB^|omTE$JtsME4q)mq)7UoW$rzFPz= zQC!9kyeTNmT9bbHoaiJ)j-+A@lrDSCZqs(%+FX++L_g4WIyH)6#MfS@OEFEQjR@OQ z>@7s4i7@Y~RVq$1MSx5#-wd5FBBkS09g57Xvj{;6v_h7Ziv+`>CFhw=wMrGnHJi>} z*67%s`n)U{8Ov)mp|#znG7?v+2}1B{CK*5stB}R;A*) z!iLEWqnpgh!pOK;oE#rBH|8huW^wa|>EiUd!sNvG!{BtIg8Fpt8xv=8~>wCg04{;5MkK1B%FB*~^_pv<8F$<%Z}>DqPw zY|&{^0;DQSCQK2NtXvZjhOdUh5}gs|VuF3o(XL~Aubu_kwyU7>Owz~d}B1#?#H z`Fd?`muI^69&)&zaMD9@sxBI;xh)oS>JpHC`!R%?c}0GONB83C7lInSB%s+HBLAy26$$Y zB`0N7C|G9TClZ+m(I<2|a69|FZbv+lN|HUa@>-od9nVJJilVMiuuz7zs@3oTHsl+5 zD@`{_qjPpz9vy>&7z8OF@-YQ-3SDNsH5*N8t{%QAKAJf?PTR4)IESdY3RW=C`Abg| zN+tCjh{et{qc2L7*DM-_ouJb5$t-y5LWdXqO%AOZ|E&*RCaG_mPSGnW{s4B(b-)_N F{{rbkf#?7L literal 0 HcmV?d00001 diff --git a/crates/io/src/native_cad/fixtures/block.FCStd b/crates/io/src/native_cad/fixtures/block.FCStd new file mode 100644 index 0000000000000000000000000000000000000000..9b06266a016f01e67d050acc15008c088acbd716 GIT binary patch literal 2485 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 = (0..good.len()).step_by((good.len() / 60).max(1)).map(|n| good[..n].to_vec()).collect(); + for i in (0..good.len()).step_by((good.len() / 80).max(1)) { + let mut b = good.to_vec(); + b[i] ^= 0x5a; + cases.push(b); + let mut b = good.to_vec(); + b[i] = 0xff; + cases.push(b); + } + let mut tail = good.to_vec(); + tail.extend((0..4096u32).map(|i| (i.wrapping_mul(2_654_435_761) >> 24) as u8)); + cases.push(tail); + cases.push(good.iter().rev().copied().collect()); + for (i, bytes) in cases.iter().enumerate() { + let r = std::panic::catch_unwind(|| crate::step_import_feature(bytes, name)); + assert!(r.is_ok(), "{name}: case {i} panicked"); + } + } +} + +/// cadmpeg decodes under its tight `service` caps, with our STEP size limit on the input. +#[test] +fn decoding_is_capped() { + let limits = convert::policy().limits; + let service = cadmpeg_core::decode::ResourceLimits::service(); + assert_eq!(limits.max_input_bytes, crate::MAX_STEP_BYTES as u64); + assert_eq!(cadmpeg_core::decode::ResourceLimits { max_input_bytes: service.max_input_bytes, ..limits }, service); +} + +/// A FreeCAD archive whose Document.xml inflates past the per-entry cap (a ZIP bomb, 300 MB of +/// zeros in a few hundred KB) is refused. +#[test] +fn a_zip_bomb_is_refused() { + use std::io::Write; + let mut zip = zip::ZipWriter::new(std::io::Cursor::new(Vec::new())); + zip.start_file("Document.xml", zip::write::SimpleFileOptions::default().large_file(true)).unwrap(); + let zeros = vec![0u8; 1 << 20]; + for _ in 0..300 { + zip.write_all(&zeros).unwrap(); + } + let bytes = zip.finish().unwrap().into_inner(); + assert!(bytes.len() < 2 << 20, "{} bytes", bytes.len()); + assert!(native_cad_to_step(&bytes, "bomb.FCStd").is_err()); +} diff --git a/crates/ui-egui/src/file_load.rs b/crates/ui-egui/src/file_load.rs index 6c37a472..49462e5e 100644 --- a/crates/ui-egui/src/file_load.rs +++ b/crates/ui-egui/src/file_load.rs @@ -125,11 +125,15 @@ const STAGED_THUMBNAIL_TRIANGLES: usize = 1_000_000; /// How long a frame spends on a staged STEP import. const STAGED_FRAME_MS: f64 = 30.0; -/// Files read in stages: STEP (not IGES, which is first restated as STEP) to insert or open. +/// Files read in stages: STEP (not IGES, FreeCAD or Rhino, which are first restated as STEP) to +/// insert or open. #[cfg_attr(not(target_arch = "wasm32"), allow(dead_code))] fn staged_kind(request: &Request) -> bool { let p = &request.path; - matches!(request.kind, Kind::Insert | Kind::Open) && solidcraft_engine::io::is_step_path(p) && !solidcraft_engine::io::is_iges_path(p) + matches!(request.kind, Kind::Insert | Kind::Open) + && solidcraft_engine::io::is_step_path(p) + && !solidcraft_engine::io::is_iges_path(p) + && !solidcraft_engine::io::is_native_cad_path(p) } impl Running { diff --git a/docs/book/src/guide/files.md b/docs/book/src/guide/files.md index 990719fe..d2c2900d 100644 --- a/docs/book/src/guide/files.md +++ b/docs/book/src/guide/files.md @@ -6,6 +6,7 @@ | `.json` (self-contained plain JSON design) | yes | yes | | STEP (AP203, AP214, AP242) | solids, assemblies, units, names, colours | AP242 with names, colours and the component tree | | IGES 5.3 | manifold solids, or trimmed surfaces sewn into solids | manifold solids with names and colours | +| FreeCAD `.FCStd`, Rhino `.3dm` | solids, through cadmpeg (desktop app only) | | | 3MF, STL, OBJ | mesh bodies | yes | | glTF 2.0 (`.glb`, `.gltf` with its `.bin` files) | mesh bodies in the node tree's components, materials as appearances | | | 3MF with face tags | as 3MF | each triangle tagged with its B-rep face, exact coordinates | @@ -13,7 +14,7 @@ | DXF, SVG | into a sketch | sketches and flat patterns as DXF | | PNG, JPEG | canvases and decals | | -Opening a STEP or IGES file creates a design with the file's bodies as a base feature, and +Opening a STEP, IGES, FreeCAD or Rhino file creates a design with the file's bodies as a base feature, and inserting one adds them to the current design. Later features build on them. Mesh bodies render, measure, move and export, but solid features need B-rep bodies. diff --git a/docs/step-import.md b/docs/step-import.md index 019722f2..3dcca34d 100644 --- a/docs/step-import.md +++ b/docs/step-import.md @@ -39,3 +39,9 @@ display on the resulting body. ## IGES IGES 5.3 files (`.igs`/`.iges`) open, insert and drop the same way: `crates/kernel/src/iges_in.rs` (written from the published specification) restates the file as STEP and the STEP reader reads it, so the feature holds STEP text. Read: manifold solid B-reps (186) with their shells, faces, loops, edge and vertex lists; trimmed (144) and bounded (143) surfaces, and bare B-spline patches, sewn into a solid by their shared edges (an open body when they do not close); lines, circular arcs, ellipses, composite curves, rational B-spline curves; planes (108, 190), cylinders, cones, spheres, tori, rational B-spline surfaces, surfaces of revolution and tabulated cylinders; transformation matrices; units; colours (314 and the predefined numbers); body names (name properties, else labels). Not read yet: ruled and offset surfaces, curves on surfaces given only in parameter space. Export (`file.export` to `.igs`) writes each body as a manifold solid B-rep on the same surfaces a STEP export uses, with its name and colour. + +## FreeCAD and Rhino + +FreeCAD `.FCStd` and Rhino `.3dm` files open, insert and drop the same way, in the desktop app and the CLI. They are read with [cadmpeg](https://github.com/cadmpeg/cadmpeg) (Apache-2.0, `crates/io/src/native_cad.rs`): cadmpeg detects the format from the bytes, decodes it into its neutral model under resource caps, checks that model and writes it as STEP AP214, which the STEP reader then reads. The feature holds that STEP text, so the design reopens without the original file. The file's solids come in; its feature history, sketches and parameters do not. Losses cadmpeg reports become warnings on the feature, and a file without an importable solid is refused with a message. cadmpeg runs inside the panic guard. How much of a file is read follows cadmpeg's support for that format ([format support](https://github.com/cadmpeg/cadmpeg/blob/main/docs/format-support.md)). + +Only codecs for open formats are compiled in: the workspace turns off cadmpeg's default features and enables `fcstd`, `rhino` and `step` (the writer). cadmpeg's codecs for commercial CAD formats are not built, and neither is its `sat` codec, which decodes ShapeManager streams with ACIS as one dialect, so ACIS `.sat`/`.sab` files are not read yet. `crates/io/src/native_cad.rs` is the one place cadmpeg is called; a cadmpeg-based STEP reader could be added there later behind a setting, to compare with the STEP reader above without changing it. The browser app does not read these formats yet: cadmpeg compiles the zstd C library, which the wasm build leaves out. diff --git a/xtask/src/assets.rs b/xtask/src/assets.rs index e2467f9d..9d03f9ef 100644 --- a/xtask/src/assets.rs +++ b/xtask/src/assets.rs @@ -30,6 +30,8 @@ const ASSET_EXT: &[&str] = &[ "step", "stp", "obj", + "fcstd", + "3dm", ]; fn walk(dir: &Path, root: &Path, out: &mut Vec) -> Result<(), String> {