3
from fontTools.misc.textTools import safeEval
17
nameRecordSize = sstruct.calcsize(nameRecordFormat)
20
class table__n_a_m_e(DefaultTable.DefaultTable):
22
def decompile(self, data, ttFont):
23
format, n, stringOffset = struct.unpack(">HHH", data[:6])
24
expectedStringOffset = 6 + n * nameRecordSize
25
if stringOffset != expectedStringOffset:
26
# XXX we need a warn function
27
print "Warning: 'name' table stringOffset incorrect.",
28
print "Expected: %s; Actual: %s" % (expectedStringOffset, stringOffset)
29
stringData = data[stringOffset:]
33
name, data = sstruct.unpack2(nameRecordFormat, data, NameRecord())
34
name.string = stringData[name.offset:name.offset+name.length]
35
assert len(name.string) == name.length
36
#if (name.platEncID, name.platformID) in ((0, 0), (1, 3)):
37
# if len(name.string) % 2:
38
# print "2-byte string doesn't have even length!"
40
del name.offset, name.length
41
self.names.append(name)
43
def compile(self, ttFont):
44
if not hasattr(self, "names"):
45
# only happens when there are NO name table entries read
48
self.names.sort() # sort according to the spec; see NameRecord.__cmp__()
52
stringOffset = 6 + n * sstruct.calcsize(nameRecordFormat)
53
data = struct.pack(">HHH", format, n, stringOffset)
55
done = {} # remember the data so we can reuse the "pointers"
56
for name in self.names:
57
if done.has_key(name.string):
58
name.offset, name.length = done[name.string]
60
name.offset, name.length = done[name.string] = len(stringData), len(name.string)
61
stringData = stringData + name.string
62
data = data + sstruct.pack(nameRecordFormat, name)
63
return data + stringData
65
def toXML(self, writer, ttFont):
66
for name in self.names:
67
name.toXML(writer, ttFont)
69
def fromXML(self, (name, attrs, content), ttFont):
70
if name <> "namerecord":
71
return # ignore unknown tags
72
if not hasattr(self, "names"):
75
self.names.append(name)
76
name.fromXML((name, attrs, content), ttFont)
78
def getName(self, nameID, platformID, platEncID, langID=None):
79
for namerecord in self.names:
80
if ( namerecord.nameID == nameID and
81
namerecord.platformID == platformID and
82
namerecord.platEncID == platEncID):
83
if langID is None or namerecord.langID == langID:
85
return None # not found
87
def __cmp__(self, other):
88
return cmp(self.names, other.names)
93
def toXML(self, writer, ttFont):
94
writer.begintag("namerecord", [
95
("nameID", self.nameID),
96
("platformID", self.platformID),
97
("platEncID", self.platEncID),
98
("langID", hex(self.langID)),
101
if self.platformID == 0 or (self.platformID == 3 and self.platEncID in (0, 1)):
102
if len(self.string) % 2:
103
# no, shouldn't happen, but some of the Apple
104
# tools cause this anyway :-(
105
writer.write16bit(self.string + "\0")
107
writer.write16bit(self.string)
109
writer.write8bit(self.string)
111
writer.endtag("namerecord")
114
def fromXML(self, (name, attrs, content), ttFont):
115
self.nameID = safeEval(attrs["nameID"])
116
self.platformID = safeEval(attrs["platformID"])
117
self.platEncID = safeEval(attrs["platEncID"])
118
self.langID = safeEval(attrs["langID"])
119
if self.platformID == 0 or (self.platformID == 3 and self.platEncID in (0, 1)):
121
for element in content:
123
s = unicode(s, "utf8")
125
self.string = s.encode("utf_16_be")
127
s = string.strip(string.join(content, ""))
128
self.string = unicode(s, "utf8").encode("latin1")
130
def __cmp__(self, other):
131
"""Compare method, so a list of NameRecords can be sorted
132
according to the spec by just sorting it..."""
133
selftuple = (self.platformID,
138
othertuple = (other.platformID,
143
return cmp(selftuple, othertuple)
146
return "<NameRecord NameID=%d; PlatformID=%d; LanguageID=%d>" % (
147
self.nameID, self.platformID, self.langID)