Browse Source

[swfinterp] Add more builtins and improve static variables

totalwebcasting
Philipp Hagemeister 10 years ago
parent
commit
fbf94a7815
2 changed files with 49 additions and 8 deletions
  1. +18
    -0
      test/swftests/ConstArrayAccess.as
  2. +31
    -8
      youtube_dl/swfinterp.py

+ 18
- 0
test/swftests/ConstArrayAccess.as View File

@ -0,0 +1,18 @@
// input: []
// output: 4
package {
public class ConstArrayAccess {
private static const x:int = 2;
private static const ar:Array = ["42", "3411"];
public static function main():int{
var c:ConstArrayAccess = new ConstArrayAccess();
return c.f();
}
public function f(): int {
return ar[1].length;
}
}
}

+ 31
- 8
youtube_dl/swfinterp.py View File

@ -62,13 +62,14 @@ class _ScopeDict(dict):
class _AVMClass(object): class _AVMClass(object):
def __init__(self, name_idx, name):
def __init__(self, name_idx, name, static_properties=None):
self.name_idx = name_idx self.name_idx = name_idx
self.name = name self.name = name
self.method_names = {} self.method_names = {}
self.method_idxs = {} self.method_idxs = {}
self.methods = {} self.methods = {}
self.method_pyfunctions = {} self.method_pyfunctions = {}
self.static_properties = static_properties if static_properties else {}
self.variables = _ScopeDict(self) self.variables = _ScopeDict(self)
self.constants = {} self.constants = {}
@ -151,15 +152,20 @@ def _read_byte(reader):
StringClass = _AVMClass('(no name idx)', 'String') StringClass = _AVMClass('(no name idx)', 'String')
ByteArrayClass = _AVMClass('(no name idx)', 'ByteArray') ByteArrayClass = _AVMClass('(no name idx)', 'ByteArray')
TimerClass = _AVMClass('(no name idx)', 'Timer')
TimerEventClass = _AVMClass('(no name idx)', 'TimerEvent', {'TIMER': 'timer'})
_builtin_classes = { _builtin_classes = {
StringClass.name: StringClass, StringClass.name: StringClass,
ByteArrayClass.name: ByteArrayClass, ByteArrayClass.name: ByteArrayClass,
TimerClass.name: TimerClass,
TimerEventClass.name: TimerEventClass,
} }
class _Undefined(object): class _Undefined(object):
def __boolean__(self):
def __bool__(self):
return False return False
__nonzero__ = __bool__
def __hash__(self): def __hash__(self):
return 0 return 0
@ -169,7 +175,9 @@ undefined = _Undefined()
class SWFInterpreter(object): class SWFInterpreter(object):
def __init__(self, file_contents): def __init__(self, file_contents):
self._patched_functions = {}
self._patched_functions = {
(TimerClass, 'addEventListener'): lambda params: undefined,
}
code_tag = next(tag code_tag = next(tag
for tag_code, tag in _extract_tags(file_contents) for tag_code, tag in _extract_tags(file_contents)
if tag_code == 82) if tag_code == 82)
@ -346,9 +354,10 @@ class SWFInterpreter(object):
u30() # iinit u30() # iinit
trait_count = u30() trait_count = u30()
for _c2 in range(trait_count): for _c2 in range(trait_count):
trait_methods, constants = parse_traits_info()
trait_methods, trait_constants = parse_traits_info()
avm_class.register_methods(trait_methods) avm_class.register_methods(trait_methods)
assert constants is None
if trait_constants:
avm_class.constants.update(trait_constants)
assert len(classes) == class_count assert len(classes) == class_count
self._classes_by_name = dict((c.name, c) for c in classes) self._classes_by_name = dict((c.name, c) for c in classes)
@ -439,7 +448,7 @@ class SWFInterpreter(object):
registers = [avm_class.variables] + list(args) + [None] * m.local_count registers = [avm_class.variables] + list(args) + [None] * m.local_count
stack = [] stack = []
scopes = collections.deque([ scopes = collections.deque([
self._classes_by_name, avm_class.variables])
self._classes_by_name, avm_class.constants, avm_class.variables])
while True: while True:
opcode = _read_byte(coder) opcode = _read_byte(coder)
if opcode == 9: # label if opcode == 9: # label
@ -587,6 +596,12 @@ class SWFInterpreter(object):
elif opcode == 72: # returnvalue elif opcode == 72: # returnvalue
res = stack.pop() res = stack.pop()
return res return res
elif opcode == 73: # constructsuper
# Not yet implemented, just hope it works without it
arg_count = u30()
args = list(reversed(
[stack.pop() for _ in range(arg_count)]))
obj = stack.pop()
elif opcode == 74: # constructproperty elif opcode == 74: # constructproperty
index = u30() index = u30()
arg_count = u30() arg_count = u30()
@ -667,8 +682,11 @@ class SWFInterpreter(object):
if mname in scope: if mname in scope:
res = scope[mname] res = scope[mname]
elif mname in _builtin_classes:
res = _builtin_classes[mname]
else: else:
res = avm_class.constants[mname]
# Assume unitialized
res = undefined
stack.append(res) stack.append(res)
elif opcode == 97: # setproperty elif opcode == 97: # setproperty
index = u30() index = u30()
@ -694,7 +712,12 @@ class SWFInterpreter(object):
stack.append(len(obj)) stack.append(len(obj))
elif isinstance(pname, compat_str): # Member access elif isinstance(pname, compat_str): # Member access
obj = stack.pop() obj = stack.pop()
assert isinstance(obj, (dict, _ScopeDict)), \
if isinstance(obj, _AVMClass):
res = obj.static_properties[pname]
stack.append(res)
continue
assert isinstance(obj, (dict, _ScopeDict)),\
'Accessing member %r on %r' % (pname, obj) 'Accessing member %r on %r' % (pname, obj)
res = obj.get(pname, undefined) res = obj.get(pname, undefined)
stack.append(res) stack.append(res)


Loading…
Cancel
Save