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 dependencies = [] 24 25 def decompile(self, data, ttFont): 26 dummy, rest = sstruct.unpack2(SINGFormat, data, self) 27 self.uniqueName = self.decompileUniqueName(self.uniqueName) 28 self.nameLength = byteord(self.nameLength) 29 assert len(rest) == self.nameLength 30 self.baseGlyphName = tostr(rest) 31 32 rawMETAMD5 = self.METAMD5 33 self.METAMD5 = "[" + hex(byteord(self.METAMD5[0])) 34 for char in rawMETAMD5[1:]: 35 self.METAMD5 = self.METAMD5 + ", " + hex(byteord(char)) 36 self.METAMD5 = self.METAMD5 + "]" 37 38 def decompileUniqueName(self, data): 39 name = "" 40 for char in data: 41 val = byteord(char) 42 if val == 0: 43 break 44 if (val > 31) or (val < 128): 45 name += chr(val) 46 else: 47 octString = oct(val) 48 if len(octString) > 3: 49 octString = octString[1:] # chop off that leading zero. 50 elif len(octString) < 3: 51 octString.zfill(3) 52 name += "\\" + octString 53 return name 54 55 def compile(self, ttFont): 56 d = self.__dict__.copy() 57 d["nameLength"] = bytechr(len(self.baseGlyphName)) 58 d["uniqueName"] = self.compilecompileUniqueName(self.uniqueName, 28) 59 METAMD5List = eval(self.METAMD5) 60 d["METAMD5"] = b"" 61 for val in METAMD5List: 62 d["METAMD5"] += bytechr(val) 63 assert len(d["METAMD5"]) == 16, "Failed to pack 16 byte MD5 hash in SING table" 64 data = sstruct.pack(SINGFormat, d) 65 data = data + tobytes(self.baseGlyphName) 66 return data 67 68 def compilecompileUniqueName(self, name, length): 69 nameLen = len(name) 70 if length <= nameLen: 71 name = name[: length - 1] + "\000" 72 else: 73 name += (nameLen - length) * "\000" 74 return name 75 76 def toXML(self, writer, ttFont): 77 writer.comment("Most of this table will be recalculated by the compiler") 78 writer.newline() 79 formatstring, names, fixes = sstruct.getformat(SINGFormat) 80 for name in names: 81 value = getattr(self, name) 82 writer.simpletag(name, value=value) 83 writer.newline() 84 writer.simpletag("baseGlyphName", value=self.baseGlyphName) 85 writer.newline() 86 87 def fromXML(self, name, attrs, content, ttFont): 88 value = attrs["value"] 89 if name in ["uniqueName", "METAMD5", "baseGlyphName"]: 90 setattr(self, name, value) 91 else: 92 setattr(self, name, safeEval(value)) 93