1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dex.reader;
18 
19 import java.lang.reflect.Modifier;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.LinkedList;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 
28 import dex.reader.DexFileReader.ClassDefItem;
29 import dex.reader.DexFileReader.FieldIdItem;
30 import dex.reader.DexFileReader.MethodsIdItem;
31 import dex.reader.DexFileReader.ProtIdItem;
32 import dex.structure.DexAnnotation;
33 import dex.structure.DexClass;
34 import dex.structure.DexField;
35 import dex.structure.DexMethod;
36 
37 /* package */final class DexClassImpl implements DexClass {
38     // constant
39     private final int NO_INDEX = -1;
40     // dex bytes
41     private final DexBuffer buffer;
42     // allready parsed
43     private final ClassDefItem classDefItem;
44     private final int[] typeIds;
45     private final String[] stringPool;
46     private ProtIdItem[] protoIdItems;
47     private FieldIdItem[] fieldIdItems;
48     private MethodsIdItem[] methodIdItems;
49 
50     //
51     private List<DexField> fields;
52     private List<DexMethod> methods;
53     private List<String> interfaces;
54     private ClassDataItem classDataItem;
55     private AnnotationsDirectoryItem annotationDir;
56     private Map<Integer, FieldAnnotation> idToFieldAnnotation =
57             new HashMap<Integer, FieldAnnotation>();
58     private Map<Integer, MethodAnnotation> idToMethodAnnotation =
59             new HashMap<Integer, MethodAnnotation>();
60     private Map<Integer, ParameterAnnotation> idToParameterAnnotation =
61             new HashMap<Integer, ParameterAnnotation>();
62 
63     private Set<DexAnnotation> annotations;
64     private TypeFormatter formatter = new TypeFormatter();
65 
66     private boolean hasClassData;
67 
68 
DexClassImpl(DexBuffer buffer, ClassDefItem classDefItem, String[] stringPool, int[] typeIds, ProtIdItem[] protoIdItems, FieldIdItem[] fieldIdItems, MethodsIdItem[] methodIdItems)69     public DexClassImpl(DexBuffer buffer, ClassDefItem classDefItem,
70             String[] stringPool, int[] typeIds, ProtIdItem[] protoIdItems,
71             FieldIdItem[] fieldIdItems, MethodsIdItem[] methodIdItems) {
72         this.buffer = buffer;
73         this.classDefItem = classDefItem;
74         this.stringPool = stringPool;
75         this.typeIds = typeIds;
76         this.protoIdItems = protoIdItems;
77         this.fieldIdItems = fieldIdItems;
78         this.methodIdItems = methodIdItems;
79         hasClassData = classDefItem.class_data_off != 0;
80         parseClassData();
81         parseAnnotationDirectory();
82         parseClassAnnotations();
83     }
84 
85     static class AnnotationsDirectoryItem {
86         int class_annotations_off; // uint
87         int fields_size; // uint
88         int methods_size; // uint
89         int annotated_params_size; // uint
90         FieldAnnotation[] fieldAnnotations;
91         MethodAnnotation[] methodAnnotations;
92         ParameterAnnotation[] parameterAnnotations;
93     }
94 
95     static class AnnotationSetItem {
96         int size;// uint
97         int[] annotationOffItem;
98     }
99 
100     static class FieldAnnotation {
101         int fieldIdx;// uint
102         int annotationsOff;// uint
103         AnnotationSetItem[] annotationSetItems;
104     }
105 
106     static class MethodAnnotation {
107         int methodIdx;// uint
108         int annotationsOff;// uint
109         AnnotationSetItem[] annotationSetItems;
110     }
111 
112     static class ParameterAnnotation {
113         int methodIdx;// uint
114         int annotationsOff;// uint
115         // AnnotationSetRefListItem[] annotationSetRefListItems;
116     }
117 
parseAnnotationDirectory()118     private void parseAnnotationDirectory() {
119         if (classDefItem.annotations_off != 0) {
120             buffer.setPosition(classDefItem.annotations_off);
121             annotationDir = new AnnotationsDirectoryItem();
122             annotationDir.class_annotations_off = buffer.readUInt();
123             annotationDir.fields_size = buffer.readUInt();
124             annotationDir.methods_size = buffer.readUInt();
125             annotationDir.annotated_params_size = buffer.readUInt();
126 
127             if (annotationDir.fields_size != 0) {
128                 annotationDir.fieldAnnotations =
129                         new FieldAnnotation[annotationDir.fields_size];
130                 for (int i = 0; i < annotationDir.fields_size; i++) {
131                     annotationDir.fieldAnnotations[i] = new FieldAnnotation();
132                     annotationDir.fieldAnnotations[i].fieldIdx = buffer
133                             .readUInt();
134                     annotationDir.fieldAnnotations[i].annotationsOff = buffer
135                             .readUInt();
136                     idToFieldAnnotation.put(
137                             annotationDir.fieldAnnotations[i].fieldIdx,
138                             annotationDir.fieldAnnotations[i]);
139                 }
140             }
141             if (annotationDir.methods_size != 0) {
142                 annotationDir.methodAnnotations =
143                         new MethodAnnotation[annotationDir.methods_size];
144                 for (int i = 0; i < annotationDir.methods_size; i++) {
145                     annotationDir.methodAnnotations[i] = new MethodAnnotation();
146                     annotationDir.methodAnnotations[i].methodIdx = buffer
147                             .readUInt();
148                     annotationDir.methodAnnotations[i].annotationsOff = buffer
149                             .readUInt();
150                     idToMethodAnnotation.put(
151                             annotationDir.methodAnnotations[i].methodIdx,
152                             annotationDir.methodAnnotations[i]);
153                 }
154             }
155             if (annotationDir.annotated_params_size != 0) {
156                 annotationDir.parameterAnnotations =
157                         new ParameterAnnotation[annotationDir
158                                 .annotated_params_size];
159                 for (int i = 0; i < annotationDir.annotated_params_size; i++) {
160                     annotationDir.parameterAnnotations[i] =
161                             new ParameterAnnotation();
162                     annotationDir.parameterAnnotations[i].methodIdx = buffer
163                             .readUInt();
164                     annotationDir.parameterAnnotations[i].annotationsOff =
165                             buffer.readUInt();
166                     idToParameterAnnotation.put(
167                             annotationDir.parameterAnnotations[i].methodIdx,
168                             annotationDir.parameterAnnotations[i]);
169                 }
170             }
171         }
172     }
173 
174     static class ClassDataItem {
175         int static_fields_size;// uleb128
176         int instance_fields_size;// uleb128
177         int direct_methods_size;// uleb128
178         int virtual_methods_size;// uleb128
179         EncodedField[] staticFields;
180         EncodedField[] instanceFields;
181         EncodedMethod[] directMethods;
182         EncodedMethod[] virtualMethods;
183     }
184 
185     static class EncodedField {
186         int field_idx_diff; // uleb128
187         int access_flags; // uleb128
188     }
189 
190     static class EncodedMethod {
191         int method_idx_diff;// uleb128
192         int access_flags;// uleb128
193         int code_off; // uleb128
194     }
195 
parseClassData()196     private void parseClassData() {
197         if (hasClassData) {
198             buffer.setPosition(classDefItem.class_data_off);
199             classDataItem = new ClassDataItem();
200             classDataItem.static_fields_size = buffer.readUleb128();
201             classDataItem.instance_fields_size = buffer.readUleb128();
202             classDataItem.direct_methods_size = buffer.readUleb128();
203             classDataItem.virtual_methods_size = buffer.readUleb128();
204             classDataItem.staticFields = parseFields(
205                     classDataItem.static_fields_size);
206             classDataItem.instanceFields = parseFields(
207                     classDataItem.instance_fields_size);
208             classDataItem.directMethods = parseMethods(
209                     classDataItem.direct_methods_size);
210             classDataItem.virtualMethods = parseMethods(
211                     classDataItem.virtual_methods_size);
212         }
213     }
214 
parseFields(int size)215     private EncodedField[] parseFields(int size) {
216         EncodedField[] fields = new EncodedField[size];
217         for (int i = 0; i < fields.length; i++) {
218             fields[i] = new EncodedField();
219             fields[i].field_idx_diff = buffer.readUleb128();
220             fields[i].access_flags = buffer.readUleb128();
221         }
222         return fields;
223     }
224 
parseMethods(int size)225     private EncodedMethod[] parseMethods(int size) {
226         EncodedMethod[] methods = new EncodedMethod[size];
227         for (int i = 0; i < methods.length; i++) {
228             methods[i] = new EncodedMethod();
229             methods[i].method_idx_diff = buffer.readUleb128();
230             methods[i].access_flags = buffer.readUleb128();
231             methods[i].code_off = buffer.readUleb128();
232         }
233         return methods;
234     }
235 
parseClassAnnotations()236     private void parseClassAnnotations() {
237         annotations = new HashSet<DexAnnotation>();
238         if (annotationDir != null && annotationDir.class_annotations_off != 0) {
239             buffer.setPosition(annotationDir.class_annotations_off);
240             final int size = buffer.readUInt();
241             for (int i = 0; i < size; i++) {
242                 annotations.add(new DexAnnotationImpl(buffer.createCopy(),
243                         buffer.readUInt(), typeIds, stringPool, fieldIdItems));
244             }
245         }
246     }
247 
getFields()248     public synchronized List<DexField> getFields() {
249         if (fields == null) {
250             fields = new ArrayList<DexField>();
251             if (hasClassData) {
252                 fields.addAll(getDexFields(classDataItem.staticFields));
253                 fields.addAll(getDexFields(classDataItem.instanceFields));
254             }
255         }
256         return fields;
257     }
258 
getDexFields(EncodedField[] fields)259     private List<DexField> getDexFields(EncodedField[] fields) {
260         List<DexField> dexFields = new ArrayList<DexField>(fields.length);
261         if (fields.length != 0) {
262             int fieldIdIdx = 0;
263             for (int i = 0; i < fields.length; i++) {
264                 int accessFlags = fields[i].access_flags;
265                 fieldIdIdx = (i == 0) ? fields[i].field_idx_diff : fieldIdIdx
266                         + fields[i].field_idx_diff;
267                 dexFields.add(new DexFieldImpl(buffer.createCopy(), this,
268                         fieldIdItems[fieldIdIdx], accessFlags,
269                         idToFieldAnnotation.get(fieldIdIdx), stringPool,
270                         typeIds, fieldIdItems));
271             }
272         }
273         return dexFields;
274     }
275 
getMethods()276     public synchronized List<DexMethod> getMethods() {
277         if (methods == null) {
278             methods = new ArrayList<DexMethod>();
279             if (hasClassData) {
280                 methods.addAll(getDexMethods(classDataItem.directMethods));
281                 methods.addAll(getDexMethods(classDataItem.virtualMethods));
282             }
283         }
284         return methods;
285     }
286 
getDexMethods(EncodedMethod[] methods)287     private List<DexMethod> getDexMethods(EncodedMethod[] methods) {
288         List<DexMethod> dexMethods = new ArrayList<DexMethod>(methods.length);
289         if (methods.length != 0) {
290             int methodIdIdx = 0;
291             EncodedMethod method = null;
292             for (int i = 0; i < methods.length; i++) {
293                 method = methods[i];
294                 methodIdIdx = (i == 0) ? method.method_idx_diff : methodIdIdx
295                         + method.method_idx_diff;
296                 dexMethods.add(new DexMethodImpl(buffer, this,
297                         methodIdItems[methodIdIdx],
298                         protoIdItems[methodIdItems[methodIdIdx].proto_idx],
299                         method.access_flags, idToMethodAnnotation
300                                 .get(methodIdIdx), idToParameterAnnotation
301                                 .get(methodIdIdx), stringPool, typeIds,
302                         fieldIdItems));
303             }
304         }
305         return dexMethods;
306     }
307 
308 
309 
getInterfaces()310     public synchronized List<String> getInterfaces() {
311         if (interfaces == null) {
312             interfaces = new LinkedList<String>();
313             if (classDefItem.interfaces_off != 0) {
314                 buffer.setPosition(classDefItem.interfaces_off);
315                 int size = buffer.readUInt();
316                 for (int i = 0; i < size; i++) {
317                     interfaces.add(stringPool[typeIds[buffer.readUShort()]]);
318                 }
319             }
320         }
321         return interfaces;
322     }
323 
324     // returns null if no super class is present
getSuperClass()325     public String getSuperClass() {
326         return classDefItem.superclass_idx == NO_INDEX ? null
327                 : stringPool[typeIds[classDefItem.superclass_idx]];
328     }
329 
getAnnotations()330     public Set<DexAnnotation> getAnnotations() {
331         return annotations;
332     }
333 
getName()334     public String getName() {
335         return stringPool[typeIds[classDefItem.class_idx]];
336     }
337 
getModifiers()338     public int getModifiers() {
339         return classDefItem.access_flags;
340     }
341 
342     @Override
toString()343     public String toString() {
344         StringBuilder builder = new StringBuilder();
345         builder.append(formatter.formatAnnotations(getAnnotations()));
346         builder.append(Modifier.toString(getModifiers()));
347         builder.append(" class ");
348         builder.append(formatter.format(getName()));
349         if (getSuperClass() != null) {
350             builder.append(" extends ");
351             builder.append(formatter.format(getSuperClass()));
352         }
353         if (!getInterfaces().isEmpty()) {
354             builder.append(" implements ");
355             builder.append(formatter.format(getInterfaces()));
356         }
357         return builder.toString();
358     }
359 
360 }
361