diff --git a/src/core/cff_parser.js b/src/core/cff_parser.js index 20b794305..8335b8fcc 100644 --- a/src/core/cff_parser.js +++ b/src/core/cff_parser.js @@ -413,26 +413,7 @@ var CFFParser = (function CFFParserClosure() { var names = []; for (var i = 0, ii = index.count; i < ii; ++i) { var name = index.get(i); - // OTS doesn't allow names to be over 127 characters. - var length = Math.min(name.length, 127); - var data = []; - // OTS also only permits certain characters in the name. - for (var j = 0; j < length; ++j) { - var c = name[j]; - if (j === 0 && c === 0) { - data[j] = c; - continue; - } - if ((c < 33 || c > 126) || c === 91 /* [ */ || c === 93 /* ] */ || - c === 40 /* ( */ || c === 41 /* ) */ || c === 123 /* { */ || - c === 125 /* } */ || c === 60 /* < */ || c === 62 /* > */ || - c === 47 /* / */ || c === 37 /* % */ || c === 35 /* # */) { - data[j] = 95; - continue; - } - data[j] = c; - } - names.push(bytesToString(data)); + names.push(bytesToString(name)); } return names; }, @@ -1413,7 +1394,27 @@ var CFFCompiler = (function CFFCompilerClosure() { compileNameIndex: function CFFCompiler_compileNameIndex(names) { var nameIndex = new CFFIndex(); for (var i = 0, ii = names.length; i < ii; ++i) { - nameIndex.add(stringToBytes(names[i])); + var name = names[i]; + // OTS doesn't allow names to be over 127 characters. + var length = Math.min(name.length, 127); + var sanitizedName = new Array(length); + for (var j = 0; j < length; j++) { + // OTS requires chars to be between a range and not certain other + // chars. + var char = name[j]; + if (char < '!' || char > '~' || char === '[' || char === ']' || + char === '(' || char === ')' || char === '{' || char === '}' || + char === '<' || char === '>' || char === '/' || char === '%') { + char = '_'; + } + sanitizedName[j] = char; + } + sanitizedName = sanitizedName.join(''); + + if (sanitizedName === '') { + sanitizedName = 'Bad_Font_Name'; + } + nameIndex.add(stringToBytes(sanitizedName)); } return this.compileIndex(nameIndex); }, diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index debd68f74..2dfd68e4b 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -115,6 +115,7 @@ !issue4630.pdf !issue4909.pdf !issue5084.pdf +!issue8960_reduced.pdf !issue5202.pdf !issue5280.pdf !issue5677.pdf diff --git a/test/pdfs/issue8960_reduced.pdf b/test/pdfs/issue8960_reduced.pdf new file mode 100644 index 000000000..4c1f90ac2 Binary files /dev/null and b/test/pdfs/issue8960_reduced.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index 6d07597d8..200d62127 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -766,6 +766,13 @@ "link": false, "type": "eq" }, + { "id": "issue8960_reduced", + "file": "pdfs/issue8960_reduced.pdf", + "md5": "12ccf71307f4b5bd4148d5f985ffde07", + "rounds": 1, + "link": false, + "type": "eq" + }, { "id": "issue5954", "file": "pdfs/issue5954.pdf", "md5": "4f60ec0d9bbeec845b681242b8982361", diff --git a/test/unit/cff_parser_spec.js b/test/unit/cff_parser_spec.js index ee5b8fcbe..3a2101025 100644 --- a/test/unit/cff_parser_spec.js +++ b/test/unit/cff_parser_spec.js @@ -14,7 +14,7 @@ */ import { - CFFCompiler, CFFIndex, CFFParser, CFFStrings + CFFCompiler, CFFParser, CFFStrings } from '../../src/core/cff_parser'; import { SEAC_ANALYSIS_ENABLED } from '../../src/core/fonts'; import { Stream } from '../../src/core/stream'; @@ -88,23 +88,6 @@ describe('CFFParser', function() { expect(names[0]).toEqual('ABCDEF+Times-Roman'); }); - it('sanitizes name index', function() { - var index = new CFFIndex(); - index.add(['['.charCodeAt(0), 'a'.charCodeAt(0)]); - - var names = parser.parseNameIndex(index); - expect(names).toEqual(['_a']); - - index = new CFFIndex(); - var longName = []; - for (var i = 0; i < 129; i++) { - longName.push(0); - } - index.add(longName); - names = parser.parseNameIndex(index); - expect(names[0].length).toEqual(127); - }); - it('parses string index', function() { var strings = cff.strings; expect(strings.count).toEqual(3); @@ -368,6 +351,16 @@ describe('CFFParser', function() { }); describe('CFFCompiler', function() { + + function testParser(bytes) { + bytes = new Uint8Array(bytes); + return new CFFParser({ + getBytes: () => { + return bytes; + }, + }, {}, SEAC_ANALYSIS_ENABLED); + } + it('encodes integers', function() { var c = new CFFCompiler(); // all the examples from the spec @@ -388,5 +381,24 @@ describe('CFFCompiler', function() { expect(c.encodeFloat(5e-11)).toEqual([0x1e, 0x5c, 0x11, 0xff]); }); + it('sanitizes name index', function() { + var c = new CFFCompiler(); + var nameIndexCompiled = c.compileNameIndex(['[a']); + var parser = testParser(nameIndexCompiled); + var nameIndex = parser.parseIndex(0); + var names = parser.parseNameIndex(nameIndex.obj); + expect(names).toEqual(['_a']); + + var longName = ''; + for (var i = 0; i < 129; i++) { + longName += '_'; + } + nameIndexCompiled = c.compileNameIndex([longName]); + parser = testParser(nameIndexCompiled); + nameIndex = parser.parseIndex(0); + names = parser.parseNameIndex(nameIndex.obj); + expect(names[0].length).toEqual(127); + }); + // TODO a lot more compiler tests });