_n_a_m_e.py revision 180ace6a5ff1399ec53bc696e8bef7cce6eef39a
12b06aaa2a6bcd363c25fb0c43f6bb906906594bdBehdad Esfahbodfrom . import DefaultTable 28413c108d21e8cf0e9059bbfffde8d13f2616340Behdad Esfahbodimport struct 38413c108d21e8cf0e9059bbfffde8d13f2616340Behdad Esfahbodfrom fontTools.misc import sstruct 47842e56b97ce677b83bdab09cda48bc2d89ac75aJustfrom fontTools.misc.textTools import safeEval 57842e56b97ce677b83bdab09cda48bc2d89ac75aJustimport string 67842e56b97ce677b83bdab09cda48bc2d89ac75aJustimport types 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 28b71d0f46f65e5ac935c444ae3a6d6088a5f42e84jvr print "Warning: 'name' table stringOffset incorrect.", 29b71d0f46f65e5ac935c444ae3a6d6088a5f42e84jvr print "Expected: %s; Actual: %s" % (expectedStringOffset, stringOffset) 30b71d0f46f65e5ac935c444ae3a6d6088a5f42e84jvr stringData = data[stringOffset:] 31a87cde236e17d7a40ca3927edc6d188798917215jvr data = data[6:] 327842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.names = [] 337842e56b97ce677b83bdab09cda48bc2d89ac75aJust for i in range(n): 34980fae897a18cd1315879b9dcb8ec6ab28fbb5e9jvr if len(data) < 12: 35980fae897a18cd1315879b9dcb8ec6ab28fbb5e9jvr # compensate for buggy font 36980fae897a18cd1315879b9dcb8ec6ab28fbb5e9jvr break 377842e56b97ce677b83bdab09cda48bc2d89ac75aJust name, data = sstruct.unpack2(nameRecordFormat, data, NameRecord()) 387842e56b97ce677b83bdab09cda48bc2d89ac75aJust name.string = stringData[name.offset:name.offset+name.length] 397c0fb3173882dfc143b2446e7a8b86f973f969f0Just assert len(name.string) == name.length 407c0fb3173882dfc143b2446e7a8b86f973f969f0Just #if (name.platEncID, name.platformID) in ((0, 0), (1, 3)): 417c0fb3173882dfc143b2446e7a8b86f973f969f0Just # if len(name.string) % 2: 427c0fb3173882dfc143b2446e7a8b86f973f969f0Just # print "2-byte string doesn't have even length!" 437c0fb3173882dfc143b2446e7a8b86f973f969f0Just # print name.__dict__ 447842e56b97ce677b83bdab09cda48bc2d89ac75aJust del name.offset, name.length 457842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.names.append(name) 467842e56b97ce677b83bdab09cda48bc2d89ac75aJust 477842e56b97ce677b83bdab09cda48bc2d89ac75aJust def compile(self, ttFont): 483507eeb3d8e09172dffc3e9b91ac8b730d8162fdjvr if not hasattr(self, "names"): 493507eeb3d8e09172dffc3e9b91ac8b730d8162fdjvr # only happens when there are NO name table entries read 503507eeb3d8e09172dffc3e9b91ac8b730d8162fdjvr # from the TTX file 513507eeb3d8e09172dffc3e9b91ac8b730d8162fdjvr self.names = [] 527842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.names.sort() # sort according to the spec; see NameRecord.__cmp__() 537842e56b97ce677b83bdab09cda48bc2d89ac75aJust stringData = "" 547842e56b97ce677b83bdab09cda48bc2d89ac75aJust format = 0 557842e56b97ce677b83bdab09cda48bc2d89ac75aJust n = len(self.names) 56b71d0f46f65e5ac935c444ae3a6d6088a5f42e84jvr stringOffset = 6 + n * sstruct.calcsize(nameRecordFormat) 57b71d0f46f65e5ac935c444ae3a6d6088a5f42e84jvr data = struct.pack(">HHH", format, n, stringOffset) 587842e56b97ce677b83bdab09cda48bc2d89ac75aJust lastoffset = 0 597842e56b97ce677b83bdab09cda48bc2d89ac75aJust done = {} # remember the data so we can reuse the "pointers" 607842e56b97ce677b83bdab09cda48bc2d89ac75aJust for name in self.names: 61bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod if name.string in done: 627842e56b97ce677b83bdab09cda48bc2d89ac75aJust name.offset, name.length = done[name.string] 637842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 647842e56b97ce677b83bdab09cda48bc2d89ac75aJust name.offset, name.length = done[name.string] = len(stringData), len(name.string) 657842e56b97ce677b83bdab09cda48bc2d89ac75aJust stringData = stringData + name.string 667842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = data + sstruct.pack(nameRecordFormat, name) 677842e56b97ce677b83bdab09cda48bc2d89ac75aJust return data + stringData 687842e56b97ce677b83bdab09cda48bc2d89ac75aJust 697842e56b97ce677b83bdab09cda48bc2d89ac75aJust def toXML(self, writer, ttFont): 707842e56b97ce677b83bdab09cda48bc2d89ac75aJust for name in self.names: 717842e56b97ce677b83bdab09cda48bc2d89ac75aJust name.toXML(writer, ttFont) 727842e56b97ce677b83bdab09cda48bc2d89ac75aJust 737842e56b97ce677b83bdab09cda48bc2d89ac75aJust def fromXML(self, (name, attrs, content), ttFont): 74180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod if name != "namerecord": 757842e56b97ce677b83bdab09cda48bc2d89ac75aJust return # ignore unknown tags 767842e56b97ce677b83bdab09cda48bc2d89ac75aJust if not hasattr(self, "names"): 777842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.names = [] 787842e56b97ce677b83bdab09cda48bc2d89ac75aJust name = NameRecord() 797842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.names.append(name) 807842e56b97ce677b83bdab09cda48bc2d89ac75aJust name.fromXML((name, attrs, content), ttFont) 817842e56b97ce677b83bdab09cda48bc2d89ac75aJust 82d29f289911059d042cc8d0044e4dafc9a1125677Just def getName(self, nameID, platformID, platEncID, langID=None): 837842e56b97ce677b83bdab09cda48bc2d89ac75aJust for namerecord in self.names: 847842e56b97ce677b83bdab09cda48bc2d89ac75aJust if ( namerecord.nameID == nameID and 857842e56b97ce677b83bdab09cda48bc2d89ac75aJust namerecord.platformID == platformID and 867842e56b97ce677b83bdab09cda48bc2d89ac75aJust namerecord.platEncID == platEncID): 877842e56b97ce677b83bdab09cda48bc2d89ac75aJust if langID is None or namerecord.langID == langID: 887842e56b97ce677b83bdab09cda48bc2d89ac75aJust return namerecord 897842e56b97ce677b83bdab09cda48bc2d89ac75aJust return None # not found 907842e56b97ce677b83bdab09cda48bc2d89ac75aJust 917842e56b97ce677b83bdab09cda48bc2d89ac75aJust def __cmp__(self, other): 920ba7aa7ab5153e6a490425dd0f859cc5947360f4Behdad Esfahbod if type(self) != type(other): return cmp(type(self), type(other)) 930ba7aa7ab5153e6a490425dd0f859cc5947360f4Behdad Esfahbod if self.__class__ != other.__class__: return cmp(self.__class__, other.__class__) 9496b321c8aea4dc64110d15a541c6f85152ae19cfBehdad Esfahbod 957842e56b97ce677b83bdab09cda48bc2d89ac75aJust return cmp(self.names, other.names) 967842e56b97ce677b83bdab09cda48bc2d89ac75aJust 977842e56b97ce677b83bdab09cda48bc2d89ac75aJust 987842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass NameRecord: 997842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1007842e56b97ce677b83bdab09cda48bc2d89ac75aJust def toXML(self, writer, ttFont): 1017842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.begintag("namerecord", [ 1027842e56b97ce677b83bdab09cda48bc2d89ac75aJust ("nameID", self.nameID), 1037842e56b97ce677b83bdab09cda48bc2d89ac75aJust ("platformID", self.platformID), 1047842e56b97ce677b83bdab09cda48bc2d89ac75aJust ("platEncID", self.platEncID), 1057842e56b97ce677b83bdab09cda48bc2d89ac75aJust ("langID", hex(self.langID)), 1067842e56b97ce677b83bdab09cda48bc2d89ac75aJust ]) 1077842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.newline() 108d29f289911059d042cc8d0044e4dafc9a1125677Just if self.platformID == 0 or (self.platformID == 3 and self.platEncID in (0, 1)): 1096d925f5b9a6e1b58765ee09fe8552b75f75241c3Just if len(self.string) % 2: 1106d925f5b9a6e1b58765ee09fe8552b75f75241c3Just # no, shouldn't happen, but some of the Apple 1116d925f5b9a6e1b58765ee09fe8552b75f75241c3Just # tools cause this anyway :-( 1126d925f5b9a6e1b58765ee09fe8552b75f75241c3Just writer.write16bit(self.string + "\0") 1136d925f5b9a6e1b58765ee09fe8552b75f75241c3Just else: 1146d925f5b9a6e1b58765ee09fe8552b75f75241c3Just writer.write16bit(self.string) 1157842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 1167842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.write8bit(self.string) 1177842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.newline() 1187842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.endtag("namerecord") 1197842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.newline() 1207842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1217842e56b97ce677b83bdab09cda48bc2d89ac75aJust def fromXML(self, (name, attrs, content), ttFont): 1227842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.nameID = safeEval(attrs["nameID"]) 1237842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.platformID = safeEval(attrs["platformID"]) 1247842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.platEncID = safeEval(attrs["platEncID"]) 1257842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.langID = safeEval(attrs["langID"]) 126b0e2817fad08e7867df1e66dc8c78c6f180060c3Just if self.platformID == 0 or (self.platformID == 3 and self.platEncID in (0, 1)): 127ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr s = "" 1287842e56b97ce677b83bdab09cda48bc2d89ac75aJust for element in content: 129ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr s = s + element 130ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr s = unicode(s, "utf8") 131ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr s = s.strip() 132ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.string = s.encode("utf_16_be") 1337842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 134ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr s = string.strip(string.join(content, "")) 135ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr self.string = unicode(s, "utf8").encode("latin1") 1367842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1377842e56b97ce677b83bdab09cda48bc2d89ac75aJust def __cmp__(self, other): 1387842e56b97ce677b83bdab09cda48bc2d89ac75aJust """Compare method, so a list of NameRecords can be sorted 1397842e56b97ce677b83bdab09cda48bc2d89ac75aJust according to the spec by just sorting it...""" 14096b321c8aea4dc64110d15a541c6f85152ae19cfBehdad Esfahbod 1410ba7aa7ab5153e6a490425dd0f859cc5947360f4Behdad Esfahbod if type(self) != type(other): return cmp(type(self), type(other)) 14296b321c8aea4dc64110d15a541c6f85152ae19cfBehdad Esfahbod 14394118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod selftuple = ( 14494118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "platformID", None), 14594118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "platEncID", None), 14694118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "langID", None), 14794118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "nameID", None), 14894118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "string", None), 14994118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod ) 15094118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod othertuple = ( 15194118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "platformID", None), 15294118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "platEncID", None), 15394118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "langID", None), 15494118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "nameID", None), 15594118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "string", None), 15694118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod ) 1577842e56b97ce677b83bdab09cda48bc2d89ac75aJust return cmp(selftuple, othertuple) 1587842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1597842e56b97ce677b83bdab09cda48bc2d89ac75aJust def __repr__(self): 1607842e56b97ce677b83bdab09cda48bc2d89ac75aJust return "<NameRecord NameID=%d; PlatformID=%d; LanguageID=%d>" % ( 1617842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.nameID, self.platformID, self.langID) 162