From 83f7009e4b013c1d671f18ee565720f9e0a36b00 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Wed, 21 Apr 2021 12:14:33 +0200 Subject: [PATCH] Change `NameOrNumberTree.getAll` to return a `Map` rather than an Object Given that we're (almost) always iterating through the result of the `getAll`-calls, using a `Map` seems nicer overall since it's more suited to iteration compared to a regular Object. Also, add a couple of `Dict`-checks in existing code touched by this patch, since it really cannot hurt to prevent *potential* errors in a corrupt PDF document. --- src/core/catalog.js | 29 +++++++++++++---------------- src/core/name_number_tree.js | 15 ++++++++------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/core/catalog.js b/src/core/catalog.js index 47df1ab36..1b3d7e154 100644 --- a/src/core/catalog.js +++ b/src/core/catalog.js @@ -514,9 +514,8 @@ class Catalog { const obj = this._readDests(), dests = Object.create(null); if (obj instanceof NameTree) { - const names = obj.getAll(); - for (const name in names) { - dests[name] = fetchDestination(names[name]); + for (const [key, value] of obj.getAll()) { + dests[key] = fetchDestination(value); } } else if (obj instanceof Dict) { obj.forEach(function (key, value) { @@ -582,8 +581,9 @@ class Catalog { currentIndex = 1; for (let i = 0, ii = this.numPages; i < ii; i++) { - if (i in nums) { - const labelDict = nums[i]; + const labelDict = nums.get(i); + + if (labelDict !== undefined) { if (!isDict(labelDict)) { throw new FormatError("PageLabel is not a dictionary."); } @@ -879,15 +879,14 @@ class Catalog { const obj = this._catDict.get("Names"); let attachments = null; - if (obj && obj.has("EmbeddedFiles")) { + if (obj instanceof Dict && obj.has("EmbeddedFiles")) { const nameTree = new NameTree(obj.getRaw("EmbeddedFiles"), this.xref); - const names = nameTree.getAll(); - for (const name in names) { - const fs = new FileSpec(names[name], this.xref); + for (const [key, value] of nameTree.getAll()) { + const fs = new FileSpec(value, this.xref); if (!attachments) { attachments = Object.create(null); } - attachments[stringToPDFString(name)] = fs.serializable; + attachments[stringToPDFString(key)] = fs.serializable; } } return shadow(this, "attachments", attachments); @@ -916,15 +915,13 @@ class Catalog { javaScript.set(name, stringToPDFString(js)); } - if (obj && obj.has("JavaScript")) { + if (obj instanceof Dict && obj.has("JavaScript")) { const nameTree = new NameTree(obj.getRaw("JavaScript"), this.xref); - const names = nameTree.getAll(); - for (const name in names) { + for (const [key, value] of nameTree.getAll()) { // We don't use most JavaScript in PDF documents. This code is // defensive so we don't cause errors on document load. - const jsDict = names[name]; - if (isDict(jsDict)) { - appendIfJavaScriptDict(name, jsDict); + if (value instanceof Dict) { + appendIfJavaScriptDict(key, value); } } } diff --git a/src/core/name_number_tree.js b/src/core/name_number_tree.js index 19b90bf51..588cad7f9 100644 --- a/src/core/name_number_tree.js +++ b/src/core/name_number_tree.js @@ -32,9 +32,9 @@ class NameOrNumberTree { } getAll() { - const dict = Object.create(null); + const map = new Map(); if (!this.root) { - return dict; + return map; } const xref = this.xref; // Reading Name/Number tree. @@ -59,13 +59,14 @@ class NameOrNumberTree { continue; } const entries = obj.get(this._type); - if (Array.isArray(entries)) { - for (let i = 0, ii = entries.length; i < ii; i += 2) { - dict[xref.fetchIfRef(entries[i])] = xref.fetchIfRef(entries[i + 1]); - } + if (!Array.isArray(entries)) { + continue; + } + for (let i = 0, ii = entries.length; i < ii; i += 2) { + map.set(xref.fetchIfRef(entries[i]), xref.fetchIfRef(entries[i + 1])); } } - return dict; + return map; } get(key) {