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
@@ -0,0 +1,65 @@
1
+ import { DocFormatError } from "../errors.js";
2
+ import { readInt16LE, readUint16LE, readUint32LE, readUint8, slice } from "../bytes.js";
3
+ import { parsePlc } from "../plc.js";
4
+ //#region src/text/piece-table.ts
5
+ /** A Clx's leading Prc marker byte, [MS-DOC] 2.9.20: "This value MUST be 0x01." */
6
+ const CLXT_PRC = 1;
7
+ /** A Clx's Pcdt marker byte, [MS-DOC] 2.9.19: "This value MUST be 0x02." */
8
+ const CLXT_PCDT = 2;
9
+ /** Pcd is 8 bytes: a 2-byte bit field, a 4-byte FcCompressed, and a 2-byte Prm. */
10
+ const PCD_SIZE = 8;
11
+ /** FcCompressed's low 30 bits hold the offset; bit 30 is fCompressed and bit 31 a reserved bit the spec says MUST be zero and MUST be ignored. */
12
+ const FC_MASK = 1073741823;
13
+ const FC_COMPRESSED_BIT = 1073741824;
14
+ /** PrcData.cbGrpprl is a signed integer that "MUST be less than or equal to 0x3FA2". */
15
+ const MAX_CB_GRPPRL = 16290;
16
+ function parseClx(clx) {
17
+ let cursor = 0;
18
+ for (;;) {
19
+ const clxt = readUint8(clx, cursor);
20
+ if (clxt === CLXT_PCDT) break;
21
+ if (clxt !== CLXT_PRC) throw new DocFormatError(`Clx element at offset ${cursor} begins with clxt 0x${clxt.toString(16).padStart(2, "0")}, which is neither a Prc (0x01) nor the Pcdt (0x02)`);
22
+ const cbGrpprl = readInt16LE(clx, cursor + 1);
23
+ if (cbGrpprl < 0 || cbGrpprl > MAX_CB_GRPPRL) throw new DocFormatError(`Clx Prc at offset ${cursor} declares cbGrpprl ${cbGrpprl}, outside the 0..0x3FA2 range [MS-DOC] permits`);
24
+ cursor += 3 + cbGrpprl;
25
+ if (cursor > clx.length) throw new DocFormatError(`Clx Prc at offset ${cursor - 3 - cbGrpprl} declares a ${cbGrpprl}-byte GrpPrl that runs past the end of the ${clx.length}-byte Clx`);
26
+ }
27
+ const lcb = readUint32LE(clx, cursor + 1);
28
+ const plcPcd = slice(clx, cursor + 5, lcb, "Clx Pcdt PlcPcd");
29
+ const plc = parsePlc(plcPcd, PCD_SIZE, "PlcPcd");
30
+ const pieces = [];
31
+ for (let index = 0; index < plc.count; index += 1) {
32
+ const element = plc.element(index);
33
+ const bits = readUint16LE(element, 0);
34
+ const fcCompressed = readUint32LE(element, 2);
35
+ const cpStart = plc.keys[index];
36
+ const cpEnd = plc.keys[index + 1];
37
+ if (cpStart === void 0 || cpEnd === void 0) throw new DocFormatError(`PlcPcd element ${index} has no bracketing character positions, so its text range is undefined`);
38
+ pieces.push({
39
+ cpStart,
40
+ cpEnd,
41
+ fc: fcCompressed & FC_MASK,
42
+ compressed: (fcCompressed & FC_COMPRESSED_BIT) !== 0,
43
+ noParaLast: (bits & 1) !== 0,
44
+ prm: readUint16LE(element, 6)
45
+ });
46
+ }
47
+ const lastCp = plc.keys[plc.keys.length - 1];
48
+ if (lastCp === void 0) throw new DocFormatError("PlcPcd carries no character positions at all");
49
+ return {
50
+ pieces,
51
+ cpKeys: plc.keys,
52
+ lastCp
53
+ };
54
+ }
55
+ function characterOffset(piece, cp) {
56
+ if (!Number.isInteger(cp) || cp < piece.cpStart || cp >= piece.cpEnd) throw new DocFormatError(`character position ${cp} is outside the piece covering [${piece.cpStart}, ${piece.cpEnd})`);
57
+ const delta = cp - piece.cpStart;
58
+ return piece.compressed ? Math.floor(piece.fc / 2) + delta : piece.fc + 2 * delta;
59
+ }
60
+ /** The number of bytes one character occupies in this piece: one for a compressed (8-bit) piece, two for an uncompressed (16-bit) one. */
61
+ function characterSize(piece) {
62
+ return piece.compressed ? 1 : 2;
63
+ }
64
+ //#endregion
65
+ export { characterOffset, characterSize, parseClx };
@@ -0,0 +1,48 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/text/special.ts
3
+ /** "An entity in a document that is used to denote the end of a paragraph and has a Unicode character code of 13." */
4
+ const PARAGRAPH_MARK = 13;
5
+ /** "A character with a hexadecimal value of 0x07 that is used to indicate the end of a cell in a table." With sprmPFTtp applied it is instead an end-of-row mark. */
6
+ const CELL_MARK = 7;
7
+ /** The last character of every section but the last, per [MS-DOC] 2.4.4's worked example. */
8
+ const SECTION_MARK = 12;
9
+ /** "This Sprm MUST NOT be applied to any character other than a line break character (Unicode 0x000B)." */
10
+ const LINE_BREAK = 11;
11
+ /** "U+0013 - A field begin character. See Plcfld." */
12
+ const FIELD_BEGIN = 19;
13
+ /** "U+0014 - A field separator character." Everything between the begin and the separator is the field's instruction, not its displayed result. */
14
+ const FIELD_SEPARATOR = 20;
15
+ /** "U+0015 - A field end character." */
16
+ const FIELD_END = 21;
17
+ /** "U+0001 - A picture location that is used in conjunction with sprmCPicLocation." */
18
+ const INLINE_PICTURE = 1;
19
+ /** "U+0002 - An auto-numbered footnote reference. See plcffndRef." */
20
+ const FOOTNOTE_REFERENCE = 2;
21
+ /** "U+0005 - An annotation reference character. See PlcfandRef." */
22
+ const ANNOTATION_REFERENCE = 5;
23
+ /** "U+0008 - A drawn object. See plcfSpa." */
24
+ const DRAWN_OBJECT = 8;
25
+ /** "U+0028 - A symbol. See sprmCSymbol." Only special when sprmCFSpec is applied; an ordinary '(' otherwise, so it is never treated as structural here. */
26
+ const SYMBOL_ANCHOR = 40;
27
+ /** Ends a paragraph. [MS-DOC] 2.4.2: "The character at the end character position of a paragraph MUST be a paragraph mark, an end-of-section character, a cell mark, or a TTP mark." */
28
+ function endsParagraph(code) {
29
+ return code === 13 || code === 7 || code === 12;
30
+ }
31
+ function isAnchorOnly(code) {
32
+ return code === 1 || code === 2 || code === 5 || code === 8;
33
+ }
34
+ //#endregion
35
+ exports.ANNOTATION_REFERENCE = ANNOTATION_REFERENCE;
36
+ exports.CELL_MARK = CELL_MARK;
37
+ exports.DRAWN_OBJECT = DRAWN_OBJECT;
38
+ exports.FIELD_BEGIN = FIELD_BEGIN;
39
+ exports.FIELD_END = FIELD_END;
40
+ exports.FIELD_SEPARATOR = FIELD_SEPARATOR;
41
+ exports.FOOTNOTE_REFERENCE = FOOTNOTE_REFERENCE;
42
+ exports.INLINE_PICTURE = INLINE_PICTURE;
43
+ exports.LINE_BREAK = LINE_BREAK;
44
+ exports.PARAGRAPH_MARK = PARAGRAPH_MARK;
45
+ exports.SECTION_MARK = SECTION_MARK;
46
+ exports.SYMBOL_ANCHOR = SYMBOL_ANCHOR;
47
+ exports.endsParagraph = endsParagraph;
48
+ exports.isAnchorOnly = isAnchorOnly;
@@ -0,0 +1,30 @@
1
+ //#region src/text/special.d.ts
2
+ /** "An entity in a document that is used to denote the end of a paragraph and has a Unicode character code of 13." */
3
+ declare const PARAGRAPH_MARK = 13;
4
+ /** "A character with a hexadecimal value of 0x07 that is used to indicate the end of a cell in a table." With sprmPFTtp applied it is instead an end-of-row mark. */
5
+ declare const CELL_MARK = 7;
6
+ /** The last character of every section but the last, per [MS-DOC] 2.4.4's worked example. */
7
+ declare const SECTION_MARK = 12;
8
+ /** "This Sprm MUST NOT be applied to any character other than a line break character (Unicode 0x000B)." */
9
+ declare const LINE_BREAK = 11;
10
+ /** "U+0013 - A field begin character. See Plcfld." */
11
+ declare const FIELD_BEGIN = 19;
12
+ /** "U+0014 - A field separator character." Everything between the begin and the separator is the field's instruction, not its displayed result. */
13
+ declare const FIELD_SEPARATOR = 20;
14
+ /** "U+0015 - A field end character." */
15
+ declare const FIELD_END = 21;
16
+ /** "U+0001 - A picture location that is used in conjunction with sprmCPicLocation." */
17
+ declare const INLINE_PICTURE = 1;
18
+ /** "U+0002 - An auto-numbered footnote reference. See plcffndRef." */
19
+ declare const FOOTNOTE_REFERENCE = 2;
20
+ /** "U+0005 - An annotation reference character. See PlcfandRef." */
21
+ declare const ANNOTATION_REFERENCE = 5;
22
+ /** "U+0008 - A drawn object. See plcfSpa." */
23
+ declare const DRAWN_OBJECT = 8;
24
+ /** "U+0028 - A symbol. See sprmCSymbol." Only special when sprmCFSpec is applied; an ordinary '(' otherwise, so it is never treated as structural here. */
25
+ declare const SYMBOL_ANCHOR = 40;
26
+ /** Ends a paragraph. [MS-DOC] 2.4.2: "The character at the end character position of a paragraph MUST be a paragraph mark, an end-of-section character, a cell mark, or a TTP mark." */
27
+ declare function endsParagraph(code: number): boolean;
28
+ declare function isAnchorOnly(code: number): boolean;
29
+ //#endregion
30
+ export { ANNOTATION_REFERENCE, CELL_MARK, DRAWN_OBJECT, FIELD_BEGIN, FIELD_END, FIELD_SEPARATOR, FOOTNOTE_REFERENCE, INLINE_PICTURE, LINE_BREAK, PARAGRAPH_MARK, SECTION_MARK, SYMBOL_ANCHOR, endsParagraph, isAnchorOnly };
@@ -0,0 +1,30 @@
1
+ //#region src/text/special.d.ts
2
+ /** "An entity in a document that is used to denote the end of a paragraph and has a Unicode character code of 13." */
3
+ declare const PARAGRAPH_MARK = 13;
4
+ /** "A character with a hexadecimal value of 0x07 that is used to indicate the end of a cell in a table." With sprmPFTtp applied it is instead an end-of-row mark. */
5
+ declare const CELL_MARK = 7;
6
+ /** The last character of every section but the last, per [MS-DOC] 2.4.4's worked example. */
7
+ declare const SECTION_MARK = 12;
8
+ /** "This Sprm MUST NOT be applied to any character other than a line break character (Unicode 0x000B)." */
9
+ declare const LINE_BREAK = 11;
10
+ /** "U+0013 - A field begin character. See Plcfld." */
11
+ declare const FIELD_BEGIN = 19;
12
+ /** "U+0014 - A field separator character." Everything between the begin and the separator is the field's instruction, not its displayed result. */
13
+ declare const FIELD_SEPARATOR = 20;
14
+ /** "U+0015 - A field end character." */
15
+ declare const FIELD_END = 21;
16
+ /** "U+0001 - A picture location that is used in conjunction with sprmCPicLocation." */
17
+ declare const INLINE_PICTURE = 1;
18
+ /** "U+0002 - An auto-numbered footnote reference. See plcffndRef." */
19
+ declare const FOOTNOTE_REFERENCE = 2;
20
+ /** "U+0005 - An annotation reference character. See PlcfandRef." */
21
+ declare const ANNOTATION_REFERENCE = 5;
22
+ /** "U+0008 - A drawn object. See plcfSpa." */
23
+ declare const DRAWN_OBJECT = 8;
24
+ /** "U+0028 - A symbol. See sprmCSymbol." Only special when sprmCFSpec is applied; an ordinary '(' otherwise, so it is never treated as structural here. */
25
+ declare const SYMBOL_ANCHOR = 40;
26
+ /** Ends a paragraph. [MS-DOC] 2.4.2: "The character at the end character position of a paragraph MUST be a paragraph mark, an end-of-section character, a cell mark, or a TTP mark." */
27
+ declare function endsParagraph(code: number): boolean;
28
+ declare function isAnchorOnly(code: number): boolean;
29
+ //#endregion
30
+ export { ANNOTATION_REFERENCE, CELL_MARK, DRAWN_OBJECT, FIELD_BEGIN, FIELD_END, FIELD_SEPARATOR, FOOTNOTE_REFERENCE, INLINE_PICTURE, LINE_BREAK, PARAGRAPH_MARK, SECTION_MARK, SYMBOL_ANCHOR, endsParagraph, isAnchorOnly };
@@ -0,0 +1,34 @@
1
+ //#region src/text/special.ts
2
+ /** "An entity in a document that is used to denote the end of a paragraph and has a Unicode character code of 13." */
3
+ const PARAGRAPH_MARK = 13;
4
+ /** "A character with a hexadecimal value of 0x07 that is used to indicate the end of a cell in a table." With sprmPFTtp applied it is instead an end-of-row mark. */
5
+ const CELL_MARK = 7;
6
+ /** The last character of every section but the last, per [MS-DOC] 2.4.4's worked example. */
7
+ const SECTION_MARK = 12;
8
+ /** "This Sprm MUST NOT be applied to any character other than a line break character (Unicode 0x000B)." */
9
+ const LINE_BREAK = 11;
10
+ /** "U+0013 - A field begin character. See Plcfld." */
11
+ const FIELD_BEGIN = 19;
12
+ /** "U+0014 - A field separator character." Everything between the begin and the separator is the field's instruction, not its displayed result. */
13
+ const FIELD_SEPARATOR = 20;
14
+ /** "U+0015 - A field end character." */
15
+ const FIELD_END = 21;
16
+ /** "U+0001 - A picture location that is used in conjunction with sprmCPicLocation." */
17
+ const INLINE_PICTURE = 1;
18
+ /** "U+0002 - An auto-numbered footnote reference. See plcffndRef." */
19
+ const FOOTNOTE_REFERENCE = 2;
20
+ /** "U+0005 - An annotation reference character. See PlcfandRef." */
21
+ const ANNOTATION_REFERENCE = 5;
22
+ /** "U+0008 - A drawn object. See plcfSpa." */
23
+ const DRAWN_OBJECT = 8;
24
+ /** "U+0028 - A symbol. See sprmCSymbol." Only special when sprmCFSpec is applied; an ordinary '(' otherwise, so it is never treated as structural here. */
25
+ const SYMBOL_ANCHOR = 40;
26
+ /** Ends a paragraph. [MS-DOC] 2.4.2: "The character at the end character position of a paragraph MUST be a paragraph mark, an end-of-section character, a cell mark, or a TTP mark." */
27
+ function endsParagraph(code) {
28
+ return code === 13 || code === 7 || code === 12;
29
+ }
30
+ function isAnchorOnly(code) {
31
+ return code === 1 || code === 2 || code === 5 || code === 8;
32
+ }
33
+ //#endregion
34
+ export { ANNOTATION_REFERENCE, CELL_MARK, DRAWN_OBJECT, FIELD_BEGIN, FIELD_END, FIELD_SEPARATOR, FOOTNOTE_REFERENCE, INLINE_PICTURE, LINE_BREAK, PARAGRAPH_MARK, SECTION_MARK, SYMBOL_ANCHOR, endsParagraph, isAnchorOnly };
package/package.json CHANGED
@@ -1,5 +1,96 @@
1
1
  {
2
2
  "name": "doc-codec",
3
- "version": "0.0.0",
4
- "private": false
3
+ "version": "1.0.1",
4
+ "description": "A hand-written reader for the Word Binary File Format ([MS-DOC], .doc) against the shared document-schema.js content pivot: FIB parsing, piece-table text reconstruction, and CHPX/PAPX formatting exceptions.",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/ExaDev/documents.js.git",
9
+ "directory": "packages/doc-codec"
10
+ },
11
+ "homepage": "https://github.com/ExaDev/documents.js/tree/main/packages/doc-codec",
12
+ "bugs": {
13
+ "url": "https://github.com/ExaDev/documents.js/issues"
14
+ },
15
+ "exports": {
16
+ ".": {
17
+ "types": {
18
+ "import": "./dist/index.d.ts",
19
+ "require": "./dist/index.d.cts"
20
+ },
21
+ "import": "./dist/index.js",
22
+ "require": "./dist/index.cjs"
23
+ },
24
+ "./*": {
25
+ "types": {
26
+ "import": "./dist/*.d.ts",
27
+ "require": "./dist/*.d.cts"
28
+ },
29
+ "import": "./dist/*.js",
30
+ "require": "./dist/*.cjs"
31
+ }
32
+ },
33
+ "main": "./dist/index.cjs",
34
+ "module": "./dist/index.js",
35
+ "types": "./dist/index.d.ts",
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "publishConfig": {
40
+ "access": "public",
41
+ "provenance": true,
42
+ "registry": "https://registry.npmjs.org/"
43
+ },
44
+ "sideEffects": false,
45
+ "engines": {
46
+ "node": ">=20"
47
+ },
48
+ "scripts": {
49
+ "build": "turbo run _build",
50
+ "_build": "tsdown",
51
+ "prepublishOnly": "pnpm run lint && pnpm run typecheck && tsdown && publint && attw --pack",
52
+ "lint": "turbo run _lint",
53
+ "_lint": "eslint . --fix --cache --max-warnings 0",
54
+ "lint:check": "eslint . --max-warnings 0",
55
+ "typecheck": "turbo run _typecheck _typecheck:attw",
56
+ "_typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.node.json",
57
+ "_typecheck:attw": "attw --pack",
58
+ "test": "turbo run _test",
59
+ "_test": "vitest run --project unit",
60
+ "test:watch": "vitest --project unit",
61
+ "test:workers": "turbo run _test:workers",
62
+ "_test:workers": "vitest run --config vitest.workers.config.ts",
63
+ "test:smoke": "turbo run _test:smoke",
64
+ "_test:smoke": "vitest run --project smoke",
65
+ "prepare": "husky"
66
+ },
67
+ "keywords": [
68
+ "doc",
69
+ "word",
70
+ "ms-doc",
71
+ "binary",
72
+ "codec",
73
+ "ms-cfb"
74
+ ],
75
+ "license": "MIT",
76
+ "packageManager": "pnpm@11.6.0",
77
+ "dependencies": {
78
+ "archive-codec": "^1.3.0",
79
+ "document-schema.js": "^5.4.0"
80
+ },
81
+ "devDependencies": {
82
+ "@arethetypeswrong/cli": "^0.18.5",
83
+ "@cloudflare/vitest-pool-workers": "^0.20.1",
84
+ "@types/node": "^26.1.2",
85
+ "eslint": "^10.8.0",
86
+ "husky": "^9.1.7",
87
+ "publint": "^0.3.21",
88
+ "tsdown": "^0.22.13",
89
+ "turbo": "^2.10.8",
90
+ "typescript": "^6.0.3",
91
+ "vitest": "^4.1.10"
92
+ },
93
+ "lint-staged": {
94
+ "*.ts": "eslint --fix"
95
+ }
5
96
  }