swfinterp.py (31486B)
1 from __future__ import unicode_literals 2 3 import collections 4 import io 5 import zlib 6 7 from .compat import ( 8 compat_str, 9 compat_struct_unpack, 10 ) 11 from .utils import ( 12 ExtractorError, 13 ) 14 15 16 def _extract_tags(file_contents): 17 if file_contents[1:3] != b'WS': 18 raise ExtractorError( 19 'Not an SWF file; header is %r' % file_contents[:3]) 20 if file_contents[:1] == b'C': 21 content = zlib.decompress(file_contents[8:]) 22 else: 23 raise NotImplementedError( 24 'Unsupported compression format %r' % 25 file_contents[:1]) 26 27 # Determine number of bits in framesize rectangle 28 framesize_nbits = compat_struct_unpack('!B', content[:1])[0] >> 3 29 framesize_len = (5 + 4 * framesize_nbits + 7) // 8 30 31 pos = framesize_len + 2 + 2 32 while pos < len(content): 33 header16 = compat_struct_unpack('<H', content[pos:pos + 2])[0] 34 pos += 2 35 tag_code = header16 >> 6 36 tag_len = header16 & 0x3f 37 if tag_len == 0x3f: 38 tag_len = compat_struct_unpack('<I', content[pos:pos + 4])[0] 39 pos += 4 40 assert pos + tag_len <= len(content), \ 41 ('Tag %d ends at %d+%d - that\'s longer than the file (%d)' 42 % (tag_code, pos, tag_len, len(content))) 43 yield (tag_code, content[pos:pos + tag_len]) 44 pos += tag_len 45 46 47 class _AVMClass_Object(object): 48 def __init__(self, avm_class): 49 self.avm_class = avm_class 50 51 def __repr__(self): 52 return '%s#%x' % (self.avm_class.name, id(self)) 53 54 55 class _ScopeDict(dict): 56 def __init__(self, avm_class): 57 super(_ScopeDict, self).__init__() 58 self.avm_class = avm_class 59 60 def __repr__(self): 61 return '%s__Scope(%s)' % ( 62 self.avm_class.name, 63 super(_ScopeDict, self).__repr__()) 64 65 66 class _AVMClass(object): 67 def __init__(self, name_idx, name, static_properties=None): 68 self.name_idx = name_idx 69 self.name = name 70 self.method_names = {} 71 self.method_idxs = {} 72 self.methods = {} 73 self.method_pyfunctions = {} 74 self.static_properties = static_properties if static_properties else {} 75 76 self.variables = _ScopeDict(self) 77 self.constants = {} 78 79 def make_object(self): 80 return _AVMClass_Object(self) 81 82 def __repr__(self): 83 return '_AVMClass(%s)' % (self.name) 84 85 def register_methods(self, methods): 86 self.method_names.update(methods.items()) 87 self.method_idxs.update(dict( 88 (idx, name) 89 for name, idx in methods.items())) 90 91 92 class _Multiname(object): 93 def __init__(self, kind): 94 self.kind = kind 95 96 def __repr__(self): 97 return '[MULTINAME kind: 0x%x]' % self.kind 98 99 100 def _read_int(reader): 101 res = 0 102 shift = 0 103 for _ in range(5): 104 buf = reader.read(1) 105 assert len(buf) == 1 106 b = compat_struct_unpack('<B', buf)[0] 107 res = res | ((b & 0x7f) << shift) 108 if b & 0x80 == 0: 109 break 110 shift += 7 111 return res 112 113 114 def _u30(reader): 115 res = _read_int(reader) 116 assert res & 0xf0000000 == 0 117 return res 118 119 120 _u32 = _read_int 121 122 123 def _s32(reader): 124 v = _read_int(reader) 125 if v & 0x80000000 != 0: 126 v = - ((v ^ 0xffffffff) + 1) 127 return v 128 129 130 def _s24(reader): 131 bs = reader.read(3) 132 assert len(bs) == 3 133 last_byte = b'\xff' if (ord(bs[2:3]) >= 0x80) else b'\x00' 134 return compat_struct_unpack('<i', bs + last_byte)[0] 135 136 137 def _read_string(reader): 138 slen = _u30(reader) 139 resb = reader.read(slen) 140 assert len(resb) == slen 141 return resb.decode('utf-8') 142 143 144 def _read_bytes(count, reader): 145 assert count >= 0 146 resb = reader.read(count) 147 assert len(resb) == count 148 return resb 149 150 151 def _read_byte(reader): 152 resb = _read_bytes(1, reader=reader) 153 res = compat_struct_unpack('<B', resb)[0] 154 return res 155 156 157 StringClass = _AVMClass('(no name idx)', 'String') 158 ByteArrayClass = _AVMClass('(no name idx)', 'ByteArray') 159 TimerClass = _AVMClass('(no name idx)', 'Timer') 160 TimerEventClass = _AVMClass('(no name idx)', 'TimerEvent', {'TIMER': 'timer'}) 161 _builtin_classes = { 162 StringClass.name: StringClass, 163 ByteArrayClass.name: ByteArrayClass, 164 TimerClass.name: TimerClass, 165 TimerEventClass.name: TimerEventClass, 166 } 167 168 169 class _Undefined(object): 170 def __bool__(self): 171 return False 172 __nonzero__ = __bool__ 173 174 def __hash__(self): 175 return 0 176 177 def __str__(self): 178 return 'undefined' 179 __repr__ = __str__ 180 181 182 undefined = _Undefined() 183 184 185 class SWFInterpreter(object): 186 def __init__(self, file_contents): 187 self._patched_functions = { 188 (TimerClass, 'addEventListener'): lambda params: undefined, 189 } 190 code_tag = next(tag 191 for tag_code, tag in _extract_tags(file_contents) 192 if tag_code == 82) 193 p = code_tag.index(b'\0', 4) + 1 194 code_reader = io.BytesIO(code_tag[p:]) 195 196 # Parse ABC (AVM2 ByteCode) 197 198 # Define a couple convenience methods 199 u30 = lambda *args: _u30(*args, reader=code_reader) 200 s32 = lambda *args: _s32(*args, reader=code_reader) 201 u32 = lambda *args: _u32(*args, reader=code_reader) 202 read_bytes = lambda *args: _read_bytes(*args, reader=code_reader) 203 read_byte = lambda *args: _read_byte(*args, reader=code_reader) 204 205 # minor_version + major_version 206 read_bytes(2 + 2) 207 208 # Constant pool 209 int_count = u30() 210 self.constant_ints = [0] 211 for _c in range(1, int_count): 212 self.constant_ints.append(s32()) 213 self.constant_uints = [0] 214 uint_count = u30() 215 for _c in range(1, uint_count): 216 self.constant_uints.append(u32()) 217 double_count = u30() 218 read_bytes(max(0, (double_count - 1)) * 8) 219 string_count = u30() 220 self.constant_strings = [''] 221 for _c in range(1, string_count): 222 s = _read_string(code_reader) 223 self.constant_strings.append(s) 224 namespace_count = u30() 225 for _c in range(1, namespace_count): 226 read_bytes(1) # kind 227 u30() # name 228 ns_set_count = u30() 229 for _c in range(1, ns_set_count): 230 count = u30() 231 for _c2 in range(count): 232 u30() 233 multiname_count = u30() 234 MULTINAME_SIZES = { 235 0x07: 2, # QName 236 0x0d: 2, # QNameA 237 0x0f: 1, # RTQName 238 0x10: 1, # RTQNameA 239 0x11: 0, # RTQNameL 240 0x12: 0, # RTQNameLA 241 0x09: 2, # Multiname 242 0x0e: 2, # MultinameA 243 0x1b: 1, # MultinameL 244 0x1c: 1, # MultinameLA 245 } 246 self.multinames = [''] 247 for _c in range(1, multiname_count): 248 kind = u30() 249 assert kind in MULTINAME_SIZES, 'Invalid multiname kind %r' % kind 250 if kind == 0x07: 251 u30() # namespace_idx 252 name_idx = u30() 253 self.multinames.append(self.constant_strings[name_idx]) 254 elif kind == 0x09: 255 name_idx = u30() 256 u30() 257 self.multinames.append(self.constant_strings[name_idx]) 258 else: 259 self.multinames.append(_Multiname(kind)) 260 for _c2 in range(MULTINAME_SIZES[kind]): 261 u30() 262 263 # Methods 264 method_count = u30() 265 MethodInfo = collections.namedtuple( 266 'MethodInfo', 267 ['NEED_ARGUMENTS', 'NEED_REST']) 268 method_infos = [] 269 for method_id in range(method_count): 270 param_count = u30() 271 u30() # return type 272 for _ in range(param_count): 273 u30() # param type 274 u30() # name index (always 0 for youtube) 275 flags = read_byte() 276 if flags & 0x08 != 0: 277 # Options present 278 option_count = u30() 279 for c in range(option_count): 280 u30() # val 281 read_bytes(1) # kind 282 if flags & 0x80 != 0: 283 # Param names present 284 for _ in range(param_count): 285 u30() # param name 286 mi = MethodInfo(flags & 0x01 != 0, flags & 0x04 != 0) 287 method_infos.append(mi) 288 289 # Metadata 290 metadata_count = u30() 291 for _c in range(metadata_count): 292 u30() # name 293 item_count = u30() 294 for _c2 in range(item_count): 295 u30() # key 296 u30() # value 297 298 def parse_traits_info(): 299 trait_name_idx = u30() 300 kind_full = read_byte() 301 kind = kind_full & 0x0f 302 attrs = kind_full >> 4 303 methods = {} 304 constants = None 305 if kind == 0x00: # Slot 306 u30() # Slot id 307 u30() # type_name_idx 308 vindex = u30() 309 if vindex != 0: 310 read_byte() # vkind 311 elif kind == 0x06: # Const 312 u30() # Slot id 313 u30() # type_name_idx 314 vindex = u30() 315 vkind = 'any' 316 if vindex != 0: 317 vkind = read_byte() 318 if vkind == 0x03: # Constant_Int 319 value = self.constant_ints[vindex] 320 elif vkind == 0x04: # Constant_UInt 321 value = self.constant_uints[vindex] 322 else: 323 return {}, None # Ignore silently for now 324 constants = {self.multinames[trait_name_idx]: value} 325 elif kind in (0x01, 0x02, 0x03): # Method / Getter / Setter 326 u30() # disp_id 327 method_idx = u30() 328 methods[self.multinames[trait_name_idx]] = method_idx 329 elif kind == 0x04: # Class 330 u30() # slot_id 331 u30() # classi 332 elif kind == 0x05: # Function 333 u30() # slot_id 334 function_idx = u30() 335 methods[function_idx] = self.multinames[trait_name_idx] 336 else: 337 raise ExtractorError('Unsupported trait kind %d' % kind) 338 339 if attrs & 0x4 != 0: # Metadata present 340 metadata_count = u30() 341 for _c3 in range(metadata_count): 342 u30() # metadata index 343 344 return methods, constants 345 346 # Classes 347 class_count = u30() 348 classes = [] 349 for class_id in range(class_count): 350 name_idx = u30() 351 352 cname = self.multinames[name_idx] 353 avm_class = _AVMClass(name_idx, cname) 354 classes.append(avm_class) 355 356 u30() # super_name idx 357 flags = read_byte() 358 if flags & 0x08 != 0: # Protected namespace is present 359 u30() # protected_ns_idx 360 intrf_count = u30() 361 for _c2 in range(intrf_count): 362 u30() 363 u30() # iinit 364 trait_count = u30() 365 for _c2 in range(trait_count): 366 trait_methods, trait_constants = parse_traits_info() 367 avm_class.register_methods(trait_methods) 368 if trait_constants: 369 avm_class.constants.update(trait_constants) 370 371 assert len(classes) == class_count 372 self._classes_by_name = dict((c.name, c) for c in classes) 373 374 for avm_class in classes: 375 avm_class.cinit_idx = u30() 376 trait_count = u30() 377 for _c2 in range(trait_count): 378 trait_methods, trait_constants = parse_traits_info() 379 avm_class.register_methods(trait_methods) 380 if trait_constants: 381 avm_class.constants.update(trait_constants) 382 383 # Scripts 384 script_count = u30() 385 for _c in range(script_count): 386 u30() # init 387 trait_count = u30() 388 for _c2 in range(trait_count): 389 parse_traits_info() 390 391 # Method bodies 392 method_body_count = u30() 393 Method = collections.namedtuple('Method', ['code', 'local_count']) 394 self._all_methods = [] 395 for _c in range(method_body_count): 396 method_idx = u30() 397 u30() # max_stack 398 local_count = u30() 399 u30() # init_scope_depth 400 u30() # max_scope_depth 401 code_length = u30() 402 code = read_bytes(code_length) 403 m = Method(code, local_count) 404 self._all_methods.append(m) 405 for avm_class in classes: 406 if method_idx in avm_class.method_idxs: 407 avm_class.methods[avm_class.method_idxs[method_idx]] = m 408 exception_count = u30() 409 for _c2 in range(exception_count): 410 u30() # from 411 u30() # to 412 u30() # target 413 u30() # exc_type 414 u30() # var_name 415 trait_count = u30() 416 for _c2 in range(trait_count): 417 parse_traits_info() 418 419 assert p + code_reader.tell() == len(code_tag) 420 421 def patch_function(self, avm_class, func_name, f): 422 self._patched_functions[(avm_class, func_name)] = f 423 424 def extract_class(self, class_name, call_cinit=True): 425 try: 426 res = self._classes_by_name[class_name] 427 except KeyError: 428 raise ExtractorError('Class %r not found' % class_name) 429 430 if call_cinit and hasattr(res, 'cinit_idx'): 431 res.register_methods({'$cinit': res.cinit_idx}) 432 res.methods['$cinit'] = self._all_methods[res.cinit_idx] 433 cinit = self.extract_function(res, '$cinit') 434 cinit([]) 435 436 return res 437 438 def extract_function(self, avm_class, func_name): 439 p = self._patched_functions.get((avm_class, func_name)) 440 if p: 441 return p 442 if func_name in avm_class.method_pyfunctions: 443 return avm_class.method_pyfunctions[func_name] 444 if func_name in self._classes_by_name: 445 return self._classes_by_name[func_name].make_object() 446 if func_name not in avm_class.methods: 447 raise ExtractorError('Cannot find function %s.%s' % ( 448 avm_class.name, func_name)) 449 m = avm_class.methods[func_name] 450 451 def resfunc(args): 452 # Helper functions 453 coder = io.BytesIO(m.code) 454 s24 = lambda: _s24(coder) 455 u30 = lambda: _u30(coder) 456 457 registers = [avm_class.variables] + list(args) + [None] * m.local_count 458 stack = [] 459 scopes = collections.deque([ 460 self._classes_by_name, avm_class.constants, avm_class.variables]) 461 while True: 462 opcode = _read_byte(coder) 463 if opcode == 9: # label 464 pass # Spec says: "Do nothing." 465 elif opcode == 16: # jump 466 offset = s24() 467 coder.seek(coder.tell() + offset) 468 elif opcode == 17: # iftrue 469 offset = s24() 470 value = stack.pop() 471 if value: 472 coder.seek(coder.tell() + offset) 473 elif opcode == 18: # iffalse 474 offset = s24() 475 value = stack.pop() 476 if not value: 477 coder.seek(coder.tell() + offset) 478 elif opcode == 19: # ifeq 479 offset = s24() 480 value2 = stack.pop() 481 value1 = stack.pop() 482 if value2 == value1: 483 coder.seek(coder.tell() + offset) 484 elif opcode == 20: # ifne 485 offset = s24() 486 value2 = stack.pop() 487 value1 = stack.pop() 488 if value2 != value1: 489 coder.seek(coder.tell() + offset) 490 elif opcode == 21: # iflt 491 offset = s24() 492 value2 = stack.pop() 493 value1 = stack.pop() 494 if value1 < value2: 495 coder.seek(coder.tell() + offset) 496 elif opcode == 32: # pushnull 497 stack.append(None) 498 elif opcode == 33: # pushundefined 499 stack.append(undefined) 500 elif opcode == 36: # pushbyte 501 v = _read_byte(coder) 502 stack.append(v) 503 elif opcode == 37: # pushshort 504 v = u30() 505 stack.append(v) 506 elif opcode == 38: # pushtrue 507 stack.append(True) 508 elif opcode == 39: # pushfalse 509 stack.append(False) 510 elif opcode == 40: # pushnan 511 stack.append(float('NaN')) 512 elif opcode == 42: # dup 513 value = stack[-1] 514 stack.append(value) 515 elif opcode == 44: # pushstring 516 idx = u30() 517 stack.append(self.constant_strings[idx]) 518 elif opcode == 48: # pushscope 519 new_scope = stack.pop() 520 scopes.append(new_scope) 521 elif opcode == 66: # construct 522 arg_count = u30() 523 args = list(reversed( 524 [stack.pop() for _ in range(arg_count)])) 525 obj = stack.pop() 526 res = obj.avm_class.make_object() 527 stack.append(res) 528 elif opcode == 70: # callproperty 529 index = u30() 530 mname = self.multinames[index] 531 arg_count = u30() 532 args = list(reversed( 533 [stack.pop() for _ in range(arg_count)])) 534 obj = stack.pop() 535 536 if obj == StringClass: 537 if mname == 'String': 538 assert len(args) == 1 539 assert isinstance(args[0], ( 540 int, compat_str, _Undefined)) 541 if args[0] == undefined: 542 res = 'undefined' 543 else: 544 res = compat_str(args[0]) 545 stack.append(res) 546 continue 547 else: 548 raise NotImplementedError( 549 'Function String.%s is not yet implemented' 550 % mname) 551 elif isinstance(obj, _AVMClass_Object): 552 func = self.extract_function(obj.avm_class, mname) 553 res = func(args) 554 stack.append(res) 555 continue 556 elif isinstance(obj, _AVMClass): 557 func = self.extract_function(obj, mname) 558 res = func(args) 559 stack.append(res) 560 continue 561 elif isinstance(obj, _ScopeDict): 562 if mname in obj.avm_class.method_names: 563 func = self.extract_function(obj.avm_class, mname) 564 res = func(args) 565 else: 566 res = obj[mname] 567 stack.append(res) 568 continue 569 elif isinstance(obj, compat_str): 570 if mname == 'split': 571 assert len(args) == 1 572 assert isinstance(args[0], compat_str) 573 if args[0] == '': 574 res = list(obj) 575 else: 576 res = obj.split(args[0]) 577 stack.append(res) 578 continue 579 elif mname == 'charCodeAt': 580 assert len(args) <= 1 581 idx = 0 if len(args) == 0 else args[0] 582 assert isinstance(idx, int) 583 res = ord(obj[idx]) 584 stack.append(res) 585 continue 586 elif isinstance(obj, list): 587 if mname == 'slice': 588 assert len(args) == 1 589 assert isinstance(args[0], int) 590 res = obj[args[0]:] 591 stack.append(res) 592 continue 593 elif mname == 'join': 594 assert len(args) == 1 595 assert isinstance(args[0], compat_str) 596 res = args[0].join(obj) 597 stack.append(res) 598 continue 599 raise NotImplementedError( 600 'Unsupported property %r on %r' 601 % (mname, obj)) 602 elif opcode == 71: # returnvoid 603 res = undefined 604 return res 605 elif opcode == 72: # returnvalue 606 res = stack.pop() 607 return res 608 elif opcode == 73: # constructsuper 609 # Not yet implemented, just hope it works without it 610 arg_count = u30() 611 args = list(reversed( 612 [stack.pop() for _ in range(arg_count)])) 613 obj = stack.pop() 614 elif opcode == 74: # constructproperty 615 index = u30() 616 arg_count = u30() 617 args = list(reversed( 618 [stack.pop() for _ in range(arg_count)])) 619 obj = stack.pop() 620 621 mname = self.multinames[index] 622 assert isinstance(obj, _AVMClass) 623 624 # We do not actually call the constructor for now; 625 # we just pretend it does nothing 626 stack.append(obj.make_object()) 627 elif opcode == 79: # callpropvoid 628 index = u30() 629 mname = self.multinames[index] 630 arg_count = u30() 631 args = list(reversed( 632 [stack.pop() for _ in range(arg_count)])) 633 obj = stack.pop() 634 if isinstance(obj, _AVMClass_Object): 635 func = self.extract_function(obj.avm_class, mname) 636 res = func(args) 637 assert res is undefined 638 continue 639 if isinstance(obj, _ScopeDict): 640 assert mname in obj.avm_class.method_names 641 func = self.extract_function(obj.avm_class, mname) 642 res = func(args) 643 assert res is undefined 644 continue 645 if mname == 'reverse': 646 assert isinstance(obj, list) 647 obj.reverse() 648 else: 649 raise NotImplementedError( 650 'Unsupported (void) property %r on %r' 651 % (mname, obj)) 652 elif opcode == 86: # newarray 653 arg_count = u30() 654 arr = [] 655 for i in range(arg_count): 656 arr.append(stack.pop()) 657 arr = arr[::-1] 658 stack.append(arr) 659 elif opcode == 93: # findpropstrict 660 index = u30() 661 mname = self.multinames[index] 662 for s in reversed(scopes): 663 if mname in s: 664 res = s 665 break 666 else: 667 res = scopes[0] 668 if mname not in res and mname in _builtin_classes: 669 stack.append(_builtin_classes[mname]) 670 else: 671 stack.append(res[mname]) 672 elif opcode == 94: # findproperty 673 index = u30() 674 mname = self.multinames[index] 675 for s in reversed(scopes): 676 if mname in s: 677 res = s 678 break 679 else: 680 res = avm_class.variables 681 stack.append(res) 682 elif opcode == 96: # getlex 683 index = u30() 684 mname = self.multinames[index] 685 for s in reversed(scopes): 686 if mname in s: 687 scope = s 688 break 689 else: 690 scope = avm_class.variables 691 692 if mname in scope: 693 res = scope[mname] 694 elif mname in _builtin_classes: 695 res = _builtin_classes[mname] 696 else: 697 # Assume uninitialized 698 # TODO warn here 699 res = undefined 700 stack.append(res) 701 elif opcode == 97: # setproperty 702 index = u30() 703 value = stack.pop() 704 idx = self.multinames[index] 705 if isinstance(idx, _Multiname): 706 idx = stack.pop() 707 obj = stack.pop() 708 obj[idx] = value 709 elif opcode == 98: # getlocal 710 index = u30() 711 stack.append(registers[index]) 712 elif opcode == 99: # setlocal 713 index = u30() 714 value = stack.pop() 715 registers[index] = value 716 elif opcode == 102: # getproperty 717 index = u30() 718 pname = self.multinames[index] 719 if pname == 'length': 720 obj = stack.pop() 721 assert isinstance(obj, (compat_str, list)) 722 stack.append(len(obj)) 723 elif isinstance(pname, compat_str): # Member access 724 obj = stack.pop() 725 if isinstance(obj, _AVMClass): 726 res = obj.static_properties[pname] 727 stack.append(res) 728 continue 729 730 assert isinstance(obj, (dict, _ScopeDict)),\ 731 'Accessing member %r on %r' % (pname, obj) 732 res = obj.get(pname, undefined) 733 stack.append(res) 734 else: # Assume attribute access 735 idx = stack.pop() 736 assert isinstance(idx, int) 737 obj = stack.pop() 738 assert isinstance(obj, list) 739 stack.append(obj[idx]) 740 elif opcode == 104: # initproperty 741 index = u30() 742 value = stack.pop() 743 idx = self.multinames[index] 744 if isinstance(idx, _Multiname): 745 idx = stack.pop() 746 obj = stack.pop() 747 obj[idx] = value 748 elif opcode == 115: # convert_ 749 value = stack.pop() 750 intvalue = int(value) 751 stack.append(intvalue) 752 elif opcode == 128: # coerce 753 u30() 754 elif opcode == 130: # coerce_a 755 value = stack.pop() 756 # um, yes, it's any value 757 stack.append(value) 758 elif opcode == 133: # coerce_s 759 assert isinstance(stack[-1], (type(None), compat_str)) 760 elif opcode == 147: # decrement 761 value = stack.pop() 762 assert isinstance(value, int) 763 stack.append(value - 1) 764 elif opcode == 149: # typeof 765 value = stack.pop() 766 return { 767 _Undefined: 'undefined', 768 compat_str: 'String', 769 int: 'Number', 770 float: 'Number', 771 }[type(value)] 772 elif opcode == 160: # add 773 value2 = stack.pop() 774 value1 = stack.pop() 775 res = value1 + value2 776 stack.append(res) 777 elif opcode == 161: # subtract 778 value2 = stack.pop() 779 value1 = stack.pop() 780 res = value1 - value2 781 stack.append(res) 782 elif opcode == 162: # multiply 783 value2 = stack.pop() 784 value1 = stack.pop() 785 res = value1 * value2 786 stack.append(res) 787 elif opcode == 164: # modulo 788 value2 = stack.pop() 789 value1 = stack.pop() 790 res = value1 % value2 791 stack.append(res) 792 elif opcode == 168: # bitand 793 value2 = stack.pop() 794 value1 = stack.pop() 795 assert isinstance(value1, int) 796 assert isinstance(value2, int) 797 res = value1 & value2 798 stack.append(res) 799 elif opcode == 171: # equals 800 value2 = stack.pop() 801 value1 = stack.pop() 802 result = value1 == value2 803 stack.append(result) 804 elif opcode == 175: # greaterequals 805 value2 = stack.pop() 806 value1 = stack.pop() 807 result = value1 >= value2 808 stack.append(result) 809 elif opcode == 192: # increment_i 810 value = stack.pop() 811 assert isinstance(value, int) 812 stack.append(value + 1) 813 elif opcode == 208: # getlocal_0 814 stack.append(registers[0]) 815 elif opcode == 209: # getlocal_1 816 stack.append(registers[1]) 817 elif opcode == 210: # getlocal_2 818 stack.append(registers[2]) 819 elif opcode == 211: # getlocal_3 820 stack.append(registers[3]) 821 elif opcode == 212: # setlocal_0 822 registers[0] = stack.pop() 823 elif opcode == 213: # setlocal_1 824 registers[1] = stack.pop() 825 elif opcode == 214: # setlocal_2 826 registers[2] = stack.pop() 827 elif opcode == 215: # setlocal_3 828 registers[3] = stack.pop() 829 else: 830 raise NotImplementedError( 831 'Unsupported opcode %d' % opcode) 832 833 avm_class.method_pyfunctions[func_name] = resfunc 834 return resfunc