doc-codec 2.4.3 → 2.6.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.
Files changed (90) hide show
  1. package/README.md +53 -20
  2. package/dist/chp-B6AOh85P.d.ts +18 -0
  3. package/dist/chp-BpCqpb7V.d.cts +18 -0
  4. package/dist/detect.cjs +3 -0
  5. package/dist/detect.d.cts +3 -1
  6. package/dist/detect.d.ts +3 -1
  7. package/dist/detect.js +3 -1
  8. package/dist/encryption.cjs +44 -10
  9. package/dist/encryption.d.cts +2 -2
  10. package/dist/encryption.d.ts +2 -2
  11. package/dist/encryption.js +45 -11
  12. package/dist/fib/fib.cjs +14 -0
  13. package/dist/fib/fib.d.cts +1 -1
  14. package/dist/fib/fib.d.ts +1 -1
  15. package/dist/fib/fib.js +14 -0
  16. package/dist/fib/offsets.cjs +14 -0
  17. package/dist/fib/offsets.d.cts +14 -0
  18. package/dist/fib/offsets.d.ts +14 -0
  19. package/dist/fib/offsets.js +14 -0
  20. package/dist/{fib-DWFta19r.d.cts → fib-6BFIx153.d.cts} +14 -0
  21. package/dist/{fib-DWFta19r.d.ts → fib-6BFIx153.d.ts} +14 -0
  22. package/dist/fkp-I-laf-8y.d.cts +33 -0
  23. package/dist/fkp-I-laf-8y.d.ts +33 -0
  24. package/dist/headers-footers.cjs +34 -0
  25. package/dist/headers-footers.d.cts +16 -0
  26. package/dist/headers-footers.d.ts +16 -0
  27. package/dist/headers-footers.js +33 -0
  28. package/dist/index.cjs +20 -9
  29. package/dist/index.d.cts +16 -12
  30. package/dist/index.d.ts +16 -12
  31. package/dist/index.js +15 -11
  32. package/dist/list/numbering-write.d.cts +1 -1
  33. package/dist/list/numbering-write.d.ts +1 -1
  34. package/dist/list/numbering.d.cts +23 -1
  35. package/dist/list/numbering.d.ts +23 -1
  36. package/dist/notes.cjs +26 -0
  37. package/dist/notes.d.cts +20 -0
  38. package/dist/notes.d.ts +20 -0
  39. package/dist/notes.js +25 -0
  40. package/dist/{pap-BT1p0uzu.d.cts → pap-BQ2E17K9.d.cts} +5 -3
  41. package/dist/{pap-DOFLMWcG.d.ts → pap-iWFIpCdo.d.ts} +5 -3
  42. package/dist/paragraphs-DQUp8_HB.d.cts +31 -0
  43. package/dist/paragraphs-s2lJ6w2I.d.ts +31 -0
  44. package/dist/pictures.cjs +93 -0
  45. package/dist/pictures.d.cts +6 -0
  46. package/dist/pictures.d.ts +6 -0
  47. package/dist/pictures.js +92 -0
  48. package/dist/piece-table-CA18mhjv.d.cts +28 -0
  49. package/dist/piece-table-CA18mhjv.d.ts +28 -0
  50. package/dist/prop/chp.d.cts +1 -17
  51. package/dist/prop/chp.d.ts +1 -17
  52. package/dist/prop/fkp.d.cts +1 -32
  53. package/dist/prop/fkp.d.ts +1 -32
  54. package/dist/prop/pap.cjs +4 -2
  55. package/dist/prop/pap.d.cts +1 -1
  56. package/dist/prop/pap.d.ts +1 -1
  57. package/dist/prop/pap.js +4 -2
  58. package/dist/prop/sep.cjs +20 -10
  59. package/dist/prop/sep.d.cts +8 -4
  60. package/dist/prop/sep.d.ts +8 -4
  61. package/dist/prop/sep.js +20 -10
  62. package/dist/read.cjs +48 -153
  63. package/dist/read.d.cts +13 -15
  64. package/dist/read.d.ts +13 -15
  65. package/dist/read.js +51 -156
  66. package/dist/stsh-Bj0YSEOp.d.ts +40 -0
  67. package/dist/stsh-CK59x6XG.d.cts +40 -0
  68. package/dist/style/stsh.d.cts +1 -39
  69. package/dist/style/stsh.d.ts +1 -39
  70. package/dist/subdocument.cjs +20 -0
  71. package/dist/subdocument.d.cts +8 -0
  72. package/dist/subdocument.d.ts +8 -0
  73. package/dist/subdocument.js +18 -0
  74. package/dist/table/read.cjs +31 -17
  75. package/dist/table/read.d.cts +1 -1
  76. package/dist/table/read.d.ts +1 -1
  77. package/dist/table/read.js +32 -18
  78. package/dist/text/characters.d.cts +1 -1
  79. package/dist/text/characters.d.ts +1 -1
  80. package/dist/text/paragraphs.cjs +189 -0
  81. package/dist/text/paragraphs.d.cts +2 -0
  82. package/dist/text/paragraphs.d.ts +2 -0
  83. package/dist/text/paragraphs.js +187 -0
  84. package/dist/text/piece-table.d.cts +1 -27
  85. package/dist/text/piece-table.d.ts +1 -27
  86. package/dist/write.cjs +3 -3
  87. package/dist/write.js +3 -3
  88. package/package.json +2 -2
  89. package/dist/numbering-DSpm9w6y.d.cts +0 -24
  90. package/dist/numbering-DayjnHXY.d.ts +0 -24
package/dist/prop/pap.js CHANGED
@@ -35,7 +35,7 @@ const SPRM_P_ILVL = 9738;
35
35
  const SPRM_P_ILFO = 17931;
36
36
  /** sprmPItap: the paragraph's own table depth -- read only far enough to detect a depth greater than 1 (a table nested inside a table cell), which this package refuses rather than mis-reads. */
37
37
  const SPRM_P_ITAP = 26185;
38
- /** sprmPFInnerTableCell / sprmPFInnerTtp: a nested table's own cell-ending or row-ending mark. Neither is acted on beyond refusing the nested table it signals. */
38
+ /** sprmPFInnerTableCell / sprmPFInnerTtp: a nested table's (table depth greater than 1) own cell-ending or row-ending mark, [MS-DOC] 2.4.3's Overview of Tables -- the paragraph-mark (0x000D) analogues of sprmPFInTable's cell-mark (0x0007) boundary and sprmPFTtp's row-mark at depth 1. */
39
39
  const SPRM_P_F_INNER_TABLE_CELL = 9291;
40
40
  const SPRM_P_F_INNER_TTP = 9292;
41
41
  const TWIPS_PER_POINT = 20;
@@ -134,7 +134,9 @@ function applyParagraphSprms(prls, into) {
134
134
  into.tableDepth = readUint32LE(prl.operand, 0);
135
135
  break;
136
136
  case SPRM_P_F_INNER_TABLE_CELL:
137
- case SPRM_P_F_INNER_TTP: if (readUint8(prl.operand, 0) !== 0) into.nestedTableMark = true;
137
+ into.innerTableCellMark = readUint8(prl.operand, 0) !== 0;
138
+ break;
139
+ case SPRM_P_F_INNER_TTP: into.innerTtpMark = readUint8(prl.operand, 0) !== 0;
138
140
  }
139
141
  }
140
142
  return into;
package/dist/prop/sep.cjs CHANGED
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_errors = require("../errors.cjs");
2
3
  const require_bytes = require("../bytes.cjs");
3
4
  const require_plc = require("../plc.cjs");
4
5
  const require_prop_sprm = require("./sprm.cjs");
@@ -47,17 +48,26 @@ function applySectionSprms(prls, into) {
47
48
  }
48
49
  return into;
49
50
  }
50
- /** Resolves the document's first section's own page size and margins from PlcfSed/Sepx -- absent entirely when the file carries no PlcfSed at all (lcbPlcfSed 0), which read.ts's own DEFAULT_PAGE_SIZE/DEFAULT_MARGINS then stand in for field by field, exactly as an individual unstated sprm already does. This reader only ever resolves the section covering the whole main document (see read.ts's own DocContent comment on why more than one section is out of scope), so it reads PlcfSed's first Sed regardless of how many the file actually carries. */
51
- function readSectionProperties(wordDocument, table, fib) {
52
- if (fib.lcbPlcfSed === 0) return {};
51
+ /** Resolves every section PlcfSed/Sepx states, in document order -- a single zero-start entry with no properties when the file carries no PlcfSed at all (lcbPlcfSed 0) or an empty one, which read.ts's own DEFAULT_PAGE_SIZE/DEFAULT_MARGINS then stand in for field by field, exactly as an individual unstated sprm already does, matching what a single-section document with no PlcfSed at all would resolve to anyway. */
52
+ function readAllSectionProperties(wordDocument, table, fib) {
53
+ if (fib.lcbPlcfSed === 0) return [{ startCp: 0 }];
53
54
  const plc = require_plc.parsePlc(require_bytes.slice(table, fib.fcPlcfSed, fib.lcbPlcfSed, "PlcfSed in the Table stream"), SED_SIZE, "PlcfSed");
54
- if (plc.count === 0) return {};
55
- const sed = plc.element(0);
56
- const fcSepx = require_bytes.readUint32LE(sed, SED_FC_SEPX_OFFSET);
57
- const cb = require_bytes.readUint16LE(wordDocument, fcSepx);
58
- const grpprl = require_bytes.slice(wordDocument, fcSepx + 2, cb, "Sepx grpprl in the WordDocument stream");
59
- return applySectionSprms(require_prop_sprm.readGrpprl(grpprl), {});
55
+ if (plc.count === 0) return [{ startCp: 0 }];
56
+ const sections = [];
57
+ for (let index = 0; index < plc.count; index += 1) {
58
+ const startCp = plc.keys[index];
59
+ if (startCp === void 0) throw new require_errors.DocFormatError(`internal defect: PlcfSed key ${index} is absent from a PLC of ${plc.count} elements`);
60
+ const sed = plc.element(index);
61
+ const fcSepx = require_bytes.readUint32LE(sed, SED_FC_SEPX_OFFSET);
62
+ const cb = require_bytes.readUint16LE(wordDocument, fcSepx);
63
+ const grpprl = require_bytes.slice(wordDocument, fcSepx + 2, cb, "Sepx grpprl in the WordDocument stream");
64
+ sections.push({
65
+ startCp,
66
+ ...applySectionSprms(require_prop_sprm.readGrpprl(grpprl), {})
67
+ });
68
+ }
69
+ return sections;
60
70
  }
61
71
  //#endregion
62
72
  exports.applySectionSprms = applySectionSprms;
63
- exports.readSectionProperties = readSectionProperties;
73
+ exports.readAllSectionProperties = readAllSectionProperties;
@@ -1,4 +1,4 @@
1
- import { t as Fib } from "../fib-DWFta19r.cjs";
1
+ import { t as Fib } from "../fib-6BFIx153.cjs";
2
2
  import { t as Prl } from "../sprm-DEyvdOo0.cjs";
3
3
  //#region src/prop/sep.d.ts
4
4
  interface SectionProperties {
@@ -10,7 +10,11 @@ interface SectionProperties {
10
10
  marginBottomPt?: number;
11
11
  }
12
12
  declare function applySectionSprms(prls: readonly Prl[], into: SectionProperties): SectionProperties;
13
- /** Resolves the document's first section's own page size and margins from PlcfSed/Sepx -- absent entirely when the file carries no PlcfSed at all (lcbPlcfSed 0), which read.ts's own DEFAULT_PAGE_SIZE/DEFAULT_MARGINS then stand in for field by field, exactly as an individual unstated sprm already does. This reader only ever resolves the section covering the whole main document (see read.ts's own DocContent comment on why more than one section is out of scope), so it reads PlcfSed's first Sed regardless of how many the file actually carries. */
14
- declare function readSectionProperties(wordDocument: Uint8Array, table: Uint8Array, fib: Pick<Fib, "fcPlcfSed" | "lcbPlcfSed">): SectionProperties;
13
+ /** One section's own resolved properties (page size, margins) alongside `startCp`, the character position PlcfSed.aCp[i] names as where its text begins in the main document -- [MS-DOC] 2.8.26: "Each CP specifies the beginning of a range of text in the main document that constitutes a section." read.ts's own splitIntoSections groups the main document's paragraph entries by these boundaries. */
14
+ interface DocSectionProperties extends SectionProperties {
15
+ readonly startCp: number;
16
+ }
17
+ /** Resolves every section PlcfSed/Sepx states, in document order -- a single zero-start entry with no properties when the file carries no PlcfSed at all (lcbPlcfSed 0) or an empty one, which read.ts's own DEFAULT_PAGE_SIZE/DEFAULT_MARGINS then stand in for field by field, exactly as an individual unstated sprm already does, matching what a single-section document with no PlcfSed at all would resolve to anyway. */
18
+ declare function readAllSectionProperties(wordDocument: Uint8Array, table: Uint8Array, fib: Pick<Fib, "fcPlcfSed" | "lcbPlcfSed">): readonly DocSectionProperties[];
15
19
  //#endregion
16
- export { SectionProperties, applySectionSprms, readSectionProperties };
20
+ export { DocSectionProperties, SectionProperties, applySectionSprms, readAllSectionProperties };
@@ -1,4 +1,4 @@
1
- import { t as Fib } from "../fib-DWFta19r.js";
1
+ import { t as Fib } from "../fib-6BFIx153.js";
2
2
  import { t as Prl } from "../sprm-DEyvdOo0.js";
3
3
  //#region src/prop/sep.d.ts
4
4
  interface SectionProperties {
@@ -10,7 +10,11 @@ interface SectionProperties {
10
10
  marginBottomPt?: number;
11
11
  }
12
12
  declare function applySectionSprms(prls: readonly Prl[], into: SectionProperties): SectionProperties;
13
- /** Resolves the document's first section's own page size and margins from PlcfSed/Sepx -- absent entirely when the file carries no PlcfSed at all (lcbPlcfSed 0), which read.ts's own DEFAULT_PAGE_SIZE/DEFAULT_MARGINS then stand in for field by field, exactly as an individual unstated sprm already does. This reader only ever resolves the section covering the whole main document (see read.ts's own DocContent comment on why more than one section is out of scope), so it reads PlcfSed's first Sed regardless of how many the file actually carries. */
14
- declare function readSectionProperties(wordDocument: Uint8Array, table: Uint8Array, fib: Pick<Fib, "fcPlcfSed" | "lcbPlcfSed">): SectionProperties;
13
+ /** One section's own resolved properties (page size, margins) alongside `startCp`, the character position PlcfSed.aCp[i] names as where its text begins in the main document -- [MS-DOC] 2.8.26: "Each CP specifies the beginning of a range of text in the main document that constitutes a section." read.ts's own splitIntoSections groups the main document's paragraph entries by these boundaries. */
14
+ interface DocSectionProperties extends SectionProperties {
15
+ readonly startCp: number;
16
+ }
17
+ /** Resolves every section PlcfSed/Sepx states, in document order -- a single zero-start entry with no properties when the file carries no PlcfSed at all (lcbPlcfSed 0) or an empty one, which read.ts's own DEFAULT_PAGE_SIZE/DEFAULT_MARGINS then stand in for field by field, exactly as an individual unstated sprm already does, matching what a single-section document with no PlcfSed at all would resolve to anyway. */
18
+ declare function readAllSectionProperties(wordDocument: Uint8Array, table: Uint8Array, fib: Pick<Fib, "fcPlcfSed" | "lcbPlcfSed">): readonly DocSectionProperties[];
15
19
  //#endregion
16
- export { SectionProperties, applySectionSprms, readSectionProperties };
20
+ export { DocSectionProperties, SectionProperties, applySectionSprms, readAllSectionProperties };
package/dist/prop/sep.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { DocFormatError } from "../errors.js";
1
2
  import { readInt16LE, readUint16LE, readUint32LE, slice } from "../bytes.js";
2
3
  import { parsePlc } from "../plc.js";
3
4
  import { SGC, readGrpprl } from "./sprm.js";
@@ -46,16 +47,25 @@ function applySectionSprms(prls, into) {
46
47
  }
47
48
  return into;
48
49
  }
49
- /** Resolves the document's first section's own page size and margins from PlcfSed/Sepx -- absent entirely when the file carries no PlcfSed at all (lcbPlcfSed 0), which read.ts's own DEFAULT_PAGE_SIZE/DEFAULT_MARGINS then stand in for field by field, exactly as an individual unstated sprm already does. This reader only ever resolves the section covering the whole main document (see read.ts's own DocContent comment on why more than one section is out of scope), so it reads PlcfSed's first Sed regardless of how many the file actually carries. */
50
- function readSectionProperties(wordDocument, table, fib) {
51
- if (fib.lcbPlcfSed === 0) return {};
50
+ /** Resolves every section PlcfSed/Sepx states, in document order -- a single zero-start entry with no properties when the file carries no PlcfSed at all (lcbPlcfSed 0) or an empty one, which read.ts's own DEFAULT_PAGE_SIZE/DEFAULT_MARGINS then stand in for field by field, exactly as an individual unstated sprm already does, matching what a single-section document with no PlcfSed at all would resolve to anyway. */
51
+ function readAllSectionProperties(wordDocument, table, fib) {
52
+ if (fib.lcbPlcfSed === 0) return [{ startCp: 0 }];
52
53
  const plc = parsePlc(slice(table, fib.fcPlcfSed, fib.lcbPlcfSed, "PlcfSed in the Table stream"), SED_SIZE, "PlcfSed");
53
- if (plc.count === 0) return {};
54
- const sed = plc.element(0);
55
- const fcSepx = readUint32LE(sed, SED_FC_SEPX_OFFSET);
56
- const cb = readUint16LE(wordDocument, fcSepx);
57
- const grpprl = slice(wordDocument, fcSepx + 2, cb, "Sepx grpprl in the WordDocument stream");
58
- return applySectionSprms(readGrpprl(grpprl), {});
54
+ if (plc.count === 0) return [{ startCp: 0 }];
55
+ const sections = [];
56
+ for (let index = 0; index < plc.count; index += 1) {
57
+ const startCp = plc.keys[index];
58
+ if (startCp === void 0) throw new DocFormatError(`internal defect: PlcfSed key ${index} is absent from a PLC of ${plc.count} elements`);
59
+ const sed = plc.element(index);
60
+ const fcSepx = readUint32LE(sed, SED_FC_SEPX_OFFSET);
61
+ const cb = readUint16LE(wordDocument, fcSepx);
62
+ const grpprl = slice(wordDocument, fcSepx + 2, cb, "Sepx grpprl in the WordDocument stream");
63
+ sections.push({
64
+ startCp,
65
+ ...applySectionSprms(readGrpprl(grpprl), {})
66
+ });
67
+ }
68
+ return sections;
59
69
  }
60
70
  //#endregion
61
- export { applySectionSprms, readSectionProperties };
71
+ export { applySectionSprms, readAllSectionProperties };
package/dist/read.cjs CHANGED
@@ -3,22 +3,21 @@ const require_errors = require("./errors.cjs");
3
3
  const require_bytes = require("./bytes.cjs");
4
4
  const require_detect = require("./detect.cjs");
5
5
  const require_encryption = require("./encryption.cjs");
6
- const require_fib_fib = require("./fib/fib.cjs");
6
+ const require_prop_fkp = require("./prop/fkp.cjs");
7
+ const require_style_stsh = require("./style/stsh.cjs");
8
+ const require_text_paragraphs = require("./text/paragraphs.cjs");
7
9
  const require_text_piece_table = require("./text/piece-table.cjs");
8
10
  const require_text_characters = require("./text/characters.cjs");
9
- const require_text_special = require("./text/special.cjs");
10
- const require_prop_sprm = require("./prop/sprm.cjs");
11
- const require_prop_fkp = require("./prop/fkp.cjs");
12
- const require_prop_chp = require("./prop/chp.cjs");
13
- const require_prop_pap = require("./prop/pap.cjs");
11
+ const require_table_read = require("./table/read.cjs");
12
+ const require_headers_footers = require("./headers-footers.cjs");
13
+ const require_fib_fib = require("./fib/fib.cjs");
14
14
  const require_prop_sep = require("./prop/sep.cjs");
15
- const require_style_stsh = require("./style/stsh.cjs");
16
15
  const require_style_fonts = require("./style/fonts.cjs");
17
16
  const require_list_numbering = require("./list/numbering.cjs");
18
- const require_table_read = require("./table/read.cjs");
17
+ const require_notes = require("./notes.cjs");
19
18
  let archive_codec = require("archive-codec");
20
19
  //#region src/read.ts
21
- /** Word's own default for a new document (US Letter, one-inch margins) -- what a field this reader resolves from PlcfSed/Sepx (prop/sep.ts's readSectionProperties) falls back to when the file states nothing for it, exactly as it would fall back to Word's own implementation-dependent default for that one unstated sprm. */
20
+ /** Word's own default for a new document (US Letter, one-inch margins) -- what a field this reader resolves from PlcfSed/Sepx (prop/sep.ts's readAllSectionProperties) falls back to when the file states nothing for it, exactly as it would fall back to Word's own implementation-dependent default for that one unstated sprm. */
22
21
  const DEFAULT_PAGE_SIZE = {
23
22
  widthPt: 612,
24
23
  heightPt: 792
@@ -40,177 +39,73 @@ function readDocStreams(bytes, password) {
40
39
  let wordDocument = wordDocumentStream.bytes;
41
40
  let table = tableStream.bytes;
42
41
  if (flags.fEncrypted) {
43
- if (flags.fObfuscated) throw new require_errors.DocUnsupportedError("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");
44
- const decrypted = require_encryption.decryptDocStreams(wordDocument, table, password);
42
+ const decrypted = require_encryption.decryptDocStreams(wordDocument, table, password, flags.fObfuscated);
45
43
  wordDocument = decrypted.wordDocument;
46
44
  table = decrypted.table;
47
45
  }
48
46
  const fib = require_fib_fib.parseFib(wordDocument);
49
47
  const metadata = streams.find((stream) => stream.path === require_detect.SUMMARY_INFORMATION_STREAM);
48
+ const data = streams.find((stream) => stream.path === require_detect.DATA_STREAM);
50
49
  return {
51
50
  wordDocument,
52
51
  table,
53
52
  fib,
54
- metadata: metadata?.bytes
53
+ metadata: metadata?.bytes,
54
+ data: data?.bytes
55
55
  };
56
56
  }
57
57
  function readDocContent(bytes, password) {
58
- const { wordDocument, table, fib, metadata } = readDocStreams(bytes, password);
58
+ const { wordDocument, table, fib, metadata, data } = readDocStreams(bytes, password);
59
59
  const pieceTable = require_text_piece_table.parseClx(require_bytes.slice(table, fib.fcClx, fib.lcbClx, "Clx in the Table stream"));
60
60
  const styles = fib.lcbStshf > 0 ? require_style_stsh.parseStsh(require_bytes.slice(table, fib.fcStshf, fib.lcbStshf, "STSH in the Table stream")) : void 0;
61
- const chpxTable = new require_prop_fkp.PropertyBinTable(wordDocument, require_bytes.slice(table, fib.fcPlcfBteChpx, fib.lcbPlcfBteChpx, "PlcBteChpx in the Table stream"), "PlcBteChpx");
62
- const papxTable = new require_prop_fkp.PropertyBinTable(wordDocument, require_bytes.slice(table, fib.fcPlcfBtePapx, fib.lcbPlcfBtePapx, "PlcBtePapx in the Table stream"), "PlcBtePapx");
63
- const fonts = fib.lcbSttbfFfn > 0 ? require_style_fonts.parseFontTable(require_bytes.slice(table, fib.fcSttbfFfn, fib.lcbSttbfFfn, "SttbfFfn in the Table stream")) : void 0;
64
- const range = require_text_characters.readTextRange(wordDocument, pieceTable, 0, fib.ccpText);
65
- const entries = readParagraphs(range.text, range.fcs, {
66
- chpxTable,
67
- papxTable,
61
+ const context = {
62
+ chpxTable: new require_prop_fkp.PropertyBinTable(wordDocument, require_bytes.slice(table, fib.fcPlcfBteChpx, fib.lcbPlcfBteChpx, "PlcBteChpx in the Table stream"), "PlcBteChpx"),
63
+ papxTable: new require_prop_fkp.PropertyBinTable(wordDocument, require_bytes.slice(table, fib.fcPlcfBtePapx, fib.lcbPlcfBtePapx, "PlcBtePapx in the Table stream"), "PlcBtePapx"),
68
64
  styles,
69
- fonts,
65
+ dataStream: data,
66
+ fonts: fib.lcbSttbfFfn > 0 ? require_style_fonts.parseFontTable(require_bytes.slice(table, fib.fcSttbfFfn, fib.lcbSttbfFfn, "SttbfFfn in the Table stream")) : void 0,
70
67
  characterProperties: /* @__PURE__ */ new Map()
71
- });
72
- const blocks = require_table_read.assembleBlocks(entries);
68
+ };
69
+ const range = require_text_characters.readTextRange(wordDocument, pieceTable, 0, fib.ccpText);
70
+ const entries = require_text_paragraphs.readParagraphs(range.text, range.fcs, context);
73
71
  const numbering = require_list_numbering.readNumberingDefinitions(table, fib);
74
- const sectionProperties = require_prop_sep.readSectionProperties(wordDocument, table, fib);
72
+ const sectionProperties = require_prop_sep.readAllSectionProperties(wordDocument, table, fib);
73
+ const entriesBySection = splitIntoSections(entries, sectionProperties);
74
+ const { footnotes, endnotes, comments } = require_notes.readNoteBodies(wordDocument, table, pieceTable, context, fib);
75
+ const headerFooterStories = require_headers_footers.readHeaderFooterStories(wordDocument, table, pieceTable, context, fib, sectionProperties.length);
75
76
  return {
76
77
  kind: "wordprocessing",
77
78
  metadata: metadata === void 0 ? {} : (0, archive_codec.summaryInformationToLayoutMetadata)((0, archive_codec.readSummaryInformation)(metadata)),
78
- sections: [{
79
+ sections: sectionProperties.map((properties, index) => ({
79
80
  pageSize: {
80
- widthPt: sectionProperties.pageWidthPt ?? DEFAULT_PAGE_SIZE.widthPt,
81
- heightPt: sectionProperties.pageHeightPt ?? DEFAULT_PAGE_SIZE.heightPt
81
+ widthPt: properties.pageWidthPt ?? DEFAULT_PAGE_SIZE.widthPt,
82
+ heightPt: properties.pageHeightPt ?? DEFAULT_PAGE_SIZE.heightPt
82
83
  },
83
84
  margins: {
84
- leftPt: sectionProperties.marginLeftPt ?? DEFAULT_MARGINS.leftPt,
85
- rightPt: sectionProperties.marginRightPt ?? DEFAULT_MARGINS.rightPt,
86
- topPt: sectionProperties.marginTopPt ?? DEFAULT_MARGINS.topPt,
87
- bottomPt: sectionProperties.marginBottomPt ?? DEFAULT_MARGINS.bottomPt
85
+ leftPt: properties.marginLeftPt ?? DEFAULT_MARGINS.leftPt,
86
+ rightPt: properties.marginRightPt ?? DEFAULT_MARGINS.rightPt,
87
+ topPt: properties.marginTopPt ?? DEFAULT_MARGINS.topPt,
88
+ bottomPt: properties.marginBottomPt ?? DEFAULT_MARGINS.bottomPt
88
89
  },
89
- blocks
90
- }],
91
- numbering
90
+ blocks: require_table_read.assembleBlocks(entriesBySection[index] ?? [])
91
+ })),
92
+ numbering,
93
+ footnotes,
94
+ endnotes,
95
+ comments,
96
+ headerFooterStories
92
97
  };
93
98
  }
94
- function readParagraphs(text, fcs, context) {
95
- const entries = [];
96
- let start = 0;
97
- for (let index = 0; index < text.length; index += 1) {
98
- const code = text.charCodeAt(index);
99
- if (!require_text_special.endsParagraph(code)) continue;
100
- const markFc = fcs[index];
101
- if (markFc === void 0) throw new require_errors.DocFormatError(`character ${index} has no byte offset, so its paragraph's properties cannot be located`);
102
- entries.push(buildParagraph(text.slice(start, index), fcs.slice(start, index), markFc, code, context));
103
- start = index + 1;
104
- }
105
- if (start < text.length) {
106
- const firstFc = fcs[start];
107
- if (firstFc === void 0) throw new require_errors.DocFormatError(`character ${start} has no byte offset, so the trailing paragraph's properties cannot be located`);
108
- entries.push(buildParagraph(text.slice(start), fcs.slice(start), firstFc, 13, context));
109
- }
110
- return entries;
111
- }
112
- function buildParagraph(text, fcs, propertyFc, terminator, context) {
113
- const papx = context.papxTable.papx(propertyFc);
114
- const properties = {};
115
- const grpprl = papx !== void 0 ? require_prop_sprm.readGrpprl(papx.grpprl) : [];
116
- if (papx !== void 0) {
117
- properties.istd = papx.istd;
118
- if (context.styles !== void 0) require_prop_pap.applyParagraphSprms(require_style_stsh.resolveStyleFormatting(context.styles, papx.istd).paragraphPrls, properties);
119
- require_prop_pap.applyParagraphSprms(grpprl, properties);
120
- }
121
- return {
122
- paragraph: {
123
- kind: "paragraph",
124
- runs: buildRuns(text, fcs, context, papx?.istd),
125
- ...paragraphAttributes(properties, context)
126
- },
127
- properties,
128
- grpprl,
129
- terminator
130
- };
131
- }
132
- function paragraphAttributes(properties, context) {
133
- const attributes = {};
134
- const istd = properties.istd;
135
- if (istd !== void 0) {
136
- const style = context.styles?.styles[istd];
137
- if (style !== void 0 && style.name !== "") attributes.styleId = style.name;
138
- const headingLevel = require_style_stsh.headingLevelFromIstd(istd);
139
- if (headingLevel !== void 0) attributes.headingLevel = headingLevel;
140
- }
141
- if (attributes.headingLevel === void 0 && properties.outlineLevel !== void 0) attributes.headingLevel = properties.outlineLevel + 1;
142
- if (properties.alignment !== void 0) attributes.alignment = properties.alignment;
143
- if (properties.spacingBeforePt !== void 0) attributes.spacingBeforePt = properties.spacingBeforePt;
144
- if (properties.spacingAfterPt !== void 0) attributes.spacingAfterPt = properties.spacingAfterPt;
145
- if (properties.lineSpacing !== void 0) attributes.lineSpacing = properties.lineSpacing;
146
- if (properties.indentLeftPt !== void 0) attributes.indentLeftPt = properties.indentLeftPt;
147
- if (properties.indentRightPt !== void 0) attributes.indentRightPt = properties.indentRightPt;
148
- if (properties.indentFirstLinePt !== void 0) attributes.indentFirstLinePt = properties.indentFirstLinePt;
149
- if (properties.pageBreakBefore === true) attributes.pageBreakBefore = true;
150
- if (properties.listId !== void 0) attributes.list = {
151
- numId: String(properties.listId),
152
- level: properties.listLevel ?? 0
153
- };
154
- return attributes;
155
- }
156
- function buildRuns(text, fcs, context, paragraphIstd) {
157
- const runs = [];
158
- let currentKey;
159
- let currentText = "";
160
- let currentProperties = {};
161
- const paragraphStyleCharacterPrls = context.styles !== void 0 && paragraphIstd !== void 0 ? require_style_stsh.resolveStyleFormatting(context.styles, paragraphIstd).characterPrls : [];
162
- const enclosingInstruction = [];
163
- let inInstruction = false;
164
- const flush = () => {
165
- if (currentText !== "") runs.push({
166
- text: currentText,
167
- ...currentProperties
168
- });
169
- currentText = "";
170
- };
171
- for (let index = 0; index < text.length; index += 1) {
172
- const code = text.charCodeAt(index);
173
- if (code === 19) {
174
- flush();
175
- enclosingInstruction.push(inInstruction);
176
- inInstruction = true;
177
- continue;
178
- }
179
- if (code === 20) {
180
- inInstruction = false;
181
- continue;
182
- }
183
- if (code === 21) {
184
- inInstruction = enclosingInstruction.pop() ?? inInstruction;
185
- continue;
186
- }
187
- if (inInstruction || require_text_special.isAnchorOnly(code)) continue;
188
- const fc = fcs[index];
189
- if (fc === void 0) throw new require_errors.DocFormatError(`character ${index} of a paragraph has no byte offset, so its formatting cannot be located`);
190
- const grpprl = context.chpxTable.chpxGrpprl(fc);
191
- const chpxKey = grpprl === void 0 ? "none" : `${grpprl.byteOffset}:${grpprl.byteLength}`;
192
- const key = `${paragraphIstd ?? "none"}:${chpxKey}`;
193
- if (key !== currentKey) {
194
- flush();
195
- currentKey = key;
196
- let properties = context.characterProperties.get(key);
197
- if (properties === void 0) {
198
- properties = {};
199
- require_prop_chp.applyCharacterSprms(paragraphStyleCharacterPrls, properties, context.fonts);
200
- if (grpprl !== void 0) {
201
- const runPrls = require_prop_sprm.readGrpprl(grpprl);
202
- const characterIstd = require_prop_chp.characterIstdFromGrpprl(runPrls);
203
- if (characterIstd !== void 0 && context.styles !== void 0) require_prop_chp.applyCharacterSprms(require_style_stsh.resolveStyleFormatting(context.styles, characterIstd).characterPrls, properties, context.fonts);
204
- require_prop_chp.applyCharacterSprms(runPrls, properties, context.fonts);
205
- }
206
- context.characterProperties.set(key, properties);
207
- }
208
- currentProperties = properties;
209
- }
210
- currentText += String.fromCharCode(code === 11 ? 10 : code);
99
+ function splitIntoSections(entries, sections) {
100
+ const groups = sections.map(() => []);
101
+ let sectionIndex = 0;
102
+ for (const entry of entries) {
103
+ const group = groups[sectionIndex];
104
+ if (group === void 0) throw new require_errors.DocFormatError(`internal defect: section index ${sectionIndex} has no group despite ${sections.length} sections`);
105
+ group.push(entry);
106
+ if (entry.endCp === sections[sectionIndex + 1]?.startCp) sectionIndex += 1;
211
107
  }
212
- flush();
213
- return runs;
108
+ return groups;
214
109
  }
215
110
  //#endregion
216
111
  exports.readDocContent = readDocContent;
package/dist/read.d.cts CHANGED
@@ -1,8 +1,8 @@
1
- import { t as Fib } from "./fib-DWFta19r.cjs";
2
- import { t as Prl } from "./sprm-DEyvdOo0.cjs";
3
- import { t as ParagraphProperties } from "./pap-BT1p0uzu.cjs";
4
- import { r as NumberingDefinitions } from "./numbering-DSpm9w6y.cjs";
5
- import { ContentDocument, ContentParagraph } from "document-schema.js";
1
+ import { t as Fib } from "./fib-6BFIx153.cjs";
2
+ import { HeaderFooterStories } from "./headers-footers.cjs";
3
+ import { NumberingDefinitions } from "./list/numbering.cjs";
4
+ import { NoteBodies } from "./notes.cjs";
5
+ import { ContentDocument } from "document-schema.js";
6
6
  //#region src/read.d.ts
7
7
  interface DocStreams {
8
8
  readonly wordDocument: Uint8Array;
@@ -10,20 +10,18 @@ interface DocStreams {
10
10
  readonly fib: Fib;
11
11
  /** The raw "\x05SummaryInformation" stream bytes, or undefined when the container carries none -- a valid, spec-conformant Word Binary File need not carry document properties at all. */
12
12
  readonly metadata: Uint8Array<ArrayBuffer> | undefined;
13
+ /** The raw "Data" stream bytes, or undefined when the container carries none -- a valid Word Binary File with no pictures need not have one. sprmCPicLocation's operand addresses this stream (pictures.ts). */
14
+ readonly data: Uint8Array<ArrayBuffer> | undefined;
13
15
  }
14
16
  declare function readDocStreams(bytes: Uint8Array<ArrayBuffer>, password?: string): DocStreams;
15
- /** readDocContent's own return type: a ContentDocument (kind 'wordprocessing') plus numbering -- the list-level formatting (glyph/format, level-text template, start-at value) PlfLst/PlfLfo carry, which ContentListMembership has nowhere to hold. Mirrors ooxml.js's own DocxDocument.numbering exactly in field name and NumberingDefinitions' own shape (see list/numbering.ts's top comment for why it sits outside the shared schema rather than inside ContentListMembership); unlike DocxDocument, DocContent stays a genuine ContentDocument subtype (an intersection, not a fresh shape) since readDocContent already had one return type to widen rather than two to reconcile. */
17
+ /** readDocContent's own return type: a ContentDocument (kind 'wordprocessing') plus numbering, footnotes, endnotes, comments, and headerFooterStories -- constructs [MS-DOC] carries outside the main document's own text and document-schema.js's ContentDocument has nowhere to hold. Mirrors ooxml.js's own DocxDocument in field name and shape wherever the two formats' own constructs genuinely agree (numbering/NumberingDefinitions, footnotes/endnotes/comments as plain-text `Footnote`/`Comment`); headerFooterStories is doc-codec's own shape rather than DocxDocument's path-addressed HeaderFooterPart, since [MS-DOC] has no named parts of its own for a header or footer to be identified by, only a (section, slot) position (see headers-footers.ts's own top comment). Unlike DocxDocument, DocContent stays a genuine ContentDocument subtype (an intersection, not a fresh shape) since readDocContent already had one return type to widen rather than several to reconcile. */
16
18
  type DocContent = ContentDocument & {
17
19
  readonly numbering: NumberingDefinitions;
20
+ readonly footnotes: NoteBodies["footnotes"];
21
+ readonly endnotes: NoteBodies["endnotes"];
22
+ readonly comments: NoteBodies["comments"];
23
+ readonly headerFooterStories: HeaderFooterStories;
18
24
  };
19
25
  declare function readDocContent(bytes: Uint8Array<ArrayBuffer>, password?: string): DocContent;
20
- /** One paragraph/cell/row-ending mark, still flat -- table/read.ts's assembleBlocks is what folds a run of these into a real ContentTable. `properties` and `grpprl` are carried alongside the already-built `paragraph` because table grouping needs sprmPFInTable/sprmPFTtp/sprmPItap (properties) and, on a row's own mark, its table-defining sgc-5 sprms (grpprl) -- neither of which survives onto a plain ContentParagraph. */
21
- interface ParagraphEntry {
22
- readonly paragraph: ContentParagraph;
23
- readonly properties: ParagraphProperties;
24
- readonly grpprl: readonly Prl[];
25
- /** The character that terminated this paragraph in the text stream: PARAGRAPH_MARK, CELL_MARK, or SECTION_MARK. */
26
- readonly terminator: number;
27
- }
28
26
  //#endregion
29
- export { DocContent, DocStreams, ParagraphEntry, readDocContent, readDocStreams };
27
+ export { DocContent, DocStreams, readDocContent, readDocStreams };
package/dist/read.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { t as Fib } from "./fib-DWFta19r.js";
2
- import { t as Prl } from "./sprm-DEyvdOo0.js";
3
- import { t as ParagraphProperties } from "./pap-DOFLMWcG.js";
4
- import { r as NumberingDefinitions } from "./numbering-DayjnHXY.js";
5
- import { ContentDocument, ContentParagraph } from "document-schema.js";
1
+ import { t as Fib } from "./fib-6BFIx153.js";
2
+ import { HeaderFooterStories } from "./headers-footers.js";
3
+ import { NumberingDefinitions } from "./list/numbering.js";
4
+ import { NoteBodies } from "./notes.js";
5
+ import { ContentDocument } from "document-schema.js";
6
6
  //#region src/read.d.ts
7
7
  interface DocStreams {
8
8
  readonly wordDocument: Uint8Array;
@@ -10,20 +10,18 @@ interface DocStreams {
10
10
  readonly fib: Fib;
11
11
  /** The raw "\x05SummaryInformation" stream bytes, or undefined when the container carries none -- a valid, spec-conformant Word Binary File need not carry document properties at all. */
12
12
  readonly metadata: Uint8Array<ArrayBuffer> | undefined;
13
+ /** The raw "Data" stream bytes, or undefined when the container carries none -- a valid Word Binary File with no pictures need not have one. sprmCPicLocation's operand addresses this stream (pictures.ts). */
14
+ readonly data: Uint8Array<ArrayBuffer> | undefined;
13
15
  }
14
16
  declare function readDocStreams(bytes: Uint8Array<ArrayBuffer>, password?: string): DocStreams;
15
- /** readDocContent's own return type: a ContentDocument (kind 'wordprocessing') plus numbering -- the list-level formatting (glyph/format, level-text template, start-at value) PlfLst/PlfLfo carry, which ContentListMembership has nowhere to hold. Mirrors ooxml.js's own DocxDocument.numbering exactly in field name and NumberingDefinitions' own shape (see list/numbering.ts's top comment for why it sits outside the shared schema rather than inside ContentListMembership); unlike DocxDocument, DocContent stays a genuine ContentDocument subtype (an intersection, not a fresh shape) since readDocContent already had one return type to widen rather than two to reconcile. */
17
+ /** readDocContent's own return type: a ContentDocument (kind 'wordprocessing') plus numbering, footnotes, endnotes, comments, and headerFooterStories -- constructs [MS-DOC] carries outside the main document's own text and document-schema.js's ContentDocument has nowhere to hold. Mirrors ooxml.js's own DocxDocument in field name and shape wherever the two formats' own constructs genuinely agree (numbering/NumberingDefinitions, footnotes/endnotes/comments as plain-text `Footnote`/`Comment`); headerFooterStories is doc-codec's own shape rather than DocxDocument's path-addressed HeaderFooterPart, since [MS-DOC] has no named parts of its own for a header or footer to be identified by, only a (section, slot) position (see headers-footers.ts's own top comment). Unlike DocxDocument, DocContent stays a genuine ContentDocument subtype (an intersection, not a fresh shape) since readDocContent already had one return type to widen rather than several to reconcile. */
16
18
  type DocContent = ContentDocument & {
17
19
  readonly numbering: NumberingDefinitions;
20
+ readonly footnotes: NoteBodies["footnotes"];
21
+ readonly endnotes: NoteBodies["endnotes"];
22
+ readonly comments: NoteBodies["comments"];
23
+ readonly headerFooterStories: HeaderFooterStories;
18
24
  };
19
25
  declare function readDocContent(bytes: Uint8Array<ArrayBuffer>, password?: string): DocContent;
20
- /** One paragraph/cell/row-ending mark, still flat -- table/read.ts's assembleBlocks is what folds a run of these into a real ContentTable. `properties` and `grpprl` are carried alongside the already-built `paragraph` because table grouping needs sprmPFInTable/sprmPFTtp/sprmPItap (properties) and, on a row's own mark, its table-defining sgc-5 sprms (grpprl) -- neither of which survives onto a plain ContentParagraph. */
21
- interface ParagraphEntry {
22
- readonly paragraph: ContentParagraph;
23
- readonly properties: ParagraphProperties;
24
- readonly grpprl: readonly Prl[];
25
- /** The character that terminated this paragraph in the text stream: PARAGRAPH_MARK, CELL_MARK, or SECTION_MARK. */
26
- readonly terminator: number;
27
- }
28
26
  //#endregion
29
- export { DocContent, DocStreams, ParagraphEntry, readDocContent, readDocStreams };
27
+ export { DocContent, DocStreams, readDocContent, readDocStreams };