xls-codec 4.7.6 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- package/dist/biff/record-types.cjs +21 -0
- package/dist/biff/record-types.d.cts +15 -1
- package/dist/biff/record-types.d.ts +15 -1
- package/dist/biff/record-types.js +15 -1
- package/dist/biff/substreams.cjs +7 -8
- package/dist/biff/substreams.d.cts +1 -1
- package/dist/biff/substreams.d.ts +1 -1
- package/dist/biff/substreams.js +7 -8
- package/dist/{conditional-format-12-DBhe7Zo6.d.cts → conditional-format-12-CZ43-CR4.d.cts} +2 -2
- package/dist/{conditional-format-12-D-X5g_O3.d.ts → conditional-format-12-Xl52VBCj.d.ts} +2 -2
- package/dist/{conditional-format-Czh2oTzQ.d.cts → conditional-format-Bt1vRWgc.d.cts} +1 -1
- package/dist/{conditional-format-DOdazxWe.d.ts → conditional-format-Cqcjnm7O.d.ts} +1 -1
- package/dist/content.cjs +40 -18
- package/dist/content.js +40 -18
- package/dist/{data-validation-BXvIVU0e.d.ts → data-validation-BeYpL3Nb.d.ts} +1 -1
- package/dist/{data-validation-DfpjUN-N.d.cts → data-validation-lJWM9-AP.d.cts} +1 -1
- package/dist/drawing/blips.cjs +83 -0
- package/dist/drawing/blips.d.cts +10 -0
- package/dist/drawing/blips.d.ts +10 -0
- package/dist/drawing/blips.js +82 -0
- package/dist/drawing/bytes.cjs +15 -0
- package/dist/drawing/bytes.d.cts +5 -0
- package/dist/drawing/bytes.d.ts +5 -0
- package/dist/drawing/bytes.js +14 -0
- package/dist/drawing/escher-constants.cjs +52 -0
- package/dist/drawing/escher-constants.d.cts +34 -0
- package/dist/drawing/escher-constants.d.ts +34 -0
- package/dist/drawing/escher-constants.js +34 -0
- package/dist/drawing/escher.cjs +84 -0
- package/dist/drawing/escher.d.cts +30 -0
- package/dist/drawing/escher.d.ts +30 -0
- package/dist/drawing/escher.js +80 -0
- package/dist/drawing/shapes.cjs +80 -0
- package/dist/drawing/shapes.d.cts +24 -0
- package/dist/drawing/shapes.d.ts +24 -0
- package/dist/drawing/shapes.js +79 -0
- package/dist/index.cjs +10 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/{print-names-CCwUHAoL.d.cts → print-names-B2OR0fvs.d.cts} +1 -1
- package/dist/{print-names-CxAbgcjB.d.ts → print-names-BXcmmwVi.d.ts} +1 -1
- package/dist/{substreams-Dp5cZoUo.d.ts → substreams-CgTHx5kX.d.ts} +1 -1
- package/dist/{substreams-CHv3oWmn.d.cts → substreams-XDNgDvRJ.d.cts} +1 -1
- package/dist/units.cjs +7 -0
- package/dist/units.d.cts +6 -1
- package/dist/units.d.ts +6 -1
- package/dist/units.js +6 -1
- package/dist/workbook/chart.cjs +230 -0
- package/dist/workbook/chart.d.cts +19 -0
- package/dist/workbook/chart.d.ts +19 -0
- package/dist/workbook/chart.js +229 -0
- package/dist/workbook/comments.cjs +2 -1
- package/dist/workbook/comments.d.cts +7 -2
- package/dist/workbook/comments.d.ts +7 -2
- package/dist/workbook/comments.js +2 -2
- package/dist/workbook/conditional-format-12.d.cts +1 -1
- package/dist/workbook/conditional-format-12.d.ts +1 -1
- package/dist/workbook/conditional-format.d.cts +1 -1
- package/dist/workbook/conditional-format.d.ts +1 -1
- package/dist/workbook/data-validation.d.cts +1 -1
- package/dist/workbook/data-validation.d.ts +1 -1
- package/dist/workbook/drawing.cjs +270 -0
- package/dist/workbook/drawing.d.cts +31 -0
- package/dist/workbook/drawing.d.ts +31 -0
- package/dist/workbook/drawing.js +268 -0
- package/dist/workbook/globals-writer.d.cts +1 -1
- package/dist/workbook/globals-writer.d.ts +1 -1
- package/dist/workbook/globals.d.cts +2 -2
- package/dist/workbook/globals.d.ts +2 -2
- package/dist/workbook/print-names.d.cts +1 -1
- package/dist/workbook/print-names.d.ts +1 -1
- package/dist/workbook/sheet-writer.cjs +1 -1
- package/dist/workbook/sheet-writer.js +1 -1
- package/dist/workbook/sheet.d.cts +4 -4
- package/dist/workbook/sheet.d.ts +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@ Under active development, with real, tested **read and write** support. Built an
|
|
|
22
22
|
- **Print settings** — every field of `ContentSheetPrintSettings`: page size and orientation, all four margins, gridline and row/column-header printing, page order, print scale or fit-to-page counts, manual page breaks, the print range, and the repeated header rows and columns — read from and written to the nine worksheet-substream records and the two built-in defined names that carry them, in both directions and verified against real LibreOffice-produced BIFF8 (see [Print settings](#print-settings)).
|
|
23
23
|
- **Cell alignment** — a cell's own horizontal (`left`/`center`/`right`/`justify`) and vertical (`top`/`middle`) alignment, read from and written to `XF`'s trailing `CellXF`/`StyleXF` payload's own leading word, in both directions and verified against real LibreOffice-produced BIFF8 (see [Cell alignment](#cell-alignment)).
|
|
24
24
|
- **Data validation, read-only (ExaDev/documents.js#1098)** — a sheet's own `Dv` records (`src/workbook/data-validation.ts`) into `ContentSheet.dataValidations`: type, comparison operator, one or two formulas (via the same `Ptg` reader `Formula` records already use), allow-blank/show-input/show-error flags, error style, and prompt/error titles and messages, resolved directly against [MS-XLS]'s own published `Dv`/`DVal`/`DVParsedFormula`/`SqRefU` field layouts rather than a producer-specific convention.
|
|
25
|
+
- **Charts, drawings, and images, read-only (ExaDev/documents.js#924)** — a worksheet's own MS-ODRAW (Escher) drawing layer (`src/drawing/escher.ts`, `src/drawing/shapes.ts`, `src/drawing/blips.ts`), the workbook-wide Blip Store every picture shape's own `pib` property indexes into, and an embedded chart's own nested substream (`src/workbook/chart.ts`), joined into `ContentSheet.images` and `ContentSheet.embeddedObjects` by `src/workbook/drawing.ts` — see "Charts, drawings, and images, resolved for real" under Read-side gaps below.
|
|
25
26
|
|
|
26
27
|
Verified primarily by round trip (`src/write.test.ts`, plus a dedicated `test/workers/write.test.ts` proving the whole write path inside a real `workerd` isolate, not just Node): build a `ContentDocument`, write it, read it back through this package's own independently-pinned reader, and check the result. Every record's own byte layout is additionally cited to its [MS-XLS] section in the writer's source, matching the reader's own convention.
|
|
27
28
|
|
|
@@ -35,7 +36,8 @@ What `writeXlsContent`/`writeXls` cover: every `ContentCellValue` kind a real `.
|
|
|
35
36
|
| Per-cell font | The reader does not read one back: `ContentSheetCell` has no cell-level font field at all (`ooxml.js`'s xlsx reader makes the identical font-scope choice), so writing a real value here would be unverifiable by round trip. Every `XF` this writer emits still references the same single font. |
|
|
36
37
|
| `MulBlank`/`RK`/`MulRk` | Pure compaction optimisations over information a plain `Blank`/`Number`/`LabelSst`/`BoolErr` record already carries losslessly. (`Blank` itself _is_ written, for a formatted empty cell — see the `empty` row below.) |
|
|
37
38
|
| An `empty`-kind cell carrying no formatting | Written as nothing at all, which is what round-trips: `content.ts`'s reader drops an unformatted blank cell it reads, and a merged range's empty anchor is independently reconstructed from `MergeCells` alone. A formatted one (a fill, a border, or a non-default alignment) is the opposite case — its formatting exists only in the `XF` a cell record names, so it gets a real `Blank` record ([MS-XLS] 2.4.20) and round-trips with that formatting intact. |
|
|
38
|
-
| Images, embedded objects
|
|
39
|
+
| Images, embedded objects (charts/drawings) | The reader now recovers a sheet's own pictures, charts, and generic drawing shapes (see Read-side gaps below), but writing them back out is its own separate mechanism — a shape's own MS-ODRAW (Escher) container tree, a workbook-wide Blip Store, and (for a chart) a whole nested `BOF`/`EOF` substream, none of which this writer's existing per-record emission has any machinery for — scoped as its own piece of work rather than folded into recovering the read side, the same split this table already draws for `Formula` records. `ContentSheet.images` and `ContentSheet.embeddedObjects` are silently ignored on write. |
|
|
40
|
+
| Defined names (`Lbl`) | Read only for the two built-in ones a sheet's print range and repeated header bands live in ([Print settings](#print-settings)); a user-defined name has nowhere to land in `document-schema.js`'s spreadsheet model, so there is no round trip to verify a writer for it against. |
|
|
39
41
|
| Data validation (`Dv`/`DVal`) | The reader now recovers a sheet's own validation rules (see Read-side gaps below), but writing them back out is its own separate mechanism -- re-encoding a formula's own text back into `Ptg` tokens for `Dv`'s two `DVParsedFormula` fields, the same "not folded into recovering the read side" split this table already draws for `Formula` records. A `ContentSheet.dataValidations` is silently ignored on write. |
|
|
40
42
|
| Conditional formatting (`CondFmt`/`CF`, `CondFmt12`/`CF12`) | The reader now recovers a sheet's own base `cellIs` rules and `CF12`'s colour scale/data bar/icon set rules (see Read-side gaps below), but writing them back out is its own separate mechanism, the same "not folded into recovering the read side" split this table already draws for `Formula` records and `Dv`. A `ContentSheet.conditionalFormats` is silently ignored on write. |
|
|
41
43
|
| Cell comments (`Note`/`Txo`) | The reader now recovers a cell's comment (see Read-side gaps below), but writing one back out is its own separate mechanism -- a `Note`/`Obj`/`Txo` triple with its own object-id bookkeeping, distinct from every other cell record this writer already emits -- scoped as its own piece of work rather than folded into recovering the read side, the same split this table already draws for `Formula` records. A `ContentSheetCell.comment` is silently ignored on write. |
|
|
@@ -54,10 +56,11 @@ Each deliberate rather than overlooked:
|
|
|
54
56
|
- **Print settings, resolved for real.** Every field of `ContentSheetPrintSettings` is read from the records that carry it, with Excel's own "Normal" preset standing in per field for whatever the file leaves unstated — see [Print settings](#print-settings) for the record map, the two of BIFF8's own conditional rules that decide how to read `Setup`, and the three things that genuinely do not come through.
|
|
55
57
|
- **Cell comments, resolved for real (ExaDev/documents.js#949).** A legacy BIFF8 comment is split across three record kinds a single self-contained xlsx `<comment>` element never needs: a `Note` record ([MS-XLS] 2.4.179, wrapping a `NoteSh` structure) anchors the comment to a cell and names its author, but carries no text of its own; the text lives in a `Txo` record ([MS-XLS] 2.4.329), its characters carried across trailing `Continue` records; the two are joined through an `Obj` record ([MS-XLS] 2.4.181) whose `FtCmo` names an object id and type, the `Note`'s own `idObj` field naming that same id, and a `Txo` always immediately following the `Obj` record whose shape it belongs to (`src/workbook/comments.ts`). Read in one independent pass over the whole worksheet substream rather than assuming stream order between a `Note` and the `Obj`+`Txo` pair it names -- both are resolved regardless of which comes first. Legacy BIFF8 has no threading and no per-comment timestamp at all (unlike xlsx's own `[MS-XLSX]` threaded-comments extension), so `ContentSheetCellComment.replies` and `.createdAt` are never populated from an `.xls` source; rich per-character formatting within a comment (`TxORuns`) is skipped rather than modelled, the same scope limit this reader already applies to the shared string table's own rich runs, since `ContentSheetCellComment.text` is a plain string with nowhere to carry them.
|
|
56
58
|
- **Data validation, resolved for real (ExaDev/documents.js#1098).** `Dv` ([MS-XLS] 2.4.95) is a fixed, published binary structure -- a bit-packed flags `DWORD` (`valType`/`errStyle`/`fAllowBlank`/`fShowInputMsg`/`fShowErrorMsg`/`typOperator`), four `XLUnicodeString`s (prompt/error titles and messages), one or two `DVParsedFormula` structures, and a trailing `SqRefU` range list -- read directly against that spec (`src/workbook/data-validation.ts`), unlike `calcext:condition`'s own LibreOffice-source-transcribed mini-language odf.js's equivalent reader needed. A `DVParsedFormula`'s own `rgce` is the identical `Ptg` token grammar a cell's `Formula` record carries, so its formula text is recovered with the same `parseFormulaText` this reader already uses for ordinary cell formulas. `DVal` ([MS-XLS] 2.4.96), the record that precedes a sheet's own `Dv` collection, carries only input-window UI state (position, drop-down `Obj` reference) with no counterpart in `ContentSheetDataValidationSchema` and is not read for its own fields.
|
|
59
|
+
- **Charts, drawings, and images, resolved for real (ExaDev/documents.js#924).** A worksheet's own `MsoDrawing` records ([MS-XLS] 2.1.7.20.3-adjacent, `RECORD_MSODRAWING`) carry MS-ODRAW (Escher) bytes that split across as many records as the drawing needs and simply concatenate, in stream order, into one continuous Escher record tree (`src/drawing/escher.ts`, reading [MS-ODRAW]'s own `OfficeArtRecordHeader`/container-vs-atom framing directly against its spec rather than from memory). Within that tree, `src/drawing/shapes.ts` walks the `DgContainer`/`SpgrContainer`/`SpContainer` hierarchy for each real top-level shape's own type, id, and cell anchor (`ClientAnchorSheet`, [MS-XLS] 2.5.163 — one `Sp` atom's `recInstance` and `ClientAnchor`'s corner-cell-plus-fractional-offset pair, 1/1024ths of a cell's width and 1/256ths of its height), skipping the invisible "patriarch" group root every drawing wraps its real shapes in. A picture shape's own `Opt` property table names a `pib` — a 1-based index into the **workbook-wide** Blip Store (`OfficeArtBstoreContainer`, read once from the globals substream's own `MsoDrawingGroup` stream, `src/drawing/blips.ts`) — resolved to real image bytes for a PNG or JPEG blip (`OfficeArtBlipPNG`/`OfficeArtBlipJPEG`'s own literal file bytes, past their `rgbUid` header); a DIB/EMF/WMF/PICT/TIFF blip is recognised but produces no image, since `ContentImageBlockSchema.format` has no lossless slot for any of them. Since neither an Escher shape nor a `MsoDrawing` record names what kind of object it actually holds, each shape is paired 1:1, in document order, with the worksheet substream's own `Obj` records (skipping any Note-type `Obj` `src/workbook/comments.ts` already accounts for) — the same positional correlation every other real BIFF8 reader relies on. An `Obj` naming a **chart** locates the chart's own nested `BOF`(dt=`0x0020`)/`EOF` substream — which sits INSIDE the worksheet substream, immediately after the shape that anchors it ([MS-XLS] "Chart Area") — via `src/biff/substreams.ts`'s own stack-based substream nesting (a genuinely new capability this issue needed: `splitSubstreams` previously treated any BOF met mid-substream as ending it outright, which would have silently dropped every worksheet record written after an embedded chart). `src/workbook/chart.ts` reads that substream's `Series`/`AI` (`BRAI`)/`SeriesText` records — a series' own name and its category/value data links — resolving each link's value either from the chart's own on-disk `SERIESDATA` cache (`Dimensions`/`SIIndex`/`Number`/`BoolErr`/`Blank`/`Label`, present when the chart's data lives on another sheet or is genuinely external) or, for the common case of a chart plotting its own sheet's cells, by resolving the `AI`'s `PtgArea3d`/`PtgRef3d` reference token directly against that sheet's own already-mapped cells — and lands as a `ContentEmbeddedObject` with `objectKind: 'chart'`, its cached series/category table flattened into a small one-sheet spreadsheet `ContentDocument`, the identical shape `ooxml.js`'s own xlsx/pptx chart reading already produces (ExaDev/documents.js#719): `document-schema.js` has no richer, chart-type-aware object model yet, so this reader targets the fallback that exists rather than inventing one. Every other recognised shape (an autoshape, a text box, a line, a group) lands as `objectKind: 'drawing'`, a single-page `ContentDocument` holding one sized-and-positioned `ContentShape` with no text content modelled. Not modelled at all: a shape's own rotation, fill/line formatting, or text runs; a group's own nested transform (a nested nested group's shapes are still recovered, cell-anchored, but a group's own rotation/scale is not composed into its children's positions); and a chart's own type, axes, and legend, which `document-schema.js`'s flattened-table representation has no field for regardless of what this reader could recover.
|
|
57
60
|
- **Conditional formatting, base rules resolved for real (ExaDev/documents.js#1102).** A `CondFmt` record ([MS-XLS] 2.4.56) marks the start of one to three `CF` records ([MS-XLS] 2.4.42) sharing one cell-range list, read together as a group (`src/workbook/conditional-format.ts`) since a `CF`'s own ranges live on its parent `CondFmt`, not on itself. Base BIFF8 (Excel 97) conditional formatting has exactly two rule shapes: a comparison ("Cell Value Is") condition, promoted to `ContentSheetConditionalFormat`'s `cellIs` variant with its formula(s) recovered through the same `parseFormulaText` this reader already uses for cell formulas and `Dv`; and a formula condition, left unpromoted for the same "no closed-form structure without a general formula engine" reason `data-validation.ts` and `ooxml.js`'s own xlsx `cfRule` reading already draw. A rule's resulting style -- font colour and fill background -- comes from its `CF`'s own `DXFN` structure, resolved through the identical `icv`/`Palette` colour machinery a regular cell's fill and border already use ([Cell decoration](#cell-decoration)); a `DXFN` naming a user-defined number format (`DXFNumUsr`) degrades that one rule's style to absent rather than risk misreading the font/fill fields that follow it, since [MS-XLS]'s own prose for `DXFNumUsr`'s length field does not settle whether it counts itself. Every richer rule type Excel 2007+ added has no representation in the base `CF` record at all; it rides a `CF12` record instead, linked to its own `CondFmt` through a `CFEx` extension record.
|
|
58
61
|
- **Conditional formatting, CF12's colour scale/data bar/icon set rules resolved for real (ExaDev/documents.js#1104).** `CF12`'s own `ct` field picks one of six rule shapes ([MS-XLS] 2.4.43); this reader promotes the three that share a genuine array-of-thresholds building block already modelled in `document-schema.js` -- colour scale, data bar, and icon set (`src/workbook/conditional-format-12.ts`) -- each reading an array of `CFVO` threshold objects (the identical `num`/`percent`/`max`/`min`/`formula`/`percentile` vocabulary `ContentSheetConditionalFormatValueSchema` already carries for `ooxml.js`'s xlsx reader and `odf.js`'s ods reader) paired with `CFColor` values. A `CFColor` naming an indexed colour resolves through the same `icv`/`Palette` machinery as base `CF`'s own `DXFN`, then Excel's own TintAndShade model applies the colour's own tint/shade Xnum (`xf-colors.ts`'s `applyTint`); one naming a plain RGB triple resolves directly, tint included; one naming an automatic or theme colour degrades the whole rule to absent, since this package has no BIFF8 `Theme` reader to resolve a theme reference against. Icon set's own `iIconSet` byte maps to the identical ECMA-376 `ST_IconSetType` vocabulary (`3Arrows`, `3TrafficLights1`, `5Quarters`, and the rest of the seventeen built-in sets) `ooxml.js`'s xlsx `cfRule` reading already carries as a plain string. A record longer than the 8224-byte single-record ceiling continues onto `ContinueFrt12` rather than the plain `Continue` every other record in this package joins against; `groupRecords` (`src/biff/substreams.ts`) strips its own restated `FrtRefHeader` before joining it.
|
|
59
62
|
- **Conditional formatting, CF12's filter-dispatched template rules resolved for real (ExaDev/documents.js#1106).** `ct` 0x05 ("filter") dispatches further through `icfTemplate`, alongside a 16-byte `CFExTemplateParams` block always present regardless of `ct`. Of that block's five variants, only two need real parsing -- `CFExFilterParams` (top10's own `fTop`/`fPercent`/`iParam`) and `CFExAveragesTemplateParams` (the aboveAverage family's own standard-deviation count) -- since `CFExDefaultTemplateParams` (duplicateValues/uniqueValues/the four blank/error conditions) is 16 reserved bytes and `CFExDateTemplateParams`'s own `dateOp` field is a fixed restatement of `icfTemplate` for all ten date/time periods, so both dispatch directly off `icfTemplate` with no further byte reading. Unlike colour scale/data bar/icon set, [MS-XLS] does not force a `ct` 0x05 rule's own `cbDxf` to zero, so its `DXFN12` can carry a genuine font/fill override; that structure resolves through the identical `parseDxfStyle` base `CF`'s own `DXFN` already uses. A malformed `iParam` of zero degrades a top10 rule to absent rather than promoting a `rank` `ContentSheetConditionalFormatSchema` itself requires to be positive. Comparison/formula rules re-expressed in this newer record shape, `containsText`'s own four sub-types (`CFExTextTemplateParams` names which one a rule is but not its actual search string, and CF12's own formula fields are spec'd to be zero for every `ct` 0x05 rule -- where the literal text operand lives is a genuine open question), and `CFEx`'s own extension of a legacy `CF` record all remain unread (ExaDev/documents.js#1100).
|
|
60
|
-
- **Not read at all:**
|
|
63
|
+
- **Not read at all:** `CF12`'s `containsText` filter rules, and `CFEx`'s own `CF`-record extension (ExaDev/documents.js#1100). Defined names (`Lbl`) are read only for the two built-in ones a sheet's print range and repeated header bands live in ([Print settings](#print-settings)); a user-defined name has nowhere to land in `document-schema.js`'s spreadsheet model, so it is skipped.
|
|
61
64
|
- **RC4-encrypted workbooks, decrypted for real (ExaDev/documents.js#1108).** A `FilePass` record ([MS-XLS] 2.4.117) means every record after it is ciphertext under one of three schemes; this reader implements exactly one, the [MS-OFFCRYPTO] 2.3.6.1 "RC4 encryption header" -- `readXlsContent`/`readXls` take an optional `password`, verify it against the header's own `EncryptedVerifier`/`EncryptedVerifierHash` pair, then decrypt every subsequent record's data (`src/workbook/encryption.ts`) using the RC4/MD5 primitives [`archive-codec`](../archive-codec/README.md#legacy-office-encryption) shares with `doc-codec`/`ppt-codec`'s own eventual integration. [MS-XLS] 2.2.10's own exclusion list -- `BOF`, `FilePass`, and four shared-workbook revision-tracking records this package otherwise never reads, plus `BoundSheet8`'s own `lbPlyPos` field specifically -- is honoured exactly, re-derived independently in this package's own tests rather than trusted by construction. A missing or incorrect password throws rather than returning a garbled document; the newer "RC4 CryptoAPI encryption header" scheme and XOR obfuscation are explicitly out of scope, tracked separately on [#922](https://github.com/ExaDev/documents.js/issues/922).
|
|
62
65
|
|
|
63
66
|
This package is wired into `documents.js`'s conversion registry (`xlsToPdf`/`pdfToXls`, `convertDocument("xls", ...)`, and every same-variant spreadsheet bridge) — see that package's own README Fidelity table for exactly which pairs route and which don't. Remaining read+write scope gaps (formula writing and per-cell font) are tracked on [#815](https://github.com/ExaDev/documents.js/issues/815).
|
|
@@ -201,6 +204,8 @@ Layered bottom-up, each layer testable against hand-built byte sequences taken f
|
|
|
201
204
|
- **`src/biff/xf-colors.ts`** — the `Icv` colour table (both the eight fixed colours and the 56-entry default palette), the `BorderStyle`/`FillPattern` vocabularies, and the `CellXF`/`StyleXF` trailing payload's own border/fill bit-layout packing and unpacking, shared by `globals.ts`'s read side and `biff/xf-writer.ts`'s write side — see [Cell decoration](#cell-decoration).
|
|
202
205
|
- **`src/biff/print-setup.ts`**, **`src/workbook/print-names.ts`** — the two halves of [Print settings](#print-settings). The first is the `Setup` record's own flag bit layout and `iPaperSize` code table, packed and unpacked in one place exactly as `xf-colors.ts` does for the `XF` payload; the second is both directions of the built-in `Print_Area`/`Print_Titles` defined names, which live in the globals substream rather than the sheet's own and so are read by `globals.ts` and written by `globals-writer.ts`.
|
|
203
206
|
- **[`excel-number-format`](../excel-number-format/README.md)**, **`src/serial.ts`** — number-format classification and date-serial conversion, the two pieces of xlsx semantics BIFF8 shares because ECMA-376 inherited them from BIFF. The classifier itself is a dependency shared with `ooxml.js`, not a module in this package (ExaDev/documents.js#848) — `classifyNumberFormat` and `BUILTIN_NUMBER_FORMATS` still ride this package's own barrel (`export * from "excel-number-format"` in `src/index.ts`), so `import { classifyNumberFormat } from "xls-codec"` is unchanged.
|
|
207
|
+
- **`src/drawing/escher.ts`**, **`src/drawing/shapes.ts`**, **`src/drawing/blips.ts`** — MS-ODRAW (Escher), read as its own record tree independent of BIFF8's own record framing: the shared `OfficeArtRecordHeader` container/atom reader, the per-sheet shape walk (type, id, cell anchor, a picture's own `pib` blip reference), and the workbook-wide Blip Store a `pib` resolves against.
|
|
208
|
+
- **`src/workbook/chart.ts`**, **`src/workbook/drawing.ts`** — an embedded chart's own nested substream, read into a flattened series/category table; and the orchestration that pairs each Escher shape with the `Obj` record naming what it holds (a picture, a chart, or a generic shape) and produces `ContentSheet.images`/`ContentSheet.embeddedObjects` — see "Charts, drawings, and images, resolved for real" under [Read-side gaps](#read-side-gaps).
|
|
204
209
|
- **`src/content.ts`** — the mapping onto `document-schema.js`.
|
|
205
210
|
- **`src/metadata.ts`** — wraps `archive-codec`'s own `SummaryInformationProperties` <-> `LayoutMetadata` mapping with this package's `createdIso`/`modifiedIso` date validation, throwing `BiffWriteError` for a malformed one rather than letting an opaque `RangeError` escape the FILETIME conversion (see [Metadata](#metadata)).
|
|
206
211
|
|
|
@@ -72,6 +72,20 @@ const RECORD_NOTE = 28;
|
|
|
72
72
|
const RECORD_OBJ = 93;
|
|
73
73
|
/** The rich text of a text box or comment, its characters and formatting runs carried in trailing Continue records ([MS-XLS] 2.4.329). */
|
|
74
74
|
const RECORD_TXO = 438;
|
|
75
|
+
/** One worksheet's own MS-ODRAW (Escher) drawing bytes, chunked across as many of these records as the drawing needs ([MS-XLS] 2.4.180's sibling "MsoDrawing", https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-xls/1b0b0ea3-5e1d-41ce-8e79-e27f1041331e) -- every MsoDrawing record's own data in one worksheet substream concatenates, in stream order, into one continuous Escher byte stream (src/drawing/escher.ts reads it). */
|
|
76
|
+
const RECORD_MSODRAWING = 236;
|
|
77
|
+
/** The workbook-wide counterpart of MsoDrawing, carrying the drawing group's own shared state -- most importantly the Blip Store (`OfficeArtBStoreContainer`) every worksheet's picture/chart shapes reference by index -- concatenated the same way, but read from the WORKBOOK GLOBALS substream rather than a worksheet's. */
|
|
78
|
+
const RECORD_MSODRAWINGGROUP = 235;
|
|
79
|
+
/** Which Escher shapes a worksheet had selected when it was last saved -- UI state this package has no use for, named here only so a reader that walks every record type in a worksheet substream can recognise and skip it rather than mistake it for drawing bytes. */
|
|
80
|
+
const RECORD_MSODRAWINGSELECTION = 237;
|
|
81
|
+
/** One data series' own type/count header and, following it, its four AI (BRAI) links -- categories, values, bubble sizes, name, each identified by the AI's own `id` field rather than by position ([MS-XLS] "Series"). */
|
|
82
|
+
const RECORD_SERIES = 4099;
|
|
83
|
+
/** A series' cached NAME text, when the file states one as a literal rather than through its own `AI id=0` formula reference ([MS-XLS] "SeriesText"): a ShortXLUnicodeString (one-byte length prefix), unlike the double-byte-length XLUnicodeString most other BIFF8 strings use. */
|
|
84
|
+
const RECORD_SERIESTEXT = 4109;
|
|
85
|
+
/** A data-role link on a series -- name, categories, values, or bubble sizes, selected by the record's own `id` field -- carrying either a literal value/text or a `ChartParsedFormula` range reference this package's own Ptg reference tokens (PtgArea3d/PtgRef3d) can resolve ([MS-XLS] "AI"/BRAI, restricted to a narrower Ptg grammar than a worksheet cell's own Formula record). */
|
|
86
|
+
const RECORD_AI = 4177;
|
|
87
|
+
/** Precedes each of the up-to-three chart-wide cached data blocks (values, categories, bubble sizes) a `SERIESDATA` production carries, its own `numIndex` field naming which of the three follows ([MS-XLS] "SIIndex"). Each cached `Number`/`BoolErr`/`Blank`/`Label` record that follows carries the same `col` field the worksheet cell-record family already does, here reused as the zero-based Series-record index the cached value belongs to. */
|
|
88
|
+
const RECORD_SIINDEX = 4197;
|
|
75
89
|
/** Whether the row and column headers are printed ([MS-XLS] 2.4.203). */
|
|
76
90
|
const RECORD_PRINTROWCOL = 42;
|
|
77
91
|
/** Whether the gridlines are printed ([MS-XLS] 2.4.202). */
|
|
@@ -147,6 +161,7 @@ exports.BOF_TYPE_MACRO = BOF_TYPE_MACRO;
|
|
|
147
161
|
exports.BOF_TYPE_WORKBOOK = BOF_TYPE_WORKBOOK;
|
|
148
162
|
exports.BOF_TYPE_WORKSHEET = BOF_TYPE_WORKSHEET;
|
|
149
163
|
exports.MAX_RECORD_DATA_SIZE = MAX_RECORD_DATA_SIZE;
|
|
164
|
+
exports.RECORD_AI = RECORD_AI;
|
|
150
165
|
exports.RECORD_ARRAY = RECORD_ARRAY;
|
|
151
166
|
exports.RECORD_BLANK = RECORD_BLANK;
|
|
152
167
|
exports.RECORD_BOF = RECORD_BOF;
|
|
@@ -185,6 +200,9 @@ exports.RECORD_LABELSST = RECORD_LABELSST;
|
|
|
185
200
|
exports.RECORD_LBL = RECORD_LBL;
|
|
186
201
|
exports.RECORD_LEFTMARGIN = RECORD_LEFTMARGIN;
|
|
187
202
|
exports.RECORD_MERGECELLS = RECORD_MERGECELLS;
|
|
203
|
+
exports.RECORD_MSODRAWING = RECORD_MSODRAWING;
|
|
204
|
+
exports.RECORD_MSODRAWINGGROUP = RECORD_MSODRAWINGGROUP;
|
|
205
|
+
exports.RECORD_MSODRAWINGSELECTION = RECORD_MSODRAWINGSELECTION;
|
|
188
206
|
exports.RECORD_MULBLANK = RECORD_MULBLANK;
|
|
189
207
|
exports.RECORD_MULRK = RECORD_MULRK;
|
|
190
208
|
exports.RECORD_NOTE = RECORD_NOTE;
|
|
@@ -198,8 +216,11 @@ exports.RECORD_RK = RECORD_RK;
|
|
|
198
216
|
exports.RECORD_ROW = RECORD_ROW;
|
|
199
217
|
exports.RECORD_RRDHEAD = RECORD_RRDHEAD;
|
|
200
218
|
exports.RECORD_RRDINFO = RECORD_RRDINFO;
|
|
219
|
+
exports.RECORD_SERIES = RECORD_SERIES;
|
|
220
|
+
exports.RECORD_SERIESTEXT = RECORD_SERIESTEXT;
|
|
201
221
|
exports.RECORD_SETUP = RECORD_SETUP;
|
|
202
222
|
exports.RECORD_SHRFMLA = RECORD_SHRFMLA;
|
|
223
|
+
exports.RECORD_SIINDEX = RECORD_SIINDEX;
|
|
203
224
|
exports.RECORD_SST = RECORD_SST;
|
|
204
225
|
exports.RECORD_STRING = RECORD_STRING;
|
|
205
226
|
exports.RECORD_STYLE = RECORD_STYLE;
|
|
@@ -71,6 +71,20 @@ declare const RECORD_NOTE = 28;
|
|
|
71
71
|
declare const RECORD_OBJ = 93;
|
|
72
72
|
/** The rich text of a text box or comment, its characters and formatting runs carried in trailing Continue records ([MS-XLS] 2.4.329). */
|
|
73
73
|
declare const RECORD_TXO = 438;
|
|
74
|
+
/** One worksheet's own MS-ODRAW (Escher) drawing bytes, chunked across as many of these records as the drawing needs ([MS-XLS] 2.4.180's sibling "MsoDrawing", https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-xls/1b0b0ea3-5e1d-41ce-8e79-e27f1041331e) -- every MsoDrawing record's own data in one worksheet substream concatenates, in stream order, into one continuous Escher byte stream (src/drawing/escher.ts reads it). */
|
|
75
|
+
declare const RECORD_MSODRAWING = 236;
|
|
76
|
+
/** The workbook-wide counterpart of MsoDrawing, carrying the drawing group's own shared state -- most importantly the Blip Store (`OfficeArtBStoreContainer`) every worksheet's picture/chart shapes reference by index -- concatenated the same way, but read from the WORKBOOK GLOBALS substream rather than a worksheet's. */
|
|
77
|
+
declare const RECORD_MSODRAWINGGROUP = 235;
|
|
78
|
+
/** Which Escher shapes a worksheet had selected when it was last saved -- UI state this package has no use for, named here only so a reader that walks every record type in a worksheet substream can recognise and skip it rather than mistake it for drawing bytes. */
|
|
79
|
+
declare const RECORD_MSODRAWINGSELECTION = 237;
|
|
80
|
+
/** One data series' own type/count header and, following it, its four AI (BRAI) links -- categories, values, bubble sizes, name, each identified by the AI's own `id` field rather than by position ([MS-XLS] "Series"). */
|
|
81
|
+
declare const RECORD_SERIES = 4099;
|
|
82
|
+
/** A series' cached NAME text, when the file states one as a literal rather than through its own `AI id=0` formula reference ([MS-XLS] "SeriesText"): a ShortXLUnicodeString (one-byte length prefix), unlike the double-byte-length XLUnicodeString most other BIFF8 strings use. */
|
|
83
|
+
declare const RECORD_SERIESTEXT = 4109;
|
|
84
|
+
/** A data-role link on a series -- name, categories, values, or bubble sizes, selected by the record's own `id` field -- carrying either a literal value/text or a `ChartParsedFormula` range reference this package's own Ptg reference tokens (PtgArea3d/PtgRef3d) can resolve ([MS-XLS] "AI"/BRAI, restricted to a narrower Ptg grammar than a worksheet cell's own Formula record). */
|
|
85
|
+
declare const RECORD_AI = 4177;
|
|
86
|
+
/** Precedes each of the up-to-three chart-wide cached data blocks (values, categories, bubble sizes) a `SERIESDATA` production carries, its own `numIndex` field naming which of the three follows ([MS-XLS] "SIIndex"). Each cached `Number`/`BoolErr`/`Blank`/`Label` record that follows carries the same `col` field the worksheet cell-record family already does, here reused as the zero-based Series-record index the cached value belongs to. */
|
|
87
|
+
declare const RECORD_SIINDEX = 4197;
|
|
74
88
|
/** Whether the row and column headers are printed ([MS-XLS] 2.4.203). */
|
|
75
89
|
declare const RECORD_PRINTROWCOL = 42;
|
|
76
90
|
/** Whether the gridlines are printed ([MS-XLS] 2.4.202). */
|
|
@@ -140,4 +154,4 @@ declare const BIFF8_VERSION = 1536;
|
|
|
140
154
|
/** [MS-XLS] 2.1.4: "The record size ... MUST be less than or equal to 8224." The ceiling a writer splits a record at, and the bound a reader can sanity-check a declared size against. */
|
|
141
155
|
declare const MAX_RECORD_DATA_SIZE = 8224;
|
|
142
156
|
//#endregion
|
|
143
|
-
export { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_TYPE_WORKSHEET, MAX_RECORD_DATA_SIZE, RECORD_ARRAY, RECORD_BLANK, RECORD_BOF, RECORD_BOOLERR, RECORD_BOTTOMMARGIN, RECORD_BOUNDSHEET8, RECORD_CALCCOUNT, RECORD_CALCDELTA, RECORD_CALCITER, RECORD_CALCREFMODE, RECORD_CALCSAVERECALC, RECORD_CF, RECORD_CF12, RECORD_COLINFO, RECORD_CONDFMT, RECORD_CONDFMT12, RECORD_CONTINUE, RECORD_CONTINUEFRT12, RECORD_DATE1904, RECORD_DEFAULTROWHEIGHT, RECORD_DEFCOLWIDTH, RECORD_DIMENSIONS, RECORD_DV, RECORD_DVAL, RECORD_EOF, RECORD_EXTERNSHEET, RECORD_FILELOCK, RECORD_FILEPASS, RECORD_FONT, RECORD_FORMAT, RECORD_FORMULA, RECORD_HORIZONTALPAGEBREAKS, RECORD_INTERFACEHDR, RECORD_LABEL, RECORD_LABELSST, RECORD_LBL, RECORD_LEFTMARGIN, RECORD_MERGECELLS, RECORD_MULBLANK, RECORD_MULRK, RECORD_NOTE, RECORD_NUMBER, RECORD_OBJ, RECORD_PALETTE, RECORD_PRINTGRID, RECORD_PRINTROWCOL, RECORD_RIGHTMARGIN, RECORD_RK, RECORD_ROW, RECORD_RRDHEAD, RECORD_RRDINFO, RECORD_SETUP, RECORD_SHRFMLA, RECORD_SST, RECORD_STRING, RECORD_STYLE, RECORD_SUPBOOK, RECORD_TABLE, RECORD_TOPMARGIN, RECORD_TXO, RECORD_USREXCL, RECORD_VERTICALPAGEBREAKS, RECORD_WSBOOL, RECORD_XF };
|
|
157
|
+
export { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_TYPE_WORKSHEET, MAX_RECORD_DATA_SIZE, RECORD_AI, RECORD_ARRAY, RECORD_BLANK, RECORD_BOF, RECORD_BOOLERR, RECORD_BOTTOMMARGIN, RECORD_BOUNDSHEET8, RECORD_CALCCOUNT, RECORD_CALCDELTA, RECORD_CALCITER, RECORD_CALCREFMODE, RECORD_CALCSAVERECALC, RECORD_CF, RECORD_CF12, RECORD_COLINFO, RECORD_CONDFMT, RECORD_CONDFMT12, RECORD_CONTINUE, RECORD_CONTINUEFRT12, RECORD_DATE1904, RECORD_DEFAULTROWHEIGHT, RECORD_DEFCOLWIDTH, RECORD_DIMENSIONS, RECORD_DV, RECORD_DVAL, RECORD_EOF, RECORD_EXTERNSHEET, RECORD_FILELOCK, RECORD_FILEPASS, RECORD_FONT, RECORD_FORMAT, RECORD_FORMULA, RECORD_HORIZONTALPAGEBREAKS, RECORD_INTERFACEHDR, RECORD_LABEL, RECORD_LABELSST, RECORD_LBL, RECORD_LEFTMARGIN, RECORD_MERGECELLS, RECORD_MSODRAWING, RECORD_MSODRAWINGGROUP, RECORD_MSODRAWINGSELECTION, RECORD_MULBLANK, RECORD_MULRK, RECORD_NOTE, RECORD_NUMBER, RECORD_OBJ, RECORD_PALETTE, RECORD_PRINTGRID, RECORD_PRINTROWCOL, RECORD_RIGHTMARGIN, RECORD_RK, RECORD_ROW, RECORD_RRDHEAD, RECORD_RRDINFO, RECORD_SERIES, RECORD_SERIESTEXT, RECORD_SETUP, RECORD_SHRFMLA, RECORD_SIINDEX, RECORD_SST, RECORD_STRING, RECORD_STYLE, RECORD_SUPBOOK, RECORD_TABLE, RECORD_TOPMARGIN, RECORD_TXO, RECORD_USREXCL, RECORD_VERTICALPAGEBREAKS, RECORD_WSBOOL, RECORD_XF };
|
|
@@ -71,6 +71,20 @@ declare const RECORD_NOTE = 28;
|
|
|
71
71
|
declare const RECORD_OBJ = 93;
|
|
72
72
|
/** The rich text of a text box or comment, its characters and formatting runs carried in trailing Continue records ([MS-XLS] 2.4.329). */
|
|
73
73
|
declare const RECORD_TXO = 438;
|
|
74
|
+
/** One worksheet's own MS-ODRAW (Escher) drawing bytes, chunked across as many of these records as the drawing needs ([MS-XLS] 2.4.180's sibling "MsoDrawing", https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-xls/1b0b0ea3-5e1d-41ce-8e79-e27f1041331e) -- every MsoDrawing record's own data in one worksheet substream concatenates, in stream order, into one continuous Escher byte stream (src/drawing/escher.ts reads it). */
|
|
75
|
+
declare const RECORD_MSODRAWING = 236;
|
|
76
|
+
/** The workbook-wide counterpart of MsoDrawing, carrying the drawing group's own shared state -- most importantly the Blip Store (`OfficeArtBStoreContainer`) every worksheet's picture/chart shapes reference by index -- concatenated the same way, but read from the WORKBOOK GLOBALS substream rather than a worksheet's. */
|
|
77
|
+
declare const RECORD_MSODRAWINGGROUP = 235;
|
|
78
|
+
/** Which Escher shapes a worksheet had selected when it was last saved -- UI state this package has no use for, named here only so a reader that walks every record type in a worksheet substream can recognise and skip it rather than mistake it for drawing bytes. */
|
|
79
|
+
declare const RECORD_MSODRAWINGSELECTION = 237;
|
|
80
|
+
/** One data series' own type/count header and, following it, its four AI (BRAI) links -- categories, values, bubble sizes, name, each identified by the AI's own `id` field rather than by position ([MS-XLS] "Series"). */
|
|
81
|
+
declare const RECORD_SERIES = 4099;
|
|
82
|
+
/** A series' cached NAME text, when the file states one as a literal rather than through its own `AI id=0` formula reference ([MS-XLS] "SeriesText"): a ShortXLUnicodeString (one-byte length prefix), unlike the double-byte-length XLUnicodeString most other BIFF8 strings use. */
|
|
83
|
+
declare const RECORD_SERIESTEXT = 4109;
|
|
84
|
+
/** A data-role link on a series -- name, categories, values, or bubble sizes, selected by the record's own `id` field -- carrying either a literal value/text or a `ChartParsedFormula` range reference this package's own Ptg reference tokens (PtgArea3d/PtgRef3d) can resolve ([MS-XLS] "AI"/BRAI, restricted to a narrower Ptg grammar than a worksheet cell's own Formula record). */
|
|
85
|
+
declare const RECORD_AI = 4177;
|
|
86
|
+
/** Precedes each of the up-to-three chart-wide cached data blocks (values, categories, bubble sizes) a `SERIESDATA` production carries, its own `numIndex` field naming which of the three follows ([MS-XLS] "SIIndex"). Each cached `Number`/`BoolErr`/`Blank`/`Label` record that follows carries the same `col` field the worksheet cell-record family already does, here reused as the zero-based Series-record index the cached value belongs to. */
|
|
87
|
+
declare const RECORD_SIINDEX = 4197;
|
|
74
88
|
/** Whether the row and column headers are printed ([MS-XLS] 2.4.203). */
|
|
75
89
|
declare const RECORD_PRINTROWCOL = 42;
|
|
76
90
|
/** Whether the gridlines are printed ([MS-XLS] 2.4.202). */
|
|
@@ -140,4 +154,4 @@ declare const BIFF8_VERSION = 1536;
|
|
|
140
154
|
/** [MS-XLS] 2.1.4: "The record size ... MUST be less than or equal to 8224." The ceiling a writer splits a record at, and the bound a reader can sanity-check a declared size against. */
|
|
141
155
|
declare const MAX_RECORD_DATA_SIZE = 8224;
|
|
142
156
|
//#endregion
|
|
143
|
-
export { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_TYPE_WORKSHEET, MAX_RECORD_DATA_SIZE, RECORD_ARRAY, RECORD_BLANK, RECORD_BOF, RECORD_BOOLERR, RECORD_BOTTOMMARGIN, RECORD_BOUNDSHEET8, RECORD_CALCCOUNT, RECORD_CALCDELTA, RECORD_CALCITER, RECORD_CALCREFMODE, RECORD_CALCSAVERECALC, RECORD_CF, RECORD_CF12, RECORD_COLINFO, RECORD_CONDFMT, RECORD_CONDFMT12, RECORD_CONTINUE, RECORD_CONTINUEFRT12, RECORD_DATE1904, RECORD_DEFAULTROWHEIGHT, RECORD_DEFCOLWIDTH, RECORD_DIMENSIONS, RECORD_DV, RECORD_DVAL, RECORD_EOF, RECORD_EXTERNSHEET, RECORD_FILELOCK, RECORD_FILEPASS, RECORD_FONT, RECORD_FORMAT, RECORD_FORMULA, RECORD_HORIZONTALPAGEBREAKS, RECORD_INTERFACEHDR, RECORD_LABEL, RECORD_LABELSST, RECORD_LBL, RECORD_LEFTMARGIN, RECORD_MERGECELLS, RECORD_MULBLANK, RECORD_MULRK, RECORD_NOTE, RECORD_NUMBER, RECORD_OBJ, RECORD_PALETTE, RECORD_PRINTGRID, RECORD_PRINTROWCOL, RECORD_RIGHTMARGIN, RECORD_RK, RECORD_ROW, RECORD_RRDHEAD, RECORD_RRDINFO, RECORD_SETUP, RECORD_SHRFMLA, RECORD_SST, RECORD_STRING, RECORD_STYLE, RECORD_SUPBOOK, RECORD_TABLE, RECORD_TOPMARGIN, RECORD_TXO, RECORD_USREXCL, RECORD_VERTICALPAGEBREAKS, RECORD_WSBOOL, RECORD_XF };
|
|
157
|
+
export { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_TYPE_WORKSHEET, MAX_RECORD_DATA_SIZE, RECORD_AI, RECORD_ARRAY, RECORD_BLANK, RECORD_BOF, RECORD_BOOLERR, RECORD_BOTTOMMARGIN, RECORD_BOUNDSHEET8, RECORD_CALCCOUNT, RECORD_CALCDELTA, RECORD_CALCITER, RECORD_CALCREFMODE, RECORD_CALCSAVERECALC, RECORD_CF, RECORD_CF12, RECORD_COLINFO, RECORD_CONDFMT, RECORD_CONDFMT12, RECORD_CONTINUE, RECORD_CONTINUEFRT12, RECORD_DATE1904, RECORD_DEFAULTROWHEIGHT, RECORD_DEFCOLWIDTH, RECORD_DIMENSIONS, RECORD_DV, RECORD_DVAL, RECORD_EOF, RECORD_EXTERNSHEET, RECORD_FILELOCK, RECORD_FILEPASS, RECORD_FONT, RECORD_FORMAT, RECORD_FORMULA, RECORD_HORIZONTALPAGEBREAKS, RECORD_INTERFACEHDR, RECORD_LABEL, RECORD_LABELSST, RECORD_LBL, RECORD_LEFTMARGIN, RECORD_MERGECELLS, RECORD_MSODRAWING, RECORD_MSODRAWINGGROUP, RECORD_MSODRAWINGSELECTION, RECORD_MULBLANK, RECORD_MULRK, RECORD_NOTE, RECORD_NUMBER, RECORD_OBJ, RECORD_PALETTE, RECORD_PRINTGRID, RECORD_PRINTROWCOL, RECORD_RIGHTMARGIN, RECORD_RK, RECORD_ROW, RECORD_RRDHEAD, RECORD_RRDINFO, RECORD_SERIES, RECORD_SERIESTEXT, RECORD_SETUP, RECORD_SHRFMLA, RECORD_SIINDEX, RECORD_SST, RECORD_STRING, RECORD_STYLE, RECORD_SUPBOOK, RECORD_TABLE, RECORD_TOPMARGIN, RECORD_TXO, RECORD_USREXCL, RECORD_VERTICALPAGEBREAKS, RECORD_WSBOOL, RECORD_XF };
|
|
@@ -71,6 +71,20 @@ const RECORD_NOTE = 28;
|
|
|
71
71
|
const RECORD_OBJ = 93;
|
|
72
72
|
/** The rich text of a text box or comment, its characters and formatting runs carried in trailing Continue records ([MS-XLS] 2.4.329). */
|
|
73
73
|
const RECORD_TXO = 438;
|
|
74
|
+
/** One worksheet's own MS-ODRAW (Escher) drawing bytes, chunked across as many of these records as the drawing needs ([MS-XLS] 2.4.180's sibling "MsoDrawing", https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-xls/1b0b0ea3-5e1d-41ce-8e79-e27f1041331e) -- every MsoDrawing record's own data in one worksheet substream concatenates, in stream order, into one continuous Escher byte stream (src/drawing/escher.ts reads it). */
|
|
75
|
+
const RECORD_MSODRAWING = 236;
|
|
76
|
+
/** The workbook-wide counterpart of MsoDrawing, carrying the drawing group's own shared state -- most importantly the Blip Store (`OfficeArtBStoreContainer`) every worksheet's picture/chart shapes reference by index -- concatenated the same way, but read from the WORKBOOK GLOBALS substream rather than a worksheet's. */
|
|
77
|
+
const RECORD_MSODRAWINGGROUP = 235;
|
|
78
|
+
/** Which Escher shapes a worksheet had selected when it was last saved -- UI state this package has no use for, named here only so a reader that walks every record type in a worksheet substream can recognise and skip it rather than mistake it for drawing bytes. */
|
|
79
|
+
const RECORD_MSODRAWINGSELECTION = 237;
|
|
80
|
+
/** One data series' own type/count header and, following it, its four AI (BRAI) links -- categories, values, bubble sizes, name, each identified by the AI's own `id` field rather than by position ([MS-XLS] "Series"). */
|
|
81
|
+
const RECORD_SERIES = 4099;
|
|
82
|
+
/** A series' cached NAME text, when the file states one as a literal rather than through its own `AI id=0` formula reference ([MS-XLS] "SeriesText"): a ShortXLUnicodeString (one-byte length prefix), unlike the double-byte-length XLUnicodeString most other BIFF8 strings use. */
|
|
83
|
+
const RECORD_SERIESTEXT = 4109;
|
|
84
|
+
/** A data-role link on a series -- name, categories, values, or bubble sizes, selected by the record's own `id` field -- carrying either a literal value/text or a `ChartParsedFormula` range reference this package's own Ptg reference tokens (PtgArea3d/PtgRef3d) can resolve ([MS-XLS] "AI"/BRAI, restricted to a narrower Ptg grammar than a worksheet cell's own Formula record). */
|
|
85
|
+
const RECORD_AI = 4177;
|
|
86
|
+
/** Precedes each of the up-to-three chart-wide cached data blocks (values, categories, bubble sizes) a `SERIESDATA` production carries, its own `numIndex` field naming which of the three follows ([MS-XLS] "SIIndex"). Each cached `Number`/`BoolErr`/`Blank`/`Label` record that follows carries the same `col` field the worksheet cell-record family already does, here reused as the zero-based Series-record index the cached value belongs to. */
|
|
87
|
+
const RECORD_SIINDEX = 4197;
|
|
74
88
|
/** Whether the row and column headers are printed ([MS-XLS] 2.4.203). */
|
|
75
89
|
const RECORD_PRINTROWCOL = 42;
|
|
76
90
|
/** Whether the gridlines are printed ([MS-XLS] 2.4.202). */
|
|
@@ -140,4 +154,4 @@ const BIFF8_VERSION = 1536;
|
|
|
140
154
|
/** [MS-XLS] 2.1.4: "The record size ... MUST be less than or equal to 8224." The ceiling a writer splits a record at, and the bound a reader can sanity-check a declared size against. */
|
|
141
155
|
const MAX_RECORD_DATA_SIZE = 8224;
|
|
142
156
|
//#endregion
|
|
143
|
-
export { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_TYPE_WORKSHEET, MAX_RECORD_DATA_SIZE, RECORD_ARRAY, RECORD_BLANK, RECORD_BOF, RECORD_BOOLERR, RECORD_BOTTOMMARGIN, RECORD_BOUNDSHEET8, RECORD_CALCCOUNT, RECORD_CALCDELTA, RECORD_CALCITER, RECORD_CALCREFMODE, RECORD_CALCSAVERECALC, RECORD_CF, RECORD_CF12, RECORD_COLINFO, RECORD_CONDFMT, RECORD_CONDFMT12, RECORD_CONTINUE, RECORD_CONTINUEFRT12, RECORD_DATE1904, RECORD_DEFAULTROWHEIGHT, RECORD_DEFCOLWIDTH, RECORD_DIMENSIONS, RECORD_DV, RECORD_DVAL, RECORD_EOF, RECORD_EXTERNSHEET, RECORD_FILELOCK, RECORD_FILEPASS, RECORD_FONT, RECORD_FORMAT, RECORD_FORMULA, RECORD_HORIZONTALPAGEBREAKS, RECORD_INTERFACEHDR, RECORD_LABEL, RECORD_LABELSST, RECORD_LBL, RECORD_LEFTMARGIN, RECORD_MERGECELLS, RECORD_MULBLANK, RECORD_MULRK, RECORD_NOTE, RECORD_NUMBER, RECORD_OBJ, RECORD_PALETTE, RECORD_PRINTGRID, RECORD_PRINTROWCOL, RECORD_RIGHTMARGIN, RECORD_RK, RECORD_ROW, RECORD_RRDHEAD, RECORD_RRDINFO, RECORD_SETUP, RECORD_SHRFMLA, RECORD_SST, RECORD_STRING, RECORD_STYLE, RECORD_SUPBOOK, RECORD_TABLE, RECORD_TOPMARGIN, RECORD_TXO, RECORD_USREXCL, RECORD_VERTICALPAGEBREAKS, RECORD_WSBOOL, RECORD_XF };
|
|
157
|
+
export { BIFF8_VERSION, BOF_TYPE_CHART, BOF_TYPE_MACRO, BOF_TYPE_WORKBOOK, BOF_TYPE_WORKSHEET, MAX_RECORD_DATA_SIZE, RECORD_AI, RECORD_ARRAY, RECORD_BLANK, RECORD_BOF, RECORD_BOOLERR, RECORD_BOTTOMMARGIN, RECORD_BOUNDSHEET8, RECORD_CALCCOUNT, RECORD_CALCDELTA, RECORD_CALCITER, RECORD_CALCREFMODE, RECORD_CALCSAVERECALC, RECORD_CF, RECORD_CF12, RECORD_COLINFO, RECORD_CONDFMT, RECORD_CONDFMT12, RECORD_CONTINUE, RECORD_CONTINUEFRT12, RECORD_DATE1904, RECORD_DEFAULTROWHEIGHT, RECORD_DEFCOLWIDTH, RECORD_DIMENSIONS, RECORD_DV, RECORD_DVAL, RECORD_EOF, RECORD_EXTERNSHEET, RECORD_FILELOCK, RECORD_FILEPASS, RECORD_FONT, RECORD_FORMAT, RECORD_FORMULA, RECORD_HORIZONTALPAGEBREAKS, RECORD_INTERFACEHDR, RECORD_LABEL, RECORD_LABELSST, RECORD_LBL, RECORD_LEFTMARGIN, RECORD_MERGECELLS, RECORD_MSODRAWING, RECORD_MSODRAWINGGROUP, RECORD_MSODRAWINGSELECTION, RECORD_MULBLANK, RECORD_MULRK, RECORD_NOTE, RECORD_NUMBER, RECORD_OBJ, RECORD_PALETTE, RECORD_PRINTGRID, RECORD_PRINTROWCOL, RECORD_RIGHTMARGIN, RECORD_RK, RECORD_ROW, RECORD_RRDHEAD, RECORD_RRDINFO, RECORD_SERIES, RECORD_SERIESTEXT, RECORD_SETUP, RECORD_SHRFMLA, RECORD_SIINDEX, RECORD_SST, RECORD_STRING, RECORD_STYLE, RECORD_SUPBOOK, RECORD_TABLE, RECORD_TOPMARGIN, RECORD_TXO, RECORD_USREXCL, RECORD_VERTICALPAGEBREAKS, RECORD_WSBOOL, RECORD_XF };
|
package/dist/biff/substreams.cjs
CHANGED
|
@@ -34,16 +34,14 @@ function groupRecords(records) {
|
|
|
34
34
|
}
|
|
35
35
|
/** The BOF record's own fixed prefix: a two-byte vers followed by a two-byte dt. */
|
|
36
36
|
const BOF_PREFIX_SIZE = 4;
|
|
37
|
-
/** Splits a grouped record sequence into its substreams, verifying each BOF declares BIFF8. */
|
|
37
|
+
/** Splits a grouped record sequence into its substreams, verifying each BOF declares BIFF8. A BOF met while a substream is already open pushes that substream onto a stack and starts a nested one; the nested substream is closed and reported (via its own EOF) before its parent resumes collecting records -- see this module's own top comment for why a stack, not a flat "BOF ends the previous substream", is what a chart embedded in a worksheet needs. */
|
|
38
38
|
function splitSubstreams(groups) {
|
|
39
39
|
const substreams = [];
|
|
40
|
+
const stack = [];
|
|
40
41
|
let current;
|
|
41
42
|
for (const group of groups) {
|
|
42
43
|
if (group.type === 2057) {
|
|
43
|
-
if (current !== void 0)
|
|
44
|
-
...current,
|
|
45
|
-
index: substreams.length
|
|
46
|
-
});
|
|
44
|
+
if (current !== void 0) stack.push(current);
|
|
47
45
|
current = {
|
|
48
46
|
documentType: readBofDocumentType(group),
|
|
49
47
|
records: [],
|
|
@@ -57,14 +55,15 @@ function splitSubstreams(groups) {
|
|
|
57
55
|
...current,
|
|
58
56
|
index: substreams.length
|
|
59
57
|
});
|
|
60
|
-
current =
|
|
58
|
+
current = stack.pop();
|
|
61
59
|
}
|
|
62
60
|
continue;
|
|
63
61
|
}
|
|
64
62
|
current?.records.push(group);
|
|
65
63
|
}
|
|
66
|
-
if (current !== void 0)
|
|
67
|
-
|
|
64
|
+
if (current !== void 0) stack.push(current);
|
|
65
|
+
for (const open of stack.reverse()) substreams.push({
|
|
66
|
+
...open,
|
|
68
67
|
index: substreams.length
|
|
69
68
|
});
|
|
70
69
|
return substreams;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as splitSubstreams, i as recordByteLength, n as Substream, r as groupRecords, t as RecordGroup } from "../substreams-
|
|
1
|
+
import { a as splitSubstreams, i as recordByteLength, n as Substream, r as groupRecords, t as RecordGroup } from "../substreams-XDNgDvRJ.cjs";
|
|
2
2
|
export { RecordGroup, Substream, groupRecords, recordByteLength, splitSubstreams };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as splitSubstreams, i as recordByteLength, n as Substream, r as groupRecords, t as RecordGroup } from "../substreams-
|
|
1
|
+
import { a as splitSubstreams, i as recordByteLength, n as Substream, r as groupRecords, t as RecordGroup } from "../substreams-CgTHx5kX.js";
|
|
2
2
|
export { RecordGroup, Substream, groupRecords, recordByteLength, splitSubstreams };
|
package/dist/biff/substreams.js
CHANGED
|
@@ -33,16 +33,14 @@ function groupRecords(records) {
|
|
|
33
33
|
}
|
|
34
34
|
/** The BOF record's own fixed prefix: a two-byte vers followed by a two-byte dt. */
|
|
35
35
|
const BOF_PREFIX_SIZE = 4;
|
|
36
|
-
/** Splits a grouped record sequence into its substreams, verifying each BOF declares BIFF8. */
|
|
36
|
+
/** Splits a grouped record sequence into its substreams, verifying each BOF declares BIFF8. A BOF met while a substream is already open pushes that substream onto a stack and starts a nested one; the nested substream is closed and reported (via its own EOF) before its parent resumes collecting records -- see this module's own top comment for why a stack, not a flat "BOF ends the previous substream", is what a chart embedded in a worksheet needs. */
|
|
37
37
|
function splitSubstreams(groups) {
|
|
38
38
|
const substreams = [];
|
|
39
|
+
const stack = [];
|
|
39
40
|
let current;
|
|
40
41
|
for (const group of groups) {
|
|
41
42
|
if (group.type === 2057) {
|
|
42
|
-
if (current !== void 0)
|
|
43
|
-
...current,
|
|
44
|
-
index: substreams.length
|
|
45
|
-
});
|
|
43
|
+
if (current !== void 0) stack.push(current);
|
|
46
44
|
current = {
|
|
47
45
|
documentType: readBofDocumentType(group),
|
|
48
46
|
records: [],
|
|
@@ -56,14 +54,15 @@ function splitSubstreams(groups) {
|
|
|
56
54
|
...current,
|
|
57
55
|
index: substreams.length
|
|
58
56
|
});
|
|
59
|
-
current =
|
|
57
|
+
current = stack.pop();
|
|
60
58
|
}
|
|
61
59
|
continue;
|
|
62
60
|
}
|
|
63
61
|
current?.records.push(group);
|
|
64
62
|
}
|
|
65
|
-
if (current !== void 0)
|
|
66
|
-
|
|
63
|
+
if (current !== void 0) stack.push(current);
|
|
64
|
+
for (const open of stack.reverse()) substreams.push({
|
|
65
|
+
...open,
|
|
67
66
|
index: substreams.length
|
|
68
67
|
});
|
|
69
68
|
return substreams;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as FormulaSheetContext } from "./ptg-CCBbJLZJ.cjs";
|
|
2
|
-
import { t as RecordGroup } from "./substreams-
|
|
3
|
-
import { i as RawConditionalFormatStyle } from "./conditional-format-
|
|
2
|
+
import { t as RecordGroup } from "./substreams-XDNgDvRJ.cjs";
|
|
3
|
+
import { i as RawConditionalFormatStyle } from "./conditional-format-Bt1vRWgc.cjs";
|
|
4
4
|
import { Color, ContentSheetConditionalFormat, ContentSheetConditionalFormatValue, ContentSheetRange } from "document-schema.js";
|
|
5
5
|
//#region src/workbook/conditional-format-12.d.ts
|
|
6
6
|
type RawCfColor = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as FormulaSheetContext } from "./ptg-CCBbJLZJ.js";
|
|
2
|
-
import { t as RecordGroup } from "./substreams-
|
|
3
|
-
import { i as RawConditionalFormatStyle } from "./conditional-format-
|
|
2
|
+
import { t as RecordGroup } from "./substreams-CgTHx5kX.js";
|
|
3
|
+
import { i as RawConditionalFormatStyle } from "./conditional-format-Cqcjnm7O.js";
|
|
4
4
|
import { Color, ContentSheetConditionalFormat, ContentSheetConditionalFormatValue, ContentSheetRange } from "document-schema.js";
|
|
5
5
|
//#region src/workbook/conditional-format-12.d.ts
|
|
6
6
|
type RawCfColor = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as FormulaSheetContext } from "./ptg-CCBbJLZJ.cjs";
|
|
2
|
-
import { t as RecordGroup } from "./substreams-
|
|
2
|
+
import { t as RecordGroup } from "./substreams-XDNgDvRJ.cjs";
|
|
3
3
|
import { ContentSheetRange, SheetRuleOperator } from "document-schema.js";
|
|
4
4
|
//#region src/workbook/conditional-format.d.ts
|
|
5
5
|
interface RawConditionalFormatFill {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as FormulaSheetContext } from "./ptg-CCBbJLZJ.js";
|
|
2
|
-
import { t as RecordGroup } from "./substreams-
|
|
2
|
+
import { t as RecordGroup } from "./substreams-CgTHx5kX.js";
|
|
3
3
|
import { ContentSheetRange, SheetRuleOperator } from "document-schema.js";
|
|
4
4
|
//#region src/workbook/conditional-format.d.ts
|
|
5
5
|
interface RawConditionalFormatFill {
|
package/dist/content.cjs
CHANGED
|
@@ -6,7 +6,10 @@ const require_units = require("./units.cjs");
|
|
|
6
6
|
const require_biff_print_setup = require("./biff/print-setup.cjs");
|
|
7
7
|
const require_biff_substreams = require("./biff/substreams.cjs");
|
|
8
8
|
const require_biff_xf_colors = require("./biff/xf-colors.cjs");
|
|
9
|
+
const require_drawing_blips = require("./drawing/blips.cjs");
|
|
10
|
+
const require_drawing_bytes = require("./drawing/bytes.cjs");
|
|
9
11
|
const require_workbook_comments = require("./workbook/comments.cjs");
|
|
12
|
+
const require_workbook_drawing = require("./workbook/drawing.cjs");
|
|
10
13
|
const require_serial = require("./serial.cjs");
|
|
11
14
|
const require_workbook_globals = require("./workbook/globals.cjs");
|
|
12
15
|
const require_workbook_sheet = require("./workbook/sheet.cjs");
|
|
@@ -91,16 +94,22 @@ function readXlsContent(bytes, password) {
|
|
|
91
94
|
const globalsSubstream = substreams[0];
|
|
92
95
|
if (globalsSubstream === void 0) throw new require_biff_records.BiffFormatError("workbook stream holds no substreams, so it carries no globals substream");
|
|
93
96
|
const globals = require_workbook_globals.readWorkbookGlobals(globalsSubstream.records);
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
sheetIndex
|
|
97
|
-
})).filter(({ entry }) => entry.sheetType === SHEET_TYPE_WORKSHEET).map(({ entry, sheetIndex }) => readSheet(entry, sheetIndex, substreams, globals));
|
|
97
|
+
const blipStore = require_drawing_blips.readBlipStore(concatDrawingGroupBytes(globalsSubstream.records));
|
|
98
|
+
const documentMetadata = metadata === void 0 ? {} : (0, archive_codec.summaryInformationToLayoutMetadata)((0, archive_codec.readSummaryInformation)(metadata));
|
|
98
99
|
return {
|
|
99
100
|
kind: "spreadsheet",
|
|
100
|
-
metadata:
|
|
101
|
-
sheets
|
|
101
|
+
metadata: documentMetadata,
|
|
102
|
+
sheets: globals.sheets.map((entry, sheetIndex) => ({
|
|
103
|
+
entry,
|
|
104
|
+
sheetIndex
|
|
105
|
+
})).filter(({ entry }) => entry.sheetType === SHEET_TYPE_WORKSHEET).map(({ entry, sheetIndex }) => readSheet(entry, sheetIndex, substreams, globals, blipStore, documentMetadata))
|
|
102
106
|
};
|
|
103
107
|
}
|
|
108
|
+
/** Every MsoDrawingGroup record's own data, in stream order, concatenated into one Escher byte stream -- the workbook-wide counterpart of a worksheet's own MsoDrawing concatenation (drawing/shapes.ts's own readSheetShapes), carrying the Blip Store rather than any one sheet's shape tree. */
|
|
109
|
+
function concatDrawingGroupBytes(records) {
|
|
110
|
+
const chunks = records.filter((record) => record.type === 235).map((record) => record.blocks[0]).filter((block) => block !== void 0);
|
|
111
|
+
return require_drawing_bytes.concatBytes(chunks);
|
|
112
|
+
}
|
|
104
113
|
/** The tree-form read: readXlsContent composed with the schema's own structural transform, exactly as ooxml.js's readXlsx wraps readXlsxContent. */
|
|
105
114
|
function readXls(bytes, password) {
|
|
106
115
|
return (0, document_schema_js.assembleTree)(readXlsContent(bytes, password));
|
|
@@ -110,8 +119,17 @@ function readXls(bytes, password) {
|
|
|
110
119
|
*
|
|
111
120
|
* The substream is found by the byte offset BoundSheet8's lbPlyPos names, not by position: the order sheets appear in the workbook (which is BoundSheet8 order, and therefore the order of `globals.sheets`) is not required to match the order their substreams were written in. A sheet whose substream cannot be found still produces a ContentSheet, empty -- losing the sheet entirely would be a worse answer than losing its cells, since its name and position are real information the workbook did state.
|
|
112
121
|
*/
|
|
113
|
-
function readSheet(entry, sheetIndex, substreams, globals) {
|
|
122
|
+
function readSheet(entry, sheetIndex, substreams, globals, blipStore, documentMetadata) {
|
|
114
123
|
const substream = substreams.find((candidate) => candidate.offset === entry.bofPosition && candidate.documentType === 16);
|
|
124
|
+
const emptyPrint = {
|
|
125
|
+
marginsPt: {},
|
|
126
|
+
rowBreaks: [],
|
|
127
|
+
columnBreaks: []
|
|
128
|
+
};
|
|
129
|
+
const formulaSheets = {
|
|
130
|
+
sheets: globals.sheets,
|
|
131
|
+
sheetRanges: globals.sheetRanges
|
|
132
|
+
};
|
|
115
133
|
const raw = substream === void 0 ? {
|
|
116
134
|
cells: [],
|
|
117
135
|
rows: [],
|
|
@@ -120,29 +138,33 @@ function readSheet(entry, sheetIndex, substreams, globals) {
|
|
|
120
138
|
dataValidations: [],
|
|
121
139
|
conditionalFormats: [],
|
|
122
140
|
conditionalFormats12: [],
|
|
123
|
-
print:
|
|
124
|
-
|
|
125
|
-
rowBreaks: [],
|
|
126
|
-
columnBreaks: []
|
|
127
|
-
}
|
|
128
|
-
} : require_workbook_sheet.readSheetRecords(substream.records, globals.sharedStrings, {
|
|
129
|
-
sheets: globals.sheets,
|
|
130
|
-
sheetRanges: globals.sheetRanges
|
|
131
|
-
});
|
|
141
|
+
print: emptyPrint
|
|
142
|
+
} : require_workbook_sheet.readSheetRecords(substream.records, globals.sharedStrings, formulaSheets);
|
|
132
143
|
const comments = substream === void 0 ? /* @__PURE__ */ new Map() : require_workbook_comments.readSheetComments(substream.records);
|
|
133
144
|
const cells = mapCells(raw, globals);
|
|
134
145
|
applyCellComments(comments, cells);
|
|
135
146
|
const dataValidations = mapDataValidations(raw.dataValidations);
|
|
136
147
|
const conditionalFormats = [...mapConditionalFormats(raw.conditionalFormats, globals.palette), ...mapConditionalFormats12(raw.conditionalFormats12, globals.palette)];
|
|
148
|
+
const drawing = require_workbook_drawing.readSheetDrawing(substream?.records ?? [], {
|
|
149
|
+
blipStore,
|
|
150
|
+
columns: raw.columns,
|
|
151
|
+
rows: raw.rows,
|
|
152
|
+
ownSheetIndex: sheetIndex,
|
|
153
|
+
formulaSheets,
|
|
154
|
+
ownSheetCells: cells,
|
|
155
|
+
metadata: documentMetadata,
|
|
156
|
+
allSubstreams: substreams
|
|
157
|
+
});
|
|
137
158
|
return {
|
|
138
159
|
name: entry.name,
|
|
139
160
|
cells,
|
|
140
161
|
columns: mapColumns(raw),
|
|
141
162
|
rows: mapRows(raw),
|
|
142
|
-
images: [],
|
|
163
|
+
images: [...drawing.images],
|
|
143
164
|
printSettings: mapPrintSettings(raw.print, globals.printNames.get(sheetIndex)),
|
|
144
165
|
...dataValidations.length > 0 ? { dataValidations } : {},
|
|
145
|
-
...conditionalFormats.length > 0 ? { conditionalFormats } : {}
|
|
166
|
+
...conditionalFormats.length > 0 ? { conditionalFormats } : {},
|
|
167
|
+
...drawing.embeddedObjects.length > 0 ? { embeddedObjects: [...drawing.embeddedObjects] } : {}
|
|
146
168
|
};
|
|
147
169
|
}
|
|
148
170
|
function mapConditionalFormats(raw, palette) {
|
package/dist/content.js
CHANGED
|
@@ -5,7 +5,10 @@ import { inchesToPoints } from "./units.js";
|
|
|
5
5
|
import { pageSizeFromSetup } from "./biff/print-setup.js";
|
|
6
6
|
import { groupRecords, splitSubstreams } from "./biff/substreams.js";
|
|
7
7
|
import { applyTint, resolveBorderEdge, resolveFillBackground, resolveIcvColor } from "./biff/xf-colors.js";
|
|
8
|
+
import { readBlipStore } from "./drawing/blips.js";
|
|
9
|
+
import { concatBytes } from "./drawing/bytes.js";
|
|
8
10
|
import { readSheetComments } from "./workbook/comments.js";
|
|
11
|
+
import { readSheetDrawing } from "./workbook/drawing.js";
|
|
9
12
|
import { serialToIsoDate, serialToIsoDateTime, serialToIsoTime } from "./serial.js";
|
|
10
13
|
import { formatCodeOf, readWorkbookGlobals } from "./workbook/globals.js";
|
|
11
14
|
import { readSheetRecords } from "./workbook/sheet.js";
|
|
@@ -90,16 +93,22 @@ function readXlsContent(bytes, password) {
|
|
|
90
93
|
const globalsSubstream = substreams[0];
|
|
91
94
|
if (globalsSubstream === void 0) throw new BiffFormatError("workbook stream holds no substreams, so it carries no globals substream");
|
|
92
95
|
const globals = readWorkbookGlobals(globalsSubstream.records);
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
sheetIndex
|
|
96
|
-
})).filter(({ entry }) => entry.sheetType === SHEET_TYPE_WORKSHEET).map(({ entry, sheetIndex }) => readSheet(entry, sheetIndex, substreams, globals));
|
|
96
|
+
const blipStore = readBlipStore(concatDrawingGroupBytes(globalsSubstream.records));
|
|
97
|
+
const documentMetadata = metadata === void 0 ? {} : summaryInformationToLayoutMetadata(readSummaryInformation(metadata));
|
|
97
98
|
return {
|
|
98
99
|
kind: "spreadsheet",
|
|
99
|
-
metadata:
|
|
100
|
-
sheets
|
|
100
|
+
metadata: documentMetadata,
|
|
101
|
+
sheets: globals.sheets.map((entry, sheetIndex) => ({
|
|
102
|
+
entry,
|
|
103
|
+
sheetIndex
|
|
104
|
+
})).filter(({ entry }) => entry.sheetType === SHEET_TYPE_WORKSHEET).map(({ entry, sheetIndex }) => readSheet(entry, sheetIndex, substreams, globals, blipStore, documentMetadata))
|
|
101
105
|
};
|
|
102
106
|
}
|
|
107
|
+
/** Every MsoDrawingGroup record's own data, in stream order, concatenated into one Escher byte stream -- the workbook-wide counterpart of a worksheet's own MsoDrawing concatenation (drawing/shapes.ts's own readSheetShapes), carrying the Blip Store rather than any one sheet's shape tree. */
|
|
108
|
+
function concatDrawingGroupBytes(records) {
|
|
109
|
+
const chunks = records.filter((record) => record.type === 235).map((record) => record.blocks[0]).filter((block) => block !== void 0);
|
|
110
|
+
return concatBytes(chunks);
|
|
111
|
+
}
|
|
103
112
|
/** The tree-form read: readXlsContent composed with the schema's own structural transform, exactly as ooxml.js's readXlsx wraps readXlsxContent. */
|
|
104
113
|
function readXls(bytes, password) {
|
|
105
114
|
return assembleTree(readXlsContent(bytes, password));
|
|
@@ -109,8 +118,17 @@ function readXls(bytes, password) {
|
|
|
109
118
|
*
|
|
110
119
|
* The substream is found by the byte offset BoundSheet8's lbPlyPos names, not by position: the order sheets appear in the workbook (which is BoundSheet8 order, and therefore the order of `globals.sheets`) is not required to match the order their substreams were written in. A sheet whose substream cannot be found still produces a ContentSheet, empty -- losing the sheet entirely would be a worse answer than losing its cells, since its name and position are real information the workbook did state.
|
|
111
120
|
*/
|
|
112
|
-
function readSheet(entry, sheetIndex, substreams, globals) {
|
|
121
|
+
function readSheet(entry, sheetIndex, substreams, globals, blipStore, documentMetadata) {
|
|
113
122
|
const substream = substreams.find((candidate) => candidate.offset === entry.bofPosition && candidate.documentType === 16);
|
|
123
|
+
const emptyPrint = {
|
|
124
|
+
marginsPt: {},
|
|
125
|
+
rowBreaks: [],
|
|
126
|
+
columnBreaks: []
|
|
127
|
+
};
|
|
128
|
+
const formulaSheets = {
|
|
129
|
+
sheets: globals.sheets,
|
|
130
|
+
sheetRanges: globals.sheetRanges
|
|
131
|
+
};
|
|
114
132
|
const raw = substream === void 0 ? {
|
|
115
133
|
cells: [],
|
|
116
134
|
rows: [],
|
|
@@ -119,29 +137,33 @@ function readSheet(entry, sheetIndex, substreams, globals) {
|
|
|
119
137
|
dataValidations: [],
|
|
120
138
|
conditionalFormats: [],
|
|
121
139
|
conditionalFormats12: [],
|
|
122
|
-
print:
|
|
123
|
-
|
|
124
|
-
rowBreaks: [],
|
|
125
|
-
columnBreaks: []
|
|
126
|
-
}
|
|
127
|
-
} : readSheetRecords(substream.records, globals.sharedStrings, {
|
|
128
|
-
sheets: globals.sheets,
|
|
129
|
-
sheetRanges: globals.sheetRanges
|
|
130
|
-
});
|
|
140
|
+
print: emptyPrint
|
|
141
|
+
} : readSheetRecords(substream.records, globals.sharedStrings, formulaSheets);
|
|
131
142
|
const comments = substream === void 0 ? /* @__PURE__ */ new Map() : readSheetComments(substream.records);
|
|
132
143
|
const cells = mapCells(raw, globals);
|
|
133
144
|
applyCellComments(comments, cells);
|
|
134
145
|
const dataValidations = mapDataValidations(raw.dataValidations);
|
|
135
146
|
const conditionalFormats = [...mapConditionalFormats(raw.conditionalFormats, globals.palette), ...mapConditionalFormats12(raw.conditionalFormats12, globals.palette)];
|
|
147
|
+
const drawing = readSheetDrawing(substream?.records ?? [], {
|
|
148
|
+
blipStore,
|
|
149
|
+
columns: raw.columns,
|
|
150
|
+
rows: raw.rows,
|
|
151
|
+
ownSheetIndex: sheetIndex,
|
|
152
|
+
formulaSheets,
|
|
153
|
+
ownSheetCells: cells,
|
|
154
|
+
metadata: documentMetadata,
|
|
155
|
+
allSubstreams: substreams
|
|
156
|
+
});
|
|
136
157
|
return {
|
|
137
158
|
name: entry.name,
|
|
138
159
|
cells,
|
|
139
160
|
columns: mapColumns(raw),
|
|
140
161
|
rows: mapRows(raw),
|
|
141
|
-
images: [],
|
|
162
|
+
images: [...drawing.images],
|
|
142
163
|
printSettings: mapPrintSettings(raw.print, globals.printNames.get(sheetIndex)),
|
|
143
164
|
...dataValidations.length > 0 ? { dataValidations } : {},
|
|
144
|
-
...conditionalFormats.length > 0 ? { conditionalFormats } : {}
|
|
165
|
+
...conditionalFormats.length > 0 ? { conditionalFormats } : {},
|
|
166
|
+
...drawing.embeddedObjects.length > 0 ? { embeddedObjects: [...drawing.embeddedObjects] } : {}
|
|
145
167
|
};
|
|
146
168
|
}
|
|
147
169
|
function mapConditionalFormats(raw, palette) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as FormulaSheetContext } from "./ptg-CCBbJLZJ.js";
|
|
2
|
-
import { t as RecordGroup } from "./substreams-
|
|
2
|
+
import { t as RecordGroup } from "./substreams-CgTHx5kX.js";
|
|
3
3
|
import { ContentSheetRange, SheetRuleOperator } from "document-schema.js";
|
|
4
4
|
//#region src/workbook/data-validation.d.ts
|
|
5
5
|
interface RawDataValidation {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as FormulaSheetContext } from "./ptg-CCBbJLZJ.cjs";
|
|
2
|
-
import { t as RecordGroup } from "./substreams-
|
|
2
|
+
import { t as RecordGroup } from "./substreams-XDNgDvRJ.cjs";
|
|
3
3
|
import { ContentSheetRange, SheetRuleOperator } from "document-schema.js";
|
|
4
4
|
//#region src/workbook/data-validation.d.ts
|
|
5
5
|
interface RawDataValidation {
|