From e1412de32075e76f3c6129dc59ef6631cc68b6c6 Mon Sep 17 00:00:00 2001
From: Jonas Jenwald <jonas.jenwald@gmail.com>
Date: Sat, 22 Oct 2016 18:08:25 +0200
Subject: [PATCH] Add more validation to `PDFLinkService_navigateTo`

In some PDF files, the first element (i.e. the one containing either a `Ref` or a `Number` pointing to a page) of the explicit destination Array may be bogus.

One such example is actually the file `pdf.pdf` in the test-suite, where some destinations are incompletely specified. One such example being the `G1.998360` destination whose explicit destination Array contains `[null, /XYZ, 54, 488, null]`, i.e. the destination page is `null`.
Hence this patch adds a bit more validation for that case. It also adds an additional check to ensure that the resulting `pageNumber` is non-negative, and finally a couple more error messages for existing cases of malformed data.
---
 web/pdf_link_service.js | 39 ++++++++++++++++++++++++++++-----------
 1 file changed, 28 insertions(+), 11 deletions(-)

diff --git a/web/pdf_link_service.js b/web/pdf_link_service.js
index 045913a56..28945180e 100644
--- a/web/pdf_link_service.js
+++ b/web/pdf_link_service.js
@@ -106,13 +106,21 @@ var PDFLinkService = (function PDFLinkServiceClosure() {
 
       var goToDestination = function(destRef) {
         // dest array looks like that: <page-ref> </XYZ|/FitXXX> <args..>
-        var pageNumber = destRef instanceof Object ?
-          self._pagesRefCache[destRef.num + ' ' + destRef.gen + ' R'] :
-          (destRef + 1);
+        var pageNumber;
+        if (destRef instanceof Object) {
+          pageNumber = self._cachedPageNumber(destRef);
+        } else if ((destRef | 0) === destRef) { // Integer
+          pageNumber = destRef + 1;
+        } else {
+          console.error('PDFLinkService_navigateTo: "' + destRef +
+                        '" is not a valid destination reference.');
+          return;
+        }
+
         if (pageNumber) {
-          if (pageNumber > self.pagesCount) {
-            console.error('PDFLinkService_navigateTo: ' +
-                          'Trying to navigate to a non-existent page.');
+          if (pageNumber < 1 || pageNumber > self.pagesCount) {
+            console.error('PDFLinkService_navigateTo: "' + pageNumber +
+                          '" is a non-existent page number.');
             return;
           }
           self.pdfViewer.scrollPageIntoView({
@@ -130,10 +138,12 @@ var PDFLinkService = (function PDFLinkServiceClosure() {
           }
         } else {
           self.pdfDocument.getPageIndex(destRef).then(function (pageIndex) {
-            var pageNum = pageIndex + 1;
-            var cacheKey = destRef.num + ' ' + destRef.gen + ' R';
-            self._pagesRefCache[cacheKey] = pageNum;
+            self.cachePageRef(pageIndex + 1, destRef);
             goToDestination(destRef);
+          }).catch(function () {
+            console.error('PDFLinkService_navigateTo: "' + destRef +
+                          '" is not a valid page reference.');
+            return;
           });
         }
       };
@@ -148,7 +158,9 @@ var PDFLinkService = (function PDFLinkServiceClosure() {
       destinationPromise.then(function(destination) {
         dest = destination;
         if (!(destination instanceof Array)) {
-          return; // invalid destination
+          console.error('PDFLinkService_navigateTo: "' + destination +
+                        '" is not a valid destination array.');
+          return;
         }
         goToDestination(destination[0]);
       });
@@ -333,7 +345,12 @@ var PDFLinkService = (function PDFLinkServiceClosure() {
     cachePageRef: function PDFLinkService_cachePageRef(pageNum, pageRef) {
       var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
       this._pagesRefCache[refStr] = pageNum;
-    }
+    },
+
+    _cachedPageNumber: function PDFLinkService_cachedPageNumber(pageRef) {
+      var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
+      return (this._pagesRefCache && this._pagesRefCache[refStr]) || null;
+    },
   };
 
   function isValidExplicitDestination(dest) {