mirror of
				https://github.com/ytdl-org/youtube-dl.git
				synced 2025-10-29 09:26:20 -07:00 
			
		
		
		
	[swfinterp] Add support for calls to instance methods
This commit is contained in:
		
							
								
								
									
										17
									
								
								test/swftests/ClassCall.as
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								test/swftests/ClassCall.as
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
| 	} | ||||
| } | ||||
| @@ -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,30 +405,35 @@ 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) | ||||
|                         stack.append(res) | ||||
|                         continue | ||||
|                     elif isinstance(obj, compat_str): | ||||
|                         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': | ||||
|                             continue | ||||
|                     elif isinstance(obj, list): | ||||
|                         if mname == 'slice': | ||||
|                             assert len(args) == 1 | ||||
|                             assert isinstance(args[0], int) | ||||
|                         assert isinstance(obj, list) | ||||
|                             res = obj[args[0]:] | ||||
|                             stack.append(res) | ||||
|                             continue | ||||
|                         elif mname == 'join': | ||||
|                             assert len(args) == 1 | ||||
|                             assert isinstance(args[0], compat_str) | ||||
|                         assert isinstance(obj, list) | ||||
|                             res = args[0].join(obj) | ||||
|                             stack.append(res) | ||||
|                     elif mname in avm_class.method_pyfunctions: | ||||
|                         stack.append(avm_class.method_pyfunctions[mname](args)) | ||||
|                     else: | ||||
|                             continue | ||||
|                     raise NotImplementedError( | ||||
|                         'Unsupported property %r on %r' | ||||
|                         % (mname, obj)) | ||||
| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user