• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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