doc-codec 2.4.3 → 2.5.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 +47 -16
- package/dist/chp-B6AOh85P.d.ts +18 -0
- package/dist/chp-BpCqpb7V.d.cts +18 -0
- package/dist/detect.cjs +3 -0
- package/dist/detect.d.cts +3 -1
- package/dist/detect.d.ts +3 -1
- package/dist/detect.js +3 -1
- package/dist/fib/fib.cjs +14 -0
- package/dist/fib/fib.d.cts +1 -1
- package/dist/fib/fib.d.ts +1 -1
- package/dist/fib/fib.js +14 -0
- package/dist/fib/offsets.cjs +14 -0
- package/dist/fib/offsets.d.cts +14 -0
- package/dist/fib/offsets.d.ts +14 -0
- package/dist/fib/offsets.js +14 -0
- package/dist/{fib-DWFta19r.d.cts → fib-6BFIx153.d.cts} +14 -0
- package/dist/{fib-DWFta19r.d.ts → fib-6BFIx153.d.ts} +14 -0
- package/dist/fkp-I-laf-8y.d.cts +33 -0
- package/dist/fkp-I-laf-8y.d.ts +33 -0
- package/dist/headers-footers.cjs +34 -0
- package/dist/headers-footers.d.cts +16 -0
- package/dist/headers-footers.d.ts +16 -0
- package/dist/headers-footers.js +33 -0
- package/dist/index.cjs +20 -9
- package/dist/index.d.cts +16 -12
- package/dist/index.d.ts +16 -12
- package/dist/index.js +15 -11
- package/dist/list/numbering-write.d.cts +1 -1
- package/dist/list/numbering-write.d.ts +1 -1
- package/dist/list/numbering.d.cts +23 -1
- package/dist/list/numbering.d.ts +23 -1
- package/dist/notes.cjs +26 -0
- package/dist/notes.d.cts +20 -0
- package/dist/notes.d.ts +20 -0
- package/dist/notes.js +25 -0
- package/dist/{pap-BT1p0uzu.d.cts → pap-BQ2E17K9.d.cts} +5 -3
- package/dist/{pap-DOFLMWcG.d.ts → pap-iWFIpCdo.d.ts} +5 -3
- package/dist/paragraphs-DQUp8_HB.d.cts +31 -0
- package/dist/paragraphs-s2lJ6w2I.d.ts +31 -0
- package/dist/pictures.cjs +93 -0
- package/dist/pictures.d.cts +6 -0
- package/dist/pictures.d.ts +6 -0
- package/dist/pictures.js +92 -0
- package/dist/piece-table-CA18mhjv.d.cts +28 -0
- package/dist/piece-table-CA18mhjv.d.ts +28 -0
- package/dist/prop/chp.d.cts +1 -17
- package/dist/prop/chp.d.ts +1 -17
- package/dist/prop/fkp.d.cts +1 -32
- package/dist/prop/fkp.d.ts +1 -32
- package/dist/prop/pap.cjs +4 -2
- package/dist/prop/pap.d.cts +1 -1
- package/dist/prop/pap.d.ts +1 -1
- package/dist/prop/pap.js +4 -2
- package/dist/prop/sep.cjs +20 -10
- package/dist/prop/sep.d.cts +8 -4
- package/dist/prop/sep.d.ts +8 -4
- package/dist/prop/sep.js +20 -10
- package/dist/read.cjs +47 -151
- package/dist/read.d.cts +13 -15
- package/dist/read.d.ts +13 -15
- package/dist/read.js +49 -153
- package/dist/stsh-Bj0YSEOp.d.ts +40 -0
- package/dist/stsh-CK59x6XG.d.cts +40 -0
- package/dist/style/stsh.d.cts +1 -39
- package/dist/style/stsh.d.ts +1 -39
- package/dist/subdocument.cjs +20 -0
- package/dist/subdocument.d.cts +8 -0
- package/dist/subdocument.d.ts +8 -0
- package/dist/subdocument.js +18 -0
- package/dist/table/read.cjs +31 -17
- package/dist/table/read.d.cts +1 -1
- package/dist/table/read.d.ts +1 -1
- package/dist/table/read.js +32 -18
- package/dist/text/characters.d.cts +1 -1
- package/dist/text/characters.d.ts +1 -1
- package/dist/text/paragraphs.cjs +189 -0
- package/dist/text/paragraphs.d.cts +2 -0
- package/dist/text/paragraphs.d.ts +2 -0
- package/dist/text/paragraphs.js +187 -0
- package/dist/text/piece-table.d.cts +1 -27
- package/dist/text/piece-table.d.ts +1 -27
- package/dist/write.cjs +3 -3
- package/dist/write.js +3 -3
- package/package.json +1 -1
- package/dist/numbering-DSpm9w6y.d.cts +0 -24
- package/dist/numbering-DayjnHXY.d.ts +0 -24
package/README.md
CHANGED
|
@@ -17,14 +17,17 @@ Built and shipped, on the read side:
|
|
|
17
17
|
- **Text reconstruction** — `readTextRange` turns a range of character positions into real characters through [MS-DOC] 2.4.1's own Retrieving Text algorithm, applying the specification's byte-to-code-point mapping for compressed pieces, and returns each character's byte offset alongside it.
|
|
18
18
|
- **Character and paragraph formatting** — the `PlcBteChpx`/`PlcBtePapx` bin tables and the `ChpxFkp`/`PapxFkp` pages behind them, the `Sprm`/`Prl` operand-sizing rules, and the subset of the character- and paragraph-property tables listed under [What is converted](#what-is-converted), now including `sprmCRgFtc0`'s font-table lookup (see [The font table](#the-font-table)).
|
|
19
19
|
- **The style sheet** — `parseStsh` reads each style's index, name, kind, parent, and (for a paragraph or character style) its own `grLPUpxSw` formatting sets; `resolveStyleFormatting` walks the `istdBase` inheritance chain and folds each style's own paragraph/character properties, most-specific style winning, beneath a paragraph's or run's own direct exceptions ([ExaDev/documents.js#1005](https://github.com/ExaDev/documents.js/issues/1005)). `headingLevelFromIstd` applies `sprmPIstd`'s own rule that an `istd` of 1 through 9 states an outline level.
|
|
20
|
-
- **Tables** — `table/read.ts`'s `assembleBlocks`
|
|
20
|
+
- **Tables, including nested tables** — `table/read.ts`'s `walkBlocksAtDepth`/`assembleBlocks` fold a contiguous run of table-depth paragraphs into a real `ContentTable`, at whatever nesting depth the file states: cell boundaries at each cell-mark (`0x07`) character at depth 1, or a paragraph mark (`0x000D`) carrying `sprmPFInnerTableCell` one level deeper ([MS-DOC] 2.4.3's own depth-1-vs-deeper distinction), a cell holding more than one paragraph where only its last ends in a cell mark, and each row's own trailing mark (`sprmPFTtp`/`sprmPFInnerTtp`) resolved through `table/tap.ts`'s `applyTableSprms` for its TAP — column boundaries and every physical cell's own horizontal/vertical merge state, from `sprmTDefTable`'s `TDefTableOperand` (and a `sprmTMerge` range or `sprmTVertMerge` per-cell flag where a real producer states a merge that way instead — see [Tables](#tables) below for why both are read). A table nested inside a table cell (detected via `sprmPItap`/`sprmPFInnerTableCell`/`sprmPFInnerTtp`) resolves to a real nested `ContentTable`, to whatever depth the file actually states, rather than being refused. A row whose own TAP this reader cannot resolve at all — no direct `sprmTDefTable` anywhere in its grpprl, or a cell-mark count that disagrees with it — degrades the whole run back to flat paragraphs instead, since that is a legal producer choice this reader does not yet follow rather than corruption (see [Tables](#tables)).
|
|
21
21
|
- **Table cell decoration** — `ContentTableCell.background` and `.borders`, from every encoding [MS-DOC] states them in: each cell's own four `Brc80` borders inside `TC80`, the exact-colour `sprmTSetBrc` layer a real producer writes beside them, the row-level shading arrays (`sprmTDefTableShd`/`2nd`/`3rd`, their `Raw` counterparts, the Word 97-era `sprmTDefTableShd80`, and `sprmTSetShd`/`sprmTSetShdOdd`), and, cascaded onto whichever cells and sides those leave unstated, the row/table-level `sprmTTableBorders`/`sprmTTableBorders80` border set and `sprmTSetShdTable`'s own per-row background. See [Cell decoration](#cell-decoration).
|
|
22
22
|
- **`readDocContent`** — the whole chain, producing a `'wordprocessing'` `ContentDocument` of paragraphs, runs and tables.
|
|
23
23
|
- **`isDocBytes`** — distinguishes a `.doc` from the `.xls`, `.ppt` and OLE embeddings that share its container, by looking for a `WordDocument` stream carrying `FibBase.wIdent`.
|
|
24
24
|
- **Document metadata** — `title`/`subject`/`author`/`keywords`/`createdIso`/`modifiedIso` read from a `"\x05SummaryInformation"` stream when one is present (see [Metadata](#metadata)); `comments` and `lastPrintedIso` remain unread, since `LayoutMetadata` has no field for either.
|
|
25
25
|
- **RC4-encrypted documents, decrypted for real (ExaDev/documents.js#1113)** — `readDocContent`/`readDocStreams` take an optional `password`, verified against the Table stream's own `EncryptionHeader` before anything is trusted (see [Encryption](#encryption)). XOR obfuscation and RC4 CryptoAPI stay refused, tracked on [ExaDev/documents.js#922](https://github.com/ExaDev/documents.js/issues/922).
|
|
26
26
|
- **Numbering definitions** — `readDocContent`'s own `numbering` field: every list's glyph/format, level-text template, and start-at value, resolved from `PlfLst`/`PlfLfo` and keyed by the same `listId` a paragraph's `ContentParagraph.list.numId` already carries. See [Numbering definitions](#numbering-definitions), which also covers `writeDocContent`'s own inverse.
|
|
27
|
-
- **
|
|
27
|
+
- **Every section's own page size and margins** — `prop/sep.ts`'s `readAllSectionProperties` resolves every `Sed` `PlcfSed` carries, each into its own `ContentSection.pageSize`/`.margins` (`sprmSXaPage`/`sprmSYaPage`/`sprmSDxaLeft`/`sprmSDxaRight`/`sprmSDyaTop`/`sprmSDyaBottom`), falling back field by field to Word's own new-document default (US Letter, one-inch margins) for a document carrying no `PlcfSed` at all, or for any one sprm a section leaves unstated. `read.ts`'s `splitIntoSections` groups the main document's own paragraphs by which section each falls in, per [MS-DOC] 2.8.26's own "each CP specifies the beginning of a range of text ... that constitutes a section" — a genuinely multi-section `.doc` now reads as multiple `ContentSection`s, each with its own real page geometry, rather than the whole document collapsing onto the first section's.
|
|
28
|
+
- **Footnotes, endnotes, and comments, as plain text** — `notes.ts`'s `readNoteBodies` resolves `PlcffndTxt`/`PlcfendTxt`/`PlcfandTxt` (each a CP-only plex dividing its own subdocument into stories, [MS-DOC]'s own "each CP ... specifies the beginning of a story ... the story ends immediately prior to the next CP") into `DocContent.footnotes`/`.endnotes`/`.comments`: one `{id, text}`/`{id, text}` entry per story, `id` a synthetic one-based ordinal, matching the same simplification `ooxml.js`'s own `DocxDocument.footnotes`/`.endnotes`/`.comments` already make for the identical constructs (plain text, no paragraph/run structure). A story's own trailing guard paragraph mark ("not considered part of the story contents", [MS-DOC]'s own words) is excluded from its text; a genuinely empty story reads as `""`.
|
|
29
|
+
- **Headers and footers, as real block flow** — `headers-footers.ts`'s `readHeaderFooterStories` resolves `Plcfhdd` (the identical CP-only-plex shape as the note-text plexes above) into `DocContent.headerFooterStories`: one entry per non-empty story, each carrying which section it belongs to, which of the six fixed slots it is (`evenHeader`/`oddHeader`/`evenFooter`/`oddFooter`/`firstHeader`/`firstFooter`, [MS-DOC]'s own fixed per-section story order), and a real `ContentBlock[]` — paragraphs and tables, read through the identical pipeline the main document uses, rather than plain text. An empty story ([MS-DOC]'s own "the beginning CP has the same value as the next CP") is left out of the array entirely, since it means "reuse the previous section's header/footer of this kind" rather than a genuinely blank one. The six footnote/endnote-separator stories Plcfhdd carries ahead of every section's own six are not read: neither this package's schema nor `ooxml.js`'s `DocxDocument` has anywhere to put a separator story.
|
|
30
|
+
- **Inline pictures** — `pictures.ts`'s `readInlinePicture` resolves a picture character (`U+0001`, `sprmCFSpec` applied) through its own Chpx's `sprmCPicLocation` operand: an offset into the container's `"Data"` stream where a `PICF` ([MS-DOC] 68-byte type/size/border header) is followed, for every producer this reader has seen, by a real `OfficeArtInlineSpContainer` ([MS-ODRAW] 2.2.15) regardless of `PICF.mfpf.mm`'s own value. The container's own `shape` (an `OfficeArtSpContainer`) is skipped whole by its own record header's `recLen`, and the first blip record in `rgfb` immediately after it is decoded when it is `OfficeArtBlipJPEG`/`OfficeArtBlipPNG` — the two raster formats `document-schema.js`'s `ContentImageBlock` can hold losslessly — into a real inline image, sized from `PICMID`'s own `dxaGoal`/`dyaGoal` scaled by `mx`/`my`. A paragraph containing a picture anchor is split around it into a real `ContentBlock[]` (`text/paragraphs.ts`'s `buildParagraphBlocks`), since an inline image is block-level in `document-schema.js`'s own model rather than a run property — mirroring how `ooxml.js`'s own docx reader splits a paragraph around a mid-run page break, paragraph-level formatting carried unchanged onto every split piece. See [Images](#images) for what this does not read.
|
|
28
31
|
|
|
29
32
|
Built and shipped, on the write side — see [Writing](#writing) for the full scope statement:
|
|
30
33
|
|
|
@@ -33,19 +36,19 @@ Built and shipped, on the write side — see [Writing](#writing) for the full sc
|
|
|
33
36
|
|
|
34
37
|
**Not built, and not approximated, on either side.** Each of these is a genuine layer of [MS-DOC] that this package does not implement; none is silently faked, and a document using one reads (or fails to write) as though it did not:
|
|
35
38
|
|
|
36
|
-
| Absent
|
|
37
|
-
|
|
|
38
|
-
| **Nested tables**
|
|
39
|
-
| **
|
|
40
|
-
| **A style's own formatting on write**
|
|
41
|
-
| **Table and numbering style formatting**
|
|
42
|
-
| **Subdocuments**
|
|
43
|
-
| **
|
|
44
|
-
| **Extended and user-defined document properties**
|
|
45
|
-
| **Encryption**
|
|
46
|
-
| **`sprmPHugePapx` / `sprmPTableProps`**
|
|
47
|
-
| **Hyperlinks and fields**
|
|
48
|
-
| **Every FIB field beyond what this package's own reader needs**
|
|
39
|
+
| Absent | Consequence |
|
|
40
|
+
| ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
41
|
+
| **Nested tables, on write** | `readDocContent` recurses into a table nested inside a table cell to whatever depth the file states (see the read-side Tables bullet above and [Tables](#tables)). `writeDocContent` still refuses a `ContentTable` block found inside a table cell's own blocks: it has no depth-aware sgc-1/sgc-5 grpprl encoding for anything past depth 1, and writing one incorrectly would silently corrupt the nested table's own structure rather than fail loudly. |
|
|
42
|
+
| **Floating/anchored drawn objects, text boxes, and every picture format beyond JPEG/PNG** | An inline picture (`U+0001`) resolves to a real image when its own blip is `OfficeArtBlipJPEG`/`OfficeArtBlipPNG` (see the read-side Inline pictures bullet above and [Images](#images)). A floating or anchored drawn object (`U+0008`, `PlcfSpa`) is a genuinely different structure — an arbitrary `OfficeArtSpContainer` shape (which may or may not be a picture at all), reached through a document-level drawing tree (`OfficeArtDgContainer`) rather than a single inline blip — and is not resolved at all; its anchor character is dropped. A text box rides the identical drawing layer (`PlcfTxbxTxt`, itself anchored via a drawn object), so it is likewise not read. A blip format other than JPEG/PNG (a WMF/EMF/PICT metafile, a raw DIB, TIFF) is a structure this package's own image schema (`png`/`jpeg`/`svg`/`gif` only) has nowhere to hold without re-encoding pixels this package has no image codec to perform, so `readInlinePicture` returns undefined for one rather than mis-decoding it, and the anchor drops exactly as an unresolved floating object's does. `writeDocContent` refuses an image block outright, on either side of this line. |
|
|
43
|
+
| **A style's own formatting on write** | A style's own property sets (`STD.grLPUpxSw`) are resolved and folded on read ([ExaDev/documents.js#1005](https://github.com/ExaDev/documents.js/issues/1005)): a paragraph's formatting is its style's own grpprlPapx/grpprlChpx (walked up the full `istdBase` inheritance chain, most-specific style winning) plus its own direct exceptions on top, and a run's own referenced character style (`sprmCIstd`) folds in the same way. `writeDocContent` mints a real STSH entry for every distinct `styleId`/`headingLevel` a document's paragraphs use ([ExaDev/documents.js#1059](https://github.com/ExaDev/documents.js/issues/1059)), so style IDENTITY round-trips -- but every minted entry carries an empty `grLPUpxSw` (no formatting of its own), since doc-codec's flat `ContentDocument` has no style-vs-direct-formatting split to draw a real one from: every property this writer emits is already, unconditionally, a direct exception. A style's own inherited formatting therefore never round-trips through a write -- only its name and istd position do. |
|
|
44
|
+
| **Table and numbering style formatting** | `STD.grLPUpxSw` is resolved only for paragraph and character styles (`stk` 1/2, see the row above) -- a table style's `StkTableGRLPUPX` (its own `TAPX` plus `CNFC`-conditional per-region formatting, [MS-DOC] 2.4.6.6's own table-specific steps 6-9) and a numbering style's `StkListGRLPUPX` are neither read nor written. A table applying a named table style, or a paragraph using a numbering style rather than direct list formatting, reports none of the formatting either would supply. |
|
|
45
|
+
| **Subdocuments, on write; text boxes, on either side** | Footnotes, endnotes, comments, and headers/footers are now read (see the three read-side bullets above); none is written — `writeDocContent` still only ever produces a main document with `ccpFtn`/`ccpHdd`/`ccpAtn`/`ccpEdn` all zero, and a `ContentDocument` carries nowhere on its own `ContentSection.blocks` to state a header/footer's own content distinctly from the body's, which a real inverse would need. Text boxes are not read or written in either direction: `PlcfTxbxTxt` divides its own subdocument into stories the identical way the note-text plexes above do, but a text box's own anchor rides the drawn-object mechanism ([Images](#images)'s own scope note), which this package does not resolve. |
|
|
46
|
+
| **Multiple sections, on write** | `readDocContent` resolves every section `PlcfSed` states, each with its own page size and margins (see the read-side bullet above). `writeDocContent` still refuses a `ContentDocument` with more than one section, rather than silently merging their content into what would read back as one — writing a real multi-section `PlcfSed`/`Sepx` array is unimplemented on the write side. |
|
|
47
|
+
| **Extended and user-defined document properties** | `title`/`subject`/`author`/`keywords`/`createdIso`/`modifiedIso` are read from and written to a `"\x05SummaryInformation"` stream when present (see [Metadata](#metadata)); the sibling `"\x05DocumentSummaryInformation"` stream (company, manager, and custom user-defined properties) is not read or written at all. |
|
|
48
|
+
| **Encryption** | RC4-encrypted documents ([MS-DOC] 2.2.6.2, ExaDev/documents.js#1113) are decrypted given a password -- `readDocContent`/`readDocStreams` take an optional `password`, verified against the Table stream's own EncryptionHeader before anything is trusted (see [Encryption](#encryption) below). XOR obfuscation and RC4 CryptoAPI (a different, newer EncryptionHeader shape) still refuse with a `DocUnsupportedError` rather than being read as plaintext or misread as the wrong scheme. `writeDocContent` never encrypts. |
|
|
49
|
+
| **`sprmPHugePapx` / `sprmPTableProps`** | Paragraph properties stored indirectly in the Data stream are not followed, so such a paragraph reads with fewer properties than it states. [MS-DOC] 2.4.3's own Overview of Tables text names `sprmPTableProps` as a real, legal alternative to `sprmTDefTable` some applications process — but a real producer's row mark is not shown to prefer it: a genuine LibreOffice-authored `.doc` table's own row mark states its TAP through the identical direct `sprmTDefTable` this package's reader and writer already use (confirmed by parsing a LibreOffice 26.2.5.2-authored table's raw `PapxFkp` bytes; see [ExaDev/documents.js#892](https://github.com/ExaDev/documents.js/issues/892)), matching 2.4.3's own compatibility guidance ("An application SHOULD use sprmTDefTable to define table cells for applications that do not process sprmPTableProps"). `writeDocContent` never writes an indirect Papx. |
|
|
50
|
+
| **Hyperlinks and fields** | `ContentRun.hyperlink`, footnote/comment/annotation references, and every other field or anchor character are read as plain text or dropped (see [What is converted](#what-is-converted)) and are not written. |
|
|
51
|
+
| **Every FIB field beyond what this package's own reader needs** | `writeDocContent` populates only the fc/lcb pairs its own reader consults (the style sheet, the two property bin tables, the Clx, the font table). Roughly 140 other `FibRgFcLcb97` pairs — `SttbfAssoc`, `Dop`, the printer-driver structures among them — are left zero, which is the format's own "undefined, MUST be ignored" contract for most of them, but not a certification that every third-party [MS-DOC] reader accepts the result; see `fib/write.ts`'s own note. |
|
|
49
52
|
|
|
50
53
|
One construct is refused rather than mis-read: a `sprmPChgTabs` whose `cb` is the `255` sentinel encodes its own length as a formula over tab-stop counts this package does not parse, and its length is needed to find the next `Prl`. Rather than guess and silently mis-read every property after it, `operandSize` throws.
|
|
51
54
|
|
|
@@ -86,7 +89,7 @@ Fields are handled structurally: everything between a field-begin (`U+0013`) and
|
|
|
86
89
|
|
|
87
90
|
## Tables
|
|
88
91
|
|
|
89
|
-
A table in [MS-DOC] is not a separate container: it is a run of ordinary paragraphs marked `sprmPFInTable`, with cell boundaries at literal `0x07` cell-mark characters in the text stream and each row closed by its own row-ending mark — a cell mark additionally carrying `sprmPFTtp` — per [MS-DOC] 2.4.3's own Overview of Tables. `src/table/` implements exactly this model
|
|
92
|
+
A table in [MS-DOC] is not a separate container: it is a run of ordinary paragraphs marked `sprmPFInTable`, with cell boundaries at literal `0x07` cell-mark characters in the text stream and each row closed by its own row-ending mark — a cell mark additionally carrying `sprmPFTtp` — per [MS-DOC] 2.4.3's own Overview of Tables. `src/table/` implements exactly this model on the read side at every depth a document states: a table nested inside a table cell (table depth greater than 1) uses a genuinely different pair of marks — a paragraph mark (`0x000D`) carrying `sprmPFInnerTableCell` for a cell boundary, `sprmPFInnerTtp` for a row's own terminating mark, in place of the cell-mark character depth 1 uses — and `table/read.ts`'s `walkBlocksAtDepth`/`tryAssembleTable` are mutually recursive over that depth, so a cell's own content resolves to a nested `ContentTable` wherever the file states one, to whatever depth it actually nests. The write side stays depth-1 only: `writeDocContent` still refuses a `ContentTable` block found inside a table cell's own blocks (see the "Nested tables, on write" row in the scope table above).
|
|
90
93
|
|
|
91
94
|
**Reading** (`table/read.ts`'s `assembleBlocks`, called from `read.ts`). It walks the flat paragraph sequence `read.ts` already produces, grouping every contiguous run of `inTable` paragraphs into a `ContentTable`: consecutive paragraphs up to and including the one terminated by an ordinary cell mark become one cell's own `blocks` (a cell may hold more than one paragraph — only its last ends in a cell mark, per 2.4.3's own "the last paragraph in a table cell is terminated by a cell mark"), and the row's own trailing mark resolves the row's whole TAP through `table/tap.ts`'s `applyTableSprms`: column boundaries and every physical cell's own merge state, read directly from `sprmTDefTable`'s `TDefTableOperand` — its `rgdxaCenter` array and its `rgTc80` array of per-column `TC80` records ([MS-DOC] 2.9.313, whose own `tcgrf` field is 2.9.317) — folded with a `sprmTMerge` range or `sprmTVertMerge` per-cell flag on top where a real producer states a merge incrementally instead, genuinely regardless of which order the two appear in within the grpprl (`table/tap.ts`'s own note). Column layout is never assumed shared across a table's own rows: [MS-DOC] 2.6.3 permits each row to declare its own independent `rgdxaCenter` ("There is no requirement that each row of a table have the same number of cells"), and a real, independent [MS-DOC] implementation (LibreOffice 26.2.5.2) was confirmed to rely on exactly this for a horizontal merge — its own merged row simply has fewer, wider physical cells, with no `TCGRF.horzMerge`/`sprmTMerge` signal at all (see the third-party verification paragraph below). `table/read.ts` reconstructs the table's shared column grid as the union of every row's own `rgdxaCenter` boundary values, then expresses each physical cell's own `colSpan` as however many of that shared grid's segments its own boundaries cover. That union is taken within one point rather than by exact integer equality, because [MS-DOC] states those boundaries per row and defines no quantum coarser than the twip itself for them, so two rows meaning the identical grid may legally disagree by a twip or two — and an exact union turns that drift into a phantom hairline column plus a spurious `colSpan` on the cells of every row either side of it (two rows one twip apart across a 2338-twip boundary read back as `columnWidthsPt` `[116.9, 0.05, 144.95, 220]` instead of `[116.9, 145, 220]`; [ExaDev/documents.js#898](https://github.com/ExaDev/documents.js/issues/898)). The default tolerance is `TWIPS_PER_POINT` itself, not a picked number: `columnWidthsPt` states the reconstructed grid in points, so a segment narrower than one point sits below the smallest unit that grid can distinguish at all. It is also the fuzz a real, independent implementation applies to an analogous reconstruct-one-shared-grid-from-N-per-row-arrays problem — LibreOffice's table model is per-row too (`SwTableLine` → `SwTableBox`, each box carrying its own width), and `sw/source/filter/inc/wrtswtbl.hxx` answers it, on its own ODF export (the point at which it projects that per-row model onto one shared grid, `sw/source/filter/xml/xmltble.cxx`'s `SwXMLTableColumn_Impl`), with `#define COLFUZZY 20` twips, `SwWriteTableCol::operator==` treating two column positions as equal when they differ by at most that. Its changeover was confirmed empirically and exactly, not assumed: patching a single `int16` inside a real LibreOffice-authored table's second row and round-tripping it through that implementation's own `.doc` import followed by its ODF export gives three columns and no covered cell for a drift of 1 through 20 twips, and four columns with a real `table:covered-table-cell` from 21 (the `.doc` import side alone preserves the drifted boundary byte-for-byte — the fuzz is applied on export, not import). Per-row drift is not hypothetical even without Word or LibreOffice's own export step in the picture: `WW8TabDesc::CalcDefaults` widens any imported cell narrower than that same implementation's own minimum cell width (`MINLAY`, 23 twips in `sw/inc/swtypes.hxx`) by mutating boundaries per row during `.doc` import itself, so a document that has been through that import is one real mechanism by which per-row drift reaches a `.doc` at all.
|
|
92
95
|
|
|
@@ -158,6 +161,34 @@ A paragraph's own `list.numId`/`list.level` (`sprmPIlfo`/`sprmPIlvl`, unchanged
|
|
|
158
161
|
|
|
159
162
|
**The write side is verified by this package's own round trip, not yet against a third-party implementation.** `write.test.ts`'s own `describe("writeDocContent numbering")` block covers a multi-level list (`format`/`text` per level surviving through `readDocContent`), a bulleted list (its glyph, not a numbered placeholder), separate `ilfo` minting for separate `numId`s, a document with no lists at all (no `PlfLst`/`PlfLfo` written), and a list membership inside a table cell -- every case reading back through this package's own reader exactly as written. `list/numbering-write.test.ts` covers `buildNumberingTables` one layer down, independently of `gatherListUsage`: the `LSTF`/`LFO` byte shape a hand-built `NumberingDefinitions` produces, the empty-definitions-map case returning `undefined`, the numerically-colliding-key rejection described above, and that `gatherListUsage`'s own output can never trigger that rejection. Unlike the read side's LibreOffice cross-check above, no independent [MS-DOC] implementation has yet opened a `writeDocContent` numbering sample: that verification is the next thing worth doing here, mirroring how [Tables](#tables) and [Cell decoration](#cell-decoration) were each verified once a real producer's own file was available to compare against.
|
|
160
163
|
|
|
164
|
+
## Sections
|
|
165
|
+
|
|
166
|
+
[MS-DOC] 2.8.26's `PlcfSed` divides the main document's own text into sections the identical way `Plcfhdd`/`PlcffndTxt`/`PlcfandTxt`/`PlcfendTxt` (below) divide their own subdocuments into stories: an array of CPs, each naming where the next section's text begins, "the range of text ends immediately prior to the next CP." `prop/sep.ts`'s `readAllSectionProperties` resolves every `Sed` this way, in document order, each into its own page width/height and four margins via `applySectionSprms` (`sprmSXaPage`/`sprmSYaPage`/`sprmSDxaLeft`/`sprmSDxaRight`/`sprmSDyaTop`/`sprmSDyaBottom`); `read.ts`'s `splitIntoSections` then walks the main document's own flat paragraph sequence once, advancing to the next section exactly when a paragraph's own end CP matches the next section's start CP — the paragraph carrying the end-of-section character (`0x000C`) itself, per [MS-DOC]'s own "there MUST also be an end-of-section character... as the final character in the text range of all but the last section." A file with no `PlcfSed` at all (`lcbPlcfSed` 0) reads as a single section falling back, field by field, to Word's own new-document default (US Letter, one-inch margins) — the identical fallback a `PlcfSed` that leaves one sprm unstated already used before multi-section support existed.
|
|
167
|
+
|
|
168
|
+
Only page size and the four margins are resolved, matching what `document-schema.js`'s own `ContentSection` (`pageSize` + `margins`) has anywhere to hold; every other section sprm (columns, headers/footers distance, vertical justification, page borders, line numbering, and the rest of the roughly seventy [MS-DOC] 2.6.4 names) is absent rather than present-and-ignored, the identical documented-gap convention the paragraph- and character-property tables already use. `writeDocContent` still only ever writes one section (see [Writing](#writing)); a real multi-section write is unimplemented.
|
|
169
|
+
|
|
170
|
+
## Subdocuments
|
|
171
|
+
|
|
172
|
+
The main document is only the first of several logical text ranges [MS-DOC] 2.4.1 concatenates into one CP space, in this fixed order: the main document (`0` to `ccpText`), the footnote document (`ccpFtn` characters), the header document (`ccpHdd`), the comment/annotation document (`ccpAtn`), the endnote document (`ccpEdn`), and the textbox documents (`ccpTxbx`/`ccpHdrTxbx`, not read at all — see below). `subdocument.ts`'s `readSubdocumentStories` is the one function every subdocument this package reads goes through: it reads a subdocument's own CP range via the identical `readTextRange`/`readParagraphs` pipeline the main document uses, then splits the resulting flat paragraph sequence by a boundary plex's own CPs (`text/paragraphs.ts`'s `splitEntriesByBoundaries`) into one group per story. `PlcffndTxt`/`PlcfandTxt`/`PlcfendTxt`/`Plcfhdd` all share the identical shape and the identical two conventions this one function handles once: "the story is considered empty" when two consecutive CPs are equal (skipped past, never assigned any entry — a run of several empty stories in a row is handled correctly, not just a single one), and a trailing CP the structure's own page states is "undefined and MUST be ignored" (the last group `readSubdocumentStories` produces is always dropped). A non-empty story's own final paragraph — a bare paragraph mark with no content of its own, the guard "not considered part of the story contents" — is likewise dropped from what a caller actually sees.
|
|
173
|
+
|
|
174
|
+
**Footnotes, endnotes, and comments** (`notes.ts`) resolve to `DocContent.footnotes`/`.endnotes`/`.comments`: one `{id, text}` entry per story, `id` a synthetic one-based ordinal in document order (this reader does not resolve `PlcffndRef`/`PlcfandRef`/`PlcfendRef`'s own reference data — the auto-numbering/custom-symbol state a real footnote mark carries — only the order its own text plex already states), `text` the story's own paragraphs joined by `\n`. This is a deliberate simplification matching `ooxml.js`'s own `DocxDocument.footnotes`/`.endnotes`/`.comments`, which carry the identical flat-text shape for the identical constructs rather than real block flow.
|
|
175
|
+
|
|
176
|
+
**Headers and footers** (`headers-footers.ts`) resolve to `DocContent.headerFooterStories`, real block flow instead: `Plcfhdd`'s own fixed layout is six footnote/endnote-separator stories (not read — neither this package's schema nor `ooxml.js`'s `DocxDocument` has anywhere to put one), then six per section in a fixed order (`evenHeader`, `oddHeader`, `evenFooter`, `oddFooter`, `firstHeader`, `firstFooter`), so each resolved story carries its own `section` index, `slot`, and a genuine `ContentBlock[]` read through the same `assembleBlocks` pipeline the main document uses — paragraphs and tables both. An empty story means "the header/footer of this kind from the previous section is reused" ([MS-DOC]'s own words) rather than a deliberately blank one, so it is left out of the array entirely instead of appearing as a hollow `{blocks: []}` entry.
|
|
177
|
+
|
|
178
|
+
**Not read at all: text boxes.** `PlcfTxbxTxt`/`PlcfHdrtxbxTxt` divide their own subdocument into stories the identical way, but a text box's own anchor is a drawn object (`U+0008`, `PlcfSpa`) — the same drawing-layer mechanism [Images](#images) below does not resolve — so there is no way to reach a text box's own story from the main document's text at all without that layer, and this package does not attempt it.
|
|
179
|
+
|
|
180
|
+
Nothing on this subdocument side is written: `writeDocContent` produces a main document only, with `ccpFtn`/`ccpHdd`/`ccpAtn`/`ccpEdn` all zero (`fib/write.ts`'s own note).
|
|
181
|
+
|
|
182
|
+
## Images
|
|
183
|
+
|
|
184
|
+
An inline picture is a character with Unicode value `U+0001` ("A picture location that is used in conjunction with sprmCPicLocation") carrying `sprmCFSpec` and `sprmCPicLocation` — a signed 32-bit offset into the container's own `"Data"` stream, a stream with "no predefined structure... referenced from the FIB or from other parts of the file," genuinely optional like `"\x05SummaryInformation"`. `pictures.ts`'s `readInlinePicture` reads what sits at that offset: a 68-byte `PICF` (type/size/border information — `cbHeader`, `mfpf.mm`, `PICF_Shape`, `PICMID`'s own `dxaGoal`/`dyaGoal`/`mx`/`my` and four `Brc80` borders this package does not read), an optional `cchPicName`/`stPicName` pair when `mfpf.mm` is `MM_SHAPEFILE`, then `picture`: a real `OfficeArtInlineSpContainer` ([MS-ODRAW] 2.2.15) — every producer this reader has seen writes this container regardless of `mfpf.mm`'s own value, so there is no simpler, non-OfficeArt path even for the plainest bitmap. The container's own `shape` (an `OfficeArtSpContainer`, [MS-ODRAW] 2.2.14) is skipped whole by its own 8-byte record header's `recLen` — this reader has no need for a shape's own fill/line/position properties — and the first entry of `rgfb` immediately after it, an `OfficeArtBlip` record, is read directly: its own `recInstance` states how many 16-byte MD4 `rgbUid` fields precede the one-byte internal-resource `tag` and the raw file bytes (one for `OfficeArtBlipJPEG`'s RGB/CMYK-1-UID instances and `OfficeArtBlipPNG`'s 1-UID instance, two for each format's own 2-UID sibling), so `blipDataStart`/`blipDataLength` fall out directly from the header once the format is known. `widthPt`/`heightPt` come from `PICMID`'s own `dxaGoal`/`dyaGoal` (the picture's initial size in twips) scaled by `mx`/`my` (each "the ratio, measured in tenths of a percent, between the final display width/height and the initial picture width/height") and converted to points.
|
|
185
|
+
|
|
186
|
+
**Only `OfficeArtBlipJPEG` (`0xF01D`) and `OfficeArtBlipPNG` (`0xF01E`) are decoded** — the two raster formats `document-schema.js`'s `ContentImageBlockSchema` can hold losslessly (`format: "png" | "jpeg" | "svg" | "gif"`). Every other blip kind `readInlinePicture` returns `undefined` for rather than mis-decoding: a metafile (`OfficeArtBlipEMF`/`WMF`/`PICT`) carries a further `OfficeArtMetafileHeader` and, for EMF/WMF, DEFLATE-compressed payload bytes this package has no decompressor for; a raw DIB (`OfficeArtBlipDIB`) has no `ContentImageBlock` format token to hold it under at all without an image codec to re-encode its pixels as PNG, which this package does not have; `OfficeArtBlipTIFF` is likewise a format this schema names no token for. A paragraph whose only content is such an anchor still reads as a genuine, empty `ContentParagraph` — the identical degrade an unresolved anchor already produced before this feature existed — rather than losing the paragraph entirely.
|
|
187
|
+
|
|
188
|
+
**A paragraph is split around a resolved (or attempted) picture, never left as a run.** An inline image is block-level in `document-schema.js`'s own model, so `text/paragraphs.ts`'s `buildParagraphBlocks` splits the paragraph's own text at each `U+0001` anchor into however many `ContentBlock`s the anchors demand — a leading paragraph, the image, a trailing paragraph, and so on for a paragraph carrying more than one — every split paragraph piece keeping the whole paragraph's own alignment/spacing/list attributes unchanged, mirroring how `ooxml.js`'s own docx reader already splits a paragraph around a mid-run page break. A paragraph containing nothing but one unresolved picture anchor (an unsupported blip format, or no `"Data"` stream at all) collapses to the identical single empty `ContentParagraph` a plain anchor-only paragraph always produced; a paragraph that resolves to at least one real block (text, an image) never gains a synthetic empty wrapper alongside it.
|
|
189
|
+
|
|
190
|
+
**Not read: floating/anchored drawn objects and text boxes.** A floating picture is a different anchor entirely — `U+0008` ("A drawn object. See plcfSpa"), referenced by a `PlcfSpa` (`SPA` records, 26 bytes each, one `spid` per anchor) that names a shape inside a document-level `OfficeArtDgContainer` drawing tree rather than a single inline blip a `Chpx` sprm points at directly. That shape need not even be a picture — an arbitrary `OfficeArtSpContainer` (autoshape, connector, text box) — so resolving one properly means walking the whole drawing tree, not decoding one more blip kind; this package does not attempt it, and the anchor character drops exactly as any other unresolved anchor does. `writeDocContent` refuses an image block outright, on either side of this line.
|
|
191
|
+
|
|
161
192
|
## Metadata
|
|
162
193
|
|
|
163
194
|
A `.doc`'s title, author, and dates do not live in any [MS-DOC] structure at all — they live in a `"\x05SummaryInformation"` stream, a genuinely different format ([MS-OLEPS] Property Set Streams) that happens to sit beside `WordDocument`/`1Table` in the same [MS-CFB] compound file. `readDocContent` reads that stream when present (`archive-codec`'s `readSummaryInformation`, since the property-set format itself is zero document-format knowledge, exactly as the [MS-CFB] container it sits inside is) and maps it onto `document-schema.js`'s `LayoutMetadata` (`archive-codec`'s own `summaryInformationToLayoutMetadata` — the mapping is format-agnostic, so it lives there rather than being copied in this package, alongside `xls-codec`'s and `ppt-codec`'s identical need for it); `writeDocContent` does the inverse (`src/metadata.ts`'s `layoutMetadataToSummaryInformation`, which validates `createdIso`/`modifiedIso` as real dates and throws a `DocFormatError` naming the offending field before delegating to `archive-codec`'s own mapping — see [Writing](#writing)), including a `"\x05SummaryInformation"` stream in its `writeCompoundFile` call only when the input's metadata actually carries something that stream can hold — an input whose metadata is `{}`, or carries only fields the mapping below has no destination for, produces no stream at all, matching what an absent-metadata read already returns.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { t as Prl } from "./sprm-DEyvdOo0.js";
|
|
2
|
+
import { Color } from "document-schema.js";
|
|
3
|
+
//#region src/prop/chp.d.ts
|
|
4
|
+
interface CharacterProperties {
|
|
5
|
+
bold?: boolean;
|
|
6
|
+
italic?: boolean;
|
|
7
|
+
underline?: boolean;
|
|
8
|
+
strike?: boolean;
|
|
9
|
+
sizePt?: number;
|
|
10
|
+
color?: Color;
|
|
11
|
+
fontFamily?: string;
|
|
12
|
+
/** The istd of a character style applied by sprmCIstd, carried so a caller can resolve the style's own name. */
|
|
13
|
+
istd?: number;
|
|
14
|
+
}
|
|
15
|
+
declare function applyCharacterSprms(prls: readonly Prl[], into: CharacterProperties, fonts?: readonly string[]): CharacterProperties;
|
|
16
|
+
declare function characterIstdFromGrpprl(prls: readonly Prl[]): number | undefined;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { applyCharacterSprms as n, characterIstdFromGrpprl as r, CharacterProperties as t };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { t as Prl } from "./sprm-DEyvdOo0.cjs";
|
|
2
|
+
import { Color } from "document-schema.js";
|
|
3
|
+
//#region src/prop/chp.d.ts
|
|
4
|
+
interface CharacterProperties {
|
|
5
|
+
bold?: boolean;
|
|
6
|
+
italic?: boolean;
|
|
7
|
+
underline?: boolean;
|
|
8
|
+
strike?: boolean;
|
|
9
|
+
sizePt?: number;
|
|
10
|
+
color?: Color;
|
|
11
|
+
fontFamily?: string;
|
|
12
|
+
/** The istd of a character style applied by sprmCIstd, carried so a caller can resolve the style's own name. */
|
|
13
|
+
istd?: number;
|
|
14
|
+
}
|
|
15
|
+
declare function applyCharacterSprms(prls: readonly Prl[], into: CharacterProperties, fonts?: readonly string[]): CharacterProperties;
|
|
16
|
+
declare function characterIstdFromGrpprl(prls: readonly Prl[]): number | undefined;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { applyCharacterSprms as n, characterIstdFromGrpprl as r, CharacterProperties as t };
|
package/dist/detect.cjs
CHANGED
|
@@ -7,6 +7,8 @@ let archive_codec = require("archive-codec");
|
|
|
7
7
|
const WORD_DOCUMENT_STREAM = "WordDocument";
|
|
8
8
|
/** The [MS-OLEPS] Property Set Stream a .doc's title/author/dates live in when present -- a genuinely optional stream, unlike WordDocument, since a valid Word Binary File need not carry document properties at all. */
|
|
9
9
|
const SUMMARY_INFORMATION_STREAM = "SummaryInformation";
|
|
10
|
+
/** The stream sprmCPicLocation's operand addresses, [MS-DOC] "Data Stream": "has no predefined structure. It contains data that is referenced from the FIB or from other parts of the file. This stream need not be present if there are no references to it." -- genuinely optional, like SUMMARY_INFORMATION_STREAM, since a document with no pictures need not carry one. */
|
|
11
|
+
const DATA_STREAM = "Data";
|
|
10
12
|
function isDocBytes(bytes) {
|
|
11
13
|
if (!(0, archive_codec.isCompoundFile)(bytes)) return false;
|
|
12
14
|
let streams;
|
|
@@ -20,6 +22,7 @@ function isDocBytes(bytes) {
|
|
|
20
22
|
return require_bytes.readUint16LE(wordDocument.bytes, 0) === require_fib_offsets.FIB_W_IDENT;
|
|
21
23
|
}
|
|
22
24
|
//#endregion
|
|
25
|
+
exports.DATA_STREAM = DATA_STREAM;
|
|
23
26
|
exports.SUMMARY_INFORMATION_STREAM = SUMMARY_INFORMATION_STREAM;
|
|
24
27
|
exports.WORD_DOCUMENT_STREAM = WORD_DOCUMENT_STREAM;
|
|
25
28
|
exports.isDocBytes = isDocBytes;
|
package/dist/detect.d.cts
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
declare const WORD_DOCUMENT_STREAM = "WordDocument";
|
|
4
4
|
/** The [MS-OLEPS] Property Set Stream a .doc's title/author/dates live in when present -- a genuinely optional stream, unlike WordDocument, since a valid Word Binary File need not carry document properties at all. */
|
|
5
5
|
declare const SUMMARY_INFORMATION_STREAM = "SummaryInformation";
|
|
6
|
+
/** The stream sprmCPicLocation's operand addresses, [MS-DOC] "Data Stream": "has no predefined structure. It contains data that is referenced from the FIB or from other parts of the file. This stream need not be present if there are no references to it." -- genuinely optional, like SUMMARY_INFORMATION_STREAM, since a document with no pictures need not carry one. */
|
|
7
|
+
declare const DATA_STREAM = "Data";
|
|
6
8
|
declare function isDocBytes(bytes: Uint8Array<ArrayBuffer>): boolean;
|
|
7
9
|
//#endregion
|
|
8
|
-
export { SUMMARY_INFORMATION_STREAM, WORD_DOCUMENT_STREAM, isDocBytes };
|
|
10
|
+
export { DATA_STREAM, SUMMARY_INFORMATION_STREAM, WORD_DOCUMENT_STREAM, isDocBytes };
|
package/dist/detect.d.ts
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
declare const WORD_DOCUMENT_STREAM = "WordDocument";
|
|
4
4
|
/** The [MS-OLEPS] Property Set Stream a .doc's title/author/dates live in when present -- a genuinely optional stream, unlike WordDocument, since a valid Word Binary File need not carry document properties at all. */
|
|
5
5
|
declare const SUMMARY_INFORMATION_STREAM = "SummaryInformation";
|
|
6
|
+
/** The stream sprmCPicLocation's operand addresses, [MS-DOC] "Data Stream": "has no predefined structure. It contains data that is referenced from the FIB or from other parts of the file. This stream need not be present if there are no references to it." -- genuinely optional, like SUMMARY_INFORMATION_STREAM, since a document with no pictures need not carry one. */
|
|
7
|
+
declare const DATA_STREAM = "Data";
|
|
6
8
|
declare function isDocBytes(bytes: Uint8Array<ArrayBuffer>): boolean;
|
|
7
9
|
//#endregion
|
|
8
|
-
export { SUMMARY_INFORMATION_STREAM, WORD_DOCUMENT_STREAM, isDocBytes };
|
|
10
|
+
export { DATA_STREAM, SUMMARY_INFORMATION_STREAM, WORD_DOCUMENT_STREAM, isDocBytes };
|
package/dist/detect.js
CHANGED
|
@@ -6,6 +6,8 @@ import { isCompoundFile, readCompoundFile } from "archive-codec";
|
|
|
6
6
|
const WORD_DOCUMENT_STREAM = "WordDocument";
|
|
7
7
|
/** The [MS-OLEPS] Property Set Stream a .doc's title/author/dates live in when present -- a genuinely optional stream, unlike WordDocument, since a valid Word Binary File need not carry document properties at all. */
|
|
8
8
|
const SUMMARY_INFORMATION_STREAM = "SummaryInformation";
|
|
9
|
+
/** The stream sprmCPicLocation's operand addresses, [MS-DOC] "Data Stream": "has no predefined structure. It contains data that is referenced from the FIB or from other parts of the file. This stream need not be present if there are no references to it." -- genuinely optional, like SUMMARY_INFORMATION_STREAM, since a document with no pictures need not carry one. */
|
|
10
|
+
const DATA_STREAM = "Data";
|
|
9
11
|
function isDocBytes(bytes) {
|
|
10
12
|
if (!isCompoundFile(bytes)) return false;
|
|
11
13
|
let streams;
|
|
@@ -19,4 +21,4 @@ function isDocBytes(bytes) {
|
|
|
19
21
|
return readUint16LE(wordDocument.bytes, 0) === FIB_W_IDENT;
|
|
20
22
|
}
|
|
21
23
|
//#endregion
|
|
22
|
-
export { SUMMARY_INFORMATION_STREAM, WORD_DOCUMENT_STREAM, isDocBytes };
|
|
24
|
+
export { DATA_STREAM, SUMMARY_INFORMATION_STREAM, WORD_DOCUMENT_STREAM, isDocBytes };
|
package/dist/fib/fib.cjs
CHANGED
|
@@ -49,6 +49,20 @@ function parseFib(wordDocument) {
|
|
|
49
49
|
lcbClx: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbClx),
|
|
50
50
|
fcPlcfSed: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcPlcfSed),
|
|
51
51
|
lcbPlcfSed: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbPlcfSed),
|
|
52
|
+
fcPlcffndRef: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcPlcffndRef),
|
|
53
|
+
lcbPlcffndRef: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbPlcffndRef),
|
|
54
|
+
fcPlcffndTxt: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcPlcffndTxt),
|
|
55
|
+
lcbPlcffndTxt: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbPlcffndTxt),
|
|
56
|
+
fcPlcfandRef: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcPlcfandRef),
|
|
57
|
+
lcbPlcfandRef: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbPlcfandRef),
|
|
58
|
+
fcPlcfandTxt: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcPlcfandTxt),
|
|
59
|
+
lcbPlcfandTxt: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbPlcfandTxt),
|
|
60
|
+
fcPlcfendRef: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcPlcfendRef),
|
|
61
|
+
lcbPlcfendRef: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbPlcfendRef),
|
|
62
|
+
fcPlcfendTxt: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcPlcfendTxt),
|
|
63
|
+
lcbPlcfendTxt: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbPlcfendTxt),
|
|
64
|
+
fcPlcfHdd: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcPlcfHdd),
|
|
65
|
+
lcbPlcfHdd: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbPlcfHdd),
|
|
52
66
|
fcSttbfFfn: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcSttbfFfn),
|
|
53
67
|
lcbSttbfFfn: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbSttbfFfn),
|
|
54
68
|
fcPlfLst: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcPlfLst),
|
package/dist/fib/fib.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as tableStreamName, n as parseFib, r as peekFibBaseFlags, t as Fib } from "../fib-
|
|
1
|
+
import { i as tableStreamName, n as parseFib, r as peekFibBaseFlags, t as Fib } from "../fib-6BFIx153.cjs";
|
|
2
2
|
export { Fib, parseFib, peekFibBaseFlags, tableStreamName };
|
package/dist/fib/fib.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as tableStreamName, n as parseFib, r as peekFibBaseFlags, t as Fib } from "../fib-
|
|
1
|
+
import { i as tableStreamName, n as parseFib, r as peekFibBaseFlags, t as Fib } from "../fib-6BFIx153.js";
|
|
2
2
|
export { Fib, parseFib, peekFibBaseFlags, tableStreamName };
|
package/dist/fib/fib.js
CHANGED
|
@@ -48,6 +48,20 @@ function parseFib(wordDocument) {
|
|
|
48
48
|
lcbClx: fcLcb(FC_LCB_VALUE_INDEX.lcbClx),
|
|
49
49
|
fcPlcfSed: fcLcb(FC_LCB_VALUE_INDEX.fcPlcfSed),
|
|
50
50
|
lcbPlcfSed: fcLcb(FC_LCB_VALUE_INDEX.lcbPlcfSed),
|
|
51
|
+
fcPlcffndRef: fcLcb(FC_LCB_VALUE_INDEX.fcPlcffndRef),
|
|
52
|
+
lcbPlcffndRef: fcLcb(FC_LCB_VALUE_INDEX.lcbPlcffndRef),
|
|
53
|
+
fcPlcffndTxt: fcLcb(FC_LCB_VALUE_INDEX.fcPlcffndTxt),
|
|
54
|
+
lcbPlcffndTxt: fcLcb(FC_LCB_VALUE_INDEX.lcbPlcffndTxt),
|
|
55
|
+
fcPlcfandRef: fcLcb(FC_LCB_VALUE_INDEX.fcPlcfandRef),
|
|
56
|
+
lcbPlcfandRef: fcLcb(FC_LCB_VALUE_INDEX.lcbPlcfandRef),
|
|
57
|
+
fcPlcfandTxt: fcLcb(FC_LCB_VALUE_INDEX.fcPlcfandTxt),
|
|
58
|
+
lcbPlcfandTxt: fcLcb(FC_LCB_VALUE_INDEX.lcbPlcfandTxt),
|
|
59
|
+
fcPlcfendRef: fcLcb(FC_LCB_VALUE_INDEX.fcPlcfendRef),
|
|
60
|
+
lcbPlcfendRef: fcLcb(FC_LCB_VALUE_INDEX.lcbPlcfendRef),
|
|
61
|
+
fcPlcfendTxt: fcLcb(FC_LCB_VALUE_INDEX.fcPlcfendTxt),
|
|
62
|
+
lcbPlcfendTxt: fcLcb(FC_LCB_VALUE_INDEX.lcbPlcfendTxt),
|
|
63
|
+
fcPlcfHdd: fcLcb(FC_LCB_VALUE_INDEX.fcPlcfHdd),
|
|
64
|
+
lcbPlcfHdd: fcLcb(FC_LCB_VALUE_INDEX.lcbPlcfHdd),
|
|
51
65
|
fcSttbfFfn: fcLcb(FC_LCB_VALUE_INDEX.fcSttbfFfn),
|
|
52
66
|
lcbSttbfFfn: fcLcb(FC_LCB_VALUE_INDEX.lcbSttbfFfn),
|
|
53
67
|
fcPlfLst: fcLcb(FC_LCB_VALUE_INDEX.fcPlfLst),
|
package/dist/fib/offsets.cjs
CHANGED
|
@@ -32,8 +32,18 @@ const LW_OFFSET = {
|
|
|
32
32
|
const FC_LCB_VALUE_INDEX = {
|
|
33
33
|
fcStshf: 2,
|
|
34
34
|
lcbStshf: 3,
|
|
35
|
+
fcPlcffndRef: 4,
|
|
36
|
+
lcbPlcffndRef: 5,
|
|
37
|
+
fcPlcffndTxt: 6,
|
|
38
|
+
lcbPlcffndTxt: 7,
|
|
39
|
+
fcPlcfandRef: 8,
|
|
40
|
+
lcbPlcfandRef: 9,
|
|
41
|
+
fcPlcfandTxt: 10,
|
|
42
|
+
lcbPlcfandTxt: 11,
|
|
35
43
|
fcPlcfSed: 12,
|
|
36
44
|
lcbPlcfSed: 13,
|
|
45
|
+
fcPlcfHdd: 22,
|
|
46
|
+
lcbPlcfHdd: 23,
|
|
37
47
|
fcPlcfBteChpx: 24,
|
|
38
48
|
lcbPlcfBteChpx: 25,
|
|
39
49
|
fcPlcfBtePapx: 26,
|
|
@@ -42,6 +52,10 @@ const FC_LCB_VALUE_INDEX = {
|
|
|
42
52
|
lcbSttbfFfn: 31,
|
|
43
53
|
fcClx: 66,
|
|
44
54
|
lcbClx: 67,
|
|
55
|
+
fcPlcfendRef: 92,
|
|
56
|
+
lcbPlcfendRef: 93,
|
|
57
|
+
fcPlcfendTxt: 94,
|
|
58
|
+
lcbPlcfendTxt: 95,
|
|
45
59
|
fcPlfLst: 146,
|
|
46
60
|
lcbPlfLst: 147,
|
|
47
61
|
fcPlfLfo: 148,
|
package/dist/fib/offsets.d.cts
CHANGED
|
@@ -31,8 +31,18 @@ declare const LW_OFFSET: {
|
|
|
31
31
|
declare const FC_LCB_VALUE_INDEX: {
|
|
32
32
|
readonly fcStshf: 2;
|
|
33
33
|
readonly lcbStshf: 3;
|
|
34
|
+
readonly fcPlcffndRef: 4;
|
|
35
|
+
readonly lcbPlcffndRef: 5;
|
|
36
|
+
readonly fcPlcffndTxt: 6;
|
|
37
|
+
readonly lcbPlcffndTxt: 7;
|
|
38
|
+
readonly fcPlcfandRef: 8;
|
|
39
|
+
readonly lcbPlcfandRef: 9;
|
|
40
|
+
readonly fcPlcfandTxt: 10;
|
|
41
|
+
readonly lcbPlcfandTxt: 11;
|
|
34
42
|
readonly fcPlcfSed: 12;
|
|
35
43
|
readonly lcbPlcfSed: 13;
|
|
44
|
+
readonly fcPlcfHdd: 22;
|
|
45
|
+
readonly lcbPlcfHdd: 23;
|
|
36
46
|
readonly fcPlcfBteChpx: 24;
|
|
37
47
|
readonly lcbPlcfBteChpx: 25;
|
|
38
48
|
readonly fcPlcfBtePapx: 26;
|
|
@@ -41,6 +51,10 @@ declare const FC_LCB_VALUE_INDEX: {
|
|
|
41
51
|
readonly lcbSttbfFfn: 31;
|
|
42
52
|
readonly fcClx: 66;
|
|
43
53
|
readonly lcbClx: 67;
|
|
54
|
+
readonly fcPlcfendRef: 92;
|
|
55
|
+
readonly lcbPlcfendRef: 93;
|
|
56
|
+
readonly fcPlcfendTxt: 94;
|
|
57
|
+
readonly lcbPlcfendTxt: 95;
|
|
44
58
|
readonly fcPlfLst: 146;
|
|
45
59
|
readonly lcbPlfLst: 147;
|
|
46
60
|
readonly fcPlfLfo: 148;
|
package/dist/fib/offsets.d.ts
CHANGED
|
@@ -31,8 +31,18 @@ declare const LW_OFFSET: {
|
|
|
31
31
|
declare const FC_LCB_VALUE_INDEX: {
|
|
32
32
|
readonly fcStshf: 2;
|
|
33
33
|
readonly lcbStshf: 3;
|
|
34
|
+
readonly fcPlcffndRef: 4;
|
|
35
|
+
readonly lcbPlcffndRef: 5;
|
|
36
|
+
readonly fcPlcffndTxt: 6;
|
|
37
|
+
readonly lcbPlcffndTxt: 7;
|
|
38
|
+
readonly fcPlcfandRef: 8;
|
|
39
|
+
readonly lcbPlcfandRef: 9;
|
|
40
|
+
readonly fcPlcfandTxt: 10;
|
|
41
|
+
readonly lcbPlcfandTxt: 11;
|
|
34
42
|
readonly fcPlcfSed: 12;
|
|
35
43
|
readonly lcbPlcfSed: 13;
|
|
44
|
+
readonly fcPlcfHdd: 22;
|
|
45
|
+
readonly lcbPlcfHdd: 23;
|
|
36
46
|
readonly fcPlcfBteChpx: 24;
|
|
37
47
|
readonly lcbPlcfBteChpx: 25;
|
|
38
48
|
readonly fcPlcfBtePapx: 26;
|
|
@@ -41,6 +51,10 @@ declare const FC_LCB_VALUE_INDEX: {
|
|
|
41
51
|
readonly lcbSttbfFfn: 31;
|
|
42
52
|
readonly fcClx: 66;
|
|
43
53
|
readonly lcbClx: 67;
|
|
54
|
+
readonly fcPlcfendRef: 92;
|
|
55
|
+
readonly lcbPlcfendRef: 93;
|
|
56
|
+
readonly fcPlcfendTxt: 94;
|
|
57
|
+
readonly lcbPlcfendTxt: 95;
|
|
44
58
|
readonly fcPlfLst: 146;
|
|
45
59
|
readonly lcbPlfLst: 147;
|
|
46
60
|
readonly fcPlfLfo: 148;
|
package/dist/fib/offsets.js
CHANGED
|
@@ -31,8 +31,18 @@ const LW_OFFSET = {
|
|
|
31
31
|
const FC_LCB_VALUE_INDEX = {
|
|
32
32
|
fcStshf: 2,
|
|
33
33
|
lcbStshf: 3,
|
|
34
|
+
fcPlcffndRef: 4,
|
|
35
|
+
lcbPlcffndRef: 5,
|
|
36
|
+
fcPlcffndTxt: 6,
|
|
37
|
+
lcbPlcffndTxt: 7,
|
|
38
|
+
fcPlcfandRef: 8,
|
|
39
|
+
lcbPlcfandRef: 9,
|
|
40
|
+
fcPlcfandTxt: 10,
|
|
41
|
+
lcbPlcfandTxt: 11,
|
|
34
42
|
fcPlcfSed: 12,
|
|
35
43
|
lcbPlcfSed: 13,
|
|
44
|
+
fcPlcfHdd: 22,
|
|
45
|
+
lcbPlcfHdd: 23,
|
|
36
46
|
fcPlcfBteChpx: 24,
|
|
37
47
|
lcbPlcfBteChpx: 25,
|
|
38
48
|
fcPlcfBtePapx: 26,
|
|
@@ -41,6 +51,10 @@ const FC_LCB_VALUE_INDEX = {
|
|
|
41
51
|
lcbSttbfFfn: 31,
|
|
42
52
|
fcClx: 66,
|
|
43
53
|
lcbClx: 67,
|
|
54
|
+
fcPlcfendRef: 92,
|
|
55
|
+
lcbPlcfendRef: 93,
|
|
56
|
+
fcPlcfendTxt: 94,
|
|
57
|
+
lcbPlcfendTxt: 95,
|
|
44
58
|
fcPlfLst: 146,
|
|
45
59
|
lcbPlfLst: 147,
|
|
46
60
|
fcPlfLfo: 148,
|
|
@@ -23,6 +23,20 @@ interface Fib {
|
|
|
23
23
|
readonly lcbClx: number;
|
|
24
24
|
readonly fcPlcfSed: number;
|
|
25
25
|
readonly lcbPlcfSed: number;
|
|
26
|
+
readonly fcPlcffndRef: number;
|
|
27
|
+
readonly lcbPlcffndRef: number;
|
|
28
|
+
readonly fcPlcffndTxt: number;
|
|
29
|
+
readonly lcbPlcffndTxt: number;
|
|
30
|
+
readonly fcPlcfandRef: number;
|
|
31
|
+
readonly lcbPlcfandRef: number;
|
|
32
|
+
readonly fcPlcfandTxt: number;
|
|
33
|
+
readonly lcbPlcfandTxt: number;
|
|
34
|
+
readonly fcPlcfendRef: number;
|
|
35
|
+
readonly lcbPlcfendRef: number;
|
|
36
|
+
readonly fcPlcfendTxt: number;
|
|
37
|
+
readonly lcbPlcfendTxt: number;
|
|
38
|
+
readonly fcPlcfHdd: number;
|
|
39
|
+
readonly lcbPlcfHdd: number;
|
|
26
40
|
readonly fcSttbfFfn: number;
|
|
27
41
|
readonly lcbSttbfFfn: number;
|
|
28
42
|
readonly fcPlfLst: number;
|
|
@@ -23,6 +23,20 @@ interface Fib {
|
|
|
23
23
|
readonly lcbClx: number;
|
|
24
24
|
readonly fcPlcfSed: number;
|
|
25
25
|
readonly lcbPlcfSed: number;
|
|
26
|
+
readonly fcPlcffndRef: number;
|
|
27
|
+
readonly lcbPlcffndRef: number;
|
|
28
|
+
readonly fcPlcffndTxt: number;
|
|
29
|
+
readonly lcbPlcffndTxt: number;
|
|
30
|
+
readonly fcPlcfandRef: number;
|
|
31
|
+
readonly lcbPlcfandRef: number;
|
|
32
|
+
readonly fcPlcfandTxt: number;
|
|
33
|
+
readonly lcbPlcfandTxt: number;
|
|
34
|
+
readonly fcPlcfendRef: number;
|
|
35
|
+
readonly lcbPlcfendRef: number;
|
|
36
|
+
readonly fcPlcfendTxt: number;
|
|
37
|
+
readonly lcbPlcfendTxt: number;
|
|
38
|
+
readonly fcPlcfHdd: number;
|
|
39
|
+
readonly lcbPlcfHdd: number;
|
|
26
40
|
readonly fcSttbfFfn: number;
|
|
27
41
|
readonly lcbSttbfFfn: number;
|
|
28
42
|
readonly fcPlfLst: number;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/prop/fkp.d.ts
|
|
2
|
+
/** Every FKP is exactly one 512-byte page, whatever the compound file's own sector size. */
|
|
3
|
+
declare const FKP_PAGE_SIZE = 512;
|
|
4
|
+
interface ChpxFkp {
|
|
5
|
+
readonly rgfc: readonly number[];
|
|
6
|
+
/** The Chpx's grpprl for run `index`, or undefined when the run's rgb entry is zero and it carries no exception. */
|
|
7
|
+
grpprl(index: number): Uint8Array | undefined;
|
|
8
|
+
}
|
|
9
|
+
interface PapxRecord {
|
|
10
|
+
readonly istd: number;
|
|
11
|
+
readonly grpprl: Uint8Array;
|
|
12
|
+
}
|
|
13
|
+
interface PapxFkp {
|
|
14
|
+
readonly rgfc: readonly number[];
|
|
15
|
+
/** The PapxInFkp for paragraph `index`, or undefined when its BxPap.bOffset is zero and the paragraph takes the defaults. */
|
|
16
|
+
papx(index: number): PapxRecord | undefined;
|
|
17
|
+
}
|
|
18
|
+
declare function parseChpxFkp(page: Uint8Array): ChpxFkp;
|
|
19
|
+
declare function parsePapxFkp(page: Uint8Array): PapxFkp;
|
|
20
|
+
interface PapxLookup extends PapxRecord {
|
|
21
|
+
/** The byte offset one past the end of the paragraph this record covers -- PapxFkp.rgfc[k + 1], the paragraph boundary [MS-DOC] 2.4.2 derives its own from. */
|
|
22
|
+
readonly fcLim: number;
|
|
23
|
+
}
|
|
24
|
+
declare class PropertyBinTable {
|
|
25
|
+
#private;
|
|
26
|
+
constructor(wordDocument: Uint8Array, plc: Uint8Array, what: string);
|
|
27
|
+
/** The direct character-formatting grpprl covering `fc`, or undefined when the offset is outside the table or its run carries no exception. */
|
|
28
|
+
chpxGrpprl(fc: number): Uint8Array | undefined;
|
|
29
|
+
/** The direct paragraph-formatting record covering `fc`, or undefined when the offset is outside the table or its paragraph carries no exception. */
|
|
30
|
+
papx(fc: number): PapxLookup | undefined;
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { PapxRecord as a, parsePapxFkp as c, PapxLookup as i, FKP_PAGE_SIZE as n, PropertyBinTable as o, PapxFkp as r, parseChpxFkp as s, ChpxFkp as t };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/prop/fkp.d.ts
|
|
2
|
+
/** Every FKP is exactly one 512-byte page, whatever the compound file's own sector size. */
|
|
3
|
+
declare const FKP_PAGE_SIZE = 512;
|
|
4
|
+
interface ChpxFkp {
|
|
5
|
+
readonly rgfc: readonly number[];
|
|
6
|
+
/** The Chpx's grpprl for run `index`, or undefined when the run's rgb entry is zero and it carries no exception. */
|
|
7
|
+
grpprl(index: number): Uint8Array | undefined;
|
|
8
|
+
}
|
|
9
|
+
interface PapxRecord {
|
|
10
|
+
readonly istd: number;
|
|
11
|
+
readonly grpprl: Uint8Array;
|
|
12
|
+
}
|
|
13
|
+
interface PapxFkp {
|
|
14
|
+
readonly rgfc: readonly number[];
|
|
15
|
+
/** The PapxInFkp for paragraph `index`, or undefined when its BxPap.bOffset is zero and the paragraph takes the defaults. */
|
|
16
|
+
papx(index: number): PapxRecord | undefined;
|
|
17
|
+
}
|
|
18
|
+
declare function parseChpxFkp(page: Uint8Array): ChpxFkp;
|
|
19
|
+
declare function parsePapxFkp(page: Uint8Array): PapxFkp;
|
|
20
|
+
interface PapxLookup extends PapxRecord {
|
|
21
|
+
/** The byte offset one past the end of the paragraph this record covers -- PapxFkp.rgfc[k + 1], the paragraph boundary [MS-DOC] 2.4.2 derives its own from. */
|
|
22
|
+
readonly fcLim: number;
|
|
23
|
+
}
|
|
24
|
+
declare class PropertyBinTable {
|
|
25
|
+
#private;
|
|
26
|
+
constructor(wordDocument: Uint8Array, plc: Uint8Array, what: string);
|
|
27
|
+
/** The direct character-formatting grpprl covering `fc`, or undefined when the offset is outside the table or its run carries no exception. */
|
|
28
|
+
chpxGrpprl(fc: number): Uint8Array | undefined;
|
|
29
|
+
/** The direct paragraph-formatting record covering `fc`, or undefined when the offset is outside the table or its paragraph carries no exception. */
|
|
30
|
+
papx(fc: number): PapxLookup | undefined;
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { PapxRecord as a, parsePapxFkp as c, PapxLookup as i, FKP_PAGE_SIZE as n, PropertyBinTable as o, PapxFkp as r, parseChpxFkp as s, ChpxFkp as t };
|