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 |         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): | class _AVMClass_Object(object): | ||||||
|     def __init__(self, avm_class): |     def __init__(self, avm_class): | ||||||
|         self.avm_class = avm_class |         self.avm_class = avm_class | ||||||
| @@ -74,14 +64,6 @@ class _AVMClass(object): | |||||||
|                 super(ScopeDict, self).__init__() |                 super(ScopeDict, self).__init__() | ||||||
|                 self.avm_class = avm_class |                 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): |             def __repr__(self): | ||||||
|                 return '%s__Scope(%s)' % ( |                 return '%s__Scope(%s)' % ( | ||||||
|                     self.avm_class.name, |                     self.avm_class.name, | ||||||
| @@ -92,6 +74,15 @@ class _AVMClass(object): | |||||||
|     def make_object(self): |     def make_object(self): | ||||||
|         return _AVMClass_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): | def _read_int(reader): | ||||||
|     res = 0 |     res = 0 | ||||||
| @@ -290,7 +281,11 @@ class SWFInterpreter(object): | |||||||
|         classes = [] |         classes = [] | ||||||
|         for class_id in range(class_count): |         for class_id in range(class_count): | ||||||
|             name_idx = u30() |             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 |             u30()  # super_name idx | ||||||
|             flags = read_byte() |             flags = read_byte() | ||||||
|             if flags & 0x08 != 0:  # Protected namespace is present |             if flags & 0x08 != 0:  # Protected namespace is present | ||||||
| @@ -301,7 +296,9 @@ class SWFInterpreter(object): | |||||||
|             u30()  # iinit |             u30()  # iinit | ||||||
|             trait_count = u30() |             trait_count = u30() | ||||||
|             for _c2 in range(trait_count): |             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 |         assert len(classes) == class_count | ||||||
|         self._classes_by_name = dict((c.name, c) for c in classes) |         self._classes_by_name = dict((c.name, c) for c in classes) | ||||||
|  |  | ||||||
| @@ -310,10 +307,7 @@ class SWFInterpreter(object): | |||||||
|             trait_count = u30() |             trait_count = u30() | ||||||
|             for _c2 in range(trait_count): |             for _c2 in range(trait_count): | ||||||
|                 trait_methods = parse_traits_info() |                 trait_methods = parse_traits_info() | ||||||
|                 avm_class.method_names.update(trait_methods.items()) |                 avm_class.register_methods(trait_methods) | ||||||
|                 avm_class.method_idxs.update(dict( |  | ||||||
|                     (idx, name) |  | ||||||
|                     for name, idx in trait_methods.items())) |  | ||||||
|  |  | ||||||
|         # Scripts |         # Scripts | ||||||
|         script_count = u30() |         script_count = u30() | ||||||
| @@ -358,12 +352,14 @@ class SWFInterpreter(object): | |||||||
|             raise ExtractorError('Class %r not found' % class_name) |             raise ExtractorError('Class %r not found' % class_name) | ||||||
|  |  | ||||||
|     def extract_function(self, avm_class, func_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: |         if func_name in avm_class.method_pyfunctions: | ||||||
|             return avm_class.method_pyfunctions[func_name] |             return avm_class.method_pyfunctions[func_name] | ||||||
|         if func_name in self._classes_by_name: |         if func_name in self._classes_by_name: | ||||||
|             return self._classes_by_name[func_name].make_object() |             return self._classes_by_name[func_name].make_object() | ||||||
|         if func_name not in avm_class.methods: |         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] |         m = avm_class.methods[func_name] | ||||||
|  |  | ||||||
|         def resfunc(args): |         def resfunc(args): | ||||||
| @@ -375,7 +371,8 @@ class SWFInterpreter(object): | |||||||
|             print('Invoking %s.%s(%r)' % (avm_class.name, func_name, tuple(args))) |             print('Invoking %s.%s(%r)' % (avm_class.name, func_name, tuple(args))) | ||||||
|             registers = [avm_class.variables] + list(args) + [None] * m.local_count |             registers = [avm_class.variables] + list(args) + [None] * m.local_count | ||||||
|             stack = [] |             stack = [] | ||||||
|             scopes = collections.deque([avm_class.variables]) |             scopes = collections.deque([ | ||||||
|  |                 self._classes_by_name, avm_class.variables]) | ||||||
|             while True: |             while True: | ||||||
|                 opcode = _read_byte(coder) |                 opcode = _read_byte(coder) | ||||||
|                 print('opcode: %r, stack(%d): %r' % (opcode, len(stack), stack)) |                 print('opcode: %r, stack(%d): %r' % (opcode, len(stack), stack)) | ||||||
| @@ -408,33 +405,38 @@ class SWFInterpreter(object): | |||||||
|                     args = list(reversed( |                     args = list(reversed( | ||||||
|                         [stack.pop() for _ in range(arg_count)])) |                         [stack.pop() for _ in range(arg_count)])) | ||||||
|                     obj = stack.pop() |                     obj = stack.pop() | ||||||
|                     if mname == 'split': |  | ||||||
|                         assert len(args) == 1 |                     if isinstance(obj, _AVMClass_Object): | ||||||
|                         assert isinstance(args[0], compat_str) |                         func = self.extract_function(obj.avm_class, mname) | ||||||
|                         assert isinstance(obj, compat_str) |                         res = func(args) | ||||||
|                         if args[0] == '': |  | ||||||
|                             res = list(obj) |  | ||||||
|                         else: |  | ||||||
|                             res = obj.split(args[0]) |  | ||||||
|                         stack.append(res) |                         stack.append(res) | ||||||
|                     elif mname == 'slice': |                         continue | ||||||
|                         assert len(args) == 1 |                     elif isinstance(obj, compat_str): | ||||||
|                         assert isinstance(args[0], int) |                         if mname == 'split': | ||||||
|                         assert isinstance(obj, list) |                             assert len(args) == 1 | ||||||
|                         res = obj[args[0]:] |                             assert isinstance(args[0], compat_str) | ||||||
|                         stack.append(res) |                             if args[0] == '': | ||||||
|                     elif mname == 'join': |                                 res = list(obj) | ||||||
|                         assert len(args) == 1 |                             else: | ||||||
|                         assert isinstance(args[0], compat_str) |                                 res = obj.split(args[0]) | ||||||
|                         assert isinstance(obj, list) |                             stack.append(res) | ||||||
|                         res = args[0].join(obj) |                             continue | ||||||
|                         stack.append(res) |                     elif isinstance(obj, list): | ||||||
|                     elif mname in avm_class.method_pyfunctions: |                         if mname == 'slice': | ||||||
|                         stack.append(avm_class.method_pyfunctions[mname](args)) |                             assert len(args) == 1 | ||||||
|                     else: |                             assert isinstance(args[0], int) | ||||||
|                         raise NotImplementedError( |                             res = obj[args[0]:] | ||||||
|                             'Unsupported property %r on %r' |                             stack.append(res) | ||||||
|                             % (mname, obj)) |                             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 |                 elif opcode == 72:  # returnvalue | ||||||
|                     res = stack.pop() |                     res = stack.pop() | ||||||
|                     return res |                     return res | ||||||
| @@ -446,11 +448,12 @@ class SWFInterpreter(object): | |||||||
|                     obj = stack.pop() |                     obj = stack.pop() | ||||||
|  |  | ||||||
|                     mname = self.multinames[index] |                     mname = self.multinames[index] | ||||||
|  |                     assert isinstance(obj, _AVMClass) | ||||||
|                     construct_method = self.extract_function( |                     construct_method = self.extract_function( | ||||||
|                         obj.avm_class, mname) |                         obj, mname) | ||||||
|                     # We do not actually call the constructor for now; |                     # We do not actually call the constructor for now; | ||||||
|                     # we just pretend it does nothing |                     # we just pretend it does nothing | ||||||
|                     stack.append(obj) |                     stack.append(obj.make_object()) | ||||||
|                 elif opcode == 79:  # callpropvoid |                 elif opcode == 79:  # callpropvoid | ||||||
|                     index = u30() |                     index = u30() | ||||||
|                     mname = self.multinames[index] |                     mname = self.multinames[index] | ||||||
| @@ -481,7 +484,7 @@ class SWFInterpreter(object): | |||||||
|                             break |                             break | ||||||
|                     else: |                     else: | ||||||
|                         res = scopes[0] |                         res = scopes[0] | ||||||
|                     stack.append(res) |                     stack.append(res[mname]) | ||||||
|                 elif opcode == 94:  # findproperty |                 elif opcode == 94:  # findproperty | ||||||
|                     index = u30() |                     index = u30() | ||||||
|                     mname = self.multinames[index] |                     mname = self.multinames[index] | ||||||
| @@ -490,7 +493,7 @@ class SWFInterpreter(object): | |||||||
|                             res = s |                             res = s | ||||||
|                             break |                             break | ||||||
|                     else: |                     else: | ||||||
|                         res = scopes[0] |                         res = avm_class.variables | ||||||
|                     stack.append(res) |                     stack.append(res) | ||||||
|                 elif opcode == 96:  # getlex |                 elif opcode == 96:  # getlex | ||||||
|                     index = u30() |                     index = u30() | ||||||
| @@ -500,7 +503,7 @@ class SWFInterpreter(object): | |||||||
|                             scope = s |                             scope = s | ||||||
|                             break |                             break | ||||||
|                     else: |                     else: | ||||||
|                         scope = scopes[0] |                         scope = avm_class.variables | ||||||
|                     # I cannot find where static variables are initialized |                     # I cannot find where static variables are initialized | ||||||
|                     # so let's just return None |                     # so let's just return None | ||||||
|                     res = scope.get(mname) |                     res = scope.get(mname) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user