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