From 4686ae4b64c3c0a88b9a8a3fb7a7657df3753c5e Mon Sep 17 00:00:00 2001 From: Philipp Hagemeister Date: Mon, 17 Nov 2014 04:45:12 +0100 Subject: [PATCH] [swfinterp] Implement various opcodes --- youtube_dl/swfinterp.py | 46 +++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/youtube_dl/swfinterp.py b/youtube_dl/swfinterp.py index f4ee022f4..008cd76c7 100644 --- a/youtube_dl/swfinterp.py +++ b/youtube_dl/swfinterp.py @@ -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()