_n_a_m_e.py revision 821572c9a92d338a7ecbb4261c08ce378eb5434d
132c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbodfrom __future__ import print_function, division 230e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom fontTools.misc.py23 import * 38413c108d21e8cf0e9059bbfffde8d13f2616340Behdad Esfahbodfrom fontTools.misc import sstruct 47842e56b97ce677b83bdab09cda48bc2d89ac75aJustfrom fontTools.misc.textTools import safeEval 530e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom . import DefaultTable 630e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodimport struct 77842e56b97ce677b83bdab09cda48bc2d89ac75aJust 87842e56b97ce677b83bdab09cda48bc2d89ac75aJustnameRecordFormat = """ 97842e56b97ce677b83bdab09cda48bc2d89ac75aJust > # big endian 107842e56b97ce677b83bdab09cda48bc2d89ac75aJust platformID: H 117842e56b97ce677b83bdab09cda48bc2d89ac75aJust platEncID: H 127842e56b97ce677b83bdab09cda48bc2d89ac75aJust langID: H 137842e56b97ce677b83bdab09cda48bc2d89ac75aJust nameID: H 147842e56b97ce677b83bdab09cda48bc2d89ac75aJust length: H 157842e56b97ce677b83bdab09cda48bc2d89ac75aJust offset: H 167842e56b97ce677b83bdab09cda48bc2d89ac75aJust""" 177842e56b97ce677b83bdab09cda48bc2d89ac75aJust 18aabca6d793a14e728260d08a75149343b56ff073jvrnameRecordSize = sstruct.calcsize(nameRecordFormat) 19aabca6d793a14e728260d08a75149343b56ff073jvr 20aabca6d793a14e728260d08a75149343b56ff073jvr 217842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass table__n_a_m_e(DefaultTable.DefaultTable): 227842e56b97ce677b83bdab09cda48bc2d89ac75aJust 237842e56b97ce677b83bdab09cda48bc2d89ac75aJust def decompile(self, data, ttFont): 24b71d0f46f65e5ac935c444ae3a6d6088a5f42e84jvr format, n, stringOffset = struct.unpack(">HHH", data[:6]) 25aabca6d793a14e728260d08a75149343b56ff073jvr expectedStringOffset = 6 + n * nameRecordSize 26b71d0f46f65e5ac935c444ae3a6d6088a5f42e84jvr if stringOffset != expectedStringOffset: 27aabca6d793a14e728260d08a75149343b56ff073jvr # XXX we need a warn function 283ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print("Warning: 'name' table stringOffset incorrect. Expected: %s; Actual: %s" % (expectedStringOffset, stringOffset)) 29b71d0f46f65e5ac935c444ae3a6d6088a5f42e84jvr stringData = data[stringOffset:] 30a87cde236e17d7a40ca3927edc6d188798917215jvr data = data[6:] 317842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.names = [] 327842e56b97ce677b83bdab09cda48bc2d89ac75aJust for i in range(n): 33980fae897a18cd1315879b9dcb8ec6ab28fbb5e9jvr if len(data) < 12: 34980fae897a18cd1315879b9dcb8ec6ab28fbb5e9jvr # compensate for buggy font 35980fae897a18cd1315879b9dcb8ec6ab28fbb5e9jvr break 367842e56b97ce677b83bdab09cda48bc2d89ac75aJust name, data = sstruct.unpack2(nameRecordFormat, data, NameRecord()) 377842e56b97ce677b83bdab09cda48bc2d89ac75aJust name.string = stringData[name.offset:name.offset+name.length] 387c0fb3173882dfc143b2446e7a8b86f973f969f0Just assert len(name.string) == name.length 397c0fb3173882dfc143b2446e7a8b86f973f969f0Just #if (name.platEncID, name.platformID) in ((0, 0), (1, 3)): 407c0fb3173882dfc143b2446e7a8b86f973f969f0Just # if len(name.string) % 2: 417c0fb3173882dfc143b2446e7a8b86f973f969f0Just # print "2-byte string doesn't have even length!" 427c0fb3173882dfc143b2446e7a8b86f973f969f0Just # print name.__dict__ 437842e56b97ce677b83bdab09cda48bc2d89ac75aJust del name.offset, name.length 447842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.names.append(name) 457842e56b97ce677b83bdab09cda48bc2d89ac75aJust 467842e56b97ce677b83bdab09cda48bc2d89ac75aJust def compile(self, ttFont): 473507eeb3d8e09172dffc3e9b91ac8b730d8162fdjvr if not hasattr(self, "names"): 483507eeb3d8e09172dffc3e9b91ac8b730d8162fdjvr # only happens when there are NO name table entries read 493507eeb3d8e09172dffc3e9b91ac8b730d8162fdjvr # from the TTX file 503507eeb3d8e09172dffc3e9b91ac8b730d8162fdjvr self.names = [] 51b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod self.names.sort() # sort according to the spec; see NameRecord.__lt__() 52821572c9a92d338a7ecbb4261c08ce378eb5434dBehdad Esfahbod stringData = b"" 537842e56b97ce677b83bdab09cda48bc2d89ac75aJust format = 0 547842e56b97ce677b83bdab09cda48bc2d89ac75aJust n = len(self.names) 55b71d0f46f65e5ac935c444ae3a6d6088a5f42e84jvr stringOffset = 6 + n * sstruct.calcsize(nameRecordFormat) 56b71d0f46f65e5ac935c444ae3a6d6088a5f42e84jvr data = struct.pack(">HHH", format, n, stringOffset) 577842e56b97ce677b83bdab09cda48bc2d89ac75aJust lastoffset = 0 587842e56b97ce677b83bdab09cda48bc2d89ac75aJust done = {} # remember the data so we can reuse the "pointers" 597842e56b97ce677b83bdab09cda48bc2d89ac75aJust for name in self.names: 60bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod if name.string in done: 617842e56b97ce677b83bdab09cda48bc2d89ac75aJust name.offset, name.length = done[name.string] 627842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 637842e56b97ce677b83bdab09cda48bc2d89ac75aJust name.offset, name.length = done[name.string] = len(stringData), len(name.string) 647842e56b97ce677b83bdab09cda48bc2d89ac75aJust stringData = stringData + name.string 657842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = data + sstruct.pack(nameRecordFormat, name) 667842e56b97ce677b83bdab09cda48bc2d89ac75aJust return data + stringData 677842e56b97ce677b83bdab09cda48bc2d89ac75aJust 687842e56b97ce677b83bdab09cda48bc2d89ac75aJust def toXML(self, writer, ttFont): 697842e56b97ce677b83bdab09cda48bc2d89ac75aJust for name in self.names: 707842e56b97ce677b83bdab09cda48bc2d89ac75aJust name.toXML(writer, ttFont) 717842e56b97ce677b83bdab09cda48bc2d89ac75aJust 723a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def fromXML(self, name, attrs, content, ttFont): 73180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod if name != "namerecord": 747842e56b97ce677b83bdab09cda48bc2d89ac75aJust return # ignore unknown tags 757842e56b97ce677b83bdab09cda48bc2d89ac75aJust if not hasattr(self, "names"): 767842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.names = [] 777842e56b97ce677b83bdab09cda48bc2d89ac75aJust name = NameRecord() 787842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.names.append(name) 793a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod name.fromXML(name, attrs, content, ttFont) 807842e56b97ce677b83bdab09cda48bc2d89ac75aJust 81d29f289911059d042cc8d0044e4dafc9a1125677Just def getName(self, nameID, platformID, platEncID, langID=None): 827842e56b97ce677b83bdab09cda48bc2d89ac75aJust for namerecord in self.names: 837842e56b97ce677b83bdab09cda48bc2d89ac75aJust if ( namerecord.nameID == nameID and 847842e56b97ce677b83bdab09cda48bc2d89ac75aJust namerecord.platformID == platformID and 857842e56b97ce677b83bdab09cda48bc2d89ac75aJust namerecord.platEncID == platEncID): 867842e56b97ce677b83bdab09cda48bc2d89ac75aJust if langID is None or namerecord.langID == langID: 877842e56b97ce677b83bdab09cda48bc2d89ac75aJust return namerecord 887842e56b97ce677b83bdab09cda48bc2d89ac75aJust return None # not found 897842e56b97ce677b83bdab09cda48bc2d89ac75aJust 907842e56b97ce677b83bdab09cda48bc2d89ac75aJust 917842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass NameRecord: 927842e56b97ce677b83bdab09cda48bc2d89ac75aJust 937842e56b97ce677b83bdab09cda48bc2d89ac75aJust def toXML(self, writer, ttFont): 947842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.begintag("namerecord", [ 957842e56b97ce677b83bdab09cda48bc2d89ac75aJust ("nameID", self.nameID), 967842e56b97ce677b83bdab09cda48bc2d89ac75aJust ("platformID", self.platformID), 977842e56b97ce677b83bdab09cda48bc2d89ac75aJust ("platEncID", self.platEncID), 987842e56b97ce677b83bdab09cda48bc2d89ac75aJust ("langID", hex(self.langID)), 997842e56b97ce677b83bdab09cda48bc2d89ac75aJust ]) 1007842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.newline() 101d29f289911059d042cc8d0044e4dafc9a1125677Just if self.platformID == 0 or (self.platformID == 3 and self.platEncID in (0, 1)): 1026d925f5b9a6e1b58765ee09fe8552b75f75241c3Just if len(self.string) % 2: 1036d925f5b9a6e1b58765ee09fe8552b75f75241c3Just # no, shouldn't happen, but some of the Apple 1046d925f5b9a6e1b58765ee09fe8552b75f75241c3Just # tools cause this anyway :-( 1056d925f5b9a6e1b58765ee09fe8552b75f75241c3Just writer.write16bit(self.string + "\0") 1066d925f5b9a6e1b58765ee09fe8552b75f75241c3Just else: 1076d925f5b9a6e1b58765ee09fe8552b75f75241c3Just writer.write16bit(self.string) 1087842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 1097842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.write8bit(self.string) 1107842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.newline() 1117842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.endtag("namerecord") 1127842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.newline() 1137842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1143a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def fromXML(self, name, attrs, content, ttFont): 1157842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.nameID = safeEval(attrs["nameID"]) 1167842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.platformID = safeEval(attrs["platformID"]) 1177842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.platEncID = safeEval(attrs["platEncID"]) 1187842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.langID = safeEval(attrs["langID"]) 1199005774c106a796473cae36edc1ca24413139e2fBehdad Esfahbod s = ''.join(content).decode("utf8").strip() 120b0e2817fad08e7867df1e66dc8c78c6f180060c3Just if self.platformID == 0 or (self.platformID == 3 and self.platEncID in (0, 1)): 121ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.string = s.encode("utf_16_be") 1227842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 1239005774c106a796473cae36edc1ca24413139e2fBehdad Esfahbod self.string = s.encode("latin1") 1247842e56b97ce677b83bdab09cda48bc2d89ac75aJust 125b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod def __lt__(self, other): 126b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod if type(self) != type(other): 127b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod raise TypeError("unordered types %s() < %s()", type(self), type(other)) 12896b321c8aea4dc64110d15a541c6f85152ae19cfBehdad Esfahbod 129b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod # implemented so that list.sort() sorts according to the spec. 130b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod selfTuple = ( 13194118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "platformID", None), 13294118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "platEncID", None), 13394118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "langID", None), 13494118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "nameID", None), 13594118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "string", None), 13694118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod ) 137b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod otherTuple = ( 13894118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "platformID", None), 13994118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "platEncID", None), 14094118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "langID", None), 14194118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "nameID", None), 14294118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "string", None), 14394118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod ) 144b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod return selfTuple < otherTuple 1457842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1467842e56b97ce677b83bdab09cda48bc2d89ac75aJust def __repr__(self): 1477842e56b97ce677b83bdab09cda48bc2d89ac75aJust return "<NameRecord NameID=%d; PlatformID=%d; LanguageID=%d>" % ( 1487842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.nameID, self.platformID, self.langID) 149