[swfinterp] Add support for void methods
[youtube-dl] / youtube_dl / swfinterp.py
index 85efde5924cddb12988260510da68a296f4241b0..f4ee022f4e3fc3052f6ca9fbb9e19c5653b08a93 100644 (file)
@@ -148,6 +148,9 @@ def _read_byte(reader):
     return res
 
 
+StringClass = _AVMClass('(no name idx)', 'String')
+
+
 class SWFInterpreter(object):
     def __init__(self, file_contents):
         self._patched_functions = {}
@@ -423,6 +426,10 @@ class SWFInterpreter(object):
                 elif opcode == 36:  # pushbyte
                     v = _read_byte(coder)
                     stack.append(v)
+                elif opcode == 38:  # pushtrue
+                    stack.append(True)
+                elif opcode == 39:  # pushfalse
+                    stack.append(False)
                 elif opcode == 42:  # dup
                     value = stack[-1]
                     stack.append(value)
@@ -483,9 +490,23 @@ class SWFInterpreter(object):
                             res = args[0].join(obj)
                             stack.append(res)
                             continue
+                    elif obj == StringClass:
+                        if mname == 'String':
+                            assert len(args) == 1
+                            assert isinstance(args[0], (int, compat_str))
+                            res = compat_str(args[0])
+                            stack.append(res)
+                            continue
+                        else:
+                            raise NotImplementedError(
+                                'Function String.%s is not yet implemented'
+                                % mname)
                     raise NotImplementedError(
                         'Unsupported property %r on %r'
                         % (mname, obj))
+                elif opcode == 71:  # returnvoid
+                    res = None
+                    return res
                 elif opcode == 72:  # returnvalue
                     res = stack.pop()
                     return res
@@ -509,6 +530,17 @@ class SWFInterpreter(object):
                     args = list(reversed(
                         [stack.pop() for _ in range(arg_count)]))
                     obj = stack.pop()
+                    if isinstance(obj, _AVMClass_Object):
+                        func = self.extract_function(obj.avm_class, mname)
+                        res = func(args)
+                        assert res is None
+                        continue
+                    if isinstance(obj, _ScopeDict):
+                        assert mname in obj.avm_class.method_names
+                        func = self.extract_function(obj.avm_class, mname)
+                        res = func(args)
+                        assert res is None
+                        continue
                     if mname == 'reverse':
                         assert isinstance(obj, list)
                         obj.reverse()
@@ -532,7 +564,10 @@ class SWFInterpreter(object):
                             break
                     else:
                         res = scopes[0]
-                    stack.append(res[mname])
+                    if mname not in res and mname == 'String':
+                        stack.append(StringClass)
+                    else:
+                        stack.append(res[mname])
                 elif opcode == 94:  # findproperty
                     index = u30()
                     mname = self.multinames[index]
@@ -576,13 +611,14 @@ class SWFInterpreter(object):
                     pname = self.multinames[index]
                     if pname == 'length':
                         obj = stack.pop()
-                        assert isinstance(obj, list)
+                        assert isinstance(obj, (compat_str, list))
                         stack.append(len(obj))
                     elif isinstance(pname, compat_str):  # Member access
                         obj = stack.pop()
                         assert isinstance(obj, (dict, _ScopeDict)), \
                             'Accessing member %r on %r' % (pname, obj)
-                        stack.append(obj[pname])
+                        res = obj.get(pname, None)
+                        stack.append(res)
                     else:  # Assume attribute access
                         idx = stack.pop()
                         assert isinstance(idx, int)
@@ -612,6 +648,11 @@ class SWFInterpreter(object):
                     value1 = stack.pop()
                     res = value1 % value2
                     stack.append(res)
+                elif opcode == 171:  # equals
+                    value2 = stack.pop()
+                    value1 = stack.pop()
+                    result = value1 == value2
+                    stack.append(result)
                 elif opcode == 175:  # greaterequals
                     value2 = stack.pop()
                     value1 = stack.pop()