diff --git a/src/core/obj.js b/src/core/obj.js index dd302d10b..95924a6fe 100644 --- a/src/core/obj.js +++ b/src/core/obj.js @@ -640,20 +640,32 @@ var Catalog = (function CatalogClosure() { var destDict = params.destDict; if (!isDict(destDict)) { - warn('Catalog_parseDestDictionary: "destDict" must be a dictionary.'); + warn('parseDestDictionary: "destDict" must be a dictionary.'); return; } var resultObj = params.resultObj; if (typeof resultObj !== 'object') { - warn('Catalog_parseDestDictionary: "resultObj" must be an object.'); + warn('parseDestDictionary: "resultObj" must be an object.'); return; } var docBaseUrl = params.docBaseUrl || null; var 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. + action = destDict.get('Dest'); + } + if (isDict(action)) { - var linkType = action.get('S').name; - switch (linkType) { + let actionType = action.get('S'); + if (!isName(actionType)) { + warn('parseDestDictionary: Invalid type in Action dictionary.'); + return; + } + let actionName = actionType.name; + + switch (actionName) { case 'URI': url = action.get('URI'); if (isName(url)) { @@ -748,11 +760,10 @@ var Catalog = (function CatalogClosure() { } /* falls through */ default: - warn('Catalog_parseDestDictionary: Unrecognized link type "' + - linkType + '".'); + warn(`parseDestDictionary: Unsupported Action type "${actionName}".`); break; } - } else if (destDict.has('Dest')) { // Simple destination link. + } else if (destDict.has('Dest')) { // Simple destination. dest = destDict.get('Dest'); } diff --git a/test/unit/annotation_spec.js b/test/unit/annotation_spec.js index b51f2e690..15975f9f0 100644 --- a/test/unit/annotation_spec.js +++ b/test/unit/annotation_spec.js @@ -689,6 +689,36 @@ describe('annotation', function() { expect(data.dest).toEqual([{ num: 17, gen: 0, }, { name: 'XYZ', }, 0, 841.89, null]); }); + + it('should correctly parse a Dest, which violates the specification ' + + 'by containing a dictionary', function() { + let destDict = new Dict(); + destDict.set('Type', Name.get('Action')); + destDict.set('S', Name.get('GoTo')); + destDict.set('D', 'page.157'); + + let annotationDict = new Dict(); + annotationDict.set('Type', Name.get('Annot')); + annotationDict.set('Subtype', Name.get('Link')); + // The /Dest must be a Name or an Array, refer to ISO 32000-1:2008 + // section 12.3.3, but there are PDF files where it's a dictionary. + annotationDict.set('Dest', destDict); + + let annotationRef = new Ref(798, 0); + let xref = new XRefMock([ + { ref: annotationRef, data: annotationDict, } + ]); + + let annotation = annotationFactory.create(xref, annotationRef, + pdfManagerMock, idFactoryMock); + let data = annotation.data; + expect(data.annotationType).toEqual(AnnotationType.LINK); + + expect(data.url).toBeUndefined(); + expect(data.unsafeUrl).toBeUndefined(); + expect(data.dest).toEqual('page.157'); + }); + }); describe('WidgetAnnotation', function() {