Commit Graph

20 Commits

Author SHA1 Message Date
Brandon Thomas fc45b7f6d8 Release 0.6.1: rebuild with the fixed shared release workflow
The previous release build failed in craft-common-actions, not in this
repo: riscv64 packaging got --formats deb,rpm,tar (fixed in
craft-common-actions#3), Linux jobs lacked the ALSA headers
(craft-common-actions#5), and Windows signing needed the AZURE_* secrets
listed in the caller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 11:11:15 -04:00
Brandon Thomas b3acae6b77 Release prep: 0.6.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 05:44:31 -04:00
lloyd 70d857a699 XLSX: decrypt Agile and Standard encrypted packages (#11)
Clean-room from [MS-OFFCRYPTO]: EncryptionInfo parsing, SHA-1/SHA-2 key
derivation with a capped spin count, AES-ECB/CBC. RC4, Extensible and
certificate-only encryption are reported as unsupported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:29:28 +02:00
Brandon Thomas e211f666a6 Merge main into installed-fonts: workbook fonts bind on top of main's per-language font set and fallback faces; only families that survive drop_unparseable_fonts count as bound; a language switch rebinds them (review fix-up for #9)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:38:42 -04:00
Brandon Thomas 2af0984af0 Merge pull request #308 from vangel76/feat/review-allow-edit-ranges
Review: Allow Edit Ranges with Excel-compatible password hashes (#307)

# Conflicts:
#	ROADMAP.md
#	crates/xlsx/src/sheet_write.rs
#	crates/xlsx/src/tests/malformed.rs
#	docs/file-format-parity.md
#	docs/gaps.md
#	docs/parity-checklist.md
#	docs/target-app-parity.md
2026-10-11 12:05:30 -04:00
Brandon Thomas 331a535d3c Merge pull request #277 from vangel76/fix/linux-font-panic
UI: skip system fonts egui can't parse instead of panicking at startup (#226)
2026-10-11 11:24:38 -04:00
vangel76 3b918ada2c Review: Allow Edit Ranges with Excel-compatible password hashes (#307)
- Model: Sheet.edit_ranges (title, ranges, optional password hash,
  security descriptor) and gridcraft_model::password: the ECMA-376 legacy
  16-bit hash and the salted, iterated SHA-2 hash (SHA-512/384/256; other
  algorithms, damaged hashes and spin counts over 10,000,000 are refused).
  New passwords use SHA-512, spin count 100000. Adds the sha2 crate.
- XLSX: <protectedRanges> read and written; an unreadable password keeps
  the range locked.
- review.allowEditRanges {action: list|add|modify|delete|unlock, ...}: empty
  params list; ranges can't change while the sheet is protected; unlock
  verifies the password for the session. Not journaled (passwords).
- Locked-cell checks (commit guard, cell.set, picture in cell) let edits
  through in open or unlocked ranges; ranges move with structural edits.
- Ribbon button and a form dialog (menu invocation only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:26:14 +02:00
vangel76 573cf92745 UI: skip system fonts egui can't parse instead of panicking at startup (#226)
epaint panics in set_fonts on a face skrifa can't open. Every system font
file is now checked with the same skrifa call (plus a readable cmap)
before it reaches FontDefinitions; a bad candidate is skipped with a
warning and the next one is tried, and a final pass drops any remaining
unparseable face from the definitions and every family.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:55:32 +02:00
pkibiego 2f078962a0 xlsx: bump quick-xml to 0.41 for the namespace-declaration DoS (RUSTSEC-2026-0195)
The ODS and XLSB readers parse untrusted package metadata and content through
`quick_xml::NsReader`. In 0.38.4 that is RUSTSEC-2026-0195 (CVSS 7.5): the namespace
resolver pushes a binding for every `xmlns` / `xmlns:*` declaration on a start tag, with
no cap on how many there are, and `NsReader::read_event` reaches that path - not only
`read_resolved_event`.

None of our caps bound it. MAX_PART (512 MiB), MAX_TOTAL (1 GiB), MAX_ENTRIES,
MAX_CELLS, MAX_TEXT and MAX_DEPTH bound part size, entry count, cells, text and nesting,
never declarations per tag.

Measured with `gridcraft-cli info` on crafted .ods files, before this change:

     754 B, 0 declarations  ->    8.6 MB, exit 0
     24 KB, 1,000,000       ->   52.6 MB, exit 0
    187 KB, 8,000,000       ->  367.8 MB, exit 0
    770 KB, 33,000,000      ->    1.46 GB, exit 0

About 45 bytes of resident memory per declaration, roughly 1,900x the file size, and no
error at all. At MAX_PART a ~1 MB file reaches ~1.9 GB, and every part is held in memory
while the package is read. Both readers share the path, so a downloaded .ods or .xlsb
was enough. Nothing panicked, so `Session::execute` never saw it.

0.41.0 caps declarations per start tag at 256 (DEFAULT_MAX_DECLARATIONS_PER_ELEMENT,
raisable through NamespaceResolver::set_max_declarations_per_element) and returns
`NamespaceError::TooManyDeclarations` beyond it. The same fixtures after:

     754 B ->    8.6 MB, ok         24 KB ->   19 MB, error
    187 KB ->  101.8 MB, error     770 KB ->    397 MB, error

with "start tag declares more than 256 namespace bindings". The residual peak is the
part itself: MAX_PART still lets one part decompress to 256 MiB, the existing intended
bound.

API changes for 0.41 (0.x bumps may break; all four are in the xlsx crate):
- `resolve_element` and `resolve_attribute` moved off `NsReader` on to the resolver:
  `reader.resolver_mut().resolve_element(..)`. `attr` and `tag` in ods.rs take
  `&mut NsReader` for that.
- `Attribute::unescape_value` is deprecated in favour of `normalized_value`, which also
  applies the attribute-value normalization the XML specification requires.
- `BytesText::xml_content` now takes the document's XML version.

This also clears RUSTSEC-2026-0194, the quadratic duplicate-attribute check. xml.rs
already passed `with_checks(false)`, but ods.rs and xlsb.rs used the checked iterator, so
they were on the quadratic path as well.

Regression test: `ods_tests::ods_namespace_declaration_bomb_is_rejected` asserts that a
tag with thousands of declarations is an error and that a document with a handful still
reads. It fails on 0.38.4 (the tag is accepted) and passes on 0.41.0.

Verified: `cargo xtask ci`; the full xlsx suite (80 tests) plus the malformed-input
tests; and the four measurements above, before and after, with no panics either way.
2026-10-11 03:39:32 +03:00
Brandon Thomas 9f896c1249
Bump version to 0.5.0 for release (#227)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:10:53 -04:00
Brandon Thomas 277f01265b Merge fixed #38 (font fallback) into feat/i18n-language
# Conflicts:
#	crates/ui-egui/src/grid.rs
#	crates/ui-egui/src/ribbon.rs
#	crates/ui-egui/src/widgets.rs
2026-10-10 12:31:57 -04:00
Brandon Thomas 13664fe66b Bump version to 0.4.0 (from 0.3.0) for release; refresh contributors
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:02:14 -04:00
justinjohn0306 e8e010b446 i18n: switch the interface language (issue #20)
Add an interface-language preference. It defaults to the system's
language on first run (sys-locale, native only) and is switched by hand
from the View tab, next to Dark Mode, or with app.language.english /
app.language.japanese over the control channel. It is saved in ui.json.

Follows the filmcraft house convention: a Language enum and a
table of English-to-Japanese strings with English fallback, so coverage
can grow incrementally. Japanese chrome renders without any bundled
font: the CJK fallback faces already appended to every family cover
kana and kanji.

The ribbon chrome all flows through the small_button/big_button/
toggle_button/split_button/icon_button helpers and menu_items, so
translating there localises the whole ribbon in one place; the language
of the frame is read from egui context data (i18n::current). Command
ids, file names and document text are never translated.
2026-10-09 13:14:48 +05:30
Brandon Thomas fb823899c5 Bump version to 0.3.0 (from 0.2.0) for release
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:02:29 -04:00
Brandon Thomas a3cbb9b9a7 Bump version to 0.2.0 (from 0.1.0) for release
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 08:13:30 -04:00
justinjohn0306 f654615640 Fix: list and render installed system fonts (#4)
The font dropdown showed a hardcoded 17-name list and cells always
rendered in the built-in Calibri/role font, so a font installed on the
machine could not be listed or chosen. Both trace to one constraint:
egui panics when asked for a FontFamily::Name that was never bound to
font data, so only the 8 built-in roles were ever bound.

Scan the platform font folders for installed families (a bounded read of
each file's name table via skrifa, already compiled transitively through
epaint), bind the faces a workbook actually uses into egui as
fnt:{family}:{b|n}{i|n} roles chained to the defaults, and offer the
installed families in the font combos after the standard set. cell_family
returns the installed role when it is bound, else the previous bucketing,
so it never names an unbound family. The scan runs in the background and
the first frame that rebinds skips painting, like the existing startup
gate. Native only; wasm keeps the standard list.

Incidental: newer local clippy flagged pre-existing lints in untouched
crates (no toolchain is pinned); fixed behavior-preservingly so the gate
passes.
2026-10-08 16:04:14 +05:30
Brandon Thomas 488e12de31 Rename SheetCraft to GridCraft everywhere (crates, apps, bundle ids, packaging, docs)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 01:39:08 -04:00
Brandon Thomas 168b8ec8b7 M4–M10: PivotTables, PDF export & printing, what-if analysis, spelling, more commands
- PivotTables: engine (grouping, date groups, multiple values, show-as, filters, layouts,
  refresh, recommended pivots) + PivotTable Fields task pane
- sheetcraft-pdf (dependency-free PDF writer, core-14 fonts) + file.exportPdf/print/
  printPreview/pageLayout.pageSetup with pagination, headers/footers, charts, images
- What-if: Goal Seek, Scenario Manager, data tables, advanced filter, consolidate
- Page Break Preview rendering; view mode buttons
- Spelling (system dictionary), icons library, cell checkboxes, recorded scripts,
  chart design/format commands, arrange, custom views, watch window, Get Data from CSV/JSON
- Native macOS menu bar
- UI interaction tests (kittest): fixed arrow keys losing grid focus and Escape not cancelling
- Perf: FxHash in calc, sparse range reads, Arc'd formula ASTs, fast auto row heights
- Parity 254/290 (87.6%)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 01:04:46 -04:00
Brandon Thomas beb353943e M1: Excel-style egui UI, desktop app, chart renderer, MCP server, CLI, release packaging
- ui-egui: title bar with QAT, full ribbon (Home/Insert/Draw/Page Layout/Formulas/Data/
  Review/View/Automate + Table/Chart Design), formula bar with Name Box, virtualised grid
  (frozen panes, overflow, borders, CF data bars/scales/icons, tables, sparklines, filter
  buttons, charts/pictures/shapes), in-cell editor with point mode, reference colouring,
  autocomplete and argument hints, sheet tabs, status bar, dialogs, control channel
- apps/sheetcraft: desktop app (control server, file dialogs, prefs, drag & drop)
- chart: toolkit-free chart layout/rendering for 25 chart kinds + sparklines + rasteriser
- mcp + sheetcraft-cli: MCP server (headless or bridged) and CLI (info/convert/eval/cat/run/mcp)
- xtask (ci/layers/assets/wasm/version/parity), release workflows, packaging, placeholder icon
- automatic row heights

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 00:00:15 -04:00
Brandon Thomas 1ba9daa263 M0: foundation — core, numfmt, formula, functions (478), model, calc, xlsx/csv, engine
Clean-room spreadsheet engine: addresses/values/dates, Excel number formats,
formula parser/printer/reference adjustment, worksheet function library,
copy-on-write workbook model, dependency-driven recalculation with dynamic
arrays, XLSX/CSV I/O, and a command engine (cell entry, clipboard, fill,
formatting, sheets, sort/filter, tables, charts, CF, names, view, file).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 23:18:10 -04:00