Mercurial > paraspace
comparison paraspace/injection.py @ 88:bbe8d5cbe368
Clone objects with meta info
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Sun, 24 Jul 2011 19:15:04 +0800 |
parents | cd1ee85853f4 |
children | 88645ab29aeb |
comparison
equal
deleted
inserted
replaced
87:cd1ee85853f4 | 88:bbe8d5cbe368 |
---|---|
1 | 1 |
2 def _deep_travel(obj, cloner, adjuster, visit_log=None): | 2 def _relocatable_children(obj): |
3 from paraspace.dexfile import _dex_type | 3 from paraspace.dexfile import relocatable |
4 | 4 |
5 if not visit_log: | 5 attr_value_pairs = [(attr, getattr(obj, attr)) for attr in dir(obj)] |
6 visit_log = {} | 6 rel_children = [(attr, value) for attr, value in attr_value_pairs |
7 pass | 7 if isinstance(value, relocatable)] |
8 return rel_children | |
8 | 9 |
10 | |
11 ## \brief Travel relocatable descendants. | |
12 # | |
13 # \param cloner is the function to return a clone. | |
14 # \param adjuster is called to adjust the clone. | |
15 # \param visit_log is a dictionary to keep clones. | |
16 # | |
17 def _travel_desc_relocatable(obj, worker, visit_log): | |
9 if id(obj) in visit_log: | 18 if id(obj) in visit_log: |
10 return visit_log[id(obj)] | 19 return visit_log[id(obj)] |
11 | 20 |
12 attrs = [attr for attr in dir(obj) | 21 result = worker(obj) |
13 if not attr.startswith('_') and \ | 22 visit_log[id(obj)] = result |
14 isinstance(getattr(obj, attr), _dex_type)] | |
15 | 23 |
24 rel_children = _relocatable_children(obj) | |
25 for attr, value in rel_children: | |
26 _travel_conn_objs(value, worker, visit_log) | |
27 pass | |
28 pass | |
29 | |
30 | |
31 ## \brief Return name string of a linked class definition item. | |
32 def classdef_name(classdef): | |
33 return classdef.classIdx.descriptorIdx.stringDataOff.data | |
34 | |
35 | |
36 ## \brief Return a map that map type of a object to the list of a DEXFile. | |
37 def dex_type_2_array_attr_map(): | |
38 global dex_type_2_array_attr_map | |
39 from paraspace.dexfile import DEXFile, array | |
40 | |
41 attr_values = [(attr, getattr(DEXFile, attr)) | |
42 for attr in dir(DEXFile)] | |
43 type_2_attr = dict([(value.child_type, attr) | |
44 for attr, value in attr_values | |
45 if isinstance(value, array)]) | |
46 | |
47 dex_type_2_array_attr_map = lambda: type_2_attr | |
48 | |
49 return type_2_attr | |
50 | |
51 | |
52 ## \brief Append a object to appropriate list of a DEXFile object. | |
53 # | |
54 # Skip the object if found no appropriate list. | |
55 # | |
56 def dex_append_obj_list(dex, obj): | |
57 from paraspace.dex_deptracker import _dex_tree_get_child | |
58 from paraspace.dex_deptracker import _dex_tree_set_child | |
59 | |
60 type_2_attr = dex_type_2_array_attr_map() | |
61 try: | |
62 attr = type_2_attr[obj.__class__] | |
63 except KeyError: | |
64 return | |
65 | |
66 array = getattr(dex, attr) | |
67 array.items.append(obj) | |
68 | |
69 count_name = array.count_name | |
70 count = _dex_tree_get_child(dex, count_name) | |
71 _dex_tree_set_child(dex, count_name, count + 1) | |
72 pass | |
73 | |
74 | |
75 ## \brief Clone a class definition item | |
76 # | |
77 # \param dex is the DEXFile that clazz is cloning for. | |
78 # \param clazz is the class definition item that is cloning. | |
79 # | |
80 def _clone_classdef(dex, clazz): | |
81 from copy import copy | |
82 from paraspace.dexfile import _DEX_StringDataItem, _DEX_StringId | |
83 from paraspace.dexfile import _DEX_TypeId | |
84 | |
85 visit_log = {} | |
86 | |
87 def cloner(obj): | |
88 clone = copy(obj) | |
89 return clone | |
90 | |
91 def relink_dependencies(clone): | |
92 rel_children = _relocatable_children(clone) | |
93 for attr, value in rel_children: | |
94 clone_value = visit_log[id(value)] | |
95 setattr(clone, attr, clone_value) | |
96 pass | |
97 pass | |
98 | |
99 def merge_unique_strdata(): | |
100 strdatas = [(obj_id, obj) | |
101 for obj_id, obj in visit_log.items() | |
102 if isinstance(obj, _DEX_StringDataItem)] | |
103 dex_str_2_strdata = dict([(strdata.data, strdata) | |
104 for strdata in dex.stringDataItems.items]) | |
105 for obj_id, strdata in strdatas: | |
106 if strdata.data in dex_str_2_strdata: | |
107 visit_log[obj_id] = dex_str_2_strdata[strdata] | |
108 else: | |
109 dex_append_obj_list(dex, strdata) | |
110 pass | |
111 pass | |
112 pass | |
113 | |
114 def merge_unique_strid(): | |
115 strids = [(obj_id, obj) | |
116 for obj_id, obj in visit_log.items() | |
117 if isinstance(obj, _DEX_StringId)] | |
118 | |
119 for obj_id, strid in strids: | |
120 relink_dependencies(strid) | |
121 pass | |
122 | |
123 strdata_2_strid = dict([(strid.stringDataOff, strid) | |
124 for strid in dex.stringIds.items]) | |
125 for obj_id, strid in strids: | |
126 if strid.stringDataOff in strdata_2_strid: | |
127 visit_log[obj_id] = strdata_2_strid[strid.stringDataOff] | |
128 else: | |
129 dex_append_obj_list(dex, strid) | |
130 pass | |
131 pass | |
132 pass | |
133 | |
134 def merge_unique_typeid(): | |
135 typeids = [(obj_id, obj) | |
136 for obj_id, obj in visit_log.items() | |
137 if isinstance(obj, _DEX_TypeId)] | |
138 | |
139 for obj_id, typeid in typeids: | |
140 relink_dependencies(typeid) | |
141 pass | |
142 | |
143 strid_2_typeid = dict([(typeid.descriptorIdx, typeid) | |
144 for typeid in dex.typeIds.items]) | |
145 for obj_id, typeid in typeids: | |
146 if typeid.descriptorIdx in strid_2_typeid: | |
147 visit_log[obj_id] = strid_2_typeid[typeid.descriptorIdx] | |
148 else: | |
149 dex_append_obj_list(dex, typeid) | |
150 pass | |
151 pass | |
152 pass | |
153 | |
154 def has_classdef(clazz): | |
155 class_typeIds = set([classdef.classIdx | |
156 for classdef in dex.classDefs.items]) | |
157 return dex.classIdx in class_typeIds | |
158 | |
159 _travel_desc_relocatable(obj, cloner, visit_log) | |
160 | |
161 merge_unique_strdata() | |
162 merge_unique_strid() | |
163 merge_unique_typeid() | |
164 | |
165 for obj in visit_log.values(): | |
166 if isinstance(obj, (_DEX_StringDataItem, | |
167 _DEX_StringId, | |
168 _DEX_TypeId)): | |
169 continue | |
170 relink_dependencies(obj) | |
171 dex_append_obj_list(dex, obj) | |
172 pass | |
173 | |
174 if has_classef(clazz): | |
175 raise RuntimeError, \ | |
176 'clone a class \'%s\'that is already in the DEXFile' % \ | |
177 classdef_name(clazz) | |
16 pass | 178 pass |
17 | 179 |
18 | 180 |
19 def dexfile_insert_class(dex, class_def): | 181 def dexfile_insert_class(dex, class_def): |
20 classId_orig = class_def.classIdx | 182 _clone_classdef(dex, class_def) |
21 if dex_find_type(dex, class_orig): | |
22 raise RuntimeError, 'duplicated type' | |
23 classId = dex_dup_insert_type(dex, classId_orig) | |
24 | |
25 superclassId_orig = class_def.superclassId | |
26 superclassId = dex_find_type(dex, superclassId_orig) or \ | |
27 dex_dup_insert_type(dex, superclassId_orig) | |
28 | |
29 if dex.interfacesOffRef.is_true: | |
30 interfaces_orig = dex.interfacesOffRef.value | |
31 interfaces = dex_dup_insert_typelist(dex, interfaces_org) | |
32 pass | |
33 | |
34 sourceFileIdx_orig = dex.sourceFileIdx | |
35 sourceFileIdx = dex_find_type(dex, sourceFileIdx_orig) or \ | |
36 dex_dup_insert_type(dex, sourceFileIdx_orig) | |
37 | |
38 if dex.annotationsOffRef.is_true: | |
39 annotations_orig = dex.annotationsOffRef.value | |
40 annotations = dex_dup_insert(dex, annotations_orig) | |
41 pass | |
42 | |
43 if dex.classDataOffRef.is_true: | |
44 class_data_orig = dex.classDataOffRef.value | |
45 class_data = dex_dup_insert(dex, class_data_orig) | |
46 pass | |
47 pass | 183 pass |