ClassDefinition.java revision 090e553f34a176bc558f0d70392181c0fbd83fe8
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.InstructionIterator; 34import org.jf.dexlib.Code.Opcode; 35import org.jf.dexlib.Code.Format.Format; 36import org.jf.dexlib.Code.Format.Instruction21c; 37import org.jf.dexlib.Util.AccessFlags; 38import org.jf.dexlib.Util.SparseArray; 39import org.antlr.stringtemplate.StringTemplate; 40import org.antlr.stringtemplate.StringTemplateGroup; 41 42import java.util.*; 43 44public class ClassDefinition { 45 private StringTemplateGroup stg; 46 private ClassDefItem classDefItem; 47 private ClassDataItem classDataItem; 48 49 private SparseArray<AnnotationSetItem> methodAnnotationsMap; 50 private SparseArray<AnnotationSetItem> fieldAnnotationsMap; 51 private SparseArray<AnnotationSetRefList> parameterAnnotationsMap; 52 53 private SparseArray<FieldIdItem> fieldsSetInStaticConstructor; 54 55 public ClassDefinition(StringTemplateGroup stg, ClassDefItem classDefItem) { 56 this.stg = stg; 57 this.classDefItem = classDefItem; 58 this.classDataItem = classDefItem.getClassData(); 59 buildAnnotationMaps(); 60 findFieldsSetInStaticConstructor(); 61 } 62 63 public StringTemplate makeTemplate() { 64 StringTemplate template = stg.getInstanceOf("smaliFile"); 65 66 template.setAttribute("AccessFlags", getAccessFlags()); 67 template.setAttribute("ClassType", classDefItem.getClassType().getTypeDescriptor()); 68 template.setAttribute("SuperType", getSuperType()); 69 template.setAttribute("SourceFile", getSourceFile()); 70 template.setAttribute("Interfaces", getInterfaces()); 71 template.setAttribute("Annotations", getAnnotations()); 72 template.setAttribute("StaticFields", getStaticFields()); 73 template.setAttribute("InstanceFields", getInstanceFields()); 74 template.setAttribute("DirectMethods", getDirectMethods()); 75 template.setAttribute("VirtualMethods", getVirtualMethods()); 76 77 return template; 78 } 79 80 private void buildAnnotationMaps() { 81 AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations(); 82 if (annotationDirectory == null) { 83 methodAnnotationsMap = new SparseArray<AnnotationSetItem>(0); 84 fieldAnnotationsMap = new SparseArray<AnnotationSetItem>(0); 85 parameterAnnotationsMap = new SparseArray<AnnotationSetRefList>(0); 86 return; 87 } 88 89 methodAnnotationsMap = new SparseArray<AnnotationSetItem>(annotationDirectory.getMethodAnnotationCount()); 90 annotationDirectory.iterateMethodAnnotations(new AnnotationDirectoryItem.MethodAnnotationIteratorDelegate() { 91 public void processMethodAnnotations(MethodIdItem method, AnnotationSetItem methodAnnotations) { 92 methodAnnotationsMap.put(method.getIndex(), methodAnnotations); 93 } 94 }); 95 96 fieldAnnotationsMap = new SparseArray<AnnotationSetItem>(annotationDirectory.getFieldAnnotationCount()); 97 annotationDirectory.iterateFieldAnnotations(new AnnotationDirectoryItem.FieldAnnotationIteratorDelegate() { 98 public void processFieldAnnotations(FieldIdItem field, AnnotationSetItem fieldAnnotations) { 99 fieldAnnotationsMap.put(field.getIndex(), fieldAnnotations); 100 } 101 }); 102 103 parameterAnnotationsMap = new SparseArray<AnnotationSetRefList>( 104 annotationDirectory.getParameterAnnotationCount()); 105 annotationDirectory.iterateParameterAnnotations( 106 new AnnotationDirectoryItem.ParameterAnnotationIteratorDelegate() { 107 public void processParameterAnnotations(MethodIdItem method, AnnotationSetRefList parameterAnnotations) { 108 parameterAnnotationsMap.put(method.getIndex(), parameterAnnotations); 109 } 110 }); 111 } 112 113 private void findFieldsSetInStaticConstructor() { 114 fieldsSetInStaticConstructor = new SparseArray<FieldIdItem>(); 115 116 if (classDataItem == null) { 117 return; 118 } 119 120 for (ClassDataItem.EncodedMethod directMethod: classDataItem.getDirectMethods()) { 121 if (directMethod.method.getMethodName().getStringValue().equals("<clinit>")) { 122 final byte[] encodedInstructions = directMethod.codeItem.getEncodedInstructions(); 123 124 InstructionIterator.IterateInstructions(encodedInstructions, 125 new InstructionIterator.ProcessRawInstructionDelegate() { 126 public void ProcessNormalInstruction(Opcode opcode, int index) { 127 } 128 129 public void ProcessReferenceInstruction(Opcode opcode, int index) { 130 switch (opcode) { 131 case SPUT: 132 case SPUT_BOOLEAN: 133 case SPUT_BYTE: 134 case SPUT_CHAR: 135 case SPUT_OBJECT: 136 case SPUT_SHORT: 137 case SPUT_WIDE: 138 Instruction21c ins = (Instruction21c)Format.Format21c.Factory.makeInstruction( 139 classDefItem.getDexFile(), opcode, encodedInstructions, index); 140 FieldIdItem fieldIdItem = (FieldIdItem)ins.getReferencedItem(); 141 fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem); 142 } 143 } 144 145 public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) { 146 } 147 148 public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) { 149 } 150 151 public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount, int instructionLength) { 152 } 153 }); 154 155 } 156 } 157 } 158 159 private List<String> getAccessFlags() { 160 List<String> accessFlags = new ArrayList<String>(); 161 162 for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForClass(classDefItem.getAccessFlags())) { 163 accessFlags.add(accessFlag.toString()); 164 } 165 166 return accessFlags; 167 } 168 169 170 private String getSuperType() { 171 TypeIdItem superClass = classDefItem.getSuperclass(); 172 if (superClass != null) { 173 return superClass.getTypeDescriptor(); 174 } 175 return null; 176 } 177 178 private String getSourceFile() { 179 StringIdItem sourceFile = classDefItem.getSourceFile(); 180 181 if (sourceFile == null) { 182 return null; 183 } 184 return classDefItem.getSourceFile().getStringValue(); 185 } 186 187 private List<String> getInterfaces() { 188 List<String> interfaces = new ArrayList<String>(); 189 190 TypeListItem interfaceList = classDefItem.getInterfaces(); 191 192 if (interfaceList != null) { 193 for (TypeIdItem typeIdItem: interfaceList.getTypes()) { 194 interfaces.add(typeIdItem.getTypeDescriptor()); 195 } 196 } 197 198 return interfaces; 199 } 200 201 private List<StringTemplate> getAnnotations() { 202 AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations(); 203 if (annotationDirectory == null) { 204 return null; 205 } 206 207 AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations(); 208 if (annotationSet == null) { 209 return null; 210 } 211 212 List<StringTemplate> annotations = new ArrayList<StringTemplate>(); 213 214 for (AnnotationItem annotationItem: annotationSet.getAnnotations()) { 215 annotations.add(AnnotationAdaptor.makeTemplate(stg, annotationItem)); 216 } 217 return annotations; 218 } 219 220 private List<StringTemplate> getStaticFields() { 221 List<StringTemplate> staticFields = new ArrayList<StringTemplate>(); 222 223 if (classDataItem != null) { 224 EncodedArrayItem encodedStaticInitializers = classDefItem.getStaticFieldInitializers(); 225 226 EncodedValue[] staticInitializers; 227 if (encodedStaticInitializers != null) { 228 staticInitializers = encodedStaticInitializers.getEncodedArray().values; 229 } else { 230 staticInitializers = new EncodedValue[0]; 231 } 232 233 int i=0; 234 for (ClassDataItem.EncodedField field: classDataItem.getStaticFields()) { 235 EncodedValue encodedValue = null; 236 if (i < staticInitializers.length) { 237 encodedValue = staticInitializers[i]; 238 } 239 AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex()); 240 241 boolean setInStaticConstructor = 242 fieldsSetInStaticConstructor.get(field.field.getIndex()) != null; 243 244 staticFields.add(FieldDefinition.createTemplate(stg, field, encodedValue, annotationSet, 245 setInStaticConstructor)); 246 i++; 247 } 248 } 249 return staticFields; 250 } 251 252 private List<StringTemplate> getInstanceFields() { 253 List<StringTemplate> instanceFields = new ArrayList<StringTemplate>(); 254 255 if (classDataItem != null) { 256 for (ClassDataItem.EncodedField field: classDataItem.getInstanceFields()) { 257 AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex()); 258 instanceFields.add(FieldDefinition.createTemplate(stg, field, annotationSet)); 259 } 260 } 261 262 return instanceFields; 263 } 264 265 private List<StringTemplate> getDirectMethods() { 266 List<StringTemplate> directMethods = new ArrayList<StringTemplate>(); 267 268 if (classDataItem != null) { 269 for (ClassDataItem.EncodedMethod method: classDataItem.getDirectMethods()) { 270 AnnotationSetItem annotationSet = methodAnnotationsMap.get(method.method.getIndex()); 271 AnnotationSetRefList parameterAnnotationList = parameterAnnotationsMap.get(method.method.getIndex()); 272 directMethods.add(MethodDefinition.makeTemplate(stg, method, annotationSet, parameterAnnotationList)); 273 } 274 } 275 276 return directMethods; 277 } 278 279 private List<StringTemplate> getVirtualMethods() { 280 List<StringTemplate> virtualMethods = new ArrayList<StringTemplate>(); 281 282 if (classDataItem != null) { 283 for (ClassDataItem.EncodedMethod method: classDataItem.getVirtualMethods()) { 284 AnnotationSetItem annotationSet = methodAnnotationsMap.get(method.method.getIndex()); 285 AnnotationSetRefList parameterAnnotationList = parameterAnnotationsMap.get(method.method.getIndex()); 286 virtualMethods.add(MethodDefinition.makeTemplate(stg, method, annotationSet, parameterAnnotationList)); 287 } 288 } 289 290 return virtualMethods; 291 } 292} 293