Merge pull request #9990 from timvandermeij/catalog
Convert the `Catalog` class, in `src/core/obj.js`, to ES6 syntax
This commit is contained in:
commit
7b7cd6dc95
361
src/core/obj.js
361
src/core/obj.js
@ -32,13 +32,14 @@ function fetchDestination(dest) {
|
||||
return isDict(dest) ? dest.get('D') : dest;
|
||||
}
|
||||
|
||||
var Catalog = (function CatalogClosure() {
|
||||
function Catalog(pdfManager, xref) {
|
||||
class Catalog {
|
||||
constructor(pdfManager, xref) {
|
||||
this.pdfManager = pdfManager;
|
||||
this.xref = xref;
|
||||
|
||||
this.catDict = xref.getCatalogObj();
|
||||
if (!isDict(this.catDict)) {
|
||||
throw new FormatError('catalog object is not a dictionary');
|
||||
throw new FormatError('Catalog object is not a dictionary.');
|
||||
}
|
||||
|
||||
this.fontCache = new RefSetCache();
|
||||
@ -46,21 +47,20 @@ var Catalog = (function CatalogClosure() {
|
||||
this.pageKidsCountCache = new RefSetCache();
|
||||
}
|
||||
|
||||
Catalog.prototype = {
|
||||
get metadata() {
|
||||
var streamRef = this.catDict.getRaw('Metadata');
|
||||
const streamRef = this.catDict.getRaw('Metadata');
|
||||
if (!isRef(streamRef)) {
|
||||
return shadow(this, 'metadata', null);
|
||||
}
|
||||
|
||||
var encryptMetadata = (!this.xref.encrypt ? false :
|
||||
const suppressEncryption = !(this.xref.encrypt &&
|
||||
this.xref.encrypt.encryptMetadata);
|
||||
const stream = this.xref.fetch(streamRef, suppressEncryption);
|
||||
let metadata;
|
||||
|
||||
var stream = this.xref.fetch(streamRef, !encryptMetadata);
|
||||
var metadata;
|
||||
if (stream && isDict(stream.dict)) {
|
||||
var type = stream.dict.get('Type');
|
||||
var subtype = stream.dict.get('Subtype');
|
||||
const type = stream.dict.get('Type');
|
||||
const subtype = stream.dict.get('Subtype');
|
||||
|
||||
if (isName(type, 'Metadata') && isName(subtype, 'XML')) {
|
||||
// XXX: This should examine the charset the XML document defines,
|
||||
@ -78,31 +78,35 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shadow(this, 'metadata', metadata);
|
||||
},
|
||||
get toplevelPagesDict() {
|
||||
var pagesObj = this.catDict.get('Pages');
|
||||
if (!isDict(pagesObj)) {
|
||||
throw new FormatError('invalid top-level pages dictionary');
|
||||
}
|
||||
// shadow the prototype getter
|
||||
|
||||
get toplevelPagesDict() {
|
||||
const pagesObj = this.catDict.get('Pages');
|
||||
if (!isDict(pagesObj)) {
|
||||
throw new FormatError('Invalid top-level pages dictionary.');
|
||||
}
|
||||
return shadow(this, 'toplevelPagesDict', pagesObj);
|
||||
},
|
||||
}
|
||||
|
||||
get documentOutline() {
|
||||
var obj = null;
|
||||
let obj = null;
|
||||
try {
|
||||
obj = this.readDocumentOutline();
|
||||
obj = this._readDocumentOutline();
|
||||
} catch (ex) {
|
||||
if (ex instanceof MissingDataException) {
|
||||
throw ex;
|
||||
}
|
||||
warn('Unable to read document outline');
|
||||
warn('Unable to read document outline.');
|
||||
}
|
||||
return shadow(this, 'documentOutline', obj);
|
||||
},
|
||||
readDocumentOutline: function Catalog_readDocumentOutline() {
|
||||
var obj = this.catDict.get('Outlines');
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_readDocumentOutline() {
|
||||
let obj = this.catDict.get('Outlines');
|
||||
if (!isDict(obj)) {
|
||||
return null;
|
||||
}
|
||||
@ -110,39 +114,42 @@ var Catalog = (function CatalogClosure() {
|
||||
if (!isRef(obj)) {
|
||||
return null;
|
||||
}
|
||||
var root = { items: [], };
|
||||
var queue = [{ obj, parent: root, }];
|
||||
|
||||
const root = { items: [], };
|
||||
const queue = [{ obj, parent: root, }];
|
||||
// To avoid recursion, keep track of the already processed items.
|
||||
var processed = new RefSet();
|
||||
const processed = new RefSet();
|
||||
processed.put(obj);
|
||||
var xref = this.xref, blackColor = new Uint8ClampedArray(3);
|
||||
const xref = this.xref, blackColor = new Uint8ClampedArray(3);
|
||||
|
||||
while (queue.length > 0) {
|
||||
var i = queue.shift();
|
||||
var outlineDict = xref.fetchIfRef(i.obj);
|
||||
const i = queue.shift();
|
||||
const outlineDict = xref.fetchIfRef(i.obj);
|
||||
if (outlineDict === null) {
|
||||
continue;
|
||||
}
|
||||
if (!outlineDict.has('Title')) {
|
||||
throw new FormatError('Invalid outline item');
|
||||
throw new FormatError('Invalid outline item encountered.');
|
||||
}
|
||||
|
||||
var data = { url: null, dest: null, };
|
||||
const data = { url: null, dest: null, };
|
||||
Catalog.parseDestDictionary({
|
||||
destDict: outlineDict,
|
||||
resultObj: data,
|
||||
docBaseUrl: this.pdfManager.docBaseUrl,
|
||||
});
|
||||
var title = outlineDict.get('Title');
|
||||
var flags = outlineDict.get('F') || 0;
|
||||
const title = outlineDict.get('Title');
|
||||
const flags = outlineDict.get('F') || 0;
|
||||
const color = outlineDict.getArray('C');
|
||||
let rgbColor = blackColor;
|
||||
|
||||
var color = outlineDict.getArray('C'), rgbColor = blackColor;
|
||||
// We only need to parse the color when it's valid, and non-default.
|
||||
if (Array.isArray(color) && color.length === 3 &&
|
||||
(color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) {
|
||||
rgbColor = ColorSpace.singletons.rgb.getRgb(color, 0);
|
||||
}
|
||||
var outlineItem = {
|
||||
|
||||
const outlineItem = {
|
||||
dest: data.dest,
|
||||
url: data.url,
|
||||
unsafeUrl: data.unsafeUrl,
|
||||
@ -154,6 +161,7 @@ var Catalog = (function CatalogClosure() {
|
||||
italic: !!(flags & 1),
|
||||
items: [],
|
||||
};
|
||||
|
||||
i.parent.items.push(outlineItem);
|
||||
obj = outlineDict.getRaw('First');
|
||||
if (isRef(obj) && !processed.has(obj)) {
|
||||
@ -167,16 +175,16 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
}
|
||||
return (root.items.length > 0 ? root.items : null);
|
||||
},
|
||||
}
|
||||
|
||||
get numPages() {
|
||||
var obj = this.toplevelPagesDict.get('Count');
|
||||
const obj = this.toplevelPagesDict.get('Count');
|
||||
if (!Number.isInteger(obj)) {
|
||||
throw new FormatError(
|
||||
'page count in top level pages object is not an integer');
|
||||
'Page count in top-level pages dictionary is not an integer.');
|
||||
}
|
||||
// shadow the prototype getter
|
||||
return shadow(this, 'numPages', obj);
|
||||
},
|
||||
}
|
||||
|
||||
get destinations() {
|
||||
const obj = this._readDests(), dests = Object.create(null);
|
||||
@ -193,14 +201,19 @@ var Catalog = (function CatalogClosure() {
|
||||
});
|
||||
}
|
||||
return shadow(this, 'destinations', dests);
|
||||
},
|
||||
}
|
||||
|
||||
getDestination(destinationId) {
|
||||
const obj = this._readDests();
|
||||
if (obj instanceof NameTree || obj instanceof Dict) {
|
||||
return fetchDestination(obj.get(destinationId) || null);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_readDests() {
|
||||
const obj = this.catDict.get('Names');
|
||||
if (obj && obj.has('Dests')) {
|
||||
@ -208,12 +221,12 @@ var Catalog = (function CatalogClosure() {
|
||||
} else if (this.catDict.has('Dests')) { // Simple destination dictionary.
|
||||
return this.catDict.get('Dests');
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
get pageLabels() {
|
||||
var obj = null;
|
||||
let obj = null;
|
||||
try {
|
||||
obj = this.readPageLabels();
|
||||
obj = this._readPageLabels();
|
||||
} catch (ex) {
|
||||
if (ex instanceof MissingDataException) {
|
||||
throw ex;
|
||||
@ -221,25 +234,29 @@ var Catalog = (function CatalogClosure() {
|
||||
warn('Unable to read page labels.');
|
||||
}
|
||||
return shadow(this, 'pageLabels', obj);
|
||||
},
|
||||
readPageLabels: function Catalog_readPageLabels() {
|
||||
var obj = this.catDict.getRaw('PageLabels');
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_readPageLabels() {
|
||||
const obj = this.catDict.getRaw('PageLabels');
|
||||
if (!obj) {
|
||||
return null;
|
||||
}
|
||||
var pageLabels = new Array(this.numPages);
|
||||
var style = null;
|
||||
var prefix = '';
|
||||
|
||||
var numberTree = new NumberTree(obj, this.xref);
|
||||
var nums = numberTree.getAll();
|
||||
var currentLabel = '', currentIndex = 1;
|
||||
const pageLabels = new Array(this.numPages);
|
||||
let style = null, prefix = '';
|
||||
|
||||
for (var i = 0, ii = this.numPages; i < ii; i++) {
|
||||
const numberTree = new NumberTree(obj, this.xref);
|
||||
const nums = numberTree.getAll();
|
||||
let currentLabel = '', currentIndex = 1;
|
||||
|
||||
for (let i = 0, ii = this.numPages; i < ii; i++) {
|
||||
if (i in nums) {
|
||||
const labelDict = nums[i];
|
||||
if (!isDict(labelDict)) {
|
||||
throw new FormatError('The PageLabel is not a dictionary.');
|
||||
throw new FormatError('PageLabel is not a dictionary.');
|
||||
}
|
||||
|
||||
if (labelDict.has('Type') &&
|
||||
@ -288,15 +305,15 @@ var Catalog = (function CatalogClosure() {
|
||||
break;
|
||||
case 'A':
|
||||
case 'a':
|
||||
var LIMIT = 26; // Use only the characters A--Z, or a--z.
|
||||
var A_UPPER_CASE = 0x41, A_LOWER_CASE = 0x61;
|
||||
const LIMIT = 26; // Use only the characters A-Z, or a-z.
|
||||
const A_UPPER_CASE = 0x41, A_LOWER_CASE = 0x61;
|
||||
|
||||
var baseCharCode = (style === 'a' ? A_LOWER_CASE : A_UPPER_CASE);
|
||||
var letterIndex = currentIndex - 1;
|
||||
var character = String.fromCharCode(baseCharCode +
|
||||
const baseCharCode = (style === 'a' ? A_LOWER_CASE : A_UPPER_CASE);
|
||||
const letterIndex = currentIndex - 1;
|
||||
const character = String.fromCharCode(baseCharCode +
|
||||
(letterIndex % LIMIT));
|
||||
var charBuf = [];
|
||||
for (var j = 0, jj = (letterIndex / LIMIT) | 0; j <= jj; j++) {
|
||||
const charBuf = [];
|
||||
for (let j = 0, jj = (letterIndex / LIMIT) | 0; j <= jj; j++) {
|
||||
charBuf.push(character);
|
||||
}
|
||||
currentLabel = charBuf.join('');
|
||||
@ -313,10 +330,10 @@ var Catalog = (function CatalogClosure() {
|
||||
currentIndex++;
|
||||
}
|
||||
return pageLabels;
|
||||
},
|
||||
}
|
||||
|
||||
get pageMode() {
|
||||
let obj = this.catDict.get('PageMode');
|
||||
const obj = this.catDict.get('PageMode');
|
||||
let pageMode = 'UseNone'; // Default value.
|
||||
|
||||
if (isName(obj)) {
|
||||
@ -331,21 +348,17 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
}
|
||||
return shadow(this, 'pageMode', pageMode);
|
||||
},
|
||||
|
||||
get attachments() {
|
||||
var xref = this.xref;
|
||||
var attachments = null, nameTreeRef;
|
||||
var obj = this.catDict.get('Names');
|
||||
if (obj) {
|
||||
nameTreeRef = obj.getRaw('EmbeddedFiles');
|
||||
}
|
||||
|
||||
if (nameTreeRef) {
|
||||
var nameTree = new NameTree(nameTreeRef, xref);
|
||||
var names = nameTree.getAll();
|
||||
for (var name in names) {
|
||||
var fs = new FileSpec(names[name], xref);
|
||||
get attachments() {
|
||||
const obj = this.catDict.get('Names');
|
||||
let attachments = null;
|
||||
|
||||
if (obj && 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);
|
||||
if (!attachments) {
|
||||
attachments = Object.create(null);
|
||||
}
|
||||
@ -353,49 +366,52 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
}
|
||||
return shadow(this, 'attachments', attachments);
|
||||
},
|
||||
}
|
||||
|
||||
get javaScript() {
|
||||
var xref = this.xref;
|
||||
var obj = this.catDict.get('Names');
|
||||
const obj = this.catDict.get('Names');
|
||||
|
||||
let javaScript = null;
|
||||
function appendIfJavaScriptDict(jsDict) {
|
||||
var type = jsDict.get('S');
|
||||
const type = jsDict.get('S');
|
||||
if (!isName(type, 'JavaScript')) {
|
||||
return;
|
||||
}
|
||||
var js = jsDict.get('JS');
|
||||
|
||||
let js = jsDict.get('JS');
|
||||
if (isStream(js)) {
|
||||
js = bytesToString(js.getBytes());
|
||||
} else if (!isString(js)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!javaScript) {
|
||||
javaScript = [];
|
||||
}
|
||||
javaScript.push(stringToPDFString(js));
|
||||
}
|
||||
|
||||
if (obj && obj.has('JavaScript')) {
|
||||
var nameTree = new NameTree(obj.getRaw('JavaScript'), xref);
|
||||
var names = nameTree.getAll();
|
||||
for (var name in names) {
|
||||
// We don't really use the JavaScript right now. This code is
|
||||
const nameTree = new NameTree(obj.getRaw('JavaScript'), this.xref);
|
||||
const names = nameTree.getAll();
|
||||
for (const name in names) {
|
||||
// We don't use most JavaScript in PDF documents. This code is
|
||||
// defensive so we don't cause errors on document load.
|
||||
var jsDict = names[name];
|
||||
const jsDict = names[name];
|
||||
if (isDict(jsDict)) {
|
||||
appendIfJavaScriptDict(jsDict);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append OpenAction actions to javaScript array
|
||||
var openactionDict = this.catDict.get('OpenAction');
|
||||
if (isDict(openactionDict, 'Action')) {
|
||||
var actionType = openactionDict.get('S');
|
||||
// Append OpenAction actions to the JavaScript array.
|
||||
const openActionDict = this.catDict.get('OpenAction');
|
||||
if (isDict(openActionDict, 'Action')) {
|
||||
const actionType = openActionDict.get('S');
|
||||
if (isName(actionType, 'Named')) {
|
||||
// The named Print action is not a part of the PDF 1.7 specification,
|
||||
// but is supported by many PDF readers/writers (including Adobe's).
|
||||
var action = openactionDict.get('N');
|
||||
const action = openActionDict.get('N');
|
||||
if (isName(action, 'Print')) {
|
||||
if (!javaScript) {
|
||||
javaScript = [];
|
||||
@ -403,39 +419,40 @@ var Catalog = (function CatalogClosure() {
|
||||
javaScript.push('print({});');
|
||||
}
|
||||
} else {
|
||||
appendIfJavaScriptDict(openactionDict);
|
||||
appendIfJavaScriptDict(openActionDict);
|
||||
}
|
||||
}
|
||||
|
||||
return shadow(this, 'javaScript', javaScript);
|
||||
},
|
||||
}
|
||||
|
||||
cleanup: function Catalog_cleanup() {
|
||||
cleanup() {
|
||||
this.pageKidsCountCache.clear();
|
||||
|
||||
var promises = [];
|
||||
this.fontCache.forEach(function (promise) {
|
||||
const promises = [];
|
||||
this.fontCache.forEach(function(promise) {
|
||||
promises.push(promise);
|
||||
});
|
||||
|
||||
return Promise.all(promises).then((translatedFonts) => {
|
||||
for (var i = 0, ii = translatedFonts.length; i < ii; i++) {
|
||||
var font = translatedFonts[i].dict;
|
||||
for (let i = 0, ii = translatedFonts.length; i < ii; i++) {
|
||||
const font = translatedFonts[i].dict;
|
||||
delete font.translated;
|
||||
}
|
||||
this.fontCache.clear();
|
||||
this.builtInCMapCache.clear();
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
getPageDict: function Catalog_getPageDict(pageIndex) {
|
||||
var capability = createPromiseCapability();
|
||||
var nodesToVisit = [this.catDict.getRaw('Pages')];
|
||||
var count, currentPageIndex = 0;
|
||||
var xref = this.xref, pageKidsCountCache = this.pageKidsCountCache;
|
||||
getPageDict(pageIndex) {
|
||||
const capability = createPromiseCapability();
|
||||
const nodesToVisit = [this.catDict.getRaw('Pages')];
|
||||
const xref = this.xref, pageKidsCountCache = this.pageKidsCountCache;
|
||||
let count, currentPageIndex = 0;
|
||||
|
||||
function next() {
|
||||
while (nodesToVisit.length) {
|
||||
var currentNode = nodesToVisit.pop();
|
||||
const currentNode = nodesToVisit.pop();
|
||||
|
||||
if (isRef(currentNode)) {
|
||||
count = pageKidsCountCache.get(currentNode);
|
||||
@ -445,7 +462,7 @@ var Catalog = (function CatalogClosure() {
|
||||
continue;
|
||||
}
|
||||
|
||||
xref.fetchAsync(currentNode).then(function (obj) {
|
||||
xref.fetchAsync(currentNode).then(function(obj) {
|
||||
if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) {
|
||||
if (pageIndex === currentPageIndex) {
|
||||
// Cache the Page reference, since it can *greatly* improve
|
||||
@ -470,7 +487,7 @@ var Catalog = (function CatalogClosure() {
|
||||
// Must be a child page dictionary.
|
||||
if (!isDict(currentNode)) {
|
||||
capability.reject(new FormatError(
|
||||
'page dictionary kid reference points to wrong type of object'));
|
||||
'Page dictionary kid reference points to wrong type of object.'));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -478,7 +495,7 @@ var Catalog = (function CatalogClosure() {
|
||||
if (Number.isInteger(count) && count >= 0) {
|
||||
// Cache the Kids count, since it can reduce redundant lookups in
|
||||
// documents where all nodes are found at *one* level of the tree.
|
||||
var objId = currentNode.objId;
|
||||
const objId = currentNode.objId;
|
||||
if (objId && !pageKidsCountCache.has(objId)) {
|
||||
pageKidsCountCache.put(objId, count);
|
||||
}
|
||||
@ -489,7 +506,7 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
}
|
||||
|
||||
var kids = currentNode.get('Kids');
|
||||
const kids = currentNode.get('Kids');
|
||||
if (!Array.isArray(kids)) {
|
||||
// Prevent errors in corrupt PDF documents that violate the
|
||||
// specification by *inlining* Page dicts directly in the Kids
|
||||
@ -505,105 +522,104 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
|
||||
capability.reject(new FormatError(
|
||||
'page dictionary kids object is not an array'));
|
||||
'Page dictionary kids object is not an array.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Always check all `Kids` nodes, to avoid getting stuck in an empty
|
||||
// node further down in the tree (see issue5644.pdf, issue8088.pdf),
|
||||
// and to ensure that we actually find the correct `Page` dict.
|
||||
for (var last = kids.length - 1; last >= 0; last--) {
|
||||
for (let last = kids.length - 1; last >= 0; last--) {
|
||||
nodesToVisit.push(kids[last]);
|
||||
}
|
||||
}
|
||||
capability.reject(new Error('Page index ' + pageIndex + ' not found.'));
|
||||
capability.reject(new Error(`Page index ${pageIndex} not found.`));
|
||||
}
|
||||
next();
|
||||
return capability.promise;
|
||||
},
|
||||
}
|
||||
|
||||
getPageIndex: function Catalog_getPageIndex(pageRef) {
|
||||
getPageIndex(pageRef) {
|
||||
// The page tree nodes have the count of all the leaves below them. To get
|
||||
// how many pages are before we just have to walk up the tree and keep
|
||||
// adding the count of siblings to the left of the node.
|
||||
var xref = this.xref;
|
||||
const xref = this.xref;
|
||||
|
||||
function pagesBeforeRef(kidRef) {
|
||||
var total = 0;
|
||||
var parentRef;
|
||||
return xref.fetchAsync(kidRef).then(function (node) {
|
||||
let total = 0, parentRef;
|
||||
|
||||
return xref.fetchAsync(kidRef).then(function(node) {
|
||||
if (isRefsEqual(kidRef, pageRef) && !isDict(node, 'Page') &&
|
||||
!(isDict(node) && !node.has('Type') && node.has('Contents'))) {
|
||||
throw new FormatError(
|
||||
'The reference does not point to a /Page Dict.');
|
||||
'The reference does not point to a /Page dictionary.');
|
||||
}
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
if (!isDict(node)) {
|
||||
throw new FormatError('node must be a Dict.');
|
||||
throw new FormatError('Node must be a dictionary.');
|
||||
}
|
||||
parentRef = node.getRaw('Parent');
|
||||
return node.getAsync('Parent');
|
||||
}).then(function (parent) {
|
||||
}).then(function(parent) {
|
||||
if (!parent) {
|
||||
return null;
|
||||
}
|
||||
if (!isDict(parent)) {
|
||||
throw new FormatError('parent must be a Dict.');
|
||||
throw new FormatError('Parent must be a dictionary.');
|
||||
}
|
||||
return parent.getAsync('Kids');
|
||||
}).then(function (kids) {
|
||||
}).then(function(kids) {
|
||||
if (!kids) {
|
||||
return null;
|
||||
}
|
||||
var kidPromises = [];
|
||||
var found = false;
|
||||
for (var i = 0; i < kids.length; i++) {
|
||||
var kid = kids[i];
|
||||
|
||||
const kidPromises = [];
|
||||
let found = false;
|
||||
for (let i = 0, ii = kids.length; i < ii; i++) {
|
||||
const kid = kids[i];
|
||||
if (!isRef(kid)) {
|
||||
throw new FormatError('kid must be a Ref.');
|
||||
throw new FormatError('Kid must be a reference.');
|
||||
}
|
||||
if (isRefsEqual(kid, kidRef)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
kidPromises.push(xref.fetchAsync(kid).then(function (kid) {
|
||||
kidPromises.push(xref.fetchAsync(kid).then(function(kid) {
|
||||
if (!isDict(kid)) {
|
||||
throw new FormatError('kid node must be a Dict.');
|
||||
throw new FormatError('Kid node must be a dictionary.');
|
||||
}
|
||||
if (kid.has('Count')) {
|
||||
var count = kid.get('Count');
|
||||
total += count;
|
||||
} else { // page leaf node
|
||||
total += kid.get('Count');
|
||||
} else { // Page leaf node.
|
||||
total++;
|
||||
}
|
||||
}));
|
||||
}
|
||||
if (!found) {
|
||||
throw new FormatError('kid ref not found in parents kids');
|
||||
throw new FormatError('Kid reference not found in parent\'s kids.');
|
||||
}
|
||||
return Promise.all(kidPromises).then(function () {
|
||||
return Promise.all(kidPromises).then(function() {
|
||||
return [total, parentRef];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var total = 0;
|
||||
let total = 0;
|
||||
function next(ref) {
|
||||
return pagesBeforeRef(ref).then(function (args) {
|
||||
return pagesBeforeRef(ref).then(function(args) {
|
||||
if (!args) {
|
||||
return total;
|
||||
}
|
||||
var count = args[0];
|
||||
var parentRef = args[1];
|
||||
const [count, parentRef] = args;
|
||||
total += count;
|
||||
return next(parentRef);
|
||||
});
|
||||
}
|
||||
|
||||
return next(pageRef);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef ParseDestDictionaryParameters
|
||||
@ -618,16 +634,17 @@ var Catalog = (function CatalogClosure() {
|
||||
* Helper function used to parse the contents of destination dictionaries.
|
||||
* @param {ParseDestDictionaryParameters} params
|
||||
*/
|
||||
Catalog.parseDestDictionary = function Catalog_parseDestDictionary(params) {
|
||||
static parseDestDictionary(params) {
|
||||
// Lets URLs beginning with 'www.' default to using the 'http://' protocol.
|
||||
function addDefaultProtocolToUrl(url) {
|
||||
if (url.indexOf('www.') === 0) {
|
||||
return ('http://' + url);
|
||||
return `http://${url}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
// According to ISO 32000-1:2008, section 12.6.4.7, URIs should be encoded
|
||||
// in 7-bit ASCII. Some bad PDFs use UTF-8 encoding, see Bugzilla 1122280.
|
||||
// in 7-bit ASCII. Some bad PDFs use UTF-8 encoding; see Bugzilla 1122280.
|
||||
function tryConvertUrlEncoding(url) {
|
||||
try {
|
||||
return stringToUTF8String(url);
|
||||
@ -636,19 +653,19 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
}
|
||||
|
||||
var destDict = params.destDict;
|
||||
const destDict = params.destDict;
|
||||
if (!isDict(destDict)) {
|
||||
warn('parseDestDictionary: "destDict" must be a dictionary.');
|
||||
warn('parseDestDictionary: `destDict` must be a dictionary.');
|
||||
return;
|
||||
}
|
||||
var resultObj = params.resultObj;
|
||||
const resultObj = params.resultObj;
|
||||
if (typeof resultObj !== 'object') {
|
||||
warn('parseDestDictionary: "resultObj" must be an object.');
|
||||
warn('parseDestDictionary: `resultObj` must be an object.');
|
||||
return;
|
||||
}
|
||||
var docBaseUrl = params.docBaseUrl || null;
|
||||
const docBaseUrl = params.docBaseUrl || null;
|
||||
|
||||
var action = destDict.get('A'), url, dest;
|
||||
let action = destDict.get('A'), url, dest;
|
||||
if (!isDict(action) && destDict.has('Dest')) {
|
||||
// A /Dest entry should *only* contain a Name or an Array, but some bad
|
||||
// PDF generators ignore that and treat it as an /A entry.
|
||||
@ -656,12 +673,12 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
|
||||
if (isDict(action)) {
|
||||
let actionType = action.get('S');
|
||||
const actionType = action.get('S');
|
||||
if (!isName(actionType)) {
|
||||
warn('parseDestDictionary: Invalid type in Action dictionary.');
|
||||
return;
|
||||
}
|
||||
let actionName = actionType.name;
|
||||
const actionName = actionType.name;
|
||||
|
||||
switch (actionName) {
|
||||
case 'URI':
|
||||
@ -687,7 +704,7 @@ var Catalog = (function CatalogClosure() {
|
||||
/* falls through */
|
||||
|
||||
case 'GoToR':
|
||||
var urlDict = action.get('F');
|
||||
const urlDict = action.get('F');
|
||||
if (isDict(urlDict)) {
|
||||
// We assume that we found a FileSpec dictionary
|
||||
// and fetch the URL without checking any further.
|
||||
@ -697,13 +714,13 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
|
||||
// NOTE: the destination is relative to the *remote* document.
|
||||
var remoteDest = action.get('D');
|
||||
let remoteDest = action.get('D');
|
||||
if (remoteDest) {
|
||||
if (isName(remoteDest)) {
|
||||
remoteDest = remoteDest.name;
|
||||
}
|
||||
if (isString(url)) {
|
||||
let baseUrl = url.split('#')[0];
|
||||
const baseUrl = url.split('#')[0];
|
||||
if (isString(remoteDest)) {
|
||||
url = baseUrl + '#' + remoteDest;
|
||||
} else if (Array.isArray(remoteDest)) {
|
||||
@ -712,21 +729,23 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
}
|
||||
// The 'NewWindow' property, equal to `LinkTarget.BLANK`.
|
||||
var newWindow = action.get('NewWindow');
|
||||
const newWindow = action.get('NewWindow');
|
||||
if (isBool(newWindow)) {
|
||||
resultObj.newWindow = newWindow;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Named':
|
||||
var namedAction = action.get('N');
|
||||
const namedAction = action.get('N');
|
||||
if (isName(namedAction)) {
|
||||
resultObj.action = namedAction.name;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'JavaScript':
|
||||
var jsAction = action.get('JS'), js;
|
||||
const jsAction = action.get('JS');
|
||||
let js;
|
||||
|
||||
if (isStream(jsAction)) {
|
||||
js = bytesToString(jsAction.getBytes());
|
||||
} else if (isString(jsAction)) {
|
||||
@ -734,19 +753,19 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
|
||||
if (js) {
|
||||
// Attempt to recover valid URLs from 'JS' entries with certain
|
||||
// white-listed formats, e.g.
|
||||
// Attempt to recover valid URLs from `JS` entries with certain
|
||||
// white-listed formats:
|
||||
// - window.open('http://example.com')
|
||||
// - app.launchURL('http://example.com', true)
|
||||
var URL_OPEN_METHODS = [
|
||||
const URL_OPEN_METHODS = [
|
||||
'app.launchURL',
|
||||
'window.open'
|
||||
];
|
||||
var regex = new RegExp(
|
||||
const regex = new RegExp(
|
||||
'^\\s*(' + URL_OPEN_METHODS.join('|').split('.').join('\\.') +
|
||||
')\\((?:\'|\")([^\'\"]*)(?:\'|\")(?:,\\s*(\\w+)\\)|\\))', 'i');
|
||||
|
||||
var jsUrl = regex.exec(stringToPDFString(js));
|
||||
const jsUrl = regex.exec(stringToPDFString(js));
|
||||
if (jsUrl && jsUrl[2]) {
|
||||
url = jsUrl[2];
|
||||
|
||||
@ -758,7 +777,7 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
/* falls through */
|
||||
default:
|
||||
warn(`parseDestDictionary: Unsupported Action type "${actionName}".`);
|
||||
warn(`parseDestDictionary: unsupported action type "${actionName}".`);
|
||||
break;
|
||||
}
|
||||
} else if (destDict.has('Dest')) { // Simple destination.
|
||||
@ -767,7 +786,7 @@ var Catalog = (function CatalogClosure() {
|
||||
|
||||
if (isString(url)) {
|
||||
url = tryConvertUrlEncoding(url);
|
||||
var absoluteUrl = createValidAbsoluteUrl(url, docBaseUrl);
|
||||
const absoluteUrl = createValidAbsoluteUrl(url, docBaseUrl);
|
||||
if (absoluteUrl) {
|
||||
resultObj.url = absoluteUrl.href;
|
||||
}
|
||||
@ -781,10 +800,8 @@ var Catalog = (function CatalogClosure() {
|
||||
resultObj.dest = dest;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return Catalog;
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
var XRef = (function XRefClosure() {
|
||||
function XRef(stream, pdfManager) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user