From adc9eb5a5a91ad8f7edc71f92fa3c84c7b6a1b87 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 20 Apr 2025 13:56:52 +0200 Subject: [PATCH] Always fallback to checking all destinations, when lookup fails (issue 19835) In the referenced PDF document the keys, in the /Dests dictionary, need to account for PDFDocEncoding. To improve destination handling in general we'll now unconditionally fallback to always checking all destinations. --- src/core/catalog.js | 10 +++++----- test/pdfs/issue19835.pdf.link | 1 + test/test_manifest.json | 8 ++++++++ test/unit/api_spec.js | 22 ++++++++++++++++++++++ 4 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 test/pdfs/issue19835.pdf.link diff --git a/src/core/catalog.js b/src/core/catalog.js index ee5484e26..e8181d224 100644 --- a/src/core/catalog.js +++ b/src/core/catalog.js @@ -682,7 +682,7 @@ class Catalog { const dest = fetchDest(value); if (dest) { // Always let the NameTree take precedence. - dests[key] ||= dest; + dests[stringToPDFString(key)] ||= dest; } } } @@ -701,12 +701,12 @@ class Catalog { } } - if (rawDests[0] instanceof NameTree) { - // Fallback to checking the *entire* NameTree, in an attempt to handle - // corrupt PDF documents with out-of-order NameTrees (fixes issue 10272). + // Always fallback to checking all destinations, in order to support: + // - PDF documents with out-of-order NameTrees (fixes issue 10272). + // - Destination keys that use PDFDocEncoding (fixes issue 19835). + if (rawDests.length) { const dest = this.destinations[id]; if (dest) { - warn(`Found "${id}" at an incorrect position in the NameTree.`); return dest; } } diff --git a/test/pdfs/issue19835.pdf.link b/test/pdfs/issue19835.pdf.link new file mode 100644 index 000000000..9bf33441d --- /dev/null +++ b/test/pdfs/issue19835.pdf.link @@ -0,0 +1 @@ +https://github.com/user-attachments/files/19825124/AAPL-2024-09-28-10-K-d71aeb7ff955e2fc4770624610676221.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index 621818daa..002bf23ab 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -23,6 +23,14 @@ "link": true, "type": "other" }, + { + "id": "issue19835", + "file": "pdfs/issue19835.pdf", + "md5": "2940a2f8a41fae299b9a599b8364d05c", + "rounds": 1, + "link": true, + "type": "other" + }, { "id": "filled-background-range", "file": "pdfs/filled-background.pdf", diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index f8c100611..37f2453c8 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -1399,6 +1399,28 @@ describe("api", function () { await loadingTask.destroy(); }); + it("gets a destination, from /Dests dictionary with keys using PDFDocEncoding", async function () { + if (isNodeJS) { + pending("Linked test-cases are not supported in Node.js."); + } + const loadingTask = getDocument(buildGetDocumentParams("issue19835.pdf")); + const pdfDoc = await loadingTask.promise; + + const page3 = await pdfDoc.getPage(3); + const annots = await page3.getAnnotations(); + + const annot = annots.find(x => x.id === "22R"); + // Sanity check to make sure that we found the "correct" annotation. + expect(annot.dest).toEqual( + "\u00f2\u00ab\u00d9\u0025\u006f\u2030\u0062\u2122\u0030\u00ab\u00f4\u0047\u0016\u0142\u00e8\u00bd\u2014\u0063\u00a1\u00db" + ); + + const dest = await pdfDoc.getDestination(annot.dest); + expect(dest).toEqual([2, { name: "XYZ" }, 34.0799999, 315.439999, 0]); + + await loadingTask.destroy(); + }); + it("gets non-string destination", async function () { let numberPromise = pdfDocument.getDestination(4.3); let booleanPromise = pdfDocument.getDestination(true);