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