doc-codec 0.0.0 → 1.0.1

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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/dist/bytes.cjs +44 -0
  4. package/dist/bytes.d.cts +9 -0
  5. package/dist/bytes.d.ts +9 -0
  6. package/dist/bytes.js +38 -0
  7. package/dist/detect.cjs +22 -0
  8. package/dist/detect.d.cts +6 -0
  9. package/dist/detect.d.ts +6 -0
  10. package/dist/detect.js +20 -0
  11. package/dist/errors.cjs +17 -0
  12. package/dist/errors.d.cts +9 -0
  13. package/dist/errors.d.ts +9 -0
  14. package/dist/errors.js +15 -0
  15. package/dist/fib/fib.cjs +50 -0
  16. package/dist/fib/fib.d.cts +29 -0
  17. package/dist/fib/fib.d.ts +29 -0
  18. package/dist/fib/fib.js +48 -0
  19. package/dist/fib/offsets.cjs +61 -0
  20. package/dist/fib/offsets.d.cts +47 -0
  21. package/dist/fib/offsets.d.ts +47 -0
  22. package/dist/fib/offsets.js +47 -0
  23. package/dist/index.cjs +79 -0
  24. package/dist/index.d.cts +16 -0
  25. package/dist/index.d.ts +16 -0
  26. package/dist/index.js +16 -0
  27. package/dist/plc.cjs +44 -0
  28. package/dist/plc.d.cts +12 -0
  29. package/dist/plc.d.ts +12 -0
  30. package/dist/plc.js +42 -0
  31. package/dist/prop/chp.cjs +172 -0
  32. package/dist/prop/chp.d.cts +16 -0
  33. package/dist/prop/chp.d.ts +16 -0
  34. package/dist/prop/chp.js +171 -0
  35. package/dist/prop/fkp.cjs +141 -0
  36. package/dist/prop/fkp.d.cts +33 -0
  37. package/dist/prop/fkp.d.ts +33 -0
  38. package/dist/prop/fkp.js +137 -0
  39. package/dist/prop/pap.cjs +134 -0
  40. package/dist/prop/pap.d.cts +25 -0
  41. package/dist/prop/pap.d.ts +25 -0
  42. package/dist/prop/pap.js +133 -0
  43. package/dist/prop/sprm.cjs +68 -0
  44. package/dist/prop/sprm.d.cts +26 -0
  45. package/dist/prop/sprm.d.ts +26 -0
  46. package/dist/prop/sprm.js +64 -0
  47. package/dist/read.cjs +171 -0
  48. package/dist/read.d.cts +12 -0
  49. package/dist/read.d.ts +12 -0
  50. package/dist/read.js +169 -0
  51. package/dist/style/stsh.cjs +65 -0
  52. package/dist/style/stsh.d.cts +29 -0
  53. package/dist/style/stsh.d.ts +29 -0
  54. package/dist/style/stsh.js +61 -0
  55. package/dist/text/characters.cjs +69 -0
  56. package/dist/text/characters.d.cts +14 -0
  57. package/dist/text/characters.d.ts +14 -0
  58. package/dist/text/characters.js +67 -0
  59. package/dist/text/piece-table.cjs +68 -0
  60. package/dist/text/piece-table.d.cts +28 -0
  61. package/dist/text/piece-table.d.ts +28 -0
  62. package/dist/text/piece-table.js +65 -0
  63. package/dist/text/special.cjs +48 -0
  64. package/dist/text/special.d.cts +30 -0
  65. package/dist/text/special.d.ts +30 -0
  66. package/dist/text/special.js +34 -0
  67. package/package.json +93 -2
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Joseph Mearman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # doc-codec
2
+
3
+ [![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/documents.js/tree/main/packages/doc-codec) [![npm](https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=white)](https://www.npmjs.com/package/doc-codec) [![npm version](https://img.shields.io/npm/v/doc-codec)](https://www.npmjs.com/package/doc-codec) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/documents.js/ci.yml?branch=main)](https://github.com/ExaDev/documents.js/actions)
4
+
5
+ > A hand-written, dependency-minimal reader for the Word Binary File Format (`.doc`, [MS-DOC]) against the shared [`document-schema.js`](../document-schema.js/README.md) content pivot.
6
+
7
+ `.doc` is the pre-2007 Word format: a binary document living inside an [MS-CFB] compound file, with none of the XML that makes `.docx` tractable. Its text is not stored contiguously, its formatting is stored as sparse exceptions on 512-byte pages, and every structure in it is addressed by a character position that only becomes a byte offset by passing through a piece table. `doc-codec` reads that structure by hand from the published specification, exactly as `ooxml.js` reads `.docx` and `odf.js` reads `.odt`, and produces the same `ContentDocument` all three target.
8
+
9
+ ## Status
10
+
11
+ **Under active development. This package reads; it does not write.**
12
+
13
+ Built and shipped:
14
+
15
+ - **The compound-file container and the FIB** — `readDocStreams` resolves the `WordDocument` stream and whichever of `1Table`/`0Table` `FibBase.fWhichTblStm` selects, then parses the File Information Block for the counts and offsets every later step needs.
16
+ - **The piece table** — `parseClx` resolves a `Clx` (skipping any leading `Prc` array) into the pieces the logical text stream is assembled from, including the compressed 8-bit spelling and its halved byte offset.
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
+ - **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).
19
+ - **The style sheet** — `parseStsh` reads each style's index, name, kind and parent, and `headingLevelFromIstd` applies `sprmPIstd`'s own rule that an `istd` of 1 through 9 states an outline level.
20
+ - **`readDocContent`** — the whole chain, producing a `'wordprocessing'` `ContentDocument` of paragraphs and runs.
21
+ - **`isDocBytes`** — distinguishes a `.doc` from the `.xls`, `.ppt` and OLE embeddings that share its container, by looking for a `WordDocument` stream carrying `FibBase.wIdent`.
22
+
23
+ **Not built, and not approximated.** 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 as though it did not:
24
+
25
+ | Absent | Consequence |
26
+ | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
27
+ | **Writing** | There is no `writeDoc`. The package is read-only. |
28
+ | **Tables** | A table's cells read as ordinary paragraphs in document order, with no `ContentTable` and no row or column structure. Cell marks end paragraphs; `sprmPFInTable`/`sprmPFTtp` are parsed but not yet acted on. |
29
+ | **Images and drawn objects** | The anchor characters (`U+0001`, `U+0008`) are dropped rather than emitted as control characters. No picture data is read. |
30
+ | **Style-inherited formatting** | A style's own property sets live in the `STD`'s `grLPUpxSw` and are not read, so a paragraph's formatting is the document defaults plus its own direct exceptions. A `Heading 1` paragraph reports its `styleId` and `headingLevel` but not the boldness or size its style would supply. |
31
+ | **Subdocuments** | Only the main document (character positions 0 to `ccpText`) is converted. Footnotes, endnotes, headers, footers, comments and text boxes are not. |
32
+ | **Section properties** | Section boundaries are not read, so the whole document is one section, and its page size and margins are a US Letter placeholder rather than the document's own. |
33
+ | **Numbering definitions** | `sprmPIlfo`/`sprmPIlvl` are read into a `list` membership, but the `PlfLfo`/`PlfLst` tables that say what the list looks like are not, so no marker text or numbering format is available. |
34
+ | **Metadata** | Title, author and dates live in `SummaryInformation` property-set streams ([MS-OLEPS], not [MS-DOC]) and are not read; `metadata` is empty. |
35
+ | **Encryption** | An encrypted or XOR-obfuscated document is refused with a `DocUnsupportedError` rather than read as plaintext. |
36
+ | **`sprmPHugePapx` / `sprmPTableProps`** | Paragraph properties stored indirectly in the Data stream are not followed, so such a paragraph reads with fewer properties than it states. |
37
+
38
+ 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.
39
+
40
+ ## What is converted
41
+
42
+ Character properties, from `Chpx` grpprls:
43
+
44
+ | Sprm | Becomes |
45
+ | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
46
+ | `sprmCFBold` (0x0835), `sprmCFItalic` (0x0836), `sprmCFStrike` (0x0837) | `bold` / `italic` / `strike`, honouring `ToggleOperand`'s inherit (0x80) and invert (0x81) values |
47
+ | `sprmCKul` (0x2A3E) | `underline` (any non-zero `Kul` style) |
48
+ | `sprmCHps` (0x4A43) | `sizePt`, the operand being half-points |
49
+ | `sprmCIco` (0x2A42) | `color`, through [MS-DOC] 2.9.126's fixed palette |
50
+ | `sprmCCv` (0x6870) | `color`, from a `COLORREF` |
51
+ | `sprmCIstd` (0x4A30) | the character style index, carried for a caller to resolve |
52
+
53
+ Paragraph properties, from `PapxInFkp` grpprls:
54
+
55
+ | Sprm | Becomes |
56
+ | ----------------------------------------------------- | ----------------------------------------------------------------------- |
57
+ | `sprmPIstd` (0x4600) | `styleId` (the style's name) and `headingLevel` (via the istd 1-9 rule) |
58
+ | `sprmPJc` (0x2461), `sprmPJc80` (0x2403) | `alignment` |
59
+ | `sprmPDxaLeft` (0x845E) / `sprmPDxaLeft80` (0x840F) | `indentLeftPt` |
60
+ | `sprmPDxaLeft1` (0x8460) / `sprmPDxaLeft180` (0x8411) | `indentFirstLinePt` |
61
+ | `sprmPDyaBefore` (0xA413), `sprmPDyaAfter` (0xA414) | `spacingBeforePt` / `spacingAfterPt` |
62
+ | `sprmPDyaLine` (0x6412) | `lineSpacing`, only for `LSPD`'s multiplier form |
63
+ | `sprmPFPageBreakBefore` (0x2407) | `pageBreakBefore` |
64
+ | `sprmPOutLvl` (0x2640) | `headingLevel`, where the istd did not already supply one |
65
+ | `sprmPIlfo` (0x460B), `sprmPIlvl` (0x260A) | `list` membership |
66
+
67
+ Fields are handled structurally: everything between a field-begin (`U+0013`) and a field-separator (`U+0014`) is the field's instruction and is dropped; the result between the separator and the field-end (`U+0015`) is kept. A line break (`U+000B`) inside a paragraph survives as a newline.
68
+
69
+ ## Architecture
70
+
71
+ This package hand-parses [MS-DOC] against its published field tables. It depends on no third-party `.doc` reader, and its ESLint configuration bans several by name (`word-extractor`, `mammoth`, `textract`, the `cfb` package) so the decision is enforced rather than merely intended — the same bet `markdown-codec` makes against every markdown library and `pdf-codec` against `pdf-lib`.
72
+
73
+ It depends on exactly two siblings: [`archive-codec`](../archive-codec/README.md) for the [MS-CFB] container, and [`document-schema.js`](../document-schema.js/README.md) for the content pivot it produces. It does not depend on `ooxml.js`, and `ooxml.js` does not depend on it: `.doc` and `.docx` are unrelated formats that happen to share an application, and the only thing they genuinely have in common is the `ContentDocument` both target.
74
+
75
+ ```mermaid
76
+ graph TD
77
+ archive("archive-codec")
78
+ schema("document-schema.js")
79
+ doc("doc-codec")
80
+ archive --> doc
81
+ schema --> doc
82
+ style doc fill:#f9a825,stroke:#333,stroke-width:3px
83
+ ```
84
+
85
+ The modules layer in the order [MS-DOC]'s own algorithms chain:
86
+
87
+ | Module | What it does |
88
+ | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
89
+ | `src/bytes.ts` | Bounds-checked little-endian reads; every offset in the format is attacker-controlled data, so an over-read fails loudly. |
90
+ | `src/plc.ts` | The `PLC` container shape, whose element count is derived from its total size by [MS-DOC] 2.2.2's own formula, and the "largest key at most" lookup every algorithm phrases in those words. |
91
+ | `src/fib/` | The FIB's field offsets, derived by summing the declared field sizes, and the parse that reads the counts and offsets from them. |
92
+ | `src/text/piece-table.ts` | The `Clx` and its `PlcPcd`, and the character-position-to-byte-offset mapping. |
93
+ | `src/text/characters.ts` | Text reconstruction, including the compressed-byte mapping table. |
94
+ | `src/text/special.ts` | The characters that carry structure rather than glyphs. |
95
+ | `src/prop/sprm.ts` | `Sprm` decoding and the operand-size table that makes a grpprl walkable. |
96
+ | `src/prop/fkp.ts` | The formatted disk pages and the bin tables that address them. |
97
+ | `src/prop/chp.ts`, `src/prop/pap.ts` | Folding a grpprl into character and paragraph properties. |
98
+ | `src/style/stsh.ts` | The style sheet. |
99
+ | `src/read.ts` | The whole chain, to a `ContentDocument`. |
100
+
101
+ ### Why the piece table gets the most attention
102
+
103
+ A `.doc`'s text is assembled from pieces, each naming a byte range of the `WordDocument` stream and the character positions that range supplies, and every other structure in the format addresses text by character position. Two details carry most of the risk, and both live in one 32-bit field: the low 30 bits are a byte offset, and bit 30 says whether the piece's characters are 16-bit (offset used as-is) or 8-bit (the real offset being that value **halved**). Forget the halving and the reader does not fail — it produces real characters from the wrong place in the stream.
104
+
105
+ That is the failure mode this package is built to avoid throughout: a binary parser that guesses does not crash, it corrupts. So every structure here was implemented against the specification's own field tables, with a failing test written first from those tables, and the piece table is additionally tested against [MS-DOC] 2.9.6's published worked example — the same `Clx`, the same four character positions, the same three pieces, the same `"Hello World."` the specification says they assemble to.
106
+
107
+ ## Getting started
108
+
109
+ Requires Node.js `>=20` and pnpm `11.6.0` (pinned via `packageManager` in `package.json`).
110
+
111
+ ```sh
112
+ pnpm install
113
+ pnpm build
114
+ pnpm test
115
+ ```
116
+
117
+ ```ts
118
+ import { readDocContent, isDocBytes } from "doc-codec";
119
+
120
+ const bytes = new Uint8Array(await file.arrayBuffer());
121
+ if (isDocBytes(bytes)) {
122
+ const document = readDocContent(bytes);
123
+ // document.kind === "wordprocessing"
124
+ }
125
+ ```
126
+
127
+ `readDocContent` throws a `DocFormatError` when the bytes do not conform to [MS-DOC], and a `DocUnsupportedError` when they conform but use a feature this package deliberately refuses rather than approximates (encryption, or the `sprmPChgTabs` sentinel above).
128
+
129
+ ## Worker-isomorphic
130
+
131
+ Like every foundation and format-codec package in this family, `doc-codec`'s published `src/` imports no `node:*` module and uses no Node-only global. The whole surface is byte arithmetic over `Uint8Array` and `DataView`, with no I/O of its own. A `test:workers` suite runs the reader inside workerd, the real Cloudflare Workers runtime, so the property is a runtime-checked fact rather than an assertion.
132
+
133
+ ## Testing
134
+
135
+ Every structure is tested against bytes hand-assembled from [MS-DOC]'s own field tables rather than dumped from a real Word file, and the test-support builders (`src/test-support/`) place each field by adding up the specification's declared sizes while the parsers read them from independently derived constants — so the two agree only if both match the specification. `buildDoc` assembles a whole synthetic `.doc`: a real compound file, a real FIB, a real piece table, real FKP pages, and a real style sheet, wired together with the offsets a producer would compute.
136
+
137
+ There is no real-world conformance corpus. That is a genuine gap, not an oversight: the tests prove this reader matches the published specification, which is not the same as proving it matches what Word actually wrote between 1997 and 2007. Anyone extending this package should treat a corpus as the next thing worth building.
138
+
139
+ ## Specification
140
+
141
+ Every structure in this package cites the section of [MS-DOC] it implements. The specification is published by Microsoft under its Open Specifications programme:
142
+
143
+ - [[MS-DOC]: Word (.doc) Binary File Format](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/) — in particular [Fib](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/9aeaa2e7-4a45-468e-ab13-3f6193eb9394), [Retrieving Text](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/01d5d8c4-cf9c-4ef9-80fd-439e763cfe01), [Clx](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/bad26767-b575-44d3-9da3-96378d56ce14), [FcCompressed](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/aa2e55a2-f4f2-4795-bab5-6d9d7a0ed249), [ChpxFkp](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/f5f10f04-d4cc-4ebd-86df-0de6d227675c), [PapxFkp](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/34aaeaf3-9578-41af-a3f5-c12f6f66bf1b), [PapxInFkp](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/580510b8-df7a-467e-a51c-0d71eb15c7cd), [Sprm](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/099eb99c-a927-4caf-a80c-66254ea83d6a), [Character Properties](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/7022285b-9621-42e9-ad4d-4e02c115ef18), [Paragraph Properties](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/484822ee-a9d9-4af4-8423-29fda67a6a58), and [STSH](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/c8ee0f39-02c3-4caa-b27a-6a97600130fe).
144
+ - [[MS-CFB]: Compound File Binary File Format](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb/) — the container, read through `archive-codec`.
145
+
146
+ ## Licence
147
+
148
+ MIT. See [LICENSE](LICENSE).
package/dist/bytes.cjs ADDED
@@ -0,0 +1,44 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_errors = require("./errors.cjs");
3
+ //#region src/bytes.ts
4
+ function checkRange(bytes, offset, size, what) {
5
+ if (!Number.isInteger(offset) || offset < 0) throw new require_errors.DocFormatError(`${what} read at offset ${offset}, which is not a non-negative integer`);
6
+ if (offset + size > bytes.length) throw new require_errors.DocFormatError(`${what} read of ${size} bytes at offset ${offset} runs past the end of a ${bytes.length}-byte stream`);
7
+ }
8
+ function readUint8(bytes, offset) {
9
+ checkRange(bytes, offset, 1, "uint8");
10
+ const value = bytes[offset];
11
+ if (value === void 0) throw new require_errors.DocFormatError(`uint8 read at offset ${offset} found no byte`);
12
+ return value;
13
+ }
14
+ function readUint16LE(bytes, offset) {
15
+ checkRange(bytes, offset, 2, "uint16");
16
+ return view(bytes).getUint16(offset, true);
17
+ }
18
+ function readInt16LE(bytes, offset) {
19
+ checkRange(bytes, offset, 2, "int16");
20
+ return view(bytes).getInt16(offset, true);
21
+ }
22
+ function readUint32LE(bytes, offset) {
23
+ checkRange(bytes, offset, 4, "uint32");
24
+ return view(bytes).getUint32(offset, true);
25
+ }
26
+ function readInt32LE(bytes, offset) {
27
+ checkRange(bytes, offset, 4, "int32");
28
+ return view(bytes).getInt32(offset, true);
29
+ }
30
+ function view(bytes) {
31
+ return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
32
+ }
33
+ function slice(bytes, offset, length, what) {
34
+ if (!Number.isInteger(length) || length < 0) throw new require_errors.DocFormatError(`${what} declares a length of ${length}, which is not a non-negative integer`);
35
+ checkRange(bytes, offset, length, what);
36
+ return bytes.subarray(offset, offset + length);
37
+ }
38
+ //#endregion
39
+ exports.readInt16LE = readInt16LE;
40
+ exports.readInt32LE = readInt32LE;
41
+ exports.readUint16LE = readUint16LE;
42
+ exports.readUint32LE = readUint32LE;
43
+ exports.readUint8 = readUint8;
44
+ exports.slice = slice;
@@ -0,0 +1,9 @@
1
+ //#region src/bytes.d.ts
2
+ declare function readUint8(bytes: Uint8Array, offset: number): number;
3
+ declare function readUint16LE(bytes: Uint8Array, offset: number): number;
4
+ declare function readInt16LE(bytes: Uint8Array, offset: number): number;
5
+ declare function readUint32LE(bytes: Uint8Array, offset: number): number;
6
+ declare function readInt32LE(bytes: Uint8Array, offset: number): number;
7
+ declare function slice(bytes: Uint8Array, offset: number, length: number, what: string): Uint8Array;
8
+ //#endregion
9
+ export { readInt16LE, readInt32LE, readUint16LE, readUint32LE, readUint8, slice };
@@ -0,0 +1,9 @@
1
+ //#region src/bytes.d.ts
2
+ declare function readUint8(bytes: Uint8Array, offset: number): number;
3
+ declare function readUint16LE(bytes: Uint8Array, offset: number): number;
4
+ declare function readInt16LE(bytes: Uint8Array, offset: number): number;
5
+ declare function readUint32LE(bytes: Uint8Array, offset: number): number;
6
+ declare function readInt32LE(bytes: Uint8Array, offset: number): number;
7
+ declare function slice(bytes: Uint8Array, offset: number, length: number, what: string): Uint8Array;
8
+ //#endregion
9
+ export { readInt16LE, readInt32LE, readUint16LE, readUint32LE, readUint8, slice };
package/dist/bytes.js ADDED
@@ -0,0 +1,38 @@
1
+ import { DocFormatError } from "./errors.js";
2
+ //#region src/bytes.ts
3
+ function checkRange(bytes, offset, size, what) {
4
+ if (!Number.isInteger(offset) || offset < 0) throw new DocFormatError(`${what} read at offset ${offset}, which is not a non-negative integer`);
5
+ if (offset + size > bytes.length) throw new DocFormatError(`${what} read of ${size} bytes at offset ${offset} runs past the end of a ${bytes.length}-byte stream`);
6
+ }
7
+ function readUint8(bytes, offset) {
8
+ checkRange(bytes, offset, 1, "uint8");
9
+ const value = bytes[offset];
10
+ if (value === void 0) throw new DocFormatError(`uint8 read at offset ${offset} found no byte`);
11
+ return value;
12
+ }
13
+ function readUint16LE(bytes, offset) {
14
+ checkRange(bytes, offset, 2, "uint16");
15
+ return view(bytes).getUint16(offset, true);
16
+ }
17
+ function readInt16LE(bytes, offset) {
18
+ checkRange(bytes, offset, 2, "int16");
19
+ return view(bytes).getInt16(offset, true);
20
+ }
21
+ function readUint32LE(bytes, offset) {
22
+ checkRange(bytes, offset, 4, "uint32");
23
+ return view(bytes).getUint32(offset, true);
24
+ }
25
+ function readInt32LE(bytes, offset) {
26
+ checkRange(bytes, offset, 4, "int32");
27
+ return view(bytes).getInt32(offset, true);
28
+ }
29
+ function view(bytes) {
30
+ return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
31
+ }
32
+ function slice(bytes, offset, length, what) {
33
+ if (!Number.isInteger(length) || length < 0) throw new DocFormatError(`${what} declares a length of ${length}, which is not a non-negative integer`);
34
+ checkRange(bytes, offset, length, what);
35
+ return bytes.subarray(offset, offset + length);
36
+ }
37
+ //#endregion
38
+ export { readInt16LE, readInt32LE, readUint16LE, readUint32LE, readUint8, slice };
@@ -0,0 +1,22 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_bytes = require("./bytes.cjs");
3
+ const require_fib_offsets = require("./fib/offsets.cjs");
4
+ let archive_codec = require("archive-codec");
5
+ //#region src/detect.ts
6
+ /** The stream a Word Binary File's FIB and text live in, [MS-DOC] 2.1.1. */
7
+ const WORD_DOCUMENT_STREAM = "WordDocument";
8
+ function isDocBytes(bytes) {
9
+ if (!(0, archive_codec.isCompoundFile)(bytes)) return false;
10
+ let streams;
11
+ try {
12
+ streams = (0, archive_codec.readCompoundFile)(bytes);
13
+ } catch {
14
+ return false;
15
+ }
16
+ const wordDocument = streams.find((stream) => stream.path === WORD_DOCUMENT_STREAM);
17
+ if (wordDocument === void 0 || wordDocument.bytes.length < 2) return false;
18
+ return require_bytes.readUint16LE(wordDocument.bytes, 0) === require_fib_offsets.FIB_W_IDENT;
19
+ }
20
+ //#endregion
21
+ exports.WORD_DOCUMENT_STREAM = WORD_DOCUMENT_STREAM;
22
+ exports.isDocBytes = isDocBytes;
@@ -0,0 +1,6 @@
1
+ //#region src/detect.d.ts
2
+ /** The stream a Word Binary File's FIB and text live in, [MS-DOC] 2.1.1. */
3
+ declare const WORD_DOCUMENT_STREAM = "WordDocument";
4
+ declare function isDocBytes(bytes: Uint8Array<ArrayBuffer>): boolean;
5
+ //#endregion
6
+ export { WORD_DOCUMENT_STREAM, isDocBytes };
@@ -0,0 +1,6 @@
1
+ //#region src/detect.d.ts
2
+ /** The stream a Word Binary File's FIB and text live in, [MS-DOC] 2.1.1. */
3
+ declare const WORD_DOCUMENT_STREAM = "WordDocument";
4
+ declare function isDocBytes(bytes: Uint8Array<ArrayBuffer>): boolean;
5
+ //#endregion
6
+ export { WORD_DOCUMENT_STREAM, isDocBytes };
package/dist/detect.js ADDED
@@ -0,0 +1,20 @@
1
+ import { readUint16LE } from "./bytes.js";
2
+ import { FIB_W_IDENT } from "./fib/offsets.js";
3
+ import { isCompoundFile, readCompoundFile } from "archive-codec";
4
+ //#region src/detect.ts
5
+ /** The stream a Word Binary File's FIB and text live in, [MS-DOC] 2.1.1. */
6
+ const WORD_DOCUMENT_STREAM = "WordDocument";
7
+ function isDocBytes(bytes) {
8
+ if (!isCompoundFile(bytes)) return false;
9
+ let streams;
10
+ try {
11
+ streams = readCompoundFile(bytes);
12
+ } catch {
13
+ return false;
14
+ }
15
+ const wordDocument = streams.find((stream) => stream.path === WORD_DOCUMENT_STREAM);
16
+ if (wordDocument === void 0 || wordDocument.bytes.length < 2) return false;
17
+ return readUint16LE(wordDocument.bytes, 0) === FIB_W_IDENT;
18
+ }
19
+ //#endregion
20
+ export { WORD_DOCUMENT_STREAM, isDocBytes };
@@ -0,0 +1,17 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/errors.ts
3
+ var DocFormatError = class extends Error {
4
+ constructor(message) {
5
+ super(message);
6
+ this.name = "DocFormatError";
7
+ }
8
+ };
9
+ var DocUnsupportedError = class extends Error {
10
+ constructor(message) {
11
+ super(message);
12
+ this.name = "DocUnsupportedError";
13
+ }
14
+ };
15
+ //#endregion
16
+ exports.DocFormatError = DocFormatError;
17
+ exports.DocUnsupportedError = DocUnsupportedError;
@@ -0,0 +1,9 @@
1
+ //#region src/errors.d.ts
2
+ declare class DocFormatError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ declare class DocUnsupportedError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ //#endregion
9
+ export { DocFormatError, DocUnsupportedError };
@@ -0,0 +1,9 @@
1
+ //#region src/errors.d.ts
2
+ declare class DocFormatError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ declare class DocUnsupportedError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ //#endregion
9
+ export { DocFormatError, DocUnsupportedError };
package/dist/errors.js ADDED
@@ -0,0 +1,15 @@
1
+ //#region src/errors.ts
2
+ var DocFormatError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "DocFormatError";
6
+ }
7
+ };
8
+ var DocUnsupportedError = class extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = "DocUnsupportedError";
12
+ }
13
+ };
14
+ //#endregion
15
+ export { DocFormatError, DocUnsupportedError };
@@ -0,0 +1,50 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_errors = require("../errors.cjs");
3
+ const require_bytes = require("../bytes.cjs");
4
+ const require_fib_offsets = require("./offsets.cjs");
5
+ //#region src/fib/fib.ts
6
+ function parseFib(wordDocument) {
7
+ const wIdent = require_bytes.readUint16LE(wordDocument, 0);
8
+ if (wIdent !== 42476) throw new require_errors.DocFormatError(`the WordDocument stream begins with 0x${wIdent.toString(16).toUpperCase().padStart(4, "0")} rather than the 0xA5EC every Word Binary File's FibBase.wIdent must carry`);
9
+ const nFib = require_bytes.readUint16LE(wordDocument, 2);
10
+ const flags = require_bytes.readUint16LE(wordDocument, 10);
11
+ if ((flags & require_fib_offsets.FIB_BASE_FLAG.fEncrypted) !== 0) throw new require_errors.DocUnsupportedError((flags & require_fib_offsets.FIB_BASE_FLAG.fObfuscated) !== 0 ? "this document is XOR-obfuscated ([MS-DOC] 2.2.6.1); doc-codec cannot decrypt it, and reading its streams as plaintext would produce arbitrary text rather than the document's own" : "this document is encrypted ([MS-DOC] 2.2.6); doc-codec cannot decrypt it, and reading its streams as plaintext would produce arbitrary text rather than the document's own");
12
+ const csw = require_bytes.readUint16LE(wordDocument, 32);
13
+ if (csw !== 14) throw new require_errors.DocFormatError(`Fib.csw is 0x${csw.toString(16)} rather than the mandated 0x${14 .toString(16)}, so FibRgW97 is not the size every later offset assumes`);
14
+ const cslw = require_bytes.readUint16LE(wordDocument, 62);
15
+ if (cslw !== 22) throw new require_errors.DocFormatError(`Fib.cslw is 0x${cslw.toString(16)} rather than the mandated 0x${22 .toString(16)}, so FibRgLw97 is not the size every later offset assumes`);
16
+ const cbRgFcLcb = require_bytes.readUint16LE(wordDocument, 152);
17
+ const blobValues = cbRgFcLcb * 2;
18
+ const highestIndex = Math.max(...Object.values(require_fib_offsets.FC_LCB_VALUE_INDEX));
19
+ if (highestIndex >= blobValues) throw new require_errors.DocFormatError(`Fib.cbRgFcLcb is ${cbRgFcLcb}, giving a FibRgFcLcb blob of ${blobValues} 4-byte values, which does not reach value index ${highestIndex} where lcbClx lives`);
20
+ const lw = (offset) => require_bytes.readInt32LE(wordDocument, 64 + offset);
21
+ const fcLcb = (index) => require_bytes.readUint32LE(wordDocument, 154 + index * 4);
22
+ return {
23
+ nFib,
24
+ fComplex: (flags & require_fib_offsets.FIB_BASE_FLAG.fComplex) !== 0,
25
+ fWhichTblStm: (flags & require_fib_offsets.FIB_BASE_FLAG.fWhichTblStm) !== 0 ? 1 : 0,
26
+ cbMac: lw(require_fib_offsets.LW_OFFSET.cbMac),
27
+ ccpText: lw(require_fib_offsets.LW_OFFSET.ccpText),
28
+ ccpFtn: lw(require_fib_offsets.LW_OFFSET.ccpFtn),
29
+ ccpHdd: lw(require_fib_offsets.LW_OFFSET.ccpHdd),
30
+ ccpAtn: lw(require_fib_offsets.LW_OFFSET.ccpAtn),
31
+ ccpEdn: lw(require_fib_offsets.LW_OFFSET.ccpEdn),
32
+ ccpTxbx: lw(require_fib_offsets.LW_OFFSET.ccpTxbx),
33
+ ccpHdrTxbx: lw(require_fib_offsets.LW_OFFSET.ccpHdrTxbx),
34
+ fcStshf: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcStshf),
35
+ lcbStshf: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbStshf),
36
+ fcPlcfBteChpx: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcPlcfBteChpx),
37
+ lcbPlcfBteChpx: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbPlcfBteChpx),
38
+ fcPlcfBtePapx: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcPlcfBtePapx),
39
+ lcbPlcfBtePapx: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbPlcfBtePapx),
40
+ fcClx: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.fcClx),
41
+ lcbClx: fcLcb(require_fib_offsets.FC_LCB_VALUE_INDEX.lcbClx)
42
+ };
43
+ }
44
+ /** The name of the compound-file stream every `fc` offset in the Fib is relative to, selected by FibBase.fWhichTblStm. */
45
+ function tableStreamName(fib) {
46
+ return fib.fWhichTblStm === 1 ? "1Table" : "0Table";
47
+ }
48
+ //#endregion
49
+ exports.parseFib = parseFib;
50
+ exports.tableStreamName = tableStreamName;
@@ -0,0 +1,29 @@
1
+ //#region src/fib/fib.d.ts
2
+ interface Fib {
3
+ readonly nFib: number;
4
+ /** Set when the last save was an incremental ("fast") save. The piece table is what makes such a document readable at all, so this is informational rather than a refusal. */
5
+ readonly fComplex: boolean;
6
+ /** 1 selects the "1Table" stream, 0 the "0Table" stream, as the Table stream every fc offset below is relative to. */
7
+ readonly fWhichTblStm: 0 | 1;
8
+ readonly cbMac: number;
9
+ readonly ccpText: number;
10
+ readonly ccpFtn: number;
11
+ readonly ccpHdd: number;
12
+ readonly ccpAtn: number;
13
+ readonly ccpEdn: number;
14
+ readonly ccpTxbx: number;
15
+ readonly ccpHdrTxbx: number;
16
+ readonly fcStshf: number;
17
+ readonly lcbStshf: number;
18
+ readonly fcPlcfBteChpx: number;
19
+ readonly lcbPlcfBteChpx: number;
20
+ readonly fcPlcfBtePapx: number;
21
+ readonly lcbPlcfBtePapx: number;
22
+ readonly fcClx: number;
23
+ readonly lcbClx: number;
24
+ }
25
+ declare function parseFib(wordDocument: Uint8Array): Fib;
26
+ /** The name of the compound-file stream every `fc` offset in the Fib is relative to, selected by FibBase.fWhichTblStm. */
27
+ declare function tableStreamName(fib: Fib): "0Table" | "1Table";
28
+ //#endregion
29
+ export { Fib, parseFib, tableStreamName };
@@ -0,0 +1,29 @@
1
+ //#region src/fib/fib.d.ts
2
+ interface Fib {
3
+ readonly nFib: number;
4
+ /** Set when the last save was an incremental ("fast") save. The piece table is what makes such a document readable at all, so this is informational rather than a refusal. */
5
+ readonly fComplex: boolean;
6
+ /** 1 selects the "1Table" stream, 0 the "0Table" stream, as the Table stream every fc offset below is relative to. */
7
+ readonly fWhichTblStm: 0 | 1;
8
+ readonly cbMac: number;
9
+ readonly ccpText: number;
10
+ readonly ccpFtn: number;
11
+ readonly ccpHdd: number;
12
+ readonly ccpAtn: number;
13
+ readonly ccpEdn: number;
14
+ readonly ccpTxbx: number;
15
+ readonly ccpHdrTxbx: number;
16
+ readonly fcStshf: number;
17
+ readonly lcbStshf: number;
18
+ readonly fcPlcfBteChpx: number;
19
+ readonly lcbPlcfBteChpx: number;
20
+ readonly fcPlcfBtePapx: number;
21
+ readonly lcbPlcfBtePapx: number;
22
+ readonly fcClx: number;
23
+ readonly lcbClx: number;
24
+ }
25
+ declare function parseFib(wordDocument: Uint8Array): Fib;
26
+ /** The name of the compound-file stream every `fc` offset in the Fib is relative to, selected by FibBase.fWhichTblStm. */
27
+ declare function tableStreamName(fib: Fib): "0Table" | "1Table";
28
+ //#endregion
29
+ export { Fib, parseFib, tableStreamName };
@@ -0,0 +1,48 @@
1
+ import { DocFormatError, DocUnsupportedError } from "../errors.js";
2
+ import { readInt32LE, readUint16LE, readUint32LE } from "../bytes.js";
3
+ import { FC_LCB_VALUE_INDEX, FIB_BASE_FLAG, LW_OFFSET } from "./offsets.js";
4
+ //#region src/fib/fib.ts
5
+ function parseFib(wordDocument) {
6
+ const wIdent = readUint16LE(wordDocument, 0);
7
+ if (wIdent !== 42476) throw new DocFormatError(`the WordDocument stream begins with 0x${wIdent.toString(16).toUpperCase().padStart(4, "0")} rather than the 0xA5EC every Word Binary File's FibBase.wIdent must carry`);
8
+ const nFib = readUint16LE(wordDocument, 2);
9
+ const flags = readUint16LE(wordDocument, 10);
10
+ if ((flags & FIB_BASE_FLAG.fEncrypted) !== 0) throw new DocUnsupportedError((flags & FIB_BASE_FLAG.fObfuscated) !== 0 ? "this document is XOR-obfuscated ([MS-DOC] 2.2.6.1); doc-codec cannot decrypt it, and reading its streams as plaintext would produce arbitrary text rather than the document's own" : "this document is encrypted ([MS-DOC] 2.2.6); doc-codec cannot decrypt it, and reading its streams as plaintext would produce arbitrary text rather than the document's own");
11
+ const csw = readUint16LE(wordDocument, 32);
12
+ if (csw !== 14) throw new DocFormatError(`Fib.csw is 0x${csw.toString(16)} rather than the mandated 0x${14 .toString(16)}, so FibRgW97 is not the size every later offset assumes`);
13
+ const cslw = readUint16LE(wordDocument, 62);
14
+ if (cslw !== 22) throw new DocFormatError(`Fib.cslw is 0x${cslw.toString(16)} rather than the mandated 0x${22 .toString(16)}, so FibRgLw97 is not the size every later offset assumes`);
15
+ const cbRgFcLcb = readUint16LE(wordDocument, 152);
16
+ const blobValues = cbRgFcLcb * 2;
17
+ const highestIndex = Math.max(...Object.values(FC_LCB_VALUE_INDEX));
18
+ if (highestIndex >= blobValues) throw new DocFormatError(`Fib.cbRgFcLcb is ${cbRgFcLcb}, giving a FibRgFcLcb blob of ${blobValues} 4-byte values, which does not reach value index ${highestIndex} where lcbClx lives`);
19
+ const lw = (offset) => readInt32LE(wordDocument, 64 + offset);
20
+ const fcLcb = (index) => readUint32LE(wordDocument, 154 + index * 4);
21
+ return {
22
+ nFib,
23
+ fComplex: (flags & FIB_BASE_FLAG.fComplex) !== 0,
24
+ fWhichTblStm: (flags & FIB_BASE_FLAG.fWhichTblStm) !== 0 ? 1 : 0,
25
+ cbMac: lw(LW_OFFSET.cbMac),
26
+ ccpText: lw(LW_OFFSET.ccpText),
27
+ ccpFtn: lw(LW_OFFSET.ccpFtn),
28
+ ccpHdd: lw(LW_OFFSET.ccpHdd),
29
+ ccpAtn: lw(LW_OFFSET.ccpAtn),
30
+ ccpEdn: lw(LW_OFFSET.ccpEdn),
31
+ ccpTxbx: lw(LW_OFFSET.ccpTxbx),
32
+ ccpHdrTxbx: lw(LW_OFFSET.ccpHdrTxbx),
33
+ fcStshf: fcLcb(FC_LCB_VALUE_INDEX.fcStshf),
34
+ lcbStshf: fcLcb(FC_LCB_VALUE_INDEX.lcbStshf),
35
+ fcPlcfBteChpx: fcLcb(FC_LCB_VALUE_INDEX.fcPlcfBteChpx),
36
+ lcbPlcfBteChpx: fcLcb(FC_LCB_VALUE_INDEX.lcbPlcfBteChpx),
37
+ fcPlcfBtePapx: fcLcb(FC_LCB_VALUE_INDEX.fcPlcfBtePapx),
38
+ lcbPlcfBtePapx: fcLcb(FC_LCB_VALUE_INDEX.lcbPlcfBtePapx),
39
+ fcClx: fcLcb(FC_LCB_VALUE_INDEX.fcClx),
40
+ lcbClx: fcLcb(FC_LCB_VALUE_INDEX.lcbClx)
41
+ };
42
+ }
43
+ /** The name of the compound-file stream every `fc` offset in the Fib is relative to, selected by FibBase.fWhichTblStm. */
44
+ function tableStreamName(fib) {
45
+ return fib.fWhichTblStm === 1 ? "1Table" : "0Table";
46
+ }
47
+ //#endregion
48
+ export { parseFib, tableStreamName };
@@ -0,0 +1,61 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/fib/offsets.ts
3
+ /** FibBase, [MS-DOC] 2.5.2 -- the fixed 32-byte head of every Fib. csw, the count of 16-bit values in FibRgW97, sits immediately after it, so this doubles as csw's own offset. */
4
+ const FIB_BASE_SIZE = 32;
5
+ /** csw MUST be 0x000E, fixing FibRgW97 at 28 bytes and every offset after it. */
6
+ const FIB_CSW_REQUIRED = 14;
7
+ /** FibRgW97, [MS-DOC] 2.5.3 -- 14 16-bit values, none of which this reader needs. */
8
+ const FIB_RG_W_OFFSET = 34;
9
+ const FIB_RG_W_SIZE = 28;
10
+ /** cslw, the count of 32-bit values in FibRgLw97. MUST be 0x0016. */
11
+ const FIB_CSLW_OFFSET = 62;
12
+ const FIB_CSLW_REQUIRED = 22;
13
+ /** FibRgLw97, [MS-DOC] 2.5.4 -- 22 32-bit values holding cbMac and the per-subdocument CP counts. */
14
+ const FIB_RG_LW_OFFSET = 64;
15
+ const FIB_RG_LW_SIZE = 88;
16
+ /** cbRgFcLcb, the count of 64-bit values in FibRgFcLcbBlob. Varies by nFib (0x005D for 0x00C1 through 0x00B7 for 0x0112), so it is read rather than assumed. */
17
+ const FIB_CB_RG_FC_LCB_OFFSET = 152;
18
+ /** FibRgFcLcb97, [MS-DOC] 2.5.5 -- the flat array of paired file offsets and lengths locating every other structure in the Table stream. */
19
+ const FIB_FC_LCB_BLOB_OFFSET = 154;
20
+ const LW_OFFSET = {
21
+ cbMac: 0,
22
+ ccpText: 12,
23
+ ccpFtn: 16,
24
+ ccpHdd: 20,
25
+ ccpAtn: 28,
26
+ ccpEdn: 32,
27
+ ccpTxbx: 36,
28
+ ccpHdrTxbx: 40
29
+ };
30
+ const FC_LCB_VALUE_INDEX = {
31
+ fcStshf: 2,
32
+ lcbStshf: 3,
33
+ fcPlcfBteChpx: 24,
34
+ lcbPlcfBteChpx: 25,
35
+ fcPlcfBtePapx: 26,
36
+ lcbPlcfBtePapx: 27,
37
+ fcClx: 66,
38
+ lcbClx: 67
39
+ };
40
+ const FIB_BASE_FLAG = {
41
+ fComplex: 4,
42
+ fEncrypted: 256,
43
+ fWhichTblStm: 512,
44
+ fObfuscated: 32768
45
+ };
46
+ const FIB_W_IDENT = 42476;
47
+ //#endregion
48
+ exports.FC_LCB_VALUE_INDEX = FC_LCB_VALUE_INDEX;
49
+ exports.FIB_BASE_FLAG = FIB_BASE_FLAG;
50
+ exports.FIB_BASE_SIZE = FIB_BASE_SIZE;
51
+ exports.FIB_CB_RG_FC_LCB_OFFSET = FIB_CB_RG_FC_LCB_OFFSET;
52
+ exports.FIB_CSLW_OFFSET = FIB_CSLW_OFFSET;
53
+ exports.FIB_CSLW_REQUIRED = FIB_CSLW_REQUIRED;
54
+ exports.FIB_CSW_REQUIRED = FIB_CSW_REQUIRED;
55
+ exports.FIB_FC_LCB_BLOB_OFFSET = FIB_FC_LCB_BLOB_OFFSET;
56
+ exports.FIB_RG_LW_OFFSET = FIB_RG_LW_OFFSET;
57
+ exports.FIB_RG_LW_SIZE = FIB_RG_LW_SIZE;
58
+ exports.FIB_RG_W_OFFSET = FIB_RG_W_OFFSET;
59
+ exports.FIB_RG_W_SIZE = FIB_RG_W_SIZE;
60
+ exports.FIB_W_IDENT = FIB_W_IDENT;
61
+ exports.LW_OFFSET = LW_OFFSET;