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/diagnostics.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-
|
|
1
|
+
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-CjMoO7x1.cjs";
|
|
2
2
|
export { NOOP_RTF_DIAGNOSTIC_SINK, RtfDiagnostic, RtfDiagnosticCodes, RtfDiagnosticSeverity, RtfDiagnosticSink, RtfInputTooLargeError, RtfNestingLimitExceededError, RtfNotAnRtfDocumentError, RtfParseError, RtfUnsupportedDocumentKindError, RtfWriteError };
|
package/dist/diagnostics.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-
|
|
1
|
+
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-CjMoO7x1.js";
|
|
2
2
|
export { NOOP_RTF_DIAGNOSTIC_SINK, RtfDiagnostic, RtfDiagnosticCodes, RtfDiagnosticSeverity, RtfDiagnosticSink, RtfInputTooLargeError, RtfNestingLimitExceededError, RtfNotAnRtfDocumentError, RtfParseError, RtfUnsupportedDocumentKindError, RtfWriteError };
|
package/dist/diagnostics.js
CHANGED
|
@@ -7,13 +7,15 @@ const RtfDiagnosticCodes = {
|
|
|
7
7
|
UNSUPPORTED_CODEPAGE: "rtf/unsupported-codepage",
|
|
8
8
|
UNSUPPORTED_PICTURE_FORMAT: "rtf/unsupported-picture-format",
|
|
9
9
|
PICTURE_SIZE_UNSTATED: "rtf/picture-size-unstated",
|
|
10
|
+
EMBEDDED_OBJECT_UNREADABLE: "rtf/embedded-object-unreadable",
|
|
10
11
|
TABLE_ROW_WITHOUT_DEFINITION: "rtf/table-row-without-definition",
|
|
11
12
|
TABLE_COLUMN_WIDTH_INVALID: "rtf/table-column-width-invalid",
|
|
12
13
|
NESTED_TABLE_FLATTENED: "rtf/nested-table-flattened",
|
|
13
14
|
SECTION_BREAK_UNREPRESENTED: "rtf/section-break-unrepresented",
|
|
14
15
|
BOOKMARK_UNPAIRED: "rtf/bookmark-unpaired",
|
|
16
|
+
FORM_FIELD_SPAN_DROPPED: "rtf/form-field-span-dropped",
|
|
17
|
+
FORM_FIELD_KEYWORD_LOST: "rtf/form-field-keyword-lost",
|
|
15
18
|
CONSTRUCT_UNREPRESENTED: "rtf/construct-unrepresented",
|
|
16
|
-
EMBEDDED_OBJECT_DROPPED: "rtf/embedded-object-dropped",
|
|
17
19
|
PACKAGE_TABLE_DROPPED: "rtf/package-table-dropped"
|
|
18
20
|
};
|
|
19
21
|
var RtfParseError = class extends Error {
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let document_schema_js = require("document-schema.js");
|
|
3
|
+
let archive_codec = require("archive-codec");
|
|
4
|
+
//#region src/embedded-object.ts
|
|
5
|
+
const PACKAGE_LABEL = "rtf-codec-embedded-object.json";
|
|
6
|
+
const OBJECT_HEADER_FORMAT_ID_EMBEDDED = 2;
|
|
7
|
+
const OBJECT_HEADER_FORMAT_ID_LINKED = 1;
|
|
8
|
+
const OBJECT_HEADER_OLE_VERSION = 1281;
|
|
9
|
+
const OBJECT_HEADER_CLASS_NAME = "Package";
|
|
10
|
+
const ANSI_DECODER = new TextDecoder("windows-1252");
|
|
11
|
+
const PRESENTATION_OBJECT_HEADER_FORMAT_ID = 5;
|
|
12
|
+
const PRESENTATION_CLASS_NAME = "";
|
|
13
|
+
const CLIPBOARD_FORMAT_CF_DIB = 8;
|
|
14
|
+
const DIB_HEADER_SIZE_BITMAPINFOHEADER = 40;
|
|
15
|
+
const DIB_BIT_COUNT_MONOCHROME = 1;
|
|
16
|
+
function writeLengthPrefixedAnsiString(value) {
|
|
17
|
+
if (value.length === 0) return /* @__PURE__ */ new Uint8Array(4);
|
|
18
|
+
for (let index = 0; index < value.length; index++) {
|
|
19
|
+
const code = value.charCodeAt(index);
|
|
20
|
+
if (code > 127) throw new Error(`ObjectHeader string contains a character (U+${code.toString(16).padStart(4, "0")}) outside ASCII; encoding it to an arbitrary windows-1252 byte would need a full codepage table this module does not carry`);
|
|
21
|
+
}
|
|
22
|
+
const length = value.length + 1;
|
|
23
|
+
const out = new Uint8Array(4 + length);
|
|
24
|
+
new DataView(out.buffer).setUint32(0, length, true);
|
|
25
|
+
for (let index = 0; index < value.length; index++) out[4 + index] = value.charCodeAt(index);
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
function readLengthPrefixedAnsiString(bytes, offset, fieldName) {
|
|
29
|
+
if (offset + 4 > bytes.length) throw new Error(`ObjectHeader ends before its ${fieldName} length field`);
|
|
30
|
+
const length = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(offset, true);
|
|
31
|
+
offset += 4;
|
|
32
|
+
if (length === 0) return {
|
|
33
|
+
value: "",
|
|
34
|
+
next: offset
|
|
35
|
+
};
|
|
36
|
+
if (offset + length > bytes.length) throw new Error(`ObjectHeader's ${fieldName} declares ${length} bytes but only ${bytes.length - offset} remain`);
|
|
37
|
+
return {
|
|
38
|
+
value: ANSI_DECODER.decode(bytes.subarray(offset, offset + length - 1)),
|
|
39
|
+
next: offset + length
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function writeObjectHeader() {
|
|
43
|
+
const classNameBytes = writeLengthPrefixedAnsiString(OBJECT_HEADER_CLASS_NAME);
|
|
44
|
+
const topicNameBytes = writeLengthPrefixedAnsiString("");
|
|
45
|
+
const itemNameBytes = writeLengthPrefixedAnsiString("");
|
|
46
|
+
const out = new Uint8Array(8 + classNameBytes.length + topicNameBytes.length + itemNameBytes.length);
|
|
47
|
+
const view = new DataView(out.buffer);
|
|
48
|
+
view.setUint32(0, OBJECT_HEADER_OLE_VERSION, true);
|
|
49
|
+
view.setUint32(4, OBJECT_HEADER_FORMAT_ID_EMBEDDED, true);
|
|
50
|
+
let offset = 8;
|
|
51
|
+
out.set(classNameBytes, offset);
|
|
52
|
+
offset += classNameBytes.length;
|
|
53
|
+
out.set(topicNameBytes, offset);
|
|
54
|
+
offset += topicNameBytes.length;
|
|
55
|
+
out.set(itemNameBytes, offset);
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
function readObjectHeader(bytes) {
|
|
59
|
+
if (bytes.length < 8) throw new Error("ObjectHeader ends before its FormatID field");
|
|
60
|
+
const formatId = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(4, true);
|
|
61
|
+
let offset = 8;
|
|
62
|
+
offset = readLengthPrefixedAnsiString(bytes, offset, "ClassName").next;
|
|
63
|
+
offset = readLengthPrefixedAnsiString(bytes, offset, "TopicName").next;
|
|
64
|
+
offset = readLengthPrefixedAnsiString(bytes, offset, "ItemName").next;
|
|
65
|
+
return {
|
|
66
|
+
formatId,
|
|
67
|
+
next: offset
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function writeMinimalDib() {
|
|
71
|
+
const width = 1;
|
|
72
|
+
const height = 1;
|
|
73
|
+
const colorCount = 2;
|
|
74
|
+
const out = new Uint8Array(48 + 4 * Math.abs(height));
|
|
75
|
+
const view = new DataView(out.buffer);
|
|
76
|
+
view.setUint32(0, DIB_HEADER_SIZE_BITMAPINFOHEADER, true);
|
|
77
|
+
view.setInt32(4, width, true);
|
|
78
|
+
view.setInt32(8, height, true);
|
|
79
|
+
view.setUint16(12, 1, true);
|
|
80
|
+
view.setUint16(14, DIB_BIT_COUNT_MONOCHROME, true);
|
|
81
|
+
view.setUint32(16, 0, true);
|
|
82
|
+
view.setUint32(20, 0, true);
|
|
83
|
+
view.setInt32(24, 0, true);
|
|
84
|
+
view.setInt32(28, 0, true);
|
|
85
|
+
view.setUint32(32, colorCount, true);
|
|
86
|
+
view.setUint32(36, 0, true);
|
|
87
|
+
out.set([
|
|
88
|
+
0,
|
|
89
|
+
0,
|
|
90
|
+
0,
|
|
91
|
+
0
|
|
92
|
+
], DIB_HEADER_SIZE_BITMAPINFOHEADER);
|
|
93
|
+
out.set([
|
|
94
|
+
255,
|
|
95
|
+
255,
|
|
96
|
+
255,
|
|
97
|
+
0
|
|
98
|
+
], 44);
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
function writePresentationObjectHeader() {
|
|
102
|
+
const classNameBytes = writeLengthPrefixedAnsiString(PRESENTATION_CLASS_NAME);
|
|
103
|
+
const out = new Uint8Array(8 + classNameBytes.length);
|
|
104
|
+
const view = new DataView(out.buffer);
|
|
105
|
+
view.setUint32(0, OBJECT_HEADER_OLE_VERSION, true);
|
|
106
|
+
view.setUint32(4, PRESENTATION_OBJECT_HEADER_FORMAT_ID, true);
|
|
107
|
+
out.set(classNameBytes, 8);
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
function writeClipboardFormatHeader() {
|
|
111
|
+
const headerBytes = writePresentationObjectHeader();
|
|
112
|
+
const out = new Uint8Array(headerBytes.length + 4);
|
|
113
|
+
out.set(headerBytes, 0);
|
|
114
|
+
new DataView(out.buffer).setUint32(headerBytes.length, CLIPBOARD_FORMAT_CF_DIB, true);
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
function writePresentationObject() {
|
|
118
|
+
const headerBytes = writeClipboardFormatHeader();
|
|
119
|
+
const dib = writeMinimalDib();
|
|
120
|
+
const out = new Uint8Array(headerBytes.length + 4 + dib.length);
|
|
121
|
+
out.set(headerBytes, 0);
|
|
122
|
+
new DataView(out.buffer).setUint32(headerBytes.length, dib.length, true);
|
|
123
|
+
out.set(dib, headerBytes.length + 4);
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
function skipPresentationObjectHeader(bytes, offset) {
|
|
127
|
+
if (offset + 8 > bytes.length) throw new Error("the Presentation field ends before its PresentationObjectHeader's FormatID");
|
|
128
|
+
const formatId = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(offset + 4, true);
|
|
129
|
+
if (formatId !== PRESENTATION_OBJECT_HEADER_FORMAT_ID) throw new Error(`PresentationObjectHeader.FormatID is 0x${formatId.toString(16).padStart(8, "0")}, not the 0x00000005 this module's own Presentation field always writes`);
|
|
130
|
+
return readLengthPrefixedAnsiString(bytes, offset + 8, "PresentationObjectHeader.ClassName").next;
|
|
131
|
+
}
|
|
132
|
+
function skipClipboardFormatHeader(bytes, offset) {
|
|
133
|
+
const afterHeader = skipPresentationObjectHeader(bytes, offset);
|
|
134
|
+
if (afterHeader + 4 > bytes.length) throw new Error("ClipboardFormatHeader ends before its ClipboardFormat field");
|
|
135
|
+
const clipboardFormat = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(afterHeader, true);
|
|
136
|
+
if (clipboardFormat !== CLIPBOARD_FORMAT_CF_DIB) throw new Error(`ClipboardFormatHeader.ClipboardFormat is 0x${clipboardFormat.toString(16).padStart(8, "0")}, not the CF_DIB (0x00000008) this module's own Presentation field always writes`);
|
|
137
|
+
return afterHeader + 4;
|
|
138
|
+
}
|
|
139
|
+
function skipPresentationObject(bytes, offset) {
|
|
140
|
+
const afterHeader = skipClipboardFormatHeader(bytes, offset);
|
|
141
|
+
if (afterHeader + 4 > bytes.length) throw new Error("StandardClipboardFormatPresentationObject ends before its PresentationDataSize field");
|
|
142
|
+
const presentationDataSize = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(afterHeader, true);
|
|
143
|
+
const dataStart = afterHeader + 4;
|
|
144
|
+
if (dataStart + presentationDataSize > bytes.length) throw new Error(`StandardClipboardFormatPresentationObject's PresentationDataSize declares ${String(presentationDataSize)} bytes but only ${String(bytes.length - dataStart)} remain`);
|
|
145
|
+
return dataStart + presentationDataSize;
|
|
146
|
+
}
|
|
147
|
+
function writeEmbeddedObjectData(embedded) {
|
|
148
|
+
const payload = {
|
|
149
|
+
objectKind: embedded.objectKind,
|
|
150
|
+
document: embedded.document,
|
|
151
|
+
frame: embedded.frame,
|
|
152
|
+
anchorRow: embedded.anchorRow,
|
|
153
|
+
anchorColumn: embedded.anchorColumn,
|
|
154
|
+
offsetXPt: embedded.offsetXPt,
|
|
155
|
+
offsetYPt: embedded.offsetYPt,
|
|
156
|
+
source: embedded.source
|
|
157
|
+
};
|
|
158
|
+
const fileBytes = new TextEncoder().encode(JSON.stringify(payload));
|
|
159
|
+
const packageBytes = (0, archive_codec.writeOlePackage)({
|
|
160
|
+
label: PACKAGE_LABEL,
|
|
161
|
+
sourcePath: "",
|
|
162
|
+
tempPath: "",
|
|
163
|
+
fileBytes
|
|
164
|
+
});
|
|
165
|
+
const nativeData = (0, archive_codec.writeCompoundFile)([{
|
|
166
|
+
path: "Package",
|
|
167
|
+
bytes: packageBytes
|
|
168
|
+
}]);
|
|
169
|
+
const headerBytes = writeObjectHeader();
|
|
170
|
+
const presentationBytes = writePresentationObject();
|
|
171
|
+
const out = new Uint8Array(headerBytes.length + 4 + nativeData.length + presentationBytes.length);
|
|
172
|
+
out.set(headerBytes, 0);
|
|
173
|
+
new DataView(out.buffer).setUint32(headerBytes.length, nativeData.length, true);
|
|
174
|
+
out.set(nativeData, headerBytes.length + 4);
|
|
175
|
+
out.set(presentationBytes, headerBytes.length + 4 + nativeData.length);
|
|
176
|
+
return out;
|
|
177
|
+
}
|
|
178
|
+
function knownContentEmbeddedObjectFields(embedded) {
|
|
179
|
+
const source = document_schema_js.SourceResidueSchema.safeParse(embedded.source);
|
|
180
|
+
return {
|
|
181
|
+
objectKind: embedded.objectKind,
|
|
182
|
+
document: embedded.document,
|
|
183
|
+
frame: embedded.frame,
|
|
184
|
+
...embedded.anchorRow === void 0 ? {} : { anchorRow: embedded.anchorRow },
|
|
185
|
+
...embedded.anchorColumn === void 0 ? {} : { anchorColumn: embedded.anchorColumn },
|
|
186
|
+
...embedded.offsetXPt === void 0 ? {} : { offsetXPt: embedded.offsetXPt },
|
|
187
|
+
...embedded.offsetYPt === void 0 ? {} : { offsetYPt: embedded.offsetYPt },
|
|
188
|
+
...source.success ? { source: source.data } : {}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function readEmbeddedObjectData(bytes) {
|
|
192
|
+
try {
|
|
193
|
+
const header = readObjectHeader(bytes);
|
|
194
|
+
if (header.formatId !== OBJECT_HEADER_FORMAT_ID_EMBEDDED && header.formatId !== OBJECT_HEADER_FORMAT_ID_LINKED) return;
|
|
195
|
+
if (header.next + 4 > bytes.length) return;
|
|
196
|
+
const nativeDataSize = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(header.next, true);
|
|
197
|
+
const nativeDataStart = header.next + 4;
|
|
198
|
+
if (nativeDataStart + nativeDataSize > bytes.length) return;
|
|
199
|
+
const nativeData = bytes.subarray(nativeDataStart, nativeDataStart + nativeDataSize);
|
|
200
|
+
const packageStream = (0, archive_codec.readCompoundFile)(nativeData).find((stream) => stream.path === "Package");
|
|
201
|
+
if (packageStream === void 0) return;
|
|
202
|
+
const olePackage = (0, archive_codec.readOlePackage)(packageStream.bytes);
|
|
203
|
+
const text = new TextDecoder("utf-8").decode(olePackage.fileBytes);
|
|
204
|
+
const parsed = JSON.parse(text);
|
|
205
|
+
const result = document_schema_js.ContentEmbeddedObjectSchema.safeParse(parsed);
|
|
206
|
+
if (!result.success) return;
|
|
207
|
+
skipPresentationObject(bytes, nativeDataStart + nativeDataSize);
|
|
208
|
+
return knownContentEmbeddedObjectFields(result.data);
|
|
209
|
+
} catch {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
//#endregion
|
|
214
|
+
exports.readEmbeddedObjectData = readEmbeddedObjectData;
|
|
215
|
+
exports.writeEmbeddedObjectData = writeEmbeddedObjectData;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ContentEmbeddedObject } from "document-schema.js";
|
|
2
|
+
//#region src/embedded-object.d.ts
|
|
3
|
+
declare function writeEmbeddedObjectData(embedded: ContentEmbeddedObject): Uint8Array<ArrayBuffer>;
|
|
4
|
+
declare function readEmbeddedObjectData(bytes: Uint8Array<ArrayBuffer>): ContentEmbeddedObject | undefined;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { readEmbeddedObjectData, writeEmbeddedObjectData };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ContentEmbeddedObject } from "document-schema.js";
|
|
2
|
+
//#region src/embedded-object.d.ts
|
|
3
|
+
declare function writeEmbeddedObjectData(embedded: ContentEmbeddedObject): Uint8Array<ArrayBuffer>;
|
|
4
|
+
declare function readEmbeddedObjectData(bytes: Uint8Array<ArrayBuffer>): ContentEmbeddedObject | undefined;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { readEmbeddedObjectData, writeEmbeddedObjectData };
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { ContentEmbeddedObjectSchema, SourceResidueSchema } from "document-schema.js";
|
|
2
|
+
import { readCompoundFile, readOlePackage, writeCompoundFile, writeOlePackage } from "archive-codec";
|
|
3
|
+
//#region src/embedded-object.ts
|
|
4
|
+
const PACKAGE_LABEL = "rtf-codec-embedded-object.json";
|
|
5
|
+
const OBJECT_HEADER_FORMAT_ID_EMBEDDED = 2;
|
|
6
|
+
const OBJECT_HEADER_FORMAT_ID_LINKED = 1;
|
|
7
|
+
const OBJECT_HEADER_OLE_VERSION = 1281;
|
|
8
|
+
const OBJECT_HEADER_CLASS_NAME = "Package";
|
|
9
|
+
const ANSI_DECODER = new TextDecoder("windows-1252");
|
|
10
|
+
const PRESENTATION_OBJECT_HEADER_FORMAT_ID = 5;
|
|
11
|
+
const PRESENTATION_CLASS_NAME = "";
|
|
12
|
+
const CLIPBOARD_FORMAT_CF_DIB = 8;
|
|
13
|
+
const DIB_HEADER_SIZE_BITMAPINFOHEADER = 40;
|
|
14
|
+
const DIB_BIT_COUNT_MONOCHROME = 1;
|
|
15
|
+
function writeLengthPrefixedAnsiString(value) {
|
|
16
|
+
if (value.length === 0) return /* @__PURE__ */ new Uint8Array(4);
|
|
17
|
+
for (let index = 0; index < value.length; index++) {
|
|
18
|
+
const code = value.charCodeAt(index);
|
|
19
|
+
if (code > 127) throw new Error(`ObjectHeader string contains a character (U+${code.toString(16).padStart(4, "0")}) outside ASCII; encoding it to an arbitrary windows-1252 byte would need a full codepage table this module does not carry`);
|
|
20
|
+
}
|
|
21
|
+
const length = value.length + 1;
|
|
22
|
+
const out = new Uint8Array(4 + length);
|
|
23
|
+
new DataView(out.buffer).setUint32(0, length, true);
|
|
24
|
+
for (let index = 0; index < value.length; index++) out[4 + index] = value.charCodeAt(index);
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
function readLengthPrefixedAnsiString(bytes, offset, fieldName) {
|
|
28
|
+
if (offset + 4 > bytes.length) throw new Error(`ObjectHeader ends before its ${fieldName} length field`);
|
|
29
|
+
const length = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(offset, true);
|
|
30
|
+
offset += 4;
|
|
31
|
+
if (length === 0) return {
|
|
32
|
+
value: "",
|
|
33
|
+
next: offset
|
|
34
|
+
};
|
|
35
|
+
if (offset + length > bytes.length) throw new Error(`ObjectHeader's ${fieldName} declares ${length} bytes but only ${bytes.length - offset} remain`);
|
|
36
|
+
return {
|
|
37
|
+
value: ANSI_DECODER.decode(bytes.subarray(offset, offset + length - 1)),
|
|
38
|
+
next: offset + length
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function writeObjectHeader() {
|
|
42
|
+
const classNameBytes = writeLengthPrefixedAnsiString(OBJECT_HEADER_CLASS_NAME);
|
|
43
|
+
const topicNameBytes = writeLengthPrefixedAnsiString("");
|
|
44
|
+
const itemNameBytes = writeLengthPrefixedAnsiString("");
|
|
45
|
+
const out = new Uint8Array(8 + classNameBytes.length + topicNameBytes.length + itemNameBytes.length);
|
|
46
|
+
const view = new DataView(out.buffer);
|
|
47
|
+
view.setUint32(0, OBJECT_HEADER_OLE_VERSION, true);
|
|
48
|
+
view.setUint32(4, OBJECT_HEADER_FORMAT_ID_EMBEDDED, true);
|
|
49
|
+
let offset = 8;
|
|
50
|
+
out.set(classNameBytes, offset);
|
|
51
|
+
offset += classNameBytes.length;
|
|
52
|
+
out.set(topicNameBytes, offset);
|
|
53
|
+
offset += topicNameBytes.length;
|
|
54
|
+
out.set(itemNameBytes, offset);
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
function readObjectHeader(bytes) {
|
|
58
|
+
if (bytes.length < 8) throw new Error("ObjectHeader ends before its FormatID field");
|
|
59
|
+
const formatId = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(4, true);
|
|
60
|
+
let offset = 8;
|
|
61
|
+
offset = readLengthPrefixedAnsiString(bytes, offset, "ClassName").next;
|
|
62
|
+
offset = readLengthPrefixedAnsiString(bytes, offset, "TopicName").next;
|
|
63
|
+
offset = readLengthPrefixedAnsiString(bytes, offset, "ItemName").next;
|
|
64
|
+
return {
|
|
65
|
+
formatId,
|
|
66
|
+
next: offset
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function writeMinimalDib() {
|
|
70
|
+
const width = 1;
|
|
71
|
+
const height = 1;
|
|
72
|
+
const colorCount = 2;
|
|
73
|
+
const out = new Uint8Array(48 + 4 * Math.abs(height));
|
|
74
|
+
const view = new DataView(out.buffer);
|
|
75
|
+
view.setUint32(0, DIB_HEADER_SIZE_BITMAPINFOHEADER, true);
|
|
76
|
+
view.setInt32(4, width, true);
|
|
77
|
+
view.setInt32(8, height, true);
|
|
78
|
+
view.setUint16(12, 1, true);
|
|
79
|
+
view.setUint16(14, DIB_BIT_COUNT_MONOCHROME, true);
|
|
80
|
+
view.setUint32(16, 0, true);
|
|
81
|
+
view.setUint32(20, 0, true);
|
|
82
|
+
view.setInt32(24, 0, true);
|
|
83
|
+
view.setInt32(28, 0, true);
|
|
84
|
+
view.setUint32(32, colorCount, true);
|
|
85
|
+
view.setUint32(36, 0, true);
|
|
86
|
+
out.set([
|
|
87
|
+
0,
|
|
88
|
+
0,
|
|
89
|
+
0,
|
|
90
|
+
0
|
|
91
|
+
], DIB_HEADER_SIZE_BITMAPINFOHEADER);
|
|
92
|
+
out.set([
|
|
93
|
+
255,
|
|
94
|
+
255,
|
|
95
|
+
255,
|
|
96
|
+
0
|
|
97
|
+
], 44);
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
function writePresentationObjectHeader() {
|
|
101
|
+
const classNameBytes = writeLengthPrefixedAnsiString(PRESENTATION_CLASS_NAME);
|
|
102
|
+
const out = new Uint8Array(8 + classNameBytes.length);
|
|
103
|
+
const view = new DataView(out.buffer);
|
|
104
|
+
view.setUint32(0, OBJECT_HEADER_OLE_VERSION, true);
|
|
105
|
+
view.setUint32(4, PRESENTATION_OBJECT_HEADER_FORMAT_ID, true);
|
|
106
|
+
out.set(classNameBytes, 8);
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
function writeClipboardFormatHeader() {
|
|
110
|
+
const headerBytes = writePresentationObjectHeader();
|
|
111
|
+
const out = new Uint8Array(headerBytes.length + 4);
|
|
112
|
+
out.set(headerBytes, 0);
|
|
113
|
+
new DataView(out.buffer).setUint32(headerBytes.length, CLIPBOARD_FORMAT_CF_DIB, true);
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
function writePresentationObject() {
|
|
117
|
+
const headerBytes = writeClipboardFormatHeader();
|
|
118
|
+
const dib = writeMinimalDib();
|
|
119
|
+
const out = new Uint8Array(headerBytes.length + 4 + dib.length);
|
|
120
|
+
out.set(headerBytes, 0);
|
|
121
|
+
new DataView(out.buffer).setUint32(headerBytes.length, dib.length, true);
|
|
122
|
+
out.set(dib, headerBytes.length + 4);
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
function skipPresentationObjectHeader(bytes, offset) {
|
|
126
|
+
if (offset + 8 > bytes.length) throw new Error("the Presentation field ends before its PresentationObjectHeader's FormatID");
|
|
127
|
+
const formatId = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(offset + 4, true);
|
|
128
|
+
if (formatId !== PRESENTATION_OBJECT_HEADER_FORMAT_ID) throw new Error(`PresentationObjectHeader.FormatID is 0x${formatId.toString(16).padStart(8, "0")}, not the 0x00000005 this module's own Presentation field always writes`);
|
|
129
|
+
return readLengthPrefixedAnsiString(bytes, offset + 8, "PresentationObjectHeader.ClassName").next;
|
|
130
|
+
}
|
|
131
|
+
function skipClipboardFormatHeader(bytes, offset) {
|
|
132
|
+
const afterHeader = skipPresentationObjectHeader(bytes, offset);
|
|
133
|
+
if (afterHeader + 4 > bytes.length) throw new Error("ClipboardFormatHeader ends before its ClipboardFormat field");
|
|
134
|
+
const clipboardFormat = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(afterHeader, true);
|
|
135
|
+
if (clipboardFormat !== CLIPBOARD_FORMAT_CF_DIB) throw new Error(`ClipboardFormatHeader.ClipboardFormat is 0x${clipboardFormat.toString(16).padStart(8, "0")}, not the CF_DIB (0x00000008) this module's own Presentation field always writes`);
|
|
136
|
+
return afterHeader + 4;
|
|
137
|
+
}
|
|
138
|
+
function skipPresentationObject(bytes, offset) {
|
|
139
|
+
const afterHeader = skipClipboardFormatHeader(bytes, offset);
|
|
140
|
+
if (afterHeader + 4 > bytes.length) throw new Error("StandardClipboardFormatPresentationObject ends before its PresentationDataSize field");
|
|
141
|
+
const presentationDataSize = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(afterHeader, true);
|
|
142
|
+
const dataStart = afterHeader + 4;
|
|
143
|
+
if (dataStart + presentationDataSize > bytes.length) throw new Error(`StandardClipboardFormatPresentationObject's PresentationDataSize declares ${String(presentationDataSize)} bytes but only ${String(bytes.length - dataStart)} remain`);
|
|
144
|
+
return dataStart + presentationDataSize;
|
|
145
|
+
}
|
|
146
|
+
function writeEmbeddedObjectData(embedded) {
|
|
147
|
+
const payload = {
|
|
148
|
+
objectKind: embedded.objectKind,
|
|
149
|
+
document: embedded.document,
|
|
150
|
+
frame: embedded.frame,
|
|
151
|
+
anchorRow: embedded.anchorRow,
|
|
152
|
+
anchorColumn: embedded.anchorColumn,
|
|
153
|
+
offsetXPt: embedded.offsetXPt,
|
|
154
|
+
offsetYPt: embedded.offsetYPt,
|
|
155
|
+
source: embedded.source
|
|
156
|
+
};
|
|
157
|
+
const fileBytes = new TextEncoder().encode(JSON.stringify(payload));
|
|
158
|
+
const packageBytes = writeOlePackage({
|
|
159
|
+
label: PACKAGE_LABEL,
|
|
160
|
+
sourcePath: "",
|
|
161
|
+
tempPath: "",
|
|
162
|
+
fileBytes
|
|
163
|
+
});
|
|
164
|
+
const nativeData = writeCompoundFile([{
|
|
165
|
+
path: "Package",
|
|
166
|
+
bytes: packageBytes
|
|
167
|
+
}]);
|
|
168
|
+
const headerBytes = writeObjectHeader();
|
|
169
|
+
const presentationBytes = writePresentationObject();
|
|
170
|
+
const out = new Uint8Array(headerBytes.length + 4 + nativeData.length + presentationBytes.length);
|
|
171
|
+
out.set(headerBytes, 0);
|
|
172
|
+
new DataView(out.buffer).setUint32(headerBytes.length, nativeData.length, true);
|
|
173
|
+
out.set(nativeData, headerBytes.length + 4);
|
|
174
|
+
out.set(presentationBytes, headerBytes.length + 4 + nativeData.length);
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
function knownContentEmbeddedObjectFields(embedded) {
|
|
178
|
+
const source = SourceResidueSchema.safeParse(embedded.source);
|
|
179
|
+
return {
|
|
180
|
+
objectKind: embedded.objectKind,
|
|
181
|
+
document: embedded.document,
|
|
182
|
+
frame: embedded.frame,
|
|
183
|
+
...embedded.anchorRow === void 0 ? {} : { anchorRow: embedded.anchorRow },
|
|
184
|
+
...embedded.anchorColumn === void 0 ? {} : { anchorColumn: embedded.anchorColumn },
|
|
185
|
+
...embedded.offsetXPt === void 0 ? {} : { offsetXPt: embedded.offsetXPt },
|
|
186
|
+
...embedded.offsetYPt === void 0 ? {} : { offsetYPt: embedded.offsetYPt },
|
|
187
|
+
...source.success ? { source: source.data } : {}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function readEmbeddedObjectData(bytes) {
|
|
191
|
+
try {
|
|
192
|
+
const header = readObjectHeader(bytes);
|
|
193
|
+
if (header.formatId !== OBJECT_HEADER_FORMAT_ID_EMBEDDED && header.formatId !== OBJECT_HEADER_FORMAT_ID_LINKED) return;
|
|
194
|
+
if (header.next + 4 > bytes.length) return;
|
|
195
|
+
const nativeDataSize = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(header.next, true);
|
|
196
|
+
const nativeDataStart = header.next + 4;
|
|
197
|
+
if (nativeDataStart + nativeDataSize > bytes.length) return;
|
|
198
|
+
const nativeData = bytes.subarray(nativeDataStart, nativeDataStart + nativeDataSize);
|
|
199
|
+
const packageStream = readCompoundFile(nativeData).find((stream) => stream.path === "Package");
|
|
200
|
+
if (packageStream === void 0) return;
|
|
201
|
+
const olePackage = readOlePackage(packageStream.bytes);
|
|
202
|
+
const text = new TextDecoder("utf-8").decode(olePackage.fileBytes);
|
|
203
|
+
const parsed = JSON.parse(text);
|
|
204
|
+
const result = ContentEmbeddedObjectSchema.safeParse(parsed);
|
|
205
|
+
if (!result.success) return;
|
|
206
|
+
skipPresentationObject(bytes, nativeDataStart + nativeDataSize);
|
|
207
|
+
return knownContentEmbeddedObjectFields(result.data);
|
|
208
|
+
} catch {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
//#endregion
|
|
213
|
+
export { readEmbeddedObjectData, writeEmbeddedObjectData };
|
package/dist/header.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as RtfDiagnosticSink } from "./diagnostics-
|
|
1
|
+
import { a as RtfDiagnosticSink } from "./diagnostics-CjMoO7x1.cjs";
|
|
2
2
|
import { RtfToken } from "./tokenize.cjs";
|
|
3
3
|
import { Color, LayoutMetadata } from "document-schema.js";
|
|
4
4
|
//#region src/header.d.ts
|
package/dist/header.d.ts
CHANGED
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { rtfBytesFromLatin1 } from "./bytes.cjs";
|
|
2
2
|
import { RtfBytesSchema, rtfCodec, rtfContentCodec } from "./codec.cjs";
|
|
3
|
-
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-
|
|
3
|
+
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-CjMoO7x1.cjs";
|
|
4
4
|
import { DEFAULT_MAX_GROUP_DEPTH, DEFAULT_MAX_INPUT_BYTES, ReadRtfOptions, RtfLineEnding, WriteRtfOptions } from "./options.cjs";
|
|
5
5
|
import { ReadRtfContentResult, ReadRtfResult, readRtf, readRtfContent } from "./read.cjs";
|
|
6
6
|
import { writeRtf, writeRtfContent } from "./write.cjs";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { rtfBytesFromLatin1 } from "./bytes.js";
|
|
2
2
|
import { RtfBytesSchema, rtfCodec, rtfContentCodec } from "./codec.js";
|
|
3
|
-
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-
|
|
3
|
+
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-CjMoO7x1.js";
|
|
4
4
|
import { DEFAULT_MAX_GROUP_DEPTH, DEFAULT_MAX_INPUT_BYTES, ReadRtfOptions, RtfLineEnding, WriteRtfOptions } from "./options.js";
|
|
5
5
|
import { ReadRtfContentResult, ReadRtfResult, readRtf, readRtfContent } from "./read.js";
|
|
6
6
|
import { writeRtf, writeRtfContent } from "./write.js";
|
package/dist/options.d.cts
CHANGED
package/dist/options.d.ts
CHANGED