psCharStrings.py revision bf2f402913a2706dfa92190e60cba7acbf01c9d7
1"""psCharStrings.py -- module implementing various kinds of CharStrings:
2CFF dictionary data and Type1/Type2 CharStrings.
3"""
4
5__version__ = "1.0b1"
6__author__ = "jvr"
7
8
9import types
10import struct
11import string
12
13
14t1OperandEncoding = [None] * 256
15t1OperandEncoding[0:32] = (32) * ["do_operator"]
16t1OperandEncoding[32:247] = (247 - 32) * ["read_byte"]
17t1OperandEncoding[247:251] = (251 - 247) * ["read_smallInt1"]
18t1OperandEncoding[251:255] = (255 - 251) * ["read_smallInt2"]
19t1OperandEncoding[255] = "read_longInt"
20assert len(t1OperandEncoding) == 256
21
22t2OperandEncoding = t1OperandEncoding[:]
23t2OperandEncoding[28] = "read_shortInt"
24
25cffDictOperandEncoding = t2OperandEncoding[:]
26cffDictOperandEncoding[29] = "read_longInt"
27cffDictOperandEncoding[30] = "read_realNumber"
28cffDictOperandEncoding[255] = "reserved"
29
30
31realNibbles = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
32		'.', 'E', 'E-', None, '-']
33
34
35class ByteCodeDecompilerBase:
36
37	def read_byte(self, b0, data, index):
38		return b0 - 139, index
39
40	def read_smallInt1(self, b0, data, index):
41		b1 = ord(data[index])
42		return (b0-247)*256 + b1 + 108, index+1
43
44	def read_smallInt2(self, b0, data, index):
45		b1 = ord(data[index])
46		return -(b0-251)*256 - b1 - 108, index+1
47
48	def read_shortInt(self, b0, data, index):
49		bin = data[index] + data[index+1]
50		value, = struct.unpack(">h", bin)
51		return value, index+2
52
53	def read_longInt(self, b0, data, index):
54		bin = data[index] + data[index+1] + data[index+2] + data[index+3]
55		value, = struct.unpack(">l", bin)
56		return value, index+4
57
58	def read_realNumber(self, b0, data, index):
59		number = ''
60		while 1:
61			b = ord(data[index])
62			index = index + 1
63			nibble0 = (b & 0xf0) >> 4
64			nibble1 = b & 0x0f
65			if nibble0 == 0xf:
66				break
67			number = number + realNibbles[nibble0]
68			if nibble1 == 0xf:
69				break
70			number = number + realNibbles[nibble1]
71		return string.atof(number), index
72
73
74def buildOperatorDict(operatorList):
75	dict = {}
76	for item in operatorList:
77		if len(item) == 2:
78			dict[item[0]] = item[1]
79		else:
80			dict[item[0]] = item[1:]
81	return dict
82
83
84t2Operators = [
85#	opcode     name
86	(1,        'hstem'),
87	(3,        'vstem'),
88	(4,        'vmoveto'),
89	(5,        'rlineto'),
90	(6,        'hlineto'),
91	(7,        'vlineto'),
92	(8,        'rrcurveto'),
93	(10,       'callsubr'),
94	(11,       'return'),
95	(14,       'endchar'),
96	(16,       'blend'),
97	(18,       'hstemhm'),
98	(19,       'hintmask'),
99	(20,       'cntrmask'),
100	(21,       'rmoveto'),
101	(22,       'hmoveto'),
102	(23,       'vstemhm'),
103	(24,       'rcurveline'),
104	(25,       'rlinecurve'),
105	(26,       'vvcurveto'),
106	(27,       'hhcurveto'),
107#	(28,       'shortint'),  # not really an operator
108	(29,       'callgsubr'),
109	(30,       'vhcurveto'),
110	(31,       'hvcurveto'),
111	((12, 3),  'and'),
112	((12, 4),  'or'),
113	((12, 5),  'not'),
114	((12, 8),  'store'),
115	((12, 9),  'abs'),
116	((12, 10), 'add'),
117	((12, 11), 'sub'),
118	((12, 12), 'div'),
119	((12, 13), 'load'),
120	((12, 14), 'neg'),
121	((12, 15), 'eq'),
122	((12, 18), 'drop'),
123	((12, 20), 'put'),
124	((12, 21), 'get'),
125	((12, 22), 'ifelse'),
126	((12, 23), 'random'),
127	((12, 24), 'mul'),
128	((12, 26), 'sqrt'),
129	((12, 27), 'dup'),
130	((12, 28), 'exch'),
131	((12, 29), 'index'),
132	((12, 30), 'roll'),
133	((12, 34), 'hflex'),
134	((12, 35), 'flex'),
135	((12, 36), 'hflex1'),
136	((12, 37), 'flex1'),
137]
138
139class T2CharString(ByteCodeDecompilerBase):
140
141	operandEncoding = t2OperandEncoding
142	operators = buildOperatorDict(t2Operators)
143
144	def __init__(self, bytecode=None, program=None):
145		if program is None:
146			program = []
147		self.bytecode = bytecode
148		self.program = program
149
150	def __repr__(self):
151		if self.bytecode is None:
152			return "<%s (source) at %x>" % (self.__class__.__name__, id(self))
153		else:
154			return "<%s (bytecode) at %x>" % (self.__class__.__name__, id(self))
155
156	def needsDecompilation(self):
157		return self.bytecode is not None
158
159	def setProgram(self, program):
160		self.program = program
161		self.bytecode = None
162
163	def getToken(self, index,
164			len=len, ord=ord, getattr=getattr, type=type, StringType=types.StringType):
165		if self.bytecode is not None:
166			if index >= len(self.bytecode):
167				return None, 0, 0
168			b0 = ord(self.bytecode[index])
169			index = index + 1
170			code = self.operandEncoding[b0]
171			handler = getattr(self, code)
172			token, index = handler(b0, self.bytecode, index)
173		else:
174			if index >= len(self.program):
175				return None, 0, 0
176			token = self.program[index]
177			index = index + 1
178		isOperator = type(token) == StringType
179		return token, isOperator, index
180
181	def getBytes(self, index, nBytes):
182		if self.bytecode is not None:
183			newIndex = index + nBytes
184			bytes = self.bytecode[index:newIndex]
185			index = newIndex
186		else:
187			bytes = self.program[index]
188			index = index + 1
189		assert len(bytes) == nBytes
190		return bytes, index
191
192	def do_operator(self, b0, data, index):
193		if b0 == 12:
194			op = (b0, ord(data[index]))
195			index = index+1
196		else:
197			op = b0
198		operator = self.operators[op]
199		return operator, index
200
201	def toXML(self, xmlWriter):
202		from fontTools.misc.textTools import num2binary
203		if self.bytecode is not None:
204			xmlWriter.dumphex(self.bytecode)
205		else:
206			index = 0
207			args = []
208			while 1:
209				token, isOperator, index = self.getToken(index)
210				if token is None:
211					break
212				if isOperator:
213					args = map(str, args)
214					if token in ('hintmask', 'cntrmask'):
215						hintMask, isOperator, index = self.getToken(index)
216						bits = []
217						for byte in hintMask:
218							bits.append(num2binary(ord(byte), 8))
219						hintMask = repr(string.join(bits, ""))
220						line = string.join(args + [token, hintMask], " ")
221					else:
222						line = string.join(args + [token], " ")
223					xmlWriter.write(line)
224					xmlWriter.newline()
225					args = []
226				else:
227					args.append(token)
228
229
230t1Operators = [
231#	opcode     name
232	(1,        'hstem'),
233	(3,        'vstem'),
234	(4,        'vmoveto'),
235	(5,        'rlineto'),
236	(6,        'hlineto'),
237	(7,        'vlineto'),
238	(8,        'rrcurveto'),
239	(9,        'closepath'),
240	(10,       'callsubr'),
241	(11,       'return'),
242	(13,       'hsbw'),
243	(14,       'endchar'),
244	(21,       'rmoveto'),
245	(22,       'hmoveto'),
246	(30,       'vhcurveto'),
247	(31,       'hvcurveto'),
248	((12, 0),  'dotsection'),
249	((12, 1),  'vstem3'),
250	((12, 2),  'hstem3'),
251	((12, 6),  'seac'),
252	((12, 7),  'sbw'),
253	((12, 12), 'div'),
254	((12, 16), 'callothersubr'),
255	((12, 17), 'pop'),
256	((12, 33), 'setcurrentpoint'),
257]
258
259class T1CharString(T2CharString):
260
261	operandEncoding = t1OperandEncoding
262	operators = buildOperatorDict(t1Operators)
263
264	def decompile(self):
265		if self.program is not None:
266			return
267		program = []
268		index = 0
269		while 1:
270			token, isOperator, index = self.getToken(index)
271			if token is None:
272				break
273			program.append(token)
274		self.setProgram(program)
275
276
277class SimpleT2Decompiler:
278
279	def __init__(self, localSubrs, globalSubrs):
280		self.localSubrs = localSubrs
281		self.localBias = calcSubrBias(localSubrs)
282		self.globalSubrs = globalSubrs
283		self.globalBias = calcSubrBias(globalSubrs)
284		self.reset()
285
286	def reset(self):
287		self.callingStack = []
288		self.operandStack = []
289		self.hintCount = 0
290		self.hintMaskBytes = 0
291
292	def execute(self, charString):
293		self.callingStack.append(charString)
294		needsDecompilation = charString.needsDecompilation()
295		if needsDecompilation:
296			program = []
297			pushToProgram = program.append
298		else:
299			pushToProgram = lambda x: None
300		pushToStack = self.operandStack.append
301		index = 0
302		while 1:
303			token, isOperator, index = charString.getToken(index)
304			if token is None:
305				break  # we're done!
306			pushToProgram(token)
307			if isOperator:
308				handlerName = "op_" + token
309				if hasattr(self, handlerName):
310					handler = getattr(self, handlerName)
311					rv = handler(index)
312					if rv:
313						hintMaskBytes, index = rv
314						pushToProgram(hintMaskBytes)
315				else:
316					self.popall()
317			else:
318				pushToStack(token)
319		if needsDecompilation:
320			charString.setProgram(program)
321			assert program[-1] in ("endchar", "return", "callsubr", "callgsubr", "seac")
322		del self.callingStack[-1]
323
324	def pop(self):
325		value = self.operandStack[-1]
326		del self.operandStack[-1]
327		return value
328
329	def popall(self):
330		stack = self.operandStack[:]
331		self.operandStack[:] = []
332		return stack
333
334	def push(self, value):
335		self.operandStack.append(value)
336
337	def op_return(self, index):
338		if self.operandStack:
339			pass
340
341	def op_endchar(self, index):
342		pass
343
344	def op_callsubr(self, index):
345		subrIndex = self.pop()
346		subr = self.localSubrs[subrIndex+self.localBias]
347		self.execute(subr)
348
349	def op_callgsubr(self, index):
350		subrIndex = self.pop()
351		subr = self.globalSubrs[subrIndex+self.globalBias]
352		self.execute(subr)
353
354	def op_hstemhm(self, index):
355		self.countHints()
356
357	op_vstemhm = op_hstemhm
358
359	def op_hintmask(self, index):
360		if not self.hintMaskBytes:
361			self.countHints()
362			self.hintMaskBytes = (self.hintCount + 7) / 8
363		hintMaskBytes, index = self.callingStack[-1].getBytes(index, self.hintMaskBytes)
364		return hintMaskBytes, index
365
366	op_cntrmask = op_hintmask
367
368	def countHints(self):
369		assert self.hintMaskBytes == 0
370		args = self.popall()
371		self.hintCount = self.hintCount + len(args) / 2
372
373
374class T2OutlineExtractor(SimpleT2Decompiler):
375
376	def __init__(self, localSubrs, globalSubrs, nominalWidthX, defaultWidthX):
377		SimpleT2Decompiler.__init__(self, localSubrs, globalSubrs)
378		self.nominalWidthX = nominalWidthX
379		self.defaultWidthX = defaultWidthX
380
381	def reset(self):
382		import Numeric
383		SimpleT2Decompiler.reset(self)
384		self.hints = []
385		self.gotWidth = 0
386		self.width = 0
387		self.currentPoint = Numeric.array((0, 0), Numeric.Int16)
388		self.contours = []
389
390	def getContours(self):
391		return self.contours
392
393	def newPath(self):
394		self.contours.append([[], [], 0])
395
396	def closePath(self):
397		if self.contours and self.contours[-1][2] == 0:
398			self.contours[-1][2] = 1
399
400	def appendPoint(self, point, isPrimary):
401		import Numeric
402		point = self.currentPoint + Numeric.array(point, Numeric.Int16)
403		if not self.contours or self.contours[-1][2]:
404			# The subpath doesn't start with a moveto. Not sure whether
405			# this is legal, but apparently it usually works.
406			self.newPath()
407			self.appendPoint((0, 0), 1)
408		self.currentPoint = point
409		points, flags, isClosed = self.contours[-1]
410		points.append(point)
411		flags.append(isPrimary)
412
413	def popallWidth(self, evenOdd=0):
414		args = self.popall()
415		if not self.gotWidth:
416			if evenOdd ^ (len(args) % 2):
417				self.width = self.nominalWidthX + args[0]
418				args = args[1:]
419			else:
420				self.width = self.defaultWidthX
421			self.gotWidth = 1
422		return args
423
424	def countHints(self):
425		assert self.hintMaskBytes == 0
426		args = self.popallWidth()
427		self.hintCount = self.hintCount + len(args) / 2
428
429	#
430	# hint operators
431	#
432	def op_hstem(self, index):
433		self.popallWidth()  # XXX
434	def op_vstem(self, index):
435		self.popallWidth()  # XXX
436	def op_hstemhm(self, index):
437		self.countHints()
438		#XXX
439	def op_vstemhm(self, index):
440		self.countHints()
441		#XXX
442	#def op_hintmask(self, index):
443	#	self.countHints()
444	#def op_cntrmask(self, index):
445	#	self.countHints()
446
447	#
448	# path constructors, moveto
449	#
450	def op_rmoveto(self, index):
451		self.closePath()
452		self.newPath()
453		self.appendPoint(self.popallWidth(), 1)
454	def op_hmoveto(self, index):
455		self.closePath()
456		self.newPath()
457		self.appendPoint((self.popallWidth(1)[0], 0), 1)
458	def op_vmoveto(self, index):
459		self.closePath()
460		self.newPath()
461		self.appendPoint((0, self.popallWidth(1)[0]), 1)
462	def op_endchar(self, index):
463		self.closePath()
464
465	#
466	# path constructors, lines
467	#
468	def op_rlineto(self, index):
469		args = self.popall()
470		for i in range(0, len(args), 2):
471			point = args[i:i+2]
472			self.appendPoint(point, 1)
473
474	def op_hlineto(self, index):
475		self.alternatingLineto(1)
476	def op_vlineto(self, index):
477		self.alternatingLineto(0)
478
479	#
480	# path constructors, curves
481	#
482	def op_rrcurveto(self, index):
483		"""{dxa dya dxb dyb dxc dyc}+ rrcurveto"""
484		args = self.popall()
485		for i in range(0, len(args), 6):
486			dxa, dya, dxb, dyb, dxc, dyc, = args[i:i+6]
487			self.rrcurveto((dxa, dya), (dxb, dyb), (dxc, dyc))
488
489	def op_rcurveline(self, index):
490		"""{dxa dya dxb dyb dxc dyc}+ dxd dyd rcurveline"""
491		args = self.popall()
492		for i in range(0, len(args)-2, 6):
493			dxb, dyb, dxc, dyc, dxd, dyd = args[i:i+6]
494			self.rrcurveto((dxb, dyb), (dxc, dyc), (dxd, dyd))
495		self.appendPoint(args[-2:], 1)
496
497	def op_rlinecurve(self, index):
498		"""{dxa dya}+ dxb dyb dxc dyc dxd dyd rlinecurve"""
499		args = self.popall()
500		lineArgs = args[:-6]
501		for i in range(0, len(lineArgs), 2):
502			self.appendPoint(lineArgs[i:i+2], 1)
503		dxb, dyb, dxc, dyc, dxd, dyd = args[-6:]
504		self.rrcurveto((dxb, dyb), (dxc, dyc), (dxd, dyd))
505
506	def op_vvcurveto(self, index):
507		"dx1? {dya dxb dyb dyc}+ vvcurveto"
508		args = self.popall()
509		if len(args) % 2:
510			dx1 = args[0]
511			args = args[1:]
512		else:
513			dx1 = 0
514		for i in range(0, len(args), 4):
515			dya, dxb, dyb, dyc = args[i:i+4]
516			self.rrcurveto((dx1, dya), (dxb, dyb), (0, dyc))
517			dx1 = 0
518
519	def op_hhcurveto(self, index):
520		"""dy1? {dxa dxb dyb dxc}+ hhcurveto"""
521		args = self.popall()
522		if len(args) % 2:
523			dy1 = args[0]
524			args = args[1:]
525		else:
526			dy1 = 0
527		for i in range(0, len(args), 4):
528			dxa, dxb, dyb, dxc = args[i:i+4]
529			self.rrcurveto((dxa, dy1), (dxb, dyb), (dxc, 0))
530			dy1 = 0
531
532	def op_vhcurveto(self, index):
533		"""dy1 dx2 dy2 dx3 {dxa dxb dyb dyc dyd dxe dye dxf}* dyf? vhcurveto (30)
534		{dya dxb dyb dxc dxd dxe dye dyf}+ dxf? vhcurveto
535		"""
536		args = self.popall()
537		while args:
538			args = self.vcurveto(args)
539			if args:
540				args = self.hcurveto(args)
541
542	def op_hvcurveto(self, index):
543		"""dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf?
544		{dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
545		"""
546		args = self.popall()
547		while args:
548			args = self.hcurveto(args)
549			if args:
550				args = self.vcurveto(args)
551
552	#
553	# path constructors, flex
554	#
555	def op_hflex(self, index):
556		XXX
557	def op_flex(self, index):
558		XXX
559	def op_hflex1(self, index):
560		XXX
561	def op_flex1(self, index):
562		XXX
563
564	#
565	# MultipleMaster. Well...
566	#
567	def op_blend(self, index):
568		XXX
569
570	# misc
571	def op_and(self, index):
572		XXX
573	def op_or(self, index):
574		XXX
575	def op_not(self, index):
576		XXX
577	def op_store(self, index):
578		XXX
579	def op_abs(self, index):
580		XXX
581	def op_add(self, index):
582		XXX
583	def op_sub(self, index):
584		XXX
585	def op_div(self, index):
586		num2 = self.pop()
587		num1 = self.pop()
588		d1 = num1/num2
589		d2 = float(num1)/num2
590		if d1 == d2:
591			self.push(d1)
592		else:
593			self.push(d2)
594	def op_load(self, index):
595		XXX
596	def op_neg(self, index):
597		XXX
598	def op_eq(self, index):
599		XXX
600	def op_drop(self, index):
601		XXX
602	def op_put(self, index):
603		XXX
604	def op_get(self, index):
605		XXX
606	def op_ifelse(self, index):
607		XXX
608	def op_random(self, index):
609		XXX
610	def op_mul(self, index):
611		XXX
612	def op_sqrt(self, index):
613		XXX
614	def op_dup(self, index):
615		XXX
616	def op_exch(self, index):
617		XXX
618	def op_index(self, index):
619		XXX
620	def op_roll(self, index):
621		XXX
622
623	#
624	# miscelaneous helpers
625	#
626	def alternatingLineto(self, isHorizontal):
627		args = self.popall()
628		for arg in args:
629			if isHorizontal:
630				point = (arg, 0)
631			else:
632				point = (0, arg)
633			self.appendPoint(point, 1)
634			isHorizontal = not isHorizontal
635
636	def rrcurveto(self, p1, p2, p3):
637		self.appendPoint(p1, 0)
638		self.appendPoint(p2, 0)
639		self.appendPoint(p3, 1)
640
641	def vcurveto(self, args):
642		dya, dxb, dyb, dxc = args[:4]
643		args = args[4:]
644		if len(args) == 1:
645			dyc = args[0]
646			args = []
647		else:
648			dyc = 0
649		self.rrcurveto((0, dya), (dxb, dyb), (dxc, dyc))
650		return args
651
652	def hcurveto(self, args):
653		dxa, dxb, dyb, dyc = args[:4]
654		args = args[4:]
655		if len(args) == 1:
656			dxc = args[0]
657			args = []
658		else:
659			dxc = 0
660		self.rrcurveto((dxa, 0), (dxb, dyb), (dxc, dyc))
661		return args
662
663
664class T1OutlineExtractor(T2OutlineExtractor):
665
666	def __init__(self, subrs):
667		self.subrs = subrs
668		self.reset()
669
670	def reset(self):
671		self.flexing = 0
672		self.width = 0
673		self.sbx = 0
674		T2OutlineExtractor.reset(self)
675
676	def popallWidth(self, evenOdd=0):
677		return self.popall()
678
679	def exch(self):
680		stack = self.operandStack
681		stack[-1], stack[-2] = stack[-2], stack[-1]
682
683	#
684	# path constructors
685	#
686	def op_rmoveto(self, index):
687		if self.flexing:
688			return
689		self.newPath()
690		self.appendPoint(self.popall(), 1)
691	def op_hmoveto(self, index):
692		if self.flexing:
693			# We must add a parameter to the stack if we are flexing
694			self.push(0)
695			return
696		self.newPath()
697		self.appendPoint((self.popall()[0], 0), 1)
698	def op_vmoveto(self, index):
699		if self.flexing:
700			# We must add a parameter to the stack if we are flexing
701			self.push(0)
702			self.exch()
703			return
704		self.newPath()
705		self.appendPoint((0, self.popall()[0]), 1)
706	def op_closepath(self, index):
707		self.closePath()
708	def op_setcurrentpoint(self, index):
709		args = self.popall()
710		x, y = args
711		self.currentPoint[0] = x
712		self.currentPoint[1] = y
713
714	def op_endchar(self, index):
715		self.closePath()
716
717	def op_hsbw(self, index):
718		sbx, wx = self.popall()
719		self.width = wx
720		self.sbx = sbx
721		self.currentPoint[0] = sbx
722	def op_sbw(self, index):
723		self.popall()  # XXX
724
725	#
726	def op_callsubr(self, index):
727		subrIndex = self.pop()
728		subr = self.subrs[subrIndex]
729		self.execute(subr)
730	def op_callothersubr(self, index):
731		subrIndex = self.pop()
732		nArgs = self.pop()
733		#print nArgs, subrIndex, "callothersubr"
734		if subrIndex == 0 and nArgs == 3:
735			self.doFlex()
736			self.flexing = 0
737		elif subrIndex == 1 and nArgs == 0:
738			self.flexing = 1
739		# ignore...
740	def op_pop(self, index):
741		pass  # ignore...
742
743	def doFlex(self):
744		finaly = self.pop()
745		finalx = self.pop()
746		self.pop()	# flex height is unused
747
748		p3y = self.pop()
749		p3x = self.pop()
750		bcp4y = self.pop()
751		bcp4x = self.pop()
752		bcp3y = self.pop()
753		bcp3x = self.pop()
754		p2y = self.pop()
755		p2x = self.pop()
756		bcp2y = self.pop()
757		bcp2x = self.pop()
758		bcp1y = self.pop()
759		bcp1x = self.pop()
760		rpy = self.pop()
761		rpx = self.pop()
762
763		# call rrcurveto
764		self.push(bcp1x+rpx)
765		self.push(bcp1y+rpy)
766		self.push(bcp2x)
767		self.push(bcp2y)
768		self.push(p2x)
769		self.push(p2y)
770		self.op_rrcurveto(None)
771
772		# call rrcurveto
773		self.push(bcp3x)
774		self.push(bcp3y)
775		self.push(bcp4x)
776		self.push(bcp4y)
777		self.push(p3x)
778		self.push(p3y)
779		self.op_rrcurveto(None)
780
781		# Push back final coords so subr 0 can find them
782		self.push(finalx)
783		self.push(finaly)
784
785	def op_dotsection(self, index):
786		self.popall()  # XXX
787	def op_hstem3(self, index):
788		self.popall()  # XXX
789	def op_seac(self, index):
790		"asb adx ady bchar achar seac"
791		asb, adx, ady, bchar, achar = self.popall()  # XXX
792		self.contours.append([(asb, adx, ady, bchar, achar), None, -1])
793	def op_vstem3(self, index):
794		self.popall()  # XXX
795
796
797class DictDecompiler(ByteCodeDecompilerBase):
798
799	operandEncoding = cffDictOperandEncoding
800	dictDefaults = {}
801
802	def __init__(self, strings):
803		self.stack = []
804		self.strings = strings
805		self.dict = {}
806
807	def getDict(self):
808		assert len(self.stack) == 0, "non-empty stack"
809		return self.dict
810
811	def decompile(self, data):
812		index = 0
813		lenData = len(data)
814		push = self.stack.append
815		while index < lenData:
816			b0 = ord(data[index])
817			index = index + 1
818			code = self.operandEncoding[b0]
819			handler = getattr(self, code)
820			value, index = handler(b0, data, index)
821			if value is not None:
822				push(value)
823
824	def pop(self):
825		value = self.stack[-1]
826		del self.stack[-1]
827		return value
828
829	def popall(self):
830		all = self.stack[:]
831		del self.stack[:]
832		return all
833
834	def do_operator(self, b0, data, index):
835		if b0 == 12:
836			op = (b0, ord(data[index]))
837			index = index+1
838		else:
839			op = b0
840		operator, argType = self.operators[op]
841		self.handle_operator(operator, argType)
842		return None, index
843
844	def handle_operator(self, operator, argType):
845		if type(argType) == type(()):
846			value = ()
847			for i in range(len(argType)-1, -1, -1):
848				arg = argType[i]
849				arghandler = getattr(self, "arg_" + arg)
850				value = (arghandler(operator),) + value
851		else:
852			arghandler = getattr(self, "arg_" + argType)
853			value = arghandler(operator)
854		self.dict[operator] = value
855
856	def arg_number(self, name):
857		return self.pop()
858	def arg_SID(self, name):
859		return self.strings[self.pop()]
860	def arg_array(self, name):
861		return self.popall()
862
863
864def calcSubrBias(subrs):
865	nSubrs = len(subrs)
866	if nSubrs < 1240:
867		bias = 107
868	elif nSubrs < 33900:
869		bias = 1131
870	else:
871		bias = 32768
872	return bias
873
874