ClassDefinition.java revision 00fc68adf2e39aeb9fed35293f2576bbe729ec4b
1dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/*
2dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * [The "BSD licence"]
3dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * Copyright (c) 2010 Ben Gruver (JesusFreke)
4dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * All rights reserved.
5dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines *
6dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * Redistribution and use in source and binary forms, with or without
7dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * modification, are permitted provided that the following conditions
8dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * are met:
9dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * 1. Redistributions of source code must retain the above copyright
10dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines *    notice, this list of conditions and the following disclaimer.
11dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * 2. Redistributions in binary form must reproduce the above copyright
12dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines *    notice, this list of conditions and the following disclaimer in the
13dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines *    documentation and/or other materials provided with the distribution.
14dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * 3. The name of the author may not be used to endorse or promote products
15dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines *    derived from this software without specific prior written permission.
16dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines *
17dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines */
28dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
29dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinespackage org.jf.baksmali.Adaptors;
30dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
31dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.Code.Analysis.ValidationException;
32dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.EncodedValue.EncodedValue;
33dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.*;
34dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.Code.Instruction;
35dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.Code.Format.Instruction21c;
36dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.Util.AccessFlags;
37dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.Util.SparseArray;
38dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.antlr.stringtemplate.StringTemplate;
39dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.antlr.stringtemplate.StringTemplateGroup;
40dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
41dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport java.util.*;
42dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
43dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinespublic class ClassDefinition {
44dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    private StringTemplateGroup stg;
45dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    private ClassDefItem classDefItem;
46dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    private ClassDataItem classDataItem;
47dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
48dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    private SparseArray<AnnotationSetItem> methodAnnotationsMap;
49dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    private SparseArray<AnnotationSetItem> fieldAnnotationsMap;
50dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    private SparseArray<AnnotationSetRefList> parameterAnnotationsMap;
51dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
52dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    private SparseArray<FieldIdItem> fieldsSetInStaticConstructor;
53dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
54dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    protected boolean validationErrors;
55dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
56dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    public ClassDefinition(StringTemplateGroup stg, ClassDefItem classDefItem) {
57dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        this.stg = stg;
58dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        this.classDefItem = classDefItem;
59dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        this.classDataItem = classDefItem.getClassData();
60dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        buildAnnotationMaps();
61dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        findFieldsSetInStaticConstructor();
62dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    }
63dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
64dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    public StringTemplate createTemplate() {
65dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        StringTemplate template = stg.getInstanceOf("smaliFile");
66dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
67dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        template.setAttribute("AccessFlags", getAccessFlags());
68dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        template.setAttribute("ClassType", classDefItem.getClassType().getTypeDescriptor());
69dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        template.setAttribute("SuperType", getSuperType());
70dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        template.setAttribute("SourceFile", getSourceFile());
71dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        template.setAttribute("Interfaces", getInterfaces());
72dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        template.setAttribute("Annotations", getAnnotations());
73dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        template.setAttribute("StaticFields", getStaticFields());
74dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        template.setAttribute("InstanceFields", getInstanceFields());
75        template.setAttribute("DirectMethods", getDirectMethods());
76        template.setAttribute("VirtualMethods", getVirtualMethods());
77
78        return template;
79    }
80
81    public boolean hadValidationErrors() {
82        return validationErrors;
83    }
84
85    private void buildAnnotationMaps() {
86        AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations();
87        if (annotationDirectory == null) {
88            methodAnnotationsMap = new SparseArray<AnnotationSetItem>(0);
89            fieldAnnotationsMap = new SparseArray<AnnotationSetItem>(0);
90            parameterAnnotationsMap = new SparseArray<AnnotationSetRefList>(0);
91            return;
92        }
93
94        methodAnnotationsMap = new SparseArray<AnnotationSetItem>(annotationDirectory.getMethodAnnotationCount());
95        annotationDirectory.iterateMethodAnnotations(new AnnotationDirectoryItem.MethodAnnotationIteratorDelegate() {
96            public void processMethodAnnotations(MethodIdItem method, AnnotationSetItem methodAnnotations) {
97                methodAnnotationsMap.put(method.getIndex(), methodAnnotations);
98            }
99        });
100
101        fieldAnnotationsMap = new SparseArray<AnnotationSetItem>(annotationDirectory.getFieldAnnotationCount());
102        annotationDirectory.iterateFieldAnnotations(new AnnotationDirectoryItem.FieldAnnotationIteratorDelegate() {
103            public void processFieldAnnotations(FieldIdItem field, AnnotationSetItem fieldAnnotations) {
104                fieldAnnotationsMap.put(field.getIndex(), fieldAnnotations);
105            }
106        });
107
108        parameterAnnotationsMap = new SparseArray<AnnotationSetRefList>(
109                annotationDirectory.getParameterAnnotationCount());
110        annotationDirectory.iterateParameterAnnotations(
111          new AnnotationDirectoryItem.ParameterAnnotationIteratorDelegate() {
112            public void processParameterAnnotations(MethodIdItem method, AnnotationSetRefList parameterAnnotations) {
113                parameterAnnotationsMap.put(method.getIndex(), parameterAnnotations);
114            }
115        });
116    }
117
118    private void findFieldsSetInStaticConstructor() {
119        fieldsSetInStaticConstructor = new SparseArray<FieldIdItem>();
120
121        if (classDataItem == null) {
122            return;
123        }
124
125        for (ClassDataItem.EncodedMethod directMethod: classDataItem.getDirectMethods()) {
126            if (directMethod.method.getMethodName().getStringValue().equals("<clinit>")) {
127
128                for (Instruction instruction: directMethod.codeItem.getInstructions()) {
129                    switch (instruction.opcode) {
130                        case SPUT:
131                        case SPUT_BOOLEAN:
132                        case SPUT_BYTE:
133                        case SPUT_CHAR:
134                        case SPUT_OBJECT:
135                        case SPUT_SHORT:
136                        case SPUT_WIDE:
137                            Instruction21c ins = (Instruction21c)instruction;
138                            FieldIdItem fieldIdItem = (FieldIdItem)ins.getReferencedItem();
139                            fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem);
140                    }
141                }
142            }
143        }
144    }
145
146    private List<String> getAccessFlags() {
147        List<String> accessFlags = new ArrayList<String>();
148
149        for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForClass(classDefItem.getAccessFlags())) {
150            accessFlags.add(accessFlag.toString());
151        }
152
153        return accessFlags;
154    }
155
156
157    private String getSuperType() {
158        TypeIdItem superClass = classDefItem.getSuperclass();
159        if (superClass != null) {
160            return superClass.getTypeDescriptor();
161        }
162        return null;
163    }
164
165    private String getSourceFile() {
166        StringIdItem sourceFile = classDefItem.getSourceFile();
167
168        if (sourceFile == null) {
169            return null;
170        }
171        return classDefItem.getSourceFile().getStringValue();
172    }
173
174    private List<String> getInterfaces() {
175        List<String> interfaces = new ArrayList<String>();
176
177        TypeListItem interfaceList = classDefItem.getInterfaces();
178
179        if (interfaceList != null) {
180            for (TypeIdItem typeIdItem: interfaceList.getTypes()) {
181                interfaces.add(typeIdItem.getTypeDescriptor());
182            }
183        }
184
185        return interfaces;
186    }
187
188    private List<StringTemplate> getAnnotations() {
189        AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations();
190        if (annotationDirectory == null) {
191            return null;
192        }
193
194        AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations();
195        if (annotationSet == null) {
196            return null;
197        }
198
199        List<StringTemplate> annotations = new ArrayList<StringTemplate>();
200
201        for (AnnotationItem annotationItem: annotationSet.getAnnotations()) {
202            annotations.add(AnnotationAdaptor.createTemplate(stg, annotationItem));
203        }
204        return annotations;
205    }
206
207    private List<StringTemplate> getStaticFields() {
208        List<StringTemplate> staticFields = new ArrayList<StringTemplate>();
209
210        if (classDataItem != null) {
211            //if classDataItem is not null, then classDefItem won't be null either
212            assert(classDefItem != null);
213            EncodedArrayItem encodedStaticInitializers = classDefItem.getStaticFieldInitializers();
214
215            EncodedValue[] staticInitializers;
216            if (encodedStaticInitializers != null) {
217                staticInitializers = encodedStaticInitializers.getEncodedArray().values;
218            } else {
219                staticInitializers = new EncodedValue[0];
220            }
221
222            int i=0;
223            for (ClassDataItem.EncodedField field: classDataItem.getStaticFields()) {
224                EncodedValue encodedValue = null;
225                if (i < staticInitializers.length) {
226                    encodedValue = staticInitializers[i];
227                }
228                AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex());
229
230                boolean setInStaticConstructor =
231                        fieldsSetInStaticConstructor.get(field.field.getIndex()) != null;
232
233                staticFields.add(FieldDefinition.createTemplate(stg, field, encodedValue, annotationSet,
234                        setInStaticConstructor));
235                i++;
236            }
237        }
238        return staticFields;
239    }
240
241    private List<StringTemplate> getInstanceFields() {
242        List<StringTemplate> instanceFields = new ArrayList<StringTemplate>();
243
244        if (classDataItem != null) {
245            for (ClassDataItem.EncodedField field: classDataItem.getInstanceFields()) {
246                AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex());
247                instanceFields.add(FieldDefinition.createTemplate(stg, field, annotationSet));
248            }
249        }
250
251        return instanceFields;
252    }
253
254    private List<StringTemplate> getDirectMethods() {
255        if (classDataItem == null) {
256            return null;
257        }
258
259        return getTemplatesForMethods(classDataItem.getDirectMethods());
260    }
261
262    private List<StringTemplate> getVirtualMethods() {
263        if (classDataItem == null) {
264            return null;
265        }
266
267        return getTemplatesForMethods(classDataItem.getVirtualMethods());
268    }
269
270    private List<StringTemplate> getTemplatesForMethods(ClassDataItem.EncodedMethod[] methods) {
271        List<StringTemplate> methodTemplates = new ArrayList<StringTemplate>();
272
273        for (ClassDataItem.EncodedMethod method: methods) {
274            AnnotationSetItem annotationSet = methodAnnotationsMap.get(method.method.getIndex());
275            AnnotationSetRefList parameterAnnotationList = parameterAnnotationsMap.get(method.method.getIndex());
276
277            MethodDefinition methodDefinition = new MethodDefinition(stg, method);
278
279            methodTemplates.add(methodDefinition.createTemplate(annotationSet, parameterAnnotationList));
280
281            ValidationException validationException = methodDefinition.getValidationException();
282            if (validationException != null) {
283                //System.err.println(validationException.toString());
284                validationException.printStackTrace(System.err);
285                this.validationErrors = true;
286            }
287        }
288
289        return methodTemplates;
290    }
291}
292