diff paraspace/injection.py @ 111:3820379b34e8

Add dexfile_insert_class_relative()
author Thinker K.F. Li <thinker@codemud.net>
date Mon, 01 Aug 2011 22:23:55 +0800
parents 6380730a80b4
children 650dcb9c01ee
line wrap: on
line diff
--- a/paraspace/injection.py	Mon Aug 01 15:00:29 2011 +0800
+++ b/paraspace/injection.py	Mon Aug 01 22:23:55 2011 +0800
@@ -94,12 +94,12 @@
     pass
 
 
-## \brief Clone a class definition item
+## \brief Clone a composite object.
 #
-# \param dex is the DEXFile that clazz is cloning for.
-# \param clazz is the class definition item that is cloning.
+# \param dex is the DEXFile that the composite object is cloning for.
+# \param comobj is composite object that is cloning.
 #
-def _clone_classdef(dex, clazz):
+def _clone_composite(dex, comobj):
     from copy import copy
     from paraspace.dexfile import _DEX_StringDataItem, _DEX_StringId
     from paraspace.dexfile import _DEX_TypeId
@@ -175,12 +175,7 @@
             pass
         pass
 
-    def has_classdef(clazz):
-        class_typeIds = set([classdef.classIdx
-                             for classdef in dex.classDefs.items])
-        return clazz.classIdx in class_typeIds
-
-    _travel_desc_relocatable(clazz, cloner, visit_log)
+    _travel_desc_relocatable(comobj, cloner, visit_log)
 
     merge_unique_strdata()
     merge_unique_strid()
@@ -195,12 +190,35 @@
         dex_append_obj_list(dex, obj)
         pass
     
+    clone = visit_log[id(comobj)]
+    return clone
+
+
+## \brief Clone a class definition item
+#
+# \param dex is the DEXFile that clazz is cloning for.
+# \param clazz is the class definition item that is cloning.
+# \return the cloning _DEX_ClassDef.
+#
+def _clone_classdef(dex, clazz):
+    from paraspace.dexfile import DEXFile_linked, _DEX_ClassDef
+    
+    def has_classdef(clazz):
+        classname = DEXFile_linked.get_classdef_name(clazz)
+        try:
+            dex.find_class_name(classname)
+        except ValueError:
+            return False
+        return True
+
+    assert isinstance(clazz, _DEX_ClassDef)
+
     if has_classdef(clazz):
         raise RuntimeError, \
             'clone a class \'%s\'that is already in the DEXFile' % \
             classdef_name(clazz)
     
-    clone = visit_log[id(clazz)]
+    clone = _clone_composite(dex, clazz)
     return clone
 
 
@@ -212,11 +230,131 @@
 # \param dex is a DEXFile_linked to insert the clone.
 # \param class_def is a class definition going to be cloned.
 #
-def dexfile_insert_class(dex, class_def):
-    clone = _clone_classdef(dex, class_def)
+def dexfile_insert_class(dex, classdef):
+    clone = _clone_classdef(dex, classdef)
     return clone
 
 
+## \brief Collect info of classes mentioned by the code of given class.
+def _find_class_relative(dex, classdef):
+    def classify_typeids_defined(dex, typeids):
+        classdefs = []
+        undef_typeids = []
+        for typeid in typeids:
+            try:
+                classdef = dex.find_class_typeid(typeid)
+            except ValueError:
+                undef_typeids.append(typeid)
+            else:
+                classdefs.append(classdef)
+                pass
+            pass
+        return classdefs, undef_typeids
+
+    typeidxs = collect_typeidxs_mentioned_by_class(dex, classdef)
+    typeids = [dex.find_typeid_idx(typeidx)
+               for typeidx in typeidxs]
+    
+    classdefs, typeids = classify_typeids_defined(dex, typeids)
+    
+    return classdefs, typeids
+
+
+def dexfile_insert_classdefs(dex_dst, dex_src, classdefs):
+    for classdef in classdefs:
+        dexfile_insert_class(dex_dst, classdef)
+        pass
+    pass
+
+
+## \brief Clone and insert a _DEX_TypeId to another DEXFile_linked.
+#
+# \param dex_dst is a DEXFile_linked where the cloning one is inserted.
+# \param dex_src is a DEXFile_linked where the cloned one is from.
+# \param typeid is a _DEX_TypeId that is cloned.
+# \return the cloning _DEX_TypeId.
+#
+def dexfile_insert_typeid(dex_dst, dex_src, typeid):
+    from paraspace.dexfile import _DEX_TypeId, DEXFile_linked
+    
+    assert isinstance(typeid, _DEX_TypeId)
+    
+    cloning = _clone_composite(dex_dst, typeid)
+    
+    methodids = dex_src.find_methodids_typeid(dex_src, typeid)
+    for methodid in methodids:
+        _clone_composite(dex_dst, methodid)
+        pass
+    
+    return cloning
+
+
+## \brief Clone and insert a list of _DEX_TypeId objects to a DEXFile_linked.
+def dexfile_insert_typeids(dex_dst, dex_src, typeids):
+    for typeid in typeids:
+        dexfile_insert_typeid(dex_dst, dex_src, typeid)
+        pass
+    pass
+
+
+## \brief Collects relative type IDs and classes definition for given class.
+def collect_classdef_relative(dex, classdef):
+    rel_classdefs = set([classdef])
+    rel_typeids = set()
+    
+    classdef_queue = [classdef]
+    while classdef_queue:
+        cur_classdef = classdef_queue.pop(0)
+        
+        classdefs, typeids = _find_class_relative(dex, classdef)
+        rel_typeids.update(typeids)
+        new_classdefs = list(set(classdefs) - rel_classdefs)
+        classdef_queue = classdef_queue + new_classdefs
+        rel_classdefs.update(new_classdefs)
+        pass
+    return rel_classdefs, rel_typeids
+
+
+## \brief Clone and insert given and relative classes into another DEXFile.
+#
+# \param dex_dst is a DEXFile_linked where the class will be inserted.
+# \param dex_src is a DEXFile_linked where the cloned class is from.
+# \param classdef is a _DEX_ClassDef that will be cloned.
+#
+def dexfile_insert_class_relative(dex_dst, dex_src, classdef):
+    from paraspace.dexfile import DEXFile_linked
+    
+    def classdef_not_in_dst(classdef):
+        classname = DEXFile_linked.get_classdef_name(classdef)
+        try:
+            dex_dst.find_class_name(classname)
+        except ValueError:
+            return True
+        return False
+
+    def typeid_not_in_dst(typeid):
+        typename = DEXFile_linked.get_typeid_name(typeid)
+        try:
+            dex_dst.find_typeid_name(typename)
+        except ValueError:
+            return True
+        return False
+    
+    relative_classdefs, relative_typeids = \
+        collect_classdef_relative(dex_src, classdef)
+    
+    inserting_classdefs = filter(classdef_not_in_dst, relative_classdefs)
+    inserting_typeids = filter(typeid_not_in_dst, relative_typeids)
+    
+    dexfile_insert_classdefs(dex_dst, dex_src, inserting_classdefs)
+    dexfile_insert_typeids(dex_dst, dex_src, inserting_typeids)
+
+    classname = DEXFile_linked.get_classdef_name(classdef)
+    cloning = dex_dst.find_class_name(classname)
+    
+    return cloning
+
+
 ## \brief Redirect types and methods for the code of given method.
 def method_redirect_types(dex, method, types_redir, methods_redir):
     from paraspace.dalvik_opcodes import decode_insn_blk, all_opcodes