@embedpdf/engine-services 3.0.0-next.10 → 3.0.0-next.11
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.cjs +432 -230
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -2
- package/dist/index.d.ts +18 -2
- package/dist/index.js +433 -231
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1212,11 +1212,143 @@ function readI32(mem, ptr, byteOffset = 0) {
|
|
|
1212
1212
|
return Number(mem.peek(ptr, "i32", byteOffset));
|
|
1213
1213
|
}
|
|
1214
1214
|
//#endregion
|
|
1215
|
+
//#region src/features/destinations/destinationViewCodes.ts
|
|
1216
|
+
/**
|
|
1217
|
+
* `PDFDEST_VIEW_*` fit-type codes (public/fpdf_doc.h) — the shared
|
|
1218
|
+
* vocabulary of `FPDFDest_GetView` (read) and `EPDFDest_CreateView`
|
|
1219
|
+
* (write). XYZ is listed for completeness but never goes through
|
|
1220
|
+
* CreateView (it has its own null-aware constructor).
|
|
1221
|
+
*/
|
|
1222
|
+
const DEST_VIEW = {
|
|
1223
|
+
unknown: 0,
|
|
1224
|
+
xyz: 1,
|
|
1225
|
+
fit: 2,
|
|
1226
|
+
fitH: 3,
|
|
1227
|
+
fitV: 4,
|
|
1228
|
+
fitR: 5,
|
|
1229
|
+
fitB: 6,
|
|
1230
|
+
fitBH: 7,
|
|
1231
|
+
fitBV: 8
|
|
1232
|
+
};
|
|
1233
|
+
/** Wire destination kind → PDFDEST_VIEW code, for the non-XYZ kinds. */
|
|
1234
|
+
const VIEW_CODE_BY_KIND = {
|
|
1235
|
+
fit: DEST_VIEW.fit,
|
|
1236
|
+
fitH: DEST_VIEW.fitH,
|
|
1237
|
+
fitV: DEST_VIEW.fitV,
|
|
1238
|
+
fitR: DEST_VIEW.fitR,
|
|
1239
|
+
fitB: DEST_VIEW.fitB,
|
|
1240
|
+
fitBH: DEST_VIEW.fitBH,
|
|
1241
|
+
fitBV: DEST_VIEW.fitBV
|
|
1242
|
+
};
|
|
1243
|
+
//#endregion
|
|
1244
|
+
//#region src/features/destinations/readDestination.ts
|
|
1245
|
+
const MAX_VIEW_PARAMS = 4;
|
|
1246
|
+
/**
|
|
1247
|
+
* Materialise one explicit `PdfDestination` from a live `destPtr`. PDFium
|
|
1248
|
+
* already resolved named destinations before handing us the pointer, so
|
|
1249
|
+
* only explicit arrays arrive here (the rule `PdfDestination` documents).
|
|
1250
|
+
*
|
|
1251
|
+
* Returns `null` when the destination is unreadable: no visible indirect page
|
|
1252
|
+
* in the document, or an unknown fit type. Coordinates stay raw PDF user
|
|
1253
|
+
* space — no conversion at this layer.
|
|
1254
|
+
*
|
|
1255
|
+
* Shared by the link reader, `goto` action-node payloads, and the document
|
|
1256
|
+
* `openDestination`; the outline/bookmark port reuses it too.
|
|
1257
|
+
*/
|
|
1258
|
+
function readDestination(fn, mem, docPtr, destPtr) {
|
|
1259
|
+
const pageObjectNumber = fn.EPDFDest_GetPageObjectNumber(docPtr, destPtr);
|
|
1260
|
+
if (pageObjectNumber === 0) return null;
|
|
1261
|
+
const view = withScratchN(mem, [4, MAX_VIEW_PARAMS * 4], ([countPtr, paramsPtr]) => {
|
|
1262
|
+
const code = fn.FPDFDest_GetView(destPtr, countPtr, paramsPtr);
|
|
1263
|
+
const count = Math.min(readI32(mem, countPtr), MAX_VIEW_PARAMS);
|
|
1264
|
+
const params = [];
|
|
1265
|
+
for (let i = 0; i < count; i++) params.push(readF32(mem, paramsPtr, i * 4));
|
|
1266
|
+
return {
|
|
1267
|
+
code,
|
|
1268
|
+
params
|
|
1269
|
+
};
|
|
1270
|
+
});
|
|
1271
|
+
const at = (i) => i < view.params.length ? view.params[i] : null;
|
|
1272
|
+
switch (view.code) {
|
|
1273
|
+
case DEST_VIEW.xyz: return {
|
|
1274
|
+
kind: "xyz",
|
|
1275
|
+
pageObjectNumber,
|
|
1276
|
+
...readXyzLocation(fn, mem, destPtr)
|
|
1277
|
+
};
|
|
1278
|
+
case DEST_VIEW.fit: return {
|
|
1279
|
+
kind: "fit",
|
|
1280
|
+
pageObjectNumber
|
|
1281
|
+
};
|
|
1282
|
+
case DEST_VIEW.fitH: return {
|
|
1283
|
+
kind: "fitH",
|
|
1284
|
+
pageObjectNumber,
|
|
1285
|
+
top: at(0)
|
|
1286
|
+
};
|
|
1287
|
+
case DEST_VIEW.fitV: return {
|
|
1288
|
+
kind: "fitV",
|
|
1289
|
+
pageObjectNumber,
|
|
1290
|
+
left: at(0)
|
|
1291
|
+
};
|
|
1292
|
+
case DEST_VIEW.fitR:
|
|
1293
|
+
if (view.params.length < 4) return {
|
|
1294
|
+
kind: "fit",
|
|
1295
|
+
pageObjectNumber
|
|
1296
|
+
};
|
|
1297
|
+
return {
|
|
1298
|
+
kind: "fitR",
|
|
1299
|
+
pageObjectNumber,
|
|
1300
|
+
left: view.params[0],
|
|
1301
|
+
bottom: view.params[1],
|
|
1302
|
+
right: view.params[2],
|
|
1303
|
+
top: view.params[3]
|
|
1304
|
+
};
|
|
1305
|
+
case DEST_VIEW.fitB: return {
|
|
1306
|
+
kind: "fitB",
|
|
1307
|
+
pageObjectNumber
|
|
1308
|
+
};
|
|
1309
|
+
case DEST_VIEW.fitBH: return {
|
|
1310
|
+
kind: "fitBH",
|
|
1311
|
+
pageObjectNumber,
|
|
1312
|
+
top: at(0)
|
|
1313
|
+
};
|
|
1314
|
+
case DEST_VIEW.fitBV: return {
|
|
1315
|
+
kind: "fitBV",
|
|
1316
|
+
pageObjectNumber,
|
|
1317
|
+
left: at(0)
|
|
1318
|
+
};
|
|
1319
|
+
default: return null;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
/** `/XYZ` null-aware axes via `FPDFDest_GetLocationInPage` (FPDF_BOOL is 4 bytes). */
|
|
1323
|
+
function readXyzLocation(fn, mem, destPtr) {
|
|
1324
|
+
return withScratchN(mem, [
|
|
1325
|
+
4,
|
|
1326
|
+
4,
|
|
1327
|
+
4,
|
|
1328
|
+
4,
|
|
1329
|
+
4,
|
|
1330
|
+
4
|
|
1331
|
+
], ([hasLeft, hasTop, hasZoom, left, top, zoom]) => {
|
|
1332
|
+
if (!fn.FPDFDest_GetLocationInPage(destPtr, hasLeft, hasTop, hasZoom, left, top, zoom)) return {
|
|
1333
|
+
left: null,
|
|
1334
|
+
top: null,
|
|
1335
|
+
zoom: null
|
|
1336
|
+
};
|
|
1337
|
+
return {
|
|
1338
|
+
left: readI32(mem, hasLeft) ? readF32(mem, left) : null,
|
|
1339
|
+
top: readI32(mem, hasTop) ? readF32(mem, top) : null,
|
|
1340
|
+
zoom: readI32(mem, hasZoom) ? readF32(mem, zoom) : null
|
|
1341
|
+
};
|
|
1342
|
+
});
|
|
1343
|
+
}
|
|
1344
|
+
//#endregion
|
|
1215
1345
|
//#region src/features/actions/ActionModelReader.ts
|
|
1216
1346
|
const DEFAULT_ACTION_READ_BUDGET = {
|
|
1217
1347
|
maxModels: 512,
|
|
1218
1348
|
maxNodes: 16384,
|
|
1219
|
-
maxScriptCodeUnits: 16e6
|
|
1349
|
+
maxScriptCodeUnits: 16e6,
|
|
1350
|
+
maxTargetEntries: 4096,
|
|
1351
|
+
maxPayloadCodeUnits: 262144
|
|
1220
1352
|
};
|
|
1221
1353
|
const ACTION_TYPE_BY_CODE = {
|
|
1222
1354
|
0: "unknown",
|
|
@@ -1244,22 +1376,20 @@ const WARNING_MALFORMED_NEXT = 2;
|
|
|
1244
1376
|
const WARNING_INCOMPLETE = 4;
|
|
1245
1377
|
const INVALID_NODE_U32 = 4294967295;
|
|
1246
1378
|
/** Decode one `EPDF_ACTION_TYPE_*` code — the shared vocabulary consumers
|
|
1247
|
-
*
|
|
1379
|
+
* use so action-shaped surfaces cannot drift. */
|
|
1248
1380
|
function actionTypeFromCode(code) {
|
|
1249
1381
|
return ACTION_TYPE_BY_CODE[code] ?? "unknown";
|
|
1250
1382
|
}
|
|
1251
|
-
/**
|
|
1252
|
-
*
|
|
1253
|
-
function isValidActionNodeId(raw) {
|
|
1254
|
-
return raw !== -1 && raw >>> 0 !== INVALID_NODE_U32;
|
|
1255
|
-
}
|
|
1256
|
-
/** Mutable aggregate budget shared by every action model in one read job. */
|
|
1383
|
+
/** Mutable aggregate budget shared by every action model in one read job.
|
|
1384
|
+
* Payload budgets are RESERVED before the backing buffer is allocated. */
|
|
1257
1385
|
var ActionReadBudgetTracker = class {
|
|
1258
1386
|
constructor(limits = DEFAULT_ACTION_READ_BUDGET) {
|
|
1259
1387
|
this.limits = limits;
|
|
1260
1388
|
_defineProperty(this, "models", 0);
|
|
1261
1389
|
_defineProperty(this, "nodes", 0);
|
|
1262
1390
|
_defineProperty(this, "scriptCodeUnits", 0);
|
|
1391
|
+
_defineProperty(this, "targetEntries", 0);
|
|
1392
|
+
_defineProperty(this, "payloadCodeUnits", 0);
|
|
1263
1393
|
}
|
|
1264
1394
|
addModel(nodeCount) {
|
|
1265
1395
|
this.models += 1;
|
|
@@ -1270,11 +1400,23 @@ var ActionReadBudgetTracker = class {
|
|
|
1270
1400
|
this.scriptCodeUnits += script.length;
|
|
1271
1401
|
this.assertWithinBudget();
|
|
1272
1402
|
}
|
|
1403
|
+
/** Charge target entries BEFORE the target array is walked. */
|
|
1404
|
+
reserveTargets(count) {
|
|
1405
|
+
this.targetEntries += count;
|
|
1406
|
+
this.assertWithinBudget();
|
|
1407
|
+
}
|
|
1408
|
+
/** Charge payload text BEFORE the scratch buffer for it is allocated. */
|
|
1409
|
+
reservePayloadBytes(length) {
|
|
1410
|
+
this.payloadCodeUnits += length;
|
|
1411
|
+
this.assertWithinBudget();
|
|
1412
|
+
}
|
|
1273
1413
|
assertWithinBudget() {
|
|
1274
|
-
if (this.models > this.limits.maxModels || this.nodes > this.limits.maxNodes || this.scriptCodeUnits > this.limits.maxScriptCodeUnits) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.MalformedPdf, "aggregate PDF action read budget exceeded", { details: {
|
|
1414
|
+
if (this.models > this.limits.maxModels || this.nodes > this.limits.maxNodes || this.scriptCodeUnits > this.limits.maxScriptCodeUnits || this.targetEntries > this.limits.maxTargetEntries || this.payloadCodeUnits > this.limits.maxPayloadCodeUnits) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.MalformedPdf, "aggregate PDF action read budget exceeded", { details: {
|
|
1275
1415
|
models: this.models,
|
|
1276
1416
|
nodes: this.nodes,
|
|
1277
1417
|
scriptCodeUnits: this.scriptCodeUnits,
|
|
1418
|
+
targetEntries: this.targetEntries,
|
|
1419
|
+
payloadCodeUnits: this.payloadCodeUnits,
|
|
1278
1420
|
limits: this.limits
|
|
1279
1421
|
} });
|
|
1280
1422
|
}
|
|
@@ -1282,8 +1424,17 @@ var ActionReadBudgetTracker = class {
|
|
|
1282
1424
|
/**
|
|
1283
1425
|
* Convert and close one detached native action model. This is the only
|
|
1284
1426
|
* native-model walker used by document, page, field, and annotation reads.
|
|
1427
|
+
*
|
|
1428
|
+
* `docPtr` resolves `goto` destinations (page identity + named-destination
|
|
1429
|
+
* lookup); every caller reads within an open document session.
|
|
1430
|
+
*
|
|
1431
|
+
* Payload rule: a node whose payload cannot be materialised (a goto without
|
|
1432
|
+
* a resolvable destination, a javascript node with no `/JS`, a withheld
|
|
1433
|
+
* target list) degrades to `{ type: 'unknown' }` with its original `/S` on
|
|
1434
|
+
* `subtype`, and the tree gains the `'payload-dropped'` warning — impossible
|
|
1435
|
+
* states stay unrepresentable while malformed documents stay readable.
|
|
1285
1436
|
*/
|
|
1286
|
-
function readActionModel(fn, mem, modelPtr, budget) {
|
|
1437
|
+
function readActionModel(fn, mem, docPtr, modelPtr, budget) {
|
|
1287
1438
|
if (modelPtr === _embedpdf_engine_runtime.NULL_PTR) return null;
|
|
1288
1439
|
try {
|
|
1289
1440
|
const nodeCount = fn.EPDFAction_GetNodeCount(modelPtr);
|
|
@@ -1293,13 +1444,61 @@ function readActionModel(fn, mem, modelPtr, budget) {
|
|
|
1293
1444
|
const incomplete = !fn.EPDFAction_IsComplete(modelPtr);
|
|
1294
1445
|
const rootId = normalizeOptionalNodeId(fn.EPDFAction_GetRootNode(modelPtr), nodeCount);
|
|
1295
1446
|
const visiting = /* @__PURE__ */ new Set();
|
|
1447
|
+
let payloadDropped = false;
|
|
1448
|
+
/** Probe the two-call length first and charge the budget BEFORE the
|
|
1449
|
+
* scratch buffer for the value is allocated. */
|
|
1450
|
+
const readPayloadString = (call) => {
|
|
1451
|
+
const length = call(_embedpdf_engine_runtime.NULL_PTR, 0);
|
|
1452
|
+
if (length <= 0) return null;
|
|
1453
|
+
budget.reservePayloadBytes(length);
|
|
1454
|
+
return readUtf8String(mem, call);
|
|
1455
|
+
};
|
|
1456
|
+
const readOutBool = (read) => withScratchN(mem, [4], ([outPtr]) => read(outPtr) ? readI32(mem, outPtr) !== 0 : null);
|
|
1457
|
+
const readTargetObjectNumber = (nodeId, index) => withScratchN(mem, [4], ([outPtr]) => {
|
|
1458
|
+
if (!fn.EPDFAction_GetNodeTargetObjectNumber(modelPtr, nodeId, index, outPtr)) return null;
|
|
1459
|
+
const value = readI32(mem, outPtr) >>> 0;
|
|
1460
|
+
return value === 0 ? null : value;
|
|
1461
|
+
});
|
|
1462
|
+
const readTargets = (nodeId, count) => {
|
|
1463
|
+
const targets = [];
|
|
1464
|
+
for (let index = 0; index < count; index++) {
|
|
1465
|
+
const name = readPayloadString((buf, capacity) => fn.EPDFAction_GetNodeTargetName(modelPtr, nodeId, index, buf, capacity));
|
|
1466
|
+
if (name !== null) {
|
|
1467
|
+
targets.push({
|
|
1468
|
+
kind: "name",
|
|
1469
|
+
name
|
|
1470
|
+
});
|
|
1471
|
+
continue;
|
|
1472
|
+
}
|
|
1473
|
+
const objectNumber = readTargetObjectNumber(nodeId, index);
|
|
1474
|
+
if (objectNumber === null) return null;
|
|
1475
|
+
targets.push({
|
|
1476
|
+
kind: "objectNumber",
|
|
1477
|
+
objectNumber
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
return targets;
|
|
1481
|
+
};
|
|
1482
|
+
const readResetFormState = (nodeId) => withScratchN(mem, [4, 4], ([hasFieldsPtr, excludePtr]) => {
|
|
1483
|
+
if (!fn.EPDFAction_GetNodeResetForm(modelPtr, nodeId, hasFieldsPtr, excludePtr)) return null;
|
|
1484
|
+
return {
|
|
1485
|
+
hasFields: readI32(mem, hasFieldsPtr) !== 0,
|
|
1486
|
+
exclude: readI32(mem, excludePtr) !== 0
|
|
1487
|
+
};
|
|
1488
|
+
});
|
|
1489
|
+
const readSubmitFormState = (nodeId) => withScratchN(mem, [4, 4], ([hasFieldsPtr, flagsPtr]) => {
|
|
1490
|
+
if (!fn.EPDFAction_GetNodeSubmitForm(modelPtr, nodeId, hasFieldsPtr, flagsPtr)) return null;
|
|
1491
|
+
return {
|
|
1492
|
+
hasFields: readI32(mem, hasFieldsPtr) !== 0,
|
|
1493
|
+
flags: readI32(mem, flagsPtr) >>> 0
|
|
1494
|
+
};
|
|
1495
|
+
});
|
|
1296
1496
|
const readNode = (nodeId) => {
|
|
1297
1497
|
if (visiting.has(nodeId)) throw malformedActionModel("native action model contains a cycle", { nodeId });
|
|
1298
1498
|
visiting.add(nodeId);
|
|
1299
1499
|
try {
|
|
1500
|
+
const type = actionTypeFromCode(fn.EPDFAction_GetNodeType(modelPtr, nodeId));
|
|
1300
1501
|
const subtype = readUtf8String(mem, (buf, capacity) => fn.EPDFAction_GetNodeSubtype(modelPtr, nodeId, buf, capacity)) ?? "";
|
|
1301
|
-
const script = fn.EPDFAction_NodeHasJavaScript(modelPtr, nodeId) ? readUtf16String(mem, (buf, capacity) => fn.EPDFAction_GetNodeJavaScript(modelPtr, nodeId, buf, capacity)) ?? "" : void 0;
|
|
1302
|
-
if (script !== void 0) budget.addScript(script);
|
|
1303
1502
|
const nextCount = fn.EPDFAction_GetNextCount(modelPtr, nodeId);
|
|
1304
1503
|
if (!Number.isInteger(nextCount) || nextCount < 0) throw malformedActionModel("invalid action child count", {
|
|
1305
1504
|
nodeId,
|
|
@@ -1310,21 +1509,157 @@ function readActionModel(fn, mem, modelPtr, budget) {
|
|
|
1310
1509
|
const childId = normalizeNodeId(fn.EPDFAction_GetNextAt(modelPtr, nodeId, index), nodeCount);
|
|
1311
1510
|
next.push(readNode(childId));
|
|
1312
1511
|
}
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1512
|
+
const degraded = () => {
|
|
1513
|
+
payloadDropped = true;
|
|
1514
|
+
return {
|
|
1515
|
+
type: "unknown",
|
|
1516
|
+
subtype,
|
|
1517
|
+
next
|
|
1518
|
+
};
|
|
1318
1519
|
};
|
|
1520
|
+
switch (type) {
|
|
1521
|
+
case "javascript": {
|
|
1522
|
+
if (!fn.EPDFAction_NodeHasJavaScript(modelPtr, nodeId)) return degraded();
|
|
1523
|
+
const script = readUtf16String(mem, (buf, capacity) => fn.EPDFAction_GetNodeJavaScript(modelPtr, nodeId, buf, capacity)) ?? "";
|
|
1524
|
+
budget.addScript(script);
|
|
1525
|
+
return {
|
|
1526
|
+
type,
|
|
1527
|
+
subtype,
|
|
1528
|
+
script,
|
|
1529
|
+
next
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
case "rendition": {
|
|
1533
|
+
if (!fn.EPDFAction_NodeHasJavaScript(modelPtr, nodeId)) return {
|
|
1534
|
+
type,
|
|
1535
|
+
subtype,
|
|
1536
|
+
next
|
|
1537
|
+
};
|
|
1538
|
+
const script = readUtf16String(mem, (buf, capacity) => fn.EPDFAction_GetNodeJavaScript(modelPtr, nodeId, buf, capacity)) ?? "";
|
|
1539
|
+
budget.addScript(script);
|
|
1540
|
+
return {
|
|
1541
|
+
type,
|
|
1542
|
+
subtype,
|
|
1543
|
+
script,
|
|
1544
|
+
next
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
case "goto": {
|
|
1548
|
+
const destPtr = fn.EPDFAction_GetNodeDest(docPtr, modelPtr, nodeId);
|
|
1549
|
+
const destination = destPtr !== _embedpdf_engine_runtime.NULL_PTR ? readDestination(fn, mem, docPtr, destPtr) : null;
|
|
1550
|
+
return destination ? {
|
|
1551
|
+
type,
|
|
1552
|
+
subtype,
|
|
1553
|
+
destination,
|
|
1554
|
+
next
|
|
1555
|
+
} : degraded();
|
|
1556
|
+
}
|
|
1557
|
+
case "uri": {
|
|
1558
|
+
const uri = readPayloadString((buf, capacity) => fn.EPDFAction_GetNodeURI(docPtr, modelPtr, nodeId, buf, capacity));
|
|
1559
|
+
if (uri === null) return degraded();
|
|
1560
|
+
return {
|
|
1561
|
+
type,
|
|
1562
|
+
subtype,
|
|
1563
|
+
uri,
|
|
1564
|
+
isMap: readOutBool((outPtr) => fn.EPDFAction_GetNodeURIIsMap(modelPtr, nodeId, outPtr)) ?? false,
|
|
1565
|
+
next
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
case "named": {
|
|
1569
|
+
const name = readPayloadString((buf, capacity) => fn.EPDFAction_GetNodeName(modelPtr, nodeId, buf, capacity));
|
|
1570
|
+
return name === null ? degraded() : {
|
|
1571
|
+
type,
|
|
1572
|
+
subtype,
|
|
1573
|
+
name,
|
|
1574
|
+
next
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1577
|
+
case "hide": {
|
|
1578
|
+
const count = fn.EPDFAction_GetNodeTargetCount(modelPtr, nodeId);
|
|
1579
|
+
if (!Number.isInteger(count) || count < 0) return degraded();
|
|
1580
|
+
budget.reserveTargets(count);
|
|
1581
|
+
const targets = readTargets(nodeId, count);
|
|
1582
|
+
if (targets === null) return degraded();
|
|
1583
|
+
return {
|
|
1584
|
+
type,
|
|
1585
|
+
subtype,
|
|
1586
|
+
targets,
|
|
1587
|
+
hide: readOutBool((outPtr) => fn.EPDFAction_GetNodeHideFlag(modelPtr, nodeId, outPtr)) ?? true,
|
|
1588
|
+
next
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
case "reset-form": {
|
|
1592
|
+
const state = readResetFormState(nodeId);
|
|
1593
|
+
const count = fn.EPDFAction_GetNodeTargetCount(modelPtr, nodeId);
|
|
1594
|
+
if (state === null || !Number.isInteger(count) || count < 0) return degraded();
|
|
1595
|
+
budget.reserveTargets(count);
|
|
1596
|
+
const fields = state.hasFields ? readTargets(nodeId, count) : null;
|
|
1597
|
+
if (state.hasFields && fields === null) return degraded();
|
|
1598
|
+
return {
|
|
1599
|
+
type,
|
|
1600
|
+
subtype,
|
|
1601
|
+
fields,
|
|
1602
|
+
exclude: state.exclude,
|
|
1603
|
+
next
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
case "submit-form": {
|
|
1607
|
+
if (typeof fn.EPDFAction_GetNodeSubmitForm !== "function") return {
|
|
1608
|
+
type,
|
|
1609
|
+
subtype,
|
|
1610
|
+
next
|
|
1611
|
+
};
|
|
1612
|
+
const state = readSubmitFormState(nodeId);
|
|
1613
|
+
if (state === null) return degraded();
|
|
1614
|
+
const url = readPayloadString((buf, capacity) => fn.EPDFAction_GetNodeSubmitFormURL(modelPtr, nodeId, buf, capacity));
|
|
1615
|
+
if (url === null) return degraded();
|
|
1616
|
+
const count = fn.EPDFAction_GetNodeTargetCount(modelPtr, nodeId);
|
|
1617
|
+
if (!Number.isInteger(count) || count < 0) return degraded();
|
|
1618
|
+
budget.reserveTargets(count);
|
|
1619
|
+
const fields = state.hasFields ? readTargets(nodeId, count) : null;
|
|
1620
|
+
if (state.hasFields && fields === null) return degraded();
|
|
1621
|
+
const charSet = readPayloadString((buf, capacity) => fn.EPDFAction_GetNodeSubmitFormCharSet(modelPtr, nodeId, buf, capacity));
|
|
1622
|
+
return {
|
|
1623
|
+
type,
|
|
1624
|
+
subtype,
|
|
1625
|
+
payload: {
|
|
1626
|
+
url,
|
|
1627
|
+
fields,
|
|
1628
|
+
flags: (0, _embedpdf_engine_core_runtime.decodeSubmitFormFlags)(state.flags),
|
|
1629
|
+
...charSet === null ? {} : { charSet }
|
|
1630
|
+
},
|
|
1631
|
+
next
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
case "goto-remote":
|
|
1635
|
+
case "goto-embedded":
|
|
1636
|
+
case "launch": {
|
|
1637
|
+
const filePath = readPayloadString((buf, capacity) => fn.EPDFAction_GetNodeFilePath(modelPtr, nodeId, buf, capacity));
|
|
1638
|
+
return filePath === null ? degraded() : {
|
|
1639
|
+
type,
|
|
1640
|
+
subtype,
|
|
1641
|
+
filePath,
|
|
1642
|
+
next
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
default: return {
|
|
1646
|
+
type,
|
|
1647
|
+
subtype,
|
|
1648
|
+
next
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1319
1651
|
} finally {
|
|
1320
1652
|
visiting.delete(nodeId);
|
|
1321
1653
|
}
|
|
1322
1654
|
};
|
|
1655
|
+
const root = rootId === null ? null : readNode(rootId);
|
|
1656
|
+
const warnings = warningsFromFlags(warningFlags, incomplete);
|
|
1657
|
+
if (payloadDropped) warnings.push("payload-dropped");
|
|
1323
1658
|
return {
|
|
1324
|
-
root
|
|
1659
|
+
root,
|
|
1325
1660
|
incomplete,
|
|
1326
1661
|
warningFlags,
|
|
1327
|
-
warnings
|
|
1662
|
+
warnings
|
|
1328
1663
|
};
|
|
1329
1664
|
} finally {
|
|
1330
1665
|
fn.EPDFAction_CloseModel(modelPtr);
|
|
@@ -1404,8 +1739,8 @@ var PagesReader = class {
|
|
|
1404
1739
|
};
|
|
1405
1740
|
function readPageActions(fn, mem, docPtr, pageObjectNumber, budget) {
|
|
1406
1741
|
const actions = {};
|
|
1407
|
-
const open = readActionModel(fn, mem, fn.EPDFDoc_GetPageActionModel(docPtr, pageObjectNumber, 0), budget);
|
|
1408
|
-
const close = readActionModel(fn, mem, fn.EPDFDoc_GetPageActionModel(docPtr, pageObjectNumber, 1), budget);
|
|
1742
|
+
const open = readActionModel(fn, mem, docPtr, fn.EPDFDoc_GetPageActionModel(docPtr, pageObjectNumber, 0), budget);
|
|
1743
|
+
const close = readActionModel(fn, mem, docPtr, fn.EPDFDoc_GetPageActionModel(docPtr, pageObjectNumber, 1), budget);
|
|
1409
1744
|
if (open) actions.open = open;
|
|
1410
1745
|
if (close) actions.close = close;
|
|
1411
1746
|
return open || close ? actions : void 0;
|
|
@@ -2823,167 +3158,67 @@ function readLine(fn, mem, annotPtr, base) {
|
|
|
2823
3158
|
};
|
|
2824
3159
|
}
|
|
2825
3160
|
//#endregion
|
|
2826
|
-
//#region src/features/annotations/internal/destinationViewCodes.ts
|
|
2827
|
-
/**
|
|
2828
|
-
* `PDFDEST_VIEW_*` fit-type codes (public/fpdf_doc.h) — the shared
|
|
2829
|
-
* vocabulary of `FPDFDest_GetView` (read) and `EPDFDest_CreateView`
|
|
2830
|
-
* (write). XYZ is listed for completeness but never goes through
|
|
2831
|
-
* CreateView (it has its own null-aware constructor).
|
|
2832
|
-
*/
|
|
2833
|
-
const DEST_VIEW = {
|
|
2834
|
-
unknown: 0,
|
|
2835
|
-
xyz: 1,
|
|
2836
|
-
fit: 2,
|
|
2837
|
-
fitH: 3,
|
|
2838
|
-
fitV: 4,
|
|
2839
|
-
fitR: 5,
|
|
2840
|
-
fitB: 6,
|
|
2841
|
-
fitBH: 7,
|
|
2842
|
-
fitBV: 8
|
|
2843
|
-
};
|
|
2844
|
-
/** Wire destination kind → PDFDEST_VIEW code, for the non-XYZ kinds. */
|
|
2845
|
-
const VIEW_CODE_BY_KIND = {
|
|
2846
|
-
fit: DEST_VIEW.fit,
|
|
2847
|
-
fitH: DEST_VIEW.fitH,
|
|
2848
|
-
fitV: DEST_VIEW.fitV,
|
|
2849
|
-
fitR: DEST_VIEW.fitR,
|
|
2850
|
-
fitB: DEST_VIEW.fitB,
|
|
2851
|
-
fitBH: DEST_VIEW.fitBH,
|
|
2852
|
-
fitBV: DEST_VIEW.fitBV
|
|
2853
|
-
};
|
|
2854
|
-
//#endregion
|
|
2855
|
-
//#region src/features/annotations/internal/read/readDestination.ts
|
|
2856
|
-
const MAX_VIEW_PARAMS = 4;
|
|
2857
|
-
/**
|
|
2858
|
-
* Materialise one explicit `PdfDestination` from a live `destPtr`. PDFium
|
|
2859
|
-
* already resolved named destinations before handing us the pointer, so
|
|
2860
|
-
* only explicit arrays arrive here (the rule `PdfDestination` documents).
|
|
2861
|
-
*
|
|
2862
|
-
* Returns `null` when the destination is unreadable: no visible indirect page
|
|
2863
|
-
* in the document, or an unknown fit type. Coordinates stay raw PDF user
|
|
2864
|
-
* space — no conversion at this layer.
|
|
2865
|
-
*
|
|
2866
|
-
* Shared by the link reader today; the outline/bookmark port reuses it.
|
|
2867
|
-
*/
|
|
2868
|
-
function readDestination(fn, mem, docPtr, destPtr) {
|
|
2869
|
-
const pageObjectNumber = fn.EPDFDest_GetPageObjectNumber(docPtr, destPtr);
|
|
2870
|
-
if (pageObjectNumber === 0) return null;
|
|
2871
|
-
const view = withScratchN(mem, [4, MAX_VIEW_PARAMS * 4], ([countPtr, paramsPtr]) => {
|
|
2872
|
-
const code = fn.FPDFDest_GetView(destPtr, countPtr, paramsPtr);
|
|
2873
|
-
const count = Math.min(readI32(mem, countPtr), MAX_VIEW_PARAMS);
|
|
2874
|
-
const params = [];
|
|
2875
|
-
for (let i = 0; i < count; i++) params.push(readF32(mem, paramsPtr, i * 4));
|
|
2876
|
-
return {
|
|
2877
|
-
code,
|
|
2878
|
-
params
|
|
2879
|
-
};
|
|
2880
|
-
});
|
|
2881
|
-
const at = (i) => i < view.params.length ? view.params[i] : null;
|
|
2882
|
-
switch (view.code) {
|
|
2883
|
-
case DEST_VIEW.xyz: return {
|
|
2884
|
-
kind: "xyz",
|
|
2885
|
-
pageObjectNumber,
|
|
2886
|
-
...readXyzLocation(fn, mem, destPtr)
|
|
2887
|
-
};
|
|
2888
|
-
case DEST_VIEW.fit: return {
|
|
2889
|
-
kind: "fit",
|
|
2890
|
-
pageObjectNumber
|
|
2891
|
-
};
|
|
2892
|
-
case DEST_VIEW.fitH: return {
|
|
2893
|
-
kind: "fitH",
|
|
2894
|
-
pageObjectNumber,
|
|
2895
|
-
top: at(0)
|
|
2896
|
-
};
|
|
2897
|
-
case DEST_VIEW.fitV: return {
|
|
2898
|
-
kind: "fitV",
|
|
2899
|
-
pageObjectNumber,
|
|
2900
|
-
left: at(0)
|
|
2901
|
-
};
|
|
2902
|
-
case DEST_VIEW.fitR:
|
|
2903
|
-
if (view.params.length < 4) return {
|
|
2904
|
-
kind: "fit",
|
|
2905
|
-
pageObjectNumber
|
|
2906
|
-
};
|
|
2907
|
-
return {
|
|
2908
|
-
kind: "fitR",
|
|
2909
|
-
pageObjectNumber,
|
|
2910
|
-
left: view.params[0],
|
|
2911
|
-
bottom: view.params[1],
|
|
2912
|
-
right: view.params[2],
|
|
2913
|
-
top: view.params[3]
|
|
2914
|
-
};
|
|
2915
|
-
case DEST_VIEW.fitB: return {
|
|
2916
|
-
kind: "fitB",
|
|
2917
|
-
pageObjectNumber
|
|
2918
|
-
};
|
|
2919
|
-
case DEST_VIEW.fitBH: return {
|
|
2920
|
-
kind: "fitBH",
|
|
2921
|
-
pageObjectNumber,
|
|
2922
|
-
top: at(0)
|
|
2923
|
-
};
|
|
2924
|
-
case DEST_VIEW.fitBV: return {
|
|
2925
|
-
kind: "fitBV",
|
|
2926
|
-
pageObjectNumber,
|
|
2927
|
-
left: at(0)
|
|
2928
|
-
};
|
|
2929
|
-
default: return null;
|
|
2930
|
-
}
|
|
2931
|
-
}
|
|
2932
|
-
/** `/XYZ` null-aware axes via `FPDFDest_GetLocationInPage` (FPDF_BOOL is 4 bytes). */
|
|
2933
|
-
function readXyzLocation(fn, mem, destPtr) {
|
|
2934
|
-
return withScratchN(mem, [
|
|
2935
|
-
4,
|
|
2936
|
-
4,
|
|
2937
|
-
4,
|
|
2938
|
-
4,
|
|
2939
|
-
4,
|
|
2940
|
-
4
|
|
2941
|
-
], ([hasLeft, hasTop, hasZoom, left, top, zoom]) => {
|
|
2942
|
-
if (!fn.FPDFDest_GetLocationInPage(destPtr, hasLeft, hasTop, hasZoom, left, top, zoom)) return {
|
|
2943
|
-
left: null,
|
|
2944
|
-
top: null,
|
|
2945
|
-
zoom: null
|
|
2946
|
-
};
|
|
2947
|
-
return {
|
|
2948
|
-
left: readI32(mem, hasLeft) ? readF32(mem, left) : null,
|
|
2949
|
-
top: readI32(mem, hasTop) ? readF32(mem, top) : null,
|
|
2950
|
-
zoom: readI32(mem, hasZoom) ? readF32(mem, zoom) : null
|
|
2951
|
-
};
|
|
2952
|
-
});
|
|
2953
|
-
}
|
|
2954
|
-
//#endregion
|
|
2955
3161
|
//#region src/features/annotations/internal/read/readLinkAnnotation.ts
|
|
2956
3162
|
/**
|
|
2957
3163
|
* Link reader: rect/flags/relationship ride the base (a link grouped to an
|
|
2958
3164
|
* annotation is plain `inReplyTo` + `replyType: 'group'`); this module only
|
|
2959
3165
|
* materialises the normalized target.
|
|
2960
3166
|
*
|
|
2961
|
-
* ONE truth,
|
|
2962
|
-
*
|
|
2963
|
-
*
|
|
2964
|
-
*
|
|
2965
|
-
* and Named-blind) is deliberately not consulted; `FPDFLink_GetDest`
|
|
2966
|
-
* remains only for the data-only direct `/Dest`, which is not an action.
|
|
3167
|
+
* ONE truth, one projection: the target is a pure function of the SAME
|
|
3168
|
+
* payload-carrying action tree the scripting plane reads
|
|
3169
|
+
* (`base.actions.activate`) — no second native read exists any more, so the
|
|
3170
|
+
* two action-shaped surfaces cannot drift by construction.
|
|
2967
3171
|
*
|
|
2968
|
-
* `/A`
|
|
2969
|
-
*
|
|
2970
|
-
*
|
|
3172
|
+
* `/A` precedence, pinned: an activate action that exists but cannot be
|
|
3173
|
+
* executed (an `incomplete` tree, a degraded/unreadable root) projects
|
|
3174
|
+
* `unsupported` — a broken action is a dead link, never an invitation to
|
|
3175
|
+
* guess. The direct `/Dest` (which is data, not an action) is consulted
|
|
3176
|
+
* ONLY when no `/A` exists at all.
|
|
2971
3177
|
*/
|
|
2972
3178
|
function readLink(fn, mem, annotPtr, base, _rawSubtypeCode, ctx) {
|
|
2973
3179
|
return {
|
|
2974
3180
|
...base,
|
|
2975
3181
|
subtype: "link",
|
|
2976
|
-
target: readLinkTarget(fn, mem, annotPtr, ctx)
|
|
3182
|
+
target: readLinkTarget(fn, mem, annotPtr, base, ctx)
|
|
2977
3183
|
};
|
|
2978
3184
|
}
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
3185
|
+
/**
|
|
3186
|
+
* Project the navigation view from a payload-carrying activate tree. Pure —
|
|
3187
|
+
* shared with any consumer that wants the root-level navigation reading of a
|
|
3188
|
+
* tree (the link plugin's no-actions-plugin fallback uses the same law).
|
|
3189
|
+
*/
|
|
3190
|
+
function linkTargetFromActionTree(tree) {
|
|
3191
|
+
if (tree.incomplete) return { kind: "unsupported" };
|
|
3192
|
+
const root = tree.root;
|
|
3193
|
+
if (!root) return { kind: "unsupported" };
|
|
3194
|
+
switch (root.type) {
|
|
3195
|
+
case "goto": return {
|
|
3196
|
+
kind: "goto",
|
|
3197
|
+
destination: root.destination
|
|
3198
|
+
};
|
|
3199
|
+
case "uri": return {
|
|
3200
|
+
kind: "uri",
|
|
3201
|
+
uri: root.uri
|
|
3202
|
+
};
|
|
3203
|
+
case "goto-remote": return {
|
|
3204
|
+
kind: "goto-remote",
|
|
3205
|
+
file: root.filePath
|
|
3206
|
+
};
|
|
3207
|
+
case "launch": return {
|
|
3208
|
+
kind: "launch",
|
|
3209
|
+
path: root.filePath
|
|
3210
|
+
};
|
|
3211
|
+
case "javascript": return { kind: "javascript" };
|
|
3212
|
+
case "named": return {
|
|
3213
|
+
kind: "named",
|
|
3214
|
+
name: root.name
|
|
3215
|
+
};
|
|
3216
|
+
default: return { kind: "unsupported" };
|
|
2986
3217
|
}
|
|
3218
|
+
}
|
|
3219
|
+
function readLinkTarget(fn, mem, annotPtr, base, ctx) {
|
|
3220
|
+
const activate = base.actions?.activate;
|
|
3221
|
+
if (activate) return linkTargetFromActionTree(activate);
|
|
2987
3222
|
const linkPtr = fn.FPDFAnnot_GetLink(annotPtr);
|
|
2988
3223
|
if (!linkPtr) return null;
|
|
2989
3224
|
const destPtr = fn.FPDFLink_GetDest(ctx.docPtr, linkPtr);
|
|
@@ -2994,43 +3229,6 @@ function readLinkTarget(fn, mem, annotPtr, ctx) {
|
|
|
2994
3229
|
destination
|
|
2995
3230
|
} : { kind: "unsupported" };
|
|
2996
3231
|
}
|
|
2997
|
-
/** Classify the root action node and fetch its payload — the projection. */
|
|
2998
|
-
function readRootTarget(fn, mem, modelPtr, node, ctx) {
|
|
2999
|
-
switch (actionTypeFromCode(fn.EPDFAction_GetNodeType(modelPtr, node))) {
|
|
3000
|
-
case "goto": {
|
|
3001
|
-
const destPtr = fn.EPDFAction_GetNodeDest(ctx.docPtr, modelPtr, node);
|
|
3002
|
-
const destination = destPtr ? readDestination(fn, mem, ctx.docPtr, destPtr) : null;
|
|
3003
|
-
return destination ? {
|
|
3004
|
-
kind: "goto",
|
|
3005
|
-
destination
|
|
3006
|
-
} : { kind: "unsupported" };
|
|
3007
|
-
}
|
|
3008
|
-
case "uri": {
|
|
3009
|
-
const uri = readUtf8String(mem, (buf, capacity) => fn.EPDFAction_GetNodeURI(ctx.docPtr, modelPtr, node, buf, capacity));
|
|
3010
|
-
return uri == null ? { kind: "unsupported" } : {
|
|
3011
|
-
kind: "uri",
|
|
3012
|
-
uri
|
|
3013
|
-
};
|
|
3014
|
-
}
|
|
3015
|
-
case "goto-remote": return {
|
|
3016
|
-
kind: "goto-remote",
|
|
3017
|
-
file: readUtf8String(mem, (buf, capacity) => fn.EPDFAction_GetNodeFilePath(modelPtr, node, buf, capacity)) ?? ""
|
|
3018
|
-
};
|
|
3019
|
-
case "launch": return {
|
|
3020
|
-
kind: "launch",
|
|
3021
|
-
path: readUtf8String(mem, (buf, capacity) => fn.EPDFAction_GetNodeFilePath(modelPtr, node, buf, capacity)) ?? ""
|
|
3022
|
-
};
|
|
3023
|
-
case "javascript": return { kind: "javascript" };
|
|
3024
|
-
case "named": {
|
|
3025
|
-
const name = readUtf8String(mem, (buf, capacity) => fn.EPDFAction_GetNodeName(modelPtr, node, buf, capacity));
|
|
3026
|
-
return name == null ? { kind: "unsupported" } : {
|
|
3027
|
-
kind: "named",
|
|
3028
|
-
name
|
|
3029
|
-
};
|
|
3030
|
-
}
|
|
3031
|
-
default: return { kind: "unsupported" };
|
|
3032
|
-
}
|
|
3033
|
-
}
|
|
3034
3232
|
//#endregion
|
|
3035
3233
|
//#region src/features/annotations/internal/read/readRedactAnnotation.ts
|
|
3036
3234
|
/** Default `/C` marking outline (red) — the redaction marking convention and
|
|
@@ -3540,7 +3738,7 @@ function readOptions(runtime, model, fieldIndex) {
|
|
|
3540
3738
|
return options;
|
|
3541
3739
|
}
|
|
3542
3740
|
/** Read one field of the native model into its per-family DTO. */
|
|
3543
|
-
function readFieldAt(runtime, model, fieldIndex, actionBudget = new ActionReadBudgetTracker()) {
|
|
3741
|
+
function readFieldAt(runtime, model, fieldIndex, docPtr, actionBudget = new ActionReadBudgetTracker()) {
|
|
3544
3742
|
const { fn } = runtime;
|
|
3545
3743
|
const fieldObjectNumber = fn.EPDFForm_GetFieldObjNum(model, fieldIndex);
|
|
3546
3744
|
const name = readWide(runtime, (buf, cap) => fn.EPDFForm_GetFieldName(model, fieldIndex, buf, cap));
|
|
@@ -3548,7 +3746,7 @@ function readFieldAt(runtime, model, fieldIndex, actionBudget = new ActionReadBu
|
|
|
3548
3746
|
const family = FAMILY_BY_CODE[fn.EPDFForm_GetFieldFamily(model, fieldIndex)] ?? "unknown";
|
|
3549
3747
|
const valueEntry = readValueEntry(runtime, model, fieldIndex, false);
|
|
3550
3748
|
const defaultValueEntry = readValueEntry(runtime, model, fieldIndex, true);
|
|
3551
|
-
const actions = readFieldActions(runtime, model, fieldIndex, actionBudget);
|
|
3749
|
+
const actions = readFieldActions(runtime, model, fieldIndex, docPtr, actionBudget);
|
|
3552
3750
|
const base = {
|
|
3553
3751
|
ref: fieldObjectNumber > 0 ? {
|
|
3554
3752
|
kind: "objectNumber",
|
|
@@ -3647,12 +3845,12 @@ function readFieldAt(runtime, model, fieldIndex, actionBudget = new ActionReadBu
|
|
|
3647
3845
|
}
|
|
3648
3846
|
}
|
|
3649
3847
|
/** Read the whole native model into a detached {@link FormSnapshot}. */
|
|
3650
|
-
function readFormSnapshot(runtime, model) {
|
|
3848
|
+
function readFormSnapshot(runtime, model, docPtr) {
|
|
3651
3849
|
const { fn } = runtime;
|
|
3652
3850
|
const count = fn.EPDFForm_CountFields(model);
|
|
3653
3851
|
const fields = [];
|
|
3654
3852
|
const actionBudget = new ActionReadBudgetTracker();
|
|
3655
|
-
for (let i = 0; i < count; i++) fields.push(readFieldAt(runtime, model, i, actionBudget));
|
|
3853
|
+
for (let i = 0; i < count; i++) fields.push(readFieldAt(runtime, model, i, docPtr, actionBudget));
|
|
3656
3854
|
const calculationOrder = [];
|
|
3657
3855
|
const calculationCount = fn.EPDFForm_CountCalculationOrder(model);
|
|
3658
3856
|
for (let index = 0; index < calculationCount; index++) {
|
|
@@ -3688,7 +3886,7 @@ function entryScalar(entry) {
|
|
|
3688
3886
|
if (entry.kind === "array") return entry.values[0] ?? "";
|
|
3689
3887
|
return "";
|
|
3690
3888
|
}
|
|
3691
|
-
function readFieldActions(runtime, model, fieldIndex, budget) {
|
|
3889
|
+
function readFieldActions(runtime, model, fieldIndex, docPtr, budget) {
|
|
3692
3890
|
const { fn, mem } = runtime;
|
|
3693
3891
|
const entries = [
|
|
3694
3892
|
["keystroke", 0],
|
|
@@ -3698,7 +3896,7 @@ function readFieldActions(runtime, model, fieldIndex, budget) {
|
|
|
3698
3896
|
];
|
|
3699
3897
|
const actions = {};
|
|
3700
3898
|
for (const [key, event] of entries) {
|
|
3701
|
-
const action = readActionModel(fn, mem, fn.EPDFForm_GetFieldActionModel(model, fieldIndex, event), budget);
|
|
3899
|
+
const action = readActionModel(fn, mem, docPtr, fn.EPDFForm_GetFieldActionModel(model, fieldIndex, event), budget);
|
|
3702
3900
|
if (action) actions[key] = action;
|
|
3703
3901
|
}
|
|
3704
3902
|
return Object.keys(actions).length > 0 ? actions : void 0;
|
|
@@ -3944,7 +4142,7 @@ function blendModeFromCode(code) {
|
|
|
3944
4142
|
* per-subtype reader builds its DTO by extending this with its own
|
|
3945
4143
|
* fields and `subtype: '...'` discriminator.
|
|
3946
4144
|
*/
|
|
3947
|
-
function readAnnotationBase(fn, mem, annotPtr, pageObjectNumber, index, revision, actionBudget = new ActionReadBudgetTracker()) {
|
|
4145
|
+
function readAnnotationBase(fn, mem, docPtr, annotPtr, pageObjectNumber, index, revision, actionBudget = new ActionReadBudgetTracker()) {
|
|
3948
4146
|
const identity = readAnnotationIdentity(fn, mem, annotPtr, pageObjectNumber, index, revision);
|
|
3949
4147
|
const rect = readAnnotRect(fn, mem, annotPtr);
|
|
3950
4148
|
const flags = readAnnotFlags(fn, annotPtr);
|
|
@@ -3956,7 +4154,7 @@ function readAnnotationBase(fn, mem, annotPtr, pageObjectNumber, index, revision
|
|
|
3956
4154
|
const blendMode = blendModeFromCode(fn.EPDFAnnot_GetBlendMode(annotPtr));
|
|
3957
4155
|
const embd = readEmbedMetadata(fn, mem, annotPtr);
|
|
3958
4156
|
const relationship = readAnnotationRelationship(fn, mem, annotPtr, pageObjectNumber);
|
|
3959
|
-
const actions = readAnnotationActions(fn, mem, annotPtr, actionBudget);
|
|
4157
|
+
const actions = readAnnotationActions(fn, mem, docPtr, annotPtr, actionBudget);
|
|
3960
4158
|
return {
|
|
3961
4159
|
ref: identity.ref,
|
|
3962
4160
|
pageObjectNumber,
|
|
@@ -3980,7 +4178,7 @@ function readAnnotationBase(fn, mem, annotPtr, pageObjectNumber, index, revision
|
|
|
3980
4178
|
...actions ? { actions } : {}
|
|
3981
4179
|
};
|
|
3982
4180
|
}
|
|
3983
|
-
function readAnnotationActions(fn, mem, annotPtr, budget) {
|
|
4181
|
+
function readAnnotationActions(fn, mem, docPtr, annotPtr, budget) {
|
|
3984
4182
|
const events = [
|
|
3985
4183
|
["activate", 0],
|
|
3986
4184
|
["cursorEnter", 1],
|
|
@@ -3996,7 +4194,7 @@ function readAnnotationActions(fn, mem, annotPtr, budget) {
|
|
|
3996
4194
|
];
|
|
3997
4195
|
const actions = {};
|
|
3998
4196
|
for (const [key, event] of events) {
|
|
3999
|
-
const action = readActionModel(fn, mem, fn.EPDFAnnot_GetActionModel(annotPtr, event), budget);
|
|
4197
|
+
const action = readActionModel(fn, mem, docPtr, fn.EPDFAnnot_GetActionModel(annotPtr, event), budget);
|
|
4000
4198
|
if (action) actions[key] = action;
|
|
4001
4199
|
}
|
|
4002
4200
|
return Object.keys(actions).length > 0 ? actions : void 0;
|
|
@@ -4027,7 +4225,7 @@ function collectPageAnnotations(input) {
|
|
|
4027
4225
|
const annotPtr = getAnnotPtrAt(i);
|
|
4028
4226
|
if (!annotPtr) continue;
|
|
4029
4227
|
try {
|
|
4030
|
-
const base = readAnnotationBase(fn, mem, annotPtr, pageObjectNumber, i, revision, actionBudget);
|
|
4228
|
+
const base = readAnnotationBase(fn, mem, readCtx.docPtr, annotPtr, pageObjectNumber, i, revision, actionBudget);
|
|
4031
4229
|
const subtypeCode = fn.FPDFAnnot_GetSubtype(annotPtr);
|
|
4032
4230
|
const { reader } = pickReader(subtypeCode);
|
|
4033
4231
|
const dto = reader(fn, mem, annotPtr, base, subtypeCode, readCtx);
|
|
@@ -4965,7 +5163,7 @@ function computeMutationImpact(inputs) {
|
|
|
4965
5163
|
* `AnnotationUpdateResult.updated`.
|
|
4966
5164
|
*/
|
|
4967
5165
|
function readAnnotationFromPtr(fn, mem, annotPtr, pageObjectNumber, index, revision, ctx) {
|
|
4968
|
-
const base = readAnnotationBase(fn, mem, annotPtr, pageObjectNumber, index, revision);
|
|
5166
|
+
const base = readAnnotationBase(fn, mem, ctx.docPtr, annotPtr, pageObjectNumber, index, revision);
|
|
4969
5167
|
const subtypeCode = fn.FPDFAnnot_GetSubtype(annotPtr);
|
|
4970
5168
|
const { reader } = pickReader(subtypeCode);
|
|
4971
5169
|
return reader(fn, mem, annotPtr, base, subtypeCode, ctx);
|
|
@@ -8183,13 +8381,13 @@ var FormReader = class {
|
|
|
8183
8381
|
snapshot(signal) {
|
|
8184
8382
|
throwIfAborted(signal);
|
|
8185
8383
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8186
|
-
return readFormSnapshot(this.runtime, model);
|
|
8384
|
+
return readFormSnapshot(this.runtime, model, this.session.requireDocPtr());
|
|
8187
8385
|
}
|
|
8188
8386
|
field(ref, signal) {
|
|
8189
8387
|
throwIfAborted(signal);
|
|
8190
8388
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8191
8389
|
const { fieldIndex } = resolveFieldRef(this.runtime, model, ref);
|
|
8192
|
-
return readFieldAt(this.runtime, model, fieldIndex);
|
|
8390
|
+
return readFieldAt(this.runtime, model, fieldIndex, this.session.requireDocPtr());
|
|
8193
8391
|
}
|
|
8194
8392
|
/**
|
|
8195
8393
|
* Serialize form data. Exports read the reconciled view (recovered
|
|
@@ -8345,7 +8543,7 @@ var FormMutator = class {
|
|
|
8345
8543
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8346
8544
|
const resolved = resolveFieldRef(this.runtime, model, ref);
|
|
8347
8545
|
this.assertWritable(resolved.fieldObjectNumber);
|
|
8348
|
-
const before = readFieldAt(this.runtime, model, resolved.fieldIndex);
|
|
8546
|
+
const before = readFieldAt(this.runtime, model, resolved.fieldIndex, this.session.requireDocPtr());
|
|
8349
8547
|
if (!FAMILY_BY_VALUE_TYPE[value.type].includes(before.family)) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.InvalidArg, `value type '${value.type}' does not apply to a '${before.family}' field`);
|
|
8350
8548
|
const changed = this.applyWrite(resolved.fieldObjectNumber, value);
|
|
8351
8549
|
return this.readBack(resolved.fieldObjectNumber, changed);
|
|
@@ -8381,7 +8579,7 @@ var FormMutator = class {
|
|
|
8381
8579
|
const fresh = acquireFormModel(this.runtime, this.session);
|
|
8382
8580
|
return {
|
|
8383
8581
|
...counters,
|
|
8384
|
-
snapshot: readFormSnapshot(this.runtime, fresh),
|
|
8582
|
+
snapshot: readFormSnapshot(this.runtime, fresh, this.session.requireDocPtr()),
|
|
8385
8583
|
meta: EMPTY_META$1
|
|
8386
8584
|
};
|
|
8387
8585
|
}
|
|
@@ -8454,7 +8652,7 @@ var FormMutator = class {
|
|
|
8454
8652
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8455
8653
|
const resolved = resolveFieldRef(this.runtime, model, ref);
|
|
8456
8654
|
this.assertWritable(resolved.fieldObjectNumber);
|
|
8457
|
-
const before = readFieldAt(this.runtime, model, resolved.fieldIndex);
|
|
8655
|
+
const before = readFieldAt(this.runtime, model, resolved.fieldIndex, this.session.requireDocPtr());
|
|
8458
8656
|
if (before.family !== patch.family) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.InvalidArg, `patch family '${patch.family}' does not match field family '${before.family}'`);
|
|
8459
8657
|
const fieldObjectNumber = resolved.fieldObjectNumber;
|
|
8460
8658
|
if (patch.name !== void 0) this.applyWideSetter(fn.EPDFForm_SetFieldName, fieldObjectNumber, patch.name, `cannot rename to "${patch.name}" (sibling conflict or invalid)`);
|
|
@@ -8485,7 +8683,7 @@ var FormMutator = class {
|
|
|
8485
8683
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8486
8684
|
const resolved = resolveFieldRef(this.runtime, model, ref);
|
|
8487
8685
|
this.assertWritable(resolved.fieldObjectNumber);
|
|
8488
|
-
const before = readFieldAt(this.runtime, model, resolved.fieldIndex);
|
|
8686
|
+
const before = readFieldAt(this.runtime, model, resolved.fieldIndex, this.session.requireDocPtr());
|
|
8489
8687
|
if (!withScratchN(mem, [256 * 4, 4], ([buf, countPtr]) => {
|
|
8490
8688
|
mem.poke(countPtr, "i32", 0);
|
|
8491
8689
|
return fn.EPDFForm_DeleteField(this.session.requireDocPtr(), resolved.fieldObjectNumber, buf, 256, countPtr);
|
|
@@ -8505,7 +8703,7 @@ var FormMutator = class {
|
|
|
8505
8703
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8506
8704
|
const resolved = resolveFieldRef(this.runtime, model, ref);
|
|
8507
8705
|
this.assertWritable(resolved.fieldObjectNumber);
|
|
8508
|
-
const before = readFieldAt(this.runtime, model, resolved.fieldIndex);
|
|
8706
|
+
const before = readFieldAt(this.runtime, model, resolved.fieldIndex, this.session.requireDocPtr());
|
|
8509
8707
|
const toggle = before.family === "checkbox" || before.family === "radio";
|
|
8510
8708
|
const state = toggle ? onState ?? (before.family === "checkbox" ? "Yes" : "") : "";
|
|
8511
8709
|
if (toggle && (!state || state === "Off")) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.InvalidArg, "attaching to a radio group needs a non-\"Off\" onState");
|
|
@@ -8551,7 +8749,7 @@ var FormMutator = class {
|
|
|
8551
8749
|
const fresh = acquireFormModel(this.runtime, this.session);
|
|
8552
8750
|
const fieldIndex = this.runtime.fn.EPDFForm_GetFieldIndexByObjNum(fresh, fieldObjectNumber);
|
|
8553
8751
|
if (fieldIndex < 0) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.Unknown, "form field vanished after write");
|
|
8554
|
-
return readFieldAt(this.runtime, fresh, fieldIndex);
|
|
8752
|
+
return readFieldAt(this.runtime, fresh, fieldIndex, this.session.requireDocPtr());
|
|
8555
8753
|
}
|
|
8556
8754
|
assertWritable(fieldObjectNumber) {
|
|
8557
8755
|
if (fieldObjectNumber === 0) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.InvalidArg, "form field is stored as a direct object and cannot be written");
|
|
@@ -8597,7 +8795,7 @@ var FormMutator = class {
|
|
|
8597
8795
|
const fresh = acquireFormModel(this.runtime, this.session);
|
|
8598
8796
|
const fieldIndex = this.runtime.fn.EPDFForm_GetFieldIndexByObjNum(fresh, fieldObjectNumber);
|
|
8599
8797
|
if (fieldIndex < 0) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.Unknown, "form field vanished after write");
|
|
8600
|
-
const field = readFieldAt(this.runtime, fresh, fieldIndex);
|
|
8798
|
+
const field = readFieldAt(this.runtime, fresh, fieldIndex, this.session.requireDocPtr());
|
|
8601
8799
|
const changedSet = new Set(changedObjNums);
|
|
8602
8800
|
return {
|
|
8603
8801
|
field,
|
|
@@ -8743,7 +8941,7 @@ var FormsEffectsApplier = class {
|
|
|
8743
8941
|
if (refs.length === 0) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.InvalidArg, "reset effect requires at least one field");
|
|
8744
8942
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8745
8943
|
const resolved = refs.map((ref) => this.resolve(model, ref));
|
|
8746
|
-
const fields = resolved.map(({ fieldIndex }) => readFieldAt(this.runtime, model, fieldIndex, actionBudget));
|
|
8944
|
+
const fields = resolved.map(({ fieldIndex }) => readFieldAt(this.runtime, model, fieldIndex, this.session.requireDocPtr(), actionBudget));
|
|
8747
8945
|
validateEffect(effect, fields);
|
|
8748
8946
|
return {
|
|
8749
8947
|
effect,
|
|
@@ -8768,7 +8966,7 @@ var FormsEffectsApplier = class {
|
|
|
8768
8966
|
const model = acquireFormModel(this.runtime, this.session);
|
|
8769
8967
|
const index = this.runtime.fn.EPDFForm_GetFieldIndexByObjNum(model, fieldObjectNumber);
|
|
8770
8968
|
if (index < 0) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.InvalidReference, "form field disappeared");
|
|
8771
|
-
return readFieldAt(this.runtime, model, index, actionBudget);
|
|
8969
|
+
return readFieldAt(this.runtime, model, index, this.session.requireDocPtr(), actionBudget);
|
|
8772
8970
|
}
|
|
8773
8971
|
readFieldsBestEffort(fieldObjectNumbers, actionBudget) {
|
|
8774
8972
|
const fields = [];
|
|
@@ -9135,22 +9333,26 @@ var DocumentActionsReader = class {
|
|
|
9135
9333
|
} finally {
|
|
9136
9334
|
fn.FPDFDoc_CloseJavaScriptAction(namedPtr);
|
|
9137
9335
|
}
|
|
9138
|
-
|
|
9336
|
+
budget.reservePayloadBytes(name.length);
|
|
9337
|
+
const action = requireAction(readActionModel(fn, mem, docPtr, fn.EPDFDoc_GetNamedJavaScriptActionModel(docPtr, index), budget), "name-tree script", index);
|
|
9139
9338
|
nameTreeScripts.push({
|
|
9140
9339
|
name,
|
|
9141
9340
|
action
|
|
9142
9341
|
});
|
|
9143
9342
|
}
|
|
9144
|
-
const openAction = readActionModel(fn, mem, fn.EPDFDoc_GetOpenActionModel(docPtr), budget);
|
|
9343
|
+
const openAction = readActionModel(fn, mem, docPtr, fn.EPDFDoc_GetOpenActionModel(docPtr), budget);
|
|
9344
|
+
const openDestPtr = openAction ? _embedpdf_engine_runtime.NULL_PTR : fn.EPDFDoc_GetOpenActionDest(docPtr);
|
|
9345
|
+
const openDestination = openDestPtr !== _embedpdf_engine_runtime.NULL_PTR ? readDestination(fn, mem, docPtr, openDestPtr) : null;
|
|
9145
9346
|
const additional = {};
|
|
9146
9347
|
for (const [key, event] of DOCUMENT_ACTION_EVENTS) {
|
|
9147
9348
|
throwIfAborted(signal);
|
|
9148
|
-
const action = readActionModel(fn, mem, fn.EPDFDoc_GetAdditionalActionModel(docPtr, event), budget);
|
|
9349
|
+
const action = readActionModel(fn, mem, docPtr, fn.EPDFDoc_GetAdditionalActionModel(docPtr, event), budget);
|
|
9149
9350
|
if (action) additional[key] = action;
|
|
9150
9351
|
}
|
|
9151
9352
|
return {
|
|
9152
9353
|
nameTreeScripts,
|
|
9153
9354
|
openAction,
|
|
9355
|
+
openDestination,
|
|
9154
9356
|
...additional
|
|
9155
9357
|
};
|
|
9156
9358
|
}
|