From 9fc7cdcc9d6d29b04ce8bbd6feee08d5b839f507 Mon Sep 17 00:00:00 2001
From: Jonas Jenwald <jonas.jenwald@gmail.com>
Date: Wed, 28 Oct 2020 14:04:09 +0100
Subject: [PATCH] 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,