Merge pull request #1361 from moyogo/kerntable

Ignore the length of kern table sutable format 0
This commit is contained in:
Denis Moyogo Jacquerye 2018-11-20 13:41:13 +00:00 committed by GitHub
commit 0c4f11f5ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 69 additions and 1 deletions

View File

@ -48,6 +48,19 @@ class table__k_e_r_n(DefaultTable.DefaultTable):
# This "version" is always 0 so we ignore it here # This "version" is always 0 so we ignore it here
_, length, subtableFormat, coverage = struct.unpack( _, length, subtableFormat, coverage = struct.unpack(
">HHBB", data[:6]) ">HHBB", data[:6])
if nTables == 1 and subtableFormat == 0:
# The "length" value is ignored since some fonts
# (like OpenSans and Calibri) have a subtable larger than
# its value.
nPairs, = struct.unpack(">H", data[6:8])
calculated_length = (nPairs * 6) + 14
if length != calculated_length:
log.warning(
"'kern' subtable longer than defined: "
"%d bytes instead of %d bytes" %
(calculated_length, length)
)
length = calculated_length
if subtableFormat not in kern_classes: if subtableFormat not in kern_classes:
subtable = KernTable_format_unkown(subtableFormat) subtable = KernTable_format_unkown(subtableFormat)
else: else:
@ -128,7 +141,6 @@ class KernTable_format_0(object):
">HHHH", data[:8]) ">HHHH", data[:8])
data = data[8:] data = data[8:]
nPairs = min(nPairs, len(data) // 6)
datas = array.array("H", data[:6 * nPairs]) datas = array.array("H", data[:6 * nPairs])
if sys.byteorder != "big": datas.byteswap() if sys.byteorder != "big": datas.byteswap()
it = iter(datas) it = iter(datas)
@ -153,6 +165,7 @@ class KernTable_format_0(object):
def compile(self, ttFont): def compile(self, ttFont):
nPairs = len(self.kernTable) nPairs = len(self.kernTable)
searchRange, entrySelector, rangeShift = getSearchRange(nPairs, 6) searchRange, entrySelector, rangeShift = getSearchRange(nPairs, 6)
searchRange &= 0xFFFF
data = struct.pack( data = struct.pack(
">HHHH", nPairs, searchRange, entrySelector, rangeShift) ">HHHH", nPairs, searchRange, entrySelector, rangeShift)
@ -175,6 +188,10 @@ class KernTable_format_0(object):
if not self.apple: if not self.apple:
version = 0 version = 0
length = len(data) + 6 length = len(data) + 6
if length >= 0x10000:
log.warning('"kern" subtable overflow, '
'truncating length value while preserving pairs.')
length &= 0xFFFF
header = struct.pack( header = struct.pack(
">HHBB", version, length, self.format, self.coverage) ">HHBB", version, length, self.format, self.coverage)
else: else:

View File

@ -5,6 +5,7 @@ from fontTools.ttLib.tables._k_e_r_n import (
KernTable_format_0, KernTable_format_unkown) KernTable_format_0, KernTable_format_unkown)
from fontTools.misc.textTools import deHexStr from fontTools.misc.textTools import deHexStr
from fontTools.misc.testTools import FakeFont, getXML, parseXML from fontTools.misc.testTools import FakeFont, getXML, parseXML
import itertools
import pytest import pytest
@ -120,12 +121,32 @@ KERN_VER_1_FMT_UNKNOWN_XML = [
'</kernsubtable>', '</kernsubtable>',
] ]
KERN_VER_0_FMT_0_OVERFLOWING_DATA = deHexStr(
'0000 ' # 0: version=0
'0001 ' # 2: nTables=1
'0000 ' # 4: version=0 (bogus field, unused)
'0274 ' # 6: length=628 (bogus value for 66164 % 0x10000)
'00 ' # 8: format=0
'01 ' # 9: coverage=1
'2B11 ' # 10: nPairs=11025
'C000 ' # 12: searchRange=49152
'000D ' # 14: entrySelector=13
'4266 ' # 16: rangeShift=16998
) + deHexStr(' '.join(
'%04X %04X %04X' % (a, b, 0)
for (a, b) in itertools.product(range(105), repeat=2)
))
@pytest.fixture @pytest.fixture
def font(): def font():
return FakeFont(list("ABCDEFGHIJKLMNOPQRSTUVWXYZ" return FakeFont(list("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz")) "abcdefghijklmnopqrstuvwxyz"))
@pytest.fixture
def overflowing_font():
return FakeFont(["glyph%i" % i for i in range(105)])
class KernTableTest(object): class KernTableTest(object):
@ -364,6 +385,36 @@ class KernTable_format_0_Test(object):
assert subtable[("B", "D")] == 1 assert subtable[("B", "D")] == 1
assert subtable[("B", "glyph65535")] == 2 assert subtable[("B", "glyph65535")] == 2
def test_compileOverflowingSubtable(self, overflowing_font):
font = overflowing_font
kern = newTable("kern")
kern.version = 0
st = KernTable_format_0(0)
kern.kernTables = [st]
st.coverage = 1
st.tupleIndex = None
st.kernTable = {
(a, b): 0
for (a, b) in itertools.product(
font.getGlyphOrder(), repeat=2)
}
assert len(st.kernTable) == 11025
data = kern.compile(font)
assert data == KERN_VER_0_FMT_0_OVERFLOWING_DATA
def test_decompileOverflowingSubtable(self, overflowing_font):
font = overflowing_font
data = KERN_VER_0_FMT_0_OVERFLOWING_DATA
kern = newTable("kern")
kern.decompile(data, font)
st = kern.kernTables[0]
assert st.kernTable == {
(a, b): 0
for (a, b) in itertools.product(
font.getGlyphOrder(), repeat=2)
}
if __name__ == "__main__": if __name__ == "__main__":
import sys import sys