diff --git a/src/core/cff_parser.js b/src/core/cff_parser.js index 2a9f3cb0e..2c7578f48 100644 --- a/src/core/cff_parser.js +++ b/src/core/cff_parser.js @@ -856,8 +856,8 @@ var CFFParser = (function CFFParserClosure() { var start = pos; var bytes = this.bytes; var format = bytes[pos++]; - var fdSelect = []; - var i; + var fdSelect = [], rawBytes; + var i, invalidFirstGID = false; switch (format) { case 0: @@ -865,11 +865,18 @@ var CFFParser = (function CFFParserClosure() { var id = bytes[pos++]; fdSelect.push(id); } + rawBytes = bytes.subarray(start, pos); break; case 3: var rangesCount = (bytes[pos++] << 8) | bytes[pos++]; for (i = 0; i < rangesCount; ++i) { var first = (bytes[pos++] << 8) | bytes[pos++]; + if (i === 0 && first !== 0) { + warn('parseFDSelect: The first range must have a first GID of 0' + + ' -- trying to recover.'); + invalidFirstGID = true; + first = 0; + } var fdIndex = bytes[pos++]; var next = (bytes[pos] << 8) | bytes[pos + 1]; for (var j = first; j < next; ++j) { @@ -878,13 +885,19 @@ var CFFParser = (function CFFParserClosure() { } // Advance past the sentinel(next). pos += 2; + rawBytes = bytes.subarray(start, pos); + + if (invalidFirstGID) { + rawBytes[3] = rawBytes[4] = 0; // Adjust the first range, first GID. + } break; default: - error('Unknown fdselect format ' + format); + error('parseFDSelect: Unknown format "' + format + '".'); break; } - var end = pos; - return new CFFFDSelect(fdSelect, bytes.subarray(start, end)); + assert(fdSelect.length === length, 'parseFDSelect: Invalid font data.'); + + return new CFFFDSelect(fdSelect, rawBytes); } }; return CFFParser; diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index f9f1c4102..d0b08ac30 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -37,6 +37,7 @@ !bug1050040.pdf !bug1200096.pdf !bug1068432.pdf +!bug1146106.pdf !issue5564_reduced.pdf !canvas.pdf !bug1132849.pdf diff --git a/test/pdfs/bug1146106.pdf b/test/pdfs/bug1146106.pdf new file mode 100644 index 000000000..c0d053876 Binary files /dev/null and b/test/pdfs/bug1146106.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index 2281e0c78..ac342b40c 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -210,6 +210,13 @@ "link": false, "type": "eq" }, + { "id": "bug1146106", + "file": "pdfs/bug1146106.pdf", + "md5": "a323d3766da49ee40f7d5dff0aeb0cc1", + "rounds": 1, + "link": false, + "type": "eq" + }, { "id": "issue1512", "file": "pdfs/issue1512r.pdf", "md5": "af48ede2658d99cca423147085c6609b", diff --git a/test/unit/cff_parser_spec.js b/test/unit/cff_parser_spec.js index 67594d3f3..754f4630e 100644 --- a/test/unit/cff_parser_spec.js +++ b/test/unit/cff_parser_spec.js @@ -262,10 +262,12 @@ describe('CFFParser', function() { var bytes = new Uint8Array([0x00, // format 0x00, // gid: 0 fd: 0 0x01 // gid: 1 fd: 1 - ]); - parser.bytes = bytes; + ]); + parser.bytes = bytes.slice(); var fdSelect = parser.parseFDSelect(0, 2); + expect(fdSelect.fdSelect).toEqual([0, 1]); + expect(fdSelect.raw).toEqual(bytes); }); it('parses fdselect format 3', function() { @@ -273,13 +275,32 @@ describe('CFFParser', function() { 0x00, 0x02, // range count 0x00, 0x00, // first gid 0x09, // font dict 1 id - 0x00, 0x02, // nex gid - 0x0a, // font dict 2 gid + 0x00, 0x02, // next gid + 0x0a, // font dict 2 id 0x00, 0x04 // sentinel (last gid) - ]); - parser.bytes = bytes; - var fdSelect = parser.parseFDSelect(0, 2); + ]); + parser.bytes = bytes.slice(); + var fdSelect = parser.parseFDSelect(0, 4); + expect(fdSelect.fdSelect).toEqual([9, 9, 0xa, 0xa]); + expect(fdSelect.raw).toEqual(bytes); + }); + + it('parses invalid fdselect format 3 (bug 1146106)', function() { + var bytes = new Uint8Array([0x03, // format + 0x00, 0x02, // range count + 0x00, 0x01, // first gid (invalid) + 0x09, // font dict 1 id + 0x00, 0x02, // next gid + 0x0a, // font dict 2 id + 0x00, 0x04 // sentinel (last gid) + ]); + parser.bytes = bytes.slice(); + var fdSelect = parser.parseFDSelect(0, 4); + + expect(fdSelect.fdSelect).toEqual([9, 9, 0xa, 0xa]); + bytes[3] = bytes[4] = 0x00; // The adjusted first range, first gid. + expect(fdSelect.raw).toEqual(bytes); }); // TODO fdArray