11ae29591efbb29492ce05378909ccf4028d7c1eeBehdad Esfahbodfrom __future__ import print_function, division, absolute_import 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 9056da965344d25223d41e202aa7fd463dc6228752Behdad Esfahbod 91e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass NameRecord(object): 927842e56b97ce677b83bdab09cda48bc2d89ac75aJust 9377ccf45eb0c59830fb90830d6829108e59e93192Behdad Esfahbod def isUnicode(self): 9477ccf45eb0c59830fb90830d6829108e59e93192Behdad Esfahbod return (self.platformID == 0 or 9577ccf45eb0c59830fb90830d6829108e59e93192Behdad Esfahbod (self.platformID == 3 and self.platEncID in [0, 1, 10])) 9677ccf45eb0c59830fb90830d6829108e59e93192Behdad Esfahbod 977842e56b97ce677b83bdab09cda48bc2d89ac75aJust def toXML(self, writer, ttFont): 987842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.begintag("namerecord", [ 997842e56b97ce677b83bdab09cda48bc2d89ac75aJust ("nameID", self.nameID), 1007842e56b97ce677b83bdab09cda48bc2d89ac75aJust ("platformID", self.platformID), 1017842e56b97ce677b83bdab09cda48bc2d89ac75aJust ("platEncID", self.platEncID), 1027842e56b97ce677b83bdab09cda48bc2d89ac75aJust ("langID", hex(self.langID)), 1037842e56b97ce677b83bdab09cda48bc2d89ac75aJust ]) 1047842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.newline() 10577ccf45eb0c59830fb90830d6829108e59e93192Behdad Esfahbod if self.isUnicode(): 1066d925f5b9a6e1b58765ee09fe8552b75f75241c3Just if len(self.string) % 2: 1076d925f5b9a6e1b58765ee09fe8552b75f75241c3Just # no, shouldn't happen, but some of the Apple 1086d925f5b9a6e1b58765ee09fe8552b75f75241c3Just # tools cause this anyway :-( 1091edfe576563d4e260a958301eeeb956adc7d0610Behdad Esfahbod writer.write16bit(self.string + b"\0", strip=True) 110ca80208a1514ea4d7c55114ae1979f0ba6b41d16Behdad Esfahbod else: 1111edfe576563d4e260a958301eeeb956adc7d0610Behdad Esfahbod writer.write16bit(self.string, strip=True) 1127842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 1131edfe576563d4e260a958301eeeb956adc7d0610Behdad Esfahbod writer.write8bit(self.string, strip=True) 1147842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.newline() 1157842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.endtag("namerecord") 1167842e56b97ce677b83bdab09cda48bc2d89ac75aJust writer.newline() 1177842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1183a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def fromXML(self, name, attrs, content, ttFont): 1197842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.nameID = safeEval(attrs["nameID"]) 1207842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.platformID = safeEval(attrs["platformID"]) 1217842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.platEncID = safeEval(attrs["platEncID"]) 1227842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.langID = safeEval(attrs["langID"]) 1235f6418d9e1fa15a89dcec29cdc433ba2c99732c3Behdad Esfahbod s = strjoin(content).strip() 12477ccf45eb0c59830fb90830d6829108e59e93192Behdad Esfahbod if self.isUnicode(): 125ca80208a1514ea4d7c55114ae1979f0ba6b41d16Behdad Esfahbod self.string = s.encode("utf_16_be") 1267842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 1276962f0cfb2b7edfcfa1ff291e99fec756f06c6f8Behdad Esfahbod # This is the inverse of write8bit... 1289005774c106a796473cae36edc1ca24413139e2fBehdad Esfahbod self.string = s.encode("latin1") 1297842e56b97ce677b83bdab09cda48bc2d89ac75aJust 130b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod def __lt__(self, other): 131b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod if type(self) != type(other): 132273a90074ac209d67b5e2cb8ea510cd6c2b10272Behdad Esfahbod return NotImplemented 13396b321c8aea4dc64110d15a541c6f85152ae19cfBehdad Esfahbod 134b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod # implemented so that list.sort() sorts according to the spec. 135b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod selfTuple = ( 13694118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "platformID", None), 13794118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "platEncID", None), 13894118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "langID", None), 13994118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "nameID", None), 14094118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(self, "string", None), 14194118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod ) 142b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod otherTuple = ( 14394118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "platformID", None), 14494118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "platEncID", None), 14594118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "langID", None), 14694118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "nameID", None), 14794118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod getattr(other, "string", None), 14894118dcea43bbc618b35774d9c9913738fa5e97aBehdad Esfahbod ) 149b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod return selfTuple < otherTuple 1507842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1517842e56b97ce677b83bdab09cda48bc2d89ac75aJust def __repr__(self): 1527842e56b97ce677b83bdab09cda48bc2d89ac75aJust return "<NameRecord NameID=%d; PlatformID=%d; LanguageID=%d>" % ( 1537842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.nameID, self.platformID, self.langID) 154