wpd-codec 3.1.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/read.js CHANGED
@@ -1,14 +1,16 @@
1
1
  import { uint16At } from "./bytes/view.js";
2
2
  import { decodeSingleByteCharacter, decodeWpCharacter } from "./stream/characters.js";
3
- import { packetByPrefixId, readTypefaceName } from "./container/prefix.js";
3
+ import { packetByPrefixId, readGeneralWpTextBlocks, readTypefaceName } from "./container/prefix.js";
4
4
  import { openWpdDocument } from "./container/container.js";
5
5
  import { readDocumentSummary } from "./container/summary.js";
6
6
  import { NOOP_WPD_DIAGNOSTIC_SINK, WpdDiagnosticCodes } from "./diagnostics.js";
7
7
  import { decodeAttributeByte, runAttributesFrom } from "./stream/attributes.js";
8
8
  import { eolMappingForSubfunction, isSingleByteEol, subfunctionForSingleByteEol } from "./stream/eol.js";
9
9
  import { readMarginPt, readPageForm } from "./stream/page.js";
10
- import { isParagraphNumberDisplayOff, isParagraphNumberDisplayOn, isStyleScopeCloser, isStyleScopeOpener, readDisplayNumberLevel, readSystemStyleNumber, styleSemanticsFor } from "./stream/style.js";
10
+ import { isParagraphNumberDisplayOff, isParagraphNumberDisplayOn, isStyleScopeCloser, isStyleScopeOpener, readDisplayNumberLevel, readStyleBeginBlock, readSystemStyleNumber, styleSemanticsFor } from "./stream/style.js";
11
11
  import { findEmbeddedSubfunction, readCellFill, readCellInformation, readCellSpanning, readEmbeddedSubfunctions, readRowInformation, readTableColumnWidthPt } from "./stream/table.js";
12
+ import { readBoxContent } from "./stream/box.js";
13
+ import { readTableFormula } from "./stream/formula.js";
12
14
  import { tabEffectFor } from "./stream/tab.js";
13
15
  import { tokeniseDocumentArea } from "./stream/tokenise.js";
14
16
  import { assembleTree } from "document-schema.js";
@@ -29,6 +31,8 @@ const CROSS_REFERENCE_GROUP = 213;
29
31
  const HEADER_FOOTER_GROUP = 214;
30
32
  const FOOTNOTE_ENDNOTE_GROUP = 215;
31
33
  const MERGE_GROUP = 222;
34
+ const MERGE_FIELD_ON = 76;
35
+ const MERGE_FIELD_OFF = 77;
32
36
  const BOX_GROUP = 223;
33
37
  const PARAGRAPH_GROUP = 211;
34
38
  const PARAGRAPH_SET_JUSTIFICATION = 5;
@@ -48,6 +52,7 @@ const JUSTIFICATION = [
48
52
  const THREE_THOUSAND_SIX_HUNDREDTHS_PER_POINT = 50;
49
53
  const COLOR_COMPONENT_MAX = 255;
50
54
  const NO_SPAN = 1;
55
+ const MAX_STYLE_RESOLUTION_DEPTH = 16;
51
56
  function sameAttributes(a, b) {
52
57
  return a.bold === b.bold && a.italic === b.italic && a.underline === b.underline && a.strike === b.strike;
53
58
  }
@@ -79,29 +84,35 @@ function flushRun(state) {
79
84
  function targetBlocks(state) {
80
85
  return state.table === void 0 ? state.blocks : state.table.cellBlocks;
81
86
  }
82
- function flushParagraph(state) {
87
+ function flushParagraph(state, sink) {
83
88
  flushRun(state);
89
+ if (state.openMergeFieldStartRun !== void 0) {
90
+ state.openMergeFieldStartRun = void 0;
91
+ reportOnce(state, sink, WpdDiagnosticCodes.MergeFieldSpansParagraphs, "A merge field's own On/Off pair straddled a paragraph boundary, which the run-scoped field construct cannot express; its text became ordinary paragraph text with no field tag.");
92
+ }
84
93
  const alignment = state.pendingAlignment ?? state.alignment;
94
+ const constructs = state.pendingConstructs.splice(0, state.pendingConstructs.length);
85
95
  const paragraph = {
86
96
  kind: "paragraph",
87
97
  runs: state.runs.splice(0, state.runs.length),
88
98
  ...alignment === void 0 ? {} : { alignment },
89
99
  ...state.pendingHeadingLevel === void 0 ? {} : { headingLevel: state.pendingHeadingLevel },
90
- ...state.pendingListLevel === void 0 ? {} : { list: { level: state.pendingListLevel } }
100
+ ...state.pendingListLevel === void 0 ? {} : { list: { level: state.pendingListLevel } },
101
+ ...constructs.length === 0 ? {} : { constructs }
91
102
  };
92
103
  state.pendingHeadingLevel = void 0;
93
104
  state.pendingListLevel = void 0;
94
105
  state.pendingAlignment = void 0;
95
106
  targetBlocks(state).push(paragraph);
96
107
  }
97
- function flushParagraphIfContent(state) {
108
+ function flushParagraphIfContent(state, sink) {
98
109
  if (state.text.length === 0 && state.runs.length === 0) return;
99
- flushParagraph(state);
110
+ flushParagraph(state, sink);
100
111
  }
101
112
  function effectiveStyle(state) {
102
113
  for (let index = state.styleScopes.length - 1; index >= 0; index -= 1) {
103
- const scope = state.styleScopes[index];
104
- if (scope !== void 0) return scope;
114
+ const semantics = state.styleScopes[index]?.semantics;
115
+ if (semantics !== void 0) return semantics;
105
116
  }
106
117
  }
107
118
  function appendText(state, text) {
@@ -122,6 +133,9 @@ function readCellAttributes(state, nonDeletable, sink) {
122
133
  const spanning = findEmbeddedSubfunction(subfunctions, 133);
123
134
  const fill = findEmbeddedSubfunction(subfunctions, 134);
124
135
  const row = findEmbeddedSubfunction(subfunctions, 128);
136
+ const formulaData = findEmbeddedSubfunction(subfunctions, 129);
137
+ const formula = formulaData === void 0 ? void 0 : readTableFormula(formulaData);
138
+ if (formulaData !== void 0 && formula === void 0) reportOnce(state, sink, WpdDiagnosticCodes.TableFormulaUnresolved, "A table cell carries a formula this reader could not decode with confidence, so the cell keeps its displayed text but not the formula that produced it.");
125
139
  const cellSpanning = spanning === void 0 ? void 0 : readCellSpanning(spanning);
126
140
  const cellFill = fill === void 0 ? void 0 : readCellFill(fill);
127
141
  if (cellFill?.blended === true) reportOnce(state, sink, WpdDiagnosticCodes.CellFillBlended, "A cell is filled with a shaded blend of two colours, resolved to a 'pattern' fill whose density is this reader's own best-effort derivation, not a value confirmed against a specification.");
@@ -131,13 +145,14 @@ function readCellAttributes(state, nonDeletable, sink) {
131
145
  background: cellFill?.fill,
132
146
  columnSpan: cellSpanning?.columnSpan ?? NO_SPAN,
133
147
  rowSpan: cellSpanning?.rowSpan ?? NO_SPAN,
134
- covered: cellSpanning?.coveredFromLeft === true || cellSpanning?.coveredFromAbove === true
148
+ covered: cellSpanning?.coveredFromLeft === true || cellSpanning?.coveredFromAbove === true,
149
+ formula
135
150
  },
136
151
  rowHeightPt: row === void 0 ? void 0 : readRowInformation(row)?.heightPt
137
152
  };
138
153
  }
139
- function closeCell(state, table, attributes) {
140
- flushParagraphIfContent(state);
154
+ function closeCell(state, table, attributes, sink) {
155
+ flushParagraphIfContent(state, sink);
141
156
  const blocks = table.cellBlocks;
142
157
  table.cellBlocks = [];
143
158
  if (attributes.covered) return;
@@ -148,7 +163,8 @@ function closeCell(state, table, attributes) {
148
163
  blocks,
149
164
  ...attributes.columnSpan > NO_SPAN ? { colSpan: attributes.columnSpan } : {},
150
165
  ...attributes.rowSpan > NO_SPAN ? { rowSpan: attributes.rowSpan } : {},
151
- ...attributes.background === void 0 ? {} : { background: attributes.background }
166
+ ...attributes.background === void 0 ? {} : { background: attributes.background },
167
+ ...attributes.formula === void 0 ? {} : { formula: attributes.formula }
152
168
  };
153
169
  table.cells.push(cell);
154
170
  }
@@ -180,14 +196,14 @@ function applyEolMapping(state, mapping, nonDeletable, sink) {
180
196
  appendText(state, " ");
181
197
  return;
182
198
  case "hardReturn":
183
- flushParagraph(state);
199
+ flushParagraph(state, sink);
184
200
  return;
185
201
  case "hardEndOfColumn":
186
202
  reportOnce(state, sink, WpdDiagnosticCodes.ColumnBreakFlattened, "A column break became a paragraph break.");
187
- flushParagraph(state);
203
+ flushParagraph(state, sink);
188
204
  return;
189
205
  case "hardEndOfPage":
190
- flushParagraph(state);
206
+ flushParagraph(state, sink);
191
207
  targetBlocks(state).push({ kind: "pageBreak" });
192
208
  return;
193
209
  case "tableCell":
@@ -197,13 +213,13 @@ function applyEolMapping(state, mapping, nonDeletable, sink) {
197
213
  const table = state.table;
198
214
  if (table === void 0) {
199
215
  reportOnce(state, sink, WpdDiagnosticCodes.TableFlattened, "A table cell or row boundary appeared with no table definition open; its text became a paragraph.");
200
- flushParagraph(state);
216
+ flushParagraph(state, sink);
201
217
  return;
202
218
  }
203
219
  const { attributes, rowHeightPt } = readCellAttributes(state, nonDeletable, sink);
204
220
  if (rowHeightPt !== void 0) table.rowHeightPt = rowHeightPt;
205
221
  const cellIsOpen = state.text.length > 0 || state.runs.length > 0 || table.cellBlocks.length > 0;
206
- if (mapping !== "tableOff" || cellIsOpen) closeCell(state, table, attributes);
222
+ if (mapping !== "tableOff" || cellIsOpen) closeCell(state, table, attributes, sink);
207
223
  if (mapping === "tableCell") return;
208
224
  closeRow(table);
209
225
  if (mapping === "tableOff") closeTable(state);
@@ -232,13 +248,13 @@ function applySingleByteFunction(state, code, sink) {
232
248
  appendText(state, "-");
233
249
  return;
234
250
  case DORMANT_HARD_RETURN:
235
- flushParagraph(state);
251
+ flushParagraph(state, sink);
236
252
  return;
237
253
  case SOFT_END_OF_CENTER_ALIGN:
238
254
  appendText(state, " ");
239
255
  return;
240
256
  case HARD_END_OF_CENTER_ALIGN:
241
- flushParagraph(state);
257
+ flushParagraph(state, sink);
242
258
  return;
243
259
  case START_OF_TEXT_TO_SKIP:
244
260
  state.skipDepth += 1;
@@ -300,13 +316,56 @@ function applyColumnGroup(state, token, sink) {
300
316
  if (token.subgroup === 0) setPageDimension(state, "leftPt", margin, sink);
301
317
  else if (token.subgroup === 1) setPageDimension(state, "rightPt", margin, sink);
302
318
  }
303
- function applyStyleGroup(state, token) {
319
+ function snapshotFormatting(state) {
320
+ return {
321
+ activeAttributes: new Set(state.activeAttributes),
322
+ fontFamily: state.fontFamily,
323
+ sizePt: state.sizePt,
324
+ color: state.color
325
+ };
326
+ }
327
+ function restoreFormattingSnapshot(state, snapshot) {
328
+ flushRun(state);
329
+ state.activeAttributes.clear();
330
+ for (const attribute of snapshot.activeAttributes) state.activeAttributes.add(attribute);
331
+ state.attributes = runAttributesFrom(state.activeAttributes);
332
+ state.fontFamily = snapshot.fontFamily;
333
+ state.sizePt = snapshot.sizePt;
334
+ state.color = snapshot.color;
335
+ }
336
+ function applyStylePacketBegin(state, token, container, sink) {
337
+ const prefixId = token.prefixIds[0];
338
+ if (prefixId === void 0) return;
339
+ const packet = packetByPrefixId(container.packets, prefixId);
340
+ if (packet?.packetType !== 48) return;
341
+ const beginBlock = readStyleBeginBlock(packet.bytes);
342
+ if (beginBlock === void 0) return;
343
+ if (state.styleResolutionDepth >= MAX_STYLE_RESOLUTION_DEPTH) {
344
+ reportOnce(state, sink, WpdDiagnosticCodes.StyleResolutionDepthExceeded, "A chain of styles resolving one another's own packets ran deeper than this reader will follow, so the deepest style's own direct formatting was not applied.");
345
+ return;
346
+ }
347
+ const snapshot = snapshotFormatting(state);
348
+ const tokens = tokeniseDocumentArea(beginBlock, 0, beginBlock.length);
349
+ state.styleResolutionDepth += 1;
350
+ for (const beginToken of tokens) applyToken(state, beginToken, container, sink);
351
+ state.styleResolutionDepth -= 1;
352
+ return snapshot;
353
+ }
354
+ function applyStyleGroup(state, token, container, sink) {
304
355
  if (isStyleScopeOpener(token.subgroup)) {
305
356
  const systemStyleNumber = readSystemStyleNumber(token.nonDeletable);
306
- state.styleScopes.push(systemStyleNumber === void 0 ? void 0 : styleSemanticsFor(systemStyleNumber));
357
+ const semantics = systemStyleNumber === void 0 ? void 0 : styleSemanticsFor(systemStyleNumber);
358
+ const snapshot = applyStylePacketBegin(state, token, container, sink);
359
+ state.styleScopes.push({
360
+ semantics,
361
+ snapshot
362
+ });
307
363
  return;
308
364
  }
309
- if (isStyleScopeCloser(token.subgroup)) state.styleScopes.pop();
365
+ if (isStyleScopeCloser(token.subgroup)) {
366
+ const entry = state.styleScopes.pop();
367
+ if (entry?.snapshot !== void 0) restoreFormattingSnapshot(state, entry.snapshot);
368
+ }
310
369
  }
311
370
  function applyDisplayNumberGroup(state, token, sink) {
312
371
  if (isParagraphNumberDisplayOn(token.subgroup)) {
@@ -322,7 +381,7 @@ function applyCharacterGroup(state, token, container, sink) {
322
381
  switch (token.subgroup) {
323
382
  case 42:
324
383
  closeTable(state);
325
- flushParagraphIfContent(state);
384
+ flushParagraphIfContent(state, sink);
326
385
  state.table = {
327
386
  columnWidthsPt: [],
328
387
  rows: [],
@@ -367,6 +426,104 @@ function applyCharacterGroup(state, token, container, sink) {
367
426
  default: return;
368
427
  }
369
428
  }
429
+ function applyMergeGroup(state, token, sink) {
430
+ if (token.subgroup === MERGE_FIELD_ON) {
431
+ flushRun(state);
432
+ state.openMergeFieldStartRun = state.runs.length;
433
+ return;
434
+ }
435
+ if (token.subgroup === MERGE_FIELD_OFF) {
436
+ const startRun = state.openMergeFieldStartRun;
437
+ state.openMergeFieldStartRun = void 0;
438
+ if (startRun === void 0) return;
439
+ flushRun(state);
440
+ const endRun = state.runs.length;
441
+ const instruction = state.runs.slice(startRun, endRun).map((run) => run.text).join("");
442
+ state.pendingConstructs.push({
443
+ descriptor: {
444
+ kind: "field",
445
+ instruction
446
+ },
447
+ startRun,
448
+ endRun
449
+ });
450
+ return;
451
+ }
452
+ reportOnce(state, sink, WpdDiagnosticCodes.MergeCodeDropped, "This document contains merge codes, which are a form-letter template's placeholders rather than text.");
453
+ }
454
+ function plainTextOf(blocks) {
455
+ return blocks.filter((block) => block.kind === "paragraph").map((paragraph) => paragraph.runs.map((run) => run.text).join("")).join("\n");
456
+ }
457
+ function applyBoxGroup(state, token, container, sink) {
458
+ const boxContent = readBoxContent(token.nonDeletable, token.prefixIds);
459
+ if (boxContent === void 0) {
460
+ reportOnce(state, sink, WpdDiagnosticCodes.BoxDropped, "This document contains a box -- a figure, text box, equation, or graphic -- whose function-level override names no content this reader can resolve.");
461
+ return;
462
+ }
463
+ const packet = boxContent.contentType === 1 || boxContent.contentType === 2 || boxContent.contentType === 4 ? packetByPrefixId(container.packets, boxContent.contentPrefixId) : void 0;
464
+ const textBlocks = packet?.packetType !== 8 ? void 0 : readGeneralWpTextBlocks(packet.bytes);
465
+ if (textBlocks === void 0) {
466
+ reportOnce(state, sink, WpdDiagnosticCodes.BoxContentUnresolved, "This document contains a box whose content this reader could not read -- an image, OLE object, or other content type this reader does not yet decode into the shared schema.");
467
+ return;
468
+ }
469
+ if (boxContent.frame === void 0) {
470
+ reportOnce(state, sink, WpdDiagnosticCodes.BoxFrameUnresolved, "This document contains a box whose content this reader could read, but whose function-level override states no width and height this reader can trust, so its content was not lifted.");
471
+ return;
472
+ }
473
+ flushParagraphIfContent(state, sink);
474
+ const nestedTokens = tokeniseDocumentArea(textBlocks, 0, textBlocks.length);
475
+ const frame = {
476
+ xPt: boxContent.frame.xPt,
477
+ yPt: boxContent.frame.yPt,
478
+ widthPt: boxContent.frame.widthPt,
479
+ heightPt: boxContent.frame.heightPt
480
+ };
481
+ if (boxContent.contentType === 4) {
482
+ const { blocks } = foldTokens(nestedTokens, container, sink);
483
+ const embed = {
484
+ kind: "embeddedObject",
485
+ objectKind: "formula",
486
+ frame,
487
+ document: {
488
+ kind: "formula",
489
+ metadata: {},
490
+ formula: {
491
+ mathml: [],
492
+ source: {
493
+ format: "wpd",
494
+ xml: plainTextOf(blocks)
495
+ }
496
+ }
497
+ }
498
+ };
499
+ targetBlocks(state).push(embed);
500
+ return;
501
+ }
502
+ const { blocks, page } = foldTokens(nestedTokens, container, sink);
503
+ const embed = {
504
+ kind: "embeddedObject",
505
+ objectKind: "wordprocessing",
506
+ frame,
507
+ document: {
508
+ kind: "wordprocessing",
509
+ metadata: {},
510
+ sections: [{
511
+ pageSize: {
512
+ widthPt: page.widthPt ?? 612,
513
+ heightPt: page.heightPt ?? 792
514
+ },
515
+ margins: {
516
+ topPt: page.topPt ?? 72,
517
+ rightPt: page.rightPt ?? 72,
518
+ bottomPt: page.bottomPt ?? 72,
519
+ leftPt: page.leftPt ?? 72
520
+ },
521
+ blocks
522
+ }]
523
+ }
524
+ };
525
+ targetBlocks(state).push(embed);
526
+ }
370
527
  function applyVariableFunction(state, token, container, sink) {
371
528
  switch (token.group) {
372
529
  case 208: {
@@ -397,7 +554,7 @@ function applyVariableFunction(state, token, container, sink) {
397
554
  return;
398
555
  }
399
556
  case 221:
400
- applyStyleGroup(state, token);
557
+ applyStyleGroup(state, token, container, sink);
401
558
  return;
402
559
  case 218:
403
560
  applyDisplayNumberGroup(state, token, sink);
@@ -412,10 +569,10 @@ function applyVariableFunction(state, token, container, sink) {
412
569
  reportOnce(state, sink, WpdDiagnosticCodes.NoteDropped, "This document contains a footnote or endnote; its text lives in a prefix packet the flat content model has nowhere to put.");
413
570
  return;
414
571
  case MERGE_GROUP:
415
- reportOnce(state, sink, WpdDiagnosticCodes.MergeCodeDropped, "This document contains merge codes, which are a form-letter template's placeholders rather than text.");
572
+ applyMergeGroup(state, token, sink);
416
573
  return;
417
574
  case BOX_GROUP:
418
- reportOnce(state, sink, WpdDiagnosticCodes.BoxDropped, "This document contains a box -- a figure, text box, equation, or graphic -- whose contents were not read.");
575
+ applyBoxGroup(state, token, container, sink);
419
576
  return;
420
577
  default: return;
421
578
  }
@@ -449,6 +606,32 @@ function applyFixedFunction(state, token, sink) {
449
606
  flushRun(state);
450
607
  state.attributes = next;
451
608
  }
609
+ function applyToken(state, token, container, sink) {
610
+ switch (token.kind) {
611
+ case "character": {
612
+ const character = decodeSingleByteCharacter(token.byte);
613
+ if (character === void 0) {
614
+ sink({
615
+ code: WpdDiagnosticCodes.UnmappedCharacter,
616
+ message: `Byte ${token.byte} in the document area has no character mapping and was rendered as U+FFFD.`
617
+ });
618
+ appendText(state, "�");
619
+ return;
620
+ }
621
+ appendText(state, character);
622
+ return;
623
+ }
624
+ case "singleByteFunction":
625
+ applySingleByteFunction(state, token.code, sink);
626
+ return;
627
+ case "variableFunction":
628
+ applyVariableFunction(state, token, container, sink);
629
+ return;
630
+ case "fixedFunction":
631
+ applyFixedFunction(state, token, sink);
632
+ return;
633
+ }
634
+ }
452
635
  function foldTokens(tokens, container, sink) {
453
636
  const state = {
454
637
  blocks: [],
@@ -462,6 +645,7 @@ function foldTokens(tokens, container, sink) {
462
645
  alignment: void 0,
463
646
  skipDepth: 0,
464
647
  styleScopes: [],
648
+ styleResolutionDepth: 0,
465
649
  pendingHeadingLevel: void 0,
466
650
  pendingListLevel: void 0,
467
651
  pendingAlignment: void 0,
@@ -476,32 +660,13 @@ function foldTokens(tokens, container, sink) {
476
660
  changeReported: false
477
661
  },
478
662
  table: void 0,
479
- reported: /* @__PURE__ */ new Set()
663
+ reported: /* @__PURE__ */ new Set(),
664
+ pendingConstructs: [],
665
+ openMergeFieldStartRun: void 0
480
666
  };
481
- for (const token of tokens) switch (token.kind) {
482
- case "character": {
483
- const character = decodeSingleByteCharacter(token.byte);
484
- if (character === void 0) {
485
- sink({
486
- code: WpdDiagnosticCodes.UnmappedCharacter,
487
- message: `Byte ${token.byte} in the document area has no character mapping and was rendered as U+FFFD.`
488
- });
489
- appendText(state, "�");
490
- break;
491
- }
492
- appendText(state, character);
493
- break;
494
- }
495
- case "singleByteFunction":
496
- applySingleByteFunction(state, token.code, sink);
497
- break;
498
- case "variableFunction":
499
- applyVariableFunction(state, token, container, sink);
500
- break;
501
- case "fixedFunction": applyFixedFunction(state, token, sink);
502
- }
667
+ for (const token of tokens) applyToken(state, token, container, sink);
503
668
  flushRun(state);
504
- if (state.runs.length > 0) flushParagraph(state);
669
+ if (state.runs.length > 0) flushParagraph(state, sink);
505
670
  if (state.table !== void 0) {
506
671
  closeRow(state.table);
507
672
  closeTable(state);
@@ -0,0 +1,122 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_bytes_view = require("../bytes/view.cjs");
3
+ const require_stream_units = require("./units.cjs");
4
+ //#region src/stream/box.ts
5
+ const OVERRIDE_BIT_POSITION = 14;
6
+ const OVERRIDE_BIT_CONTENT = 13;
7
+ const OVERRIDE_BIT_HTML = 7;
8
+ const OVERRIDE_FLAGS_OFFSET = 18;
9
+ const FIRST_OVERRIDE_BLOCK_OFFSET = 20;
10
+ function walkOverrideBlocks(nonDeletable) {
11
+ if (nonDeletable.length < FIRST_OVERRIDE_BLOCK_OFFSET) return;
12
+ const flags = require_bytes_view.uint16At(nonDeletable, OVERRIDE_FLAGS_OFFSET);
13
+ const blocks = /* @__PURE__ */ new Map();
14
+ let cursor = FIRST_OVERRIDE_BLOCK_OFFSET;
15
+ for (let bit = 15; bit >= 5; bit -= 1) {
16
+ if ((flags & 1 << bit) === 0) continue;
17
+ if (bit === OVERRIDE_BIT_HTML) continue;
18
+ if (cursor + 2 > nonDeletable.length) return;
19
+ const size = require_bytes_view.uint16At(nonDeletable, cursor);
20
+ cursor += 2;
21
+ if (cursor + size > nonDeletable.length) return;
22
+ blocks.set(bit, nonDeletable.subarray(cursor, cursor + size));
23
+ cursor += size;
24
+ }
25
+ return {
26
+ flags,
27
+ blocks
28
+ };
29
+ }
30
+ function readContentType(contentBlock) {
31
+ if (contentBlock.length < 2) return;
32
+ const flags = require_bytes_view.uint16At(contentBlock, 0);
33
+ let cursor = 2;
34
+ if ((flags & 32768) !== 0) {
35
+ if (cursor + 2 > contentBlock.length) return;
36
+ cursor += 2;
37
+ }
38
+ if ((flags & 16384) === 0) return;
39
+ return contentBlock[cursor];
40
+ }
41
+ function readPositionOverride(positionBlock) {
42
+ if (positionBlock.length < 2) return;
43
+ const flags = require_bytes_view.uint16At(positionBlock, 0);
44
+ let cursor = 2;
45
+ let widthWpu;
46
+ let heightWpu;
47
+ let xWpu;
48
+ let yWpu;
49
+ const need = (bytes) => cursor + bytes <= positionBlock.length;
50
+ if ((flags & 32768) !== 0) {
51
+ if (!need(2)) return void 0;
52
+ cursor += 2;
53
+ }
54
+ if ((flags & 16384) !== 0) {
55
+ if (!need(2)) return void 0;
56
+ cursor += 2;
57
+ }
58
+ if ((flags & 8192) !== 0) {
59
+ if (!need(5)) return void 0;
60
+ const horizontalFlags = positionBlock[cursor];
61
+ const offset = require_bytes_view.uint16At(positionBlock, cursor + 1);
62
+ if (horizontalFlags !== void 0 && (horizontalFlags & 3) === 0) xWpu = offset;
63
+ cursor += 5;
64
+ }
65
+ if ((flags & 4096) !== 0) {
66
+ if (!need(3)) return void 0;
67
+ const verticalFlags = positionBlock[cursor];
68
+ const offset = require_bytes_view.uint16At(positionBlock, cursor + 1);
69
+ if (verticalFlags !== void 0 && (verticalFlags & 3) === 0) yWpu = offset;
70
+ cursor += 3;
71
+ }
72
+ if ((flags & 2048) !== 0) {
73
+ if (!need(3)) return void 0;
74
+ widthWpu = require_bytes_view.uint16At(positionBlock, cursor + 1);
75
+ cursor += 3;
76
+ }
77
+ if ((flags & 1024) !== 0) {
78
+ if (!need(3)) return void 0;
79
+ heightWpu = require_bytes_view.uint16At(positionBlock, cursor + 1);
80
+ cursor += 3;
81
+ }
82
+ return {
83
+ widthWpu,
84
+ heightWpu,
85
+ xWpu,
86
+ yWpu
87
+ };
88
+ }
89
+ const BOX_CONTENT_TYPE_TEXT = 1;
90
+ const BOX_CONTENT_TYPE_LINKED_TEXT = 2;
91
+ const BOX_CONTENT_TYPE_IMAGE = 3;
92
+ const BOX_CONTENT_TYPE_EQUATION = 4;
93
+ function readBoxContent(nonDeletable, prefixIds) {
94
+ const walk = walkOverrideBlocks(nonDeletable);
95
+ if (walk === void 0) return;
96
+ const { flags, blocks } = walk;
97
+ const contentBlock = blocks.get(OVERRIDE_BIT_CONTENT);
98
+ if (contentBlock === void 0) return;
99
+ const contentType = readContentType(contentBlock);
100
+ if (contentType === void 0) return;
101
+ const contentPrefixId = prefixIds[1 + ((flags & 32768) !== 0 ? 1 : 0)];
102
+ if (contentPrefixId === void 0) return;
103
+ const positionBlock = blocks.get(OVERRIDE_BIT_POSITION);
104
+ const position = positionBlock === void 0 ? void 0 : readPositionOverride(positionBlock);
105
+ return {
106
+ contentType,
107
+ contentPrefixId,
108
+ frame: position?.widthWpu === void 0 || position.heightWpu === void 0 ? void 0 : {
109
+ xPt: require_stream_units.pointsFromWpu(position.xWpu ?? 0),
110
+ yPt: require_stream_units.pointsFromWpu(position.yWpu ?? 0),
111
+ widthPt: require_stream_units.pointsFromWpu(position.widthWpu),
112
+ heightPt: require_stream_units.pointsFromWpu(position.heightWpu),
113
+ positionResolved: position.xWpu !== void 0 && position.yWpu !== void 0
114
+ }
115
+ };
116
+ }
117
+ //#endregion
118
+ exports.BOX_CONTENT_TYPE_EQUATION = BOX_CONTENT_TYPE_EQUATION;
119
+ exports.BOX_CONTENT_TYPE_IMAGE = BOX_CONTENT_TYPE_IMAGE;
120
+ exports.BOX_CONTENT_TYPE_LINKED_TEXT = BOX_CONTENT_TYPE_LINKED_TEXT;
121
+ exports.BOX_CONTENT_TYPE_TEXT = BOX_CONTENT_TYPE_TEXT;
122
+ exports.readBoxContent = readBoxContent;
@@ -0,0 +1,20 @@
1
+ //#region src/stream/box.d.ts
2
+ interface WpdBoxFrame {
3
+ readonly xPt: number;
4
+ readonly yPt: number;
5
+ readonly widthPt: number;
6
+ readonly heightPt: number;
7
+ readonly positionResolved: boolean;
8
+ }
9
+ interface WpdBoxContent {
10
+ readonly contentType: number;
11
+ readonly contentPrefixId: number;
12
+ readonly frame: WpdBoxFrame | undefined;
13
+ }
14
+ declare const BOX_CONTENT_TYPE_TEXT = 1;
15
+ declare const BOX_CONTENT_TYPE_LINKED_TEXT = 2;
16
+ declare const BOX_CONTENT_TYPE_IMAGE = 3;
17
+ declare const BOX_CONTENT_TYPE_EQUATION = 4;
18
+ declare function readBoxContent(nonDeletable: Uint8Array, prefixIds: readonly number[]): WpdBoxContent | undefined;
19
+ //#endregion
20
+ export { BOX_CONTENT_TYPE_EQUATION, BOX_CONTENT_TYPE_IMAGE, BOX_CONTENT_TYPE_LINKED_TEXT, BOX_CONTENT_TYPE_TEXT, WpdBoxContent, WpdBoxFrame, readBoxContent };
@@ -0,0 +1,20 @@
1
+ //#region src/stream/box.d.ts
2
+ interface WpdBoxFrame {
3
+ readonly xPt: number;
4
+ readonly yPt: number;
5
+ readonly widthPt: number;
6
+ readonly heightPt: number;
7
+ readonly positionResolved: boolean;
8
+ }
9
+ interface WpdBoxContent {
10
+ readonly contentType: number;
11
+ readonly contentPrefixId: number;
12
+ readonly frame: WpdBoxFrame | undefined;
13
+ }
14
+ declare const BOX_CONTENT_TYPE_TEXT = 1;
15
+ declare const BOX_CONTENT_TYPE_LINKED_TEXT = 2;
16
+ declare const BOX_CONTENT_TYPE_IMAGE = 3;
17
+ declare const BOX_CONTENT_TYPE_EQUATION = 4;
18
+ declare function readBoxContent(nonDeletable: Uint8Array, prefixIds: readonly number[]): WpdBoxContent | undefined;
19
+ //#endregion
20
+ export { BOX_CONTENT_TYPE_EQUATION, BOX_CONTENT_TYPE_IMAGE, BOX_CONTENT_TYPE_LINKED_TEXT, BOX_CONTENT_TYPE_TEXT, WpdBoxContent, WpdBoxFrame, readBoxContent };