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/README.md +90 -45
- package/dist/base64.d.cts +1 -1
- package/dist/base64.d.ts +1 -1
- package/dist/codepage.d.cts +1 -1
- package/dist/codepage.d.ts +1 -1
- package/dist/constructs.cjs +35 -0
- package/dist/constructs.d.cts +13 -2
- package/dist/constructs.d.ts +13 -2
- package/dist/constructs.js +34 -1
- package/dist/{diagnostics-BgG_KAiN.d.cts → diagnostics-CjMoO7x1.d.cts} +3 -1
- package/dist/{diagnostics-BgG_KAiN.d.ts → diagnostics-CjMoO7x1.d.ts} +3 -1
- package/dist/diagnostics.cjs +3 -1
- package/dist/diagnostics.d.cts +1 -1
- package/dist/diagnostics.d.ts +1 -1
- package/dist/diagnostics.js +3 -1
- package/dist/embedded-object.cjs +215 -0
- package/dist/embedded-object.d.cts +6 -0
- package/dist/embedded-object.d.ts +6 -0
- package/dist/embedded-object.js +213 -0
- package/dist/header.d.cts +1 -1
- package/dist/header.d.ts +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/options.d.cts +1 -1
- package/dist/options.d.ts +1 -1
- package/dist/read.cjs +367 -13
- package/dist/read.d.cts +1 -1
- package/dist/read.d.ts +1 -1
- package/dist/read.js +368 -14
- package/dist/write.cjs +241 -17
- package/dist/write.js +241 -17
- package/package.json +2 -1
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", "
|
|
51
|
-
["objdata", "
|
|
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
|
-
"
|
|
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
|
-
|
|
668
|
+
addBlocks(blocks, inTable) {
|
|
669
|
+
if (blocks.length === 0) return;
|
|
563
670
|
this.flushRun();
|
|
564
|
-
this.blocks.push(
|
|
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
|
|
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 (
|
|
795
|
-
|
|
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.
|
|
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.
|
|
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-
|
|
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-
|
|
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
|