Account for broken outlines/annotations, where the destination dictionary contains an invalid /Dest
entry
According to the specification, see http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#page=377, a `Dest` entry in an outline item should *not* contain a dictionary. Unsurprisingly there's PDF generators that completely ignore this, treating is an `A` entry instead. The patch also adds a little bit more validation code in `Catalog.parseDestDictionary`.
This commit is contained in:
parent
bd85bda0a6
commit
42f2d36d1f
@ -640,20 +640,32 @@ var Catalog = (function CatalogClosure() {
|
|||||||
|
|
||||||
var destDict = params.destDict;
|
var destDict = params.destDict;
|
||||||
if (!isDict(destDict)) {
|
if (!isDict(destDict)) {
|
||||||
warn('Catalog_parseDestDictionary: "destDict" must be a dictionary.');
|
warn('parseDestDictionary: "destDict" must be a dictionary.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var resultObj = params.resultObj;
|
var resultObj = params.resultObj;
|
||||||
if (typeof resultObj !== 'object') {
|
if (typeof resultObj !== 'object') {
|
||||||
warn('Catalog_parseDestDictionary: "resultObj" must be an object.');
|
warn('parseDestDictionary: "resultObj" must be an object.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var docBaseUrl = params.docBaseUrl || null;
|
var docBaseUrl = params.docBaseUrl || null;
|
||||||
|
|
||||||
var action = destDict.get('A'), url, dest;
|
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)) {
|
if (isDict(action)) {
|
||||||
var linkType = action.get('S').name;
|
let actionType = action.get('S');
|
||||||
switch (linkType) {
|
if (!isName(actionType)) {
|
||||||
|
warn('parseDestDictionary: Invalid type in Action dictionary.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let actionName = actionType.name;
|
||||||
|
|
||||||
|
switch (actionName) {
|
||||||
case 'URI':
|
case 'URI':
|
||||||
url = action.get('URI');
|
url = action.get('URI');
|
||||||
if (isName(url)) {
|
if (isName(url)) {
|
||||||
@ -748,11 +760,10 @@ var Catalog = (function CatalogClosure() {
|
|||||||
}
|
}
|
||||||
/* falls through */
|
/* falls through */
|
||||||
default:
|
default:
|
||||||
warn('Catalog_parseDestDictionary: Unrecognized link type "' +
|
warn(`parseDestDictionary: Unsupported Action type "${actionName}".`);
|
||||||
linkType + '".');
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (destDict.has('Dest')) { // Simple destination link.
|
} else if (destDict.has('Dest')) { // Simple destination.
|
||||||
dest = destDict.get('Dest');
|
dest = destDict.get('Dest');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,6 +689,36 @@ describe('annotation', function() {
|
|||||||
expect(data.dest).toEqual([{ num: 17, gen: 0, }, { name: 'XYZ', },
|
expect(data.dest).toEqual([{ num: 17, gen: 0, }, { name: 'XYZ', },
|
||||||
0, 841.89, null]);
|
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() {
|
describe('WidgetAnnotation', function() {
|
||||||
|
Loading…
Reference in New Issue
Block a user