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