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