Skip to content

feat(spreadsheet): read XLSB workbooks with a bounds-checked BIFF12 reader - #39

Merged
chaliy merged 15 commits into
mainfrom
claude/project-thread-foq2nw
Oct 27, 2026
Merged

chaliy merged 15 commits into
mainfrom
claude/project-thread-foq2nw

Conversation

@chaliy

@chaliy chaliy commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Михайло · project thread

What changed

XLSB (Excel binary workbook) is now converted to markdown in the spreadsheet feature instead of returning UnsupportedFormat.

  • New spreadsheet/xlsb.rs: a small BIFF12 record reader. Every varint, length and offset is bounds-checked, so a malformed record becomes an error instead of a panic. We don't use calamine's XLSB reader because it panics on malformed records.
  • It reads the workbook (sheet list, visibility, 1904 dates), shared strings and styles (number formats are classified as date or duration), then streams cell values.
  • Same behaviour as the other spreadsheet formats: hidden sheets are skipped, row/column caps apply with truncated_sheet warnings, the cell pre-scan budget applies, the title comes from docProps/core.xml, and track_sources ranges are recorded.
  • Fixtures tests/fixtures/xlsb/{date,issues}.xlsb are taken from calamine (MIT, see their README) and complemented by builders for synthetic workbooks.

Why

Second part of the #11 follow-ups. fetchkit's Office backend needs .xlsb.

Before / After

markkit extract --file tests/fixtures/xlsb/date.xlsb

Before: Unsupported format: XLSB (binary Excel workbook) is not supported

After:

## Sheet1

| 2021-01-01 | 15 |
| --- | --- |
| 2021-01-02 | 16 |
| 255:10:10 | 17 |

just fmt lint test check-okf test-scripts examples pass locally.

Risk

  • Medium: this is a new parser of untrusted input.
  • Mitigations:
    • Proptests feed random and truncated records straight to the reader, without the panic guard, so a panic fails the test.
    • Security tests cover a zip bomb, huge declared dimensions and truncated workbooks.

Checklist

  • Tests added or updated (integration, security, proptests)
  • Backward compatibility considered (additive)

Part of #11


Generated by Claude Code

chaliy added 15 commits October 26, 2026 23:53
- Single-row sheets render the row as data under Excel column letters
- Extraction.title from XLSX core.xml, ODS meta.xml, XLS SummaryInformation
- XLSB content type / extension / container detected as Format::Xlsb, not Xlsx
- XLSX without _rels/.rels gets the standard package relationship
- Release profile uses panic = "unwind" so catch_unwind guards work
- Document the trailing newline as intended

Part of #11
- Single-row sheets render the row as data under Excel column letters
- Extraction.title from XLSX core.xml, ODS meta.xml, XLS SummaryInformation
- XLSB content type / extension / container detected as Format::Xlsb, not Xlsx
- XLSX without _rels/.rels gets the standard package relationship
- Release profile uses panic = "unwind" so catch_unwind guards work
- Document the trailing newline as intended

Part of #11
…-foq2nw

# Conflicts:
#	crates/markkit/src/extract.rs
#	crates/markkit/src/lib.rs
#	knowledge/log.md
@chaliy
chaliy merged commit c06ff18 into main Oct 27, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant