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".
136 lines
3.7 KiB
Python
136 lines
3.7 KiB
Python
import sys
|
|
import DefaultTable
|
|
from fontTools.misc import sstruct
|
|
import array
|
|
from types import StringType
|
|
from fontTools.misc.textTools import safeEval, readHex
|
|
from fontTools import ttLib
|
|
|
|
GPKGFormat = """
|
|
> # big endian
|
|
version: H
|
|
flags: H
|
|
numGMAPs: H
|
|
numGlyplets: H
|
|
"""
|
|
# psFontName is a byte string which follows the record above. This is zero padded
|
|
# to the beginning of the records array. The recordsOffsst is 32 bit aligned.
|
|
|
|
|
|
class table_G_P_K_G_(DefaultTable.DefaultTable):
|
|
|
|
def decompile(self, data, ttFont):
|
|
dummy, newData = sstruct.unpack2(GPKGFormat, data, self)
|
|
|
|
GMAPoffsets = array.array("I")
|
|
endPos = (self.numGMAPs+1) * 4
|
|
GMAPoffsets.fromstring(newData[:endPos])
|
|
if sys.byteorder <> "big":
|
|
GMAPoffsets.byteswap()
|
|
self.GMAPs = []
|
|
for i in range(self.numGMAPs):
|
|
start = GMAPoffsets[i]
|
|
end = GMAPoffsets[i+1]
|
|
self.GMAPs.append(data[start:end])
|
|
pos = endPos
|
|
endPos = pos + (self.numGlyplets + 1)*4
|
|
glyphletOffsets = array.array("I")
|
|
glyphletOffsets.fromstring(newData[pos:endPos])
|
|
if sys.byteorder <> "big":
|
|
glyphletOffsets.byteswap()
|
|
self.glyphlets = []
|
|
for i in range(self.numGlyplets):
|
|
start = glyphletOffsets[i]
|
|
end = glyphletOffsets[i+1]
|
|
self.glyphlets.append(data[start:end])
|
|
|
|
|
|
def compile(self, ttFont):
|
|
self.numGMAPs = len(self.GMAPs)
|
|
self.numGlyplets = len(self.glyphlets)
|
|
GMAPoffsets = [0]*(self.numGMAPs + 1)
|
|
glyphletOffsets = [0]*(self.numGlyplets + 1)
|
|
|
|
dataList =[ sstruct.pack(GPKGFormat, self)]
|
|
|
|
pos = len(dataList[0]) + (self.numGMAPs + 1)*4 + (self.numGlyplets + 1)*4
|
|
GMAPoffsets[0] = pos
|
|
for i in range(1, self.numGMAPs +1):
|
|
pos += len(self.GMAPs[i-1])
|
|
GMAPoffsets[i] = pos
|
|
gmapArray = array.array("I", GMAPoffsets)
|
|
if sys.byteorder <> "big":
|
|
gmapArray.byteswap()
|
|
dataList.append(gmapArray.tostring())
|
|
|
|
glyphletOffsets[0] = pos
|
|
for i in range(1, self.numGlyplets +1):
|
|
pos += len(self.glyphlets[i-1])
|
|
glyphletOffsets[i] = pos
|
|
glyphletArray = array.array("I", glyphletOffsets)
|
|
if sys.byteorder <> "big":
|
|
glyphletArray.byteswap()
|
|
dataList.append(glyphletArray.tostring())
|
|
dataList += self.GMAPs
|
|
dataList += self.glyphlets
|
|
data = "".join(dataList)
|
|
return data
|
|
|
|
def toXML(self, writer, ttFont):
|
|
writer.comment("Most of this table will be recalculated by the compiler")
|
|
writer.newline()
|
|
formatstring, names, fixes = sstruct.getformat(GPKGFormat)
|
|
for name in names:
|
|
value = getattr(self, name)
|
|
writer.simpletag(name, value=value)
|
|
writer.newline()
|
|
|
|
writer.begintag("GMAPs")
|
|
writer.newline()
|
|
for gmapData in self.GMAPs:
|
|
writer.begintag("hexdata")
|
|
writer.newline()
|
|
writer.dumphex(gmapData)
|
|
writer.endtag("hexdata")
|
|
writer.newline()
|
|
writer.endtag("GMAPs")
|
|
writer.newline()
|
|
|
|
writer.begintag("glyphlets")
|
|
writer.newline()
|
|
for glyphletData in self.glyphlets:
|
|
writer.begintag("hexdata")
|
|
writer.newline()
|
|
writer.dumphex(glyphletData)
|
|
writer.endtag("hexdata")
|
|
writer.newline()
|
|
writer.endtag("glyphlets")
|
|
writer.newline()
|
|
|
|
def fromXML(self, (name, attrs, content), ttFont):
|
|
if name == "GMAPs":
|
|
if not hasattr(self, "GMAPs"):
|
|
self.GMAPs = []
|
|
for element in content:
|
|
if isinstance(element, StringType):
|
|
continue
|
|
itemName, itemAttrs, itemContent = element
|
|
if itemName == "hexdata":
|
|
self.GMAPs.append(readHex(itemContent))
|
|
elif name == "glyphlets":
|
|
if not hasattr(self, "glyphlets"):
|
|
self.glyphlets = []
|
|
for element in content:
|
|
if isinstance(element, StringType):
|
|
continue
|
|
itemName, itemAttrs, itemContent = element
|
|
if itemName == "hexdata":
|
|
self.glyphlets.append(readHex(itemContent))
|
|
else:
|
|
value = attrs["value"]
|
|
try:
|
|
value = safeEval(value)
|
|
except OverflowError:
|
|
value = long(value)
|
|
setattr(self, name, value)
|