Prevent errors when parsing Annotations with missing (or invalid) /Subtype entries (issue 7446)

Note that I used a separate warning message for this case, instead of utilizing the same one as in the unsupported subtype case, to more clearly indicate that the PDF file itself is to blame rather than PDF.js.

Fixes 7446.
This commit is contained in:
Jonas Jenwald 2016-07-24 14:32:48 +02:00
parent 5678486802
commit 558a22cd02
5 changed files with 106 additions and 35 deletions

View File

@ -74,13 +74,14 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
// Determine the annotation's subtype. // Determine the annotation's subtype.
var subtype = dict.get('Subtype'); var subtype = dict.get('Subtype');
subtype = isName(subtype) ? subtype.name : ''; subtype = isName(subtype) ? subtype.name : null;
// Return the right annotation object based on the subtype and field type. // Return the right annotation object based on the subtype and field type.
var parameters = { var parameters = {
xref: xref, xref: xref,
dict: dict, dict: dict,
ref: ref ref: ref,
subtype: subtype,
}; };
switch (subtype) { switch (subtype) {
@ -116,8 +117,12 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
return new FileAttachmentAnnotation(parameters); return new FileAttachmentAnnotation(parameters);
default: default:
warn('Unimplemented annotation type "' + subtype + '", ' + if (!subtype) {
'falling back to base annotation'); warn('Annotation is missing the required /Subtype.');
} else {
warn('Unimplemented annotation type "' + subtype + '", ' +
'falling back to base annotation.');
}
return new Annotation(parameters); return new Annotation(parameters);
} }
} }
@ -181,7 +186,7 @@ var Annotation = (function AnnotationClosure() {
// Expose public properties using a data object. // Expose public properties using a data object.
this.data = {}; this.data = {};
this.data.id = params.ref.toString(); this.data.id = params.ref.toString();
this.data.subtype = dict.get('Subtype').name; this.data.subtype = params.subtype;
this.data.annotationFlags = this.flags; this.data.annotationFlags = this.flags;
this.data.rect = this.rectangle; this.data.rect = this.rectangle;
this.data.color = this.color; this.data.color = this.color;

View File

@ -31,6 +31,7 @@
!issue7403.pdf !issue7403.pdf
!issue7426.pdf !issue7426.pdf
!issue7439.pdf !issue7439.pdf
!issue7446.pdf
!issue7492.pdf !issue7492.pdf
!filled-background.pdf !filled-background.pdf
!ArabicCIDTrueType.pdf !ArabicCIDTrueType.pdf

51
test/pdfs/issue7446.pdf Normal file
View File

@ -0,0 +1,51 @@
%PDF-1.7
%%μῦ
1 0 obj
<</Type/Catalog/Pages 2 0 R>>
endobj
2 0 obj
<</Type/Pages/MediaBox[0 0 200 200]/Count 1/Kids[3 0 R]>>
endobj
3 0 obj
<</Type/Page/Parent 2 0 R/Annots[6 0 R]/Resources<</Font<</F1 4 0 R>>>>/Contents 5 0 R>>
endobj
4 0 obj
<</Type/Font/Subtype/Type1/BaseFont/Times-Roman>>
endobj
5 0 obj
<</Length 68>>
stream
BT
10 10 TD
/F1 12 Tf
(Renders even with a broken annotation) Tj
ET
endstream
endobj
6 0 obj
<</Type/Annot/Rect[266 116 430 204]/Contents( This annotation is broken )>>
endobj
xref
0 7
0000000000 65536 f
0000000018 00000 n
0000000064 00000 n
0000000138 00000 n
0000000243 00000 n
0000000309 00000 n
0000000426 00000 n
trailer
<</Size 7/Root 1 0 R>>
startxref
518
%%EOF

View File

@ -1131,6 +1131,14 @@
"link": false, "link": false,
"type": "eq" "type": "eq"
}, },
{ "id": "issue7446",
"file": "pdfs/issue7446.pdf",
"md5": "1b5bdd8a806e6ab9eda7c1c707b75fc6",
"rounds": 1,
"link": false,
"type": "load",
"about": "Annotation without the required /Subtype."
},
{ "id": "issue7492-eq", { "id": "issue7492-eq",
"file": "pdfs/issue7492.pdf", "file": "pdfs/issue7492.pdf",
"md5": "7b0b28919c1088a2a5a0aeedbaa4c3ca", "md5": "7b0b28919c1088a2a5a0aeedbaa4c3ca",

View File

@ -26,11 +26,35 @@ describe('Annotation layer', function() {
annotationFactory = null; annotationFactory = null;
}); });
describe('AnnotationFactory', function () {
it('should handle missing /Subtype', function () {
var annotationDict = new Dict();
annotationDict.set('Type', Name.get('Annot'));
var xrefMock = new XrefMock([annotationDict]);
var annotationRef = new Ref(1, 0);
var annotation = annotationFactory.create(xrefMock, annotationRef);
var data = annotation.data;
expect(data.annotationType).toBeUndefined();
});
});
describe('Annotation', function() { describe('Annotation', function() {
var dict, ref;
beforeAll(function (done) {
dict = new Dict();
ref = new Ref(1, 0);
done();
});
afterAll(function () {
dict = ref = null;
});
it('should set and get flags', function() { it('should set and get flags', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setFlags(13); annotation.setFlags(13);
expect(annotation.hasFlag(AnnotationFlag.INVISIBLE)).toEqual(true); expect(annotation.hasFlag(AnnotationFlag.INVISIBLE)).toEqual(true);
@ -40,81 +64,63 @@ describe('Annotation layer', function() {
}); });
it('should be viewable and not printable by default', function() { it('should be viewable and not printable by default', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
expect(annotation.viewable).toEqual(true); expect(annotation.viewable).toEqual(true);
expect(annotation.printable).toEqual(false); expect(annotation.printable).toEqual(false);
}); });
it('should set and get a valid rectangle', function() { it('should set and get a valid rectangle', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setRectangle([117, 694, 164.298, 720]); annotation.setRectangle([117, 694, 164.298, 720]);
expect(annotation.rectangle).toEqual([117, 694, 164.298, 720]); expect(annotation.rectangle).toEqual([117, 694, 164.298, 720]);
}); });
it('should not set and get an invalid rectangle', function() { it('should not set and get an invalid rectangle', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setRectangle([117, 694, 164.298]); annotation.setRectangle([117, 694, 164.298]);
expect(annotation.rectangle).toEqual([0, 0, 0, 0]); expect(annotation.rectangle).toEqual([0, 0, 0, 0]);
}); });
it('should reject a color if it is not an array', function() { it('should reject a color if it is not an array', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor('red'); annotation.setColor('red');
expect(annotation.color).toEqual(new Uint8Array([0, 0, 0])); expect(annotation.color).toEqual(new Uint8Array([0, 0, 0]));
}); });
it('should set and get a transparent color', function() { it('should set and get a transparent color', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([]); annotation.setColor([]);
expect(annotation.color).toEqual(null); expect(annotation.color).toEqual(null);
}); });
it('should set and get a grayscale color', function() { it('should set and get a grayscale color', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([0.4]); annotation.setColor([0.4]);
expect(annotation.color).toEqual(new Uint8Array([102, 102, 102])); expect(annotation.color).toEqual(new Uint8Array([102, 102, 102]));
}); });
it('should set and get an RGB color', function() { it('should set and get an RGB color', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([0, 0, 1]); annotation.setColor([0, 0, 1]);
expect(annotation.color).toEqual(new Uint8Array([0, 0, 255])); expect(annotation.color).toEqual(new Uint8Array([0, 0, 255]));
}); });
it('should set and get a CMYK color', function() { it('should set and get a CMYK color', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([0.1, 0.92, 0.84, 0.02]); annotation.setColor([0.1, 0.92, 0.84, 0.02]);
expect(annotation.color).toEqual(new Uint8Array([233, 59, 47])); expect(annotation.color).toEqual(new Uint8Array([233, 59, 47]));
}); });
it('should not set and get an invalid color', function() { it('should not set and get an invalid color', function() {
var dict = new Dict(); var annotation = new Annotation({ dict: dict, ref: ref });
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([0.4, 0.6]); annotation.setColor([0.4, 0.6]);
expect(annotation.color).toEqual(new Uint8Array([0, 0, 0])); expect(annotation.color).toEqual(new Uint8Array([0, 0, 0]));