ooxml-core 1.6.1 → 1.6.2
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/{PptxHandler-BTXB54UC.mjs → PptxHandler-BL4B7CZO.mjs} +2 -2
- package/dist/automation/index.cjs +1 -1
- package/dist/automation/index.mjs +1 -1
- package/dist/{chunk-CS7HRNHL.mjs → chunk-GAGSCAR3.mjs} +43 -43
- package/dist/{chunk-5CJRDY7Q.mjs → chunk-NIHPA63A.mjs} +1 -1
- package/dist/{chunk-Q5LESLDA.mjs → chunk-TTPZITQN.mjs} +841 -614
- package/dist/{chunk-4L4UB3RQ.mjs → chunk-Z7IQR4S4.mjs} +3 -3
- package/dist/{chunk-RIFVZP2S.mjs → chunk-ZAP5WLEN.mjs} +1 -1
- package/dist/crypto/index.cjs +281 -109
- package/dist/crypto/index.mjs +281 -109
- package/dist/docx/load/index.cjs +481 -254
- package/dist/docx/load/index.mjs +481 -254
- package/dist/pptx/automation/index.cjs +1388 -1154
- package/dist/pptx/automation/index.d.ts +1 -1
- package/dist/pptx/automation/index.mjs +5 -5
- package/dist/pptx/chunks/{index-DkHgeV1p.d.ts → index-Cn-GzYGp.d.ts} +62 -13
- package/dist/pptx/chunks/{index-DkHgeV1p.d.ts.map → index-Cn-GzYGp.d.ts.map} +1 -1
- package/dist/pptx/cli/index.cjs +1267 -1088
- package/dist/pptx/cli/index.mjs +4 -4
- package/dist/pptx/converter/index.mjs +2 -2
- package/dist/pptx/index.cjs +1408 -1174
- package/dist/pptx/index.d.ts +1 -1
- package/dist/pptx/index.mjs +5 -5
- package/dist/visio/index.cjs +482 -232
- package/dist/visio/index.mjs +482 -232
- package/dist/xlsx/load/index.cjs +415 -188
- package/dist/xlsx/load/index.mjs +415 -188
- package/package.json +5 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { findText, replaceText, replaceTextInSlide, mergePresentation } from './chunk-
|
|
2
|
-
import { PresentationBuilder, PptxHandler, SlideBuilder, validateSeriesIndex, removeEmptyDataPoint, ensureDataPoint, ensureChartData, assertChartGradientSupported, toChartGradientFill, STANDARD_LAYOUTS, createTextElement, createShapeElement, createImageElement, createTableElement, createChartElement, createConnectorElement, createMediaElement, createGroupElement, PptxXmlBuilder } from './chunk-
|
|
3
|
-
import { escAttr, EMU_PER_PIXEL, EMU_PER_INCH, hasTextProperties } from './chunk-
|
|
1
|
+
import { findText, replaceText, replaceTextInSlide, mergePresentation } from './chunk-ZAP5WLEN.mjs';
|
|
2
|
+
import { PresentationBuilder, PptxHandler, SlideBuilder, validateSeriesIndex, removeEmptyDataPoint, ensureDataPoint, ensureChartData, assertChartGradientSupported, toChartGradientFill, STANDARD_LAYOUTS, createTextElement, createShapeElement, createImageElement, createTableElement, createChartElement, createConnectorElement, createMediaElement, createGroupElement, PptxXmlBuilder } from './chunk-GAGSCAR3.mjs';
|
|
3
|
+
import { escAttr, EMU_PER_PIXEL, EMU_PER_INCH, hasTextProperties } from './chunk-TTPZITQN.mjs';
|
|
4
4
|
import { cloneSlide, cloneElement } from './chunk-54S5A5PZ.mjs';
|
|
5
5
|
import JSZip from 'jszip';
|
|
6
6
|
|
package/dist/crypto/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// ../../node_modules/.bun/@christophervr+ole2@0.
|
|
3
|
+
// ../../node_modules/.bun/@christophervr+ole2@0.13.0/node_modules/@christophervr/ole2/dist/ole2-parser-types.js
|
|
4
4
|
var OLE_MAGIC = new Uint8Array([208, 207, 17, 224, 161, 177, 26, 225]);
|
|
5
5
|
var ENDOFCHAIN = 4294967294;
|
|
6
6
|
var FREESECT = 4294967295;
|
|
@@ -8,7 +8,9 @@ var FATSECT = 4294967293;
|
|
|
8
8
|
var DIFSECT = 4294967292;
|
|
9
9
|
var MAXREGSECT = 4294967290;
|
|
10
10
|
var ENTRY_TYPE_EMPTY = 0;
|
|
11
|
+
var ENTRY_TYPE_STORAGE = 1;
|
|
11
12
|
var ENTRY_TYPE_STREAM = 2;
|
|
13
|
+
var NOSTREAM = 4294967295;
|
|
12
14
|
var ENTRY_TYPE_ROOT = 5;
|
|
13
15
|
var DIR_ENTRY_SIZE = 128;
|
|
14
16
|
var Ole2ParseError = class extends Error {
|
|
@@ -18,10 +20,174 @@ var Ole2ParseError = class extends Error {
|
|
|
18
20
|
}
|
|
19
21
|
};
|
|
20
22
|
|
|
21
|
-
// ../../node_modules/.bun/@christophervr+ole2@0.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
23
|
+
// ../../node_modules/.bun/@christophervr+ole2@0.13.0/node_modules/@christophervr/ole2/dist/ole2-directory.js
|
|
24
|
+
var FILETIME_UNIX_EPOCH = 116444736000000000n;
|
|
25
|
+
function readFileTime(view, offset) {
|
|
26
|
+
const ticks = view.getBigUint64(offset, true);
|
|
27
|
+
if (ticks === 0n)
|
|
28
|
+
return void 0;
|
|
29
|
+
const ms = Number((ticks - FILETIME_UNIX_EPOCH) / 10000n);
|
|
30
|
+
const date = new Date(ms);
|
|
31
|
+
return Number.isNaN(date.getTime()) ? void 0 : date;
|
|
32
|
+
}
|
|
33
|
+
function decodeSlot(dir, id, majorVersion, warnings) {
|
|
34
|
+
const view = new DataView(dir.buffer, dir.byteOffset + id * DIR_ENTRY_SIZE, DIR_ENTRY_SIZE);
|
|
35
|
+
const nameLen = view.getUint16(64, true);
|
|
36
|
+
const type = view.getUint8(66);
|
|
37
|
+
const nameValid = nameLen >= 2 && nameLen <= 64 && nameLen % 2 === 0 && view.getUint16(nameLen - 2, true) === 0;
|
|
38
|
+
let name = "";
|
|
39
|
+
if (nameValid)
|
|
40
|
+
for (let j = 0; j < nameLen - 2; j += 2)
|
|
41
|
+
name += String.fromCharCode(view.getUint16(j, true));
|
|
42
|
+
const link = (offset) => {
|
|
43
|
+
const value = view.getUint32(offset, true);
|
|
44
|
+
return value === NOSTREAM ? -1 : value;
|
|
45
|
+
};
|
|
46
|
+
const sizeLow = view.getUint32(120, true);
|
|
47
|
+
const sizeHigh = view.getUint32(124, true);
|
|
48
|
+
let size = sizeLow;
|
|
49
|
+
if (majorVersion === 4)
|
|
50
|
+
size = sizeLow + sizeHigh * 4294967296;
|
|
51
|
+
else if (sizeHigh !== 0 && type !== ENTRY_TYPE_EMPTY) {
|
|
52
|
+
warnings.push({ code: "size-high-bits", message: `Ignored v3 stream-size high bits on directory entry ${id}` });
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
id,
|
|
56
|
+
type,
|
|
57
|
+
nameValid,
|
|
58
|
+
entry: {
|
|
59
|
+
id,
|
|
60
|
+
name,
|
|
61
|
+
type,
|
|
62
|
+
color: view.getUint8(67),
|
|
63
|
+
leftSiblingId: link(68),
|
|
64
|
+
rightSiblingId: link(72),
|
|
65
|
+
childId: link(76),
|
|
66
|
+
clsid: new Uint8Array(view.buffer.slice(view.byteOffset + 80, view.byteOffset + 96)),
|
|
67
|
+
stateBits: view.getUint32(96, true),
|
|
68
|
+
created: readFileTime(view, 100),
|
|
69
|
+
modified: readFileTime(view, 108),
|
|
70
|
+
startSector: view.getUint32(116, true),
|
|
71
|
+
size,
|
|
72
|
+
parentId: -1
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function readDirectory(dir, majorVersion, strict, warnings) {
|
|
77
|
+
const count = Math.floor(dir.length / DIR_ENTRY_SIZE);
|
|
78
|
+
const slots = [];
|
|
79
|
+
for (let id = 0; id < count; id++)
|
|
80
|
+
slots.push(decodeSlot(dir, id, majorVersion, warnings));
|
|
81
|
+
const roots = slots.filter((slot) => slot.type === ENTRY_TYPE_ROOT);
|
|
82
|
+
if (roots.length !== 1 || !roots[0].nameValid)
|
|
83
|
+
throw new Ole2ParseError("Invalid root directory entry");
|
|
84
|
+
const root = roots[0];
|
|
85
|
+
root.entry.path = [];
|
|
86
|
+
const reached = /* @__PURE__ */ new Set([root.id]);
|
|
87
|
+
const fail = (message) => {
|
|
88
|
+
if (strict)
|
|
89
|
+
throw new Ole2ParseError(message);
|
|
90
|
+
warnings.push({ code: "directory-link", message });
|
|
91
|
+
};
|
|
92
|
+
const pending = [];
|
|
93
|
+
const push = (id, parent, from) => {
|
|
94
|
+
if (id === -1)
|
|
95
|
+
return;
|
|
96
|
+
const target = slots[id];
|
|
97
|
+
if (!target || target.type === ENTRY_TYPE_EMPTY || target.type === ENTRY_TYPE_ROOT) {
|
|
98
|
+
fail(`Directory entry ${from} links to invalid entry ${id}`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (reached.has(id)) {
|
|
102
|
+
fail(`Cyclic directory tree at entry ${id}`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
reached.add(id);
|
|
106
|
+
pending.push({ id, parent });
|
|
107
|
+
};
|
|
108
|
+
push(root.entry.childId, root, root.id);
|
|
109
|
+
while (pending.length) {
|
|
110
|
+
const { id, parent } = pending.pop();
|
|
111
|
+
const slot = slots[id];
|
|
112
|
+
if (!slot.nameValid)
|
|
113
|
+
throw new Ole2ParseError("Invalid directory entry name");
|
|
114
|
+
slot.entry.parentId = parent.id;
|
|
115
|
+
slot.entry.path = [...parent.entry.path, slot.entry.name];
|
|
116
|
+
push(slot.entry.leftSiblingId, parent, id);
|
|
117
|
+
push(slot.entry.rightSiblingId, parent, id);
|
|
118
|
+
if (slot.type === ENTRY_TYPE_STORAGE)
|
|
119
|
+
push(slot.entry.childId, slot, id);
|
|
120
|
+
}
|
|
121
|
+
const entries = [];
|
|
122
|
+
for (const slot of slots) {
|
|
123
|
+
if (slot.type === ENTRY_TYPE_EMPTY)
|
|
124
|
+
continue;
|
|
125
|
+
if (!reached.has(slot.id)) {
|
|
126
|
+
if (!slot.nameValid) {
|
|
127
|
+
if (strict)
|
|
128
|
+
throw new Ole2ParseError("Invalid directory entry name");
|
|
129
|
+
warnings.push({ code: "invalid-unreachable-entry", message: `Skipped undecodable stale directory entry ${slot.id}` });
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (strict)
|
|
133
|
+
throw new Ole2ParseError(`Directory entry ${slot.id} is not reachable from the root`);
|
|
134
|
+
warnings.push({ code: "unreachable-entry", message: `Directory entry ${slot.id} (${slot.entry.name}) is not reachable from the root` });
|
|
135
|
+
}
|
|
136
|
+
entries.push(slot.entry);
|
|
137
|
+
}
|
|
138
|
+
return entries;
|
|
139
|
+
}
|
|
140
|
+
function sameName(a, b) {
|
|
141
|
+
return a.length === b.length && a.toUpperCase() === b.toUpperCase();
|
|
142
|
+
}
|
|
143
|
+
function bareName(name) {
|
|
144
|
+
return name.replace(/^[\u0001-\u0006]/, "");
|
|
145
|
+
}
|
|
146
|
+
function normalizePath(path, rootName) {
|
|
147
|
+
const parts = typeof path === "string" ? path.split("/").filter((part) => part !== "") : [...path];
|
|
148
|
+
if (parts.length && sameName(parts[0], rootName) && typeof path === "string")
|
|
149
|
+
parts.shift();
|
|
150
|
+
return parts;
|
|
151
|
+
}
|
|
152
|
+
function child(entries, parentId, name) {
|
|
153
|
+
const children = entries.filter((entry) => entry.parentId === parentId && entry.path !== void 0);
|
|
154
|
+
const pick = (matches) => matches.length === 1 ? matches[0] : void 0;
|
|
155
|
+
const exact = children.filter((entry) => entry.name === name);
|
|
156
|
+
if (exact.length)
|
|
157
|
+
return pick(exact);
|
|
158
|
+
const folded = children.filter((entry) => sameName(entry.name, name));
|
|
159
|
+
if (folded.length)
|
|
160
|
+
return pick(folded);
|
|
161
|
+
return pick(children.filter((entry) => sameName(bareName(entry.name), bareName(name))));
|
|
162
|
+
}
|
|
163
|
+
function findDirectoryEntry(entries, path) {
|
|
164
|
+
const root = entries.find((entry) => entry.type === ENTRY_TYPE_ROOT);
|
|
165
|
+
if (!root)
|
|
166
|
+
return void 0;
|
|
167
|
+
let current = root;
|
|
168
|
+
for (const name of normalizePath(path, root.name)) {
|
|
169
|
+
if (current.type !== ENTRY_TYPE_ROOT && current.type !== ENTRY_TYPE_STORAGE)
|
|
170
|
+
return void 0;
|
|
171
|
+
current = child(entries, current.id, name);
|
|
172
|
+
if (!current)
|
|
173
|
+
return void 0;
|
|
174
|
+
}
|
|
175
|
+
return current;
|
|
176
|
+
}
|
|
177
|
+
function findStreamByName(entries, name, isReadable) {
|
|
178
|
+
const root = entries.find((entry) => entry.type === ENTRY_TYPE_ROOT);
|
|
179
|
+
if (root && root.name === name)
|
|
180
|
+
return root;
|
|
181
|
+
const top = entries.filter((entry) => entry.parentId === root?.id && isReadable(entry));
|
|
182
|
+
return top.find((entry) => entry.name === name) ?? top.find((entry) => sameName(entry.name, name)) ?? entries.find((entry) => entry.name === name && isReadable(entry));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ../../node_modules/.bun/@christophervr+ole2@0.13.0/node_modules/@christophervr/ole2/dist/ole2-parser-read.js
|
|
186
|
+
function parseOle2(buffer, options = {}) {
|
|
187
|
+
const strict = options.strict === true;
|
|
188
|
+
const data = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
189
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
190
|
+
const warnings = [];
|
|
25
191
|
if (data.length < 512) {
|
|
26
192
|
throw new Ole2ParseError("Truncated OLE2 compound file header");
|
|
27
193
|
}
|
|
@@ -30,11 +196,12 @@ function parseOle2(buffer) {
|
|
|
30
196
|
throw new Ole2ParseError("Not a valid OLE2 compound file");
|
|
31
197
|
}
|
|
32
198
|
}
|
|
33
|
-
view.getUint16(24, true);
|
|
34
199
|
const majorVersion = view.getUint16(26, true);
|
|
35
200
|
const byteOrder = view.getUint16(28, true);
|
|
36
201
|
if (byteOrder !== 65534) {
|
|
37
|
-
|
|
202
|
+
if (strict)
|
|
203
|
+
throw new Ole2ParseError("Invalid byte order mark");
|
|
204
|
+
warnings.push({ code: "byte-order", message: `Ignored byte order mark 0x${byteOrder.toString(16)}` });
|
|
38
205
|
}
|
|
39
206
|
const sectorSizePower = view.getUint16(30, true);
|
|
40
207
|
const miniSectorSizePower = view.getUint16(32, true);
|
|
@@ -43,10 +210,14 @@ function parseOle2(buffer) {
|
|
|
43
210
|
}
|
|
44
211
|
const sectorSize = 1 << sectorSizePower;
|
|
45
212
|
const miniSectorSize = 1 << miniSectorSizePower;
|
|
46
|
-
if (data.length < sectorSize
|
|
213
|
+
if (data.length < sectorSize)
|
|
47
214
|
throw new Ole2ParseError("Truncated OLE2 sector");
|
|
215
|
+
if (data.length % sectorSize !== 0) {
|
|
216
|
+
if (strict)
|
|
217
|
+
throw new Ole2ParseError("Truncated OLE2 sector");
|
|
218
|
+
warnings.push({ code: "unaligned-length", message: `File length ${data.length} is not a multiple of ${sectorSize}` });
|
|
48
219
|
}
|
|
49
|
-
const sectorCount = data.length / sectorSize - 1;
|
|
220
|
+
const sectorCount = Math.ceil(data.length / sectorSize) - 1;
|
|
50
221
|
const totalFATSectors = view.getUint32(44, true);
|
|
51
222
|
const firstDirectorySector = view.getUint32(48, true);
|
|
52
223
|
const miniStreamCutoff = view.getUint32(56, true);
|
|
@@ -67,6 +238,13 @@ function parseOle2(buffer) {
|
|
|
67
238
|
}
|
|
68
239
|
return data.subarray(offset, offset + sectorSize);
|
|
69
240
|
}
|
|
241
|
+
function copySector(sector, target, at, want) {
|
|
242
|
+
const offset = sectorOffset(sector);
|
|
243
|
+
if (sector >= sectorCount || offset + want > data.length) {
|
|
244
|
+
throw new Ole2ParseError(`Sector ${sector} at offset ${offset} exceeds file size ${data.length}`);
|
|
245
|
+
}
|
|
246
|
+
target.set(data.subarray(offset, offset + want), at);
|
|
247
|
+
}
|
|
70
248
|
const fatSectors = [];
|
|
71
249
|
for (let i2 = 0; i2 < 109 && fatSectors.length < totalFATSectors; i2++) {
|
|
72
250
|
const sector = view.getUint32(76 + i2 * 4, true);
|
|
@@ -102,29 +280,36 @@ function parseOle2(buffer) {
|
|
|
102
280
|
fatEntries.push(fatView.getUint32(i2 * 4, true));
|
|
103
281
|
}
|
|
104
282
|
}
|
|
105
|
-
function
|
|
106
|
-
const
|
|
107
|
-
let current = startSector;
|
|
283
|
+
function followChain(table, start, label, needed) {
|
|
284
|
+
const ids = [];
|
|
108
285
|
const visited = /* @__PURE__ */ new Set();
|
|
286
|
+
let current = start;
|
|
109
287
|
while (current <= MAXREGSECT) {
|
|
288
|
+
if (!strict && needed !== void 0 && ids.length >= needed)
|
|
289
|
+
return ids;
|
|
110
290
|
if (visited.has(current)) {
|
|
111
|
-
throw new Ole2ParseError(`Circular reference in
|
|
291
|
+
throw new Ole2ParseError(`Circular reference in ${label} chain at sector ${current}`);
|
|
112
292
|
}
|
|
113
293
|
visited.add(current);
|
|
114
|
-
|
|
115
|
-
if (
|
|
116
|
-
throw new Ole2ParseError(
|
|
117
|
-
current =
|
|
294
|
+
ids.push(current);
|
|
295
|
+
if (table[current] === void 0)
|
|
296
|
+
throw new Ole2ParseError(`Missing ${label} chain entry`);
|
|
297
|
+
current = table[current];
|
|
118
298
|
}
|
|
119
|
-
if (current !== ENDOFCHAIN)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
for (const sector of sectors) {
|
|
125
|
-
result.set(sector, offset);
|
|
126
|
-
offset += sectorSize;
|
|
299
|
+
if (current !== ENDOFCHAIN) {
|
|
300
|
+
if (strict || needed === void 0 || ids.length < needed) {
|
|
301
|
+
throw new Ole2ParseError(`Invalid ${label} chain terminator`);
|
|
302
|
+
}
|
|
303
|
+
warnings.push({ code: "chain-terminator", message: `Accepted ${label} chain ending in 0x${current.toString(16)}` });
|
|
127
304
|
}
|
|
305
|
+
return ids;
|
|
306
|
+
}
|
|
307
|
+
function readMetadataChain(startSector, label) {
|
|
308
|
+
if (startSector > MAXREGSECT)
|
|
309
|
+
return new Uint8Array(0);
|
|
310
|
+
const ids = followChain(fatEntries, startSector, label === "directory" ? "FAT" : label);
|
|
311
|
+
const result = new Uint8Array(ids.length * sectorSize);
|
|
312
|
+
ids.forEach((id, i2) => result.set(readSector(id), i2 * sectorSize));
|
|
128
313
|
return result;
|
|
129
314
|
}
|
|
130
315
|
function readStream(startSector, size) {
|
|
@@ -132,68 +317,44 @@ function parseOle2(buffer) {
|
|
|
132
317
|
return new Uint8Array(0);
|
|
133
318
|
if (size > sectorCount * sectorSize)
|
|
134
319
|
throw new Ole2ParseError("Stream size exceeds file size");
|
|
135
|
-
const
|
|
136
|
-
|
|
320
|
+
const needed = Math.ceil(size / sectorSize);
|
|
321
|
+
const ids = followChain(fatEntries, startSector, "FAT", needed);
|
|
322
|
+
if (ids.length < needed)
|
|
137
323
|
throw new Ole2ParseError("Truncated stream sector chain");
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const numEntries = Math.floor(dirRaw.length / DIR_ENTRY_SIZE);
|
|
142
|
-
const entries = [];
|
|
143
|
-
for (let i2 = 0; i2 < numEntries; i2++) {
|
|
144
|
-
const entryOffset = i2 * DIR_ENTRY_SIZE;
|
|
145
|
-
const entryView = new DataView(dirRaw.buffer, dirRaw.byteOffset + entryOffset, DIR_ENTRY_SIZE);
|
|
146
|
-
const nameLen = entryView.getUint16(64, true);
|
|
147
|
-
const objectType = entryView.getUint8(66);
|
|
148
|
-
if (objectType === ENTRY_TYPE_EMPTY) {
|
|
149
|
-
continue;
|
|
324
|
+
const result = new Uint8Array(size);
|
|
325
|
+
for (let i2 = 0; i2 < needed; i2++) {
|
|
326
|
+
copySector(ids[i2], result, i2 * sectorSize, Math.min(sectorSize, size - i2 * sectorSize));
|
|
150
327
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const leftSiblingId = entryView.getUint32(68, true);
|
|
160
|
-
const rightSiblingId = entryView.getUint32(72, true);
|
|
161
|
-
const childId = entryView.getUint32(76, true);
|
|
162
|
-
const clsid = new Uint8Array(entryView.buffer.slice(entryView.byteOffset + 80, entryView.byteOffset + 96));
|
|
163
|
-
const startSector = entryView.getUint32(116, true);
|
|
164
|
-
const sizeLow = entryView.getUint32(120, true);
|
|
165
|
-
let size = sizeLow;
|
|
166
|
-
if (majorVersion === 4) {
|
|
167
|
-
const sizeHigh = entryView.getUint32(124, true);
|
|
168
|
-
size = sizeLow + sizeHigh * 4294967296;
|
|
169
|
-
if (!Number.isSafeInteger(size) || size > sectorCount * sectorSize) {
|
|
170
|
-
throw new Ole2ParseError("Stream size exceeds supported file bounds");
|
|
171
|
-
}
|
|
328
|
+
return result;
|
|
329
|
+
}
|
|
330
|
+
if (firstDirectorySector > MAXREGSECT)
|
|
331
|
+
throw new Ole2ParseError("Missing directory chain");
|
|
332
|
+
const entries = readDirectory(readMetadataChain(firstDirectorySector, "directory"), majorVersion, strict, warnings);
|
|
333
|
+
for (const entry of entries) {
|
|
334
|
+
if (majorVersion === 4 && (!Number.isSafeInteger(entry.size) || entry.size > sectorCount * sectorSize)) {
|
|
335
|
+
throw new Ole2ParseError("Stream size exceeds supported file bounds");
|
|
172
336
|
}
|
|
173
|
-
entries.push({
|
|
174
|
-
name,
|
|
175
|
-
type: objectType,
|
|
176
|
-
startSector,
|
|
177
|
-
size,
|
|
178
|
-
childId: childId === 4294967295 ? -1 : childId,
|
|
179
|
-
leftSiblingId: leftSiblingId === 4294967295 ? -1 : leftSiblingId,
|
|
180
|
-
rightSiblingId: rightSiblingId === 4294967295 ? -1 : rightSiblingId,
|
|
181
|
-
clsid
|
|
182
|
-
});
|
|
183
337
|
}
|
|
184
338
|
const rootEntry = entries.find((e) => e.type === ENTRY_TYPE_ROOT);
|
|
185
|
-
if (!rootEntry || entries.filter((e) => e.type === ENTRY_TYPE_ROOT).length !== 1) {
|
|
186
|
-
throw new Ole2ParseError("Invalid root directory entry");
|
|
187
|
-
}
|
|
188
339
|
let miniStreamData;
|
|
189
|
-
if (rootEntry
|
|
340
|
+
if (rootEntry.startSector <= MAXREGSECT) {
|
|
190
341
|
miniStreamData = readStream(rootEntry.startSector, rootEntry.size);
|
|
191
342
|
}
|
|
192
343
|
const miniFatEntries = [];
|
|
193
|
-
if (firstMiniFATSector
|
|
194
|
-
|
|
195
|
-
if (miniFatRaw.length !== totalMiniFATSectors * sectorSize) {
|
|
344
|
+
if (firstMiniFATSector > MAXREGSECT && totalMiniFATSectors > 0) {
|
|
345
|
+
if (strict)
|
|
196
346
|
throw new Ole2ParseError("Unexpected mini FAT chain length");
|
|
347
|
+
warnings.push({ code: "mini-fat-count", message: `Header lists ${totalMiniFATSectors} mini FAT sectors but no chain` });
|
|
348
|
+
}
|
|
349
|
+
if (firstMiniFATSector <= MAXREGSECT && (totalMiniFATSectors > 0 || !strict)) {
|
|
350
|
+
const miniFatRaw = readMetadataChain(firstMiniFATSector, "mini FAT");
|
|
351
|
+
if (miniFatRaw.length !== totalMiniFATSectors * sectorSize) {
|
|
352
|
+
if (strict)
|
|
353
|
+
throw new Ole2ParseError("Unexpected mini FAT chain length");
|
|
354
|
+
warnings.push({
|
|
355
|
+
code: "mini-fat-count",
|
|
356
|
+
message: `Header lists ${totalMiniFATSectors} mini FAT sectors; chain has ${miniFatRaw.length / sectorSize}`
|
|
357
|
+
});
|
|
197
358
|
}
|
|
198
359
|
const miniFatView = new DataView(miniFatRaw.buffer, miniFatRaw.byteOffset, miniFatRaw.byteLength);
|
|
199
360
|
const miniCapacity = Math.floor((miniStreamData?.length ?? 0) / miniSectorSize);
|
|
@@ -207,45 +368,56 @@ function parseOle2(buffer) {
|
|
|
207
368
|
if (!miniStreamData) {
|
|
208
369
|
throw new Ole2ParseError("Mini stream container not found");
|
|
209
370
|
}
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
371
|
+
const needed = Math.ceil(size / miniSectorSize);
|
|
372
|
+
const capacity = miniStreamData.length / miniSectorSize;
|
|
373
|
+
let ids;
|
|
374
|
+
try {
|
|
375
|
+
ids = followChain(miniFatEntries, startSector, "mini FAT", needed);
|
|
376
|
+
} catch (error) {
|
|
377
|
+
if (error instanceof Ole2ParseError && /Missing mini FAT/.test(error.message)) {
|
|
378
|
+
throw new Ole2ParseError("Mini stream sector exceeds allocation bounds");
|
|
216
379
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
380
|
+
throw error;
|
|
381
|
+
}
|
|
382
|
+
const result = new Uint8Array(size);
|
|
383
|
+
for (let i2 = 0; i2 < ids.length && i2 < needed; i2++) {
|
|
384
|
+
const id = ids[i2];
|
|
385
|
+
if (id >= capacity || (id + 1) * miniSectorSize > miniStreamData.length) {
|
|
220
386
|
throw new Ole2ParseError("Mini stream sector exceeds allocation bounds");
|
|
221
387
|
}
|
|
222
|
-
|
|
223
|
-
|
|
388
|
+
const want = Math.min(miniSectorSize, size - i2 * miniSectorSize);
|
|
389
|
+
result.set(miniStreamData.subarray(id * miniSectorSize, id * miniSectorSize + want), i2 * miniSectorSize);
|
|
224
390
|
}
|
|
225
|
-
if (
|
|
226
|
-
throw new Ole2ParseError("Invalid mini FAT chain terminator");
|
|
227
|
-
const totalLength = sectors.length * miniSectorSize;
|
|
228
|
-
if (totalLength < size)
|
|
391
|
+
if (ids.length < needed)
|
|
229
392
|
throw new Ole2ParseError("Truncated mini stream sector chain");
|
|
230
|
-
|
|
231
|
-
let offset = 0;
|
|
232
|
-
for (const sector of sectors) {
|
|
233
|
-
result.set(sector, offset);
|
|
234
|
-
offset += miniSectorSize;
|
|
235
|
-
}
|
|
236
|
-
return result.subarray(0, size);
|
|
393
|
+
return result;
|
|
237
394
|
}
|
|
238
|
-
function
|
|
239
|
-
const entry = entries.find((e) => (e.type === ENTRY_TYPE_STREAM || e.type === ENTRY_TYPE_ROOT) && e.name === name);
|
|
240
|
-
if (!entry) {
|
|
241
|
-
return void 0;
|
|
242
|
-
}
|
|
395
|
+
function readEntry(entry) {
|
|
243
396
|
if (entry.size < miniStreamCutoff && entry.type !== ENTRY_TYPE_ROOT) {
|
|
244
397
|
return readMiniStream(entry.startSector, entry.size);
|
|
245
398
|
}
|
|
246
399
|
return readStream(entry.startSector, entry.size);
|
|
247
400
|
}
|
|
248
|
-
|
|
401
|
+
const readable = (entry) => entry.type === ENTRY_TYPE_STREAM || entry.type === ENTRY_TYPE_ROOT;
|
|
402
|
+
return {
|
|
403
|
+
entries,
|
|
404
|
+
warnings,
|
|
405
|
+
getStream(name) {
|
|
406
|
+
const entry = findStreamByName(entries, name, readable);
|
|
407
|
+
return entry ? readEntry(entry) : void 0;
|
|
408
|
+
},
|
|
409
|
+
getStreamByPath(path) {
|
|
410
|
+
const entry = findDirectoryEntry(entries, path);
|
|
411
|
+
return entry && entry.type === ENTRY_TYPE_STREAM ? readEntry(entry) : void 0;
|
|
412
|
+
},
|
|
413
|
+
getStreamById(id) {
|
|
414
|
+
const entry = entries.find((candidate) => candidate.id === id);
|
|
415
|
+
return entry && readable(entry) ? readEntry(entry) : void 0;
|
|
416
|
+
},
|
|
417
|
+
findEntry(path) {
|
|
418
|
+
return findDirectoryEntry(entries, path);
|
|
419
|
+
}
|
|
420
|
+
};
|
|
249
421
|
}
|
|
250
422
|
|
|
251
423
|
// crypto/uuid.ts
|
|
@@ -265,7 +437,7 @@ function createOfficeGuid() {
|
|
|
265
437
|
return `{${uuid.toUpperCase()}}`;
|
|
266
438
|
}
|
|
267
439
|
|
|
268
|
-
// ../../node_modules/.bun/@christophervr+ole2@0.
|
|
440
|
+
// ../../node_modules/.bun/@christophervr+ole2@0.13.0/node_modules/@christophervr/ole2/dist/utils/ooxml-crypto-primitives.js
|
|
269
441
|
function getSubtle() {
|
|
270
442
|
if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.subtle) {
|
|
271
443
|
return globalThis.crypto.subtle;
|
|
@@ -2419,7 +2591,7 @@ var EncryptedFileError = class extends Error {
|
|
|
2419
2591
|
}
|
|
2420
2592
|
};
|
|
2421
2593
|
|
|
2422
|
-
// ../../node_modules/.bun/@christophervr+ole2@0.
|
|
2594
|
+
// ../../node_modules/.bun/@christophervr+ole2@0.13.0/node_modules/@christophervr/ole2/dist/ole2-parser-write-helpers.js
|
|
2423
2595
|
function compareDirEntryNames(a, b) {
|
|
2424
2596
|
const ua = a.toUpperCase();
|
|
2425
2597
|
const ub = b.toUpperCase();
|
|
@@ -2486,7 +2658,7 @@ function writeInt32Sectors(outBytes, int32Data, firstSector, numSectors, sectorS
|
|
|
2486
2658
|
}
|
|
2487
2659
|
}
|
|
2488
2660
|
|
|
2489
|
-
// ../../node_modules/.bun/@christophervr+ole2@0.
|
|
2661
|
+
// ../../node_modules/.bun/@christophervr+ole2@0.13.0/node_modules/@christophervr/ole2/dist/ole2-parser-write-serialize.js
|
|
2490
2662
|
function writeHeader(outView, outBytes, params) {
|
|
2491
2663
|
outBytes.set(OLE_MAGIC, 0);
|
|
2492
2664
|
outView.setUint16(24, 62, true);
|
|
@@ -2579,7 +2751,7 @@ function writeStreamSectors(outBytes, streamData, chain, sectorSize) {
|
|
|
2579
2751
|
}
|
|
2580
2752
|
}
|
|
2581
2753
|
|
|
2582
|
-
// ../../node_modules/.bun/@christophervr+ole2@0.
|
|
2754
|
+
// ../../node_modules/.bun/@christophervr+ole2@0.13.0/node_modules/@christophervr/ole2/dist/ole2-parser-write.js
|
|
2583
2755
|
function buildOle2(streams2, rootClsid, miniStreamCutoff = 4096) {
|
|
2584
2756
|
const sectorSize = 512;
|
|
2585
2757
|
const miniSectorSize = 64;
|