pptx-react-viewer 1.1.4 → 1.1.5
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/index.js +512 -96
- package/dist/index.mjs +512 -97
- package/dist/viewer/index.js +530 -102
- package/dist/viewer/index.mjs +530 -103
- package/node_modules/emf-converter/dist/index.d.mts +2 -2
- package/node_modules/emf-converter/dist/index.d.ts +2 -2
- package/node_modules/emf-converter/dist/index.js +91 -33
- package/node_modules/emf-converter/dist/index.mjs +91 -33
- package/node_modules/emf-converter/package.json +1 -1
- package/node_modules/mtx-decompressor/dist/index.js +39 -9
- package/node_modules/mtx-decompressor/dist/index.mjs +39 -9
- package/node_modules/mtx-decompressor/package.json +1 -1
- package/node_modules/pptx-viewer-core/dist/cli/index.js +0 -0
- package/node_modules/pptx-viewer-core/dist/cli/index.mjs +0 -0
- package/node_modules/pptx-viewer-core/dist/converter/index.js +0 -0
- package/node_modules/pptx-viewer-core/dist/converter/index.mjs +0 -0
- package/node_modules/pptx-viewer-core/dist/index.d.mts +95 -11
- package/node_modules/pptx-viewer-core/dist/index.d.ts +95 -11
- package/node_modules/pptx-viewer-core/dist/index.js +795 -257
- package/node_modules/pptx-viewer-core/dist/index.mjs +791 -258
- package/node_modules/pptx-viewer-core/dist/{signature-inspection-status-BcJSdOvb.d.mts → signature-inspection-status-BCUpfCQh.d.mts} +13 -2
- package/node_modules/pptx-viewer-core/dist/{signature-inspection-status-BcJSdOvb.d.ts → signature-inspection-status-BCUpfCQh.d.ts} +13 -2
- package/node_modules/pptx-viewer-core/dist/signature-node/index.d.mts +2 -2
- package/node_modules/pptx-viewer-core/dist/signature-node/index.d.ts +2 -2
- package/node_modules/pptx-viewer-core/dist/signature-node/index.js +17 -3
- package/node_modules/pptx-viewer-core/dist/signature-node/index.mjs +16 -4
- package/node_modules/pptx-viewer-core/package.json +1 -1
- package/package.json +6 -4
|
@@ -10327,7 +10327,7 @@ var PptxAnimationWriteService = class {
|
|
|
10327
10327
|
return existingRawTiming;
|
|
10328
10328
|
}
|
|
10329
10329
|
if (existingRawTiming) {
|
|
10330
|
-
const cloned = JSON.parse(JSON.stringify(existingRawTiming));
|
|
10330
|
+
const cloned = typeof structuredClone === "function" ? structuredClone(existingRawTiming) : JSON.parse(JSON.stringify(existingRawTiming));
|
|
10331
10331
|
return surgicallyUpdateTimingTree(cloned, validAnimations);
|
|
10332
10332
|
}
|
|
10333
10333
|
this.nextId = 1;
|
|
@@ -10467,7 +10467,14 @@ var PptxRuntimeDependencyFactory = class {
|
|
|
10467
10467
|
// 0x80070570 (ERROR_FILE_CORRUPT) and shows the repair dialog.
|
|
10468
10468
|
// More generally, OOXML element text is always an untyped string;
|
|
10469
10469
|
// downstream callers coerce where needed.
|
|
10470
|
-
parseTagValue: false
|
|
10470
|
+
parseTagValue: false,
|
|
10471
|
+
// Security hardening (Load M3): explicitly disable XML entity
|
|
10472
|
+
// processing. PPTX XML never uses DOCTYPE / DTDs, so allowing
|
|
10473
|
+
// entity expansion serves only as an attack surface
|
|
10474
|
+
// (billion-laughs / external-entity / future fast-xml-parser
|
|
10475
|
+
// regressions). v5.5.5 currently defaults to safe behaviour but
|
|
10476
|
+
// pinning this makes the guarantee explicit and forward-stable.
|
|
10477
|
+
processEntities: false
|
|
10471
10478
|
});
|
|
10472
10479
|
}
|
|
10473
10480
|
createBuilder() {
|
|
@@ -11017,6 +11024,23 @@ function arrayBufferToBase64(buffer) {
|
|
|
11017
11024
|
return btoa(binary);
|
|
11018
11025
|
}
|
|
11019
11026
|
|
|
11027
|
+
// src/core/core/types.ts
|
|
11028
|
+
var DEFAULT_MAX_UNCOMPRESSED_BYTES = 500 * 1024 * 1024;
|
|
11029
|
+
var MAX_ZIP_ENTRY_COUNT = 65536;
|
|
11030
|
+
var ZipBombError = class extends Error {
|
|
11031
|
+
code = "ZIP_BOMB";
|
|
11032
|
+
uncompressedBytes;
|
|
11033
|
+
limit;
|
|
11034
|
+
entryCount;
|
|
11035
|
+
constructor(message, details) {
|
|
11036
|
+
super(message);
|
|
11037
|
+
this.name = "ZipBombError";
|
|
11038
|
+
this.uncompressedBytes = details.uncompressedBytes;
|
|
11039
|
+
this.limit = details.limit;
|
|
11040
|
+
this.entryCount = details.entryCount;
|
|
11041
|
+
}
|
|
11042
|
+
};
|
|
11043
|
+
|
|
11020
11044
|
// ../mtx-decompressor/dist/index.mjs
|
|
11021
11045
|
var Stream = class _Stream {
|
|
11022
11046
|
buf;
|
|
@@ -11606,14 +11630,8 @@ function decodeSimpleGlyph(numContours, streams, out, calcBBox, minX, minY, maxX
|
|
|
11606
11630
|
const flag = flagBytes[i];
|
|
11607
11631
|
onCurve[i] = flag & 128 ? 0 : 1;
|
|
11608
11632
|
const enc = TRIPLET_ENCODINGS[flag & 127];
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
for (let b = 0; b < extraBytes; b++) {
|
|
11612
|
-
subBuf[b] = sGlyph.readU8();
|
|
11613
|
-
}
|
|
11614
|
-
const sub = new Stream(subBuf, extraBytes);
|
|
11615
|
-
let dx = sub.readNBits(enc.xBits) + enc.deltaX;
|
|
11616
|
-
let dy = sub.readNBits(enc.yBits) + enc.deltaY;
|
|
11633
|
+
let dx = sGlyph.readNBits(enc.xBits) + enc.deltaX;
|
|
11634
|
+
let dy = sGlyph.readNBits(enc.yBits) + enc.deltaY;
|
|
11617
11635
|
if (enc.xSign !== 0) {
|
|
11618
11636
|
dx *= enc.xSign;
|
|
11619
11637
|
}
|
|
@@ -12165,6 +12183,8 @@ var MAX_2BYTE_DIST = 512;
|
|
|
12165
12183
|
var PRELOAD_SIZE = 2 * 32 * 96 + 4 * 256;
|
|
12166
12184
|
var LEN_MIN = 2;
|
|
12167
12185
|
var DIST_MIN = 1;
|
|
12186
|
+
var MAX_OUT_LEN = 4 * 1024 * 1024;
|
|
12187
|
+
var MAX_OUT = 16 * 1024 * 1024;
|
|
12168
12188
|
var RLE_INITIAL = 0;
|
|
12169
12189
|
var RLE_NORMAL = 1;
|
|
12170
12190
|
var RLE_SEEN_ESCAPE = 2;
|
|
@@ -12174,6 +12194,9 @@ function setDistRange(length) {
|
|
|
12174
12194
|
let distMax = DIST_MIN + ((1 << DIST_WIDTH * numDistRanges) - 1);
|
|
12175
12195
|
while (distMax < length) {
|
|
12176
12196
|
numDistRanges++;
|
|
12197
|
+
if (numDistRanges > 8) {
|
|
12198
|
+
throw new Error("LZCOMP setDistRange: numDistRanges exceeds bound (8)");
|
|
12199
|
+
}
|
|
12177
12200
|
distMax = DIST_MIN + ((1 << DIST_WIDTH * numDistRanges) - 1);
|
|
12178
12201
|
}
|
|
12179
12202
|
const DUP2 = 256 + (1 << LEN_WIDTH) * numDistRanges;
|
|
@@ -12204,7 +12227,11 @@ function decodeLength(lenEcoder, symbol, numDistRangesOut) {
|
|
|
12204
12227
|
let firstTime = true;
|
|
12205
12228
|
let value = 0;
|
|
12206
12229
|
let done;
|
|
12230
|
+
let iters = 0;
|
|
12207
12231
|
do {
|
|
12232
|
+
if (++iters > 16) {
|
|
12233
|
+
throw new Error("LZCOMP decodeLength: iteration cap exceeded");
|
|
12234
|
+
}
|
|
12208
12235
|
let bits;
|
|
12209
12236
|
if (firstTime) {
|
|
12210
12237
|
bits = symbol - 256;
|
|
@@ -12243,6 +12270,9 @@ function lzcompDecompress(data, size, version) {
|
|
|
12243
12270
|
const distEcoder = new AHuff(bio, 1 << DIST_WIDTH);
|
|
12244
12271
|
const lenEcoder = new AHuff(bio, 1 << LEN_WIDTH);
|
|
12245
12272
|
const outLen = bio.readValue(24);
|
|
12273
|
+
if (outLen > MAX_OUT_LEN) {
|
|
12274
|
+
throw new Error(`LZCOMP outLen ${outLen} exceeds maximum (${MAX_OUT_LEN})`);
|
|
12275
|
+
}
|
|
12246
12276
|
const { DUP2, DUP4, DUP6, NUM_SYMS } = setDistRange(outLen);
|
|
12247
12277
|
const symEcoder = new AHuff(bio, NUM_SYMS);
|
|
12248
12278
|
const windowSize = PRELOAD_SIZE + outLen;
|
|
@@ -12259,6 +12289,9 @@ function lzcompDecompress(data, size, version) {
|
|
|
12259
12289
|
if (!usingRunLength) {
|
|
12260
12290
|
if (outIdx >= outBufSize) {
|
|
12261
12291
|
outBufSize += outBufSize >>> 1;
|
|
12292
|
+
if (outBufSize > MAX_OUT) {
|
|
12293
|
+
throw new Error("LZCOMP output exceeds maximum size budget");
|
|
12294
|
+
}
|
|
12262
12295
|
const tmp = new Uint8Array(outBufSize);
|
|
12263
12296
|
tmp.set(outBuf);
|
|
12264
12297
|
outBuf = tmp;
|
|
@@ -12277,6 +12310,9 @@ function lzcompDecompress(data, size, version) {
|
|
|
12277
12310
|
} else {
|
|
12278
12311
|
if (outIdx >= outBufSize) {
|
|
12279
12312
|
outBufSize += outBufSize >>> 1;
|
|
12313
|
+
if (outBufSize > MAX_OUT) {
|
|
12314
|
+
throw new Error("LZCOMP output exceeds maximum size budget");
|
|
12315
|
+
}
|
|
12280
12316
|
const tmp = new Uint8Array(outBufSize);
|
|
12281
12317
|
tmp.set(outBuf);
|
|
12282
12318
|
outBuf = tmp;
|
|
@@ -12289,6 +12325,9 @@ function lzcompDecompress(data, size, version) {
|
|
|
12289
12325
|
if (rleCount === 0) {
|
|
12290
12326
|
if (outIdx >= outBufSize) {
|
|
12291
12327
|
outBufSize += outBufSize >>> 1;
|
|
12328
|
+
if (outBufSize > MAX_OUT) {
|
|
12329
|
+
throw new Error("LZCOMP output exceeds maximum size budget");
|
|
12330
|
+
}
|
|
12292
12331
|
const tmp = new Uint8Array(outBufSize);
|
|
12293
12332
|
tmp.set(outBuf);
|
|
12294
12333
|
outBuf = tmp;
|
|
@@ -12302,6 +12341,9 @@ function lzcompDecompress(data, size, version) {
|
|
|
12302
12341
|
case RLE_NEED_BYTE: {
|
|
12303
12342
|
if (outIdx + rleCount > outBufSize) {
|
|
12304
12343
|
outBufSize = outIdx + rleCount + (outBufSize >>> 1);
|
|
12344
|
+
if (outBufSize > MAX_OUT) {
|
|
12345
|
+
throw new Error("LZCOMP output exceeds maximum size budget");
|
|
12346
|
+
}
|
|
12305
12347
|
const tmp = new Uint8Array(outBufSize);
|
|
12306
12348
|
tmp.set(outBuf);
|
|
12307
12349
|
outBuf = tmp;
|
|
@@ -12461,11 +12503,23 @@ function dumpContainer(ctr) {
|
|
|
12461
12503
|
}
|
|
12462
12504
|
var ENCRYPTION_KEY = 80;
|
|
12463
12505
|
function unpackMtx(data, size) {
|
|
12506
|
+
if (size < 10 || data.length < 10) {
|
|
12507
|
+
throw new Error("MTX data too small: header requires at least 10 bytes");
|
|
12508
|
+
}
|
|
12464
12509
|
const versionMagic = data[0];
|
|
12465
12510
|
const offset2 = data[4] << 16 | data[5] << 8 | data[6];
|
|
12466
12511
|
const offset3 = data[7] << 16 | data[8] << 8 | data[9];
|
|
12512
|
+
if (offset2 < 10 || offset3 < offset2 || offset3 > size) {
|
|
12513
|
+
throw new Error(
|
|
12514
|
+
`MTX header offsets out of bounds: offset2=${offset2}, offset3=${offset3}, size=${size}`
|
|
12515
|
+
);
|
|
12516
|
+
}
|
|
12467
12517
|
const offsets = [10, offset2, offset3];
|
|
12468
|
-
const blockSizes = [
|
|
12518
|
+
const blockSizes = [
|
|
12519
|
+
Math.max(0, offset2 - 10),
|
|
12520
|
+
Math.max(0, offset3 - offset2),
|
|
12521
|
+
Math.max(0, size - offset3)
|
|
12522
|
+
];
|
|
12469
12523
|
const streams = [];
|
|
12470
12524
|
const decompressedSizes = [];
|
|
12471
12525
|
for (let i = 0; i < 3; i++) {
|
|
@@ -14712,6 +14766,9 @@ function cloneXmlObject(value) {
|
|
|
14712
14766
|
return void 0;
|
|
14713
14767
|
}
|
|
14714
14768
|
try {
|
|
14769
|
+
if (typeof structuredClone === "function") {
|
|
14770
|
+
return structuredClone(value);
|
|
14771
|
+
}
|
|
14715
14772
|
return JSON.parse(JSON.stringify(value));
|
|
14716
14773
|
} catch (error) {
|
|
14717
14774
|
console.warn("Failed to clone XML object, returning undefined.", value, error);
|
|
@@ -15173,7 +15230,23 @@ var extensionByResponseMime = {
|
|
|
15173
15230
|
"image/svg+xml": "svg",
|
|
15174
15231
|
"application/octet-stream": "bin"
|
|
15175
15232
|
};
|
|
15176
|
-
|
|
15233
|
+
var DEFAULT_SAFE_SCHEMES = /* @__PURE__ */ new Set(["pptx-resource:", "blob:", "data:"]);
|
|
15234
|
+
async function fetchUrlToBytes(url, options = {}) {
|
|
15235
|
+
let scheme;
|
|
15236
|
+
try {
|
|
15237
|
+
scheme = new URL(url).protocol;
|
|
15238
|
+
} catch {
|
|
15239
|
+
return null;
|
|
15240
|
+
}
|
|
15241
|
+
const allowedSchemes = options.allowedSchemes ?? DEFAULT_SAFE_SCHEMES;
|
|
15242
|
+
const isHttp = scheme === "http:" || scheme === "https:";
|
|
15243
|
+
if (isHttp) {
|
|
15244
|
+
if (options.allowExternalFetch !== true) {
|
|
15245
|
+
return null;
|
|
15246
|
+
}
|
|
15247
|
+
} else if (!allowedSchemes.has(scheme)) {
|
|
15248
|
+
return null;
|
|
15249
|
+
}
|
|
15177
15250
|
try {
|
|
15178
15251
|
const response = await fetch(url);
|
|
15179
15252
|
if (!response.ok) {
|
|
@@ -15303,17 +15376,35 @@ function buildForest(nodes) {
|
|
|
15303
15376
|
}
|
|
15304
15377
|
return roots;
|
|
15305
15378
|
}
|
|
15306
|
-
|
|
15379
|
+
var MAX_TREE_DEPTH = 256;
|
|
15380
|
+
function treeWidth(t, depth = 0) {
|
|
15381
|
+
if (depth >= MAX_TREE_DEPTH) {
|
|
15382
|
+
return 1;
|
|
15383
|
+
}
|
|
15307
15384
|
if (t.children.length === 0) {
|
|
15308
15385
|
return 1;
|
|
15309
15386
|
}
|
|
15310
|
-
|
|
15387
|
+
let sum = 0;
|
|
15388
|
+
for (const c of t.children) {
|
|
15389
|
+
sum += treeWidth(c, depth + 1);
|
|
15390
|
+
}
|
|
15391
|
+
return sum;
|
|
15311
15392
|
}
|
|
15312
|
-
function treeDepth(t) {
|
|
15393
|
+
function treeDepth(t, depth = 0) {
|
|
15394
|
+
if (depth >= MAX_TREE_DEPTH) {
|
|
15395
|
+
return 0;
|
|
15396
|
+
}
|
|
15313
15397
|
if (t.children.length === 0) {
|
|
15314
15398
|
return 1;
|
|
15315
15399
|
}
|
|
15316
|
-
|
|
15400
|
+
let max = 0;
|
|
15401
|
+
for (const c of t.children) {
|
|
15402
|
+
const d = treeDepth(c, depth + 1);
|
|
15403
|
+
if (d > max) {
|
|
15404
|
+
max = d;
|
|
15405
|
+
}
|
|
15406
|
+
}
|
|
15407
|
+
return 1 + max;
|
|
15317
15408
|
}
|
|
15318
15409
|
function getContentNodes(nodes) {
|
|
15319
15410
|
return nodes.filter((n) => n.text.length > 0);
|
|
@@ -15418,7 +15509,11 @@ function computeHierarchyLayout(nodes, constraints, bounds) {
|
|
|
15418
15509
|
const nodeW = constraints.w ? constraints.w * bounds.width : Math.min(cellW * 0.8, 140);
|
|
15419
15510
|
const nodeH = constraints.h ? constraints.h * bounds.height : Math.min(cellH * 0.35, 50);
|
|
15420
15511
|
const shapes = [];
|
|
15512
|
+
const MAX_WALK_DEPTH = 256;
|
|
15421
15513
|
function walk(t, xOffset, level) {
|
|
15514
|
+
if (level >= MAX_WALK_DEPTH) {
|
|
15515
|
+
return 1;
|
|
15516
|
+
}
|
|
15422
15517
|
const w = treeWidth(t);
|
|
15423
15518
|
const cx = bounds.x + begPad + (xOffset + w / 2) * cellW;
|
|
15424
15519
|
const cy = bounds.y + begPad + level * cellH + cellH / 2;
|
|
@@ -17600,7 +17695,11 @@ function reflowHierarchy(nodes, bounds) {
|
|
|
17600
17695
|
const boxW = Math.min(cellW * 0.8, 140);
|
|
17601
17696
|
const boxH = Math.min(cellH * 0.35, 28);
|
|
17602
17697
|
const shapes = [];
|
|
17698
|
+
const MAX_WALK_DEPTH = 256;
|
|
17603
17699
|
function walkTree(t, xOffset, level) {
|
|
17700
|
+
if (level >= MAX_WALK_DEPTH) {
|
|
17701
|
+
return 1;
|
|
17702
|
+
}
|
|
17604
17703
|
const w = treeWidth(t);
|
|
17605
17704
|
const cx = bounds.x + padding + (xOffset + w / 2) * cellW;
|
|
17606
17705
|
const cy = bounds.y + padding + level * cellH + cellH / 2;
|
|
@@ -19180,7 +19279,13 @@ async function createModifyVerifier(password, options) {
|
|
|
19180
19279
|
|
|
19181
19280
|
// src/core/utils/signature-xml-utils.ts
|
|
19182
19281
|
function escapeXmlAttr(value) {
|
|
19183
|
-
return value.replace(/&/g, "&").replace(
|
|
19282
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
19283
|
+
}
|
|
19284
|
+
function escapeXmlText(value) {
|
|
19285
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
19286
|
+
}
|
|
19287
|
+
function isValidBase64(value) {
|
|
19288
|
+
return typeof value === "string" && value.length > 0 && /^[A-Za-z0-9+/=\s]+$/.test(value);
|
|
19184
19289
|
}
|
|
19185
19290
|
function extractTagAttribute(xml, tagName, attributeName) {
|
|
19186
19291
|
const pattern = new RegExp(
|
|
@@ -19481,6 +19586,8 @@ function createTempCanvas(width, height) {
|
|
|
19481
19586
|
if (width <= 0 || height <= 0) {
|
|
19482
19587
|
return null;
|
|
19483
19588
|
}
|
|
19589
|
+
width = Math.max(1, Math.min(Math.floor(width), 8192));
|
|
19590
|
+
height = Math.max(1, Math.min(Math.floor(height), 8192));
|
|
19484
19591
|
if (typeof OffscreenCanvas !== "undefined") {
|
|
19485
19592
|
const canvas = new OffscreenCanvas(width, height);
|
|
19486
19593
|
const ctx = canvas.getContext("2d");
|
|
@@ -19541,18 +19648,34 @@ function applyFont(ctx, state) {
|
|
|
19541
19648
|
ctx.font = `${italic}${weight}${size}px ${state.fontFamily}`;
|
|
19542
19649
|
}
|
|
19543
19650
|
function readUtf16LE2(view, offset, charCount) {
|
|
19544
|
-
|
|
19545
|
-
|
|
19546
|
-
|
|
19547
|
-
|
|
19548
|
-
|
|
19549
|
-
|
|
19550
|
-
|
|
19551
|
-
|
|
19651
|
+
if (charCount <= 0) {
|
|
19652
|
+
return "";
|
|
19653
|
+
}
|
|
19654
|
+
const maxBytes = view.byteLength - offset;
|
|
19655
|
+
if (maxBytes <= 0) {
|
|
19656
|
+
return "";
|
|
19657
|
+
}
|
|
19658
|
+
const usableChars = Math.min(charCount, Math.floor(maxBytes / 2));
|
|
19659
|
+
if (usableChars <= 0) {
|
|
19660
|
+
return "";
|
|
19661
|
+
}
|
|
19662
|
+
let decoded;
|
|
19663
|
+
try {
|
|
19664
|
+
const bytes = new Uint8Array(view.buffer, view.byteOffset + offset, usableChars * 2);
|
|
19665
|
+
decoded = new TextDecoder("utf-16le").decode(bytes);
|
|
19666
|
+
} catch {
|
|
19667
|
+
const chars = [];
|
|
19668
|
+
for (let i = 0; i < usableChars; i++) {
|
|
19669
|
+
const code = view.getUint16(offset + i * 2, true);
|
|
19670
|
+
if (code === 0) {
|
|
19671
|
+
return chars.join("");
|
|
19672
|
+
}
|
|
19673
|
+
chars.push(String.fromCharCode(code));
|
|
19552
19674
|
}
|
|
19553
|
-
chars.
|
|
19675
|
+
return chars.join("");
|
|
19554
19676
|
}
|
|
19555
|
-
|
|
19677
|
+
const nul = decoded.indexOf(String.fromCharCode(0));
|
|
19678
|
+
return nul === -1 ? decoded : decoded.slice(0, nul);
|
|
19556
19679
|
}
|
|
19557
19680
|
function getStockObject(index) {
|
|
19558
19681
|
switch (index) {
|
|
@@ -21504,7 +21627,12 @@ function applyClipCombineMode(rCtx, combineMode, opName, clipFn) {
|
|
|
21504
21627
|
return true;
|
|
21505
21628
|
}
|
|
21506
21629
|
}
|
|
21507
|
-
|
|
21630
|
+
var MAX_REGION_TRACE_DEPTH = 64;
|
|
21631
|
+
function traceRegionNodePath(ctx, node, depth = 0) {
|
|
21632
|
+
if (depth > MAX_REGION_TRACE_DEPTH) {
|
|
21633
|
+
ctx.rect(0, 0, 0, 0);
|
|
21634
|
+
return;
|
|
21635
|
+
}
|
|
21508
21636
|
switch (node.type) {
|
|
21509
21637
|
case "rect":
|
|
21510
21638
|
ctx.rect(node.x, node.y, node.width, node.height);
|
|
@@ -21519,7 +21647,7 @@ function traceRegionNodePath(ctx, node) {
|
|
|
21519
21647
|
ctx.rect(0, 0, 0, 0);
|
|
21520
21648
|
break;
|
|
21521
21649
|
case "combine":
|
|
21522
|
-
traceRegionNodePath(ctx, node.left);
|
|
21650
|
+
traceRegionNodePath(ctx, node.left, depth + 1);
|
|
21523
21651
|
if (node.combineMode !== 0) {
|
|
21524
21652
|
emfWarn(
|
|
21525
21653
|
`traceRegionNodePath: combine mode ${node.combineMode} not fully supported, using left subtree only`
|
|
@@ -21530,7 +21658,7 @@ function traceRegionNodePath(ctx, node) {
|
|
|
21530
21658
|
} catch {
|
|
21531
21659
|
}
|
|
21532
21660
|
ctx.beginPath();
|
|
21533
|
-
traceRegionNodePath(ctx, node.right);
|
|
21661
|
+
traceRegionNodePath(ctx, node.right, depth + 1);
|
|
21534
21662
|
}
|
|
21535
21663
|
break;
|
|
21536
21664
|
}
|
|
@@ -22320,19 +22448,23 @@ function handleEmfPlusObjectRecord(rCtx, recFlags, dataOff, recDataSize) {
|
|
|
22320
22448
|
}
|
|
22321
22449
|
}
|
|
22322
22450
|
}
|
|
22323
|
-
|
|
22451
|
+
var MAX_REGION_NODE_DEPTH = 64;
|
|
22452
|
+
function parseRegionNode(view, off, endOff, depth = 0) {
|
|
22324
22453
|
if (off + 4 > endOff) {
|
|
22325
22454
|
return null;
|
|
22326
22455
|
}
|
|
22456
|
+
if (depth > MAX_REGION_NODE_DEPTH) {
|
|
22457
|
+
return null;
|
|
22458
|
+
}
|
|
22327
22459
|
const nodeType = view.getUint32(off, true);
|
|
22328
22460
|
let cursor = off + 4;
|
|
22329
22461
|
if (nodeType <= 4) {
|
|
22330
|
-
const leftResult = parseRegionNode(view, cursor, endOff);
|
|
22462
|
+
const leftResult = parseRegionNode(view, cursor, endOff, depth + 1);
|
|
22331
22463
|
if (!leftResult) {
|
|
22332
22464
|
return null;
|
|
22333
22465
|
}
|
|
22334
22466
|
cursor += leftResult.bytesRead;
|
|
22335
|
-
const rightResult = parseRegionNode(view, cursor, endOff);
|
|
22467
|
+
const rightResult = parseRegionNode(view, cursor, endOff, depth + 1);
|
|
22336
22468
|
if (!rightResult) {
|
|
22337
22469
|
return null;
|
|
22338
22470
|
}
|
|
@@ -22718,18 +22850,23 @@ function replayEmfPlusRecords(view, offset, length, ctx, _canvasW, _canvasH, sta
|
|
|
22718
22850
|
if (recDataSize >= 4) {
|
|
22719
22851
|
const totalSize = view.getUint32(dataOff, true);
|
|
22720
22852
|
const objectType = recFlags >> 8 & 127;
|
|
22721
|
-
|
|
22722
|
-
|
|
22723
|
-
|
|
22724
|
-
|
|
22725
|
-
|
|
22726
|
-
|
|
22727
|
-
|
|
22728
|
-
|
|
22729
|
-
|
|
22730
|
-
|
|
22731
|
-
|
|
22732
|
-
|
|
22853
|
+
const MAX_CONTINUATION_BYTES = 64 * 1024 * 1024;
|
|
22854
|
+
const remainingEmfPlusBytes = view.byteLength - dataOff;
|
|
22855
|
+
if (!Number.isFinite(totalSize) || totalSize <= 0 || totalSize > MAX_CONTINUATION_BYTES || totalSize > remainingEmfPlusBytes || recDataSize - 4 < 0) ;
|
|
22856
|
+
else {
|
|
22857
|
+
rCtx.continuationTotalSize = totalSize;
|
|
22858
|
+
rCtx.continuationObjectId = objectId;
|
|
22859
|
+
rCtx.continuationObjectType = objectType;
|
|
22860
|
+
rCtx.continuationBuffer = new Uint8Array(totalSize);
|
|
22861
|
+
const chunkSize = recDataSize - 4;
|
|
22862
|
+
const chunk = new Uint8Array(
|
|
22863
|
+
view.buffer,
|
|
22864
|
+
view.byteOffset + dataOff + 4,
|
|
22865
|
+
Math.min(chunkSize, totalSize)
|
|
22866
|
+
);
|
|
22867
|
+
rCtx.continuationBuffer.set(chunk, 0);
|
|
22868
|
+
rCtx.continuationOffset = chunk.length;
|
|
22869
|
+
}
|
|
22733
22870
|
}
|
|
22734
22871
|
} else {
|
|
22735
22872
|
const remaining = rCtx.continuationTotalSize - rCtx.continuationOffset;
|
|
@@ -23366,8 +23503,11 @@ function replayWmfRecords(view, ctx, header, canvasW, canvasH) {
|
|
|
23366
23503
|
);
|
|
23367
23504
|
}
|
|
23368
23505
|
}
|
|
23369
|
-
|
|
23370
|
-
|
|
23506
|
+
var MAX_METAFILE_RECURSION = 3;
|
|
23507
|
+
async function processDeferredImages(ctx, deferredImages, recursionDepth = 0) {
|
|
23508
|
+
emfLog(
|
|
23509
|
+
`processDeferredImages: processing ${deferredImages.length} deferred images (recursionDepth=${recursionDepth})...`
|
|
23510
|
+
);
|
|
23371
23511
|
for (let idx = 0; idx < deferredImages.length; idx++) {
|
|
23372
23512
|
const img = deferredImages[idx];
|
|
23373
23513
|
emfLog(
|
|
@@ -23386,8 +23526,26 @@ async function processDeferredImages(ctx, deferredImages) {
|
|
|
23386
23526
|
img.transform[5]
|
|
23387
23527
|
);
|
|
23388
23528
|
if (img.isMetafile) {
|
|
23529
|
+
if (recursionDepth >= MAX_METAFILE_RECURSION) {
|
|
23530
|
+
emfWarn(
|
|
23531
|
+
` Deferred image [${idx}]: skipping embedded metafile \u2014 recursion depth ${recursionDepth} >= ${MAX_METAFILE_RECURSION}`
|
|
23532
|
+
);
|
|
23533
|
+
continue;
|
|
23534
|
+
}
|
|
23389
23535
|
emfLog(` Deferred image [${idx}]: recursively converting embedded metafile...`);
|
|
23390
|
-
const metafileDataUrl = await convertEmfToDataUrl(
|
|
23536
|
+
const metafileDataUrl = await convertEmfToDataUrl(
|
|
23537
|
+
plainBuffer,
|
|
23538
|
+
void 0,
|
|
23539
|
+
void 0,
|
|
23540
|
+
void 0,
|
|
23541
|
+
recursionDepth + 1
|
|
23542
|
+
) ?? await convertWmfToDataUrl(
|
|
23543
|
+
plainBuffer,
|
|
23544
|
+
void 0,
|
|
23545
|
+
void 0,
|
|
23546
|
+
void 0,
|
|
23547
|
+
recursionDepth + 1
|
|
23548
|
+
);
|
|
23391
23549
|
if (metafileDataUrl) {
|
|
23392
23550
|
emfLog(
|
|
23393
23551
|
` Deferred image [${idx}]: metafile converted, dataUrl length=${metafileDataUrl.length}`
|
|
@@ -23432,7 +23590,10 @@ async function processDeferredImages(ctx, deferredImages) {
|
|
|
23432
23590
|
}
|
|
23433
23591
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
23434
23592
|
}
|
|
23435
|
-
async function convertEmfToDataUrl(buffer, maxWidth, maxHeight, optionsOrDpiScale) {
|
|
23593
|
+
async function convertEmfToDataUrl(buffer, maxWidth, maxHeight, optionsOrDpiScale, recursionDepth = 0) {
|
|
23594
|
+
if (recursionDepth > MAX_METAFILE_RECURSION) {
|
|
23595
|
+
return null;
|
|
23596
|
+
}
|
|
23436
23597
|
const opts = typeof optionsOrDpiScale === "number" ? { dpiScale: optionsOrDpiScale } : optionsOrDpiScale ?? {};
|
|
23437
23598
|
const dpiScale = opts.dpiScale ?? DEFAULT_DPI_SCALE;
|
|
23438
23599
|
const effectiveMaxWidth = maxWidth ?? opts.maxWidth;
|
|
@@ -23501,7 +23662,10 @@ async function convertEmfToDataUrl(buffer, maxWidth, maxHeight, optionsOrDpiScal
|
|
|
23501
23662
|
return null;
|
|
23502
23663
|
}
|
|
23503
23664
|
}
|
|
23504
|
-
async function convertWmfToDataUrl(buffer, maxWidth, maxHeight, optionsOrDpiScale) {
|
|
23665
|
+
async function convertWmfToDataUrl(buffer, maxWidth, maxHeight, optionsOrDpiScale, recursionDepth = 0) {
|
|
23666
|
+
if (recursionDepth > MAX_METAFILE_RECURSION) {
|
|
23667
|
+
return null;
|
|
23668
|
+
}
|
|
23505
23669
|
const opts = typeof optionsOrDpiScale === "number" ? { dpiScale: optionsOrDpiScale } : optionsOrDpiScale ?? {};
|
|
23506
23670
|
const dpiScale = opts.dpiScale ?? DEFAULT_DPI_SCALE;
|
|
23507
23671
|
const effectiveMaxWidth = maxWidth ?? opts.maxWidth;
|
|
@@ -26129,6 +26293,55 @@ function relayoutSmartArt(smartArtData, containerWidth, containerHeight) {
|
|
|
26129
26293
|
return smartArtData.drawingShapes ?? [];
|
|
26130
26294
|
}
|
|
26131
26295
|
|
|
26296
|
+
// src/core/utils/safe-path.ts
|
|
26297
|
+
function safeResolveZipPath(basePath, target) {
|
|
26298
|
+
if (typeof basePath !== "string" || typeof target !== "string") {
|
|
26299
|
+
return null;
|
|
26300
|
+
}
|
|
26301
|
+
const trimmedTarget = target.trim();
|
|
26302
|
+
if (trimmedTarget.length === 0) {
|
|
26303
|
+
return null;
|
|
26304
|
+
}
|
|
26305
|
+
if (trimmedTarget.startsWith("/")) {
|
|
26306
|
+
return normaliseSegments(trimmedTarget.slice(1).replace(/\\/g, "/"));
|
|
26307
|
+
}
|
|
26308
|
+
const baseParts = basePath.replace(/\\/g, "/").split("/").filter((p) => p.length > 0);
|
|
26309
|
+
const targetParts = trimmedTarget.replace(/\\/g, "/").split("/");
|
|
26310
|
+
const stack = [...baseParts];
|
|
26311
|
+
for (const part of targetParts) {
|
|
26312
|
+
if (part === "" || part === ".") {
|
|
26313
|
+
continue;
|
|
26314
|
+
}
|
|
26315
|
+
if (part === "..") {
|
|
26316
|
+
if (stack.length === 0) {
|
|
26317
|
+
return null;
|
|
26318
|
+
}
|
|
26319
|
+
stack.pop();
|
|
26320
|
+
continue;
|
|
26321
|
+
}
|
|
26322
|
+
stack.push(part);
|
|
26323
|
+
}
|
|
26324
|
+
return stack.join("/");
|
|
26325
|
+
}
|
|
26326
|
+
function normaliseSegments(input) {
|
|
26327
|
+
const parts = input.split("/");
|
|
26328
|
+
const stack = [];
|
|
26329
|
+
for (const part of parts) {
|
|
26330
|
+
if (part === "" || part === ".") {
|
|
26331
|
+
continue;
|
|
26332
|
+
}
|
|
26333
|
+
if (part === "..") {
|
|
26334
|
+
if (stack.length === 0) {
|
|
26335
|
+
return null;
|
|
26336
|
+
}
|
|
26337
|
+
stack.pop();
|
|
26338
|
+
continue;
|
|
26339
|
+
}
|
|
26340
|
+
stack.push(part);
|
|
26341
|
+
}
|
|
26342
|
+
return stack.join("/");
|
|
26343
|
+
}
|
|
26344
|
+
|
|
26132
26345
|
// src/core/core/runtime/PptxHandlerRuntimeSaveParagraphHelpers.ts
|
|
26133
26346
|
var EMU_PER_PX5 = 9525;
|
|
26134
26347
|
function buildParagraphPropertiesXml(textStyle, paragraphAlign, bulletInfo, spacing, level) {
|
|
@@ -26565,6 +26778,12 @@ var PptxHandlerRuntime = class {
|
|
|
26565
26778
|
* images are decoded lazily on first access via {@link getImageData}.
|
|
26566
26779
|
*/
|
|
26567
26780
|
eagerDecodeImages = false;
|
|
26781
|
+
/**
|
|
26782
|
+
* When true, relationship targets pointing at `http://` / `https://`
|
|
26783
|
+
* URLs are passed through to `<img src>`. Default `false`. Mirrors the
|
|
26784
|
+
* `allowExternalImages` load option.
|
|
26785
|
+
*/
|
|
26786
|
+
allowExternalImages = false;
|
|
26568
26787
|
/** Ordered slide file paths (populated during load for action target resolution). */
|
|
26569
26788
|
orderedSlidePaths = [];
|
|
26570
26789
|
/** Theme colour scheme map: scheme key (e.g. "dk1", "accent1") -> hex colour value. */
|
|
@@ -27912,7 +28131,13 @@ var PptxHandlerRuntime7 = class extends PptxHandlerRuntime6 {
|
|
|
27912
28131
|
return void 0;
|
|
27913
28132
|
}
|
|
27914
28133
|
const ext = this.getPathExtension(imagePath);
|
|
27915
|
-
if (imagePath.startsWith("http://") || imagePath.startsWith("https://")
|
|
28134
|
+
if (imagePath.startsWith("http://") || imagePath.startsWith("https://")) {
|
|
28135
|
+
if (this.allowExternalImages !== true) {
|
|
28136
|
+
return void 0;
|
|
28137
|
+
}
|
|
28138
|
+
return imagePath;
|
|
28139
|
+
}
|
|
28140
|
+
if (imagePath.startsWith("data:")) {
|
|
27916
28141
|
return imagePath;
|
|
27917
28142
|
}
|
|
27918
28143
|
if (this.imageDataCache.has(imagePath)) {
|
|
@@ -27961,7 +28186,11 @@ var PptxHandlerRuntime7 = class extends PptxHandlerRuntime6 {
|
|
|
27961
28186
|
* Enrich parsed media elements with timing data from the slide's
|
|
27962
28187
|
* `p:timing` tree (trim, loop, poster frame, fullScreen).
|
|
27963
28188
|
*/
|
|
27964
|
-
async enrichMediaElementsWithTiming(elements, timingMap) {
|
|
28189
|
+
async enrichMediaElementsWithTiming(elements, timingMap, depth = 0) {
|
|
28190
|
+
const MAX_TIMING_DEPTH = 32;
|
|
28191
|
+
if (depth > MAX_TIMING_DEPTH) {
|
|
28192
|
+
return;
|
|
28193
|
+
}
|
|
27965
28194
|
for (const el of elements) {
|
|
27966
28195
|
if (el.type !== "media") {
|
|
27967
28196
|
continue;
|
|
@@ -28023,7 +28252,7 @@ var PptxHandlerRuntime7 = class extends PptxHandlerRuntime6 {
|
|
|
28023
28252
|
}
|
|
28024
28253
|
for (const el of elements) {
|
|
28025
28254
|
if (el.type === "group" && el.children) {
|
|
28026
|
-
await this.enrichMediaElementsWithTiming(el.children, timingMap);
|
|
28255
|
+
await this.enrichMediaElementsWithTiming(el.children, timingMap, depth + 1);
|
|
28027
28256
|
}
|
|
28028
28257
|
}
|
|
28029
28258
|
}
|
|
@@ -28396,7 +28625,7 @@ var PptxHandlerRuntime8 = class extends PptxHandlerRuntime7 {
|
|
|
28396
28625
|
};
|
|
28397
28626
|
|
|
28398
28627
|
// src/core/core/runtime/PptxHandlerRuntimeSlideMasters.ts
|
|
28399
|
-
var PptxHandlerRuntime9 = class extends PptxHandlerRuntime8 {
|
|
28628
|
+
var PptxHandlerRuntime9 = class _PptxHandlerRuntime extends PptxHandlerRuntime8 {
|
|
28400
28629
|
/**
|
|
28401
28630
|
* Parse background colour from a `p:bg` node.
|
|
28402
28631
|
*/
|
|
@@ -28435,6 +28664,18 @@ var PptxHandlerRuntime9 = class extends PptxHandlerRuntime8 {
|
|
|
28435
28664
|
}
|
|
28436
28665
|
return result;
|
|
28437
28666
|
}
|
|
28667
|
+
/**
|
|
28668
|
+
* Allowed top-level OPC archive directories (Load M1).
|
|
28669
|
+
* After path resolution, the first segment must be one of these or the
|
|
28670
|
+
* path is rejected as a traversal attempt. PPTX archives only ever
|
|
28671
|
+
* legitimately reference parts under these roots.
|
|
28672
|
+
*/
|
|
28673
|
+
static ALLOWED_PATH_ROOTS = /* @__PURE__ */ new Set([
|
|
28674
|
+
"ppt",
|
|
28675
|
+
"customXml",
|
|
28676
|
+
"docProps",
|
|
28677
|
+
"_rels"
|
|
28678
|
+
]);
|
|
28438
28679
|
resolvePath(base, relative) {
|
|
28439
28680
|
const baseParts = base.split("/").filter(Boolean);
|
|
28440
28681
|
const relParts = relative.split("/");
|
|
@@ -28443,16 +28684,36 @@ var PptxHandlerRuntime9 = class extends PptxHandlerRuntime8 {
|
|
|
28443
28684
|
}
|
|
28444
28685
|
for (const part of relParts) {
|
|
28445
28686
|
if (part === "..") {
|
|
28687
|
+
if (baseParts.length === 0) {
|
|
28688
|
+
return "";
|
|
28689
|
+
}
|
|
28446
28690
|
baseParts.pop();
|
|
28447
28691
|
} else if (part !== ".") {
|
|
28448
28692
|
baseParts.push(part);
|
|
28449
28693
|
}
|
|
28450
28694
|
}
|
|
28451
|
-
|
|
28695
|
+
const resolved = baseParts.join("/");
|
|
28696
|
+
if (resolved.length === 0) {
|
|
28697
|
+
return "";
|
|
28698
|
+
}
|
|
28699
|
+
const firstSegment = baseParts[0];
|
|
28700
|
+
if (!_PptxHandlerRuntime.ALLOWED_PATH_ROOTS.has(firstSegment)) {
|
|
28701
|
+
return "";
|
|
28702
|
+
}
|
|
28703
|
+
return resolved;
|
|
28452
28704
|
}
|
|
28453
28705
|
resolveImagePath(slidePath, target) {
|
|
28454
28706
|
const slideDir = slidePath.substring(0, slidePath.lastIndexOf("/") + 1);
|
|
28455
|
-
|
|
28707
|
+
const resolved = target.startsWith("..") ? this.resolvePath(slideDir, target) : target.startsWith("/") ? target.substring(1) : slideDir + target;
|
|
28708
|
+
if (resolved.length === 0) {
|
|
28709
|
+
return "";
|
|
28710
|
+
}
|
|
28711
|
+
const firstSlash = resolved.indexOf("/");
|
|
28712
|
+
const firstSegment = firstSlash === -1 ? resolved : resolved.substring(0, firstSlash);
|
|
28713
|
+
if (!_PptxHandlerRuntime.ALLOWED_PATH_ROOTS.has(firstSegment)) {
|
|
28714
|
+
return "";
|
|
28715
|
+
}
|
|
28716
|
+
return resolved;
|
|
28456
28717
|
}
|
|
28457
28718
|
/**
|
|
28458
28719
|
* Parse all slide masters into structured PptxSlideMaster objects.
|
|
@@ -28931,6 +29192,9 @@ var PptxHandlerRuntime11 = class extends PptxHandlerRuntime10 {
|
|
|
28931
29192
|
return void 0;
|
|
28932
29193
|
}
|
|
28933
29194
|
try {
|
|
29195
|
+
if (typeof structuredClone === "function") {
|
|
29196
|
+
return structuredClone(value);
|
|
29197
|
+
}
|
|
28934
29198
|
return JSON.parse(JSON.stringify(value));
|
|
28935
29199
|
} catch {
|
|
28936
29200
|
return void 0;
|
|
@@ -32669,13 +32933,17 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
|
|
|
32669
32933
|
if (this.customXmlParts.length === 0) {
|
|
32670
32934
|
return;
|
|
32671
32935
|
}
|
|
32936
|
+
const SAFE_ID = /^[A-Za-z0-9_-]+$/;
|
|
32937
|
+
let fallbackIndex = 1;
|
|
32672
32938
|
for (const part of this.customXmlParts) {
|
|
32673
|
-
|
|
32939
|
+
const rawId = String(part.id);
|
|
32940
|
+
const safeId = SAFE_ID.test(rawId) ? rawId : String(fallbackIndex++);
|
|
32941
|
+
this.zip.file(`customXml/item${safeId}.xml`, part.data);
|
|
32674
32942
|
if (part.properties) {
|
|
32675
|
-
this.zip.file(`customXml/itemProps${
|
|
32943
|
+
this.zip.file(`customXml/itemProps${safeId}.xml`, part.properties);
|
|
32676
32944
|
}
|
|
32677
32945
|
if (part.rels) {
|
|
32678
|
-
this.zip.file(`customXml/_rels/item${
|
|
32946
|
+
this.zip.file(`customXml/_rels/item${safeId}.xml.rels`, part.rels);
|
|
32679
32947
|
}
|
|
32680
32948
|
}
|
|
32681
32949
|
}
|
|
@@ -32976,7 +33244,10 @@ var PptxHandlerRuntime25 = class extends PptxHandlerRuntime24 {
|
|
|
32976
33244
|
if (relNode) {
|
|
32977
33245
|
const target = String(relNode["@_Target"] || "").trim();
|
|
32978
33246
|
if (target.length > 0) {
|
|
32979
|
-
|
|
33247
|
+
const resolved = safeResolveZipPath("ppt", target);
|
|
33248
|
+
if (resolved !== null) {
|
|
33249
|
+
propsPath = resolved;
|
|
33250
|
+
}
|
|
32980
33251
|
}
|
|
32981
33252
|
}
|
|
32982
33253
|
} catch {
|
|
@@ -33420,7 +33691,10 @@ var PptxHandlerRuntime27 = class extends PptxHandlerRuntime26 {
|
|
|
33420
33691
|
continue;
|
|
33421
33692
|
}
|
|
33422
33693
|
const slideDir = slidePath.substring(0, slidePath.lastIndexOf("/") + 1);
|
|
33423
|
-
|
|
33694
|
+
const resolved = safeResolveZipPath(slideDir, target);
|
|
33695
|
+
if (resolved !== null) {
|
|
33696
|
+
return resolved;
|
|
33697
|
+
}
|
|
33424
33698
|
}
|
|
33425
33699
|
return void 0;
|
|
33426
33700
|
}
|
|
@@ -33434,7 +33708,10 @@ var PptxHandlerRuntime27 = class extends PptxHandlerRuntime26 {
|
|
|
33434
33708
|
continue;
|
|
33435
33709
|
}
|
|
33436
33710
|
const layoutDir = layoutPath.substring(0, layoutPath.lastIndexOf("/") + 1);
|
|
33437
|
-
|
|
33711
|
+
const resolved = safeResolveZipPath(layoutDir, target);
|
|
33712
|
+
if (resolved !== null) {
|
|
33713
|
+
return resolved;
|
|
33714
|
+
}
|
|
33438
33715
|
}
|
|
33439
33716
|
return void 0;
|
|
33440
33717
|
}
|
|
@@ -35546,7 +35823,20 @@ var PptxHandlerRuntime37 = class extends PptxHandlerRuntime36 {
|
|
|
35546
35823
|
expected
|
|
35547
35824
|
);
|
|
35548
35825
|
}
|
|
35549
|
-
mergeXmlObjects(base, override) {
|
|
35826
|
+
mergeXmlObjects(base, override, depth = 0) {
|
|
35827
|
+
const MAX_MERGE_DEPTH = 64;
|
|
35828
|
+
if (depth > MAX_MERGE_DEPTH) {
|
|
35829
|
+
if (!base && !override) {
|
|
35830
|
+
return void 0;
|
|
35831
|
+
}
|
|
35832
|
+
if (!base) {
|
|
35833
|
+
return override ? { ...override } : void 0;
|
|
35834
|
+
}
|
|
35835
|
+
if (!override) {
|
|
35836
|
+
return { ...base };
|
|
35837
|
+
}
|
|
35838
|
+
return { ...base, ...override };
|
|
35839
|
+
}
|
|
35550
35840
|
if (!base && !override) {
|
|
35551
35841
|
return void 0;
|
|
35552
35842
|
}
|
|
@@ -35560,7 +35850,7 @@ var PptxHandlerRuntime37 = class extends PptxHandlerRuntime36 {
|
|
|
35560
35850
|
for (const [key, value] of Object.entries(override)) {
|
|
35561
35851
|
const existing = merged[key];
|
|
35562
35852
|
if (value && typeof value === "object" && !Array.isArray(value) && existing && typeof existing === "object" && !Array.isArray(existing)) {
|
|
35563
|
-
merged[key] = this.mergeXmlObjects(existing, value);
|
|
35853
|
+
merged[key] = this.mergeXmlObjects(existing, value, depth + 1);
|
|
35564
35854
|
} else {
|
|
35565
35855
|
merged[key] = value;
|
|
35566
35856
|
}
|
|
@@ -37449,6 +37739,21 @@ var PptxHandlerRuntime45 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
|
|
|
37449
37739
|
};
|
|
37450
37740
|
|
|
37451
37741
|
// src/core/core/runtime/PptxHandlerRuntimePictureParsing.ts
|
|
37742
|
+
var INT32_MIN = -2147483648;
|
|
37743
|
+
var INT32_MAX = 2147483647;
|
|
37744
|
+
function parseEmuInt(value) {
|
|
37745
|
+
const parsed = parseInt(String(value ?? ""), 10);
|
|
37746
|
+
if (!Number.isFinite(parsed)) {
|
|
37747
|
+
return 0;
|
|
37748
|
+
}
|
|
37749
|
+
if (parsed < INT32_MIN) {
|
|
37750
|
+
return INT32_MIN;
|
|
37751
|
+
}
|
|
37752
|
+
if (parsed > INT32_MAX) {
|
|
37753
|
+
return INT32_MAX;
|
|
37754
|
+
}
|
|
37755
|
+
return parsed;
|
|
37756
|
+
}
|
|
37452
37757
|
var PptxHandlerRuntime46 = class _PptxHandlerRuntime extends PptxHandlerRuntime45 {
|
|
37453
37758
|
async parsePicture(pic, id, slidePath) {
|
|
37454
37759
|
try {
|
|
@@ -37468,13 +37773,13 @@ var PptxHandlerRuntime46 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
|
|
|
37468
37773
|
if (!off || !ext) {
|
|
37469
37774
|
return null;
|
|
37470
37775
|
}
|
|
37471
|
-
const x = Math.round(
|
|
37472
|
-
const y = Math.round(
|
|
37473
|
-
const width = Math.round(
|
|
37474
|
-
const height = Math.round(
|
|
37475
|
-
const rotation = xfrm["@_rot"] ?
|
|
37476
|
-
const skewX = xfrm["@_skewX"] ?
|
|
37477
|
-
const skewY = xfrm["@_skewY"] ?
|
|
37776
|
+
const x = Math.round(parseEmuInt(off["@_x"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
37777
|
+
const y = Math.round(parseEmuInt(off["@_y"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
37778
|
+
const width = Math.round(parseEmuInt(ext["@_cx"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
37779
|
+
const height = Math.round(parseEmuInt(ext["@_cy"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
37780
|
+
const rotation = xfrm["@_rot"] ? parseEmuInt(xfrm["@_rot"]) / 6e4 : void 0;
|
|
37781
|
+
const skewX = xfrm["@_skewX"] ? parseEmuInt(xfrm["@_skewX"]) / 6e4 : void 0;
|
|
37782
|
+
const skewY = xfrm["@_skewY"] ? parseEmuInt(xfrm["@_skewY"]) / 6e4 : void 0;
|
|
37478
37783
|
const { flipHorizontal, flipVertical } = this.readFlipState(xfrm);
|
|
37479
37784
|
const nvPr = pic?.["p:nvPicPr"]?.["p:nvPr"];
|
|
37480
37785
|
const videoFileNode = nvPr?.["a:videoFile"];
|
|
@@ -37501,7 +37806,13 @@ var PptxHandlerRuntime46 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
|
|
|
37501
37806
|
const slideRels = this.slideRelsMap.get(slidePath);
|
|
37502
37807
|
const posterTarget = slideRels?.get(posterREmbed || posterRLink);
|
|
37503
37808
|
if (posterTarget) {
|
|
37504
|
-
|
|
37809
|
+
const isExternal = posterTarget.startsWith("http://") || posterTarget.startsWith("https://");
|
|
37810
|
+
if (isExternal) {
|
|
37811
|
+
if (this.allowExternalImages === true) {
|
|
37812
|
+
posterFramePath = posterTarget;
|
|
37813
|
+
posterFrameData = posterTarget;
|
|
37814
|
+
}
|
|
37815
|
+
} else if (posterTarget.startsWith("data:")) {
|
|
37505
37816
|
posterFramePath = posterTarget;
|
|
37506
37817
|
posterFrameData = posterTarget;
|
|
37507
37818
|
} else {
|
|
@@ -37621,7 +37932,13 @@ var PptxHandlerRuntime46 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
|
|
|
37621
37932
|
const slideRels = this.slideRelsMap.get(slidePath);
|
|
37622
37933
|
const target = slideRels?.get(rEmbed || rLink);
|
|
37623
37934
|
if (target) {
|
|
37624
|
-
|
|
37935
|
+
const isExternal = target.startsWith("http://") || target.startsWith("https://");
|
|
37936
|
+
if (isExternal) {
|
|
37937
|
+
if (this.allowExternalImages === true) {
|
|
37938
|
+
imagePath = target;
|
|
37939
|
+
imageData = target;
|
|
37940
|
+
}
|
|
37941
|
+
} else if (target.startsWith("data:")) {
|
|
37625
37942
|
imagePath = target;
|
|
37626
37943
|
imageData = target;
|
|
37627
37944
|
} else {
|
|
@@ -38055,32 +38372,55 @@ var PptxHandlerRuntime47 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
|
|
|
38055
38372
|
};
|
|
38056
38373
|
|
|
38057
38374
|
// src/core/core/runtime/PptxHandlerRuntimeGroupParsing.ts
|
|
38375
|
+
var MAX_GROUP_DEPTH = 64;
|
|
38376
|
+
var INT32_MIN2 = -2147483648;
|
|
38377
|
+
var INT32_MAX2 = 2147483647;
|
|
38378
|
+
function parseEmuInt2(value) {
|
|
38379
|
+
const parsed = parseInt(String(value ?? ""), 10);
|
|
38380
|
+
if (!Number.isFinite(parsed)) {
|
|
38381
|
+
return 0;
|
|
38382
|
+
}
|
|
38383
|
+
if (parsed < INT32_MIN2) {
|
|
38384
|
+
return INT32_MIN2;
|
|
38385
|
+
}
|
|
38386
|
+
if (parsed > INT32_MAX2) {
|
|
38387
|
+
return INT32_MAX2;
|
|
38388
|
+
}
|
|
38389
|
+
return parsed;
|
|
38390
|
+
}
|
|
38058
38391
|
var PptxHandlerRuntime48 = class _PptxHandlerRuntime extends PptxHandlerRuntime47 {
|
|
38059
|
-
async parseGroupShape(group, baseId, slidePath, rawXmlStr) {
|
|
38392
|
+
async parseGroupShape(group, baseId, slidePath, rawXmlStr, depth = 0) {
|
|
38393
|
+
if (depth > MAX_GROUP_DEPTH) {
|
|
38394
|
+
this.compatibilityService.reportWarning({
|
|
38395
|
+
code: "group-depth-exceeded",
|
|
38396
|
+
severity: "warning",
|
|
38397
|
+
scope: "element",
|
|
38398
|
+
message: `Group nesting exceeded ${MAX_GROUP_DEPTH} levels; truncating subtree (baseId=${baseId})`,
|
|
38399
|
+
slideId: slidePath,
|
|
38400
|
+
elementId: baseId
|
|
38401
|
+
});
|
|
38402
|
+
return [];
|
|
38403
|
+
}
|
|
38060
38404
|
const grpSpPr = group["p:grpSpPr"];
|
|
38061
38405
|
const xfrm = grpSpPr?.["a:xfrm"];
|
|
38062
38406
|
let parentX = 0, parentY = 0, parentW = 0, parentH = 0;
|
|
38063
38407
|
let chX = 0, chY = 0, chW = 0, chH = 0;
|
|
38064
38408
|
if (xfrm) {
|
|
38065
38409
|
if (xfrm["a:off"]) {
|
|
38066
|
-
parentX = Math.round(
|
|
38067
|
-
parentY = Math.round(
|
|
38410
|
+
parentX = Math.round(parseEmuInt2(xfrm["a:off"]["@_x"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
38411
|
+
parentY = Math.round(parseEmuInt2(xfrm["a:off"]["@_y"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
38068
38412
|
}
|
|
38069
38413
|
if (xfrm["a:ext"]) {
|
|
38070
|
-
parentW = Math.round(
|
|
38071
|
-
|
|
38072
|
-
);
|
|
38073
|
-
parentH = Math.round(
|
|
38074
|
-
parseInt(xfrm["a:ext"]["@_cy"] || "0") / _PptxHandlerRuntime.EMU_PER_PX
|
|
38075
|
-
);
|
|
38414
|
+
parentW = Math.round(parseEmuInt2(xfrm["a:ext"]["@_cx"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
38415
|
+
parentH = Math.round(parseEmuInt2(xfrm["a:ext"]["@_cy"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
38076
38416
|
}
|
|
38077
38417
|
if (xfrm["a:chOff"]) {
|
|
38078
|
-
chX = Math.round(
|
|
38079
|
-
chY = Math.round(
|
|
38418
|
+
chX = Math.round(parseEmuInt2(xfrm["a:chOff"]["@_x"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
38419
|
+
chY = Math.round(parseEmuInt2(xfrm["a:chOff"]["@_y"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
38080
38420
|
}
|
|
38081
38421
|
if (xfrm["a:chExt"]) {
|
|
38082
|
-
chW = Math.round(
|
|
38083
|
-
chH = Math.round(
|
|
38422
|
+
chW = Math.round(parseEmuInt2(xfrm["a:chExt"]["@_cx"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
38423
|
+
chH = Math.round(parseEmuInt2(xfrm["a:chExt"]["@_cy"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
38084
38424
|
}
|
|
38085
38425
|
}
|
|
38086
38426
|
const scaleX = chW > 0 ? parentW / chW : 1;
|
|
@@ -38128,7 +38468,8 @@ var PptxHandlerRuntime48 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
|
|
|
38128
38468
|
subGroup,
|
|
38129
38469
|
`${baseId}-group-${entry.indexInType}`,
|
|
38130
38470
|
slidePath,
|
|
38131
|
-
rawXmlStr
|
|
38471
|
+
rawXmlStr,
|
|
38472
|
+
depth + 1
|
|
38132
38473
|
);
|
|
38133
38474
|
subElements.forEach((el) => transformElement(el));
|
|
38134
38475
|
elements.push(...subElements);
|
|
@@ -38158,16 +38499,12 @@ var PptxHandlerRuntime48 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
|
|
|
38158
38499
|
let parentX = 0, parentY = 0, parentW = 0, parentH = 0;
|
|
38159
38500
|
if (xfrm) {
|
|
38160
38501
|
if (xfrm["a:off"]) {
|
|
38161
|
-
parentX = Math.round(
|
|
38162
|
-
parentY = Math.round(
|
|
38502
|
+
parentX = Math.round(parseEmuInt2(xfrm["a:off"]["@_x"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
38503
|
+
parentY = Math.round(parseEmuInt2(xfrm["a:off"]["@_y"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
38163
38504
|
}
|
|
38164
38505
|
if (xfrm["a:ext"]) {
|
|
38165
|
-
parentW = Math.round(
|
|
38166
|
-
|
|
38167
|
-
);
|
|
38168
|
-
parentH = Math.round(
|
|
38169
|
-
parseInt(xfrm["a:ext"]["@_cy"] || "0") / _PptxHandlerRuntime.EMU_PER_PX
|
|
38170
|
-
);
|
|
38506
|
+
parentW = Math.round(parseEmuInt2(xfrm["a:ext"]["@_cx"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
38507
|
+
parentH = Math.round(parseEmuInt2(xfrm["a:ext"]["@_cy"]) / _PptxHandlerRuntime.EMU_PER_PX);
|
|
38171
38508
|
}
|
|
38172
38509
|
}
|
|
38173
38510
|
const grpFillStyle = grpSpPr ? this.extractShapeStyle(grpSpPr) : void 0;
|
|
@@ -38481,6 +38818,12 @@ var PptxHandlerRuntime51 = class extends PptxHandlerRuntime50 {
|
|
|
38481
38818
|
const slideRels = this.slideRelsMap.get(slidePath);
|
|
38482
38819
|
const target = slideRels?.get(rEmbed);
|
|
38483
38820
|
if (target) {
|
|
38821
|
+
if (target.startsWith("http://") || target.startsWith("https://")) {
|
|
38822
|
+
if (this.allowExternalImages !== true) {
|
|
38823
|
+
return void 0;
|
|
38824
|
+
}
|
|
38825
|
+
return target;
|
|
38826
|
+
}
|
|
38484
38827
|
const imagePath = this.resolveImagePath(slidePath, target);
|
|
38485
38828
|
return this.getImageData(imagePath);
|
|
38486
38829
|
}
|
|
@@ -41137,30 +41480,41 @@ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
|
|
|
41137
41480
|
};
|
|
41138
41481
|
}
|
|
41139
41482
|
collectLocalTextValues(node, localName, output) {
|
|
41140
|
-
|
|
41141
|
-
|
|
41142
|
-
|
|
41143
|
-
|
|
41144
|
-
|
|
41145
|
-
|
|
41146
|
-
}
|
|
41147
|
-
|
|
41148
|
-
|
|
41149
|
-
|
|
41150
|
-
|
|
41151
|
-
|
|
41152
|
-
|
|
41153
|
-
|
|
41154
|
-
|
|
41155
|
-
|
|
41156
|
-
|
|
41157
|
-
|
|
41158
|
-
|
|
41483
|
+
const MAX_NODES = 1e6;
|
|
41484
|
+
const stack = [node];
|
|
41485
|
+
let visited = 0;
|
|
41486
|
+
while (stack.length > 0) {
|
|
41487
|
+
if (visited++ > MAX_NODES) {
|
|
41488
|
+
break;
|
|
41489
|
+
}
|
|
41490
|
+
const current = stack.pop();
|
|
41491
|
+
if (current === null || current === void 0) {
|
|
41492
|
+
continue;
|
|
41493
|
+
}
|
|
41494
|
+
if (Array.isArray(current)) {
|
|
41495
|
+
for (const entry of current) {
|
|
41496
|
+
stack.push(entry);
|
|
41497
|
+
}
|
|
41498
|
+
continue;
|
|
41499
|
+
}
|
|
41500
|
+
if (typeof current !== "object") {
|
|
41501
|
+
continue;
|
|
41502
|
+
}
|
|
41503
|
+
const objectNode = current;
|
|
41504
|
+
for (const [key, value] of Object.entries(objectNode)) {
|
|
41505
|
+
if (this.compatibilityService.getXmlLocalName(key) === localName) {
|
|
41506
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
41507
|
+
const textValue = String(value).trim();
|
|
41508
|
+
if (textValue.length > 0) {
|
|
41509
|
+
output.push(textValue);
|
|
41510
|
+
}
|
|
41511
|
+
continue;
|
|
41159
41512
|
}
|
|
41160
|
-
|
|
41513
|
+
}
|
|
41514
|
+
if (value !== null && value !== void 0) {
|
|
41515
|
+
stack.push(value);
|
|
41161
41516
|
}
|
|
41162
41517
|
}
|
|
41163
|
-
this.collectLocalTextValues(value, localName, output);
|
|
41164
41518
|
}
|
|
41165
41519
|
}
|
|
41166
41520
|
/**
|
|
@@ -42677,6 +43031,7 @@ var PptxHandlerRuntime73 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
|
|
|
42677
43031
|
}
|
|
42678
43032
|
async initializeLoadSession(data, options) {
|
|
42679
43033
|
this.eagerDecodeImages = options.eagerDecodeImages ?? false;
|
|
43034
|
+
this.allowExternalImages = options.allowExternalImages === true;
|
|
42680
43035
|
if (data.byteLength < 4) {
|
|
42681
43036
|
throw new Error("Invalid PPTX binary: file is empty or truncated.");
|
|
42682
43037
|
}
|
|
@@ -42694,6 +43049,29 @@ var PptxHandlerRuntime73 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
|
|
|
42694
43049
|
const message = error instanceof Error ? error.message : "Unable to read zip container.";
|
|
42695
43050
|
throw new Error(`Invalid PPTX package: ${message}`, { cause: error });
|
|
42696
43051
|
}
|
|
43052
|
+
const maxBytes = typeof options.maxUncompressedBytes === "number" && options.maxUncompressedBytes > 0 ? options.maxUncompressedBytes : DEFAULT_MAX_UNCOMPRESSED_BYTES;
|
|
43053
|
+
let totalUncompressed = 0;
|
|
43054
|
+
let entryCount = 0;
|
|
43055
|
+
for (const filename of Object.keys(this.zip.files)) {
|
|
43056
|
+
entryCount += 1;
|
|
43057
|
+
if (entryCount > MAX_ZIP_ENTRY_COUNT) {
|
|
43058
|
+
throw new ZipBombError(
|
|
43059
|
+
`PPTX archive contains more than ${MAX_ZIP_ENTRY_COUNT} entries \u2014 refusing to load.`,
|
|
43060
|
+
{ limit: MAX_ZIP_ENTRY_COUNT, entryCount }
|
|
43061
|
+
);
|
|
43062
|
+
}
|
|
43063
|
+
const file = this.zip.files[filename];
|
|
43064
|
+
const size = Number(file?._data?.uncompressedSize ?? 0);
|
|
43065
|
+
if (Number.isFinite(size) && size > 0) {
|
|
43066
|
+
totalUncompressed += size;
|
|
43067
|
+
if (totalUncompressed > maxBytes) {
|
|
43068
|
+
throw new ZipBombError(
|
|
43069
|
+
`PPTX archive uncompressed size exceeds ${maxBytes} bytes (zip-bomb guard).`,
|
|
43070
|
+
{ uncompressedBytes: totalUncompressed, limit: maxBytes }
|
|
43071
|
+
);
|
|
43072
|
+
}
|
|
43073
|
+
}
|
|
43074
|
+
}
|
|
42697
43075
|
this.slideRelsMap.clear();
|
|
42698
43076
|
this.externalRelsMap.clear();
|
|
42699
43077
|
this.slideMap.clear();
|
|
@@ -42953,12 +43331,35 @@ var PptxHandlerRuntime74 = class extends PptxHandlerRuntime73 {
|
|
|
42953
43331
|
* attribute on `p:cNvPr` / `p:cNvCxnSpPr` / `p:cNvPicPr` nodes.
|
|
42954
43332
|
* This is used to seed the element builder's ID counter so that
|
|
42955
43333
|
* new elements never collide with existing ones.
|
|
43334
|
+
*
|
|
43335
|
+
* Implementation note (Load H1): uses an explicit-stack iterative walk
|
|
43336
|
+
* instead of recursion to bound stack usage on attacker-supplied XML
|
|
43337
|
+
* with deeply nested nodes. Also caps total visited nodes at
|
|
43338
|
+
* MAX_NODES to bound CPU on pathological trees.
|
|
42956
43339
|
*/
|
|
42957
43340
|
findMaxElementId(slides) {
|
|
43341
|
+
const MAX_NODES = 1e6;
|
|
42958
43342
|
let max = 0;
|
|
42959
|
-
const
|
|
43343
|
+
const stack = [];
|
|
43344
|
+
for (const slide of slides) {
|
|
43345
|
+
stack.push(slide.rawXml);
|
|
43346
|
+
}
|
|
43347
|
+
let visited = 0;
|
|
43348
|
+
while (stack.length > 0) {
|
|
43349
|
+
if (visited++ > MAX_NODES) {
|
|
43350
|
+
break;
|
|
43351
|
+
}
|
|
43352
|
+
const node = stack.pop();
|
|
42960
43353
|
if (node === null || node === void 0 || typeof node !== "object") {
|
|
42961
|
-
|
|
43354
|
+
continue;
|
|
43355
|
+
}
|
|
43356
|
+
if (Array.isArray(node)) {
|
|
43357
|
+
for (const item of node) {
|
|
43358
|
+
if (item !== null && item !== void 0 && typeof item === "object") {
|
|
43359
|
+
stack.push(item);
|
|
43360
|
+
}
|
|
43361
|
+
}
|
|
43362
|
+
continue;
|
|
42962
43363
|
}
|
|
42963
43364
|
const obj = node;
|
|
42964
43365
|
if ("@_id" in obj) {
|
|
@@ -42968,17 +43369,13 @@ var PptxHandlerRuntime74 = class extends PptxHandlerRuntime73 {
|
|
|
42968
43369
|
}
|
|
42969
43370
|
}
|
|
42970
43371
|
for (const value of Object.values(obj)) {
|
|
42971
|
-
if (
|
|
42972
|
-
|
|
42973
|
-
|
|
42974
|
-
|
|
42975
|
-
|
|
42976
|
-
visit(value);
|
|
43372
|
+
if (value === null || value === void 0) {
|
|
43373
|
+
continue;
|
|
43374
|
+
}
|
|
43375
|
+
if (Array.isArray(value) || typeof value === "object") {
|
|
43376
|
+
stack.push(value);
|
|
42977
43377
|
}
|
|
42978
43378
|
}
|
|
42979
|
-
};
|
|
42980
|
-
for (const slide of slides) {
|
|
42981
|
-
visit(slide.rawXml);
|
|
42982
43379
|
}
|
|
42983
43380
|
return max;
|
|
42984
43381
|
}
|
|
@@ -45636,27 +46033,52 @@ function perpendicularDistance(p, start, end) {
|
|
|
45636
46033
|
const distY = p.y - projY;
|
|
45637
46034
|
return Math.sqrt(distX * distX + distY * distY);
|
|
45638
46035
|
}
|
|
46036
|
+
var MAX_DOUGLAS_PEUCKER_POINTS = 1e5;
|
|
45639
46037
|
function douglasPeucker(points, tolerance) {
|
|
45640
|
-
|
|
46038
|
+
const n = points.length;
|
|
46039
|
+
if (n <= 2) {
|
|
45641
46040
|
return [...points];
|
|
45642
46041
|
}
|
|
45643
|
-
|
|
45644
|
-
|
|
45645
|
-
|
|
45646
|
-
const
|
|
45647
|
-
|
|
45648
|
-
|
|
45649
|
-
|
|
45650
|
-
|
|
45651
|
-
|
|
46042
|
+
if (n > MAX_DOUGLAS_PEUCKER_POINTS) {
|
|
46043
|
+
return [points[0], points[n - 1]];
|
|
46044
|
+
}
|
|
46045
|
+
const keep = new Uint8Array(n);
|
|
46046
|
+
keep[0] = 1;
|
|
46047
|
+
keep[n - 1] = 1;
|
|
46048
|
+
const stack = [[0, n - 1]];
|
|
46049
|
+
while (stack.length > 0) {
|
|
46050
|
+
const range = stack.pop();
|
|
46051
|
+
if (!range) {
|
|
46052
|
+
break;
|
|
46053
|
+
}
|
|
46054
|
+
const [lo, hi] = range;
|
|
46055
|
+
if (hi - lo < 2) {
|
|
46056
|
+
continue;
|
|
46057
|
+
}
|
|
46058
|
+
const first = points[lo];
|
|
46059
|
+
const last = points[hi];
|
|
46060
|
+
let maxDist = 0;
|
|
46061
|
+
let maxIdx = -1;
|
|
46062
|
+
for (let i = lo + 1; i < hi; i++) {
|
|
46063
|
+
const dist = perpendicularDistance(points[i], first, last);
|
|
46064
|
+
if (dist > maxDist) {
|
|
46065
|
+
maxDist = dist;
|
|
46066
|
+
maxIdx = i;
|
|
46067
|
+
}
|
|
46068
|
+
}
|
|
46069
|
+
if (maxIdx !== -1 && maxDist > tolerance) {
|
|
46070
|
+
keep[maxIdx] = 1;
|
|
46071
|
+
stack.push([lo, maxIdx]);
|
|
46072
|
+
stack.push([maxIdx, hi]);
|
|
45652
46073
|
}
|
|
45653
46074
|
}
|
|
45654
|
-
|
|
45655
|
-
|
|
45656
|
-
|
|
45657
|
-
|
|
46075
|
+
const result = [];
|
|
46076
|
+
for (let i = 0; i < n; i++) {
|
|
46077
|
+
if (keep[i]) {
|
|
46078
|
+
result.push(points[i]);
|
|
46079
|
+
}
|
|
45658
46080
|
}
|
|
45659
|
-
return
|
|
46081
|
+
return result;
|
|
45660
46082
|
}
|
|
45661
46083
|
function catmullRomToBezier(points, factor = 6) {
|
|
45662
46084
|
if (points.length < 2) {
|
|
@@ -46514,7 +46936,7 @@ function mergePresentation(targetData, sourceData, options) {
|
|
|
46514
46936
|
if (options?.keepSourceTheme && sourceData.themeColorMap) {
|
|
46515
46937
|
targetData.themeColorMap = { ...sourceData.themeColorMap };
|
|
46516
46938
|
if (sourceData.theme) {
|
|
46517
|
-
targetData.theme = JSON.parse(JSON.stringify(sourceData.theme));
|
|
46939
|
+
targetData.theme = typeof structuredClone === "function" ? structuredClone(sourceData.theme) : JSON.parse(JSON.stringify(sourceData.theme));
|
|
46518
46940
|
}
|
|
46519
46941
|
}
|
|
46520
46942
|
return clonedSlides.length;
|
|
@@ -49613,6 +50035,29 @@ var MediaContext = class {
|
|
|
49613
50035
|
};
|
|
49614
50036
|
|
|
49615
50037
|
// src/converter/base.ts
|
|
50038
|
+
function escapeHtml(value) {
|
|
50039
|
+
if (value === void 0 || value === null) {
|
|
50040
|
+
return "";
|
|
50041
|
+
}
|
|
50042
|
+
return String(value).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
50043
|
+
}
|
|
50044
|
+
var SAFE_LINK_PREFIXES = ["http://", "https://", "mailto:", "tel:", "#"];
|
|
50045
|
+
function safeHrefOrHash(value) {
|
|
50046
|
+
if (typeof value !== "string") {
|
|
50047
|
+
return "#";
|
|
50048
|
+
}
|
|
50049
|
+
const trimmed = value.trim();
|
|
50050
|
+
if (trimmed.length === 0) {
|
|
50051
|
+
return "#";
|
|
50052
|
+
}
|
|
50053
|
+
const lower = trimmed.toLowerCase();
|
|
50054
|
+
for (const prefix of SAFE_LINK_PREFIXES) {
|
|
50055
|
+
if (lower.startsWith(prefix)) {
|
|
50056
|
+
return trimmed;
|
|
50057
|
+
}
|
|
50058
|
+
}
|
|
50059
|
+
return "#";
|
|
50060
|
+
}
|
|
49616
50061
|
function normalizePath(pathValue) {
|
|
49617
50062
|
return pathValue.trim().replace(/\\/g, "/");
|
|
49618
50063
|
}
|
|
@@ -49666,7 +50111,8 @@ var DocumentConverter = class {
|
|
|
49666
50111
|
const lines = ["---"];
|
|
49667
50112
|
for (const [key, value] of Object.entries(metadata)) {
|
|
49668
50113
|
if (typeof value === "string") {
|
|
49669
|
-
|
|
50114
|
+
const safe = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/[-]/g, " ");
|
|
50115
|
+
lines.push(`${key}: "${safe}"`);
|
|
49670
50116
|
} else {
|
|
49671
50117
|
lines.push(`${key}: ${value}`);
|
|
49672
50118
|
}
|
|
@@ -50060,14 +50506,16 @@ var ImageElementProcessor = class {
|
|
|
50060
50506
|
console.error(`[image-processor] ${msg}`);
|
|
50061
50507
|
return `> **[Image extraction failed]** ${imageElement.id} (slide ${ctx.slideNumber})`;
|
|
50062
50508
|
}
|
|
50509
|
+
const safeAlt = escapeHtml(altText);
|
|
50510
|
+
const safeSrc = escapeHtml(imagePath);
|
|
50063
50511
|
if (ctx.semanticMode) {
|
|
50064
|
-
return ``;
|
|
50065
50513
|
}
|
|
50066
50514
|
if (ctx.layoutScale) {
|
|
50067
|
-
return `<img src="${
|
|
50515
|
+
return `<img src="${safeSrc}" alt="${safeAlt}" style="max-width:100%;height:auto">`;
|
|
50068
50516
|
}
|
|
50069
50517
|
const dims = this.computeDisplaySize(element.width, element.height);
|
|
50070
|
-
return `<img src="${
|
|
50518
|
+
return `<img src="${safeSrc}" alt="${safeAlt}" width="${dims.w}" height="${dims.h}">`;
|
|
50071
50519
|
}
|
|
50072
50520
|
/** Scale element dimensions to a sensible display size, capping width. */
|
|
50073
50521
|
computeDisplaySize(origW, origH, maxW = 600) {
|
|
@@ -50341,6 +50789,59 @@ var SmartArtElementProcessor = class {
|
|
|
50341
50789
|
};
|
|
50342
50790
|
|
|
50343
50791
|
// src/converter/elements/TableElementProcessor.ts
|
|
50792
|
+
var SAFE_CSS_NAMED_COLORS = /* @__PURE__ */ new Set([
|
|
50793
|
+
"black",
|
|
50794
|
+
"silver",
|
|
50795
|
+
"gray",
|
|
50796
|
+
"white",
|
|
50797
|
+
"maroon",
|
|
50798
|
+
"red",
|
|
50799
|
+
"purple",
|
|
50800
|
+
"fuchsia",
|
|
50801
|
+
"green",
|
|
50802
|
+
"lime",
|
|
50803
|
+
"olive",
|
|
50804
|
+
"yellow",
|
|
50805
|
+
"navy",
|
|
50806
|
+
"blue",
|
|
50807
|
+
"teal",
|
|
50808
|
+
"aqua",
|
|
50809
|
+
"orange",
|
|
50810
|
+
"transparent",
|
|
50811
|
+
"currentcolor",
|
|
50812
|
+
"inherit",
|
|
50813
|
+
"initial",
|
|
50814
|
+
"unset"
|
|
50815
|
+
]);
|
|
50816
|
+
function cssColorSafe(value) {
|
|
50817
|
+
if (typeof value !== "string") {
|
|
50818
|
+
return void 0;
|
|
50819
|
+
}
|
|
50820
|
+
const trimmed = value.trim();
|
|
50821
|
+
if (trimmed.length === 0) {
|
|
50822
|
+
return void 0;
|
|
50823
|
+
}
|
|
50824
|
+
if (/^#[0-9a-f]{3,8}$/i.test(trimmed)) {
|
|
50825
|
+
return trimmed;
|
|
50826
|
+
}
|
|
50827
|
+
if (SAFE_CSS_NAMED_COLORS.has(trimmed.toLowerCase())) {
|
|
50828
|
+
return trimmed;
|
|
50829
|
+
}
|
|
50830
|
+
return void 0;
|
|
50831
|
+
}
|
|
50832
|
+
function cssFontFamilySafe(value) {
|
|
50833
|
+
if (typeof value !== "string") {
|
|
50834
|
+
return void 0;
|
|
50835
|
+
}
|
|
50836
|
+
const trimmed = value.trim();
|
|
50837
|
+
if (trimmed.length === 0) {
|
|
50838
|
+
return void 0;
|
|
50839
|
+
}
|
|
50840
|
+
if (/^[a-zA-Z0-9 _\-,'"]{1,80}$/.test(trimmed)) {
|
|
50841
|
+
return trimmed;
|
|
50842
|
+
}
|
|
50843
|
+
return void 0;
|
|
50844
|
+
}
|
|
50344
50845
|
var TableElementProcessor = class {
|
|
50345
50846
|
supportedTypes = ["table"];
|
|
50346
50847
|
async process(element, ctx) {
|
|
@@ -50407,27 +50908,29 @@ ${htmlRows.join("\n")}
|
|
|
50407
50908
|
}
|
|
50408
50909
|
const css = this.buildCellCss(cell.style, isHeader);
|
|
50409
50910
|
if (css) {
|
|
50410
|
-
parts.push(` style="${css}"`);
|
|
50911
|
+
parts.push(` style="${escapeHtml(css)}"`);
|
|
50411
50912
|
}
|
|
50412
50913
|
return parts.join("");
|
|
50413
50914
|
}
|
|
50414
50915
|
/** Converts PptxTableCellStyle to an inline CSS string. */
|
|
50415
50916
|
buildCellCss(style, isHeader) {
|
|
50416
50917
|
const rules = [];
|
|
50417
|
-
|
|
50418
|
-
|
|
50918
|
+
const safeBackground = cssColorSafe(style?.backgroundColor);
|
|
50919
|
+
if (safeBackground) {
|
|
50920
|
+
rules.push(`background:${safeBackground}`);
|
|
50419
50921
|
}
|
|
50420
|
-
if (style?.align) {
|
|
50922
|
+
if (style?.align && /^[a-zA-Z]+$/.test(style.align)) {
|
|
50421
50923
|
rules.push(`text-align:${style.align}`);
|
|
50422
50924
|
}
|
|
50423
|
-
if (style?.vAlign) {
|
|
50925
|
+
if (style?.vAlign && /^[a-zA-Z]+$/.test(style.vAlign)) {
|
|
50424
50926
|
rules.push(`vertical-align:${style.vAlign}`);
|
|
50425
50927
|
}
|
|
50426
50928
|
if (style?.fontSize) {
|
|
50427
50929
|
rules.push(`font-size:${Math.round(style.fontSize)}px`);
|
|
50428
50930
|
}
|
|
50429
|
-
|
|
50430
|
-
|
|
50931
|
+
const safeColor = cssColorSafe(style?.color);
|
|
50932
|
+
if (safeColor) {
|
|
50933
|
+
rules.push(`color:${safeColor}`);
|
|
50431
50934
|
}
|
|
50432
50935
|
if (style?.bold || isHeader) {
|
|
50433
50936
|
rules.push("font-weight:bold");
|
|
@@ -50451,20 +50954,25 @@ ${htmlRows.join("\n")}
|
|
|
50451
50954
|
return "";
|
|
50452
50955
|
}
|
|
50453
50956
|
const edges = [];
|
|
50454
|
-
|
|
50455
|
-
|
|
50957
|
+
const topColor = cssColorSafe(style.borderTopColor);
|
|
50958
|
+
if (style.borderTopWidth && topColor) {
|
|
50959
|
+
edges.push(`border-top:${Math.round(style.borderTopWidth)}px solid ${topColor}`);
|
|
50456
50960
|
}
|
|
50457
|
-
|
|
50458
|
-
|
|
50961
|
+
const bottomColor = cssColorSafe(style.borderBottomColor);
|
|
50962
|
+
if (style.borderBottomWidth && bottomColor) {
|
|
50963
|
+
edges.push(`border-bottom:${Math.round(style.borderBottomWidth)}px solid ${bottomColor}`);
|
|
50459
50964
|
}
|
|
50460
|
-
|
|
50461
|
-
|
|
50965
|
+
const leftColor = cssColorSafe(style.borderLeftColor);
|
|
50966
|
+
if (style.borderLeftWidth && leftColor) {
|
|
50967
|
+
edges.push(`border-left:${Math.round(style.borderLeftWidth)}px solid ${leftColor}`);
|
|
50462
50968
|
}
|
|
50463
|
-
|
|
50464
|
-
|
|
50969
|
+
const rightColor = cssColorSafe(style.borderRightColor);
|
|
50970
|
+
if (style.borderRightWidth && rightColor) {
|
|
50971
|
+
edges.push(`border-right:${Math.round(style.borderRightWidth)}px solid ${rightColor}`);
|
|
50465
50972
|
}
|
|
50466
|
-
|
|
50467
|
-
|
|
50973
|
+
const fallback = cssColorSafe(style.borderColor);
|
|
50974
|
+
if (edges.length === 0 && fallback) {
|
|
50975
|
+
return `border:1px solid ${fallback}`;
|
|
50468
50976
|
}
|
|
50469
50977
|
return edges.join(";");
|
|
50470
50978
|
}
|
|
@@ -50503,7 +51011,7 @@ ${htmlRows.join("\n")}
|
|
|
50503
51011
|
}
|
|
50504
51012
|
const css = this.buildRunCss(seg, cell.style);
|
|
50505
51013
|
if (css) {
|
|
50506
|
-
parts.push(`<span style="${css}">${text}</span>`);
|
|
51014
|
+
parts.push(`<span style="${escapeHtml(css)}">${text}</span>`);
|
|
50507
51015
|
} else {
|
|
50508
51016
|
parts.push(text);
|
|
50509
51017
|
}
|
|
@@ -50516,13 +51024,19 @@ ${htmlRows.join("\n")}
|
|
|
50516
51024
|
const s = seg.style;
|
|
50517
51025
|
const rules = [];
|
|
50518
51026
|
if (s.fontFamily) {
|
|
50519
|
-
|
|
51027
|
+
const safeFamily = cssFontFamilySafe(getSubstituteFontFamily(s.fontFamily));
|
|
51028
|
+
if (safeFamily) {
|
|
51029
|
+
rules.push(`font-family:${safeFamily}`);
|
|
51030
|
+
}
|
|
50520
51031
|
}
|
|
50521
51032
|
if (s.fontSize && s.fontSize !== cellStyle?.fontSize) {
|
|
50522
51033
|
rules.push(`font-size:${Math.round(s.fontSize)}px`);
|
|
50523
51034
|
}
|
|
50524
51035
|
if (s.color && s.color !== cellStyle?.color) {
|
|
50525
|
-
|
|
51036
|
+
const safeColor = cssColorSafe(s.color);
|
|
51037
|
+
if (safeColor) {
|
|
51038
|
+
rules.push(`color:${safeColor}`);
|
|
51039
|
+
}
|
|
50526
51040
|
}
|
|
50527
51041
|
if (s.bold && !cellStyle?.bold) {
|
|
50528
51042
|
rules.push("font-weight:bold");
|
|
@@ -51001,7 +51515,7 @@ var TextElementProcessor = class {
|
|
|
51001
51515
|
if (fallbackText) {
|
|
51002
51516
|
const align = textElement.textStyle?.align;
|
|
51003
51517
|
if (align && align !== "left") {
|
|
51004
|
-
parts.push(`<p align="${align}">${fallbackText}</p>`);
|
|
51518
|
+
parts.push(`<p align="${escapeHtml(align)}">${escapeHtml(fallbackText)}</p>`);
|
|
51005
51519
|
} else {
|
|
51006
51520
|
parts.push(fallbackText);
|
|
51007
51521
|
}
|
|
@@ -51036,7 +51550,7 @@ var TextElementProcessor = class {
|
|
|
51036
51550
|
seen.add(dataUrl);
|
|
51037
51551
|
try {
|
|
51038
51552
|
const path = await ctx.mediaContext.saveImage(dataUrl, `slide${ctx.slideNumber}-bullet`);
|
|
51039
|
-
extracted.push(`<img src="${path}" alt="Bullet image">`);
|
|
51553
|
+
extracted.push(`<img src="${escapeHtml(path)}" alt="Bullet image">`);
|
|
51040
51554
|
} catch {
|
|
51041
51555
|
}
|
|
51042
51556
|
}
|
|
@@ -51061,7 +51575,7 @@ var TextElementProcessor = class {
|
|
|
51061
51575
|
if (ctx.semanticMode) {
|
|
51062
51576
|
return ``;
|
|
51063
51577
|
}
|
|
51064
|
-
return `<img src="${path}" alt="Shape fill">`;
|
|
51578
|
+
return `<img src="${escapeHtml(path)}" alt="Shape fill">`;
|
|
51065
51579
|
} catch {
|
|
51066
51580
|
return null;
|
|
51067
51581
|
}
|
|
@@ -51095,10 +51609,10 @@ var TextElementProcessor = class {
|
|
|
51095
51609
|
return ``;
|
|
51096
51610
|
}
|
|
51097
51611
|
if (ctx.layoutScale) {
|
|
51098
|
-
return `<img src="${imgPath}" alt="Shape" style="max-width:100%;height:auto">`;
|
|
51612
|
+
return `<img src="${escapeHtml(imgPath)}" alt="Shape" style="max-width:100%;height:auto">`;
|
|
51099
51613
|
}
|
|
51100
51614
|
const dims = this.computeDisplaySize(shape.width, shape.height);
|
|
51101
|
-
return `<img src="${imgPath}" alt="Shape" width="${dims.w}" height="${dims.h}">`;
|
|
51615
|
+
return `<img src="${escapeHtml(imgPath)}" alt="Shape" width="${dims.w}" height="${dims.h}">`;
|
|
51102
51616
|
} catch {
|
|
51103
51617
|
return null;
|
|
51104
51618
|
}
|
|
@@ -51428,7 +51942,7 @@ var SlideProcessor = class {
|
|
|
51428
51942
|
slide.backgroundImage,
|
|
51429
51943
|
`slide${slide.slideNumber}-bg`
|
|
51430
51944
|
);
|
|
51431
|
-
return `<img src="${path}" alt="Slide background" style="width:100%;height:100%;object-fit:cover">`;
|
|
51945
|
+
return `<img src="${escapeHtml(path)}" alt="Slide background" style="width:100%;height:100%;object-fit:cover">`;
|
|
51432
51946
|
} catch {
|
|
51433
51947
|
return void 0;
|
|
51434
51948
|
}
|
|
@@ -52223,10 +52737,11 @@ var TextSegmentRenderer = class {
|
|
|
52223
52737
|
text = `<span style="font-variant:small-caps">${text}</span>`;
|
|
52224
52738
|
}
|
|
52225
52739
|
if (segment.style.hyperlink) {
|
|
52226
|
-
const dest = this.renderLinkDestination(segment.style.hyperlink);
|
|
52227
52740
|
if (useHtml) {
|
|
52228
|
-
|
|
52741
|
+
const safeDest = escapeHtml(safeHrefOrHash(segment.style.hyperlink));
|
|
52742
|
+
text = `<a href="${safeDest}">${text}</a>`;
|
|
52229
52743
|
} else {
|
|
52744
|
+
const dest = this.renderLinkDestination(segment.style.hyperlink);
|
|
52230
52745
|
const title = segment.style.hyperlinkTooltip ? ` "${this.escapeLinkTitle(segment.style.hyperlinkTooltip)}"` : "";
|
|
52231
52746
|
text = `[${text}](${dest}${title})`;
|
|
52232
52747
|
}
|
|
@@ -52606,11 +53121,20 @@ function resolveDefaults(opts) {
|
|
|
52606
53121
|
defaultFontSize: opts?.defaultFontSize ?? 18
|
|
52607
53122
|
};
|
|
52608
53123
|
}
|
|
52609
|
-
|
|
52610
|
-
|
|
52611
|
-
|
|
53124
|
+
function createRenderContext() {
|
|
53125
|
+
return { defs: [], markerCache: /* @__PURE__ */ new Map(), markerIdCounter: 0 };
|
|
53126
|
+
}
|
|
53127
|
+
function getOrCreateArrowMarker(ctx, color) {
|
|
53128
|
+
const key = color;
|
|
53129
|
+
const cached = ctx.markerCache.get(key);
|
|
53130
|
+
if (cached) {
|
|
53131
|
+
return cached;
|
|
53132
|
+
}
|
|
53133
|
+
const id = `arrow_${++ctx.markerIdCounter}`;
|
|
52612
53134
|
const svg = `<marker id="${id}" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto" markerUnits="strokeWidth"><polygon points="0 0, 10 3.5, 0 7" fill="${escXml(color)}" /></marker>`;
|
|
52613
|
-
|
|
53135
|
+
ctx.defs.push(svg);
|
|
53136
|
+
ctx.markerCache.set(key, id);
|
|
53137
|
+
return id;
|
|
52614
53138
|
}
|
|
52615
53139
|
function renderTransform(el) {
|
|
52616
53140
|
const parts = [];
|
|
@@ -52650,13 +53174,16 @@ function renderText(el, defaults) {
|
|
|
52650
53174
|
textX = el.width - 4;
|
|
52651
53175
|
}
|
|
52652
53176
|
if (segments && segments.length > 0) {
|
|
52653
|
-
|
|
52654
|
-
|
|
52655
|
-
|
|
52656
|
-
|
|
52657
|
-
|
|
52658
|
-
|
|
52659
|
-
|
|
53177
|
+
const parts2 = [];
|
|
53178
|
+
parts2.push(
|
|
53179
|
+
`<text${attrs({
|
|
53180
|
+
x: textX,
|
|
53181
|
+
"text-anchor": textAnchor,
|
|
53182
|
+
"font-family": fontFamily,
|
|
53183
|
+
"font-size": fontSize,
|
|
53184
|
+
fill: color
|
|
53185
|
+
})}>`
|
|
53186
|
+
);
|
|
52660
53187
|
let dy = fontSize * 1.2;
|
|
52661
53188
|
let isFirstSegment = true;
|
|
52662
53189
|
for (const seg of segments) {
|
|
@@ -52693,31 +53220,36 @@ function renderText(el, defaults) {
|
|
|
52693
53220
|
if (segStyle.underline) {
|
|
52694
53221
|
segAttrs["text-decoration"] = "underline";
|
|
52695
53222
|
}
|
|
52696
|
-
|
|
53223
|
+
parts2.push(`<tspan${attrs(segAttrs)}>${escXml(seg.text)}</tspan>`);
|
|
52697
53224
|
}
|
|
52698
|
-
|
|
52699
|
-
return
|
|
53225
|
+
parts2.push(`</text>`);
|
|
53226
|
+
return parts2.join("");
|
|
52700
53227
|
}
|
|
52701
53228
|
const bold = style?.bold;
|
|
52702
53229
|
const italic = style?.italic;
|
|
52703
53230
|
const lines = text.split("\n");
|
|
52704
|
-
|
|
52705
|
-
|
|
52706
|
-
|
|
52707
|
-
"font-family": fontFamily,
|
|
52708
|
-
"font-size": fontSize,
|
|
52709
|
-
fill: color,
|
|
52710
|
-
"font-weight": bold ? "bold" : void 0,
|
|
52711
|
-
"font-style": italic ? "italic" : void 0
|
|
52712
|
-
})}>`;
|
|
52713
|
-
for (let i = 0; i < lines.length; i++) {
|
|
52714
|
-
svg += `<tspan${attrs({
|
|
53231
|
+
const parts = [];
|
|
53232
|
+
parts.push(
|
|
53233
|
+
`<text${attrs({
|
|
52715
53234
|
x: textX,
|
|
52716
|
-
|
|
52717
|
-
|
|
53235
|
+
"text-anchor": textAnchor,
|
|
53236
|
+
"font-family": fontFamily,
|
|
53237
|
+
"font-size": fontSize,
|
|
53238
|
+
fill: color,
|
|
53239
|
+
"font-weight": bold ? "bold" : void 0,
|
|
53240
|
+
"font-style": italic ? "italic" : void 0
|
|
53241
|
+
})}>`
|
|
53242
|
+
);
|
|
53243
|
+
for (let i = 0; i < lines.length; i++) {
|
|
53244
|
+
parts.push(
|
|
53245
|
+
`<tspan${attrs({
|
|
53246
|
+
x: textX,
|
|
53247
|
+
dy: i === 0 ? fontSize * 1.2 : fontSize * 1.2
|
|
53248
|
+
})}>${escXml(lines[i])}</tspan>`
|
|
53249
|
+
);
|
|
52718
53250
|
}
|
|
52719
|
-
|
|
52720
|
-
return
|
|
53251
|
+
parts.push(`</text>`);
|
|
53252
|
+
return parts.join("");
|
|
52721
53253
|
}
|
|
52722
53254
|
function renderShapeBody(el) {
|
|
52723
53255
|
if (el.type !== "shape" && el.type !== "text") {
|
|
@@ -52792,7 +53324,7 @@ function renderImageElement(el) {
|
|
|
52792
53324
|
preserveAspectRatio: "none"
|
|
52793
53325
|
})} href="${escXml(imageData)}" />`;
|
|
52794
53326
|
}
|
|
52795
|
-
function renderConnector(el,
|
|
53327
|
+
function renderConnector(el, ctx) {
|
|
52796
53328
|
if (el.type !== "connector") {
|
|
52797
53329
|
return "";
|
|
52798
53330
|
}
|
|
@@ -52802,14 +53334,12 @@ function renderConnector(el, defs) {
|
|
|
52802
53334
|
let markerStart;
|
|
52803
53335
|
let markerEnd;
|
|
52804
53336
|
if (shapeStyle?.connectorStartArrow && shapeStyle.connectorStartArrow !== "none") {
|
|
52805
|
-
const
|
|
52806
|
-
|
|
52807
|
-
markerStart = `url(#${m.id})`;
|
|
53337
|
+
const id = getOrCreateArrowMarker(ctx, strokeColor);
|
|
53338
|
+
markerStart = `url(#${id})`;
|
|
52808
53339
|
}
|
|
52809
53340
|
if (shapeStyle?.connectorEndArrow && shapeStyle.connectorEndArrow !== "none") {
|
|
52810
|
-
const
|
|
52811
|
-
|
|
52812
|
-
markerEnd = `url(#${m.id})`;
|
|
53341
|
+
const id = getOrCreateArrowMarker(ctx, strokeColor);
|
|
53342
|
+
markerEnd = `url(#${id})`;
|
|
52813
53343
|
}
|
|
52814
53344
|
return `<line${attrs({
|
|
52815
53345
|
x1: 0,
|
|
@@ -52833,7 +53363,7 @@ function renderTable(el, defaults) {
|
|
|
52833
53363
|
const cols = tableData.columnWidths;
|
|
52834
53364
|
const numRows = tableData.rows.length;
|
|
52835
53365
|
const rowHeight = el.height / numRows;
|
|
52836
|
-
|
|
53366
|
+
const parts = [];
|
|
52837
53367
|
let yOffset = 0;
|
|
52838
53368
|
for (const row of tableData.rows) {
|
|
52839
53369
|
const h = row.height ?? rowHeight;
|
|
@@ -52850,62 +53380,68 @@ function renderTable(el, defaults) {
|
|
|
52850
53380
|
const textColor = cell.style?.color ?? "#000000";
|
|
52851
53381
|
const fontSize = cell.style?.fontSize ?? defaults.defaultFontSize;
|
|
52852
53382
|
const bold = cell.style?.bold;
|
|
52853
|
-
|
|
52854
|
-
|
|
52855
|
-
|
|
52856
|
-
|
|
52857
|
-
|
|
52858
|
-
|
|
52859
|
-
|
|
52860
|
-
|
|
52861
|
-
|
|
53383
|
+
parts.push(
|
|
53384
|
+
`<rect${attrs({
|
|
53385
|
+
x: xOffset,
|
|
53386
|
+
y: yOffset,
|
|
53387
|
+
width: cellWidth,
|
|
53388
|
+
height: h,
|
|
53389
|
+
fill: bgColor,
|
|
53390
|
+
stroke: borderColor,
|
|
53391
|
+
"stroke-width": 0.5
|
|
53392
|
+
})} />`
|
|
53393
|
+
);
|
|
52862
53394
|
if (cell.text) {
|
|
52863
|
-
|
|
52864
|
-
|
|
52865
|
-
|
|
52866
|
-
|
|
52867
|
-
|
|
52868
|
-
|
|
52869
|
-
|
|
52870
|
-
|
|
52871
|
-
|
|
53395
|
+
parts.push(
|
|
53396
|
+
`<text${attrs({
|
|
53397
|
+
x: xOffset + 4,
|
|
53398
|
+
y: yOffset + h / 2,
|
|
53399
|
+
"dominant-baseline": "central",
|
|
53400
|
+
"font-family": defaults.defaultFontFamily,
|
|
53401
|
+
"font-size": fontSize,
|
|
53402
|
+
fill: textColor,
|
|
53403
|
+
"font-weight": bold ? "bold" : void 0
|
|
53404
|
+
})}>${escXml(cell.text)}</text>`
|
|
53405
|
+
);
|
|
52872
53406
|
}
|
|
52873
53407
|
xOffset += cellWidth;
|
|
52874
53408
|
}
|
|
52875
53409
|
yOffset += h;
|
|
52876
53410
|
}
|
|
52877
|
-
return
|
|
53411
|
+
return parts.join("");
|
|
52878
53412
|
}
|
|
52879
|
-
function renderGroup(el, defaults,
|
|
53413
|
+
function renderGroup(el, defaults, ctx) {
|
|
52880
53414
|
if (el.type !== "group") {
|
|
52881
53415
|
return "";
|
|
52882
53416
|
}
|
|
52883
|
-
|
|
53417
|
+
const parts = [];
|
|
52884
53418
|
for (const child of el.children) {
|
|
52885
|
-
|
|
53419
|
+
parts.push(renderElement(child, defaults, ctx));
|
|
52886
53420
|
}
|
|
52887
|
-
return
|
|
53421
|
+
return parts.join("");
|
|
52888
53422
|
}
|
|
52889
53423
|
function renderInk(el) {
|
|
52890
53424
|
if (el.type !== "ink") {
|
|
52891
53425
|
return "";
|
|
52892
53426
|
}
|
|
52893
|
-
|
|
53427
|
+
const parts = [];
|
|
52894
53428
|
for (let i = 0; i < el.inkPaths.length; i++) {
|
|
52895
53429
|
const path = el.inkPaths[i];
|
|
52896
53430
|
const color = el.inkColors?.[i] ?? "#000000";
|
|
52897
53431
|
const width = el.inkWidths?.[i] ?? 1;
|
|
52898
53432
|
const opacity = el.inkOpacities?.[i];
|
|
52899
|
-
|
|
52900
|
-
|
|
52901
|
-
|
|
52902
|
-
|
|
52903
|
-
|
|
52904
|
-
|
|
52905
|
-
|
|
52906
|
-
|
|
53433
|
+
parts.push(
|
|
53434
|
+
`<path${attrs({
|
|
53435
|
+
d: path,
|
|
53436
|
+
fill: "none",
|
|
53437
|
+
stroke: color,
|
|
53438
|
+
"stroke-width": width,
|
|
53439
|
+
"stroke-opacity": opacity,
|
|
53440
|
+
"stroke-linecap": "round"
|
|
53441
|
+
})} />`
|
|
53442
|
+
);
|
|
52907
53443
|
}
|
|
52908
|
-
return
|
|
53444
|
+
return parts.join("");
|
|
52909
53445
|
}
|
|
52910
53446
|
function renderPlaceholder(el) {
|
|
52911
53447
|
return `<rect${attrs({
|
|
@@ -52925,7 +53461,7 @@ function renderPlaceholder(el) {
|
|
|
52925
53461
|
fill: "#999999"
|
|
52926
53462
|
})}>${escXml(el.type)}</text>`;
|
|
52927
53463
|
}
|
|
52928
|
-
function renderElement(el, defaults,
|
|
53464
|
+
function renderElement(el, defaults, ctx) {
|
|
52929
53465
|
if (el.hidden) {
|
|
52930
53466
|
return "";
|
|
52931
53467
|
}
|
|
@@ -52940,7 +53476,7 @@ function renderElement(el, defaults, defs) {
|
|
|
52940
53476
|
inner = renderShapeBody(el) + renderText(el, defaults);
|
|
52941
53477
|
break;
|
|
52942
53478
|
case "connector":
|
|
52943
|
-
inner = renderConnector(el,
|
|
53479
|
+
inner = renderConnector(el, ctx);
|
|
52944
53480
|
break;
|
|
52945
53481
|
case "image":
|
|
52946
53482
|
case "picture":
|
|
@@ -52950,7 +53486,7 @@ function renderElement(el, defaults, defs) {
|
|
|
52950
53486
|
inner = renderTable(el, defaults);
|
|
52951
53487
|
break;
|
|
52952
53488
|
case "group":
|
|
52953
|
-
inner = renderGroup(el, defaults,
|
|
53489
|
+
inner = renderGroup(el, defaults, ctx);
|
|
52954
53490
|
break;
|
|
52955
53491
|
case "ink":
|
|
52956
53492
|
inner = renderInk(el);
|
|
@@ -52996,24 +53532,21 @@ var SvgExporter = class _SvgExporter {
|
|
|
52996
53532
|
* @returns A complete SVG document as a string.
|
|
52997
53533
|
*/
|
|
52998
53534
|
static exportSlide(slide, width, height, options) {
|
|
52999
|
-
_markerIdCounter = 0;
|
|
53000
53535
|
const defaults = resolveDefaults(options);
|
|
53001
|
-
const
|
|
53002
|
-
|
|
53536
|
+
const ctx = createRenderContext();
|
|
53537
|
+
const bodyParts = [];
|
|
53538
|
+
bodyParts.push(renderBackground(slide, width, height));
|
|
53003
53539
|
for (const el of slide.elements) {
|
|
53004
|
-
|
|
53005
|
-
}
|
|
53006
|
-
let defsBlock = "";
|
|
53007
|
-
if (defs.length) {
|
|
53008
|
-
defsBlock = `<defs>${defs.join("")}</defs>`;
|
|
53540
|
+
bodyParts.push(renderElement(el, defaults, ctx));
|
|
53009
53541
|
}
|
|
53542
|
+
const defsBlock = ctx.defs.length ? `<defs>${ctx.defs.join("")}</defs>` : "";
|
|
53010
53543
|
return `<svg${attrs({
|
|
53011
53544
|
xmlns: SVG_NS,
|
|
53012
53545
|
"xmlns:xlink": XLINK_NS,
|
|
53013
53546
|
viewBox: `0 0 ${width} ${height}`,
|
|
53014
53547
|
width,
|
|
53015
53548
|
height
|
|
53016
|
-
})}>${defsBlock}${
|
|
53549
|
+
})}>${defsBlock}${bodyParts.join("")}</svg>`;
|
|
53017
53550
|
}
|
|
53018
53551
|
/**
|
|
53019
53552
|
* Export all (or selected) slides to SVG XML strings.
|
|
@@ -53052,6 +53585,7 @@ exports.DEFAULT_CANVAS_WIDTH = DEFAULT_CANVAS_WIDTH;
|
|
|
53052
53585
|
exports.DEFAULT_COLOR_MAP = DEFAULT_COLOR_MAP;
|
|
53053
53586
|
exports.DEFAULT_FILL_COLOR = DEFAULT_FILL_COLOR;
|
|
53054
53587
|
exports.DEFAULT_FONT_FAMILY = DEFAULT_FONT_FAMILY;
|
|
53588
|
+
exports.DEFAULT_MAX_UNCOMPRESSED_BYTES = DEFAULT_MAX_UNCOMPRESSED_BYTES;
|
|
53055
53589
|
exports.DEFAULT_SCHEME_COLOR_MAP = DEFAULT_SCHEME_COLOR_MAP;
|
|
53056
53590
|
exports.DEFAULT_STROKE_COLOR = DEFAULT_STROKE_COLOR;
|
|
53057
53591
|
exports.DEFAULT_TEXT_COLOR = DEFAULT_TEXT_COLOR;
|
|
@@ -53081,6 +53615,7 @@ exports.FreeformPathBuilder = FreeformPathBuilder;
|
|
|
53081
53615
|
exports.GroupBuilder = GroupBuilder;
|
|
53082
53616
|
exports.ImageBuilder = ImageBuilder;
|
|
53083
53617
|
exports.IncorrectPasswordError = IncorrectPasswordError;
|
|
53618
|
+
exports.MAX_ZIP_ENTRY_COUNT = MAX_ZIP_ENTRY_COUNT;
|
|
53084
53619
|
exports.MIN_ELEMENT_SIZE = MIN_ELEMENT_SIZE;
|
|
53085
53620
|
exports.MOTION_PATH_PRESETS = MOTION_PATH_PRESETS;
|
|
53086
53621
|
exports.MediaBuilder = MediaBuilder;
|
|
@@ -53171,6 +53706,7 @@ exports.ThemePresets = ThemePresets;
|
|
|
53171
53706
|
exports.VML_SHAPE_TAGS = VML_SHAPE_TAGS;
|
|
53172
53707
|
exports.XMLDSIG_NS = XMLDSIG_NS;
|
|
53173
53708
|
exports.XML_TRANSFORM_ENVELOPED_SIGNATURE = XML_TRANSFORM_ENVELOPED_SIGNATURE;
|
|
53709
|
+
exports.ZipBombError = ZipBombError;
|
|
53174
53710
|
exports.addChartCategory = addChartCategory;
|
|
53175
53711
|
exports.addChartSeries = addChartSeries;
|
|
53176
53712
|
exports.addSection = addSection;
|
|
@@ -53274,6 +53810,7 @@ exports.emuToPixels = emuToPixels;
|
|
|
53274
53810
|
exports.encryptPptx = encryptPptx;
|
|
53275
53811
|
exports.ensureArrayValue = ensureArrayValue;
|
|
53276
53812
|
exports.escapeXmlAttr = escapeXmlAttr;
|
|
53813
|
+
exports.escapeXmlText = escapeXmlText;
|
|
53277
53814
|
exports.estimateTextBoxCapacity = estimateTextBoxCapacity;
|
|
53278
53815
|
exports.evaluateGeometryPaths = evaluateGeometryPaths;
|
|
53279
53816
|
exports.evaluateGuides = evaluateGuides;
|
|
@@ -53357,6 +53894,7 @@ exports.isSwitchableLayoutType = isSwitchableLayoutType;
|
|
|
53357
53894
|
exports.isTemplateElement = isTemplateElement;
|
|
53358
53895
|
exports.isTextElement = isTextElement;
|
|
53359
53896
|
exports.isTransitionalNamespaceUri = isTransitionalNamespaceUri;
|
|
53897
|
+
exports.isValidBase64 = isValidBase64;
|
|
53360
53898
|
exports.isZoomElement = isZoomElement;
|
|
53361
53899
|
exports.isZoomElementUtil = isZoomElement2;
|
|
53362
53900
|
exports.layoutEngineShapesToDrawingShapes = layoutEngineShapesToDrawingShapes;
|