rtf-codec 2.1.0 → 3.0.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.cjs CHANGED
@@ -5,6 +5,7 @@ const require_bytes = require("./bytes.cjs");
5
5
  const require_units = require("./units.cjs");
6
6
  const require_cell_format = require("./cell-format.cjs");
7
7
  const require_constructs = require("./constructs.cjs");
8
+ const require_embedded_object = require("./embedded-object.cjs");
8
9
  const require_codepage = require("./codepage.cjs");
9
10
  const require_group = require("./group.cjs");
10
11
  const require_header = require("./header.cjs");
@@ -23,6 +24,15 @@ const DESTINATION_KINDS = /* @__PURE__ */ new Map([
23
24
  ["listtext", "listText"],
24
25
  ["pntext", "listText"],
25
26
  ["upr", "unicodeWrapper"],
27
+ ["formfield", "formField"],
28
+ ["ffname", "formFieldName"],
29
+ ["ffhelptext", "formFieldHelpText"],
30
+ ["ffl", "formFieldListItem"],
31
+ ["ffdeftext", "skip"],
32
+ ["ffformat", "skip"],
33
+ ["ffstattext", "skip"],
34
+ ["ffentrymcr", "skip"],
35
+ ["ffexitmcr", "skip"],
26
36
  ["footnote", "skip"],
27
37
  ["header", "skip"],
28
38
  ["headerl", "skip"],
@@ -47,10 +57,15 @@ const DESTINATION_KINDS = /* @__PURE__ */ new Map([
47
57
  ["atnicn", "skip"],
48
58
  ["bkmkstart", "bookmarkStart"],
49
59
  ["bkmkend", "bookmarkEnd"],
50
- ["object", "skip"],
51
- ["objdata", "skip"],
60
+ ["object", "object"],
61
+ ["objdata", "objectData"],
52
62
  ["objclass", "skip"],
53
63
  ["objname", "skip"],
64
+ ["oleclsid", "skip"],
65
+ ["objalias", "skip"],
66
+ ["objsect", "skip"],
67
+ ["objtime", "skip"],
68
+ ["result", "skip"],
54
69
  ["do", "skip"],
55
70
  ["shp", "skip"],
56
71
  ["shptxt", "skip"],
@@ -68,6 +83,11 @@ const DESTINATION_KINDS = /* @__PURE__ */ new Map([
68
83
  ["fname", "skip"]
69
84
  ]);
70
85
  const SILENT_SKIP_DESTINATIONS = /* @__PURE__ */ new Set([
86
+ "ffdeftext",
87
+ "ffformat",
88
+ "ffstattext",
89
+ "ffentrymcr",
90
+ "ffexitmcr",
71
91
  "pn",
72
92
  "pnseclvl",
73
93
  "nonshppict",
@@ -82,7 +102,11 @@ const SILENT_SKIP_DESTINATIONS = /* @__PURE__ */ new Set([
82
102
  "atnicn",
83
103
  "objclass",
84
104
  "objname",
85
- "objdata",
105
+ "oleclsid",
106
+ "objalias",
107
+ "objsect",
108
+ "objtime",
109
+ "result",
86
110
  "shpinst",
87
111
  "shptxt",
88
112
  "ftnsep",
@@ -137,6 +161,21 @@ const SECTION_BREAK_TYPES = /* @__PURE__ */ new Map([
137
161
  ["sbkeven", "evenPage"],
138
162
  ["sbkodd", "oddPage"]
139
163
  ]);
164
+ const OBJECT_DATA_HEX_DIGITS = "0123456789abcdef";
165
+ function appendObjectDataHexText(objectData, text) {
166
+ let high = objectData.pendingHexNibble;
167
+ for (const character of text) {
168
+ const value = OBJECT_DATA_HEX_DIGITS.indexOf(character.toLowerCase());
169
+ if (value === -1) continue;
170
+ if (high === void 0) {
171
+ high = value;
172
+ continue;
173
+ }
174
+ objectData.bytes.push(high * 16 + value);
175
+ high = void 0;
176
+ }
177
+ objectData.pendingHexNibble = high;
178
+ }
140
179
  function defaultCharacterState() {
141
180
  return {
142
181
  bold: false,
@@ -175,8 +214,15 @@ function cloneGroupState(state) {
175
214
  para: { ...state.para },
176
215
  field: state.field,
177
216
  picture: state.picture,
217
+ pictureOwner: false,
218
+ objectData: state.objectData,
219
+ object: state.object,
220
+ objectDataOwner: false,
221
+ objectOwner: false,
222
+ resultOf: void 0,
178
223
  bookmark: state.bookmark,
179
- inUnicodeWrapper: state.inUnicodeWrapper
224
+ inUnicodeWrapper: state.inUnicodeWrapper,
225
+ isFieldGroup: state.isFieldGroup
180
226
  };
181
227
  }
182
228
  function runKey(char, fontName, color, hyperlink) {
@@ -251,6 +297,31 @@ function horizontalSpanAt(definitions, index) {
251
297
  while (definitions[index + span]?.horizontalMergeContinuation === true) span += 1;
252
298
  return span;
253
299
  }
300
+ function freshAccumulatorState() {
301
+ return {
302
+ blocks: [],
303
+ runs: [],
304
+ pendingRunKey: void 0,
305
+ pendingRunText: "",
306
+ pendingRunFields: {},
307
+ runProvenance: [],
308
+ pendingRunProvenance: [],
309
+ tableRows: [],
310
+ tableColumnRights: [],
311
+ rowCells: [],
312
+ cellBlocks: [],
313
+ pendingCellRights: [],
314
+ pendingCellDefinitions: [],
315
+ pendingCell: require_cell_format.newPendingCell(),
316
+ rowLeftTwips: 0,
317
+ paragraphSerial: 0,
318
+ openBookmarks: /* @__PURE__ */ new Map(),
319
+ sectionBlockExtents: [],
320
+ cellBlockExtents: [],
321
+ pendingRunConstructs: [],
322
+ closingBookmarks: []
323
+ };
324
+ }
254
325
  var ContentBuilder = class {
255
326
  header;
256
327
  sink;
@@ -276,6 +347,8 @@ var ContentBuilder = class {
276
347
  cellBlockExtents = [];
277
348
  pendingRunConstructs = [];
278
349
  closingBookmarks = [];
350
+ openFormFields = [];
351
+ resultScratchStack = [];
279
352
  constructor(header, sink) {
280
353
  this.header = header;
281
354
  this.sink = sink;
@@ -317,6 +390,39 @@ var ContentBuilder = class {
317
390
  }
318
391
  this.closingBookmarks.push(open);
319
392
  }
393
+ startFormField() {
394
+ this.flushRun();
395
+ this.openFormFields.push({
396
+ paragraphSerial: this.paragraphSerial,
397
+ runIndex: this.runs.length
398
+ });
399
+ }
400
+ endFormField(descriptor) {
401
+ this.flushRun();
402
+ const open = this.openFormFields.pop();
403
+ if (open === void 0) return;
404
+ if (descriptor === void 0) {
405
+ this.sink({
406
+ code: require_diagnostics.RtfDiagnosticCodes.FORM_FIELD_KEYWORD_LOST,
407
+ severity: "warning",
408
+ message: "a form field's contentControl is dropped: its \\*\\fldinst instruction matched a form-field keyword partway through parsing but no longer did once the complete instruction was read"
409
+ });
410
+ return;
411
+ }
412
+ if (open.paragraphSerial !== this.paragraphSerial) {
413
+ this.sink({
414
+ code: require_diagnostics.RtfDiagnosticCodes.FORM_FIELD_SPAN_DROPPED,
415
+ severity: "warning",
416
+ message: "a form field's contentControl is dropped: its \\fldrslt content crossed a paragraph or table-cell boundary, and this reader's per-paragraph construct extent cannot span one"
417
+ });
418
+ return;
419
+ }
420
+ this.pendingRunConstructs.push({
421
+ descriptor,
422
+ startRun: open.runIndex,
423
+ endRun: this.runs.length
424
+ });
425
+ }
320
426
  appendText(text, char, hyperlink) {
321
427
  if (text.length === 0 || char.hidden) return;
322
428
  const fontName = char.fontIndex === void 0 ? void 0 : this.header.fonts.get(char.fontIndex)?.name;
@@ -559,9 +665,77 @@ var ContentBuilder = class {
559
665
  }
560
666
  return widths;
561
667
  }
562
- addBlock(block) {
668
+ addBlocks(blocks, inTable) {
669
+ if (blocks.length === 0) return;
563
670
  this.flushRun();
564
- this.blocks.push(block);
671
+ (inTable ? this.cellBlocks : this.blocks).push(...blocks);
672
+ }
673
+ captureAccumulatorState() {
674
+ return {
675
+ blocks: this.blocks,
676
+ runs: this.runs,
677
+ pendingRunKey: this.pendingRunKey,
678
+ pendingRunText: this.pendingRunText,
679
+ pendingRunFields: this.pendingRunFields,
680
+ runProvenance: this.runProvenance,
681
+ pendingRunProvenance: this.pendingRunProvenance,
682
+ tableRows: this.tableRows,
683
+ tableColumnRights: this.tableColumnRights,
684
+ rowCells: this.rowCells,
685
+ cellBlocks: this.cellBlocks,
686
+ pendingCellRights: this.pendingCellRights,
687
+ pendingCellDefinitions: this.pendingCellDefinitions,
688
+ pendingCell: this.pendingCell,
689
+ rowLeftTwips: this.rowLeftTwips,
690
+ paragraphSerial: this.paragraphSerial,
691
+ openBookmarks: this.openBookmarks,
692
+ sectionBlockExtents: this.sectionBlockExtents,
693
+ cellBlockExtents: this.cellBlockExtents,
694
+ pendingRunConstructs: this.pendingRunConstructs,
695
+ closingBookmarks: this.closingBookmarks
696
+ };
697
+ }
698
+ restoreAccumulatorState(saved) {
699
+ this.blocks = saved.blocks;
700
+ this.runs = saved.runs;
701
+ this.pendingRunKey = saved.pendingRunKey;
702
+ this.pendingRunText = saved.pendingRunText;
703
+ this.pendingRunFields = saved.pendingRunFields;
704
+ this.runProvenance = saved.runProvenance;
705
+ this.pendingRunProvenance = saved.pendingRunProvenance;
706
+ this.tableRows = saved.tableRows;
707
+ this.tableColumnRights = saved.tableColumnRights;
708
+ this.rowCells = saved.rowCells;
709
+ this.cellBlocks = saved.cellBlocks;
710
+ this.pendingCellRights = saved.pendingCellRights;
711
+ this.pendingCellDefinitions = saved.pendingCellDefinitions;
712
+ this.pendingCell = saved.pendingCell;
713
+ this.rowLeftTwips = saved.rowLeftTwips;
714
+ this.paragraphSerial = saved.paragraphSerial;
715
+ this.openBookmarks = saved.openBookmarks;
716
+ this.sectionBlockExtents = saved.sectionBlockExtents;
717
+ this.cellBlockExtents = saved.cellBlockExtents;
718
+ this.pendingRunConstructs = saved.pendingRunConstructs;
719
+ this.closingBookmarks = saved.closingBookmarks;
720
+ }
721
+ beginResultScratch() {
722
+ this.flushRun();
723
+ this.resultScratchStack.push(this.captureAccumulatorState());
724
+ this.restoreAccumulatorState(freshAccumulatorState());
725
+ }
726
+ endResultScratch(para) {
727
+ this.endParagraph(para, false);
728
+ this.closeTable();
729
+ const blocks = [...this.blocks, ...this.cellBlocks];
730
+ const saved = this.resultScratchStack.pop();
731
+ if (saved !== void 0) this.restoreAccumulatorState(saved);
732
+ return blocks;
733
+ }
734
+ discardUnclosedResultScratches() {
735
+ while (this.resultScratchStack.length > 0) {
736
+ const saved = this.resultScratchStack.pop();
737
+ if (saved !== void 0) this.restoreAccumulatorState(saved);
738
+ }
565
739
  }
566
740
  endSection(section, para) {
567
741
  this.endParagraph(para, false);
@@ -590,6 +764,7 @@ var ContentBuilder = class {
590
764
  this.openBookmarks.clear();
591
765
  }
592
766
  finish(metadata, section, para) {
767
+ this.discardUnclosedResultScratches();
593
768
  this.endSection(section, para);
594
769
  if (this.sections.length === 0) this.sections.push({
595
770
  ...sectionGeometry(section),
@@ -701,9 +876,50 @@ function defaultPictureState() {
701
876
  binary: []
702
877
  };
703
878
  }
879
+ function objectSizeHintClause(object) {
880
+ const widthTwips = object?.widthTwips;
881
+ const heightTwips = object?.heightTwips;
882
+ if (widthTwips !== void 0 && heightTwips !== void 0) return ` (the object's own \\objw/\\objh declared a ${require_units.twipsToPoints(widthTwips).toFixed(2)}pt x ${require_units.twipsToPoints(heightTwips).toFixed(2)}pt size)`;
883
+ if (widthTwips !== void 0) return ` (the object's own \\objw declared a ${require_units.twipsToPoints(widthTwips).toFixed(2)}pt width)`;
884
+ if (heightTwips !== void 0) return ` (the object's own \\objh declared a ${require_units.twipsToPoints(heightTwips).toFixed(2)}pt height)`;
885
+ return "";
886
+ }
887
+ function objectDataBytes(objectData) {
888
+ return Uint8Array.from(objectData.bytes);
889
+ }
890
+ function buildEmbeddedObject(objectData, object, sink) {
891
+ const bytes = objectDataBytes(objectData);
892
+ if (bytes.length === 0) {
893
+ sink({
894
+ code: require_diagnostics.RtfDiagnosticCodes.EMBEDDED_OBJECT_UNREADABLE,
895
+ severity: "warning",
896
+ message: `an \\object destination's \\objdata carried no payload${objectSizeHintClause(object)}`
897
+ });
898
+ return;
899
+ }
900
+ const embedded = require_embedded_object.readEmbeddedObjectData(bytes);
901
+ if (embedded === void 0) {
902
+ sink({
903
+ code: require_diagnostics.RtfDiagnosticCodes.EMBEDDED_OBJECT_UNREADABLE,
904
+ severity: "warning",
905
+ message: `an \\object destination's \\objdata is not a payload this reader produced (a real OLE object's OLESaveToStream data has no decoder here), so the object is dropped${objectSizeHintClause(object)}; its \\result fallback content, if any, is read in its place`
906
+ });
907
+ return;
908
+ }
909
+ return {
910
+ ...embedded,
911
+ kind: "embeddedObject"
912
+ };
913
+ }
704
914
  function toggleValue(param) {
705
915
  return param === void 0 || param !== 0;
706
916
  }
917
+ function formFieldValueBit(param) {
918
+ return param !== void 0 && param !== 0;
919
+ }
920
+ function formFieldValueNumber(param) {
921
+ return param ?? 0;
922
+ }
707
923
  function readRtfDetail(input, options) {
708
924
  options.signal?.throwIfAborted();
709
925
  const maxInputBytes = options.maxInputBytes ?? 67108864;
@@ -727,8 +943,15 @@ function readRtfDetail(input, options) {
727
943
  para: defaultParagraphState(),
728
944
  field: void 0,
729
945
  picture: void 0,
946
+ pictureOwner: false,
947
+ objectData: void 0,
948
+ object: void 0,
949
+ objectDataOwner: false,
950
+ objectOwner: false,
951
+ resultOf: void 0,
730
952
  bookmark: void 0,
731
- inUnicodeWrapper: false
953
+ inUnicodeWrapper: false,
954
+ isFieldGroup: false
732
955
  };
733
956
  const stack = [root];
734
957
  let state = root;
@@ -756,6 +979,21 @@ function readRtfDetail(input, options) {
756
979
  state.bookmark.name += text;
757
980
  return;
758
981
  }
982
+ if (state.destination === "formFieldName" && state.field?.formField !== void 0) {
983
+ state.field.formField.name += text;
984
+ return;
985
+ }
986
+ if (state.destination === "formFieldHelpText" && state.field?.formField !== void 0) {
987
+ state.field.formField.helpText += text;
988
+ return;
989
+ }
990
+ if (state.destination === "formFieldListItem" && state.field?.formField !== void 0) {
991
+ const items = state.field.formField.listItems;
992
+ const last = items.length - 1;
993
+ const current = items[last];
994
+ if (current !== void 0) items[last] = current + text;
995
+ return;
996
+ }
759
997
  };
760
998
  let index = 0;
761
999
  let textOffset = 0;
@@ -768,7 +1006,24 @@ function readRtfDetail(input, options) {
768
1006
  const known = head.destination === void 0 ? void 0 : DESTINATION_KINDS.get(head.destination);
769
1007
  const isHeaderTable = head.destination !== void 0 && require_header.HEADER_DESTINATIONS.has(head.destination);
770
1008
  const wrapperChild = state.inUnicodeWrapper;
771
- const kind = isHeaderTable || wrapperChild && head.destination !== "ud" ? "skip" : known ?? (head.ignorable ? "skip" : state.destination);
1009
+ const objectState = state.object;
1010
+ const isResultDestination = head.destination === "result" && objectState !== void 0;
1011
+ const isDuplicateResult = isResultDestination && objectState.resultSeen;
1012
+ if (objectState !== void 0 && isResultDestination) objectState.resultSeen = true;
1013
+ if (isDuplicateResult) sink({
1014
+ code: require_diagnostics.RtfDiagnosticCodes.EMBEDDED_OBJECT_UNREADABLE,
1015
+ severity: "warning",
1016
+ message: "an \\object destination has more than one \\result child, which RTF's own grammar does not allow; only the first is kept and this one is discarded"
1017
+ });
1018
+ const isObjectDataDestination = head.destination === "objdata" && known === "objectData";
1019
+ const isDuplicateObjectData = isObjectDataDestination && objectState?.objectDataSeen === true;
1020
+ if (isDuplicateObjectData) sink({
1021
+ code: require_diagnostics.RtfDiagnosticCodes.EMBEDDED_OBJECT_UNREADABLE,
1022
+ severity: "warning",
1023
+ message: "an \\object destination has more than one \\objdata child, which RTF's own grammar does not allow; only the first is decoded and this one is discarded"
1024
+ });
1025
+ else if (isObjectDataDestination && objectState !== void 0) objectState.objectDataSeen = true;
1026
+ const kind = isHeaderTable || wrapperChild && head.destination !== "ud" ? "skip" : isDuplicateObjectData || isDuplicateResult ? "skip" : isResultDestination ? "body" : known ?? (head.ignorable ? "skip" : state.destination);
772
1027
  if (head.destination !== void 0 && !isHeaderTable) {
773
1028
  if (head.ignorable && known === void 0) sink({
774
1029
  code: require_diagnostics.RtfDiagnosticCodes.UNKNOWN_DESTINATION_SKIPPED,
@@ -789,10 +1044,46 @@ function readRtfDetail(input, options) {
789
1044
  if (stack.length >= maxGroupDepth) throw new require_diagnostics.RtfNestingLimitExceededError(maxGroupDepth);
790
1045
  const child = cloneGroupState(state);
791
1046
  child.inUnicodeWrapper = kind === "unicodeWrapper";
1047
+ child.isFieldGroup = head.destination === "field";
792
1048
  if (known !== void 0) {
793
1049
  child.destination = kind;
794
- if (head.destination === "field") child.field = { instruction: "" };
795
- if (kind === "picture") child.picture = defaultPictureState();
1050
+ if (child.isFieldGroup) child.field = {
1051
+ instruction: "",
1052
+ formField: void 0,
1053
+ formFieldStarted: false
1054
+ };
1055
+ if (head.destination === "formfield" && child.field !== void 0) child.field.formField = {
1056
+ name: "",
1057
+ helpText: "",
1058
+ ownHelp: false,
1059
+ listItems: [],
1060
+ resultIndex: void 0,
1061
+ defaultResultIndex: void 0,
1062
+ protectedField: false
1063
+ };
1064
+ if (head.destination === "ffl" && child.field?.formField !== void 0) child.field.formField.listItems.push("");
1065
+ if (kind === "picture") {
1066
+ child.picture = defaultPictureState();
1067
+ child.pictureOwner = true;
1068
+ }
1069
+ if (kind === "objectData") {
1070
+ child.objectData = {
1071
+ bytes: [],
1072
+ pendingHexNibble: void 0
1073
+ };
1074
+ child.objectDataOwner = true;
1075
+ }
1076
+ if (kind === "object") {
1077
+ child.object = {
1078
+ decoded: false,
1079
+ objectDataSeen: false,
1080
+ resultSeen: false,
1081
+ resultBlocks: void 0,
1082
+ widthTwips: void 0,
1083
+ heightTwips: void 0
1084
+ };
1085
+ child.objectOwner = true;
1086
+ }
796
1087
  if (kind === "bookmarkStart" || kind === "bookmarkEnd") child.bookmark = {
797
1088
  name: "",
798
1089
  columnFirst: void 0,
@@ -800,6 +1091,15 @@ function readRtfDetail(input, options) {
800
1091
  };
801
1092
  index = head.contentStart;
802
1093
  } else index += 1;
1094
+ if (objectState !== void 0 && isResultDestination) {
1095
+ builder.beginResultScratch();
1096
+ child.resultOf = objectState;
1097
+ child.object = void 0;
1098
+ child.para = {
1099
+ ...child.para,
1100
+ inTable: false
1101
+ };
1102
+ }
803
1103
  stack.push(child);
804
1104
  state = child;
805
1105
  textOffset = 0;
@@ -807,9 +1107,26 @@ function readRtfDetail(input, options) {
807
1107
  }
808
1108
  if (token.kind === "groupEnd") {
809
1109
  flushBytes();
810
- if (state.destination === "picture" && state.picture !== void 0) {
1110
+ if (state.destination === "picture" && state.picture !== void 0 && state.pictureOwner) {
811
1111
  const image = buildPicture(state.picture, sink);
812
- if (image !== void 0) builder.addBlock(image);
1112
+ if (image !== void 0) builder.addBlocks([image], state.para.inTable);
1113
+ }
1114
+ if (state.destination === "objectData" && state.objectData !== void 0 && state.objectDataOwner) {
1115
+ const embedded = buildEmbeddedObject(state.objectData, state.object, sink);
1116
+ if (embedded !== void 0) {
1117
+ builder.addBlocks([embedded], state.para.inTable);
1118
+ if (state.object !== void 0) state.object.decoded = true;
1119
+ }
1120
+ }
1121
+ if (state.resultOf !== void 0) state.resultOf.resultBlocks = builder.endResultScratch(state.para);
1122
+ if (state.destination === "object" && state.object !== void 0 && state.objectOwner) {
1123
+ const objectState = state.object;
1124
+ if (!objectState.decoded && objectState.resultBlocks !== void 0) builder.addBlocks(objectState.resultBlocks, state.para.inTable);
1125
+ if (!objectState.objectDataSeen) sink({
1126
+ code: require_diagnostics.RtfDiagnosticCodes.EMBEDDED_OBJECT_UNREADABLE,
1127
+ severity: "warning",
1128
+ message: objectState.resultSeen ? "an \\object destination has no \\objdata payload at all; its \\result fallback content is used in its place" : "an \\object destination has neither \\objdata nor \\result content; the whole construct is dropped"
1129
+ });
813
1130
  }
814
1131
  if (state.bookmark !== void 0) {
815
1132
  const bookmark = {
@@ -819,6 +1136,14 @@ function readRtfDetail(input, options) {
819
1136
  if (state.destination === "bookmarkStart") builder.startBookmark(bookmark, state.para);
820
1137
  else if (state.destination === "bookmarkEnd") builder.endBookmark(bookmark.name);
821
1138
  }
1139
+ if (state.destination === "fieldInstruction" && state.field !== void 0 && !state.field.formFieldStarted && require_constructs.formFieldControlType(state.field.instruction) !== void 0) {
1140
+ builder.startFormField();
1141
+ state.field.formFieldStarted = true;
1142
+ }
1143
+ if (state.isFieldGroup && state.field?.formFieldStarted === true) {
1144
+ const descriptor = require_constructs.formFieldContentControl(state.field.instruction, state.field.formField);
1145
+ builder.endFormField(descriptor);
1146
+ }
822
1147
  if (stack.length > 1) {
823
1148
  stack.pop();
824
1149
  const parent = stack[stack.length - 1];
@@ -836,6 +1161,7 @@ function readRtfDetail(input, options) {
836
1161
  if (token.kind === "text") {
837
1162
  const slice = textOffset === 0 ? token.bytes : token.bytes.subarray(textOffset);
838
1163
  if (state.destination === "picture" && state.picture !== void 0) state.picture.hex += require_bytes.asciiStringFromBytes(slice);
1164
+ else if (state.destination === "objectData" && state.objectData !== void 0) appendObjectDataHexText(state.objectData, require_bytes.asciiStringFromBytes(slice));
839
1165
  else require_bytes.appendBytes(pendingBytes, slice);
840
1166
  index += 1;
841
1167
  textOffset = 0;
@@ -843,11 +1169,13 @@ function readRtfDetail(input, options) {
843
1169
  }
844
1170
  if (token.kind === "binary") {
845
1171
  if (state.destination === "picture" && state.picture !== void 0) require_bytes.appendBytes(state.picture.binary, token.bytes);
1172
+ else if (state.destination === "objectData" && state.objectData !== void 0) require_bytes.appendBytes(state.objectData.bytes, token.bytes);
846
1173
  index += 1;
847
1174
  continue;
848
1175
  }
849
1176
  if (token.kind === "hex") {
850
1177
  if (state.destination === "picture" && state.picture !== void 0) state.picture.binary.push(token.byte);
1178
+ else if (state.destination === "objectData" && state.objectData !== void 0) state.objectData.bytes.push(token.byte);
851
1179
  else pendingBytes.push(token.byte);
852
1180
  index += 1;
853
1181
  continue;
@@ -936,6 +1264,23 @@ function applyPictureControlWord(name, param, picture) {
936
1264
  default: return;
937
1265
  }
938
1266
  }
1267
+ function applyFormFieldControlWord(name, param, formField) {
1268
+ switch (name) {
1269
+ case "ffres":
1270
+ formField.resultIndex = formFieldValueNumber(param);
1271
+ return true;
1272
+ case "ffdefres":
1273
+ formField.defaultResultIndex = formFieldValueNumber(param);
1274
+ return true;
1275
+ case "ffprot":
1276
+ formField.protectedField = formFieldValueBit(param);
1277
+ return true;
1278
+ case "ffownhelp":
1279
+ formField.ownHelp = toggleValue(param);
1280
+ return true;
1281
+ default: return false;
1282
+ }
1283
+ }
939
1284
  function applyCharacterControlWord(name, param, state, header) {
940
1285
  switch (name) {
941
1286
  case "plain":
@@ -1171,7 +1516,7 @@ function applyStructureControlWord(name, param, state, builder, section, sink) {
1171
1516
  return true;
1172
1517
  case "page":
1173
1518
  builder.endParagraph(state.para, false);
1174
- builder.addBlock({ kind: "pageBreak" });
1519
+ builder.addBlocks([{ kind: "pageBreak" }], state.para.inTable);
1175
1520
  return true;
1176
1521
  case "sect":
1177
1522
  builder.endParagraph(state.para, true);
@@ -1186,6 +1531,12 @@ function applyControlWord(name, param, state, builder, header, section, sink) {
1186
1531
  applyPictureControlWord(name, param, picture);
1187
1532
  return;
1188
1533
  }
1534
+ const object = state.object;
1535
+ if (state.destination === "object" && object !== void 0) {
1536
+ if (name === "objw") object.widthTwips = param;
1537
+ else if (name === "objh") object.heightTwips = param;
1538
+ return;
1539
+ }
1189
1540
  const bookmark = state.bookmark;
1190
1541
  if (bookmark !== void 0 && state.destination === "bookmarkStart") {
1191
1542
  if (name === "bkmkcolf") bookmark.columnFirst = param;
@@ -1193,6 +1544,9 @@ function applyControlWord(name, param, state, builder, header, section, sink) {
1193
1544
  return;
1194
1545
  }
1195
1546
  if (state.destination === "bookmarkEnd") return;
1547
+ const formField = state.field?.formField;
1548
+ if (state.destination === "formField" && formField !== void 0 && applyFormFieldControlWord(name, param, formField)) return;
1549
+ if (state.destination === "formField" || state.destination === "formFieldName" || state.destination === "formFieldHelpText" || state.destination === "formFieldListItem") return;
1196
1550
  if (applyCharacterControlWord(name, param, state, header)) return;
1197
1551
  if (builder.applyCellDefinition(name, param)) return;
1198
1552
  if (applyParagraphControlWord(name, param, state)) return;
package/dist/read.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as RtfDiagnostic } from "./diagnostics-BgG_KAiN.cjs";
1
+ import { n as RtfDiagnostic } from "./diagnostics-CjMoO7x1.cjs";
2
2
  import { ReadRtfOptions } from "./options.cjs";
3
3
  import { ContentDocument, DocumentTree } from "document-schema.js";
4
4
  //#region src/read.d.ts
package/dist/read.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as RtfDiagnostic } from "./diagnostics-BgG_KAiN.js";
1
+ import { n as RtfDiagnostic } from "./diagnostics-CjMoO7x1.js";
2
2
  import { ReadRtfOptions } from "./options.js";
3
3
  import { ContentDocument, DocumentTree } from "document-schema.js";
4
4
  //#region src/read.d.ts