17842e56b97ce677b83bdab09cda48bc2d89ac75aJust"""cffLib.py -- read/write tools for Adobe CFF fonts."""
27842e56b97ce677b83bdab09cda48bc2d89ac75aJust
31ae29591efbb29492ce05378909ccf4028d7c1eeBehdad Esfahbodfrom __future__ import print_function, division, absolute_import
430e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom fontTools.misc.py23 import *
58413c108d21e8cf0e9059bbfffde8d13f2616340Behdad Esfahbodfrom fontTools.misc import sstruct
6528614e6e254dfe3c501ff440c291c6c55de5e6fJustfrom fontTools.misc import psCharStrings
74e5af60930726d06a58a30bae45bb27ae50aea77jvrfrom fontTools.misc.textTools import safeEval
830e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodimport struct
92a9b86816e7a1b64d755e208a839b01a7a7ce903Behdad Esfahbod
10767102ea85a8af1535c169b2e04da5ba458f3b80jvrDEBUG = 0
11767102ea85a8af1535c169b2e04da5ba458f3b80jvr
12767102ea85a8af1535c169b2e04da5ba458f3b80jvr
137842e56b97ce677b83bdab09cda48bc2d89ac75aJustcffHeaderFormat = """
147842e56b97ce677b83bdab09cda48bc2d89ac75aJust	major:   B
157842e56b97ce677b83bdab09cda48bc2d89ac75aJust	minor:   B
167842e56b97ce677b83bdab09cda48bc2d89ac75aJust	hdrSize: B
177842e56b97ce677b83bdab09cda48bc2d89ac75aJust	offSize: B
187842e56b97ce677b83bdab09cda48bc2d89ac75aJust"""
197842e56b97ce677b83bdab09cda48bc2d89ac75aJust
20e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass CFFFontSet(object):
217842e56b97ce677b83bdab09cda48bc2d89ac75aJust
227842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def __init__(self):
234756b3a04014645ee16a14fb6273e93efa1c7e15jvr		pass
247842e56b97ce677b83bdab09cda48bc2d89ac75aJust
254e5af60930726d06a58a30bae45bb27ae50aea77jvr	def decompile(self, file, otFont):
26a2a75b348da46073cdd1dea50915384eabfff7c9jvr		sstruct.unpack(cffHeaderFormat, file.read(4), self)
277842e56b97ce677b83bdab09cda48bc2d89ac75aJust		assert self.major == 1 and self.minor == 0, \
287842e56b97ce677b83bdab09cda48bc2d89ac75aJust				"unknown CFF format: %d.%d" % (self.major, self.minor)
297842e56b97ce677b83bdab09cda48bc2d89ac75aJust
30f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		file.seek(self.hdrSize)
314e5af60930726d06a58a30bae45bb27ae50aea77jvr		self.fontNames = list(Index(file))
324756b3a04014645ee16a14fb6273e93efa1c7e15jvr		self.topDictIndex = TopDictIndex(file)
33767102ea85a8af1535c169b2e04da5ba458f3b80jvr		self.strings = IndexedStrings(file)
344e5af60930726d06a58a30bae45bb27ae50aea77jvr		self.GlobalSubrs = GlobalSubrsIndex(file)
354756b3a04014645ee16a14fb6273e93efa1c7e15jvr		self.topDictIndex.strings = self.strings
36016ca76e918ed36888c0fa8e287028ea367ef3d9jvr		self.topDictIndex.GlobalSubrs = self.GlobalSubrs
374756b3a04014645ee16a14fb6273e93efa1c7e15jvr
384756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def __len__(self):
394756b3a04014645ee16a14fb6273e93efa1c7e15jvr		return len(self.fontNames)
404756b3a04014645ee16a14fb6273e93efa1c7e15jvr
414756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def keys(self):
42ce522410f26648af01372cc96fe689cf3b3a7c84jvr		return list(self.fontNames)
434756b3a04014645ee16a14fb6273e93efa1c7e15jvr
44767102ea85a8af1535c169b2e04da5ba458f3b80jvr	def values(self):
45767102ea85a8af1535c169b2e04da5ba458f3b80jvr		return self.topDictIndex
46767102ea85a8af1535c169b2e04da5ba458f3b80jvr
474756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def __getitem__(self, name):
484756b3a04014645ee16a14fb6273e93efa1c7e15jvr		try:
494756b3a04014645ee16a14fb6273e93efa1c7e15jvr			index = self.fontNames.index(name)
504756b3a04014645ee16a14fb6273e93efa1c7e15jvr		except ValueError:
51cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod			raise KeyError(name)
52016ca76e918ed36888c0fa8e287028ea367ef3d9jvr		return self.topDictIndex[index]
537842e56b97ce677b83bdab09cda48bc2d89ac75aJust
544e5af60930726d06a58a30bae45bb27ae50aea77jvr	def compile(self, file, otFont):
557842e56b97ce677b83bdab09cda48bc2d89ac75aJust		strings = IndexedStrings()
56f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		writer = CFFWriter()
57f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		writer.add(sstruct.pack(cffHeaderFormat, self))
58f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		fontNames = Index()
59f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for name in self.fontNames:
60f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			fontNames.append(name)
61f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		writer.add(fontNames.getCompiler(strings, None))
62f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		topCompiler = self.topDictIndex.getCompiler(strings, None)
63f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		writer.add(topCompiler)
64f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		writer.add(strings.getCompiler())
65f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		writer.add(self.GlobalSubrs.getCompiler(strings, None))
66f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
674e5af60930726d06a58a30bae45bb27ae50aea77jvr		for topDict in self.topDictIndex:
684e5af60930726d06a58a30bae45bb27ae50aea77jvr			if not hasattr(topDict, "charset") or topDict.charset is None:
694e5af60930726d06a58a30bae45bb27ae50aea77jvr				charset = otFont.getGlyphOrder()
704e5af60930726d06a58a30bae45bb27ae50aea77jvr				topDict.charset = charset
714e5af60930726d06a58a30bae45bb27ae50aea77jvr
72f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for child in topCompiler.getChildren(strings):
73f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			writer.add(child)
74f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
75f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		writer.toFile(file)
767842e56b97ce677b83bdab09cda48bc2d89ac75aJust
777842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def toXML(self, xmlWriter, progress=None):
787842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for fontName in self.fontNames:
79024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod			xmlWriter.begintag("CFFFont", name=tostr(fontName))
807842e56b97ce677b83bdab09cda48bc2d89ac75aJust			xmlWriter.newline()
814756b3a04014645ee16a14fb6273e93efa1c7e15jvr			font = self[fontName]
827842e56b97ce677b83bdab09cda48bc2d89ac75aJust			font.toXML(xmlWriter, progress)
837842e56b97ce677b83bdab09cda48bc2d89ac75aJust			xmlWriter.endtag("CFFFont")
847842e56b97ce677b83bdab09cda48bc2d89ac75aJust			xmlWriter.newline()
857842e56b97ce677b83bdab09cda48bc2d89ac75aJust		xmlWriter.newline()
867842e56b97ce677b83bdab09cda48bc2d89ac75aJust		xmlWriter.begintag("GlobalSubrs")
877842e56b97ce677b83bdab09cda48bc2d89ac75aJust		xmlWriter.newline()
884756b3a04014645ee16a14fb6273e93efa1c7e15jvr		self.GlobalSubrs.toXML(xmlWriter, progress)
897842e56b97ce677b83bdab09cda48bc2d89ac75aJust		xmlWriter.endtag("GlobalSubrs")
907842e56b97ce677b83bdab09cda48bc2d89ac75aJust		xmlWriter.newline()
917842e56b97ce677b83bdab09cda48bc2d89ac75aJust
923a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def fromXML(self, name, attrs, content):
934e5af60930726d06a58a30bae45bb27ae50aea77jvr		if not hasattr(self, "GlobalSubrs"):
944e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.GlobalSubrs = GlobalSubrsIndex()
954e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.major = 1
964e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.minor = 0
974e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.hdrSize = 4
984e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.offSize = 4  # XXX ??
994e5af60930726d06a58a30bae45bb27ae50aea77jvr		if name == "CFFFont":
1004e5af60930726d06a58a30bae45bb27ae50aea77jvr			if not hasattr(self, "fontNames"):
1014e5af60930726d06a58a30bae45bb27ae50aea77jvr				self.fontNames = []
1024e5af60930726d06a58a30bae45bb27ae50aea77jvr				self.topDictIndex = TopDictIndex()
1034e5af60930726d06a58a30bae45bb27ae50aea77jvr			fontName = attrs["name"]
1044e5af60930726d06a58a30bae45bb27ae50aea77jvr			topDict = TopDict(GlobalSubrs=self.GlobalSubrs)
1054e5af60930726d06a58a30bae45bb27ae50aea77jvr			topDict.charset = None  # gets filled in later
1064e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.fontNames.append(fontName)
1074e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.topDictIndex.append(topDict)
1084e5af60930726d06a58a30bae45bb27ae50aea77jvr			for element in content:
1092a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr				if isinstance(element, basestring):
1104e5af60930726d06a58a30bae45bb27ae50aea77jvr					continue
1113a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod				name, attrs, content = element
1123a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod				topDict.fromXML(name, attrs, content)
1134e5af60930726d06a58a30bae45bb27ae50aea77jvr		elif name == "GlobalSubrs":
1144e5af60930726d06a58a30bae45bb27ae50aea77jvr			for element in content:
1152a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr				if isinstance(element, basestring):
1164e5af60930726d06a58a30bae45bb27ae50aea77jvr					continue
1174e5af60930726d06a58a30bae45bb27ae50aea77jvr				name, attrs, content = element
118489d76a340845361def6af9ab7d9152f8e66f417jvr				subr = psCharStrings.T2CharString()
1193a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod				subr.fromXML(name, attrs, content)
1204e5af60930726d06a58a30bae45bb27ae50aea77jvr				self.GlobalSubrs.append(subr)
1217842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1227842e56b97ce677b83bdab09cda48bc2d89ac75aJust
123e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass CFFWriter(object):
124f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
125f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def __init__(self):
126f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.data = []
127f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
128f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def add(self, table):
129f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.data.append(table)
130f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
131f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def toFile(self, file):
132f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		lastPosList = None
133f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		count = 1
134ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod		while True:
1354e5af60930726d06a58a30bae45bb27ae50aea77jvr			if DEBUG:
1363ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod				print("CFFWriter.toFile() iteration:", count)
1374e5af60930726d06a58a30bae45bb27ae50aea77jvr			count = count + 1
138f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			pos = 0
139f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			posList = [pos]
140f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			for item in self.data:
141f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				if hasattr(item, "getDataLength"):
1424e5af60930726d06a58a30bae45bb27ae50aea77jvr					endPos = pos + item.getDataLength()
143f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				else:
1444e5af60930726d06a58a30bae45bb27ae50aea77jvr					endPos = pos + len(item)
1454e5af60930726d06a58a30bae45bb27ae50aea77jvr				if hasattr(item, "setPos"):
1464e5af60930726d06a58a30bae45bb27ae50aea77jvr					item.setPos(pos, endPos)
1474e5af60930726d06a58a30bae45bb27ae50aea77jvr				pos = endPos
148f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				posList.append(pos)
149f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			if posList == lastPosList:
150f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				break
151f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			lastPosList = posList
1524e5af60930726d06a58a30bae45bb27ae50aea77jvr		if DEBUG:
1533ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod			print("CFFWriter.toFile() writing to file.")
154f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		begin = file.tell()
155f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		posList = [0]
156f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for item in self.data:
157f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			if hasattr(item, "toFile"):
158f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				item.toFile(file)
159f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			else:
160f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				file.write(item)
161f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			posList.append(file.tell() - begin)
162f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		assert posList == lastPosList
163f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
164f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
165f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef calcOffSize(largestOffset):
166f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	if largestOffset < 0x100:
167f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		offSize = 1
168f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	elif largestOffset < 0x10000:
169f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		offSize = 2
170f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	elif largestOffset < 0x1000000:
171f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		offSize = 3
172f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	else:
173f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		offSize = 4
174f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	return offSize
175f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
176f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
177e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass IndexCompiler(object):
178f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
179f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def __init__(self, items, strings, parent):
180f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.items = self.getItems(items, strings)
181f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.parent = parent
182f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
183f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getItems(self, items, strings):
184f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return items
185f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
186f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getOffsets(self):
187f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		pos = 1
188f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		offsets = [pos]
189f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for item in self.items:
190f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			if hasattr(item, "getDataLength"):
191f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				pos = pos + item.getDataLength()
192f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			else:
193f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				pos = pos + len(item)
194f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			offsets.append(pos)
195f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return offsets
196f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
197f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getDataLength(self):
198f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		lastOffset = self.getOffsets()[-1]
199f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		offSize = calcOffSize(lastOffset)
200f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		dataLength = (
201f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			2 +                                # count
202f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			1 +                                # offSize
203f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			(len(self.items) + 1) * offSize +  # the offsets
204f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			lastOffset - 1                     # size of object data
205f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		)
206f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return dataLength
207f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
208f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def toFile(self, file):
209f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		offsets = self.getOffsets()
210f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		writeCard16(file, len(self.items))
211f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		offSize = calcOffSize(offsets[-1])
212f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		writeCard8(file, offSize)
213f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		offSize = -offSize
214f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		pack = struct.pack
215f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for offset in offsets:
216f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			binOffset = pack(">l", offset)[offSize:]
217f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			assert len(binOffset) == -offSize
218f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			file.write(binOffset)
219f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for item in self.items:
220f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			if hasattr(item, "toFile"):
221f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				item.toFile(file)
222f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			else:
22385a64db5419991b228478b866eb4262df7055cb2Behdad Esfahbod				file.write(tobytes(item, encoding="latin1"))
224f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
225f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
226f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass IndexedStringsCompiler(IndexCompiler):
227f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
228f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getItems(self, items, strings):
229f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return items.strings
230f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
231f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
232f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass TopDictIndexCompiler(IndexCompiler):
233f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
234f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getItems(self, items, strings):
235f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		out = []
236f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for item in items:
237f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			out.append(item.getCompiler(strings, self))
238f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return out
239f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
240f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getChildren(self, strings):
241f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		children = []
242f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for topDict in self.items:
243f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			children.extend(topDict.getChildren(strings))
244f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return children
245f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
246f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
247ed10151701a7d22e5ff4e06766edff59bd713c89jvrclass FDArrayIndexCompiler(IndexCompiler):
248ed10151701a7d22e5ff4e06766edff59bd713c89jvr
249ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def getItems(self, items, strings):
250ed10151701a7d22e5ff4e06766edff59bd713c89jvr		out = []
251ed10151701a7d22e5ff4e06766edff59bd713c89jvr		for item in items:
252ed10151701a7d22e5ff4e06766edff59bd713c89jvr			out.append(item.getCompiler(strings, self))
253ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return out
254ed10151701a7d22e5ff4e06766edff59bd713c89jvr
255ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def getChildren(self, strings):
256ed10151701a7d22e5ff4e06766edff59bd713c89jvr		children = []
257ed10151701a7d22e5ff4e06766edff59bd713c89jvr		for fontDict in self.items:
258ed10151701a7d22e5ff4e06766edff59bd713c89jvr			children.extend(fontDict.getChildren(strings))
259ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return children
260ed10151701a7d22e5ff4e06766edff59bd713c89jvr
261ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def toFile(self, file):
262ed10151701a7d22e5ff4e06766edff59bd713c89jvr		offsets = self.getOffsets()
263ed10151701a7d22e5ff4e06766edff59bd713c89jvr		writeCard16(file, len(self.items))
264ed10151701a7d22e5ff4e06766edff59bd713c89jvr		offSize = calcOffSize(offsets[-1])
265ed10151701a7d22e5ff4e06766edff59bd713c89jvr		writeCard8(file, offSize)
266ed10151701a7d22e5ff4e06766edff59bd713c89jvr		offSize = -offSize
267ed10151701a7d22e5ff4e06766edff59bd713c89jvr		pack = struct.pack
268ed10151701a7d22e5ff4e06766edff59bd713c89jvr		for offset in offsets:
269ed10151701a7d22e5ff4e06766edff59bd713c89jvr			binOffset = pack(">l", offset)[offSize:]
270ed10151701a7d22e5ff4e06766edff59bd713c89jvr			assert len(binOffset) == -offSize
271ed10151701a7d22e5ff4e06766edff59bd713c89jvr			file.write(binOffset)
272ed10151701a7d22e5ff4e06766edff59bd713c89jvr		for item in self.items:
273ed10151701a7d22e5ff4e06766edff59bd713c89jvr			if hasattr(item, "toFile"):
274ed10151701a7d22e5ff4e06766edff59bd713c89jvr				item.toFile(file)
275ed10151701a7d22e5ff4e06766edff59bd713c89jvr			else:
276ed10151701a7d22e5ff4e06766edff59bd713c89jvr				file.write(item)
277ed10151701a7d22e5ff4e06766edff59bd713c89jvr
278ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def setPos(self, pos, endPos):
279ed10151701a7d22e5ff4e06766edff59bd713c89jvr		self.parent.rawDict["FDArray"] = pos
280ed10151701a7d22e5ff4e06766edff59bd713c89jvr
281ed10151701a7d22e5ff4e06766edff59bd713c89jvr
282f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass GlobalSubrsCompiler(IndexCompiler):
283f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getItems(self, items, strings):
284f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		out = []
285f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for cs in items:
286f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			cs.compile()
287f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			out.append(cs.bytecode)
288f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return out
289f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
290f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass SubrsCompiler(GlobalSubrsCompiler):
2914e5af60930726d06a58a30bae45bb27ae50aea77jvr	def setPos(self, pos, endPos):
292f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		offset = pos - self.parent.pos
293f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.parent.rawDict["Subrs"] = offset
294f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
295f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass CharStringsCompiler(GlobalSubrsCompiler):
2964e5af60930726d06a58a30bae45bb27ae50aea77jvr	def setPos(self, pos, endPos):
297f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.parent.rawDict["CharStrings"] = pos
298f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
299f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
300e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass Index(object):
3017842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3024756b3a04014645ee16a14fb6273e93efa1c7e15jvr	"""This class represents what the CFF spec calls an INDEX."""
3037842e56b97ce677b83bdab09cda48bc2d89ac75aJust
304f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	compilerClass = IndexCompiler
305f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
3064e5af60930726d06a58a30bae45bb27ae50aea77jvr	def __init__(self, file=None):
3074e5af60930726d06a58a30bae45bb27ae50aea77jvr		name = self.__class__.__name__
308f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		if file is None:
309f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			self.items = []
310f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			return
311767102ea85a8af1535c169b2e04da5ba458f3b80jvr		if DEBUG:
3123ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod			print("loading %s at %s" % (name, file.tell()))
3131890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr		self.file = file
314a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		count = readCard16(file)
3151890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr		self.count = count
3164756b3a04014645ee16a14fb6273e93efa1c7e15jvr		self.items = [None] * count
3171890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr		if count == 0:
318f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			self.items = []
3191890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr			return
320a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		offSize = readCard8(file)
321767102ea85a8af1535c169b2e04da5ba458f3b80jvr		if DEBUG:
3223ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod			print("    index count: %s offSize: %s" % (count, offSize))
323767102ea85a8af1535c169b2e04da5ba458f3b80jvr		assert offSize <= 4, "offSize too large: %s" % offSize
3241890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr		self.offsets = offsets = []
32518316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod		pad = b'\0' * (4 - offSize)
3261890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr		for index in range(count+1):
3271890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr			chunk = file.read(offSize)
3281890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr			chunk = pad + chunk
3291890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr			offset, = struct.unpack(">L", chunk)
3301890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr			offsets.append(int(offset))
3311890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr		self.offsetBase = file.tell() - 1
3324756b3a04014645ee16a14fb6273e93efa1c7e15jvr		file.seek(self.offsetBase + offsets[-1])  # pretend we've read the whole lot
333f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		if DEBUG:
3343ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod			print("    end of %s at %s" % (name, file.tell()))
3351890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
3361890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr	def __len__(self):
337f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return len(self.items)
3381890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
3391890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr	def __getitem__(self, index):
3404756b3a04014645ee16a14fb6273e93efa1c7e15jvr		item = self.items[index]
3414756b3a04014645ee16a14fb6273e93efa1c7e15jvr		if item is not None:
3424756b3a04014645ee16a14fb6273e93efa1c7e15jvr			return item
3431890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr		offset = self.offsets[index] + self.offsetBase
3441890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr		size = self.offsets[index+1] - self.offsets[index]
3454756b3a04014645ee16a14fb6273e93efa1c7e15jvr		file = self.file
3464756b3a04014645ee16a14fb6273e93efa1c7e15jvr		file.seek(offset)
3474756b3a04014645ee16a14fb6273e93efa1c7e15jvr		data = file.read(size)
3484756b3a04014645ee16a14fb6273e93efa1c7e15jvr		assert len(data) == size
349a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		item = self.produceItem(index, data, file, offset, size)
3504756b3a04014645ee16a14fb6273e93efa1c7e15jvr		self.items[index] = item
3514756b3a04014645ee16a14fb6273e93efa1c7e15jvr		return item
3521890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
353a2ad5447fb707448d2c442b16956f87e048ef0d1jvr	def produceItem(self, index, data, file, offset, size):
3544756b3a04014645ee16a14fb6273e93efa1c7e15jvr		return data
355f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
356f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def append(self, item):
357f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.items.append(item)
358f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
359f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getCompiler(self, strings, parent):
360f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return self.compilerClass(self, strings, parent)
3611890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
3621890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
363f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass GlobalSubrsIndex(Index):
364f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
365f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	compilerClass = GlobalSubrsCompiler
3664756b3a04014645ee16a14fb6273e93efa1c7e15jvr
3674e5af60930726d06a58a30bae45bb27ae50aea77jvr	def __init__(self, file=None, globalSubrs=None, private=None, fdSelect=None, fdArray=None):
3684e5af60930726d06a58a30bae45bb27ae50aea77jvr		Index.__init__(self, file)
369a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		self.globalSubrs = globalSubrs
370a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		self.private = private
371ed10151701a7d22e5ff4e06766edff59bd713c89jvr		if fdSelect:
372ed10151701a7d22e5ff4e06766edff59bd713c89jvr			self.fdSelect = fdSelect
373ed10151701a7d22e5ff4e06766edff59bd713c89jvr		if fdArray:
374ed10151701a7d22e5ff4e06766edff59bd713c89jvr			self.fdArray = fdArray
375a2ad5447fb707448d2c442b16956f87e048ef0d1jvr
376a2ad5447fb707448d2c442b16956f87e048ef0d1jvr	def produceItem(self, index, data, file, offset, size):
377a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		if self.private is not None:
378a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			private = self.private
379ed10151701a7d22e5ff4e06766edff59bd713c89jvr		elif hasattr(self, 'fdArray') and self.fdArray is not None:
380a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			private = self.fdArray[self.fdSelect[index]].Private
381a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		else:
382a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			private = None
383489d76a340845361def6af9ab7d9152f8e66f417jvr		return psCharStrings.T2CharString(data, private=private, globalSubrs=self.globalSubrs)
3844756b3a04014645ee16a14fb6273e93efa1c7e15jvr
3854756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def toXML(self, xmlWriter, progress):
386ed10151701a7d22e5ff4e06766edff59bd713c89jvr		xmlWriter.comment("The 'index' attribute is only for humans; it is ignored when parsed.")
3874e5af60930726d06a58a30bae45bb27ae50aea77jvr		xmlWriter.newline()
3884756b3a04014645ee16a14fb6273e93efa1c7e15jvr		for i in range(len(self)):
389b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr			subr = self[i]
390b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr			if subr.needsDecompilation():
391b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr				xmlWriter.begintag("CharString", index=i, raw=1)
392b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr			else:
393b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr				xmlWriter.begintag("CharString", index=i)
3944756b3a04014645ee16a14fb6273e93efa1c7e15jvr			xmlWriter.newline()
395b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr			subr.toXML(xmlWriter)
3964756b3a04014645ee16a14fb6273e93efa1c7e15jvr			xmlWriter.endtag("CharString")
3974756b3a04014645ee16a14fb6273e93efa1c7e15jvr			xmlWriter.newline()
398a2ad5447fb707448d2c442b16956f87e048ef0d1jvr
3993a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def fromXML(self, name, attrs, content):
400180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod		if name != "CharString":
4014e5af60930726d06a58a30bae45bb27ae50aea77jvr			return
402489d76a340845361def6af9ab7d9152f8e66f417jvr		subr = psCharStrings.T2CharString()
4033a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod		subr.fromXML(name, attrs, content)
4044e5af60930726d06a58a30bae45bb27ae50aea77jvr		self.append(subr)
4054e5af60930726d06a58a30bae45bb27ae50aea77jvr
406a2ad5447fb707448d2c442b16956f87e048ef0d1jvr	def getItemAndSelector(self, index):
407ed10151701a7d22e5ff4e06766edff59bd713c89jvr		sel = None
408ed10151701a7d22e5ff4e06766edff59bd713c89jvr		if hasattr(self, 'fdSelect'):
409ed10151701a7d22e5ff4e06766edff59bd713c89jvr			sel = self.fdSelect[index]
410a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		return self[index], sel
411f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
412e2ca9b5a4ff537ad827c3f722c8137b4f986d9a5jvr
413f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass SubrsIndex(GlobalSubrsIndex):
414f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	compilerClass = SubrsCompiler
415f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
4164756b3a04014645ee16a14fb6273e93efa1c7e15jvr
417767102ea85a8af1535c169b2e04da5ba458f3b80jvrclass TopDictIndex(Index):
418a2ad5447fb707448d2c442b16956f87e048ef0d1jvr
419f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	compilerClass = TopDictIndexCompiler
420f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
421a2ad5447fb707448d2c442b16956f87e048ef0d1jvr	def produceItem(self, index, data, file, offset, size):
422767102ea85a8af1535c169b2e04da5ba458f3b80jvr		top = TopDict(self.strings, file, offset, self.GlobalSubrs)
423767102ea85a8af1535c169b2e04da5ba458f3b80jvr		top.decompile(data)
424767102ea85a8af1535c169b2e04da5ba458f3b80jvr		return top
425a2ad5447fb707448d2c442b16956f87e048ef0d1jvr
426a2ad5447fb707448d2c442b16956f87e048ef0d1jvr	def toXML(self, xmlWriter, progress):
427a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		for i in range(len(self)):
428a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			xmlWriter.begintag("FontDict", index=i)
429a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			xmlWriter.newline()
430a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			self[i].toXML(xmlWriter, progress)
431a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			xmlWriter.endtag("FontDict")
432a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			xmlWriter.newline()
433767102ea85a8af1535c169b2e04da5ba458f3b80jvr
434767102ea85a8af1535c169b2e04da5ba458f3b80jvr
435ed10151701a7d22e5ff4e06766edff59bd713c89jvrclass FDArrayIndex(TopDictIndex):
436ed10151701a7d22e5ff4e06766edff59bd713c89jvr
437ed10151701a7d22e5ff4e06766edff59bd713c89jvr	compilerClass = FDArrayIndexCompiler
438ed10151701a7d22e5ff4e06766edff59bd713c89jvr
4393a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def fromXML(self, name, attrs, content):
440180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod		if name != "FontDict":
441ed10151701a7d22e5ff4e06766edff59bd713c89jvr			return
442ed10151701a7d22e5ff4e06766edff59bd713c89jvr		fontDict = FontDict()
443ed10151701a7d22e5ff4e06766edff59bd713c89jvr		for element in content:
4442a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr			if isinstance(element, basestring):
445ed10151701a7d22e5ff4e06766edff59bd713c89jvr				continue
4463a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod			name, attrs, content = element
4473a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod			fontDict.fromXML(name, attrs, content)
448ed10151701a7d22e5ff4e06766edff59bd713c89jvr		self.append(fontDict)
449ed10151701a7d22e5ff4e06766edff59bd713c89jvr
450ed10151701a7d22e5ff4e06766edff59bd713c89jvr
451ed10151701a7d22e5ff4e06766edff59bd713c89jvrclass	FDSelect:
452ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def __init__(self, file = None, numGlyphs = None, format=None):
453ed10151701a7d22e5ff4e06766edff59bd713c89jvr		if file:
454ed10151701a7d22e5ff4e06766edff59bd713c89jvr			# read data in from file
455ed10151701a7d22e5ff4e06766edff59bd713c89jvr			self.format = readCard8(file)
456ed10151701a7d22e5ff4e06766edff59bd713c89jvr			if self.format == 0:
457ed10151701a7d22e5ff4e06766edff59bd713c89jvr				from array import array
458ed10151701a7d22e5ff4e06766edff59bd713c89jvr				self.gidArray = array("B", file.read(numGlyphs)).tolist()
459ed10151701a7d22e5ff4e06766edff59bd713c89jvr			elif self.format == 3:
460ed10151701a7d22e5ff4e06766edff59bd713c89jvr				gidArray = [None] * numGlyphs
461ed10151701a7d22e5ff4e06766edff59bd713c89jvr				nRanges = readCard16(file)
462ed10151701a7d22e5ff4e06766edff59bd713c89jvr				prev = None
463ed10151701a7d22e5ff4e06766edff59bd713c89jvr				for i in range(nRanges):
464ed10151701a7d22e5ff4e06766edff59bd713c89jvr					first = readCard16(file)
465ed10151701a7d22e5ff4e06766edff59bd713c89jvr					if prev is not None:
466ed10151701a7d22e5ff4e06766edff59bd713c89jvr						for glyphID in range(prev, first):
467ed10151701a7d22e5ff4e06766edff59bd713c89jvr							gidArray[glyphID] = fd
468ed10151701a7d22e5ff4e06766edff59bd713c89jvr					prev = first
469ed10151701a7d22e5ff4e06766edff59bd713c89jvr					fd = readCard8(file)
470ed10151701a7d22e5ff4e06766edff59bd713c89jvr				if prev is not None:
471ed10151701a7d22e5ff4e06766edff59bd713c89jvr					first = readCard16(file)
472ed10151701a7d22e5ff4e06766edff59bd713c89jvr					for glyphID in range(prev, first):
473ed10151701a7d22e5ff4e06766edff59bd713c89jvr						gidArray[glyphID] = fd
474ed10151701a7d22e5ff4e06766edff59bd713c89jvr				self.gidArray = gidArray
475ed10151701a7d22e5ff4e06766edff59bd713c89jvr			else:
476153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod				assert False, "unsupported FDSelect format: %s" % format
477ed10151701a7d22e5ff4e06766edff59bd713c89jvr		else:
478ed10151701a7d22e5ff4e06766edff59bd713c89jvr			# reading from XML. Make empty gidArray,, and leave format as passed in.
4799e6ef94b5554c5b7dda2de9c863c11ed4b996b7aBehdad Esfahbod			# format is None will result in the smallest representation being used.
480ed10151701a7d22e5ff4e06766edff59bd713c89jvr			self.format = format
481ed10151701a7d22e5ff4e06766edff59bd713c89jvr			self.gidArray = []
482ed10151701a7d22e5ff4e06766edff59bd713c89jvr
483ed10151701a7d22e5ff4e06766edff59bd713c89jvr
484ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def __len__(self):
485ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return len(self.gidArray)
486ed10151701a7d22e5ff4e06766edff59bd713c89jvr
487ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def __getitem__(self, index):
488ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return self.gidArray[index]
489ed10151701a7d22e5ff4e06766edff59bd713c89jvr
490ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def __setitem__(self, index, fdSelectValue):
491ed10151701a7d22e5ff4e06766edff59bd713c89jvr		self.gidArray[index] = fdSelectValue
492ed10151701a7d22e5ff4e06766edff59bd713c89jvr
493ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def append(self, fdSelectValue):
494ed10151701a7d22e5ff4e06766edff59bd713c89jvr		self.gidArray.append(fdSelectValue)
495ed10151701a7d22e5ff4e06766edff59bd713c89jvr
496ed10151701a7d22e5ff4e06766edff59bd713c89jvr
497e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass CharStrings(object):
4981890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
499a2ad5447fb707448d2c442b16956f87e048ef0d1jvr	def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray):
5004e5af60930726d06a58a30bae45bb27ae50aea77jvr		if file is not None:
5014e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.charStringsIndex = SubrsIndex(file, globalSubrs, private, fdSelect, fdArray)
5024e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.charStrings = charStrings = {}
5034e5af60930726d06a58a30bae45bb27ae50aea77jvr			for i in range(len(charset)):
5044e5af60930726d06a58a30bae45bb27ae50aea77jvr				charStrings[charset[i]] = i
5054e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.charStringsAreIndexed = 1
5064e5af60930726d06a58a30bae45bb27ae50aea77jvr		else:
5074e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.charStrings = {}
5084e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.charStringsAreIndexed = 0
5094e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.globalSubrs = globalSubrs
5104e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.private = private
5119e6ef94b5554c5b7dda2de9c863c11ed4b996b7aBehdad Esfahbod			if fdSelect is not None:
512ed10151701a7d22e5ff4e06766edff59bd713c89jvr				self.fdSelect = fdSelect
5139e6ef94b5554c5b7dda2de9c863c11ed4b996b7aBehdad Esfahbod			if fdArray is not None:
514ed10151701a7d22e5ff4e06766edff59bd713c89jvr				self.fdArray = fdArray
5151890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
5164756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def keys(self):
517c2297cd41d6c00b95f857b65bc9fd4b57559ac5eBehdad Esfahbod		return list(self.charStrings.keys())
5184756b3a04014645ee16a14fb6273e93efa1c7e15jvr
519016ca76e918ed36888c0fa8e287028ea367ef3d9jvr	def values(self):
5204e5af60930726d06a58a30bae45bb27ae50aea77jvr		if self.charStringsAreIndexed:
5214e5af60930726d06a58a30bae45bb27ae50aea77jvr			return self.charStringsIndex
5224e5af60930726d06a58a30bae45bb27ae50aea77jvr		else:
523c2297cd41d6c00b95f857b65bc9fd4b57559ac5eBehdad Esfahbod			return list(self.charStrings.values())
524016ca76e918ed36888c0fa8e287028ea367ef3d9jvr
5254756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def has_key(self, name):
526bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod		return name in self.charStrings
5271890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
528767102ea85a8af1535c169b2e04da5ba458f3b80jvr	def __len__(self):
5294e5af60930726d06a58a30bae45bb27ae50aea77jvr		return len(self.charStrings)
530767102ea85a8af1535c169b2e04da5ba458f3b80jvr
5314756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def __getitem__(self, name):
5324e5af60930726d06a58a30bae45bb27ae50aea77jvr		charString = self.charStrings[name]
5334e5af60930726d06a58a30bae45bb27ae50aea77jvr		if self.charStringsAreIndexed:
5344e5af60930726d06a58a30bae45bb27ae50aea77jvr			charString = self.charStringsIndex[charString]
5354e5af60930726d06a58a30bae45bb27ae50aea77jvr		return charString
5364e5af60930726d06a58a30bae45bb27ae50aea77jvr
5374e5af60930726d06a58a30bae45bb27ae50aea77jvr	def __setitem__(self, name, charString):
5384e5af60930726d06a58a30bae45bb27ae50aea77jvr		if self.charStringsAreIndexed:
5394e5af60930726d06a58a30bae45bb27ae50aea77jvr			index = self.charStrings[name]
5404e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.charStringsIndex[index] = charString
5414e5af60930726d06a58a30bae45bb27ae50aea77jvr		else:
5424e5af60930726d06a58a30bae45bb27ae50aea77jvr			self.charStrings[name] = charString
5431890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
544a2ad5447fb707448d2c442b16956f87e048ef0d1jvr	def getItemAndSelector(self, name):
5454e5af60930726d06a58a30bae45bb27ae50aea77jvr		if self.charStringsAreIndexed:
5464e5af60930726d06a58a30bae45bb27ae50aea77jvr			index = self.charStrings[name]
5474e5af60930726d06a58a30bae45bb27ae50aea77jvr			return self.charStringsIndex.getItemAndSelector(index)
5484e5af60930726d06a58a30bae45bb27ae50aea77jvr		else:
549ed10151701a7d22e5ff4e06766edff59bd713c89jvr			if hasattr(self, 'fdSelect'):
55091bca4244286fb519c93fe92329da96b0e6f32eejvr				sel = self.fdSelect[index]  # index is not defined at this point. Read R. ?
551ed10151701a7d22e5ff4e06766edff59bd713c89jvr			else:
552ed10151701a7d22e5ff4e06766edff59bd713c89jvr				raise KeyError("fdSelect array not yet defined.")
553ed10151701a7d22e5ff4e06766edff59bd713c89jvr			return self.charStrings[name], sel
554a2ad5447fb707448d2c442b16956f87e048ef0d1jvr
5554756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def toXML(self, xmlWriter, progress):
556ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod		names = sorted(self.keys())
5577ce0a139ab67dd30614e728a1ef897e53ad805aejvr		i = 0
5587ce0a139ab67dd30614e728a1ef897e53ad805aejvr		step = 10
5597ce0a139ab67dd30614e728a1ef897e53ad805aejvr		numGlyphs = len(names)
5604756b3a04014645ee16a14fb6273e93efa1c7e15jvr		for name in names:
561ed10151701a7d22e5ff4e06766edff59bd713c89jvr			charStr, fdSelectIndex = self.getItemAndSelector(name)
562b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr			if charStr.needsDecompilation():
563b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr				raw = [("raw", 1)]
564b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr			else:
565b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr				raw = []
566ed10151701a7d22e5ff4e06766edff59bd713c89jvr			if fdSelectIndex is None:
567b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr				xmlWriter.begintag("CharString", [('name', name)] + raw)
568a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			else:
569a2ad5447fb707448d2c442b16956f87e048ef0d1jvr				xmlWriter.begintag("CharString",
570ed10151701a7d22e5ff4e06766edff59bd713c89jvr						[('name', name), ('fdSelectIndex', fdSelectIndex)] + raw)
5714756b3a04014645ee16a14fb6273e93efa1c7e15jvr			xmlWriter.newline()
572b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr			charStr.toXML(xmlWriter)
5734756b3a04014645ee16a14fb6273e93efa1c7e15jvr			xmlWriter.endtag("CharString")
5744756b3a04014645ee16a14fb6273e93efa1c7e15jvr			xmlWriter.newline()
5757ce0a139ab67dd30614e728a1ef897e53ad805aejvr			if not i % step and progress is not None:
5767ce0a139ab67dd30614e728a1ef897e53ad805aejvr				progress.setLabel("Dumping 'CFF ' table... (%s)" % name)
57732c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbod				progress.increment(step / numGlyphs)
5787ce0a139ab67dd30614e728a1ef897e53ad805aejvr			i = i + 1
5794e5af60930726d06a58a30bae45bb27ae50aea77jvr
5803a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def fromXML(self, name, attrs, content):
5814e5af60930726d06a58a30bae45bb27ae50aea77jvr		for element in content:
5822a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr			if isinstance(element, basestring):
5834e5af60930726d06a58a30bae45bb27ae50aea77jvr				continue
5844e5af60930726d06a58a30bae45bb27ae50aea77jvr			name, attrs, content = element
585180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod			if name != "CharString":
5864e5af60930726d06a58a30bae45bb27ae50aea77jvr				continue
587ed10151701a7d22e5ff4e06766edff59bd713c89jvr			fdID = -1
588ed10151701a7d22e5ff4e06766edff59bd713c89jvr			if hasattr(self, "fdArray"):
589ed10151701a7d22e5ff4e06766edff59bd713c89jvr				fdID = safeEval(attrs["fdSelectIndex"])
590ed10151701a7d22e5ff4e06766edff59bd713c89jvr				private = self.fdArray[fdID].Private
591ed10151701a7d22e5ff4e06766edff59bd713c89jvr			else:
592ed10151701a7d22e5ff4e06766edff59bd713c89jvr				private = self.private
593ed10151701a7d22e5ff4e06766edff59bd713c89jvr
5944e5af60930726d06a58a30bae45bb27ae50aea77jvr			glyphName = attrs["name"]
595489d76a340845361def6af9ab7d9152f8e66f417jvr			charString = psCharStrings.T2CharString(
596489d76a340845361def6af9ab7d9152f8e66f417jvr					private=private,
597489d76a340845361def6af9ab7d9152f8e66f417jvr					globalSubrs=self.globalSubrs)
5983a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod			charString.fromXML(name, attrs, content)
599ed10151701a7d22e5ff4e06766edff59bd713c89jvr			if fdID >= 0:
600ed10151701a7d22e5ff4e06766edff59bd713c89jvr				charString.fdSelectIndex = fdID
6014e5af60930726d06a58a30bae45bb27ae50aea77jvr			self[glyphName] = charString
6021890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
6031890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
604a2ad5447fb707448d2c442b16956f87e048ef0d1jvrdef readCard8(file):
605319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod	return byteord(file.read(1))
606a2ad5447fb707448d2c442b16956f87e048ef0d1jvr
607a2ad5447fb707448d2c442b16956f87e048ef0d1jvrdef readCard16(file):
608a2ad5447fb707448d2c442b16956f87e048ef0d1jvr	value, = struct.unpack(">H", file.read(2))
609a2ad5447fb707448d2c442b16956f87e048ef0d1jvr	return value
610a2ad5447fb707448d2c442b16956f87e048ef0d1jvr
611f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef writeCard8(file, value):
612b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod	file.write(bytechr(value))
613f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
614f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef writeCard16(file, value):
615f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	file.write(struct.pack(">H", value))
616f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
617f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef packCard8(value):
618b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod	return bytechr(value)
619f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
620f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef packCard16(value):
621f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	return struct.pack(">H", value)
622f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
6234756b3a04014645ee16a14fb6273e93efa1c7e15jvrdef buildOperatorDict(table):
6244756b3a04014645ee16a14fb6273e93efa1c7e15jvr	d = {}
6254756b3a04014645ee16a14fb6273e93efa1c7e15jvr	for op, name, arg, default, conv in table:
6264756b3a04014645ee16a14fb6273e93efa1c7e15jvr		d[op] = (name, arg)
6274756b3a04014645ee16a14fb6273e93efa1c7e15jvr	return d
6281890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
629f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef buildOpcodeDict(table):
630f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	d = {}
631f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	for op, name, arg, default, conv in table:
6322a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr		if isinstance(op, tuple):
633b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod			op = bytechr(op[0]) + bytechr(op[1])
634f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		else:
635b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod			op = bytechr(op)
636f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		d[name] = (op, arg)
637f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	return d
638f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
6394756b3a04014645ee16a14fb6273e93efa1c7e15jvrdef buildOrder(table):
6404756b3a04014645ee16a14fb6273e93efa1c7e15jvr	l = []
6414756b3a04014645ee16a14fb6273e93efa1c7e15jvr	for op, name, arg, default, conv in table:
6424756b3a04014645ee16a14fb6273e93efa1c7e15jvr		l.append(name)
6434756b3a04014645ee16a14fb6273e93efa1c7e15jvr	return l
6441890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
6454756b3a04014645ee16a14fb6273e93efa1c7e15jvrdef buildDefaults(table):
6464756b3a04014645ee16a14fb6273e93efa1c7e15jvr	d = {}
6474756b3a04014645ee16a14fb6273e93efa1c7e15jvr	for op, name, arg, default, conv in table:
6484756b3a04014645ee16a14fb6273e93efa1c7e15jvr		if default is not None:
6494756b3a04014645ee16a14fb6273e93efa1c7e15jvr			d[name] = default
6504756b3a04014645ee16a14fb6273e93efa1c7e15jvr	return d
6514756b3a04014645ee16a14fb6273e93efa1c7e15jvr
6524756b3a04014645ee16a14fb6273e93efa1c7e15jvrdef buildConverters(table):
6534756b3a04014645ee16a14fb6273e93efa1c7e15jvr	d = {}
6544756b3a04014645ee16a14fb6273e93efa1c7e15jvr	for op, name, arg, default, conv in table:
6554756b3a04014645ee16a14fb6273e93efa1c7e15jvr		d[name] = conv
6564756b3a04014645ee16a14fb6273e93efa1c7e15jvr	return d
6574756b3a04014645ee16a14fb6273e93efa1c7e15jvr
6584756b3a04014645ee16a14fb6273e93efa1c7e15jvr
659e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass SimpleConverter(object):
6607ce02ea9dfa1236002aaf61c972a8f31544d070ejvr	def read(self, parent, value):
6617ce02ea9dfa1236002aaf61c972a8f31544d070ejvr		return value
662f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def write(self, parent, value):
663f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return value
6647ce0a139ab67dd30614e728a1ef897e53ad805aejvr	def xmlWrite(self, xmlWriter, name, value, progress):
6654e5af60930726d06a58a30bae45bb27ae50aea77jvr		xmlWriter.simpletag(name, value=value)
6664e5af60930726d06a58a30bae45bb27ae50aea77jvr		xmlWriter.newline()
6673a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def xmlRead(self, name, attrs, content, parent):
6684e5af60930726d06a58a30bae45bb27ae50aea77jvr		return attrs["value"]
6694e5af60930726d06a58a30bae45bb27ae50aea77jvr
670024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbodclass ASCIIConverter(SimpleConverter):
671024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod	def read(self, parent, value):
672024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod		return tostr(value, encoding='ascii')
673024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod	def write(self, parent, value):
674024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod		return tobytes(value, encoding='ascii')
675024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod	def xmlWrite(self, xmlWriter, name, value, progress):
676024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod		xmlWriter.simpletag(name, value=tostr(value, encoding="ascii"))
677024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod		xmlWriter.newline()
678024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod	def xmlRead(self, name, attrs, content, parent):
679024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod		return tobytes(attrs["value"], encoding=("ascii"))
680024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod
681e2ca9b5a4ff537ad827c3f722c8137b4f986d9a5jvrclass Latin1Converter(SimpleConverter):
682024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod	def read(self, parent, value):
683024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod		return tostr(value, encoding='latin1')
684024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod	def write(self, parent, value):
685024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod		return tobytes(value, encoding='latin1')
6868c5c96647147a4cfc13d31d17a64f501fa824994Behdad Esfahbod	def xmlWrite(self, xmlWriter, name, value, progress):
687024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod		xmlWriter.simpletag(name, value=tostr(value, encoding="latin1"))
6888c5c96647147a4cfc13d31d17a64f501fa824994Behdad Esfahbod		xmlWriter.newline()
6893a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def xmlRead(self, name, attrs, content, parent):
690024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod		return tobytes(attrs["value"], encoding=("latin1"))
691e2ca9b5a4ff537ad827c3f722c8137b4f986d9a5jvr
692e2ca9b5a4ff537ad827c3f722c8137b4f986d9a5jvr
6934e5af60930726d06a58a30bae45bb27ae50aea77jvrdef parseNum(s):
6944e5af60930726d06a58a30bae45bb27ae50aea77jvr	try:
6954e5af60930726d06a58a30bae45bb27ae50aea77jvr		value = int(s)
6964e5af60930726d06a58a30bae45bb27ae50aea77jvr	except:
6974e5af60930726d06a58a30bae45bb27ae50aea77jvr		value = float(s)
6984e5af60930726d06a58a30bae45bb27ae50aea77jvr	return value
6994e5af60930726d06a58a30bae45bb27ae50aea77jvr
7004e5af60930726d06a58a30bae45bb27ae50aea77jvrclass NumberConverter(SimpleConverter):
7013a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def xmlRead(self, name, attrs, content, parent):
7024e5af60930726d06a58a30bae45bb27ae50aea77jvr		return parseNum(attrs["value"])
7034e5af60930726d06a58a30bae45bb27ae50aea77jvr
7044e5af60930726d06a58a30bae45bb27ae50aea77jvrclass ArrayConverter(SimpleConverter):
7057ce0a139ab67dd30614e728a1ef897e53ad805aejvr	def xmlWrite(self, xmlWriter, name, value, progress):
706e5ca79699d00fdf7ac6eaceaed372aea8d6bc1fdBehdad Esfahbod		value = " ".join(map(str, value))
707e5ca79699d00fdf7ac6eaceaed372aea8d6bc1fdBehdad Esfahbod		xmlWriter.simpletag(name, value=value)
7084e5af60930726d06a58a30bae45bb27ae50aea77jvr		xmlWriter.newline()
7093a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def xmlRead(self, name, attrs, content, parent):
7104e5af60930726d06a58a30bae45bb27ae50aea77jvr		values = attrs["value"].split()
711e5ca79699d00fdf7ac6eaceaed372aea8d6bc1fdBehdad Esfahbod		return [parseNum(value) for value in values]
7124e5af60930726d06a58a30bae45bb27ae50aea77jvr
7134e5af60930726d06a58a30bae45bb27ae50aea77jvrclass TableConverter(SimpleConverter):
7147ce0a139ab67dd30614e728a1ef897e53ad805aejvr	def xmlWrite(self, xmlWriter, name, value, progress):
715a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		xmlWriter.begintag(name)
716a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		xmlWriter.newline()
7177ce0a139ab67dd30614e728a1ef897e53ad805aejvr		value.toXML(xmlWriter, progress)
718a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		xmlWriter.endtag(name)
719a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		xmlWriter.newline()
7203a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def xmlRead(self, name, attrs, content, parent):
7214e5af60930726d06a58a30bae45bb27ae50aea77jvr		ob = self.getClass()()
7224e5af60930726d06a58a30bae45bb27ae50aea77jvr		for element in content:
7232a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr			if isinstance(element, basestring):
7244e5af60930726d06a58a30bae45bb27ae50aea77jvr				continue
7253a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod			name, attrs, content = element
7263a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod			ob.fromXML(name, attrs, content)
7274e5af60930726d06a58a30bae45bb27ae50aea77jvr		return ob
728a2ad5447fb707448d2c442b16956f87e048ef0d1jvr
7294e5af60930726d06a58a30bae45bb27ae50aea77jvrclass PrivateDictConverter(TableConverter):
7304e5af60930726d06a58a30bae45bb27ae50aea77jvr	def getClass(self):
7314e5af60930726d06a58a30bae45bb27ae50aea77jvr		return PrivateDict
7324756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def read(self, parent, value):
7334756b3a04014645ee16a14fb6273e93efa1c7e15jvr		size, offset = value
7344756b3a04014645ee16a14fb6273e93efa1c7e15jvr		file = parent.file
7354e5af60930726d06a58a30bae45bb27ae50aea77jvr		priv = PrivateDict(parent.strings, file, offset)
7364756b3a04014645ee16a14fb6273e93efa1c7e15jvr		file.seek(offset)
7374756b3a04014645ee16a14fb6273e93efa1c7e15jvr		data = file.read(size)
738153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod		assert len(data) == size
7394e5af60930726d06a58a30bae45bb27ae50aea77jvr		priv.decompile(data)
7404e5af60930726d06a58a30bae45bb27ae50aea77jvr		return priv
741f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def write(self, parent, value):
742f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return (0, 0)  # dummy value
7434756b3a04014645ee16a14fb6273e93efa1c7e15jvr
7444e5af60930726d06a58a30bae45bb27ae50aea77jvrclass SubrsConverter(TableConverter):
7454e5af60930726d06a58a30bae45bb27ae50aea77jvr	def getClass(self):
7464e5af60930726d06a58a30bae45bb27ae50aea77jvr		return SubrsIndex
7474756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def read(self, parent, value):
7484756b3a04014645ee16a14fb6273e93efa1c7e15jvr		file = parent.file
7494756b3a04014645ee16a14fb6273e93efa1c7e15jvr		file.seek(parent.offset + value)  # Offset(self)
7504e5af60930726d06a58a30bae45bb27ae50aea77jvr		return SubrsIndex(file)
751f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def write(self, parent, value):
752f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return 0  # dummy value
7534756b3a04014645ee16a14fb6273e93efa1c7e15jvr
7544e5af60930726d06a58a30bae45bb27ae50aea77jvrclass CharStringsConverter(TableConverter):
7554756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def read(self, parent, value):
7564756b3a04014645ee16a14fb6273e93efa1c7e15jvr		file = parent.file
757767102ea85a8af1535c169b2e04da5ba458f3b80jvr		charset = parent.charset
758a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		globalSubrs = parent.GlobalSubrs
759a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		if hasattr(parent, "ROS"):
760a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			fdSelect, fdArray = parent.FDSelect, parent.FDArray
761a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			private = None
762a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		else:
763a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			fdSelect, fdArray = None, None
764a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			private = parent.Private
7654756b3a04014645ee16a14fb6273e93efa1c7e15jvr		file.seek(value)  # Offset(0)
766a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		return CharStrings(file, charset, globalSubrs, private, fdSelect, fdArray)
767f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def write(self, parent, value):
768f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return 0  # dummy value
7693a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def xmlRead(self, name, attrs, content, parent):
770ed10151701a7d22e5ff4e06766edff59bd713c89jvr		if hasattr(parent, "ROS"):
771ed10151701a7d22e5ff4e06766edff59bd713c89jvr			# if it is a CID-keyed font, then the private Dict is extracted from the parent.FDArray
772ed10151701a7d22e5ff4e06766edff59bd713c89jvr			private, fdSelect, fdArray = None, parent.FDSelect, parent.FDArray
773ed10151701a7d22e5ff4e06766edff59bd713c89jvr		else:
774ed10151701a7d22e5ff4e06766edff59bd713c89jvr			# if it is a name-keyed font, then the private dict is in the top dict, and there is no fdArray.
775ed10151701a7d22e5ff4e06766edff59bd713c89jvr			private, fdSelect, fdArray = parent.Private, None, None
776ed10151701a7d22e5ff4e06766edff59bd713c89jvr		charStrings = CharStrings(None, None, parent.GlobalSubrs, private, fdSelect, fdArray)
7773a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod		charStrings.fromXML(name, attrs, content)
7784e5af60930726d06a58a30bae45bb27ae50aea77jvr		return charStrings
7794756b3a04014645ee16a14fb6273e93efa1c7e15jvr
780e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass CharsetConverter(object):
7814756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def read(self, parent, value):
7824756b3a04014645ee16a14fb6273e93efa1c7e15jvr		isCID = hasattr(parent, "ROS")
7834756b3a04014645ee16a14fb6273e93efa1c7e15jvr		if value > 2:
7844756b3a04014645ee16a14fb6273e93efa1c7e15jvr			numGlyphs = parent.numGlyphs
7854756b3a04014645ee16a14fb6273e93efa1c7e15jvr			file = parent.file
7864756b3a04014645ee16a14fb6273e93efa1c7e15jvr			file.seek(value)
787f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			if DEBUG:
7883ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod				print("loading charset at %s" % value)
789a2ad5447fb707448d2c442b16956f87e048ef0d1jvr			format = readCard8(file)
7904756b3a04014645ee16a14fb6273e93efa1c7e15jvr			if format == 0:
791c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr				charset = parseCharset0(numGlyphs, file, parent.strings, isCID)
7924756b3a04014645ee16a14fb6273e93efa1c7e15jvr			elif format == 1 or format == 2:
7934756b3a04014645ee16a14fb6273e93efa1c7e15jvr				charset = parseCharset(numGlyphs, file, parent.strings, isCID, format)
7944756b3a04014645ee16a14fb6273e93efa1c7e15jvr			else:
7954756b3a04014645ee16a14fb6273e93efa1c7e15jvr				raise NotImplementedError
7964756b3a04014645ee16a14fb6273e93efa1c7e15jvr			assert len(charset) == numGlyphs
797f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			if DEBUG:
7983ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod				print("    charset end at %s" % file.tell())
799c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr		else: # offset == 0 -> no charset data.
800bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod			if isCID or "CharStrings" not in parent.rawDict:
801c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr				assert value == 0 # We get here only when processing fontDicts from the FDArray of CFF-CID fonts. Only the real topDict references the chrset.
8024756b3a04014645ee16a14fb6273e93efa1c7e15jvr				charset = None
8034756b3a04014645ee16a14fb6273e93efa1c7e15jvr			elif value == 0:
804c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr				charset = cffISOAdobeStrings
8054756b3a04014645ee16a14fb6273e93efa1c7e15jvr			elif value == 1:
806c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr				charset = cffIExpertStrings
8074756b3a04014645ee16a14fb6273e93efa1c7e15jvr			elif value == 2:
808c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr				charset = cffExpertSubsetStrings
8094756b3a04014645ee16a14fb6273e93efa1c7e15jvr		return charset
810c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr
811f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def write(self, parent, value):
812f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return 0  # dummy value
8137ce0a139ab67dd30614e728a1ef897e53ad805aejvr	def xmlWrite(self, xmlWriter, name, value, progress):
8144e5af60930726d06a58a30bae45bb27ae50aea77jvr		# XXX only write charset when not in OT/TTX context, where we
8154e5af60930726d06a58a30bae45bb27ae50aea77jvr		# dump charset as a separate "GlyphOrder" table.
8164e5af60930726d06a58a30bae45bb27ae50aea77jvr		##xmlWriter.simpletag("charset")
8174e5af60930726d06a58a30bae45bb27ae50aea77jvr		xmlWriter.comment("charset is dumped separately as the 'GlyphOrder' element")
8184756b3a04014645ee16a14fb6273e93efa1c7e15jvr		xmlWriter.newline()
8193a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def xmlRead(self, name, attrs, content, parent):
8204e5af60930726d06a58a30bae45bb27ae50aea77jvr		if 0:
8214e5af60930726d06a58a30bae45bb27ae50aea77jvr			return safeEval(attrs["value"])
8227842e56b97ce677b83bdab09cda48bc2d89ac75aJust
8237842e56b97ce677b83bdab09cda48bc2d89ac75aJust
824e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass CharsetCompiler(object):
825f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
826f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def __init__(self, strings, charset, parent):
827f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		assert charset[0] == '.notdef'
828ed10151701a7d22e5ff4e06766edff59bd713c89jvr		isCID = hasattr(parent.dictObj, "ROS")
829ed10151701a7d22e5ff4e06766edff59bd713c89jvr		data0 = packCharset0(charset, isCID, strings)
830ed10151701a7d22e5ff4e06766edff59bd713c89jvr		data = packCharset(charset, isCID, strings)
8316004bafc1f6654e45283d01a9c1141f89cdeec3fjvr		if len(data) < len(data0):
8326004bafc1f6654e45283d01a9c1141f89cdeec3fjvr			self.data = data
8336004bafc1f6654e45283d01a9c1141f89cdeec3fjvr		else:
8346004bafc1f6654e45283d01a9c1141f89cdeec3fjvr			self.data = data0
835f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.parent = parent
836f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
8374e5af60930726d06a58a30bae45bb27ae50aea77jvr	def setPos(self, pos, endPos):
838f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.parent.rawDict["charset"] = pos
839f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
840f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getDataLength(self):
841f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return len(self.data)
842f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
843f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def toFile(self, file):
844f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		file.write(self.data)
845f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
846f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
847ed10151701a7d22e5ff4e06766edff59bd713c89jvrdef getCIDfromName(name, strings):
848ed10151701a7d22e5ff4e06766edff59bd713c89jvr	return int(name[3:])
849ed10151701a7d22e5ff4e06766edff59bd713c89jvr
850ed10151701a7d22e5ff4e06766edff59bd713c89jvrdef getSIDfromName(name, strings):
851ed10151701a7d22e5ff4e06766edff59bd713c89jvr	return strings.getSID(name)
852ed10151701a7d22e5ff4e06766edff59bd713c89jvr
853ed10151701a7d22e5ff4e06766edff59bd713c89jvrdef packCharset0(charset, isCID, strings):
854153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	fmt = 0
855153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	data = [packCard8(fmt)]
856ed10151701a7d22e5ff4e06766edff59bd713c89jvr	if isCID:
857ed10151701a7d22e5ff4e06766edff59bd713c89jvr		getNameID = getCIDfromName
858ed10151701a7d22e5ff4e06766edff59bd713c89jvr	else:
859ed10151701a7d22e5ff4e06766edff59bd713c89jvr		getNameID = getSIDfromName
860ed10151701a7d22e5ff4e06766edff59bd713c89jvr
8616004bafc1f6654e45283d01a9c1141f89cdeec3fjvr	for name in charset[1:]:
862ed10151701a7d22e5ff4e06766edff59bd713c89jvr		data.append(packCard16(getNameID(name,strings)))
86318316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod	return bytesjoin(data)
8646004bafc1f6654e45283d01a9c1141f89cdeec3fjvr
865ed10151701a7d22e5ff4e06766edff59bd713c89jvr
866ed10151701a7d22e5ff4e06766edff59bd713c89jvrdef packCharset(charset, isCID, strings):
867153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	fmt = 1
8686004bafc1f6654e45283d01a9c1141f89cdeec3fjvr	ranges = []
8696004bafc1f6654e45283d01a9c1141f89cdeec3fjvr	first = None
8706004bafc1f6654e45283d01a9c1141f89cdeec3fjvr	end = 0
871ed10151701a7d22e5ff4e06766edff59bd713c89jvr	if isCID:
872ed10151701a7d22e5ff4e06766edff59bd713c89jvr		getNameID = getCIDfromName
873ed10151701a7d22e5ff4e06766edff59bd713c89jvr	else:
874ed10151701a7d22e5ff4e06766edff59bd713c89jvr		getNameID = getSIDfromName
875ed10151701a7d22e5ff4e06766edff59bd713c89jvr
8766004bafc1f6654e45283d01a9c1141f89cdeec3fjvr	for name in charset[1:]:
877ed10151701a7d22e5ff4e06766edff59bd713c89jvr		SID = getNameID(name, strings)
8786004bafc1f6654e45283d01a9c1141f89cdeec3fjvr		if first is None:
8796004bafc1f6654e45283d01a9c1141f89cdeec3fjvr			first = SID
880180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod		elif end + 1 != SID:
8816004bafc1f6654e45283d01a9c1141f89cdeec3fjvr			nLeft = end - first
8826004bafc1f6654e45283d01a9c1141f89cdeec3fjvr			if nLeft > 255:
883153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod				fmt = 2
8846004bafc1f6654e45283d01a9c1141f89cdeec3fjvr			ranges.append((first, nLeft))
8856004bafc1f6654e45283d01a9c1141f89cdeec3fjvr			first = SID
8866004bafc1f6654e45283d01a9c1141f89cdeec3fjvr		end = SID
8876004bafc1f6654e45283d01a9c1141f89cdeec3fjvr	nLeft = end - first
8886004bafc1f6654e45283d01a9c1141f89cdeec3fjvr	if nLeft > 255:
889153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod		fmt = 2
8906004bafc1f6654e45283d01a9c1141f89cdeec3fjvr	ranges.append((first, nLeft))
8916004bafc1f6654e45283d01a9c1141f89cdeec3fjvr
892153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	data = [packCard8(fmt)]
893153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	if fmt == 1:
8946004bafc1f6654e45283d01a9c1141f89cdeec3fjvr		nLeftFunc = packCard8
8956004bafc1f6654e45283d01a9c1141f89cdeec3fjvr	else:
8966004bafc1f6654e45283d01a9c1141f89cdeec3fjvr		nLeftFunc = packCard16
8976004bafc1f6654e45283d01a9c1141f89cdeec3fjvr	for first, nLeft in ranges:
8986004bafc1f6654e45283d01a9c1141f89cdeec3fjvr		data.append(packCard16(first) + nLeftFunc(nLeft))
89918316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod	return bytesjoin(data)
9006004bafc1f6654e45283d01a9c1141f89cdeec3fjvr
901c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrdef parseCharset0(numGlyphs, file, strings, isCID):
902f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	charset = [".notdef"]
903c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr	if isCID:
904c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr		for i in range(numGlyphs - 1):
905c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr			CID = readCard16(file)
90614fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod			charset.append("cid" + str(CID).zfill(5))
907c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr	else:
908c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr		for i in range(numGlyphs - 1):
909c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr			SID = readCard16(file)
910c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr			charset.append(strings[SID])
911f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	return charset
912f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
913153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahboddef parseCharset(numGlyphs, file, strings, isCID, fmt):
914a2a75b348da46073cdd1dea50915384eabfff7c9jvr	charset = ['.notdef']
9157842e56b97ce677b83bdab09cda48bc2d89ac75aJust	count = 1
916153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	if fmt == 1:
917a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		nLeftFunc = readCard8
9184756b3a04014645ee16a14fb6273e93efa1c7e15jvr	else:
919a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		nLeftFunc = readCard16
9204756b3a04014645ee16a14fb6273e93efa1c7e15jvr	while count < numGlyphs:
921a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		first = readCard16(file)
9224756b3a04014645ee16a14fb6273e93efa1c7e15jvr		nLeft = nLeftFunc(file)
923a2a75b348da46073cdd1dea50915384eabfff7c9jvr		if isCID:
924a2a75b348da46073cdd1dea50915384eabfff7c9jvr			for CID in range(first, first+nLeft+1):
92514fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod				charset.append("cid" + str(CID).zfill(5))
926a2a75b348da46073cdd1dea50915384eabfff7c9jvr		else:
927a2a75b348da46073cdd1dea50915384eabfff7c9jvr			for SID in range(first, first+nLeft+1):
928a2a75b348da46073cdd1dea50915384eabfff7c9jvr				charset.append(strings[SID])
9297842e56b97ce677b83bdab09cda48bc2d89ac75aJust		count = count + nLeft + 1
930a2a75b348da46073cdd1dea50915384eabfff7c9jvr	return charset
9317842e56b97ce677b83bdab09cda48bc2d89ac75aJust
9327842e56b97ce677b83bdab09cda48bc2d89ac75aJust
933e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass EncodingCompiler(object):
934b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
935b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	def __init__(self, strings, encoding, parent):
9362a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr		assert not isinstance(encoding, basestring)
937b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		data0 = packEncoding0(parent.dictObj.charset, encoding, parent.strings)
938b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		data1 = packEncoding1(parent.dictObj.charset, encoding, parent.strings)
939b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		if len(data0) < len(data1):
940b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			self.data = data0
941b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		else:
942b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			self.data = data1
943b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		self.parent = parent
944b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
945b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	def setPos(self, pos, endPos):
946b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		self.parent.rawDict["Encoding"] = pos
947b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
948b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	def getDataLength(self):
949b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		return len(self.data)
950b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
951b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	def toFile(self, file):
952b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		file.write(self.data)
953b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
954b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
955b9702ba0f1d86307752ed7d593d59e923c8d4054jvrclass EncodingConverter(SimpleConverter):
956b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
957b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	def read(self, parent, value):
958b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		if value == 0:
959b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			return "StandardEncoding"
960b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		elif value == 1:
961b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			return "ExpertEncoding"
962b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		else:
963b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			assert value > 1
964b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			file = parent.file
965b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			file.seek(value)
966b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			if DEBUG:
9673ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod				print("loading Encoding at %s" % value)
968153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod			fmt = readCard8(file)
969153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod			haveSupplement = fmt & 0x80
970b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			if haveSupplement:
971cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod				raise NotImplementedError("Encoding supplements are not yet supported")
972153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod			fmt = fmt & 0x7f
973153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod			if fmt == 0:
974b9702ba0f1d86307752ed7d593d59e923c8d4054jvr				encoding = parseEncoding0(parent.charset, file, haveSupplement,
975b9702ba0f1d86307752ed7d593d59e923c8d4054jvr						parent.strings)
976153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod			elif fmt == 1:
977b9702ba0f1d86307752ed7d593d59e923c8d4054jvr				encoding = parseEncoding1(parent.charset, file, haveSupplement,
978b9702ba0f1d86307752ed7d593d59e923c8d4054jvr						parent.strings)
979b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			return encoding
980b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
981b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	def write(self, parent, value):
982b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		if value == "StandardEncoding":
983b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			return 0
984b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		elif value == "ExpertEncoding":
985b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			return 1
986b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		return 0  # dummy value
987b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
988b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	def xmlWrite(self, xmlWriter, name, value, progress):
989b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		if value in ("StandardEncoding", "ExpertEncoding"):
990b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			xmlWriter.simpletag(name, name=value)
991b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			xmlWriter.newline()
992b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			return
993b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		xmlWriter.begintag(name)
994b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		xmlWriter.newline()
995b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		for code in range(len(value)):
996b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			glyphName = value[code]
997b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			if glyphName != ".notdef":
998b9702ba0f1d86307752ed7d593d59e923c8d4054jvr				xmlWriter.simpletag("map", code=hex(code), name=glyphName)
999b9702ba0f1d86307752ed7d593d59e923c8d4054jvr				xmlWriter.newline()
1000b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		xmlWriter.endtag(name)
1001b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		xmlWriter.newline()
1002b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
10033a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def xmlRead(self, name, attrs, content, parent):
1004bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod		if "name" in attrs:
1005b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			return attrs["name"]
1006b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		encoding = [".notdef"] * 256
1007b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		for element in content:
10082a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr			if isinstance(element, basestring):
1009b9702ba0f1d86307752ed7d593d59e923c8d4054jvr				continue
1010b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			name, attrs, content = element
1011b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			code = safeEval(attrs["code"])
1012b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			glyphName = attrs["name"]
1013b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			encoding[code] = glyphName
1014b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		return encoding
1015b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
1016b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
1017b9702ba0f1d86307752ed7d593d59e923c8d4054jvrdef parseEncoding0(charset, file, haveSupplement, strings):
1018b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	nCodes = readCard8(file)
1019b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	encoding = [".notdef"] * 256
1020b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	for glyphID in range(1, nCodes + 1):
1021b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		code = readCard8(file)
1022b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		if code != 0:
1023b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			encoding[code] = charset[glyphID]
1024b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	return encoding
1025b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
1026b9702ba0f1d86307752ed7d593d59e923c8d4054jvrdef parseEncoding1(charset, file, haveSupplement, strings):
1027b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	nRanges = readCard8(file)
1028b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	encoding = [".notdef"] * 256
1029b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	glyphID = 1
1030b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	for i in range(nRanges):
1031b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		code = readCard8(file)
1032b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		nLeft = readCard8(file)
1033b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		for glyphID in range(glyphID, glyphID + nLeft + 1):
1034b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			encoding[code] = charset[glyphID]
1035b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			code = code + 1
1036b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		glyphID = glyphID + 1
1037b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	return encoding
1038b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
1039b9702ba0f1d86307752ed7d593d59e923c8d4054jvrdef packEncoding0(charset, encoding, strings):
1040153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	fmt = 0
1041b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	m = {}
1042b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	for code in range(len(encoding)):
1043b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		name = encoding[code]
1044b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		if name != ".notdef":
1045b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			m[name] = code
1046b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	codes = []
1047b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	for name in charset[1:]:
1048b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		code = m.get(name)
1049b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		codes.append(code)
1050b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
1051b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	while codes and codes[-1] is None:
1052b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		codes.pop()
1053b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
1054153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	data = [packCard8(fmt), packCard8(len(codes))]
1055b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	for code in codes:
1056b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		if code is None:
1057b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			code = 0
1058b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		data.append(packCard8(code))
105918316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod	return bytesjoin(data)
1060b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
1061b9702ba0f1d86307752ed7d593d59e923c8d4054jvrdef packEncoding1(charset, encoding, strings):
1062153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	fmt = 1
1063b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	m = {}
1064b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	for code in range(len(encoding)):
1065b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		name = encoding[code]
1066b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		if name != ".notdef":
1067b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			m[name] = code
1068b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	ranges = []
1069b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	first = None
1070b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	end = 0
1071b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	for name in charset[1:]:
1072b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		code = m.get(name, -1)
1073b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		if first is None:
1074b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			first = code
1075180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod		elif end + 1 != code:
1076b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			nLeft = end - first
1077b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			ranges.append((first, nLeft))
1078b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			first = code
1079b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		end = code
1080b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	nLeft = end - first
1081b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	ranges.append((first, nLeft))
1082b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
1083b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	# remove unencoded glyphs at the end.
1084b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	while ranges and ranges[-1][0] == -1:
1085b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		ranges.pop()
1086b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
1087153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	data = [packCard8(fmt), packCard8(len(ranges))]
1088b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	for first, nLeft in ranges:
1089b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		if first == -1:  # unencoded
1090b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			first = 0
1091b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		data.append(packCard8(first) + packCard8(nLeft))
109218316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod	return bytesjoin(data)
1093b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
1094b9702ba0f1d86307752ed7d593d59e923c8d4054jvr
10954e5af60930726d06a58a30bae45bb27ae50aea77jvrclass FDArrayConverter(TableConverter):
1096ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1097a2ad5447fb707448d2c442b16956f87e048ef0d1jvr	def read(self, parent, value):
1098a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		file = parent.file
1099a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		file.seek(value)
1100ed10151701a7d22e5ff4e06766edff59bd713c89jvr		fdArray = FDArrayIndex(file)
1101a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		fdArray.strings = parent.strings
1102a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		fdArray.GlobalSubrs = parent.GlobalSubrs
1103a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		return fdArray
1104a2ad5447fb707448d2c442b16956f87e048ef0d1jvr
1105ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def write(self, parent, value):
1106ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return 0  # dummy value
1107ed10151701a7d22e5ff4e06766edff59bd713c89jvr
11083a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def xmlRead(self, name, attrs, content, parent):
1109ed10151701a7d22e5ff4e06766edff59bd713c89jvr		fdArray = FDArrayIndex()
1110ed10151701a7d22e5ff4e06766edff59bd713c89jvr		for element in content:
11112a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr			if isinstance(element, basestring):
1112ed10151701a7d22e5ff4e06766edff59bd713c89jvr				continue
11133a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod			name, attrs, content = element
11143a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod			fdArray.fromXML(name, attrs, content)
1115ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return fdArray
1116ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1117a2ad5447fb707448d2c442b16956f87e048ef0d1jvr
1118e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass FDSelectConverter(object):
1119ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1120a2ad5447fb707448d2c442b16956f87e048ef0d1jvr	def read(self, parent, value):
1121a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		file = parent.file
1122a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		file.seek(value)
1123ed10151701a7d22e5ff4e06766edff59bd713c89jvr		fdSelect = FDSelect(file, parent.numGlyphs)
1124ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return 	fdSelect
1125ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1126ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def write(self, parent, value):
1127ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return 0  # dummy value
1128ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1129ed10151701a7d22e5ff4e06766edff59bd713c89jvr	# The FDSelect glyph data is written out to XML in the charstring keys,
1130ed10151701a7d22e5ff4e06766edff59bd713c89jvr	# so we write out only the format selector
1131ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def xmlWrite(self, xmlWriter, name, value, progress):
1132ed10151701a7d22e5ff4e06766edff59bd713c89jvr		xmlWriter.simpletag(name, [('format', value.format)])
1133ed10151701a7d22e5ff4e06766edff59bd713c89jvr		xmlWriter.newline()
1134ed10151701a7d22e5ff4e06766edff59bd713c89jvr
11353a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def xmlRead(self, name, attrs, content, parent):
1136153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod		fmt = safeEval(attrs["format"])
1137ed10151701a7d22e5ff4e06766edff59bd713c89jvr		file = None
1138ed10151701a7d22e5ff4e06766edff59bd713c89jvr		numGlyphs = None
1139153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod		fdSelect = FDSelect(file, numGlyphs, fmt)
1140ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return fdSelect
1141ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1142ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1143ed10151701a7d22e5ff4e06766edff59bd713c89jvrdef packFDSelect0(fdSelectArray):
1144153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	fmt = 0
1145153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	data = [packCard8(fmt)]
1146ed10151701a7d22e5ff4e06766edff59bd713c89jvr	for index in fdSelectArray:
1147ed10151701a7d22e5ff4e06766edff59bd713c89jvr		data.append(packCard8(index))
114818316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod	return bytesjoin(data)
1149ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1150ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1151ed10151701a7d22e5ff4e06766edff59bd713c89jvrdef packFDSelect3(fdSelectArray):
1152153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	fmt = 3
1153ed10151701a7d22e5ff4e06766edff59bd713c89jvr	fdRanges = []
1154ed10151701a7d22e5ff4e06766edff59bd713c89jvr	first = None
1155ed10151701a7d22e5ff4e06766edff59bd713c89jvr	end = 0
1156ed10151701a7d22e5ff4e06766edff59bd713c89jvr	lenArray = len(fdSelectArray)
1157ed10151701a7d22e5ff4e06766edff59bd713c89jvr	lastFDIndex = -1
1158ed10151701a7d22e5ff4e06766edff59bd713c89jvr	for i in range(lenArray):
1159ed10151701a7d22e5ff4e06766edff59bd713c89jvr		fdIndex = fdSelectArray[i]
1160ed10151701a7d22e5ff4e06766edff59bd713c89jvr		if lastFDIndex != fdIndex:
1161ed10151701a7d22e5ff4e06766edff59bd713c89jvr			fdRanges.append([i, fdIndex])
1162ed10151701a7d22e5ff4e06766edff59bd713c89jvr			lastFDIndex = fdIndex
1163ed10151701a7d22e5ff4e06766edff59bd713c89jvr	sentinelGID = i + 1
1164ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1165153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	data = [packCard8(fmt)]
1166ed10151701a7d22e5ff4e06766edff59bd713c89jvr	data.append(packCard16( len(fdRanges) ))
1167ed10151701a7d22e5ff4e06766edff59bd713c89jvr	for fdRange in fdRanges:
1168ed10151701a7d22e5ff4e06766edff59bd713c89jvr		data.append(packCard16(fdRange[0]))
1169ed10151701a7d22e5ff4e06766edff59bd713c89jvr		data.append(packCard8(fdRange[1]))
1170ed10151701a7d22e5ff4e06766edff59bd713c89jvr	data.append(packCard16(sentinelGID))
117118316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod	return bytesjoin(data)
1172ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1173ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1174e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass FDSelectCompiler(object):
1175ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1176ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def __init__(self, fdSelect, parent):
1177153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod		fmt = fdSelect.format
1178ed10151701a7d22e5ff4e06766edff59bd713c89jvr		fdSelectArray = fdSelect.gidArray
1179153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod		if fmt == 0:
1180ed10151701a7d22e5ff4e06766edff59bd713c89jvr			self.data = packFDSelect0(fdSelectArray)
1181153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod		elif fmt == 3:
1182ed10151701a7d22e5ff4e06766edff59bd713c89jvr			self.data = packFDSelect3(fdSelectArray)
1183a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		else:
1184ed10151701a7d22e5ff4e06766edff59bd713c89jvr			# choose smaller of the two formats
1185ed10151701a7d22e5ff4e06766edff59bd713c89jvr			data0 = packFDSelect0(fdSelectArray)
1186ed10151701a7d22e5ff4e06766edff59bd713c89jvr			data3 = packFDSelect3(fdSelectArray)
1187ed10151701a7d22e5ff4e06766edff59bd713c89jvr			if len(data0) < len(data3):
1188ed10151701a7d22e5ff4e06766edff59bd713c89jvr				self.data = data0
1189ed10151701a7d22e5ff4e06766edff59bd713c89jvr				fdSelect.format = 0
1190ed10151701a7d22e5ff4e06766edff59bd713c89jvr			else:
1191ed10151701a7d22e5ff4e06766edff59bd713c89jvr				self.data = data3
1192ed10151701a7d22e5ff4e06766edff59bd713c89jvr				fdSelect.format = 3
1193ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1194ed10151701a7d22e5ff4e06766edff59bd713c89jvr		self.parent = parent
1195ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1196ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def setPos(self, pos, endPos):
1197ed10151701a7d22e5ff4e06766edff59bd713c89jvr		self.parent.rawDict["FDSelect"] = pos
1198ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1199ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def getDataLength(self):
1200ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return len(self.data)
1201ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1202ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def toFile(self, file):
1203ed10151701a7d22e5ff4e06766edff59bd713c89jvr		file.write(self.data)
1204a2ad5447fb707448d2c442b16956f87e048ef0d1jvr
1205a2ad5447fb707448d2c442b16956f87e048ef0d1jvr
12064e5af60930726d06a58a30bae45bb27ae50aea77jvrclass ROSConverter(SimpleConverter):
1207ed10151701a7d22e5ff4e06766edff59bd713c89jvr
12087ce0a139ab67dd30614e728a1ef897e53ad805aejvr	def xmlWrite(self, xmlWriter, name, value, progress):
1209155aa7569f9d18fda270434f38642cfffdca4873jvr		registry, order, supplement = value
1210024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod		xmlWriter.simpletag(name, [('Registry', tostr(registry)), ('Order', tostr(order)),
1211f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			('Supplement', supplement)])
12124afb2573876b6ad2ee03fc696cb045e8d1ddb237jvr		xmlWriter.newline()
1213155aa7569f9d18fda270434f38642cfffdca4873jvr
12143a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def xmlRead(self, name, attrs, content, parent):
1215ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return (attrs['Registry'], attrs['Order'], safeEval(attrs['Supplement']))
1216ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1217ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1218155aa7569f9d18fda270434f38642cfffdca4873jvr
12194756b3a04014645ee16a14fb6273e93efa1c7e15jvrtopDictOperators = [
12204756b3a04014645ee16a14fb6273e93efa1c7e15jvr#	opcode     name                  argument type   default    converter
1221155aa7569f9d18fda270434f38642cfffdca4873jvr	((12, 30), 'ROS',        ('SID','SID','number'), None,      ROSConverter()),
1222f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	((12, 20), 'SyntheticBase',      'number',       None,      None),
12234756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(0,        'version',            'SID',          None,      None),
1224e2ca9b5a4ff537ad827c3f722c8137b4f986d9a5jvr	(1,        'Notice',             'SID',          None,      Latin1Converter()),
1225e2ca9b5a4ff537ad827c3f722c8137b4f986d9a5jvr	((12, 0),  'Copyright',          'SID',          None,      Latin1Converter()),
12264756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(2,        'FullName',           'SID',          None,      None),
1227155aa7569f9d18fda270434f38642cfffdca4873jvr	((12, 38), 'FontName',           'SID',          None,      None),
12284756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(3,        'FamilyName',         'SID',          None,      None),
12294756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(4,        'Weight',             'SID',          None,      None),
12304756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 1),  'isFixedPitch',       'number',       0,         None),
12314756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 2),  'ItalicAngle',        'number',       0,         None),
12324756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 3),  'UnderlinePosition',  'number',       None,      None),
12334756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 4),  'UnderlineThickness', 'number',       50,        None),
12344756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 5),  'PaintType',          'number',       0,         None),
12354756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 6),  'CharstringType',     'number',       2,         None),
12364756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 7),  'FontMatrix',         'array',  [0.001,0,0,0.001,0,0],  None),
12374756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(13,       'UniqueID',           'number',       None,      None),
12384756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(5,        'FontBBox',           'array',  [0,0,0,0],       None),
12394756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 8),  'StrokeWidth',        'number',       0,         None),
12404756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(14,       'XUID',               'array',        None,      None),
12414756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 21), 'PostScript',         'SID',          None,      None),
12424756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 22), 'BaseFontName',       'SID',          None,      None),
12434756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 23), 'BaseFontBlend',      'delta',        None,      None),
12444756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 31), 'CIDFontVersion',     'number',       0,         None),
12454756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 32), 'CIDFontRevision',    'number',       0,         None),
12464756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 33), 'CIDFontType',        'number',       0,         None),
12474756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 34), 'CIDCount',           'number',       8720,      None),
1248ed10151701a7d22e5ff4e06766edff59bd713c89jvr	(15,       'charset',            'number',       0,         CharsetConverter()),
12494756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 35), 'UIDBase',            'number',       None,      None),
1250b9702ba0f1d86307752ed7d593d59e923c8d4054jvr	(16,       'Encoding',           'number',       0,         EncodingConverter()),
1251155aa7569f9d18fda270434f38642cfffdca4873jvr	(18,       'Private',       ('number','number'), None,      PrivateDictConverter()),
1252ed10151701a7d22e5ff4e06766edff59bd713c89jvr	((12, 37), 'FDSelect',           'number',       None,      FDSelectConverter()),
1253ed10151701a7d22e5ff4e06766edff59bd713c89jvr	((12, 36), 'FDArray',            'number',       None,      FDArrayConverter()),
1254155aa7569f9d18fda270434f38642cfffdca4873jvr	(17,       'CharStrings',        'number',       None,      CharStringsConverter()),
12554756b3a04014645ee16a14fb6273e93efa1c7e15jvr]
12561890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
1257ed10151701a7d22e5ff4e06766edff59bd713c89jvr# Note! FDSelect and FDArray must both preceed CharStrings in the output XML build order,
1258ed10151701a7d22e5ff4e06766edff59bd713c89jvr# in order for the font to compile back from xml.
1259ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1260ed10151701a7d22e5ff4e06766edff59bd713c89jvr
12614756b3a04014645ee16a14fb6273e93efa1c7e15jvrprivateDictOperators = [
12624756b3a04014645ee16a14fb6273e93efa1c7e15jvr#	opcode     name                  argument type   default    converter
12634756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(6,        'BlueValues',         'delta',        None,      None),
12644756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(7,        'OtherBlues',         'delta',        None,      None),
12654756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(8,        'FamilyBlues',        'delta',        None,      None),
12664756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(9,        'FamilyOtherBlues',   'delta',        None,      None),
12674756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 9),  'BlueScale',          'number',       0.039625,  None),
12684756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 10), 'BlueShift',          'number',       7,         None),
12694756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 11), 'BlueFuzz',           'number',       1,         None),
12704756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(10,       'StdHW',              'number',       None,      None),
12714756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(11,       'StdVW',              'number',       None,      None),
12724756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 12), 'StemSnapH',          'delta',        None,      None),
12734756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 13), 'StemSnapV',          'delta',        None,      None),
12744756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 14), 'ForceBold',          'number',       0,         None),
1275f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	((12, 15), 'ForceBoldThreshold', 'number',       None,      None),  # deprecated
1276f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	((12, 16), 'lenIV',              'number',       None,      None),  # deprecated
12774756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 17), 'LanguageGroup',      'number',       0,         None),
12784756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 18), 'ExpansionFactor',    'number',       0.06,      None),
12794756b3a04014645ee16a14fb6273e93efa1c7e15jvr	((12, 19), 'initialRandomSeed',  'number',       0,         None),
12804756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(20,       'defaultWidthX',      'number',       0,         None),
12814756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(21,       'nominalWidthX',      'number',       0,         None),
12824756b3a04014645ee16a14fb6273e93efa1c7e15jvr	(19,       'Subrs',              'number',       None,      SubrsConverter()),
12834756b3a04014645ee16a14fb6273e93efa1c7e15jvr]
12841890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
12854e5af60930726d06a58a30bae45bb27ae50aea77jvrdef addConverters(table):
12864e5af60930726d06a58a30bae45bb27ae50aea77jvr	for i in range(len(table)):
12874e5af60930726d06a58a30bae45bb27ae50aea77jvr		op, name, arg, default, conv = table[i]
12884e5af60930726d06a58a30bae45bb27ae50aea77jvr		if conv is not None:
12894e5af60930726d06a58a30bae45bb27ae50aea77jvr			continue
12904e5af60930726d06a58a30bae45bb27ae50aea77jvr		if arg in ("delta", "array"):
12914e5af60930726d06a58a30bae45bb27ae50aea77jvr			conv = ArrayConverter()
12924e5af60930726d06a58a30bae45bb27ae50aea77jvr		elif arg == "number":
12934e5af60930726d06a58a30bae45bb27ae50aea77jvr			conv = NumberConverter()
12944e5af60930726d06a58a30bae45bb27ae50aea77jvr		elif arg == "SID":
1295024d15317fabfe6af5dbfe69a3c26badea6018eeBehdad Esfahbod			conv = ASCIIConverter()
12964e5af60930726d06a58a30bae45bb27ae50aea77jvr		else:
1297153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod			assert False
12984e5af60930726d06a58a30bae45bb27ae50aea77jvr		table[i] = op, name, arg, default, conv
12994e5af60930726d06a58a30bae45bb27ae50aea77jvr
13004e5af60930726d06a58a30bae45bb27ae50aea77jvraddConverters(privateDictOperators)
13014e5af60930726d06a58a30bae45bb27ae50aea77jvraddConverters(topDictOperators)
13024e5af60930726d06a58a30bae45bb27ae50aea77jvr
13031890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
13044756b3a04014645ee16a14fb6273e93efa1c7e15jvrclass TopDictDecompiler(psCharStrings.DictDecompiler):
13054756b3a04014645ee16a14fb6273e93efa1c7e15jvr	operators = buildOperatorDict(topDictOperators)
13061890b953f09bf6dcf84e5fbc0bdaf3f485d3a52djvr
1307e327558aa54f182912a26b8313f3af5a07bc2e77jvr
13084756b3a04014645ee16a14fb6273e93efa1c7e15jvrclass PrivateDictDecompiler(psCharStrings.DictDecompiler):
13094756b3a04014645ee16a14fb6273e93efa1c7e15jvr	operators = buildOperatorDict(privateDictOperators)
1310e327558aa54f182912a26b8313f3af5a07bc2e77jvr
13114756b3a04014645ee16a14fb6273e93efa1c7e15jvr
1312e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass DictCompiler(object):
1313f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1314f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def __init__(self, dictObj, strings, parent):
1315f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		assert isinstance(strings, IndexedStrings)
1316f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.dictObj = dictObj
1317f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.strings = strings
1318f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.parent = parent
1319f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		rawDict = {}
1320f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for name in dictObj.order:
1321f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			value = getattr(dictObj, name, None)
1322f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			if value is None:
1323f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				continue
1324f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			conv = dictObj.converters[name]
13254e5af60930726d06a58a30bae45bb27ae50aea77jvr			value = conv.write(dictObj, value)
1326f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			if value == dictObj.defaults.get(name):
1327f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				continue
1328f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			rawDict[name] = value
1329f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.rawDict = rawDict
1330f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
13314e5af60930726d06a58a30bae45bb27ae50aea77jvr	def setPos(self, pos, endPos):
1332f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		pass
1333f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1334f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getDataLength(self):
13354e5af60930726d06a58a30bae45bb27ae50aea77jvr		return len(self.compile("getDataLength"))
1336f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
13374e5af60930726d06a58a30bae45bb27ae50aea77jvr	def compile(self, reason):
13384e5af60930726d06a58a30bae45bb27ae50aea77jvr		if DEBUG:
13393ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod			print("-- compiling %s for %s" % (self.__class__.__name__, reason))
13403ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod			print("in baseDict: ", self)
1341f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		rawDict = self.rawDict
1342f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		data = []
1343f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for name in self.dictObj.order:
1344f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			value = rawDict.get(name)
1345f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			if value is None:
1346f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				continue
1347f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			op, argType = self.opcodes[name]
13482a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr			if isinstance(argType, tuple):
1349f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				l = len(argType)
1350f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				assert len(value) == l, "value doesn't match arg type"
1351f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				for i in range(l):
1352ed10151701a7d22e5ff4e06766edff59bd713c89jvr					arg = argType[i]
1353f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr					v = value[i]
1354f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr					arghandler = getattr(self, "arg_" + arg)
1355f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr					data.append(arghandler(v))
1356f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			else:
1357f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				arghandler = getattr(self, "arg_" + argType)
1358f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				data.append(arghandler(value))
1359f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			data.append(op)
136018316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod		return bytesjoin(data)
1361f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1362f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def toFile(self, file):
13634e5af60930726d06a58a30bae45bb27ae50aea77jvr		file.write(self.compile("toFile"))
1364f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1365f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def arg_number(self, num):
1366f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return encodeNumber(num)
1367f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def arg_SID(self, s):
1368f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return psCharStrings.encodeIntCFF(self.strings.getSID(s))
1369f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def arg_array(self, value):
1370f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		data = []
1371f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for num in value:
1372f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			data.append(encodeNumber(num))
137318316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod		return bytesjoin(data)
1374f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def arg_delta(self, value):
1375f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		out = []
1376f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		last = 0
1377f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for v in value:
1378f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			out.append(v - last)
1379f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			last = v
1380f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		data = []
1381f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		for num in out:
1382f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			data.append(encodeNumber(num))
138318316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod		return bytesjoin(data)
1384f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1385f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1386f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef encodeNumber(num):
1387f6ff48be3c858d7c4f942e1d4f062120c2e376e0jvr	if isinstance(num, float):
1388f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return psCharStrings.encodeFloat(num)
1389f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	else:
1390f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return psCharStrings.encodeIntCFF(num)
1391f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1392f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1393f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass TopDictCompiler(DictCompiler):
1394f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1395f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	opcodes = buildOpcodeDict(topDictOperators)
1396f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1397f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getChildren(self, strings):
1398f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		children = []
1399ed10151701a7d22e5ff4e06766edff59bd713c89jvr		if hasattr(self.dictObj, "charset") and self.dictObj.charset:
1400f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			children.append(CharsetCompiler(strings, self.dictObj.charset, self))
1401b9702ba0f1d86307752ed7d593d59e923c8d4054jvr		if hasattr(self.dictObj, "Encoding"):
1402b9702ba0f1d86307752ed7d593d59e923c8d4054jvr			encoding = self.dictObj.Encoding
14032a9bcde369fbcdc1258c11aa1b03633bf39653b4jvr			if not isinstance(encoding, basestring):
1404b9702ba0f1d86307752ed7d593d59e923c8d4054jvr				children.append(EncodingCompiler(strings, encoding, self))
1405ce522410f26648af01372cc96fe689cf3b3a7c84jvr		if hasattr(self.dictObj, "FDSelect"):
1406ed10151701a7d22e5ff4e06766edff59bd713c89jvr			# I have not yet supported merging a ttx CFF-CID font, as there are interesting
1407ed10151701a7d22e5ff4e06766edff59bd713c89jvr			# issues about merging the FDArrays. Here I assume that
1408ed10151701a7d22e5ff4e06766edff59bd713c89jvr			# either the font was read from XML, and teh FDSelect indices are all
1409ed10151701a7d22e5ff4e06766edff59bd713c89jvr			# in the charstring data, or the FDSelect array is already fully defined.
1410ed10151701a7d22e5ff4e06766edff59bd713c89jvr			fdSelect = self.dictObj.FDSelect
1411ed10151701a7d22e5ff4e06766edff59bd713c89jvr			if len(fdSelect) == 0: # probably read in from XML; assume fdIndex in CharString data
1412ed10151701a7d22e5ff4e06766edff59bd713c89jvr				charStrings = self.dictObj.CharStrings
1413ed10151701a7d22e5ff4e06766edff59bd713c89jvr				for name in self.dictObj.charset:
1414ed10151701a7d22e5ff4e06766edff59bd713c89jvr					fdSelect.append(charStrings[name].fdSelectIndex)
1415ed10151701a7d22e5ff4e06766edff59bd713c89jvr			fdSelectComp = FDSelectCompiler(fdSelect, self)
1416ed10151701a7d22e5ff4e06766edff59bd713c89jvr			children.append(fdSelectComp)
1417f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		if hasattr(self.dictObj, "CharStrings"):
1418f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			items = []
1419f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			charStrings = self.dictObj.CharStrings
1420f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			for name in self.dictObj.charset:
1421f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				items.append(charStrings[name])
1422f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			charStringsComp = CharStringsCompiler(items, strings, self)
1423f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			children.append(charStringsComp)
1424ce522410f26648af01372cc96fe689cf3b3a7c84jvr		if hasattr(self.dictObj, "FDArray"):
1425ed10151701a7d22e5ff4e06766edff59bd713c89jvr			# I have not yet supported merging a ttx CFF-CID font, as there are interesting
1426ed10151701a7d22e5ff4e06766edff59bd713c89jvr			# issues about merging the FDArrays. Here I assume that the FDArray info is correct
1427ed10151701a7d22e5ff4e06766edff59bd713c89jvr			# and complete.
1428ed10151701a7d22e5ff4e06766edff59bd713c89jvr			fdArrayIndexComp = self.dictObj.FDArray.getCompiler(strings, self)
1429ed10151701a7d22e5ff4e06766edff59bd713c89jvr			children.append(fdArrayIndexComp)
1430ed10151701a7d22e5ff4e06766edff59bd713c89jvr			children.extend(fdArrayIndexComp.getChildren(strings))
1431ed10151701a7d22e5ff4e06766edff59bd713c89jvr		if hasattr(self.dictObj, "Private"):
1432ed10151701a7d22e5ff4e06766edff59bd713c89jvr			privComp = self.dictObj.Private.getCompiler(strings, self)
1433ed10151701a7d22e5ff4e06766edff59bd713c89jvr			children.append(privComp)
1434ed10151701a7d22e5ff4e06766edff59bd713c89jvr			children.extend(privComp.getChildren(strings))
1435ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return children
1436ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1437ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1438ed10151701a7d22e5ff4e06766edff59bd713c89jvrclass FontDictCompiler(DictCompiler):
1439ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1440ed10151701a7d22e5ff4e06766edff59bd713c89jvr	opcodes = buildOpcodeDict(topDictOperators)
1441ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1442ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def getChildren(self, strings):
1443ed10151701a7d22e5ff4e06766edff59bd713c89jvr		children = []
1444f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		if hasattr(self.dictObj, "Private"):
1445f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			privComp = self.dictObj.Private.getCompiler(strings, self)
1446f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			children.append(privComp)
1447f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			children.extend(privComp.getChildren(strings))
1448f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return children
1449f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1450f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1451f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass PrivateDictCompiler(DictCompiler):
1452f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1453f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	opcodes = buildOpcodeDict(privateDictOperators)
1454f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
14554e5af60930726d06a58a30bae45bb27ae50aea77jvr	def setPos(self, pos, endPos):
14564e5af60930726d06a58a30bae45bb27ae50aea77jvr		size = endPos - pos
1457f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.parent.rawDict["Private"] = size, pos
1458f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.pos = pos
1459f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1460f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getChildren(self, strings):
1461f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		children = []
1462f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		if hasattr(self.dictObj, "Subrs"):
1463f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			children.append(self.dictObj.Subrs.getCompiler(strings, self))
1464f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return children
1465f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
14664756b3a04014645ee16a14fb6273e93efa1c7e15jvr
1467e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass BaseDict(object):
1468e327558aa54f182912a26b8313f3af5a07bc2e77jvr
14694e5af60930726d06a58a30bae45bb27ae50aea77jvr	def __init__(self, strings=None, file=None, offset=None):
14704756b3a04014645ee16a14fb6273e93efa1c7e15jvr		self.rawDict = {}
1471767102ea85a8af1535c169b2e04da5ba458f3b80jvr		if DEBUG:
14723ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod			print("loading %s at %s" % (self.__class__.__name__, offset))
14734756b3a04014645ee16a14fb6273e93efa1c7e15jvr		self.file = file
14744756b3a04014645ee16a14fb6273e93efa1c7e15jvr		self.offset = offset
14754756b3a04014645ee16a14fb6273e93efa1c7e15jvr		self.strings = strings
1476155aa7569f9d18fda270434f38642cfffdca4873jvr		self.skipNames = []
1477e327558aa54f182912a26b8313f3af5a07bc2e77jvr
14784756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def decompile(self, data):
1479f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		if DEBUG:
14803ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod			print("    length %s is %s" % (self.__class__.__name__, len(data)))
1481f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		dec = self.decompilerClass(self.strings)
14824756b3a04014645ee16a14fb6273e93efa1c7e15jvr		dec.decompile(data)
14834756b3a04014645ee16a14fb6273e93efa1c7e15jvr		self.rawDict = dec.getDict()
14844756b3a04014645ee16a14fb6273e93efa1c7e15jvr		self.postDecompile()
14854756b3a04014645ee16a14fb6273e93efa1c7e15jvr
14864756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def postDecompile(self):
14874756b3a04014645ee16a14fb6273e93efa1c7e15jvr		pass
14884756b3a04014645ee16a14fb6273e93efa1c7e15jvr
1489f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getCompiler(self, strings, parent):
1490f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return self.compilerClass(self, strings, parent)
1491f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
14924756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def __getattr__(self, name):
14934756b3a04014645ee16a14fb6273e93efa1c7e15jvr		value = self.rawDict.get(name)
14944756b3a04014645ee16a14fb6273e93efa1c7e15jvr		if value is None:
14954756b3a04014645ee16a14fb6273e93efa1c7e15jvr			value = self.defaults.get(name)
14964756b3a04014645ee16a14fb6273e93efa1c7e15jvr		if value is None:
1497cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod			raise AttributeError(name)
14984756b3a04014645ee16a14fb6273e93efa1c7e15jvr		conv = self.converters[name]
14994e5af60930726d06a58a30bae45bb27ae50aea77jvr		value = conv.read(self, value)
15004756b3a04014645ee16a14fb6273e93efa1c7e15jvr		setattr(self, name, value)
15014756b3a04014645ee16a14fb6273e93efa1c7e15jvr		return value
15024756b3a04014645ee16a14fb6273e93efa1c7e15jvr
15034756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def toXML(self, xmlWriter, progress):
15044756b3a04014645ee16a14fb6273e93efa1c7e15jvr		for name in self.order:
1505155aa7569f9d18fda270434f38642cfffdca4873jvr			if name in self.skipNames:
1506155aa7569f9d18fda270434f38642cfffdca4873jvr				continue
15074756b3a04014645ee16a14fb6273e93efa1c7e15jvr			value = getattr(self, name, None)
15084756b3a04014645ee16a14fb6273e93efa1c7e15jvr			if value is None:
15094756b3a04014645ee16a14fb6273e93efa1c7e15jvr				continue
15104e5af60930726d06a58a30bae45bb27ae50aea77jvr			conv = self.converters[name]
15117ce0a139ab67dd30614e728a1ef897e53ad805aejvr			conv.xmlWrite(xmlWriter, name, value, progress)
15124e5af60930726d06a58a30bae45bb27ae50aea77jvr
15133a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def fromXML(self, name, attrs, content):
15144e5af60930726d06a58a30bae45bb27ae50aea77jvr		conv = self.converters[name]
15153a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod		value = conv.xmlRead(name, attrs, content, self)
15164e5af60930726d06a58a30bae45bb27ae50aea77jvr		setattr(self, name, value)
1517e327558aa54f182912a26b8313f3af5a07bc2e77jvr
1518e327558aa54f182912a26b8313f3af5a07bc2e77jvr
15194756b3a04014645ee16a14fb6273e93efa1c7e15jvrclass TopDict(BaseDict):
1520e327558aa54f182912a26b8313f3af5a07bc2e77jvr
15214756b3a04014645ee16a14fb6273e93efa1c7e15jvr	defaults = buildDefaults(topDictOperators)
15224756b3a04014645ee16a14fb6273e93efa1c7e15jvr	converters = buildConverters(topDictOperators)
15234756b3a04014645ee16a14fb6273e93efa1c7e15jvr	order = buildOrder(topDictOperators)
1524f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	decompilerClass = TopDictDecompiler
1525f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	compilerClass = TopDictCompiler
15264756b3a04014645ee16a14fb6273e93efa1c7e15jvr
15274e5af60930726d06a58a30bae45bb27ae50aea77jvr	def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None):
1528016ca76e918ed36888c0fa8e287028ea367ef3d9jvr		BaseDict.__init__(self, strings, file, offset)
1529016ca76e918ed36888c0fa8e287028ea367ef3d9jvr		self.GlobalSubrs = GlobalSubrs
1530016ca76e918ed36888c0fa8e287028ea367ef3d9jvr
15314756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def getGlyphOrder(self):
15324756b3a04014645ee16a14fb6273e93efa1c7e15jvr		return self.charset
15334756b3a04014645ee16a14fb6273e93efa1c7e15jvr
15344756b3a04014645ee16a14fb6273e93efa1c7e15jvr	def postDecompile(self):
15354756b3a04014645ee16a14fb6273e93efa1c7e15jvr		offset = self.rawDict.get("CharStrings")
15364756b3a04014645ee16a14fb6273e93efa1c7e15jvr		if offset is None:
15374756b3a04014645ee16a14fb6273e93efa1c7e15jvr			return
15384756b3a04014645ee16a14fb6273e93efa1c7e15jvr		# get the number of glyphs beforehand.
15394756b3a04014645ee16a14fb6273e93efa1c7e15jvr		self.file.seek(offset)
1540a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		self.numGlyphs = readCard16(self.file)
15414756b3a04014645ee16a14fb6273e93efa1c7e15jvr
1542016ca76e918ed36888c0fa8e287028ea367ef3d9jvr	def toXML(self, xmlWriter, progress):
1543155aa7569f9d18fda270434f38642cfffdca4873jvr		if hasattr(self, "CharStrings"):
15447ce0a139ab67dd30614e728a1ef897e53ad805aejvr			self.decompileAllCharStrings(progress)
1545ed10151701a7d22e5ff4e06766edff59bd713c89jvr		if hasattr(self, "ROS"):
1546ed10151701a7d22e5ff4e06766edff59bd713c89jvr			self.skipNames = ['Encoding']
1547155aa7569f9d18fda270434f38642cfffdca4873jvr		if not hasattr(self, "ROS") or not hasattr(self, "CharStrings"):
1548155aa7569f9d18fda270434f38642cfffdca4873jvr			# these values have default values, but I only want them to show up
1549155aa7569f9d18fda270434f38642cfffdca4873jvr			# in CID fonts.
1550155aa7569f9d18fda270434f38642cfffdca4873jvr			self.skipNames = ['CIDFontVersion', 'CIDFontRevision', 'CIDFontType',
1551155aa7569f9d18fda270434f38642cfffdca4873jvr					'CIDCount']
1552016ca76e918ed36888c0fa8e287028ea367ef3d9jvr		BaseDict.toXML(self, xmlWriter, progress)
1553767102ea85a8af1535c169b2e04da5ba458f3b80jvr
15547ce0a139ab67dd30614e728a1ef897e53ad805aejvr	def decompileAllCharStrings(self, progress):
15554e5af60930726d06a58a30bae45bb27ae50aea77jvr		# XXX only when doing ttdump -i?
15567ce0a139ab67dd30614e728a1ef897e53ad805aejvr		i = 0
1557a2ad5447fb707448d2c442b16956f87e048ef0d1jvr		for charString in self.CharStrings.values():
1558ed10151701a7d22e5ff4e06766edff59bd713c89jvr			try:
1559ed10151701a7d22e5ff4e06766edff59bd713c89jvr				charString.decompile()
1560ed10151701a7d22e5ff4e06766edff59bd713c89jvr			except:
15613ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod				print("Error in charstring ", i)
1562ed10151701a7d22e5ff4e06766edff59bd713c89jvr				import sys
1563153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod				typ, value = sys.exc_info()[0:2]
1564153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod				raise typ(value)
15657ce0a139ab67dd30614e728a1ef897e53ad805aejvr			if not i % 30 and progress:
15667ce0a139ab67dd30614e728a1ef897e53ad805aejvr				progress.increment(0)  # update
15677ce0a139ab67dd30614e728a1ef897e53ad805aejvr			i = i + 1
15684756b3a04014645ee16a14fb6273e93efa1c7e15jvr
15694756b3a04014645ee16a14fb6273e93efa1c7e15jvr
1570ed10151701a7d22e5ff4e06766edff59bd713c89jvrclass FontDict(BaseDict):
1571ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1572ed10151701a7d22e5ff4e06766edff59bd713c89jvr	defaults = buildDefaults(topDictOperators)
1573ed10151701a7d22e5ff4e06766edff59bd713c89jvr	converters = buildConverters(topDictOperators)
1574ed10151701a7d22e5ff4e06766edff59bd713c89jvr	order = buildOrder(topDictOperators)
1575ed10151701a7d22e5ff4e06766edff59bd713c89jvr	decompilerClass = None
1576ed10151701a7d22e5ff4e06766edff59bd713c89jvr	compilerClass = FontDictCompiler
1577ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1578ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None):
1579ed10151701a7d22e5ff4e06766edff59bd713c89jvr		BaseDict.__init__(self, strings, file, offset)
1580ed10151701a7d22e5ff4e06766edff59bd713c89jvr		self.GlobalSubrs = GlobalSubrs
1581ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1582ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def getGlyphOrder(self):
1583ed10151701a7d22e5ff4e06766edff59bd713c89jvr		return self.charset
1584ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1585ed10151701a7d22e5ff4e06766edff59bd713c89jvr	def toXML(self, xmlWriter, progress):
1586ed10151701a7d22e5ff4e06766edff59bd713c89jvr		self.skipNames = ['Encoding']
1587ed10151701a7d22e5ff4e06766edff59bd713c89jvr		BaseDict.toXML(self, xmlWriter, progress)
1588ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1589ed10151701a7d22e5ff4e06766edff59bd713c89jvr
1590ed10151701a7d22e5ff4e06766edff59bd713c89jvr
15914756b3a04014645ee16a14fb6273e93efa1c7e15jvrclass PrivateDict(BaseDict):
15924756b3a04014645ee16a14fb6273e93efa1c7e15jvr	defaults = buildDefaults(privateDictOperators)
15934756b3a04014645ee16a14fb6273e93efa1c7e15jvr	converters = buildConverters(privateDictOperators)
15944756b3a04014645ee16a14fb6273e93efa1c7e15jvr	order = buildOrder(privateDictOperators)
1595f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	decompilerClass = PrivateDictDecompiler
1596f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	compilerClass = PrivateDictCompiler
15974756b3a04014645ee16a14fb6273e93efa1c7e15jvr
15984756b3a04014645ee16a14fb6273e93efa1c7e15jvr
1599e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass IndexedStrings(object):
1600e327558aa54f182912a26b8313f3af5a07bc2e77jvr
1601767102ea85a8af1535c169b2e04da5ba458f3b80jvr	"""SID -> string mapping."""
1602767102ea85a8af1535c169b2e04da5ba458f3b80jvr
1603767102ea85a8af1535c169b2e04da5ba458f3b80jvr	def __init__(self, file=None):
1604767102ea85a8af1535c169b2e04da5ba458f3b80jvr		if file is None:
1605e327558aa54f182912a26b8313f3af5a07bc2e77jvr			strings = []
1606767102ea85a8af1535c169b2e04da5ba458f3b80jvr		else:
1607617ec41d4c2db2011e62cadf619e2a8b07aec93eBehdad Esfahbod			strings = [tostr(s, encoding="latin1") for s in Index(file)]
1608e327558aa54f182912a26b8313f3af5a07bc2e77jvr		self.strings = strings
1609e327558aa54f182912a26b8313f3af5a07bc2e77jvr
1610f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def getCompiler(self):
1611f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return IndexedStringsCompiler(self, None, None)
1612f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1613f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def __len__(self):
1614f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return len(self.strings)
1615f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
1616e327558aa54f182912a26b8313f3af5a07bc2e77jvr	def __getitem__(self, SID):
1617e327558aa54f182912a26b8313f3af5a07bc2e77jvr		if SID < cffStandardStringCount:
1618e327558aa54f182912a26b8313f3af5a07bc2e77jvr			return cffStandardStrings[SID]
1619e327558aa54f182912a26b8313f3af5a07bc2e77jvr		else:
1620e327558aa54f182912a26b8313f3af5a07bc2e77jvr			return self.strings[SID - cffStandardStringCount]
1621e327558aa54f182912a26b8313f3af5a07bc2e77jvr
1622e327558aa54f182912a26b8313f3af5a07bc2e77jvr	def getSID(self, s):
1623e327558aa54f182912a26b8313f3af5a07bc2e77jvr		if not hasattr(self, "stringMapping"):
1624e327558aa54f182912a26b8313f3af5a07bc2e77jvr			self.buildStringMapping()
1625bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod		if s in cffStandardStringMapping:
1626e327558aa54f182912a26b8313f3af5a07bc2e77jvr			SID = cffStandardStringMapping[s]
1627bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod		elif s in self.stringMapping:
1628e327558aa54f182912a26b8313f3af5a07bc2e77jvr			SID = self.stringMapping[s]
1629e327558aa54f182912a26b8313f3af5a07bc2e77jvr		else:
1630e327558aa54f182912a26b8313f3af5a07bc2e77jvr			SID = len(self.strings) + cffStandardStringCount
1631e327558aa54f182912a26b8313f3af5a07bc2e77jvr			self.strings.append(s)
1632e327558aa54f182912a26b8313f3af5a07bc2e77jvr			self.stringMapping[s] = SID
1633e327558aa54f182912a26b8313f3af5a07bc2e77jvr		return SID
1634e327558aa54f182912a26b8313f3af5a07bc2e77jvr
1635e327558aa54f182912a26b8313f3af5a07bc2e77jvr	def getStrings(self):
1636e327558aa54f182912a26b8313f3af5a07bc2e77jvr		return self.strings
1637e327558aa54f182912a26b8313f3af5a07bc2e77jvr
1638e327558aa54f182912a26b8313f3af5a07bc2e77jvr	def buildStringMapping(self):
1639e327558aa54f182912a26b8313f3af5a07bc2e77jvr		self.stringMapping = {}
1640e327558aa54f182912a26b8313f3af5a07bc2e77jvr		for index in range(len(self.strings)):
1641e327558aa54f182912a26b8313f3af5a07bc2e77jvr			self.stringMapping[self.strings[index]] = index + cffStandardStringCount
1642e327558aa54f182912a26b8313f3af5a07bc2e77jvr
1643e327558aa54f182912a26b8313f3af5a07bc2e77jvr
16447842e56b97ce677b83bdab09cda48bc2d89ac75aJust# The 391 Standard Strings as used in the CFF format.
16457842e56b97ce677b83bdab09cda48bc2d89ac75aJust# from Adobe Technical None #5176, version 1.0, 18 March 1998
16467842e56b97ce677b83bdab09cda48bc2d89ac75aJust
16477842e56b97ce677b83bdab09cda48bc2d89ac75aJustcffStandardStrings = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign',
16487842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
16497842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one',
16507842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon',
16517842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C',
16527842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
16537842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash',
16547842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c',
16557842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
16567842e56b97ce677b83bdab09cda48bc2d89ac75aJust		's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright',
16577842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin',
16587842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft',
16597842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger',
16607842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase',
16617842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand',
16627842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve',
16637842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron',
16647842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae',
16657842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior',
16667842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn',
16677842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters',
16687842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior',
16697842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring',
16707842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave',
16717842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute',
16727842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute',
16737842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron',
16747842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
16757842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
16767842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
16777842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave',
16787842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall',
16797842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall',
16807842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader',
16817842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle',
16827842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle',
16837842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior',
16847842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior',
16857842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior',
16867842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior',
16877842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
16887842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall',
16897842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
16907842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall',
16917842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall',
16927842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall',
16937842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
16947842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall',
16957842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths',
16967842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'onethird', 'twothirds', 'zerosuperior', 'foursuperior', 'fivesuperior',
16977842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior',
16987842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior',
16997842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior',
17007842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall',
17017842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',
17027842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall',
17037842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall',
17047842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall',
17057842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall',
17067842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall',
17077842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002',
17087842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman',
17097842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'Semibold'
17107842e56b97ce677b83bdab09cda48bc2d89ac75aJust]
17117842e56b97ce677b83bdab09cda48bc2d89ac75aJust
17127842e56b97ce677b83bdab09cda48bc2d89ac75aJustcffStandardStringCount = 391
17137842e56b97ce677b83bdab09cda48bc2d89ac75aJustassert len(cffStandardStrings) == cffStandardStringCount
17147842e56b97ce677b83bdab09cda48bc2d89ac75aJust# build reverse mapping
17157842e56b97ce677b83bdab09cda48bc2d89ac75aJustcffStandardStringMapping = {}
17167842e56b97ce677b83bdab09cda48bc2d89ac75aJustfor _i in range(cffStandardStringCount):
17177842e56b97ce677b83bdab09cda48bc2d89ac75aJust	cffStandardStringMapping[cffStandardStrings[_i]] = _i
1718c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr
1719c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrcffISOAdobeStrings = [".notdef", "space", "exclam", "quotedbl", "numbersign",
1720c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright",
1721c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two",
1722c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon",
1723c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G",
1724c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
1725c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum",
1726c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1727c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
1728c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent",
1729c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle",
1730c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl",
1731c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet",
1732c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis",
1733c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"perthousand", "questiondown", "grave", "acute", "circumflex", "tilde",
1734c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut",
1735c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE",
1736c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls",
1737c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus",
1738c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn",
1739c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"threequarters", "twosuperior", "registered", "minus", "eth", "multiply",
1740c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave",
1741c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave",
1742c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute",
1743c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute",
1744c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute",
1745c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute",
1746c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis",
1747c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde",
1748c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis",
1749c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"zcaron"]
1750c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr
1751c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrcffISOAdobeStringCount = 229
1752c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrassert len(cffISOAdobeStrings) == cffISOAdobeStringCount
1753c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr
1754c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrcffIExpertStrings = [".notdef", "space", "exclamsmall", "Hungarumlautsmall",
1755c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall",
1756c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader",
1757c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle",
1758c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle",
1759c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon",
1760c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"commasuperior", "threequartersemdash", "periodsuperior", "questionsmall",
1761c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior",
1762c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior",
1763c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"tsuperior", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior",
1764c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall",
1765c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall",
1766c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall",
1767c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall",
1768c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall",
1769c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall",
1770c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall",
1771c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall",
1772c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"onequarter", "onehalf", "threequarters", "questiondownsmall", "oneeighth",
1773c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds",
1774c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"zerosuperior", "onesuperior", "twosuperior", "threesuperior", "foursuperior",
1775c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior",
1776c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior",
1777c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior",
1778c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"centinferior", "dollarinferior", "periodinferior", "commainferior",
1779c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall",
1780c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
1781c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
1782c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall",
1783c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall",
1784c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall",
1785c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall",
1786c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"Ydieresissmall"]
1787c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr
1788c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrcffExpertStringCount = 166
1789c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrassert len(cffIExpertStrings) == cffExpertStringCount
1790c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr
1791c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrcffExpertSubsetStrings = [".notdef", "space", "dollaroldstyle",
1792c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"dollarsuperior", "parenleftsuperior", "parenrightsuperior", "twodotenleader",
1793c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle",
1794c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle",
1795c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon",
1796c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"semicolon", "commasuperior", "threequartersemdash", "periodsuperior",
1797c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior",
1798c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior",
1799c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"tsuperior", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior",
1800c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"parenrightinferior", "hyphensuperior", "colonmonetary", "onefitted", "rupiah",
1801c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"centoldstyle", "figuredash", "hypheninferior", "onequarter", "onehalf",
1802c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"threequarters", "oneeighth", "threeeighths", "fiveeighths", "seveneighths",
1803c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"onethird", "twothirds", "zerosuperior", "onesuperior", "twosuperior",
1804c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior",
1805c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
1806c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior",
1807c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"eightinferior", "nineinferior", "centinferior", "dollarinferior",
1808c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr"periodinferior", "commainferior"]
1809c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvr
1810c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrcffExpertSubsetStringCount = 87
1811c60a44fa033aeda1eb7ea52a20333bb7cfc142dcjvrassert len(cffExpertSubsetStrings) == cffExpertSubsetStringCount
1812