You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

831 lines
31 KiB

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