diff paraspace/dexfile.py @ 104:61cef1662035

Redirect types
author Thinker K.F. Li <thinker@codemud.net>
date Thu, 28 Jul 2011 00:06:54 +0800
parents 7fcd555d802b
children 7821c6e89622
line wrap: on
line diff
--- a/paraspace/dexfile.py	Wed Jul 27 12:09:19 2011 +0800
+++ b/paraspace/dexfile.py	Thu Jul 28 00:06:54 2011 +0800
@@ -1031,7 +1031,7 @@
 
 class _DEX_TypeList(composite):
     num = uint32
-    typeItems = array('num', uint16)
+    typeItems = array('num', depend_idx('DEXFile.typeIds')(uint16))
 
     child_names = 'num typeItems'.split()
     pass
@@ -1693,7 +1693,29 @@
     ## \brief Return name string of a linked class definition item
     @staticmethod
     def get_classdef_name(classdef):
-        return classdef.classIdx.descriptorIdx.stringDataOff.data.data
+        return DEXFile_linked.get_typeid_name(classdef.classIdx)
+
+    ## \brief Return name string of a linked type ID item.
+    @staticmethod
+    def get_typeid_name(typeid):
+        return typeid.descriptorIdx.stringDataOff.data.data
+
+    ## \brief Get index of given type ID.
+    def get_idx_typeid(self, typeid):
+        return self.typeIds.items.index(typeid)
+
+    ## \brief Find type ID item with given name.
+    def find_typeid_name(self, name):
+        for typeid in self.typeIds.items:
+            typeid_name = DEXFile_linked.get_typeid_name(typeid)
+            if typeid_name == name:
+                return typeid
+            pass
+        pass
+    
+    ## \brief Return type ID item with given index.
+    def find_typeid_idx(self, idx):
+        return self.typeIds.items[idx]
     
     def find_class_name(self, name):
         for classdef in self.classDefs.items:
@@ -1703,6 +1725,15 @@
             pass
         raise ValueError, 'can not find class definition for \'%s\'' % (name)
 
+    ## \brief Return a class definition corresponding for give type ID.
+    def find_class_typeid(self, typeid):
+        for classdef in self.classDefs.items:
+            if classdef.classIdx == typeid:
+                return classdef
+            pass
+        raise ValueError, \
+            'can not find class definition for typeid %s' % (repr(typeid))
+
     ## \brief Update size of map items.
     #
     # Corresponding data lists of maps may be changed, it should be updated
@@ -1769,6 +1800,61 @@
                 return wmethod
             pass
         pass
+
+    ## \brief Get name of given method ID.
+    @staticmethod
+    def get_methodid_name(methoid):
+        return methoid.nameIdx.stringDataOff.data.data
+
+    ## \brief Find the method ID item of given index.
+    def find_methodid_idx(self, idx):
+        methodid = self.methodIds.items[idx]
+        return methodid
+
+    ## \brief Find a method definition with an index to method ID.
+    def find_method_idx(self, idx):
+        methodid = self.find_methodid_idx(idx)
+        method_name = DEXFile_linked.get_methoid_name(methodid)
+        method_proto = methodid.protoIdx
+        method_typeid = methodid.classIdx
+        classdef = self.find_class_typeid(method_typeid)
+        
+        method = self.find_method_name_proto(method, method_proto, classdef)
+        
+        return method
+
+    ## \brief Test if prototype of two methods are compatible.
+    @staticmethod
+    def _proto_is_compatible(proto1, proto2):
+        if proto1.returnTypeIdx != proto2.returnTypeIdx:
+            return False
+        typelist1 = proto1.parametersOffRef.value
+        typelist2 = proto2.parametersOffRef.value
+        if len(typelist1.typeItems.items) != len(typelist2.typeItems.items):
+            return False
+
+        for typeid1, typeid2 in map(None,
+                                    typelist1.typeItems.items,
+                                    typelist2.typeItems.items):
+            if typeid1 != typeid2:
+                return False
+            pass
+        return True
+
+    def find_method_name_proto(self, method_name, proto, classdef):
+        if not classdef.classDataOffRef.is_true:
+            return
+
+        classdata = classdef.classDataOffRef.value
+        for wmethod in classdata.directMethods.items + \
+                classdata.virtualMethods.items:
+            wmethod_name = DEXFile_linked.get_method_name(wmethod)
+            if method_name != wmethod_name:
+                continue
+            if DEXFile_linked._proto_is_compatible(wmethod.protoIdx, proto):
+                return wmethod
+            pass
+        raise ValueError, 'can not find a method for given name and prototype'
     pass