1from fontTools.misc import sstruct 2from fontTools.misc.textTools import bytechr, byteord, tobytes, tostr, safeEval 3from . import DefaultTable 4 5SINGFormat = """ 6 > # big endian 7 tableVersionMajor: H 8 tableVersionMinor: H 9 glyphletVersion: H 10 permissions: h 11 mainGID: H 12 unitsPerEm: H 13 vertAdvance: h 14 vertOrigin: h 15 uniqueName: 28s 16 METAMD5: 16s 17 nameLength: 1s 18""" 19# baseGlyphName is a byte string which follows the record above. 20 21 22class table_S_I_N_G_(DefaultTable.DefaultTable): 23 24 dependencies = [] 25 26 def decompile(self, data, ttFont): 27 dummy, rest = sstruct.unpack2(SINGFormat, data, self) 28 self.uniqueName = self.decompileUniqueName(self.uniqueName) 29 self.nameLength = byteord(self.nameLength) 30 assert len(rest) == self.nameLength 31 self.baseGlyphName = tostr(rest) 32 33 rawMETAMD5 = self.METAMD5 34 self.METAMD5 = "[" + hex(byteord(self.METAMD5[0])) 35 for char in rawMETAMD5[1:]: 36 self.METAMD5 = self.METAMD5 + ", " + hex(byteord(char)) 37 self.METAMD5 = self.METAMD5 + "]" 38 39 def decompileUniqueName(self, data): 40 name = "" 41 for char in data: 42 val = byteord(char) 43 if val == 0: 44 break 45 if (val > 31) or (val < 128): 46 name += chr(val) 47 else: 48 octString = oct(val) 49 if len(octString) > 3: 50 octString = octString[1:] # chop off that leading zero. 51 elif len(octString) < 3: 52 octString.zfill(3) 53 name += "\\" + octString 54 return name 55 56 def compile(self, ttFont): 57 d = self.__dict__.copy() 58 d["nameLength"] = bytechr(len(self.baseGlyphName)) 59 d["uniqueName"] = self.compilecompileUniqueName(self.uniqueName, 28) 60 METAMD5List = eval(self.METAMD5) 61 d["METAMD5"] = b"" 62 for val in METAMD5List: 63 d["METAMD5"] += bytechr(val) 64 assert (len(d["METAMD5"]) == 16), "Failed to pack 16 byte MD5 hash in SING table" 65 data = sstruct.pack(SINGFormat, d) 66 data = data + tobytes(self.baseGlyphName) 67 return data 68 69 def compilecompileUniqueName(self, name, length): 70 nameLen = len(name) 71 if length <= nameLen: 72 name = name[:length-1] + "\000" 73 else: 74 name += (nameLen - length) * "\000" 75 return name 76 77 def toXML(self, writer, ttFont): 78 writer.comment("Most of this table will be recalculated by the compiler") 79 writer.newline() 80 formatstring, names, fixes = sstruct.getformat(SINGFormat) 81 for name in names: 82 value = getattr(self, name) 83 writer.simpletag(name, value=value) 84 writer.newline() 85 writer.simpletag("baseGlyphName", value=self.baseGlyphName) 86 writer.newline() 87 88 def fromXML(self, name, attrs, content, ttFont): 89 value = attrs["value"] 90 if name in ["uniqueName", "METAMD5", "baseGlyphName"]: 91 setattr(self, name, value) 92 else: 93 setattr(self, name, safeEval(value)) 94