From 0527b8bc8d4312c7aea4b48b246fef0ba5df5abb Mon Sep 17 00:00:00 2001 From: mduan Date: Fri, 18 Jan 2013 15:06:12 -0800 Subject: [PATCH 1/2] Fix invalid version number in truetype 'head' table --- src/fonts.js | 19 +++++++++++++++++++ test/pdfs/issue2531.pdf.link | 1 + test/test_manifest.json | 8 ++++++++ 3 files changed, 28 insertions(+) create mode 100644 test/pdfs/issue2531.pdf.link diff --git a/src/fonts.js b/src/fonts.js index c70831bcb..97a296fbf 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -3254,6 +3254,21 @@ var Font = (function FontClosure() { return glyf.length; } + function sanitizeHead(head) { + var data = head.data; + + // Validate version: + // Should always be 0x00010000 + var version = int32([data[0], data[1], data[2], data[3]]); + if (version >> 16 !== 1) { + info('Invalid version in data type: ' + version); + data[0] = 0; + data[1] = 1; + data[2] = 0; + data[3] = 0; + } + } + function sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong) { var itemSize, itemDecode, itemEncode; @@ -3678,6 +3693,10 @@ var Font = (function FontClosure() { sanitizeTTPrograms(fpgm, prep); + if (head) { + sanitizeHead(head); + } + var isGlyphLocationsLong = int16([head.data[50], head.data[51]]); if (head && loca && glyf) { sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong); diff --git a/test/pdfs/issue2531.pdf.link b/test/pdfs/issue2531.pdf.link new file mode 100644 index 000000000..70f40062c --- /dev/null +++ b/test/pdfs/issue2531.pdf.link @@ -0,0 +1 @@ +http://www.rcjohnso.com/Looper/Looper.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index 9467dcb6b..f612cea6e 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -30,6 +30,14 @@ "rounds": 1, "type": "eq" }, + { "id": "issue2531", + "file": "pdfs/issue2531.pdf", + "md5": "c58e6642d8a6e2ddd5e07a543ef8f30d", + "link": true, + "rounds": 1, + "pageLimit": 4, + "type": "eq" + }, { "id": "html5-canvas-cheat-sheet-load", "file": "pdfs/canvas.pdf", "md5": "59510028561daf62e00bf9f6f066b033", From e4c3b4501dffe5bd9848f12a324dba768529bf7e Mon Sep 17 00:00:00 2001 From: mduan Date: Tue, 22 Jan 2013 10:46:54 -0800 Subject: [PATCH 2/2] Sanitization of truetype fonts to fix #2537 --- src/fonts.js | 49 ++++++++++++++++++++++++++++++++---- test/pdfs/issue2537.pdf.link | 1 + test/test_manifest.json | 12 ++++++++- 3 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 test/pdfs/issue2537.pdf.link diff --git a/src/fonts.js b/src/fonts.js index 97a296fbf..7285cb879 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -3185,13 +3185,23 @@ var Font = (function FontClosure() { font.pos += header.length - 2; var numOfMetrics = int16(font.getBytes(2)); + if (numOfMetrics > numGlyphs) { + info('The numOfMetrics (' + numOfMetrics + ') should not be ' + + 'greater than the numGlyphs (' + numGlyphs + ')'); + // Reduce numOfMetrics if it is greater than numGlyphs + numOfMetrics = numGlyphs; + header.data[34] = (numOfMetrics & 0xff00) >> 8; + header.data[35] = numOfMetrics & 0x00ff; + } + var numOfSidebearings = numGlyphs - numOfMetrics; var numMissing = numOfSidebearings - - ((hmtx.length - numOfMetrics * 4) >> 1); + ((metrics.length - numOfMetrics * 4) >> 1); + if (numMissing > 0) { font.pos = (font.start ? font.start : 0) + metrics.offset; var entries = ''; - for (var i = 0, ii = hmtx.length; i < ii; i++) + for (var i = 0, ii = metrics.length; i < ii; i++) entries += String.fromCharCode(font.getByte()); for (var i = 0; i < numMissing; i++) entries += '\x00\x00'; @@ -3254,19 +3264,48 @@ var Font = (function FontClosure() { return glyf.length; } - function sanitizeHead(head) { + function sanitizeHead(head, numGlyphs, locaLength) { var data = head.data; // Validate version: // Should always be 0x00010000 var version = int32([data[0], data[1], data[2], data[3]]); if (version >> 16 !== 1) { - info('Invalid version in data type: ' + version); + info('Attempting to fix invalid version in head table: ' + version); data[0] = 0; data[1] = 1; data[2] = 0; data[3] = 0; } + + var indexToLocFormat = int16([data[50], data[51]]); + if (indexToLocFormat < 0 || indexToLocFormat > 1) { + info('Attempting to fix invalid indexToLocFormat in head table: ' + + indexToLocFormat); + + // The value of indexToLocFormat should be 0 if the loca table + // consists of short offsets, and should be 1 if the loca table + // consists of long offsets. + // + // The number of entries in the loca table should be numGlyphs + 1. + // + // Using this information, we can work backwards to deduce if the + // size of each offset in the loca table, and thus figure out the + // appropriate value for indexToLocFormat. + + var numGlyphsPlusOne = numGlyphs + 1; + if (locaLength === numGlyphsPlusOne << 1) { + // 0x0000 indicates the loca table consists of short offsets + data[50] = 0; + data[51] = 0; + } else if (locaLength === numGlyphsPlusOne << 2) { + // 0x0001 indicates the loca table consists of long offsets + data[50] = 0; + data[51] = 1; + } else { + warn('Could not fix indexToLocFormat: ' + indexToLocFormat); + } + } } function sanitizeGlyphLocations(loca, glyf, numGlyphs, @@ -3694,7 +3733,7 @@ var Font = (function FontClosure() { sanitizeTTPrograms(fpgm, prep); if (head) { - sanitizeHead(head); + sanitizeHead(head, numGlyphs, loca.length); } var isGlyphLocationsLong = int16([head.data[50], head.data[51]]); diff --git a/test/pdfs/issue2537.pdf.link b/test/pdfs/issue2537.pdf.link new file mode 100644 index 000000000..67040ce65 --- /dev/null +++ b/test/pdfs/issue2537.pdf.link @@ -0,0 +1 @@ +http://my.herk.ro/test.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index f612cea6e..9a7a9fc96 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -35,7 +35,17 @@ "md5": "c58e6642d8a6e2ddd5e07a543ef8f30d", "link": true, "rounds": 1, - "pageLimit": 4, + "firstPage": 4, + "lastPage": 4, + "type": "eq" + }, + { "id": "issue2537", + "file": "pdfs/issue2537.pdf", + "md5": "f56805a70ed3aa52aae5c16dd335f827", + "link": true, + "rounds": 1, + "firstPage": 1, + "lastPage": 1, "type": "eq" }, { "id": "html5-canvas-cheat-sheet-load",