From 558a22cd02186965ba5191aad951c6ef94acd98c Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 24 Jul 2016 14:32:48 +0200 Subject: [PATCH] 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. --- src/core/annotation.js | 15 ++++--- test/pdfs/.gitignore | 1 + test/pdfs/issue7446.pdf | 51 +++++++++++++++++++++++ test/test_manifest.json | 8 ++++ test/unit/annotation_layer_spec.js | 66 ++++++++++++++++-------------- 5 files changed, 106 insertions(+), 35 deletions(-) create mode 100644 test/pdfs/issue7446.pdf diff --git a/src/core/annotation.js b/src/core/annotation.js index 38ca66a66..6540e0841 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -74,13 +74,14 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ { // Determine the annotation's 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. var parameters = { xref: xref, dict: dict, - ref: ref + ref: ref, + subtype: subtype, }; switch (subtype) { @@ -116,8 +117,12 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ { return new FileAttachmentAnnotation(parameters); default: - warn('Unimplemented annotation type "' + subtype + '", ' + - 'falling back to base annotation'); + if (!subtype) { + warn('Annotation is missing the required /Subtype.'); + } else { + warn('Unimplemented annotation type "' + subtype + '", ' + + 'falling back to base annotation.'); + } return new Annotation(parameters); } } @@ -181,7 +186,7 @@ var Annotation = (function AnnotationClosure() { // Expose public properties using a data object. this.data = {}; 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.rect = this.rectangle; this.data.color = this.color; diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 7e0a5f6a2..6cbda038d 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -31,6 +31,7 @@ !issue7403.pdf !issue7426.pdf !issue7439.pdf +!issue7446.pdf !issue7492.pdf !filled-background.pdf !ArabicCIDTrueType.pdf diff --git a/test/pdfs/issue7446.pdf b/test/pdfs/issue7446.pdf new file mode 100644 index 000000000..7def26265 --- /dev/null +++ b/test/pdfs/issue7446.pdf @@ -0,0 +1,51 @@ +%PDF-1.7 +%%μῦ + +1 0 obj +<> +endobj + +2 0 obj +<> +endobj + +3 0 obj +<>>>/Contents 5 0 R>> +endobj + +4 0 obj +<> +endobj + +5 0 obj +<> +stream +BT +10 10 TD +/F1 12 Tf +(Renders even with a broken annotation) Tj +ET + +endstream +endobj + +6 0 obj +<> +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 +<> + +startxref +518 +%%EOF diff --git a/test/test_manifest.json b/test/test_manifest.json index 4a1604a3d..8816c1706 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -1131,6 +1131,14 @@ "link": false, "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", "file": "pdfs/issue7492.pdf", "md5": "7b0b28919c1088a2a5a0aeedbaa4c3ca", diff --git a/test/unit/annotation_layer_spec.js b/test/unit/annotation_layer_spec.js index c7f773b94..ea8cd02eb 100644 --- a/test/unit/annotation_layer_spec.js +++ b/test/unit/annotation_layer_spec.js @@ -26,11 +26,35 @@ describe('Annotation layer', function() { 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() { + 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() { - var dict = new Dict(); - dict.set('Subtype', ''); - var annotation = new Annotation({ dict: dict, ref: 0 }); + var annotation = new Annotation({ dict: dict, ref: ref }); annotation.setFlags(13); 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() { - var dict = new Dict(); - dict.set('Subtype', ''); - var annotation = new Annotation({ dict: dict, ref: 0 }); + var annotation = new Annotation({ dict: dict, ref: ref }); expect(annotation.viewable).toEqual(true); expect(annotation.printable).toEqual(false); }); it('should set and get a valid rectangle', function() { - var dict = new Dict(); - dict.set('Subtype', ''); - var annotation = new Annotation({ dict: dict, ref: 0 }); + var annotation = new Annotation({ dict: dict, ref: ref }); annotation.setRectangle([117, 694, 164.298, 720]); expect(annotation.rectangle).toEqual([117, 694, 164.298, 720]); }); it('should not set and get an invalid rectangle', function() { - var dict = new Dict(); - dict.set('Subtype', ''); - var annotation = new Annotation({ dict: dict, ref: 0 }); + var annotation = new Annotation({ dict: dict, ref: ref }); annotation.setRectangle([117, 694, 164.298]); expect(annotation.rectangle).toEqual([0, 0, 0, 0]); }); it('should reject a color if it is not an array', function() { - var dict = new Dict(); - dict.set('Subtype', ''); - var annotation = new Annotation({ dict: dict, ref: 0 }); + var annotation = new Annotation({ dict: dict, ref: ref }); annotation.setColor('red'); expect(annotation.color).toEqual(new Uint8Array([0, 0, 0])); }); it('should set and get a transparent color', function() { - var dict = new Dict(); - dict.set('Subtype', ''); - var annotation = new Annotation({ dict: dict, ref: 0 }); + var annotation = new Annotation({ dict: dict, ref: ref }); annotation.setColor([]); expect(annotation.color).toEqual(null); }); it('should set and get a grayscale color', function() { - var dict = new Dict(); - dict.set('Subtype', ''); - var annotation = new Annotation({ dict: dict, ref: 0 }); + var annotation = new Annotation({ dict: dict, ref: ref }); annotation.setColor([0.4]); expect(annotation.color).toEqual(new Uint8Array([102, 102, 102])); }); it('should set and get an RGB color', function() { - var dict = new Dict(); - dict.set('Subtype', ''); - var annotation = new Annotation({ dict: dict, ref: 0 }); + var annotation = new Annotation({ dict: dict, ref: ref }); annotation.setColor([0, 0, 1]); expect(annotation.color).toEqual(new Uint8Array([0, 0, 255])); }); it('should set and get a CMYK color', function() { - var dict = new Dict(); - dict.set('Subtype', ''); - var annotation = new Annotation({ dict: dict, ref: 0 }); + var annotation = new Annotation({ dict: dict, ref: ref }); annotation.setColor([0.1, 0.92, 0.84, 0.02]); expect(annotation.color).toEqual(new Uint8Array([233, 59, 47])); }); it('should not set and get an invalid color', function() { - var dict = new Dict(); - dict.set('Subtype', ''); - var annotation = new Annotation({ dict: dict, ref: 0 }); + var annotation = new Annotation({ dict: dict, ref: ref }); annotation.setColor([0.4, 0.6]); expect(annotation.color).toEqual(new Uint8Array([0, 0, 0]));