11ae29591efbb29492ce05378909ccf4028d7c1eeBehdad Esfahbodfrom __future__ import print_function, division, absolute_import
230e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom fontTools.misc.py23 import *
37842e56b97ce677b83bdab09cda48bc2d89ac75aJustfrom fontTools import ttLib
47ed91eca1eaa96b79eae780778e89bb9ec44c1eeBehdad Esfahbodfrom fontTools.ttLib.standardGlyphOrder import standardGlyphOrder
57ed91eca1eaa96b79eae780778e89bb9ec44c1eeBehdad Esfahbodfrom fontTools.misc import sstruct
67842e56b97ce677b83bdab09cda48bc2d89ac75aJustfrom fontTools.misc.textTools import safeEval, readHex
730e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom . import DefaultTable
830e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodimport sys
930e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodimport struct
1030e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodimport array
117842e56b97ce677b83bdab09cda48bc2d89ac75aJust
127842e56b97ce677b83bdab09cda48bc2d89ac75aJust
137842e56b97ce677b83bdab09cda48bc2d89ac75aJustpostFormat = """
147842e56b97ce677b83bdab09cda48bc2d89ac75aJust	>
157842e56b97ce677b83bdab09cda48bc2d89ac75aJust	formatType:			16.16F
167842e56b97ce677b83bdab09cda48bc2d89ac75aJust	italicAngle:		16.16F		# italic angle in degrees
177842e56b97ce677b83bdab09cda48bc2d89ac75aJust	underlinePosition:	h
187842e56b97ce677b83bdab09cda48bc2d89ac75aJust	underlineThickness:	h
1904985bfdded4d445c67524b018965df1f4a4c313fcoiffie	isFixedPitch:		L
2004985bfdded4d445c67524b018965df1f4a4c313fcoiffie	minMemType42:		L			# minimum memory if TrueType font is downloaded
2104985bfdded4d445c67524b018965df1f4a4c313fcoiffie	maxMemType42:		L			# maximum memory if TrueType font is downloaded
2204985bfdded4d445c67524b018965df1f4a4c313fcoiffie	minMemType1:		L			# minimum memory if Type1 font is downloaded
2304985bfdded4d445c67524b018965df1f4a4c313fcoiffie	maxMemType1:		L			# maximum memory if Type1 font is downloaded
247842e56b97ce677b83bdab09cda48bc2d89ac75aJust"""
257842e56b97ce677b83bdab09cda48bc2d89ac75aJust
267842e56b97ce677b83bdab09cda48bc2d89ac75aJustpostFormatSize = sstruct.calcsize(postFormat)
277842e56b97ce677b83bdab09cda48bc2d89ac75aJust
287842e56b97ce677b83bdab09cda48bc2d89ac75aJust
297842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass table__p_o_s_t(DefaultTable.DefaultTable):
307842e56b97ce677b83bdab09cda48bc2d89ac75aJust
317842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decompile(self, data, ttFont):
327842e56b97ce677b83bdab09cda48bc2d89ac75aJust		sstruct.unpack(postFormat, data[:postFormatSize], self)
337842e56b97ce677b83bdab09cda48bc2d89ac75aJust		data = data[postFormatSize:]
347842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if self.formatType == 1.0:
357842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.decode_format_1_0(data, ttFont)
367842e56b97ce677b83bdab09cda48bc2d89ac75aJust		elif self.formatType == 2.0:
377842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.decode_format_2_0(data, ttFont)
387842e56b97ce677b83bdab09cda48bc2d89ac75aJust		elif self.formatType == 3.0:
397842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.decode_format_3_0(data, ttFont)
404a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		elif self.formatType == 4.0:
414a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten			self.decode_format_4_0(data, ttFont)
427842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
437842e56b97ce677b83bdab09cda48bc2d89ac75aJust			# supported format
44cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod			raise ttLib.TTLibError("'post' table format %f not supported" % self.formatType)
457842e56b97ce677b83bdab09cda48bc2d89ac75aJust
467842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def compile(self, ttFont):
477842e56b97ce677b83bdab09cda48bc2d89ac75aJust		data = sstruct.pack(postFormat, self)
487842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if self.formatType == 1.0:
497842e56b97ce677b83bdab09cda48bc2d89ac75aJust			pass # we're done
507842e56b97ce677b83bdab09cda48bc2d89ac75aJust		elif self.formatType == 2.0:
517842e56b97ce677b83bdab09cda48bc2d89ac75aJust			data = data + self.encode_format_2_0(ttFont)
527842e56b97ce677b83bdab09cda48bc2d89ac75aJust		elif self.formatType == 3.0:
537842e56b97ce677b83bdab09cda48bc2d89ac75aJust			pass # we're done
544a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		elif self.formatType == 4.0:
554a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten			data = data + self.encode_format_4_0(ttFont)
567842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
577842e56b97ce677b83bdab09cda48bc2d89ac75aJust			# supported format
58cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod			raise ttLib.TTLibError("'post' table format %f not supported" % self.formatType)
597842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return data
607842e56b97ce677b83bdab09cda48bc2d89ac75aJust
617842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def getGlyphOrder(self):
627842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"""This function will get called by a ttLib.TTFont instance.
637842e56b97ce677b83bdab09cda48bc2d89ac75aJust		Do not call this function yourself, use TTFont().getGlyphOrder()
647842e56b97ce677b83bdab09cda48bc2d89ac75aJust		or its relatives instead!
657842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"""
667842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if not hasattr(self, "glyphOrder"):
67cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod			raise ttLib.TTLibError("illegal use of getGlyphOrder()")
687842e56b97ce677b83bdab09cda48bc2d89ac75aJust		glyphOrder = self.glyphOrder
697842e56b97ce677b83bdab09cda48bc2d89ac75aJust		del self.glyphOrder
707842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return glyphOrder
717842e56b97ce677b83bdab09cda48bc2d89ac75aJust
727842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decode_format_1_0(self, data, ttFont):
73c2b05ccf8ce7b8ae80e06b667152398ebd4c4872jvr		self.glyphOrder = standardGlyphOrder[:ttFont["maxp"].numGlyphs]
747842e56b97ce677b83bdab09cda48bc2d89ac75aJust
757842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decode_format_2_0(self, data, ttFont):
767842e56b97ce677b83bdab09cda48bc2d89ac75aJust		numGlyphs, = struct.unpack(">H", data[:2])
777842e56b97ce677b83bdab09cda48bc2d89ac75aJust		numGlyphs = int(numGlyphs)
78f9104bcc2cd61bf029ac6736ef0ee98968bde472jvr		if numGlyphs > ttFont['maxp'].numGlyphs:
79f9104bcc2cd61bf029ac6736ef0ee98968bde472jvr			# Assume the numGlyphs field is bogus, so sync with maxp.
80f9104bcc2cd61bf029ac6736ef0ee98968bde472jvr			# I've seen this in one font, and if the assumption is
81f9104bcc2cd61bf029ac6736ef0ee98968bde472jvr			# wrong elsewhere, well, so be it: it's hard enough to
82f9104bcc2cd61bf029ac6736ef0ee98968bde472jvr			# work around _one_ non-conforming post format...
83f9104bcc2cd61bf029ac6736ef0ee98968bde472jvr			numGlyphs = ttFont['maxp'].numGlyphs
847842e56b97ce677b83bdab09cda48bc2d89ac75aJust		data = data[2:]
857842e56b97ce677b83bdab09cda48bc2d89ac75aJust		indices = array.array("H")
867842e56b97ce677b83bdab09cda48bc2d89ac75aJust		indices.fromstring(data[:2*numGlyphs])
87180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod		if sys.byteorder != "big":
887842e56b97ce677b83bdab09cda48bc2d89ac75aJust			indices.byteswap()
897842e56b97ce677b83bdab09cda48bc2d89ac75aJust		data = data[2*numGlyphs:]
907842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.extraNames = extraNames = unpackPStrings(data)
917842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.glyphOrder = glyphOrder = [None] * int(ttFont['maxp'].numGlyphs)
927842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for glyphID in range(numGlyphs):
937842e56b97ce677b83bdab09cda48bc2d89ac75aJust			index = indices[glyphID]
947842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if index > 257:
957842e56b97ce677b83bdab09cda48bc2d89ac75aJust				name = extraNames[index-258]
967842e56b97ce677b83bdab09cda48bc2d89ac75aJust			else:
977842e56b97ce677b83bdab09cda48bc2d89ac75aJust				# fetch names from standard list
987842e56b97ce677b83bdab09cda48bc2d89ac75aJust				name = standardGlyphOrder[index]
997842e56b97ce677b83bdab09cda48bc2d89ac75aJust			glyphOrder[glyphID] = name
1007842e56b97ce677b83bdab09cda48bc2d89ac75aJust		#AL990511: code added to handle the case of new glyphs without
1017842e56b97ce677b83bdab09cda48bc2d89ac75aJust		#          entries into the 'post' table
1027842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if numGlyphs < ttFont['maxp'].numGlyphs:
1037842e56b97ce677b83bdab09cda48bc2d89ac75aJust			for i in range(numGlyphs, ttFont['maxp'].numGlyphs):
1047842e56b97ce677b83bdab09cda48bc2d89ac75aJust				glyphOrder[i] = "glyph#%.5d" % i
1057842e56b97ce677b83bdab09cda48bc2d89ac75aJust				self.extraNames.append(glyphOrder[i])
1067842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.build_psNameMapping(ttFont)
1077842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1087842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def build_psNameMapping(self, ttFont):
1097842e56b97ce677b83bdab09cda48bc2d89ac75aJust		mapping = {}
1107842e56b97ce677b83bdab09cda48bc2d89ac75aJust		allNames = {}
1117842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for i in range(ttFont['maxp'].numGlyphs):
1127842e56b97ce677b83bdab09cda48bc2d89ac75aJust			glyphName = psName = self.glyphOrder[i]
113bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod			if glyphName in allNames:
1147842e56b97ce677b83bdab09cda48bc2d89ac75aJust				# make up a new glyphName that's unique
11585be2e0a9773acec3c6d14c345b1fd94ab3aa5c3Behdad Esfahbod				n = allNames[glyphName]
11685be2e0a9773acec3c6d14c345b1fd94ab3aa5c3Behdad Esfahbod				allNames[glyphName] = n + 1
117dc7e6f3e5563a853477ebe26166b002c158dbe8bBehdad Esfahbod				glyphName = glyphName + "#" + repr(n)
1187842e56b97ce677b83bdab09cda48bc2d89ac75aJust				self.glyphOrder[i] = glyphName
1197842e56b97ce677b83bdab09cda48bc2d89ac75aJust				mapping[glyphName] = psName
12085be2e0a9773acec3c6d14c345b1fd94ab3aa5c3Behdad Esfahbod			else:
12185be2e0a9773acec3c6d14c345b1fd94ab3aa5c3Behdad Esfahbod				allNames[glyphName] = 1
1227842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.mapping = mapping
1237842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1247842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decode_format_3_0(self, data, ttFont):
1257842e56b97ce677b83bdab09cda48bc2d89ac75aJust		# Setting self.glyphOrder to None will cause the TTFont object
1267842e56b97ce677b83bdab09cda48bc2d89ac75aJust		# try and construct glyph names from a Unicode cmap table.
1277842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.glyphOrder = None
1287842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1294a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten	def decode_format_4_0(self, data, ttFont):
1304a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		from fontTools import agl
1314a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		numGlyphs = ttFont['maxp'].numGlyphs
132149b9f97e39fa2ff3272a9677e49d9d3e7901140Olivier Berten		indices = array.array("H")
133149b9f97e39fa2ff3272a9677e49d9d3e7901140Olivier Berten		indices.fromstring(data)
134149b9f97e39fa2ff3272a9677e49d9d3e7901140Olivier Berten		if sys.byteorder != "big":
135149b9f97e39fa2ff3272a9677e49d9d3e7901140Olivier Berten			indices.byteswap()
1364a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		# In some older fonts, the size of the post table doesn't match
1374a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		# the number of glyphs. Sometimes it's bigger, sometimes smaller.
1384a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		self.glyphOrder = glyphOrder = [''] * int(numGlyphs)
1394a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		for i in range(min(len(indices),numGlyphs)):
1404a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten			if indices[i] == 0xFFFF:
1414a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten				self.glyphOrder[i] = ''
1424a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten			elif indices[i] in agl.UV2AGL:
1434a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten				self.glyphOrder[i] = agl.UV2AGL[indices[i]]
1444a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten			else:
1454a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten				self.glyphOrder[i] = "uni%04X" % indices[i]
1464a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		self.build_psNameMapping(ttFont)
1474a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten
1487842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def encode_format_2_0(self, ttFont):
1497842e56b97ce677b83bdab09cda48bc2d89ac75aJust		numGlyphs = ttFont['maxp'].numGlyphs
1507842e56b97ce677b83bdab09cda48bc2d89ac75aJust		glyphOrder = ttFont.getGlyphOrder()
1517842e56b97ce677b83bdab09cda48bc2d89ac75aJust		assert len(glyphOrder) == numGlyphs
1527842e56b97ce677b83bdab09cda48bc2d89ac75aJust		indices = array.array("H")
1530d762b00de43e9c73a77969afb52a68f1974c54ejvr		extraDict = {}
1540d762b00de43e9c73a77969afb52a68f1974c54ejvr		extraNames = self.extraNames
1550d762b00de43e9c73a77969afb52a68f1974c54ejvr		for i in range(len(extraNames)):
1560d762b00de43e9c73a77969afb52a68f1974c54ejvr			extraDict[extraNames[i]] = i
1577842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for glyphID in range(numGlyphs):
1587842e56b97ce677b83bdab09cda48bc2d89ac75aJust			glyphName = glyphOrder[glyphID]
159bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod			if glyphName in self.mapping:
1607842e56b97ce677b83bdab09cda48bc2d89ac75aJust				psName = self.mapping[glyphName]
1617842e56b97ce677b83bdab09cda48bc2d89ac75aJust			else:
1627842e56b97ce677b83bdab09cda48bc2d89ac75aJust				psName = glyphName
163bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod			if psName in extraDict:
1640d762b00de43e9c73a77969afb52a68f1974c54ejvr				index = 258 + extraDict[psName]
1657842e56b97ce677b83bdab09cda48bc2d89ac75aJust			elif psName in standardGlyphOrder:
1667842e56b97ce677b83bdab09cda48bc2d89ac75aJust				index = standardGlyphOrder.index(psName)
1677842e56b97ce677b83bdab09cda48bc2d89ac75aJust			else:
1680d762b00de43e9c73a77969afb52a68f1974c54ejvr				index = 258 + len(extraNames)
1690d762b00de43e9c73a77969afb52a68f1974c54ejvr				extraDict[psName] = len(extraNames)
1700d762b00de43e9c73a77969afb52a68f1974c54ejvr				extraNames.append(psName)
1717842e56b97ce677b83bdab09cda48bc2d89ac75aJust			indices.append(index)
172180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod		if sys.byteorder != "big":
1737842e56b97ce677b83bdab09cda48bc2d89ac75aJust			indices.byteswap()
1740d762b00de43e9c73a77969afb52a68f1974c54ejvr		return struct.pack(">H", numGlyphs) + indices.tostring() + packPStrings(extraNames)
1757842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1764a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten	def encode_format_4_0(self, ttFont):
1774a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		from fontTools import agl
1784a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		numGlyphs = ttFont['maxp'].numGlyphs
1794a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		glyphOrder = ttFont.getGlyphOrder()
1804a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		assert len(glyphOrder) == numGlyphs
181ec8dccb7318988591aa65bdf3a70d521837d094bOlivier Berten		indices = array.array("H")
1824a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten		for glyphID in glyphOrder:
1834a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten			glyphID = glyphID.split('#')[0]
1844a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten			if glyphID in agl.AGL2UV:
185ec8dccb7318988591aa65bdf3a70d521837d094bOlivier Berten				indices.append(agl.AGL2UV[glyphID])
1864a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten			elif len(glyphID) == 7 and glyphID[:3] == 'uni':
187ec8dccb7318988591aa65bdf3a70d521837d094bOlivier Berten				indices.append(int(glyphID[3:],16))
1884a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten			else:
189ec8dccb7318988591aa65bdf3a70d521837d094bOlivier Berten				indices.append(0xFFFF)
190ec8dccb7318988591aa65bdf3a70d521837d094bOlivier Berten		if sys.byteorder != "big":
191ec8dccb7318988591aa65bdf3a70d521837d094bOlivier Berten			indices.byteswap()
192ec8dccb7318988591aa65bdf3a70d521837d094bOlivier Berten		return indices.tostring()
1934a73f8b4e983b3910d888bab7d50293e363152e9Olivier Berten
1947842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def toXML(self, writer, ttFont):
1957842e56b97ce677b83bdab09cda48bc2d89ac75aJust		formatstring, names, fixes = sstruct.getformat(postFormat)
1967842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for name in names:
1977842e56b97ce677b83bdab09cda48bc2d89ac75aJust			value = getattr(self, name)
1987842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.simpletag(name, value=value)
1997842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
2007842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if hasattr(self, "mapping"):
2017842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.begintag("psNames")
2027842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
2037842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.comment("This file uses unique glyph names based on the information\n"
2047842e56b97ce677b83bdab09cda48bc2d89ac75aJust						"found in the 'post' table. Since these names might not be unique,\n"
2057842e56b97ce677b83bdab09cda48bc2d89ac75aJust						"we have to invent artificial names in case of clashes. In order to\n"
2067842e56b97ce677b83bdab09cda48bc2d89ac75aJust						"be able to retain the original information, we need a name to\n"
2077842e56b97ce677b83bdab09cda48bc2d89ac75aJust						"ps name mapping for those cases where they differ. That's what\n"
2087842e56b97ce677b83bdab09cda48bc2d89ac75aJust						"you see below.\n")
2097842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
210ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod			items = sorted(self.mapping.items())
2117842e56b97ce677b83bdab09cda48bc2d89ac75aJust			for name, psName in items:
2127842e56b97ce677b83bdab09cda48bc2d89ac75aJust				writer.simpletag("psName", name=name, psName=psName)
2137842e56b97ce677b83bdab09cda48bc2d89ac75aJust				writer.newline()
2147842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.endtag("psNames")
2157842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
2167842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if hasattr(self, "extraNames"):
2177842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.begintag("extraNames")
2187842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
2197842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.comment("following are the name that are not taken from the standard Mac glyph order")
2207842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
2217842e56b97ce677b83bdab09cda48bc2d89ac75aJust			for name in self.extraNames:
2227842e56b97ce677b83bdab09cda48bc2d89ac75aJust				writer.simpletag("psName", name=name)
2237842e56b97ce677b83bdab09cda48bc2d89ac75aJust				writer.newline()
2247842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.endtag("extraNames")
2257842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
2267842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if hasattr(self, "data"):
2277842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.begintag("hexdata")
2287842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
2297842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.dumphex(self.data)
2307842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.endtag("hexdata")
2317842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
2327842e56b97ce677b83bdab09cda48bc2d89ac75aJust
2333a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def fromXML(self, name, attrs, content, ttFont):
2347842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if name not in ("psNames", "extraNames", "hexdata"):
2357842e56b97ce677b83bdab09cda48bc2d89ac75aJust			setattr(self, name, safeEval(attrs["value"]))
2367842e56b97ce677b83bdab09cda48bc2d89ac75aJust		elif name == "psNames":
2377842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.mapping = {}
2387842e56b97ce677b83bdab09cda48bc2d89ac75aJust			for element in content:
239b774f9f684c5a0f91f5fa177c9a461968789123fBehdad Esfahbod				if not isinstance(element, tuple):
2407842e56b97ce677b83bdab09cda48bc2d89ac75aJust					continue
2417842e56b97ce677b83bdab09cda48bc2d89ac75aJust				name, attrs, content = element
2427842e56b97ce677b83bdab09cda48bc2d89ac75aJust				if name == "psName":
2437842e56b97ce677b83bdab09cda48bc2d89ac75aJust					self.mapping[attrs["name"]] = attrs["psName"]
2447842e56b97ce677b83bdab09cda48bc2d89ac75aJust		elif name == "extraNames":
2457842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.extraNames = []
2467842e56b97ce677b83bdab09cda48bc2d89ac75aJust			for element in content:
247b774f9f684c5a0f91f5fa177c9a461968789123fBehdad Esfahbod				if not isinstance(element, tuple):
2487842e56b97ce677b83bdab09cda48bc2d89ac75aJust					continue
2497842e56b97ce677b83bdab09cda48bc2d89ac75aJust				name, attrs, content = element
2507842e56b97ce677b83bdab09cda48bc2d89ac75aJust				if name == "psName":
2517842e56b97ce677b83bdab09cda48bc2d89ac75aJust					self.extraNames.append(attrs["name"])
2527842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
2537842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.data = readHex(content)
2547842e56b97ce677b83bdab09cda48bc2d89ac75aJust
2557842e56b97ce677b83bdab09cda48bc2d89ac75aJust
2567842e56b97ce677b83bdab09cda48bc2d89ac75aJustdef unpackPStrings(data):
2577842e56b97ce677b83bdab09cda48bc2d89ac75aJust	strings = []
258f9104bcc2cd61bf029ac6736ef0ee98968bde472jvr	index = 0
259f9104bcc2cd61bf029ac6736ef0ee98968bde472jvr	dataLen = len(data)
260f9104bcc2cd61bf029ac6736ef0ee98968bde472jvr	while index < dataLen:
261319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod		length = byteord(data[index])
26243d7ac16b19f9cad251a8d74a0b93cf8d439fad7Behdad Esfahbod		strings.append(tostr(data[index+1:index+1+length], encoding="latin1"))
263f9104bcc2cd61bf029ac6736ef0ee98968bde472jvr		index = index + 1 + length
2647842e56b97ce677b83bdab09cda48bc2d89ac75aJust	return strings
2657842e56b97ce677b83bdab09cda48bc2d89ac75aJust
266f9104bcc2cd61bf029ac6736ef0ee98968bde472jvr
2677842e56b97ce677b83bdab09cda48bc2d89ac75aJustdef packPStrings(strings):
2685f6418d9e1fa15a89dcec29cdc433ba2c99732c3Behdad Esfahbod	data = b""
2697842e56b97ce677b83bdab09cda48bc2d89ac75aJust	for s in strings:
27043d7ac16b19f9cad251a8d74a0b93cf8d439fad7Behdad Esfahbod		data = data + bytechr(len(s)) + tobytes(s, encoding="latin1")
2717842e56b97ce677b83bdab09cda48bc2d89ac75aJust	return data
2727842e56b97ce677b83bdab09cda48bc2d89ac75aJust
273