aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/swftests/ClassCall.as17
-rw-r--r--youtube_dl/swfinterp.py117
2 files changed, 77 insertions, 57 deletions
diff --git a/test/swftests/ClassCall.as b/test/swftests/ClassCall.as
new file mode 100644
index 000000000..aef58daf3
--- /dev/null
+++ b/test/swftests/ClassCall.as
@@ -0,0 +1,17 @@
+// input: []
+// output: 121
+
+package {
+public class ClassCall {
+ public static function main():int{
+ var f:OtherClass = new OtherClass();
+ return f.func(100,20);
+ }
+}
+}
+
+class OtherClass {
+ public function func(x: int, y: int):int {
+ return x+y+1;
+ }
+}
diff --git a/youtube_dl/swfinterp.py b/youtube_dl/swfinterp.py
index f7a3889a0..8ccb64c9d 100644
--- a/youtube_dl/swfinterp.py
+++ b/youtube_dl/swfinterp.py
@@ -42,16 +42,6 @@ def _extract_tags(file_contents):
pos += tag_len
-class _AVM_Object(object):
- def __init__(self, value=None, name_hint=None):
- self.value = value
- self.name_hint = name_hint
-
- def __repr__(self):
- nh = '' if self.name_hint is None else (' %s' % self.name_hint)
- return 'AVMObject%s(%r)' % (nh, self.value)
-
-
class _AVMClass_Object(object):
def __init__(self, avm_class):
self.avm_class = avm_class
@@ -74,14 +64,6 @@ class _AVMClass(object):
super(ScopeDict, self).__init__()
self.avm_class = avm_class
- def __getitem__(self, k):
- print('getting %r' % k)
- return super(ScopeDict, self).__getitem__(k)
-
- def __contains__(self, k):
- print('contains %r' % k)
- return super(ScopeDict, self).__contains__(k)
-
def __repr__(self):
return '%s__Scope(%s)' % (
self.avm_class.name,
@@ -92,6 +74,15 @@ class _AVMClass(object):
def make_object(self):
return _AVMClass_Object(self)
+ def __repr__(self):
+ return '_AVMClass(%s)' % (self.name)
+
+ def register_methods(self, methods):
+ self.method_names.update(methods.items())
+ self.method_idxs.update(dict(
+ (idx, name)
+ for name, idx in methods.items()))
+
def _read_int(reader):
res = 0
@@ -290,7 +281,11 @@ class SWFInterpreter(object):
classes = []
for class_id in range(class_count):
name_idx = u30()
- classes.append(_AVMClass(name_idx, self.multinames[name_idx]))
+
+ cname = self.multinames[name_idx]
+ avm_class = _AVMClass(name_idx, cname)
+ classes.append(avm_class)
+
u30() # super_name idx
flags = read_byte()
if flags & 0x08 != 0: # Protected namespace is present
@@ -301,7 +296,9 @@ class SWFInterpreter(object):
u30() # iinit
trait_count = u30()
for _c2 in range(trait_count):
- parse_traits_info()
+ trait_methods = parse_traits_info()
+ avm_class.register_methods(trait_methods)
+
assert len(classes) == class_count
self._classes_by_name = dict((c.name, c) for c in classes)
@@ -310,10 +307,7 @@ class SWFInterpreter(object):
trait_count = u30()
for _c2 in range(trait_count):
trait_methods = parse_traits_info()
- avm_class.method_names.update(trait_methods.items())
- avm_class.method_idxs.update(dict(
- (idx, name)
- for name, idx in trait_methods.items()))
+ avm_class.register_methods(trait_methods)
# Scripts
script_count = u30()
@@ -358,12 +352,14 @@ class SWFInterpreter(object):
raise ExtractorError('Class %r not found' % class_name)
def extract_function(self, avm_class, func_name):
+ print('Extracting %s.%s' % (avm_class.name, func_name))
if func_name in avm_class.method_pyfunctions:
return avm_class.method_pyfunctions[func_name]
if func_name in self._classes_by_name:
return self._classes_by_name[func_name].make_object()
if func_name not in avm_class.methods:
- raise ExtractorError('Cannot find function %r' % func_name)
+ raise ExtractorError('Cannot find function %s.%s' % (
+ avm_class.name, func_name))
m = avm_class.methods[func_name]
def resfunc(args):
@@ -375,7 +371,8 @@ class SWFInterpreter(object):
print('Invoking %s.%s(%r)' % (avm_class.name, func_name, tuple(args)))
registers = [avm_class.variables] + list(args) + [None] * m.local_count
stack = []
- scopes = collections.deque([avm_class.variables])
+ scopes = collections.deque([
+ self._classes_by_name, avm_class.variables])
while True:
opcode = _read_byte(coder)
print('opcode: %r, stack(%d): %r' % (opcode, len(stack), stack))
@@ -408,33 +405,38 @@ class SWFInterpreter(object):
args = list(reversed(
[stack.pop() for _ in range(arg_count)]))
obj = stack.pop()
- if mname == 'split':
- assert len(args) == 1
- assert isinstance(args[0], compat_str)
- assert isinstance(obj, compat_str)
- if args[0] == '':
- res = list(obj)
- else:
- res = obj.split(args[0])
- stack.append(res)
- elif mname == 'slice':
- assert len(args) == 1
- assert isinstance(args[0], int)
- assert isinstance(obj, list)
- res = obj[args[0]:]
- stack.append(res)
- elif mname == 'join':
- assert len(args) == 1
- assert isinstance(args[0], compat_str)
- assert isinstance(obj, list)
- res = args[0].join(obj)
+
+ if isinstance(obj, _AVMClass_Object):
+ func = self.extract_function(obj.avm_class, mname)
+ res = func(args)
stack.append(res)
- elif mname in avm_class.method_pyfunctions:
- stack.append(avm_class.method_pyfunctions[mname](args))
- else:
- raise NotImplementedError(
- 'Unsupported property %r on %r'
- % (mname, obj))
+ continue
+ elif isinstance(obj, compat_str):
+ if mname == 'split':
+ assert len(args) == 1
+ assert isinstance(args[0], compat_str)
+ if args[0] == '':
+ res = list(obj)
+ else:
+ res = obj.split(args[0])
+ stack.append(res)
+ continue
+ elif isinstance(obj, list):
+ if mname == 'slice':
+ assert len(args) == 1
+ assert isinstance(args[0], int)
+ res = obj[args[0]:]
+ stack.append(res)
+ continue
+ elif mname == 'join':
+ assert len(args) == 1
+ assert isinstance(args[0], compat_str)
+ res = args[0].join(obj)
+ stack.append(res)
+ continue
+ raise NotImplementedError(
+ 'Unsupported property %r on %r'
+ % (mname, obj))
elif opcode == 72: # returnvalue
res = stack.pop()
return res
@@ -446,11 +448,12 @@ class SWFInterpreter(object):
obj = stack.pop()
mname = self.multinames[index]
+ assert isinstance(obj, _AVMClass)
construct_method = self.extract_function(
- obj.avm_class, mname)
+ obj, mname)
# We do not actually call the constructor for now;
# we just pretend it does nothing
- stack.append(obj)
+ stack.append(obj.make_object())
elif opcode == 79: # callpropvoid
index = u30()
mname = self.multinames[index]
@@ -481,7 +484,7 @@ class SWFInterpreter(object):
break
else:
res = scopes[0]
- stack.append(res)
+ stack.append(res[mname])
elif opcode == 94: # findproperty
index = u30()
mname = self.multinames[index]
@@ -490,7 +493,7 @@ class SWFInterpreter(object):
res = s
break
else:
- res = scopes[0]
+ res = avm_class.variables
stack.append(res)
elif opcode == 96: # getlex
index = u30()
@@ -500,7 +503,7 @@ class SWFInterpreter(object):
scope = s
break
else:
- scope = scopes[0]
+ scope = avm_class.variables
# I cannot find where static variables are initialized
# so let's just return None
res = scope.get(mname)