[ttFont] fail when input is not seekable and lazy=True

the SFNTReader expects the input file to be seekable, and it already rewinds the file with file.seek(0) to get to the sfnt table directory. Thus, if TTFont is loaded with an unseekable file object and lazy=True, we raise a TTLibError requiring one to either pass a seekable input file, or to not set lazy=True (in which case the input is loaded in a seekable BytesIO)

Fixes https://github.com/fonttools/fonttools/issues/3052
This commit is contained in:
Cosimo Lupo 2023-03-21 16:51:20 +00:00
parent 1d5feb81e5
commit 4543910367
No known key found for this signature in database
GPG Key ID: DF65A8A5A119C9A8

View File

@ -6,7 +6,7 @@ from fontTools.misc.loggingTools import deprecateArgument
from fontTools.ttLib import TTLibError
from fontTools.ttLib.ttGlyphSet import _TTGlyph, _TTGlyphSetCFF, _TTGlyphSetGlyf
from fontTools.ttLib.sfnt import SFNTReader, SFNTWriter
from io import BytesIO, StringIO
from io import BytesIO, StringIO, UnsupportedOperation
import os
import logging
import traceback
@ -126,6 +126,7 @@ class TTFont(object):
self.flavor = flavor
self.flavorData = None
return
seekable = True
if not hasattr(file, "read"):
closeStream = True
# assume file is a string
@ -146,12 +147,20 @@ class TTFont(object):
else:
# assume "file" is a readable file object
closeStream = False
if file.seekable():
file.seek(0)
# SFNTReader wants the input file to be seekable.
# SpooledTemporaryFile has no seekable() on < 3.11, but still can seek:
# https://github.com/fonttools/fonttools/issues/3052
if hasattr(file, "seekable"):
seekable = file.seekable()
elif hasattr(file, "seek"):
try:
file.seek(0)
except UnsupportedOperation:
seekable = False
if not self.lazy:
# read input file in memory and wrap a stream around it to allow overwriting
if file.seekable():
if seekable:
file.seek(0)
tmp = BytesIO(file.read())
if hasattr(file, "name"):
@ -160,6 +169,8 @@ class TTFont(object):
if closeStream:
file.close()
file = tmp
elif not seekable:
raise TTLibError("Input file must be seekable when lazy=True")
self._tableCache = _tableCache
self.reader = SFNTReader(file, checkChecksums, fontNumber=fontNumber)
self.sfntVersion = self.reader.sfntVersion