1from fontTools.misc.py23 import bytesjoin, strjoin 2from fontTools.misc import sstruct 3from fontTools.misc.textTools import readHex 4from fontTools.ttLib import TTLibError 5from . import DefaultTable 6 7# Apple's documentation of 'meta': 8# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6meta.html 9 10META_HEADER_FORMAT = """ 11 > # big endian 12 version: L 13 flags: L 14 dataOffset: L 15 numDataMaps: L 16""" 17 18 19DATA_MAP_FORMAT = """ 20 > # big endian 21 tag: 4s 22 dataOffset: L 23 dataLength: L 24""" 25 26 27class table__m_e_t_a(DefaultTable.DefaultTable): 28 def __init__(self, tag=None): 29 DefaultTable.DefaultTable.__init__(self, tag) 30 self.data = {} 31 32 def decompile(self, data, ttFont): 33 headerSize = sstruct.calcsize(META_HEADER_FORMAT) 34 header = sstruct.unpack(META_HEADER_FORMAT, data[0 : headerSize]) 35 if header["version"] != 1: 36 raise TTLibError("unsupported 'meta' version %d" % 37 header["version"]) 38 dataMapSize = sstruct.calcsize(DATA_MAP_FORMAT) 39 for i in range(header["numDataMaps"]): 40 dataMapOffset = headerSize + i * dataMapSize 41 dataMap = sstruct.unpack( 42 DATA_MAP_FORMAT, 43 data[dataMapOffset : dataMapOffset + dataMapSize]) 44 tag = dataMap["tag"] 45 offset = dataMap["dataOffset"] 46 self.data[tag] = data[offset : offset + dataMap["dataLength"]] 47 if tag in ["dlng", "slng"]: 48 self.data[tag] = self.data[tag].decode("utf-8") 49 50 def compile(self, ttFont): 51 keys = sorted(self.data.keys()) 52 headerSize = sstruct.calcsize(META_HEADER_FORMAT) 53 dataOffset = headerSize + len(keys) * sstruct.calcsize(DATA_MAP_FORMAT) 54 header = sstruct.pack(META_HEADER_FORMAT, { 55 "version": 1, 56 "flags": 0, 57 "dataOffset": dataOffset, 58 "numDataMaps": len(keys) 59 }) 60 dataMaps = [] 61 dataBlocks = [] 62 for tag in keys: 63 if tag in ["dlng", "slng"]: 64 data = self.data[tag].encode("utf-8") 65 else: 66 data = self.data[tag] 67 dataMaps.append(sstruct.pack(DATA_MAP_FORMAT, { 68 "tag": tag, 69 "dataOffset": dataOffset, 70 "dataLength": len(data) 71 })) 72 dataBlocks.append(data) 73 dataOffset += len(data) 74 return bytesjoin([header] + dataMaps + dataBlocks) 75 76 def toXML(self, writer, ttFont): 77 for tag in sorted(self.data.keys()): 78 if tag in ["dlng", "slng"]: 79 writer.begintag("text", tag=tag) 80 writer.newline() 81 writer.write(self.data[tag]) 82 writer.newline() 83 writer.endtag("text") 84 writer.newline() 85 else: 86 writer.begintag("hexdata", tag=tag) 87 writer.newline() 88 data = self.data[tag] 89 if min(data) >= 0x20 and max(data) <= 0x7E: 90 writer.comment("ascii: " + data.decode("ascii")) 91 writer.newline() 92 writer.dumphex(data) 93 writer.endtag("hexdata") 94 writer.newline() 95 96 def fromXML(self, name, attrs, content, ttFont): 97 if name == "hexdata": 98 self.data[attrs["tag"]] = readHex(content) 99 elif name == "text" and attrs["tag"] in ["dlng", "slng"]: 100 self.data[attrs["tag"]] = strjoin(content).strip() 101 else: 102 raise TTLibError("can't handle '%s' element" % name) 103