Skip to content

Releases: GabrielMarquezMatte/ExcelReader

v3.1.0

Choose a tag to compare

@GabrielMarquezMatte GabrielMarquezMatte released this 14 Sep 15:50
883df26

What's Changed

Added

  • Batch-at-a-time reads across the C ABI and all three bindings — a sheet no longer has
    to be materialized in one call, so peak memory is one batch instead of one sheet. New
    exports: xl_typed_reader_open/xl_typed_reader_next/xl_typed_reader_close for typed
    reads, and xl_parse_arrow_stream over the Arrow C stream interface.

    • Python: Workbook.iter_parse_typed, to_record_batch_reader, plus iter_pandas and
      iter_polars.
    • C++: xl::typed_reader<T> and xl::arrow_stream<T>.
    • Rust: Workbook::typed_chunks and arrow::parse_arrow_stream (behind the arrow
      feature).

    The .NET reader already streams row-by-row by construction and is unchanged. Each
    binding's README documents the semantics: one chunked read per workbook, what
    batch_size means, and what invalidates a live reader.

  • find_package(excelreader) for the C++ packagecmake --install now installs the
    headers, the native binary and a config package, so a downstream project can consume an
    install prefix instead of vendoring the repo. The existing FetchContent route is
    unchanged, and the install rules stay off when cpp is pulled in as a subproject.

  • Shared column style and width validation across the XLSX, XLSB and XLS sheet writers, so
    an invalid column definition is rejected the same way in all three.

Fixed

  • A second chunked read on the same workbook is now rejected instead of producing undefined
    results, and xl_typed_reader_open zeroes *out_reader on every failure path — a caller
    that checks the out-param rather than the return code can no longer read a stale pointer.
  • Guards against double-buffered batches and against use of an already-released Arrow
    stream; the Arrow stream's release, error and schema contracts were tightened to match
    what the C Data Interface requires.
  • OpenTransient fault ordering, and several inaccuracies in the native C header.
  • Agile encryption: the CBC path now verifies the transform consumed the whole segment
    instead of silently accepting a short read.
  • Python: iter_pandas got its own pyarrow guard, and split_blocks is pinned so the
    pandas conversion no longer depends on a pyarrow default that can change.

Performance

  • Agile package encryption reuses one CBC transform across segments instead of rebuilding
    it per segment.
  • xl_parse_arrow now routes through the same resumable session as the chunked path, with
    its memory ceiling pinned by the test suite.

No public .NET API changes in this release — PublicAPI.Shipped.txt is untouched across
ExcelReader.Core and ExcelReader.Arrow, both target frameworks. The C ABI only gains
exports; every existing one keeps its signature and behavior.

Full Changelog: v3.0.2...v3.1.0

v3.0.2

Choose a tag to compare

@GabrielMarquezMatte GabrielMarquezMatte released this 09 Sep 17:40
3c0fb66

What's Changed

Added

  • ECMA-376 standard encryption support (read-only) — workbooks encrypted with the
    "standard" scheme (2.2/3.2/4.2: AES-ECB, SHA-1, 50,000 fixed iterations) now open the
    same way agile-encrypted ones already did, via Excel.Open(..., options) with a
    password. Validated against a real third-party fixture (Apache POI's published
    VelvetSweatshop-encrypted file), not just a self-forged one.
  • Rust bindings: AllRows/read_all_blob for columnar bulk row reads.

Fixed

  • Two container-parsing bugs surfaced by validating standard encryption against a genuine
    third-party file: an incorrect verifierHashSize bound, and the CFB reader demanding a
    full physical sector on a container's final, unpadded stream.
  • xl_last_error/xl_read_all_blob were declared in the native C header but missing from
    the Windows .def export files — a latent link error for native/Rust/Python consumers.
  • ExcelDataReader.Read() corrected pending-row handling.

Performance

  • Standard-encryption package decryption reuses one cipher transform across all segments
    instead of rebuilding it per 4096-byte segment (~3.8x on a large package).
  • ExcelDataReader.GetBytes/GetChars no longer round-trip through an allocated string.
  • ExcelReader.Arrow's timestamp column reuses the library's existing allocation-free
    date/text parser instead of a duplicate hand-rolled one.
  • Test suite: the encrypted-container mutation test now runs in parallel (deterministic
    failure reporting preserved) — full suite ~40s → ~23s.

No public API changes in this release — PublicAPI.Unshipped.txt is empty across
ExcelReader.Core and ExcelReader.Arrow, both target frameworks.

  • feat: ECMA-376 standard encryption support, native bulk-read export, and reader/crypto performance fixes by @GabrielMarquezMatte in #105

Full Changelog: v3.0.1...v3.0.2

v3.0.1

Choose a tag to compare

@GabrielMarquezMatte GabrielMarquezMatte released this 04 Sep 14:53
7c63ee4

What's Changed

  • chore: promote public API for v3.0.0 by @github-actions[bot] in #103
  • Enhance public API and add trimming compatibility attributes by @GabrielMarquezMatte in #104

Full Changelog: v3.0.0...v3.0.1

v3.0.0

Choose a tag to compare

@GabrielMarquezMatte GabrielMarquezMatte released this 04 Sep 03:02
ecd0ae9

⚠️ Breaking changes

  • IExcelRecordMap<T>.ConfigureExcelRecordMap is now generic in the row writer.
    Old: static abstract void ConfigureExcelRecordMap(ExcelRecordMapBuilder<T> builder);
    New: static abstract void ConfigureExcelRecordMap<TRow>(ExcelRecordMapBuilder<T, TRow> builder) where TRow : IRowWriter;

    This lets the mapped record-writer path compile each column's write action against the concrete row writer (XlsxRowWriter, XlsbRowWriter, ...) instead of dispatching through the IRowWriter interface on every cell — the same optimization the reflection-based writer already had via its per-TRow plan.

    Who's affected: only hand-written IExcelRecordMap<T> implementations. If your types use [ExcelSerializable] (the source generator), nothing to do — just recompile. A hand-written implementation needs updating:

    // before
    public static void ConfigureExcelRecordMap(ExcelRecordMapBuilder<MyRecord> builder) { ... }
    
    // after
    public static void ConfigureExcelRecordMap<TRow>(ExcelRecordMapBuilder<MyRecord, TRow> builder)
        where TRow : IRowWriter
    { ... }

New: encrypted OOXML writing

  • Excel.EncryptPackage / EncryptPackageAsync: encrypt an OOXML package into an agile-encrypted CFB container (file and stream overloads). Pairs with the encryption reading support shipped in v2.3.0 — round-tripping a password-protected workbook no longer needs a third-party tool.
  • Underlying pieces now public/available: agile EncryptionInfo descriptor serialization, the write direction of agile key derivation, and an OLE compound writer generalized to N streams with mini-FAT support.

New: ADO.NET access

  • ExcelDataReader implements IDataReader, giving Excel/CSV data a standard IDataReader surface (GetValue, GetSchemaTable, GetOrdinal, typed GetXxx accessors, etc.) for code that expects one — DataTables, data-binding, existing ADO.NET pipelines.
  • ExcelRowReaderExtensions.Sheets() / ExcelSheet: enumerate a workbook's sheets (index + name) without opening each one.

New: native bindings parity

  • Python: SheetWriter, a streaming write handle — write_row with type inference, in-memory streaming, and columnar writing. Encrypted writing wired into the native bindings.
  • Rust: Workbook::rows, a zero-allocation lending row cursor, and Workbook::read_all_decoded for an RAII row set.
  • C++: the same Workbook::rows buffer-reusing cursor and read_all_decoded counterparts.
  • ExcelReader.Arrow: RecordBatch write support (previously read-only).

Fixes

  • XLSB integers are ~2x smaller. Numeric cells with an integral value in [-2^29, 2^29) now encode as the 4-byte BrtCellRk (fInt) form instead of always paying for the 8-byte BrtCellReal — matching what Excel itself emits for a sheet of integers.
  • XlsbRowWriter.Write<T> overflow errors now name the type. A caller-defined IUtf8SpanFormattable that overflows to ±Infinity during numeric conversion previously surfaced a bare "non-finite value" error; it now names the source type, matching the message you already got for a non-numeric value.
  • Corrupt mini-stream sectors fail loudly. ReadMiniStream now throws InvalidDataException for an out-of-bounds mini-sector slice instead of letting the read overflow silently.
  • Fixed a NativeAOT startup crash affecting the Python wheel and C/C++/Rust bindings. The native library no longer pins IlcInstructionSet=native. That setting baked the build machine's CPU features into the binary as a hard requirement; because the binary is built on one machine and consumed on another (CI runner, or an end user's machine after installing the wheel), a CPU-feature mismatch made the process abort at startup with "The required instruction sets are not supported by the current CPU." — intermittently in CI, and potentially for any user whose CPU lacked whatever the build host happened to have (e.g. AVX-512). Vectorized code paths still light up at runtime on capable CPUs via Vector128/256.IsHardwareAccelerated checks, which are unaffected by this change.
  • Data integrity checks strengthened; mapped-record-writer benchmarks added for the new ExcelRecordMapBuilder<T, TRow> path.
  • Dependency bumps: dorny/paths-filter 3→4, analyzer packages.

Compatibility

  • Reading is unaffected — no breaking changes to any parser, reader, or the generated IExcelRowMap<T> side.
  • .NET 8 and .NET 10 both supported, as before.

v2.3.0

Choose a tag to compare

@GabrielMarquezMatte GabrielMarquezMatte released this 30 Aug 18:48
c7a05b1

What's Changed

Full Changelog: v2.1.3...v2.3.0

v2.2.0

Choose a tag to compare

@GabrielMarquezMatte GabrielMarquezMatte released this 26 Aug 03:10

What's Changed

Full Changelog: v2.1.3...v2.2.0

v2.1.3

Choose a tag to compare

@GabrielMarquezMatte GabrielMarquezMatte released this 20 Aug 04:45
9a244f1

What's Changed

  • chore: promote public API for v2.1.2 by @github-actions[bot] in #83
  • Native bindings performance and fuzz testing improvements by @GabrielMarquezMatte in #84
  • Bump Sep from 0.15.2 to 0.17.0 by @dependabot[bot] in #92
  • Bump Microsoft.CodeAnalysis.Analyzers and Microsoft.CodeAnalysis.CSharp by @dependabot[bot] in #91
  • Bump the test group with 2 updates by @dependabot[bot] in #90
  • build(deps): bump softprops/action-gh-release from 2 to 3 by @dependabot[bot] in #88
  • build(deps): bump actions/setup-python from 6 to 7 by @dependabot[bot] in #87
  • build(deps): bump actions/download-artifact from 6 to 8 by @dependabot[bot] in #86
  • Implementing C++ and Rust wrappers packages for native bindings with parsing and reading by @GabrielMarquezMatte in #85

Full Changelog: v2.1.2...v2.1.3

v2.1.2

Choose a tag to compare

@GabrielMarquezMatte GabrielMarquezMatte released this 16 Aug 17:14
194e0a8

What's Changed

Full Changelog: v2.1.1...v2.1.2

v2.1.1

Choose a tag to compare

@GabrielMarquezMatte GabrielMarquezMatte released this 14 Aug 13:28

What's Changed

Full Changelog: v2.1.0...v2.1.1

v2.1.0

Choose a tag to compare

@GabrielMarquezMatte GabrielMarquezMatte released this 14 Aug 06:22
4d2324a

What's Changed

  • chore: promote public API for v2.0.1 by @github-actions[bot] in #67
  • Promote public API and add fuzz testing for ExcelReader by @GabrielMarquezMatte in #68
  • Fix DateTime parsing for ISO dates below year 100 and add tests by @GabrielMarquezMatte in #69
  • Bump SharpFuzz from 2.1.1 to 2.3.0 by @dependabot[bot] in #77
  • Bump Sep from 0.15.1 to 0.15.2 by @dependabot[bot] in #76
  • Bump Microsoft.Testing.Extensions.CodeCoverage from 18.9.0 to 18.10.0 by @dependabot[bot] in #75
  • Bump the benchmarks group with 1 update by @dependabot[bot] in #74
  • Bump the analyzers group with 6 updates by @dependabot[bot] in #73
  • chore(deps): bump actions/checkout from 4 to 7 by @dependabot[bot] in #72
  • chore(deps): bump actions/upload-artifact from 4 to 7 by @dependabot[bot] in #71
  • chore(deps): bump actions/setup-dotnet from 4 to 6 by @dependabot[bot] in #70
  • Update GitHub Actions and analyzer dependencies by @GabrielMarquezMatte in #78
  • feat: native C ABI + Python bindings (excelreader package), with bulk read, date parsing, and PyPI publishing by @GabrielMarquezMatte in #79

Full Changelog: v2.0.1...v2.1.0