11ae29591efbb29492ce05378909ccf4028d7c1eeBehdad Esfahbodfrom __future__ import print_function, division, absolute_import
27279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbodfrom fontTools.misc.py23 import *
3b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbodfrom fontTools.misc import eexec
4dc0ce0b498912287a557bdad58301ec7611c569eBehdad Esfahbodfrom .psOperators import *
57279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbodimport re
67279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbodimport collections
77279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbodfrom string import whitespace
8b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
9b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
10b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbodps_special = '()<>[]{}%'	# / is one too, but we take care of that one differently
11b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
12b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad EsfahbodskipwhiteRE = re.compile("[%s]*" % whitespace)
13b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad EsfahbodendofthingPat = "[^][(){}<>/%%%s]*" % whitespace
14b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad EsfahbodendofthingRE = re.compile(endofthingPat)
15b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad EsfahbodcommentRE = re.compile("%[^\n\r]*")
16b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
17b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod# XXX This not entirely correct as it doesn't allow *nested* embedded parens:
18b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad EsfahbodstringPat = r"""
19b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	\(
20b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		(
21b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			(
22b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				[^()]*   \   [()]
23b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			)
24b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			|
25b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			(
26b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				[^()]*  \(   [^()]*  \)
27b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			)
28b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		)*
29b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		[^()]*
30b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	\)
31b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod"""
32b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad EsfahbodstringPat = "".join(stringPat.split())
33b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad EsfahbodstringRE = re.compile(stringPat)
34b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
35b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad EsfahbodhexstringRE = re.compile("<[%s0-9A-Fa-f]*>" % whitespace)
36b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
37b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbodclass PSTokenError(Exception): pass
38b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbodclass PSError(Exception): pass
39b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
40b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
417279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbodclass PSTokenizer(StringIO):
42b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
437279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod	def getnexttoken(self,
44b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			# localize some stuff, for performance
45b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			len=len,
46b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			ps_special=ps_special,
47b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			stringmatch=stringRE.match,
48b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			hexstringmatch=hexstringRE.match,
49b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			commentmatch=commentRE.match,
50b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			endmatch=endofthingRE.match,
51b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			whitematch=skipwhiteRE.match):
52b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
53b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		_, nextpos = whitematch(self.buf, self.pos).span()
54b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.pos = nextpos
55b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		if self.pos >= self.len:
56b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			return None, None
57b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		pos = self.pos
58b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		buf = self.buf
59b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		char = buf[pos]
60b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		if char in ps_special:
61b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			if char in '{}[]':
62b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				tokentype = 'do_special'
63b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				token = char
64b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			elif char == '%':
65b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				tokentype = 'do_comment'
66b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				_, nextpos = commentmatch(buf, pos).span()
67b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				token = buf[pos:nextpos]
68b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			elif char == '(':
69b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				tokentype = 'do_string'
70b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				m = stringmatch(buf, pos)
71b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				if m is None:
727279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod					raise PSTokenError('bad string at character %d' % pos)
73b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				_, nextpos = m.span()
74b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				token = buf[pos:nextpos]
75b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			elif char == '<':
76b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				tokentype = 'do_hexstring'
77b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				m = hexstringmatch(buf, pos)
78b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				if m is None:
797279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod					raise PSTokenError('bad hexstring at character %d' % pos)
80b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				_, nextpos = m.span()
81b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				token = buf[pos:nextpos]
82b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			else:
837279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod				raise PSTokenError('bad token at character %d' % pos)
84b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		else:
85b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			if char == '/':
86b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				tokentype = 'do_literal'
87b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				m = endmatch(buf, pos+1)
88b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			else:
89b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				tokentype = ''
90b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				m = endmatch(buf, pos)
91b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			if m is None:
927279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod				raise PSTokenError('bad token at character %d' % pos)
93b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			_, nextpos = m.span()
94b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			token = buf[pos:nextpos]
95b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.pos = pos + len(token)
96b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		return tokentype, token
97b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
98b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def skipwhite(self, whitematch=skipwhiteRE.match):
99b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		_, nextpos = whitematch(self.buf, self.pos).span()
100b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.pos = nextpos
101b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
102b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def starteexec(self):
103b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.pos = self.pos + 1
104b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		#self.skipwhite()
105b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.dirtybuf = self.buf[self.pos:]
106b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.buf, R = eexec.decrypt(self.dirtybuf, 55665)
107b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.len = len(self.buf)
108b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.pos = 4
109b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
110b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def stopeexec(self):
111b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		if not hasattr(self, 'dirtybuf'):
112b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			return
113b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.buf = self.dirtybuf
114b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		del self.dirtybuf
115b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
116b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def flush(self):
117b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		if self.buflist:
118b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			self.buf = self.buf + "".join(self.buflist)
119b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			self.buflist = []
120b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
121b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
122b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbodclass PSInterpreter(PSOperators):
123b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
124b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def __init__(self):
125b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		systemdict = {}
126b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		userdict = {}
127b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.dictstack = [systemdict, userdict]
128b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.stack = []
129b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.proclevel = 0
130b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.procmark = ps_procmark()
131b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.fillsystemdict()
132b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
133b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def fillsystemdict(self):
134b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		systemdict = self.dictstack[0]
135b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		systemdict['['] = systemdict['mark'] = self.mark = ps_mark()
136b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		systemdict[']'] = ps_operator(']', self.do_makearray)
137b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		systemdict['true'] = ps_boolean(1)
138b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		systemdict['false'] = ps_boolean(0)
139b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		systemdict['StandardEncoding'] = ps_array(ps_StandardEncoding)
140b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		systemdict['FontDirectory'] = ps_dict({})
141b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.suckoperators(systemdict, self.__class__)
142b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
143b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def suckoperators(self, systemdict, klass):
144b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		for name in dir(klass):
145b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			attr = getattr(self, name)
1467279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod			if isinstance(attr, collections.Callable) and name[:3] == 'ps_':
147b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				name = name[3:]
148b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				systemdict[name] = ps_operator(name, attr)
149b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		for baseclass in klass.__bases__:
150b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			self.suckoperators(systemdict, baseclass)
151b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
152b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def interpret(self, data, getattr = getattr):
153b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		tokenizer = self.tokenizer = PSTokenizer(data)
154b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		getnexttoken = tokenizer.getnexttoken
155b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		do_token = self.do_token
156b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		handle_object = self.handle_object
157b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		try:
158b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			while 1:
159b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				tokentype, token = getnexttoken()
160b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				#print token
161b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				if not token:
162b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					break
163b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				if tokentype:
164b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					handler = getattr(self, tokentype)
165b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					object = handler(token)
166b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				else:
167b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					object = do_token(token)
168b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				if object is not None:
169b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					handle_object(object)
170b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			tokenizer.close()
171b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			self.tokenizer = None
172b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		finally:
173b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			if self.tokenizer is not None:
174b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				if 0:
1757279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod					print('ps error:\n- - - - - - -')
1767279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod					print(self.tokenizer.buf[self.tokenizer.pos-50:self.tokenizer.pos])
1777279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod					print('>>>')
1787279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod					print(self.tokenizer.buf[self.tokenizer.pos:self.tokenizer.pos+50])
1797279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod					print('- - - - - - -')
180b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
181b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def handle_object(self, object):
182b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		if not (self.proclevel or object.literal or object.type == 'proceduretype'):
1837279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod			if object.type != 'operatortype':
184b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				object = self.resolve_name(object.value)
185b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			if object.literal:
186b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				self.push(object)
187b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			else:
188b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				if object.type == 'proceduretype':
189b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					self.call_procedure(object)
190b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				else:
191b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					object.function()
192b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		else:
193b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			self.push(object)
194b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
195b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def call_procedure(self, proc):
196b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		handle_object = self.handle_object
197b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		for item in proc.value:
198b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			handle_object(item)
199b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
200b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def resolve_name(self, name):
201b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		dictstack = self.dictstack
202b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		for i in range(len(dictstack)-1, -1, -1):
2037279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod			if name in dictstack[i]:
204b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				return dictstack[i][name]
2057279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod		raise PSError('name error: ' + str(name))
206b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
207b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def do_token(self, token,
208b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				int=int,
209b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				float=float,
210b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				ps_name=ps_name,
211b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				ps_integer=ps_integer,
212b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				ps_real=ps_real):
213b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		try:
214b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			num = int(token)
215b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		except (ValueError, OverflowError):
216b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			try:
217b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				num = float(token)
218b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			except (ValueError, OverflowError):
219b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				if '#' in token:
220b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					hashpos = token.find('#')
221b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					try:
222b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod						base = int(token[:hashpos])
223b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod						num = int(token[hashpos+1:], base)
224b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					except (ValueError, OverflowError):
225b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod						return ps_name(token)
226b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					else:
227b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod						return ps_integer(num)
228b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				else:
229b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					return ps_name(token)
230b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			else:
231b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				return ps_real(num)
232b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		else:
233b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			return ps_integer(num)
234b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
235b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def do_comment(self, token):
236b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		pass
237b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
238b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def do_literal(self, token):
239b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		return ps_literal(token[1:])
240b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
241b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def do_string(self, token):
242b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		return ps_string(token[1:-1])
243b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
244b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def do_hexstring(self, token):
245b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		hexStr = "".join(token[1:-1].split())
246b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		if len(hexStr) % 2:
247b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			hexStr = hexStr + '0'
248b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		cleanstr = []
249b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		for i in range(0, len(hexStr), 2):
250b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			cleanstr.append(chr(int(hexStr[i:i+2], 16)))
251b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		cleanstr = "".join(cleanstr)
252b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		return ps_string(cleanstr)
253b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
254b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def do_special(self, token):
255b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		if token == '{':
256b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			self.proclevel = self.proclevel + 1
257b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			return self.procmark
258b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		elif token == '}':
259b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			proc = []
260b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			while 1:
261b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				topobject = self.pop()
262b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				if topobject == self.procmark:
263b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod					break
264b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				proc.append(topobject)
265b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			self.proclevel = self.proclevel - 1
266b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			proc.reverse()
267b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			return ps_procedure(proc)
268b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		elif token == '[':
269b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			return self.mark
270b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		elif token == ']':
271b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			return ps_name(']')
272b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		else:
2737279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod			raise PSTokenError('huh?')
274b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
275b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def push(self, object):
276b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.stack.append(object)
277b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
278b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def pop(self, *types):
279b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		stack = self.stack
280b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		if not stack:
2817279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod			raise PSError('stack underflow')
282b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		object = stack[-1]
283b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		if types:
284b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			if object.type not in types:
2857279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod				raise PSError('typecheck, expected %s, found %s' % (repr(types), object.type))
286b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		del stack[-1]
287b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		return object
288b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
289b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def do_makearray(self):
290b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		array = []
291b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		while 1:
292b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			topobject = self.pop()
293b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			if topobject == self.mark:
294b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod				break
295b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			array.append(topobject)
296b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		array.reverse()
297b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		self.push(ps_array(array))
298b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
299b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	def close(self):
300b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		"""Remove circular references."""
301b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		del self.stack
302b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		del self.dictstack
303b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
304b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
305b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahboddef unpack_item(item):
306b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	tp = type(item.value)
3077279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod	if tp == dict:
308b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		newitem = {}
309b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		for key, value in item.value.items():
310b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			newitem[key] = unpack_item(value)
3117279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod	elif tp == list:
312b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		newitem = [None] * len(item.value)
313b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		for i in range(len(item.value)):
314b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			newitem[i] = unpack_item(item.value[i])
315b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		if item.type == 'proceduretype':
316b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			newitem = tuple(newitem)
317b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	else:
318b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		newitem = item.value
319b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	return newitem
320b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
321b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahboddef suckfont(data):
322b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	import re
323dc0ce0b498912287a557bdad58301ec7611c569eBehdad Esfahbod	m = re.search(br"/FontName\s+/([^ \t\n\r]+)\s+def", data)
324b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	if m:
325b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		fontName = m.group(1)
326b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	else:
327b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		fontName = None
328b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	interpreter = PSInterpreter()
329dc0ce0b498912287a557bdad58301ec7611c569eBehdad Esfahbod	interpreter.interpret(b"/Helvetica 4 dict dup /Encoding StandardEncoding put definefont pop")
330b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	interpreter.interpret(data)
331b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	fontdir = interpreter.dictstack[0]['FontDirectory'].value
3327279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod	if fontName in fontdir:
333b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		rawfont = fontdir[fontName]
334b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	else:
335b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		# fall back, in case fontName wasn't found
3367279302238a2d57d609cab45934615c4d959c88cBehdad Esfahbod		fontNames = list(fontdir.keys())
337b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		if len(fontNames) > 1:
338b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod			fontNames.remove("Helvetica")
339b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		fontNames.sort()
340b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		rawfont = fontdir[fontNames[0]]
341b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	interpreter.close()
342b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	return unpack_item(rawfont)
343b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
344b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod
345b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbodif __name__ == "__main__":
346b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	import EasyDialogs
347b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	path = EasyDialogs.AskFileForOpen()
348b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod	if path:
349b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		from fontTools import t1Lib
350b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		data, kind = t1Lib.read(path)
351b49aa66e6192a66330b19187d18e9c39c5a0caf3Behdad Esfahbod		font = suckfont(data)
352