diff --git a/src/core/catalog.js b/src/core/catalog.js index 0b8d3b04f..0b3a2bba9 100644 --- a/src/core/catalog.js +++ b/src/core/catalog.js @@ -53,7 +53,10 @@ import { MetadataParser } from "./metadata_parser.js"; import { StructTreeRoot } from "./struct_tree.js"; function fetchDestination(dest) { - return isDict(dest) ? dest.get("D") : dest; + if (dest instanceof Dict) { + dest = dest.get("D"); + } + return Array.isArray(dest) ? dest : null; } class Catalog { @@ -515,22 +518,41 @@ class Catalog { dests = Object.create(null); if (obj instanceof NameTree) { for (const [key, value] of obj.getAll()) { - dests[key] = fetchDestination(value); + const dest = fetchDestination(value); + if (dest) { + dests[key] = dest; + } } } else if (obj instanceof Dict) { obj.forEach(function (key, value) { - if (value) { - dests[key] = fetchDestination(value); + const dest = fetchDestination(value); + if (dest) { + dests[key] = dest; } }); } return shadow(this, "destinations", dests); } - getDestination(destinationId) { + getDestination(id) { const obj = this._readDests(); - if (obj instanceof NameTree || obj instanceof Dict) { - return fetchDestination(obj.get(destinationId) || null); + if (obj instanceof NameTree) { + const dest = fetchDestination(obj.get(id)); + if (dest) { + return dest; + } + // Fallback to checking the *entire* NameTree, in an attempt to handle + // corrupt PDF documents with out-of-order NameTrees (fixes issue 10272). + const allDest = this.destinations[id]; + if (allDest) { + warn(`Found "${id}" at an incorrect position in the NameTree.`); + return allDest; + } + } else if (obj instanceof Dict) { + const dest = fetchDestination(obj.get(id)); + if (dest) { + return dest; + } } return null; } diff --git a/src/core/name_number_tree.js b/src/core/name_number_tree.js index 588cad7f9..e0bf13ec8 100644 --- a/src/core/name_number_tree.js +++ b/src/core/name_number_tree.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { FormatError, info, unreachable, warn } from "../shared/util.js"; +import { FormatError, unreachable, warn } from "../shared/util.js"; import { isDict, RefSet } from "./primitives.js"; /** @@ -133,23 +133,6 @@ class NameOrNumberTree { return xref.fetchIfRef(entries[m + 1]); } } - - // Fallback to an exhaustive search, in an attempt to handle corrupt - // PDF files where keys are not correctly ordered (fixes issue 10272). - info( - `Falling back to an exhaustive search, for key "${key}", ` + - `in "${this._type}" tree.` - ); - for (let m = 0, mm = entries.length; m < mm; m += 2) { - const currentKey = xref.fetchIfRef(entries[m]); - if (currentKey === key) { - warn( - `The "${key}" key was found at an incorrect, ` + - `i.e. out-of-order, position in "${this._type}" tree.` - ); - return xref.fetchIfRef(entries[m + 1]); - } - } } return null; } diff --git a/src/display/api.js b/src/display/api.js index 714323a39..062c474b5 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -730,8 +730,9 @@ class PDFDocumentProxy { /** * @param {string} id - The named destination to get. - * @returns {Promise>} A promise that is resolved with all - * information of the given named destination. + * @returns {Promise | null>} A promise that is resolved with all + * information of the given named destination, or `null` when the named + * destination is not present in the PDF file. */ getDestination(id) { return this._transport.getDestination(id); diff --git a/test/pdfs/issue10272.pdf.link b/test/pdfs/issue10272.pdf.link new file mode 100644 index 000000000..3af9eedc2 --- /dev/null +++ b/test/pdfs/issue10272.pdf.link @@ -0,0 +1 @@ +https://github.com/mozilla/pdf.js/files/2598691/ATS_TEST_PVC_2_1.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index 27381b5d7..2bc7d078d 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -917,6 +917,12 @@ "link": true, "type": "load" }, + { "id": "issue10272", + "file": "pdfs/issue10272.pdf", + "md5": "bf3b2f74c6878d38a70dc0825f1b9a02", + "link": true, + "type": "other" + }, { "id": "issue10388", "file": "pdfs/issue10388_reduced.pdf", "md5": "62a6b2adbea1535432bd94a3516e2d4c", diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 7aaf2be5d..07b8b77bb 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -669,6 +669,24 @@ describe("api", function () { await loadingTask.destroy(); }); + it("gets a destination, from out-of-order /Names (NameTree) dictionary (issue 10272)", async function () { + if (isNodeJS) { + pending("Linked test-cases are not supported in Node.js."); + } + const loadingTask = getDocument(buildGetDocumentParams("issue10272.pdf")); + const pdfDoc = await loadingTask.promise; + const destination = await pdfDoc.getDestination("link_1"); + expect(destination).toEqual([ + { num: 17, gen: 0 }, + { name: "XYZ" }, + 69, + 125, + 0, + ]); + + await loadingTask.destroy(); + }); + it("gets non-string destination", async function () { let numberPromise = pdfDocument.getDestination(4.3); let booleanPromise = pdfDocument.getDestination(true);