From 9fc7cdcc9d6d29b04ce8bbd6feee08d5b839f507 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Wed, 28 Oct 2020 14:04:09 +0100 Subject: [PATCH 1/2] Use a `Map`, rather than an `Object`, internally in the `Catalog.openAction` getter (PR 11644 follow-up) This provides a work-around to avoid having to conditionally try to initialize the `openAction`-object in multiple places. Given that `Object.fromEntries` doesn't seem to *guarantee* that a `null` prototype is used, we thus hack around that by using `Object.assign` with `Object.create(null)`. --- src/core/obj.js | 24 ++++++++++-------------- src/shared/util.js | 6 ++++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/core/obj.js b/src/core/obj.js index a581317d9..9aeb8f4a5 100644 --- a/src/core/obj.js +++ b/src/core/obj.js @@ -25,6 +25,7 @@ import { isBool, isNum, isString, + objectFromEntries, PermissionFlag, shadow, stringToPDFString, @@ -786,7 +787,7 @@ class Catalog { */ get openAction() { const obj = this._catDict.get("OpenAction"); - let openAction = null; + const openActionMap = new Map(); if (isDict(obj)) { // Convert the OpenAction dictionary into a format that works with @@ -798,23 +799,18 @@ class Catalog { Catalog.parseDestDictionary({ destDict, resultObj }); if (Array.isArray(resultObj.dest)) { - if (!openAction) { - openAction = Object.create(null); - } - openAction.dest = resultObj.dest; + openActionMap.set("dest", resultObj.dest); } else if (resultObj.action) { - if (!openAction) { - openAction = Object.create(null); - } - openAction.action = resultObj.action; + openActionMap.set("action", resultObj.action); } } else if (Array.isArray(obj)) { - if (!openAction) { - openAction = Object.create(null); - } - openAction.dest = obj; + openActionMap.set("dest", obj); } - return shadow(this, "openAction", openAction); + return shadow( + this, + "openAction", + openActionMap.size > 0 ? objectFromEntries(openActionMap) : null + ); } get attachments() { diff --git a/src/shared/util.js b/src/shared/util.js index f7ec7526b..ab1f58aef 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -585,6 +585,11 @@ function string32(value) { ); } +// Ensures that the returned Object has a `null` prototype. +function objectFromEntries(iterable) { + return Object.assign(Object.create(null), Object.fromEntries(iterable)); +} + // Checks the endianness of the platform. function isLittleEndian() { const buffer8 = new Uint8Array(4); @@ -1035,6 +1040,7 @@ export { isString, isSameOrigin, createValidAbsoluteUrl, + objectFromEntries, IsLittleEndianCached, IsEvalSupportedCached, removeNullCharacters, From 820fb7f9694a34d4780464db034e01945696cc4c Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Wed, 28 Oct 2020 14:14:27 +0100 Subject: [PATCH 2/2] Update all `Object.fromEntries` call-sites to ensure that a `null` prototype is used Given that `Object.fromEntries` doesn't seem to *guarantee* that a `null` prototype is used, we thus hack around that by using `Object.assign` with `Object.create(null)`. --- src/display/annotation_storage.js | 4 +++- src/display/metadata.js | 4 ++-- src/display/optional_content_config.js | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/display/annotation_storage.js b/src/display/annotation_storage.js index e1b4fac3a..3bd751192 100644 --- a/src/display/annotation_storage.js +++ b/src/display/annotation_storage.js @@ -13,6 +13,8 @@ * limitations under the License. */ +import { objectFromEntries } from "../shared/util.js"; + /** * Key/value storage for annotation data in forms. */ @@ -67,7 +69,7 @@ class AnnotationStorage { if (this._storage.size === 0) { return null; } - return Object.fromEntries(this._storage); + return objectFromEntries(this._storage); } get size() { diff --git a/src/display/metadata.js b/src/display/metadata.js index d29246228..963eac926 100644 --- a/src/display/metadata.js +++ b/src/display/metadata.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { assert } from "../shared/util.js"; +import { assert, objectFromEntries } from "../shared/util.js"; import { SimpleXMLParser } from "../shared/xml_parser.js"; class Metadata { @@ -118,7 +118,7 @@ class Metadata { } getAll() { - return Object.fromEntries(this._metadataMap); + return objectFromEntries(this._metadataMap); } has(name) { diff --git a/src/display/optional_content_config.js b/src/display/optional_content_config.js index da9f00794..7e664a3e5 100644 --- a/src/display/optional_content_config.js +++ b/src/display/optional_content_config.js @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { warn } from "../shared/util.js"; +import { objectFromEntries, warn } from "../shared/util.js"; class OptionalContentGroup { constructor(name, intent) { @@ -145,7 +145,7 @@ class OptionalContentConfig { if (!this._groups.size) { return null; } - return Object.fromEntries(this._groups); + return objectFromEntries(this._groups); } getGroup(id) {