[swfinterp] Implement various opcodes
This commit is contained in:
parent
8d05f2c16a
commit
4686ae4b64
1 changed files with 40 additions and 6 deletions
|
@ -151,6 +151,16 @@ def _read_byte(reader):
|
||||||
StringClass = _AVMClass('(no name idx)', 'String')
|
StringClass = _AVMClass('(no name idx)', 'String')
|
||||||
|
|
||||||
|
|
||||||
|
class _Undefined(object):
|
||||||
|
def __boolean__(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
undefined = _Undefined()
|
||||||
|
|
||||||
|
|
||||||
class SWFInterpreter(object):
|
class SWFInterpreter(object):
|
||||||
def __init__(self, file_contents):
|
def __init__(self, file_contents):
|
||||||
self._patched_functions = {}
|
self._patched_functions = {}
|
||||||
|
@ -423,6 +433,8 @@ class SWFInterpreter(object):
|
||||||
coder.seek(coder.tell() + offset)
|
coder.seek(coder.tell() + offset)
|
||||||
elif opcode == 32: # pushnull
|
elif opcode == 32: # pushnull
|
||||||
stack.append(None)
|
stack.append(None)
|
||||||
|
elif opcode == 33: # pushundefined
|
||||||
|
stack.append(undefined)
|
||||||
elif opcode == 36: # pushbyte
|
elif opcode == 36: # pushbyte
|
||||||
v = _read_byte(coder)
|
v = _read_byte(coder)
|
||||||
stack.append(v)
|
stack.append(v)
|
||||||
|
@ -430,6 +442,8 @@ class SWFInterpreter(object):
|
||||||
stack.append(True)
|
stack.append(True)
|
||||||
elif opcode == 39: # pushfalse
|
elif opcode == 39: # pushfalse
|
||||||
stack.append(False)
|
stack.append(False)
|
||||||
|
elif opcode == 40: # pushnan
|
||||||
|
stack.append(float('NaN'))
|
||||||
elif opcode == 42: # dup
|
elif opcode == 42: # dup
|
||||||
value = stack[-1]
|
value = stack[-1]
|
||||||
stack.append(value)
|
stack.append(value)
|
||||||
|
@ -493,8 +507,12 @@ class SWFInterpreter(object):
|
||||||
elif obj == StringClass:
|
elif obj == StringClass:
|
||||||
if mname == 'String':
|
if mname == 'String':
|
||||||
assert len(args) == 1
|
assert len(args) == 1
|
||||||
assert isinstance(args[0], (int, compat_str))
|
assert isinstance(args[0], (
|
||||||
res = compat_str(args[0])
|
int, compat_str, _Undefined))
|
||||||
|
if args[0] == undefined:
|
||||||
|
res = 'undefined'
|
||||||
|
else:
|
||||||
|
res = compat_str(args[0])
|
||||||
stack.append(res)
|
stack.append(res)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
@ -505,7 +523,7 @@ class SWFInterpreter(object):
|
||||||
'Unsupported property %r on %r'
|
'Unsupported property %r on %r'
|
||||||
% (mname, obj))
|
% (mname, obj))
|
||||||
elif opcode == 71: # returnvoid
|
elif opcode == 71: # returnvoid
|
||||||
res = None
|
res = undefined
|
||||||
return res
|
return res
|
||||||
elif opcode == 72: # returnvalue
|
elif opcode == 72: # returnvalue
|
||||||
res = stack.pop()
|
res = stack.pop()
|
||||||
|
@ -533,13 +551,13 @@ class SWFInterpreter(object):
|
||||||
if isinstance(obj, _AVMClass_Object):
|
if isinstance(obj, _AVMClass_Object):
|
||||||
func = self.extract_function(obj.avm_class, mname)
|
func = self.extract_function(obj.avm_class, mname)
|
||||||
res = func(args)
|
res = func(args)
|
||||||
assert res is None
|
assert res is undefined
|
||||||
continue
|
continue
|
||||||
if isinstance(obj, _ScopeDict):
|
if isinstance(obj, _ScopeDict):
|
||||||
assert mname in obj.avm_class.method_names
|
assert mname in obj.avm_class.method_names
|
||||||
func = self.extract_function(obj.avm_class, mname)
|
func = self.extract_function(obj.avm_class, mname)
|
||||||
res = func(args)
|
res = func(args)
|
||||||
assert res is None
|
assert res is undefined
|
||||||
continue
|
continue
|
||||||
if mname == 'reverse':
|
if mname == 'reverse':
|
||||||
assert isinstance(obj, list)
|
assert isinstance(obj, list)
|
||||||
|
@ -617,7 +635,7 @@ class SWFInterpreter(object):
|
||||||
obj = stack.pop()
|
obj = stack.pop()
|
||||||
assert isinstance(obj, (dict, _ScopeDict)), \
|
assert isinstance(obj, (dict, _ScopeDict)), \
|
||||||
'Accessing member %r on %r' % (pname, obj)
|
'Accessing member %r on %r' % (pname, obj)
|
||||||
res = obj.get(pname, None)
|
res = obj.get(pname, undefined)
|
||||||
stack.append(res)
|
stack.append(res)
|
||||||
else: # Assume attribute access
|
else: # Assume attribute access
|
||||||
idx = stack.pop()
|
idx = stack.pop()
|
||||||
|
@ -631,8 +649,24 @@ class SWFInterpreter(object):
|
||||||
stack.append(intvalue)
|
stack.append(intvalue)
|
||||||
elif opcode == 128: # coerce
|
elif opcode == 128: # coerce
|
||||||
u30()
|
u30()
|
||||||
|
elif opcode == 130: # coerce_a
|
||||||
|
value = stack.pop()
|
||||||
|
# um, yes, it's any value
|
||||||
|
stack.append(value)
|
||||||
elif opcode == 133: # coerce_s
|
elif opcode == 133: # coerce_s
|
||||||
assert isinstance(stack[-1], (type(None), compat_str))
|
assert isinstance(stack[-1], (type(None), compat_str))
|
||||||
|
elif opcode == 147: # decrement
|
||||||
|
value = stack.pop()
|
||||||
|
assert isinstance(value, int)
|
||||||
|
stack.append(value - 1)
|
||||||
|
elif opcode == 149: # typeof
|
||||||
|
value = stack.pop()
|
||||||
|
return {
|
||||||
|
_Undefined: 'undefined',
|
||||||
|
compat_str: 'String',
|
||||||
|
int: 'Number',
|
||||||
|
float: 'Number',
|
||||||
|
}[type(value)]
|
||||||
elif opcode == 160: # add
|
elif opcode == 160: # add
|
||||||
value2 = stack.pop()
|
value2 = stack.pop()
|
||||||
value1 = stack.pop()
|
value1 = stack.pop()
|
||||||
|
|
Loading…
Reference in a new issue