Behdad Esfahbod 8413c108d2 Move sstruct under fontTools.misc
Our footprint in the Python module namespace is all under
fontTools now.  User code importing sstruct should be updated
to say "from fontTools.misc import sstruct".
2013-09-17 16:59:39 -04:00

157 lines
4.3 KiB
Python

import DefaultTable
from fontTools.misc import sstruct
import time
import string
from fontTools.misc.textTools import safeEval, num2binary, binary2num
headFormat = """
> # big endian
tableVersion: 16.16F
fontRevision: 16.16F
checkSumAdjustment: I
magicNumber: I
flags: H
unitsPerEm: H
created: 8s
modified: 8s
xMin: h
yMin: h
xMax: h
yMax: h
macStyle: H
lowestRecPPEM: H
fontDirectionHint: h
indexToLocFormat: h
glyphDataFormat: h
"""
class table__h_e_a_d(DefaultTable.DefaultTable):
dependencies = ['maxp', 'loca']
def decompile(self, data, ttFont):
dummy, rest = sstruct.unpack2(headFormat, data, self)
if rest:
# this is quite illegal, but there seem to be fonts out there that do this
assert rest == "\0\0"
self.unitsPerEm = int(self.unitsPerEm)
self.flags = int(self.flags)
self.strings2dates()
def compile(self, ttFont):
self.modified = long(time.time() - mac_epoch_diff)
self.dates2strings()
data = sstruct.pack(headFormat, self)
self.strings2dates()
return data
def strings2dates(self):
self.created = bin2long(self.created)
self.modified = bin2long(self.modified)
def dates2strings(self):
self.created = long2bin(self.created)
self.modified = long2bin(self.modified)
def toXML(self, writer, ttFont):
writer.comment("Most of this table will be recalculated by the compiler")
writer.newline()
formatstring, names, fixes = sstruct.getformat(headFormat)
for name in names:
value = getattr(self, name)
if name in ("created", "modified"):
try:
value = time.asctime(time.gmtime(max(0, value + mac_epoch_diff)))
except ValueError:
value = time.asctime(time.gmtime(0))
if name in ("magicNumber", "checkSumAdjustment"):
if value < 0:
value = value + 0x100000000L
value = hex(value)
if value[-1:] == "L":
value = value[:-1]
elif name in ("macStyle", "flags"):
value = num2binary(value, 16)
writer.simpletag(name, value=value)
writer.newline()
def fromXML(self, (name, attrs, content), ttFont):
value = attrs["value"]
if name in ("created", "modified"):
value = parse_date(value) - mac_epoch_diff
elif name in ("macStyle", "flags"):
value = binary2num(value)
else:
try:
value = safeEval(value)
except OverflowError:
value = long(value)
setattr(self, name, value)
def __cmp__(self, other):
if type(self) != type(other) or \
self.__class__ != other.__class__:
return cmp(id(self), id(other))
selfdict = self.__dict__.copy()
otherdict = other.__dict__.copy()
# for testing purposes, compare without the modified and checkSumAdjustment
# fields, since they are allowed to be different.
for key in ["modified", "checkSumAdjustment"]:
del selfdict[key]
del otherdict[key]
return cmp(selfdict, otherdict)
def calc_mac_epoch_diff():
"""calculate the difference between the original Mac epoch (1904)
to the epoch on this machine.
"""
safe_epoch_t = (1972, 1, 1, 0, 0, 0, 0, 0, 0)
safe_epoch = time.mktime(safe_epoch_t) - time.timezone
# This assert fails in certain time zones, with certain daylight settings
#assert time.gmtime(safe_epoch)[:6] == safe_epoch_t[:6]
seconds1904to1972 = 60 * 60 * 24 * (365 * (1972-1904) + 17) # thanks, Laurence!
return long(safe_epoch - seconds1904to1972)
mac_epoch_diff = calc_mac_epoch_diff()
_months = [' ', 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug',
'sep', 'oct', 'nov', 'dec']
_weekdays = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
def parse_date(datestring):
datestring = string.lower(datestring)
weekday, month, day, tim, year = string.split(datestring)
weekday = _weekdays.index(weekday)
month = _months.index(month)
year = int(year)
day = int(day)
hour, minute, second = map(int, string.split(tim, ":"))
t = (year, month, day, hour, minute, second, weekday, 0, 0)
try:
return long(time.mktime(t) - time.timezone)
except OverflowError:
return 0L
def bin2long(data):
# thanks </F>!
v = 0L
for i in map(ord, data):
v = v<<8 | i
return v
def long2bin(v, bytes=8):
mask = long("FF" * bytes, 16)
data = ""
while v:
data = chr(v & 0xff) + data
v = (v >> 8) & mask
data = (bytes - len(data)) * "\0" + data
assert len(data) == 8, "long too long"
return data