[swfinterp] Implement various opcodes
authorPhilipp Hagemeister <phihag@phihag.de>
Mon, 17 Nov 2014 03:45:12 +0000 (04:45 +0100)
committerPhilipp Hagemeister <phihag@phihag.de>
Mon, 17 Nov 2014 03:45:12 +0000 (04:45 +0100)
youtube_dl/swfinterp.py

index f4ee022f4e3fc3052f6ca9fbb9e19c5653b08a93..008cd76c7c75712267d5e4b97876c0649926bc86 100644 (file)
@@ -151,6 +151,16 @@ def _read_byte(reader):
 StringClass = _AVMClass('(no name idx)', 'String')
 
 
+class _Undefined(object):
+    def __boolean__(self):
+        return False
+
+    def __hash__(self):
+        return 0
+
+undefined = _Undefined()
+
+
 class SWFInterpreter(object):
     def __init__(self, file_contents):
         self._patched_functions = {}
@@ -423,6 +433,8 @@ class SWFInterpreter(object):
                         coder.seek(coder.tell() + offset)
                 elif opcode == 32:  # pushnull
                     stack.append(None)
+                elif opcode == 33:  # pushundefined
+                    stack.append(undefined)
                 elif opcode == 36:  # pushbyte
                     v = _read_byte(coder)
                     stack.append(v)
@@ -430,6 +442,8 @@ class SWFInterpreter(object):
                     stack.append(True)
                 elif opcode == 39:  # pushfalse
                     stack.append(False)
+                elif opcode == 40:  # pushnan
+                    stack.append(float('NaN'))
                 elif opcode == 42:  # dup
                     value = stack[-1]
                     stack.append(value)
@@ -493,8 +507,12 @@ class SWFInterpreter(object):
                     elif obj == StringClass:
                         if mname == 'String':
                             assert len(args) == 1
-                            assert isinstance(args[0], (int, compat_str))
-                            res = compat_str(args[0])
+                            assert isinstance(args[0], (
+                                int, compat_str, _Undefined))
+                            if args[0] == undefined:
+                                res = 'undefined'
+                            else:
+                                res = compat_str(args[0])
                             stack.append(res)
                             continue
                         else:
@@ -505,7 +523,7 @@ class SWFInterpreter(object):
                         'Unsupported property %r on %r'
                         % (mname, obj))
                 elif opcode == 71:  # returnvoid
-                    res = None
+                    res = undefined
                     return res
                 elif opcode == 72:  # returnvalue
                     res = stack.pop()
@@ -533,13 +551,13 @@ class SWFInterpreter(object):
                     if isinstance(obj, _AVMClass_Object):
                         func = self.extract_function(obj.avm_class, mname)
                         res = func(args)
-                        assert res is None
+                        assert res is undefined
                         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
+                        assert res is undefined
                         continue
                     if mname == 'reverse':
                         assert isinstance(obj, list)
@@ -617,7 +635,7 @@ class SWFInterpreter(object):
                         obj = stack.pop()
                         assert isinstance(obj, (dict, _ScopeDict)), \
                             'Accessing member %r on %r' % (pname, obj)
-                        res = obj.get(pname, None)
+                        res = obj.get(pname, undefined)
                         stack.append(res)
                     else:  # Assume attribute access
                         idx = stack.pop()
@@ -631,8 +649,24 @@ class SWFInterpreter(object):
                     stack.append(intvalue)
                 elif opcode == 128:  # coerce
                     u30()
+                elif opcode == 130:  # coerce_a
+                    value = stack.pop()
+                    # um, yes, it's any value
+                    stack.append(value)
                 elif opcode == 133:  # coerce_s
                     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
                     value2 = stack.pop()
                     value1 = stack.pop()