ooxml-core 0.12.0 → 0.14.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 (37) hide show
  1. package/dist/collab/broadcast-transport.d.ts +21 -0
  2. package/dist/collab/broadcast-transport.d.ts.map +1 -0
  3. package/dist/collab/index.cjs +103 -0
  4. package/dist/collab/index.d.ts +2 -0
  5. package/dist/collab/index.d.ts.map +1 -1
  6. package/dist/collab/index.mjs +100 -1
  7. package/dist/collab/package-adapter.d.ts +15 -0
  8. package/dist/collab/package-adapter.d.ts.map +1 -0
  9. package/dist/crypto/index.cjs +118 -31
  10. package/dist/crypto/index.mjs +118 -31
  11. package/dist/docx/load/index.cjs +1273 -110
  12. package/dist/docx/load/index.mjs +1273 -110
  13. package/dist/docx/load/legacy-doc.d.ts.map +1 -1
  14. package/dist/pptx/automation/index.cjs +1479 -304
  15. package/dist/pptx/automation/index.d.ts +1 -1
  16. package/dist/pptx/automation/index.mjs +1479 -304
  17. package/dist/pptx/chunks/{index-LoCVDu8Z.d.ts → index-CT9y69AZ.d.ts} +22 -12
  18. package/dist/pptx/chunks/index-CT9y69AZ.d.ts.map +1 -0
  19. package/dist/pptx/cli/index.cjs +307 -152
  20. package/dist/pptx/cli/index.mjs +307 -152
  21. package/dist/pptx/index.cjs +1479 -304
  22. package/dist/pptx/index.d.ts +1 -1
  23. package/dist/pptx/index.mjs +1479 -304
  24. package/dist/visio/index.cjs +7498 -127
  25. package/dist/visio/index.d.ts +3 -1
  26. package/dist/visio/index.d.ts.map +1 -1
  27. package/dist/visio/index.mjs +7497 -128
  28. package/dist/visio/legacy.d.ts +10 -0
  29. package/dist/visio/legacy.d.ts.map +1 -0
  30. package/dist/visio/load.d.ts +5 -0
  31. package/dist/visio/load.d.ts.map +1 -0
  32. package/dist/visio/model.d.ts +1 -1
  33. package/dist/visio/model.d.ts.map +1 -1
  34. package/dist/xlsx/load/index.cjs +144 -52
  35. package/dist/xlsx/load/index.mjs +144 -52
  36. package/package.json +2 -2
  37. package/dist/pptx/chunks/index-LoCVDu8Z.d.ts.map +0 -1
@@ -1,4 +1,4 @@
1
- // node_modules/.bun/@christophervr+ole2@0.4.0/node_modules/@christophervr/ole2/dist/ole2-parser-types.js
1
+ // node_modules/.bun/@christophervr+ole2@0.8.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;
@@ -16,10 +16,13 @@ var Ole2ParseError = class extends Error {
16
16
  }
17
17
  };
18
18
 
19
- // node_modules/.bun/@christophervr+ole2@0.4.0/node_modules/@christophervr/ole2/dist/ole2-parser-read.js
19
+ // node_modules/.bun/@christophervr+ole2@0.8.0/node_modules/@christophervr/ole2/dist/ole2-parser-read.js
20
20
  function parseOle2(buffer) {
21
21
  const data = new Uint8Array(buffer);
22
22
  const view = new DataView(buffer);
23
+ if (data.length < 512) {
24
+ throw new Ole2ParseError("Truncated OLE2 compound file header");
25
+ }
23
26
  for (let i = 0; i < OLE_MAGIC.length; i++) {
24
27
  if (data[i] !== OLE_MAGIC[i]) {
25
28
  throw new Ole2ParseError("Not a valid OLE2 compound file");
@@ -33,8 +36,15 @@ function parseOle2(buffer) {
33
36
  }
34
37
  const sectorSizePower = view.getUint16(30, true);
35
38
  const miniSectorSizePower = view.getUint16(32, true);
39
+ if (majorVersion !== 3 && majorVersion !== 4 || sectorSizePower !== (majorVersion === 3 ? 9 : 12) || miniSectorSizePower !== 6) {
40
+ throw new Ole2ParseError("Unsupported OLE2 version or sector size");
41
+ }
36
42
  const sectorSize = 1 << sectorSizePower;
37
43
  const miniSectorSize = 1 << miniSectorSizePower;
44
+ if (data.length < sectorSize || data.length % sectorSize !== 0) {
45
+ throw new Ole2ParseError("Truncated OLE2 sector");
46
+ }
47
+ const sectorCount = data.length / sectorSize - 1;
38
48
  const totalFATSectors = view.getUint32(44, true);
39
49
  const firstDirectorySector = view.getUint32(48, true);
40
50
  const miniStreamCutoff = view.getUint32(56, true);
@@ -42,6 +52,9 @@ function parseOle2(buffer) {
42
52
  const totalMiniFATSectors = view.getUint32(64, true);
43
53
  const firstDIFATSector = view.getUint32(68, true);
44
54
  const totalDIFATSectors = view.getUint32(72, true);
55
+ if (totalFATSectors > sectorCount || totalMiniFATSectors > sectorCount || totalDIFATSectors > sectorCount) {
56
+ throw new Ole2ParseError("Allocation table count exceeds file size");
57
+ }
45
58
  function sectorOffset(sector) {
46
59
  return (sector + 1) * sectorSize;
47
60
  }
@@ -60,7 +73,11 @@ function parseOle2(buffer) {
60
73
  }
61
74
  }
62
75
  let difatSector = firstDIFATSector;
76
+ const difatSeen = /* @__PURE__ */ new Set();
63
77
  for (let d = 0; d < totalDIFATSectors && difatSector <= MAXREGSECT; d++) {
78
+ if (difatSeen.has(difatSector))
79
+ throw new Ole2ParseError("Circular DIFAT chain");
80
+ difatSeen.add(difatSector);
64
81
  const difatData = readSector(difatSector);
65
82
  const difatView = new DataView(difatData.buffer, difatData.byteOffset, difatData.byteLength);
66
83
  const entriesPerSector = (sectorSize - 4) / 4;
@@ -72,11 +89,14 @@ function parseOle2(buffer) {
72
89
  }
73
90
  difatSector = difatView.getUint32(sectorSize - 4, true);
74
91
  }
92
+ if (difatSeen.size !== totalDIFATSectors || fatSectors.length !== totalFATSectors || new Set(fatSectors).size !== fatSectors.length || fatSectors.some((id) => difatSeen.has(id))) {
93
+ throw new Ole2ParseError("Invalid DIFAT allocation table");
94
+ }
75
95
  const fatEntries = [];
76
96
  for (const fatSector of fatSectors) {
77
97
  const fatData = readSector(fatSector);
78
98
  const fatView = new DataView(fatData.buffer, fatData.byteOffset, fatData.byteLength);
79
- for (let i = 0; i < sectorSize / 4; i++) {
99
+ for (let i = 0; i < sectorSize / 4 && fatEntries.length < sectorCount; i++) {
80
100
  fatEntries.push(fatView.getUint32(i * 4, true));
81
101
  }
82
102
  }
@@ -90,8 +110,12 @@ function parseOle2(buffer) {
90
110
  }
91
111
  visited.add(current);
92
112
  sectors.push(readSector(current));
93
- current = fatEntries[current] ?? ENDOFCHAIN;
113
+ if (fatEntries[current] === void 0)
114
+ throw new Ole2ParseError("Missing FAT chain entry");
115
+ current = fatEntries[current];
94
116
  }
117
+ if (current !== ENDOFCHAIN)
118
+ throw new Ole2ParseError("Invalid FAT chain terminator");
95
119
  const totalLength = sectors.length * sectorSize;
96
120
  const result = new Uint8Array(totalLength);
97
121
  let offset = 0;
@@ -102,16 +126,14 @@ function parseOle2(buffer) {
102
126
  return result;
103
127
  }
104
128
  function readStream(startSector, size) {
129
+ if (size === 0)
130
+ return new Uint8Array(0);
131
+ if (size > sectorCount * sectorSize)
132
+ throw new Ole2ParseError("Stream size exceeds file size");
105
133
  const raw = readSectorChain(startSector);
106
- return raw.subarray(0, Math.min(size, raw.length));
107
- }
108
- const miniFatEntries = [];
109
- if (firstMiniFATSector <= MAXREGSECT && totalMiniFATSectors > 0) {
110
- const miniFatRaw = readSectorChain(firstMiniFATSector);
111
- const miniFatView = new DataView(miniFatRaw.buffer, miniFatRaw.byteOffset, miniFatRaw.byteLength);
112
- for (let i = 0; i < miniFatRaw.length / 4; i++) {
113
- miniFatEntries.push(miniFatView.getUint32(i * 4, true));
114
- }
134
+ if (raw.length < size)
135
+ throw new Ole2ParseError("Truncated stream sector chain");
136
+ return raw.subarray(0, size);
115
137
  }
116
138
  const dirRaw = readSectorChain(firstDirectorySector);
117
139
  const numEntries = Math.floor(dirRaw.length / DIR_ENTRY_SIZE);
@@ -124,6 +146,9 @@ function parseOle2(buffer) {
124
146
  if (objectType === ENTRY_TYPE_EMPTY) {
125
147
  continue;
126
148
  }
149
+ if (nameLen < 2 || nameLen > 64 || nameLen % 2 !== 0 || entryView.getUint16(nameLen - 2, true) !== 0) {
150
+ throw new Ole2ParseError("Invalid directory entry name");
151
+ }
127
152
  const nameBytes = Math.max(0, nameLen - 2);
128
153
  let name = "";
129
154
  for (let j = 0; j < nameBytes; j += 2) {
@@ -137,8 +162,11 @@ function parseOle2(buffer) {
137
162
  const sizeLow = entryView.getUint32(120, true);
138
163
  let size = sizeLow;
139
164
  if (majorVersion === 4) {
140
- entryView.getUint32(124, true);
141
- size = sizeLow;
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
+ }
142
170
  }
143
171
  entries.push({
144
172
  name,
@@ -152,11 +180,28 @@ function parseOle2(buffer) {
152
180
  });
153
181
  }
154
182
  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
+ }
155
186
  let miniStreamData;
156
187
  if (rootEntry && rootEntry.startSector <= MAXREGSECT) {
157
- miniStreamData = readSectorChain(rootEntry.startSector);
188
+ miniStreamData = readStream(rootEntry.startSector, rootEntry.size);
189
+ }
190
+ const miniFatEntries = [];
191
+ if (firstMiniFATSector <= MAXREGSECT && totalMiniFATSectors > 0) {
192
+ const miniFatRaw = readSectorChain(firstMiniFATSector);
193
+ if (miniFatRaw.length !== totalMiniFATSectors * sectorSize) {
194
+ throw new Ole2ParseError("Unexpected mini FAT chain length");
195
+ }
196
+ const miniFatView = new DataView(miniFatRaw.buffer, miniFatRaw.byteOffset, miniFatRaw.byteLength);
197
+ const miniCapacity = Math.floor((miniStreamData?.length ?? 0) / miniSectorSize);
198
+ for (let i = 0; i < miniFatRaw.length / 4 && i < miniCapacity; i++) {
199
+ miniFatEntries.push(miniFatView.getUint32(i * 4, true));
200
+ }
158
201
  }
159
202
  function readMiniStream(startSector, size) {
203
+ if (size === 0)
204
+ return new Uint8Array(0);
160
205
  if (!miniStreamData) {
161
206
  throw new Ole2ParseError("Mini stream container not found");
162
207
  }
@@ -169,17 +214,24 @@ function parseOle2(buffer) {
169
214
  }
170
215
  visited.add(current);
171
216
  const offset2 = current * miniSectorSize;
217
+ if (offset2 + miniSectorSize > miniStreamData.length || miniFatEntries[current] === void 0) {
218
+ throw new Ole2ParseError("Mini stream sector exceeds allocation bounds");
219
+ }
172
220
  sectors.push(miniStreamData.subarray(offset2, offset2 + miniSectorSize));
173
- current = miniFatEntries[current] ?? ENDOFCHAIN;
221
+ current = miniFatEntries[current];
174
222
  }
223
+ if (current !== ENDOFCHAIN)
224
+ throw new Ole2ParseError("Invalid mini FAT chain terminator");
175
225
  const totalLength = sectors.length * miniSectorSize;
226
+ if (totalLength < size)
227
+ throw new Ole2ParseError("Truncated mini stream sector chain");
176
228
  const result = new Uint8Array(totalLength);
177
229
  let offset = 0;
178
230
  for (const sector of sectors) {
179
231
  result.set(sector, offset);
180
232
  offset += miniSectorSize;
181
233
  }
182
- return result.subarray(0, Math.min(size, result.length));
234
+ return result.subarray(0, size);
183
235
  }
184
236
  function getStream(name) {
185
237
  const entry = entries.find((e) => (e.type === ENTRY_TYPE_STREAM || e.type === ENTRY_TYPE_ROOT) && e.name === name);
@@ -194,7 +246,7 @@ function parseOle2(buffer) {
194
246
  return { entries, getStream };
195
247
  }
196
248
 
197
- // node_modules/.bun/@christophervr+ole2@0.4.0/node_modules/@christophervr/ole2/dist/utils/ooxml-crypto-primitives.js
249
+ // node_modules/.bun/@christophervr+ole2@0.8.0/node_modules/@christophervr/ole2/dist/utils/ooxml-crypto-primitives.js
198
250
  function getSubtle() {
199
251
  if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.subtle) {
200
252
  return globalThis.crypto.subtle;
@@ -1126,13 +1178,16 @@ var EncryptedFileError = class extends Error {
1126
1178
  }
1127
1179
  };
1128
1180
 
1129
- // node_modules/.bun/@christophervr+ole2@0.4.0/node_modules/@christophervr/ole2/dist/ole2-parser-write-helpers.js
1181
+ // node_modules/.bun/@christophervr+ole2@0.8.0/node_modules/@christophervr/ole2/dist/ole2-parser-write-helpers.js
1130
1182
  function compareDirEntryNames(a, b) {
1183
+ const ua = a.toUpperCase();
1184
+ const ub = b.toUpperCase();
1185
+ if (ua.length !== a.length || ub.length !== b.length) {
1186
+ throw new Error("CFB stream names with expanding uppercase mappings are unsupported");
1187
+ }
1131
1188
  if (a.length !== b.length) {
1132
1189
  return a.length - b.length;
1133
1190
  }
1134
- const ua = a.toUpperCase();
1135
- const ub = b.toUpperCase();
1136
1191
  for (let i = 0; i < ua.length; i++) {
1137
1192
  const diff = ua.charCodeAt(i) - ub.charCodeAt(i);
1138
1193
  if (diff !== 0) {
@@ -1149,6 +1204,24 @@ function encodeName(name) {
1149
1204
  }
1150
1205
  return bytes;
1151
1206
  }
1207
+ function buildDirectoryTree(entryCount) {
1208
+ const links = /* @__PURE__ */ new Map();
1209
+ let redLevel = 0;
1210
+ for (let remaining = entryCount - 2; remaining >= 0; remaining = Math.floor(remaining / 2) - 1)
1211
+ redLevel++;
1212
+ const build = (low, high, level) => {
1213
+ if (low > high)
1214
+ return 4294967295;
1215
+ const id = Math.floor((low + high) / 2);
1216
+ links.set(id, {
1217
+ left: build(low, id - 1, level + 1),
1218
+ right: build(id + 1, high, level + 1),
1219
+ color: level === redLevel ? 0 : 1
1220
+ });
1221
+ return id;
1222
+ };
1223
+ return { root: build(1, entryCount - 1, 0), links };
1224
+ }
1152
1225
  function writeFatChain(fat, chain) {
1153
1226
  for (let i = 0; i < chain.sectors.length; i++) {
1154
1227
  fat[chain.sectors[i]] = i < chain.sectors.length - 1 ? chain.sectors[i + 1] : ENDOFCHAIN;
@@ -1172,7 +1245,7 @@ function writeInt32Sectors(outBytes, int32Data, firstSector, numSectors, sectorS
1172
1245
  }
1173
1246
  }
1174
1247
 
1175
- // node_modules/.bun/@christophervr+ole2@0.4.0/node_modules/@christophervr/ole2/dist/ole2-parser-write-serialize.js
1248
+ // node_modules/.bun/@christophervr+ole2@0.8.0/node_modules/@christophervr/ole2/dist/ole2-parser-write-serialize.js
1176
1249
  function writeHeader(outView, outBytes, params) {
1177
1250
  outBytes.set(OLE_MAGIC, 0);
1178
1251
  outView.setUint16(24, 62, true);
@@ -1230,6 +1303,7 @@ function writeDifatSectors(outView, params) {
1230
1303
  function serializeDirectoryEntries(dirEntries, numDirSectors, sectorSize) {
1231
1304
  const dirData = new Uint8Array(numDirSectors * sectorSize);
1232
1305
  const dirView = new DataView(dirData.buffer);
1306
+ const tree = buildDirectoryTree(dirEntries.length);
1233
1307
  for (let i = 0; i < dirEntries.length; i++) {
1234
1308
  const entry = dirEntries[i];
1235
1309
  const entryOffset = i * DIR_ENTRY_SIZE;
@@ -1237,17 +1311,17 @@ function serializeDirectoryEntries(dirEntries, numDirSectors, sectorSize) {
1237
1311
  dirData.set(nameBytes.subarray(0, Math.min(nameBytes.length, 64)), entryOffset);
1238
1312
  dirView.setUint16(entryOffset + 64, Math.min((entry.name.length + 1) * 2, 64), true);
1239
1313
  dirData[entryOffset + 66] = entry.type;
1240
- dirData[entryOffset + 67] = 1;
1314
+ dirData[entryOffset + 67] = i === 0 ? 1 : tree.links.get(i).color;
1241
1315
  if (entry.clsid) {
1242
1316
  dirData.set(entry.clsid.subarray(0, 16), entryOffset + 80);
1243
1317
  }
1244
1318
  if (i === 0) {
1245
1319
  dirView.setUint32(entryOffset + 68, 4294967295, true);
1246
1320
  dirView.setUint32(entryOffset + 72, 4294967295, true);
1247
- dirView.setUint32(entryOffset + 76, dirEntries.length > 1 ? 1 : 4294967295, true);
1321
+ dirView.setUint32(entryOffset + 76, tree.root, true);
1248
1322
  } else {
1249
- dirView.setUint32(entryOffset + 68, 4294967295, true);
1250
- dirView.setUint32(entryOffset + 72, i + 1 < dirEntries.length ? i + 1 : 4294967295, true);
1323
+ dirView.setUint32(entryOffset + 68, tree.links.get(i).left, true);
1324
+ dirView.setUint32(entryOffset + 72, tree.links.get(i).right, true);
1251
1325
  dirView.setUint32(entryOffset + 76, 4294967295, true);
1252
1326
  }
1253
1327
  dirView.setUint32(entryOffset + 116, entry.startSector, true);
@@ -1264,10 +1338,23 @@ function writeStreamSectors(outBytes, streamData, chain, sectorSize) {
1264
1338
  }
1265
1339
  }
1266
1340
 
1267
- // node_modules/.bun/@christophervr+ole2@0.4.0/node_modules/@christophervr/ole2/dist/ole2-parser-write.js
1341
+ // node_modules/.bun/@christophervr+ole2@0.8.0/node_modules/@christophervr/ole2/dist/ole2-parser-write.js
1268
1342
  function buildOle2(streams2, rootClsid, miniStreamCutoff = 4096) {
1269
1343
  const sectorSize = 512;
1270
1344
  const miniSectorSize = 64;
1345
+ const names = [...streams2.keys()].sort(compareDirEntryNames);
1346
+ for (let i = 0; i < names.length; i++) {
1347
+ const name = names[i];
1348
+ if (name.toUpperCase().length !== name.length) {
1349
+ throw new Error("CFB stream names with expanding uppercase mappings are unsupported");
1350
+ }
1351
+ if (!name.length || name.length > 31 || /[\x00\\/:!]/.test(name)) {
1352
+ throw new Error("CFB stream names must be 1-31 UTF-16 code units without NUL, \\, /, :, or !");
1353
+ }
1354
+ if (i > 0 && compareDirEntryNames(names[i - 1], name) === 0) {
1355
+ throw new Error("Duplicate CFB stream names");
1356
+ }
1357
+ }
1271
1358
  const regularStreams = [];
1272
1359
  const miniStreams = [];
1273
1360
  for (const [name, data] of streams2) {
@@ -1285,7 +1372,7 @@ function buildOle2(streams2, rootClsid, miniStreamCutoff = 4096) {
1285
1372
  for (let i = 0; i < numSectors; i++) {
1286
1373
  sectors.push(nextSector++);
1287
1374
  }
1288
- fatChains.set(stream.name, { start: sectors[0] ?? 0, sectors });
1375
+ fatChains.set(stream.name, { start: sectors[0] ?? ENDOFCHAIN, sectors });
1289
1376
  }
1290
1377
  let miniStreamContainer = new Uint8Array(0);
1291
1378
  const miniFatChains = /* @__PURE__ */ new Map();
@@ -1308,7 +1395,7 @@ function buildOle2(streams2, rootClsid, miniStreamCutoff = 4096) {
1308
1395
  miniOffset += miniSectorSize;
1309
1396
  }
1310
1397
  miniFatChains.set(stream.name, {
1311
- start: miniSectors[0] ?? 0,
1398
+ start: miniSectors[0] ?? ENDOFCHAIN,
1312
1399
  sectors: miniSectors
1313
1400
  });
1314
1401
  }
@@ -1356,7 +1443,7 @@ function buildOle2(streams2, rootClsid, miniStreamCutoff = 4096) {
1356
1443
  nextSector += numDirSectors;
1357
1444
  let firstMiniFATSector = ENDOFCHAIN;
1358
1445
  let numMiniFATSectors = 0;
1359
- if (miniStreams.length > 0) {
1446
+ if (nextMiniSector > 0) {
1360
1447
  numMiniFATSectors = Math.ceil(nextMiniSector * 4 / sectorSize);
1361
1448
  firstMiniFATSector = nextSector;
1362
1449
  nextSector += numMiniFATSectors;