ttProgram.py revision 7842e56b97ce677b83bdab09cda48bc2d89ac75a
1"""ttLib.tables.ttProgram.py -- Assembler/disassembler for TrueType bytecode programs."""
2
3import array
4
5
6# first, the list of instructions that eat bytes or words from the instruction stream
7
8streamInstructions = [
9#	------  -----------  -----  ------------------------ ---  ------  ----------------------------------  --------------
10#	opcode     mnemonic argbits         descriptive name pops pushes        eats from instruction stream          pushes
11#	------  -----------  -----  ------------------------ ---  ------  ----------------------------------  --------------
12	(0x40,    'NPUSHB',     0,             'PushNBytes',  0, -1), #                      n, b1, b2,...bn      b1,b2...bn
13	(0x41,    'NPUSHW',     0,             'PushNWords',  0, -1), #                       n, w1, w2,...w      w1,w2...wn
14	(0xb0,     'PUSHB',     3,              'PushBytes',  0, -1), #                          b0, b1,..bn  b0, b1, ...,bn
15	(0xb8,     'PUSHW',     3,              'PushWords',  0, -1), #                           w0,w1,..wn   w0 ,w1, ...wn
16#	------  -----------  -----  ------------------------ ---  ------  ----------------------------------  --------------
17]
18
19
20# next, the list of "normal" instructions
21
22instructions = [
23#	------  -----------  -----  ------------------------ ---  ------  ----------------------------------  --------------
24#	opcode     mnemonic  argbits        descriptive name pops pushes                                pops          pushes
25#	------  -----------  -----  ------------------------ ---  ------  ----------------------------------  --------------
26	(0x7f,        'AA',     0,            'AdjustAngle',  1,  0), #                                    p               -
27	(0x64,       'ABS',     0,               'Absolute',  1,  1), #                                    n             |n|
28	(0x60,       'ADD',     0,                    'Add',  2,  1), #                               n2, n1       (n1 + n2)
29	(0x27,  'ALIGNPTS',     0,               'AlignPts',  2,  0), #                               p2, p1               -
30	(0x3c,   'ALIGNRP',     0,        'AlignRelativePt', -1,  0), #             p1, p2, ... , ploopvalue               -
31	(0x5a,       'AND',     0,             'LogicalAnd',  2,  1), #                               e2, e1               b
32	(0x2b,      'CALL',     0,           'CallFunction',  1,  0), #                                    f               -
33	(0x67,   'CEILING',     0,                'Ceiling',  1,  1), #                                    n         ceil(n)
34	(0x25,    'CINDEX',     0,        'CopyXToTopStack',  1,  1), #                                    k              ek
35	(0x22,     'CLEAR',     0,             'ClearStack', -1,  0), #               all items on the stack               -
36	(0x4f,     'DEBUG',     0,              'DebugCall',  1,  0), #                                    n               -
37	(0x73,   'DELTAC1',     0,       'DeltaExceptionC1', -1,  0), #    argn, cn, argn-1,cn-1, , arg1, c1               -
38	(0x74,   'DELTAC2',     0,       'DeltaExceptionC2', -1,  0), #    argn, cn, argn-1,cn-1, , arg1, c1               -
39	(0x75,   'DELTAC3',     0,       'DeltaExceptionC3', -1,  0), #    argn, cn, argn-1,cn-1, , arg1, c1               -
40	(0x5d,   'DELTAP1',     0,       'DeltaExceptionP1', -1,  0), #   argn, pn, argn-1, pn-1, , arg1, p1               -
41	(0x71,   'DELTAP2',     0,       'DeltaExceptionP2', -1,  0), #   argn, pn, argn-1, pn-1, , arg1, p1               -
42	(0x72,   'DELTAP3',     0,       'DeltaExceptionP3', -1,  0), #   argn, pn, argn-1, pn-1, , arg1, p1               -
43	(0x24,     'DEPTH',     0,          'GetDepthStack',  0,  1), #                                    -               n
44	(0x62,       'DIV',     0,                 'Divide',  2,  1), #                               n2, n1   (n1 * 64)/ n2
45	(0x20,       'DUP',     0,      'DuplicateTopStack',  1,  2), #                                    e            e, e
46	(0x59,       'EIF',     0,                  'EndIf',  0,  0), #                                    -               -
47	(0x1b,      'ELSE',     0,                   'Else',  0,  0), #                                    -               -
48	(0x2d,      'ENDF',     0,  'EndFunctionDefinition',  0,  0), #                                    -               -
49	(0x54,        'EQ',     0,                  'Equal',  2,  1), #                               e2, e1               b
50	(0x57,      'EVEN',     0,                   'Even',  1,  1), #                                    e               b
51	(0x2c,      'FDEF',     0,     'FunctionDefinition',  1,  0), #                                    f               -
52	(0x4e,   'FLIPOFF',     0,         'SetAutoFlipOff',  0,  0), #                                    -               -
53	(0x4d,    'FLIPON',     0,          'SetAutoFlipOn',  0,  0), #                                    -               -
54	(0x80,    'FLIPPT',     0,              'FlipPoint', -1,  0), #              p1, p2, ..., ploopvalue               -
55	(0x82, 'FLIPRGOFF',     0,           'FlipRangeOff',  2,  0), #                                 h, l               -
56	(0x81,  'FLIPRGON',     0,            'FlipRangeOn',  2,  0), #                                 h, l               -
57	(0x66,     'FLOOR',     0,                  'Floor',  1,  1), #                                    n        floor(n)
58	(0x46,        'GC',     1,      'GetCoordOnPVector',  1,  1), #                                    p               c
59	(0x88,   'GETINFO',     0,                'GetInfo',  1,  1), #                             selector          result
60	(0x0d,       'GFV',     0,             'GetFVector',  0,  2), #                                    -          px, py
61	(0x0c,       'GPV',     0,             'GetPVector',  0,  2), #                                    -          px, py
62	(0x52,        'GT',     0,            'GreaterThan',  2,  1), #                               e2, e1               b
63	(0x53,      'GTEQ',     0,     'GreaterThanOrEqual',  2,  1), #                               e2, e1               b
64	(0x89,      'IDEF',     0,  'InstructionDefinition',  1,  0), #                                    f               -
65	(0x58,        'IF',     0,                     'If',  1,  0), #                                    e               -
66	(0x8e,  'INSTCTRL',     0,    'SetInstrExecControl',  2,  0), #                                 s, v               -
67	(0x39,        'IP',     0,         'InterpolatePts', -1,  0), #             p1, p2, ... , ploopvalue               -
68	(0x0f,     'ISECT',     0,      'MovePtToIntersect',  5,  0), #                    a1, a0, b1, b0, p               -
69	(0x30,       'IUP',     1,      'InterpolateUntPts',  0,  0), #                                    -               -
70	(0x1c,      'JMPR',     0,                   'Jump',  1,  0), #                               offset               -
71	(0x79,      'JROF',     0,    'JumpRelativeOnFalse',  2,  0), #                            e, offset               -
72	(0x78,      'JROT',     0,     'JumpRelativeOnTrue',  2,  0), #                            e, offset               -
73	(0x2a,  'LOOPCALL',     0,    'LoopAndCallFunction',  2,  0), #                             f, count               -
74	(0x50,        'LT',     0,               'LessThan',  2,  1), #                               e2, e1               b
75	(0x51,      'LTEQ',     0,        'LessThenOrEqual',  2,  1), #                               e2, e1               b
76	(0x8b,       'MAX',     0,                'Maximum',  2,  1), #                               e2, e1     max(e1, e2)
77	(0x49,        'MD',     1,        'MeasureDistance',  2,  1), #                                p2,p1               d
78	(0x2e,      'MDAP',     1,        'MoveDirectAbsPt',  1,  0), #                                    p               -
79	(0xc0,      'MDRP',     5,        'MoveDirectRelPt',  1,  0), #                                    p               -
80	(0x3e,      'MIAP',     1,      'MoveIndirectAbsPt',  2,  0), #                                 n, p               -
81	(0x8c,       'MIN',     0,                'Minimum',  2,  1), #                               e2, e1     min(e1, e2)
82	(0x26,    'MINDEX',     0,        'MoveXToTopStack',  2,  1), #                                    k              ek
83	(0xe0,      'MIRP',     5,      'MoveIndirectRelPt',  1,  0), #                                 n, p               -
84	(0x4b,     'MPPEM',     0,      'MeasurePixelPerEm',  0,  1), #                                    -            ppem
85	(0x4c,       'MPS',     0,       'MeasurePointSize',  0,  1), #                                    -       pointSize
86	(0x3a,     'MSIRP',     1,    'MoveStackIndirRelPt',  2,  0), #                                 d, p               -
87	(0x63,       'MUL',     0,               'Multiply',  2,  1), #                               n2, n1    (n1 * n2)/64
88	(0x65,       'NEG',     0,                 'Negate',  1,  1), #                                    n              -n
89	(0x55,       'NEQ',     0,               'NotEqual',  2,  1), #                               e2, e1               b
90	(0x5c,       'NOT',     0,             'LogicalNot',  1,  1), #                                    e       ( not e )
91	(0x6c,    'NROUND',     2,                'NoRound',  1,  1), #                                   n1              n2
92	(0x56,       'ODD',     0,                    'Odd',  1,  1), #                                    e               b
93	(0x5b,        'OR',     0,              'LogicalOr',  2,  1), #                               e2, e1               b
94	(0x21,       'POP',     0,            'PopTopStack',  1,  0), #                                    e               -
95	(0x45,      'RCVT',     0,                'ReadCVT',  1,  1), #                             location           value
96	(0x7d,      'RDTG',     0,        'RoundDownToGrid',  0,  0), #                                    -               -
97	(0x7a,      'ROFF',     0,               'RoundOff',  0,  0), #                                    -               -
98	(0x8a,      'ROLL',     0,      'RollTopThreeStack',  3,  3), #                                a,b,c           b,a,c
99	(0x68,     'ROUND',     2,                  'Round',  1,  1), #                                   n1              n2
100	(0x43,        'RS',     0,              'ReadStore',  1,  1), #                                    n               v
101	(0x3d,      'RTDG',     0,      'RoundToDoubleGrid',  0,  0), #                                    -               -
102	(0x18,       'RTG',     0,            'RoundToGrid',  0,  0), #                                    -               -
103	(0x19,      'RTHG',     0,        'RoundToHalfGrid',  0,  0), #                                    -               -
104	(0x7c,      'RUTG',     0,          'RoundUpToGrid',  0,  0), #                                    -               -
105	(0x77,  'S45ROUND',     0,    'SuperRound45Degrees',  1,  0), #                                    n               -
106	(0x7e,     'SANGW',     0,         'SetAngleWeight',  1,  0), #                               weight               -
107	(0x85,  'SCANCTRL',     0,  'ScanConversionControl',  1,  0), #                                    n               -
108	(0x8d,  'SCANTYPE',     0,               'ScanType',  1,  0), #                                    n               -
109	(0x48,      'SCFS',     0,    'SetCoordFromStackFP',  2,  0), #                                 c, p               -
110	(0x1d,    'SCVTCI',     0,            'SetCVTCutIn',  1,  0), #                                    n               -
111	(0x5e,       'SDB',     0,   'SetDeltaBaseInGState',  1,  0), #                                    n               -
112	(0x86,    'SDPVTL',     1,   'SetDualPVectorToLine',  2,  0), #                               p2, p1               -
113	(0x5f,       'SDS',     0,  'SetDeltaShiftInGState',  1,  0), #                                    n               -
114	(0x0b,     'SFVFS',     0,    'SetFVectorFromStack',  2,  0), #                                 y, x               -
115	(0x04,    'SFVTCA',     1,       'SetFVectorToAxis',  0,  0), #                                    -               -
116	(0x08,     'SFVTL',     1,       'SetFVectorToLine',  2,  0), #                               p2, p1               -
117	(0x0e,    'SFVTPV',     0,    'SetFVectorToPVector',  0,  0), #                                    -               -
118	(0x34,       'SHC',     1,   'ShiftContourByLastPt',  1,  0), #                                    c               -
119	(0x32,       'SHP',     1,  'ShiftPointByLastPoint', -1,  0), #              p1, p2, ..., ploopvalue               -
120	(0x38,     'SHPIX',     0,       'ShiftZoneByPixel', -1,  0), #           d, p1, p2, ..., ploopvalue               -
121	(0x36,       'SHZ',     1,   'ShiftZoneByLastPoint',  1,  0), #                                    e               -
122	(0x17,     'SLOOP',     0,        'SetLoopVariable',  1,  0), #                                    n               -
123	(0x1a,       'SMD',     0,     'SetMinimumDistance',  1,  0), #                             distance               -
124	(0x0a,     'SPVFS',     0,    'SetPVectorFromStack',  2,  0), #                                 y, x               -
125	(0x02,    'SPVTCA',     1,       'SetPVectorToAxis',  0,  0), #                                    -               -
126	(0x06,     'SPVTL',     1,       'SetPVectorToLine',  2,  0), #                               p2, p1               -
127	(0x76,    'SROUND',     0,             'SuperRound',  1,  0), #                                    n               -
128	(0x10,      'SRP0',     0,           'SetRefPoint0',  1,  0), #                                    p               -
129	(0x11,      'SRP1',     0,           'SetRefPoint1',  1,  0), #                                    p               -
130	(0x12,      'SRP2',     0,           'SetRefPoint2',  1,  0), #                                    p               -
131	(0x1f,       'SSW',     0,         'SetSingleWidth',  1,  0), #                                    n               -
132	(0x1e,     'SSWCI',     0,    'SetSingleWidthCutIn',  1,  0), #                                    n               -
133	(0x61,       'SUB',     0,               'Subtract',  2,  1), #                               n2, n1       (n1 - n2)
134	(0x00,     'SVTCA',     1,      'SetFPVectorToAxis',  0,  0), #                                    -               -
135	(0x23,      'SWAP',     0,           'SwapTopStack',  2,  2), #                               e2, e1          e1, e2
136	(0x13,      'SZP0',     0,        'SetZonePointer0',  1,  0), #                                    n               -
137	(0x14,      'SZP1',     0,        'SetZonePointer1',  1,  0), #                                    n               -
138	(0x15,      'SZP2',     0,        'SetZonePointer2',  1,  0), #                                    n               -
139	(0x16,      'SZPS',     0,        'SetZonePointerS',  1,  0), #                                    n               -
140	(0x29,       'UTP',     0,              'UnTouchPt',  1,  0), #                                    p               -
141	(0x70,     'WCVTF',     0,       'WriteCVTInFUnits',  2,  0), #                                 n, l               -
142	(0x44,     'WCVTP',     0,       'WriteCVTInPixels',  2,  0), #                                 v, l               -
143	(0x42,        'WS',     0,             'WriteStore',  2,  0), #                                 v, l               -
144#	------  -----------  -----  ------------------------ ---  ------  ----------------------------------  --------------
145]
146
147
148def bitRepr(value, bits):
149	s = ""
150	for i in range(bits):
151		s = "01"[value & 0x1] + s
152		value = value >> 1
153	return s
154
155def makeOpcodeDict(instructionList):
156	opcodeDict = {}
157	for op, mnemonic, argbits, name, pops, pushes in instructionList:
158		if argbits:
159			argoffset = op
160			for i in range(1 << argbits):
161				opcodeDict[op+i] = mnemonic, argbits, argoffset, name
162		else:
163				opcodeDict[op] = mnemonic, 0, 0, name
164	return opcodeDict
165
166streamOpcodeDict = makeOpcodeDict(streamInstructions)
167opcodeDict = makeOpcodeDict(instructions)
168
169tt_instructions_error = "TT instructions error"
170
171
172class Program:
173
174	def __init__(self):
175		pass
176
177	def fromBytecode(self, bytecode):
178		self.bytecode = array.array("B")
179		self.bytecode.fromstring(bytecode)
180
181	def fromAssembly(self, assembly):
182		self.assembly = assembly
183
184	def getBytecode(self):
185		if not hasattr(self, "bytecode"):
186			self._assemble()
187		return self.bytecode.tostring()
188
189	def getAssembly(self):
190		if not hasattr(self, "assembly"):
191			self._disassemble()
192		return self.assembly
193
194	def _assemble(self):
195		xxx
196
197	def _disassemble(self):
198		assembly = []
199		i = 0
200		bytecode = self.bytecode
201		numBytecode = len(bytecode)
202		while i < numBytecode:
203			op = bytecode[i]
204			arg = 0
205			try:
206				mnemonic, argbits, argoffset, name = opcodeDict[op]
207			except KeyError:
208				try:
209					mnemonic, argbits, argoffset, name = streamOpcodeDict[op]
210				except KeyError:
211					raise tt_instructions_error, "illegal opcode: 0x%.2x" % op
212				pushbytes = pushwords = 0
213				if argbits:
214					if mnemonic == "PUSHB":
215						pushbytes = op - argoffset + 1
216					else:
217						pushwords = op - argoffset + 1
218				else:
219					i = i + 1
220					if mnemonic == "NPUSHB":
221						pushbytes = bytecode[i]
222					else:
223						pushwords = bytecode[i]
224				i = i + 1
225				assembly.append(mnemonic + "[ ]")
226				for j in range(pushbytes):
227					assembly.append(`bytecode[i]`)
228					i = i + 1
229				for j in range(0, pushwords, 2):
230					assembly.append(`(bytecode[i] << 8) + bytecode[i+1]`)
231					i = i + 2
232			else:
233				if argbits:
234					assembly.append(mnemonic + "[%s]" % bitRepr(op - argoffset, argbits))
235				else:
236					assembly.append(mnemonic + "[ ]")
237				i = i + 1
238		self.assembly = assembly
239		del self.bytecode
240
241
242fpgm = '@\01476&%\037\023\022\015\014\005\004\002, \260\003%E#E#ah\212 Eh \212#D`D-,KRXED\033!!Y-,  EhD \260\001` E\260Fvh\030\212E`D-,\260\022+\260\002%E\260\002%Ej\260@\213`\260\002%#D!!!-,\260\023+\260\002%E\260\002%Ej\270\377\300\214`\260\002%#D!!!-,\261\000\003%EhTX\260\003%E\260\003%E`h \260\004%#D\260\004%#D\033\260\003% Eh \212#D\260\003%Eh`\260\003%#DY-,\260\003% Eh \212#D\260\003%Eh`\260\003%#D-,KRXED\033!!Y-,F#F`\212\212F# F\212`\212a\270\377\200b# \020#\212\261KK\212pE` \260\000PX\260\001a\270\377\272\213\033\260F\214Y\260\020`h\001:-, E\260\003%FRX?\033!\021Y-,KS#KQZX E\212`D\033!!Y-,KS#KQZX8\033!!Y-'
243gpgm = '@\022\011\003\207@\005\200\004\207\000\010\007\202\001\010\004\202\000\010\000\020\320\355\020\336\355\001\020\336\375\032}\336\032\030\375\31610'
244
245p = Program()
246p.fromBytecode(fpgm)
247for line in p.getAssembly():
248	print line
249
250