ClassDefItem.java revision fdef6422d2c5c87c0a6599bd568943d493436820
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.dexlib; 30 31import org.jf.dexlib.EncodedValue.EncodedValue; 32import org.jf.dexlib.EncodedValue.EncodedValueSubField; 33import org.jf.dexlib.Util.TypeUtils; 34import org.jf.dexlib.Util.Input; 35 36import java.util.*; 37 38public class ClassDefItem extends IndexedItem<ClassDefItem> { 39 private final IndexedItemReference<TypeIdItem> classTypeReferenceField; 40 private final IntegerField accessFlagsField; 41 private final IndexedItemReference<TypeIdItem> superclassTypeReferenceField; 42 private final OffsettedItemReference<TypeListItem> classInterfacesListReferenceField; 43 private final IndexedItemReference<StringIdItem> sourceFileReferenceField; 44 private final OffsettedItemReference<AnnotationDirectoryItem> classAnnotationsReferenceField; 45 private final OffsettedItemReference<ClassDataItem> classDataReferenceField; 46 private final OffsettedItemReference<EncodedArrayItem> staticFieldInitialValuesReferenceField; 47 48 private ArrayList<EncodedValue> staticFieldInitialValuesList; 49 50 private final DexFile dexFile; 51 52 public ClassDefItem(DexFile dexFile, int index) { 53 super(dexFile, index); 54 55 this.dexFile = dexFile; 56 57 fields = new Field[] { 58 classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, 59 new IntegerField(null), "class_idx"), 60 //TODO: add annotated output showing the flags 61 accessFlagsField = new IntegerField("access_flags:"), 62 superclassTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection, 63 new IntegerField(null), "superclass_idx"), 64 classInterfacesListReferenceField = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection, 65 new IntegerField(null), "interfaces_off"), 66 sourceFileReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, 67 new IntegerField(null), "source_file_off"), 68 classAnnotationsReferenceField = new OffsettedItemReference<AnnotationDirectoryItem>( 69 dexFile.AnnotationDirectoriesSection, new IntegerField(null), "annotations_off"), 70 classDataReferenceField = new OffsettedItemReference<ClassDataItem>(dexFile.ClassDataSection, 71 new IntegerField(null), "class_data_off"), 72 staticFieldInitialValuesReferenceField = new OffsettedItemReference<EncodedArrayItem>( 73 dexFile.EncodedArraysSection, new IntegerField(null), "static_values_off") 74 }; 75 } 76 77 public ClassDefItem(DexFile dexFile, 78 TypeIdItem classType, 79 int accessFlags, 80 TypeIdItem superType, 81 TypeListItem implementsList, 82 StringIdItem source, 83 ClassDataItem classDataItem) { 84 this(dexFile, -1); 85 86 classTypeReferenceField.setReference(classType); 87 accessFlagsField.cacheValue(accessFlags); 88 superclassTypeReferenceField.setReference(superType); 89 classInterfacesListReferenceField.setReference(implementsList); 90 sourceFileReferenceField.setReference(source); 91 classDataReferenceField.setReference(classDataItem); 92 93 if (classDataItem != null) { 94 classDataItem.setParent(this); 95 } 96 } 97 98 public TypeIdItem getSuperclass() { 99 return superclassTypeReferenceField.getReference(); 100 } 101 102 public TypeIdItem getClassType() { 103 return classTypeReferenceField.getReference(); 104 } 105 106 protected int getAlignment() { 107 return 4; 108 } 109 110 public ItemType getItemType() { 111 return ItemType.TYPE_CLASS_DEF_ITEM; 112 } 113 114 public String getClassName() { 115 return classTypeReferenceField.getReference().getTypeDescriptor(); 116 } 117 118 public String getSourceFile() { 119 StringIdItem stringIdItem = sourceFileReferenceField.getReference(); 120 if (stringIdItem == null) { 121 return null; 122 } 123 return stringIdItem.getStringValue(); 124 } 125 126 public int getAccessFlags() { 127 return accessFlagsField.getCachedValue(); 128 } 129 130 public List<TypeIdItem> getInterfaces() { 131 TypeListItem interfaceList = classInterfacesListReferenceField.getReference(); 132 if (interfaceList == null) { 133 return null; 134 } 135 136 return interfaceList.getTypes(); 137 } 138 139 public ClassDataItem getClassData() { 140 return classDataReferenceField.getReference(); 141 } 142 143 public AnnotationDirectoryItem getAnnotationDirectory() { 144 return classAnnotationsReferenceField.getReference(); 145 } 146 147 public String getConciseIdentity() { 148 return "class_def_item: " + getClassName(); 149 } 150 151 public int hashCode() { 152 return classTypeReferenceField.getReference().hashCode(); 153 } 154 155 public boolean equals(Object o) { 156 if (!(o instanceof ClassDefItem)) { 157 return false; 158 } 159 ClassDefItem other = (ClassDefItem)o; 160 return classTypeReferenceField.equals(other.classTypeReferenceField); 161 } 162 163 public EncodedArrayItem getStaticInitializers() { 164 return staticFieldInitialValuesReferenceField.getReference(); 165 } 166 167 public int compareTo(ClassDefItem o) { 168 //The actual sorting for this class is implemented in SortClassDefItemSection. 169 //This method is just used for sorting the associated ClassDataItem items, so 170 //we can just do the comparison based on the offsets of the items 171 return ((Integer)this.offset).compareTo(o.offset); 172 } 173 174 public void addField(ClassDataItem.EncodedField encodedField, EncodedValue initialValue) { 175 //fields are added in ClassDefItem instead of ClassDataItem because we need to grab 176 //the static initializers for StaticFieldInitialValues 177 if (!encodedField.isStatic() && initialValue != null) { 178 throw new RuntimeException("Initial values are only allowed for static fields."); 179 } 180 181 ClassDataItem classDataItem = this.classDataReferenceField.getReference(); 182 183 int fieldIndex = classDataItem.addField(encodedField); 184 if (initialValue != null) { 185 if (staticFieldInitialValuesList == null) { 186 staticFieldInitialValuesList = new ArrayList<EncodedValue>(); 187 188 EncodedArrayItem encodedArrayItem = new EncodedArrayItem(dexFile, staticFieldInitialValuesList); 189 staticFieldInitialValuesReferenceField.setReference(encodedArrayItem); 190 } 191 192 //All static fields before this one must have an initial value. Add any default values as needed 193 for (int i=staticFieldInitialValuesList.size(); i < fieldIndex; i++) { 194 ClassDataItem.EncodedField staticField = classDataItem.getStaticFields().get(i); 195 EncodedValueSubField subField = TypeUtils.makeDefaultValueForType(dexFile, 196 staticField.getField().getFieldType().getTypeDescriptor()); 197 EncodedValue encodedValue = new EncodedValue(dexFile, subField); 198 staticFieldInitialValuesList.add(i, encodedValue); 199 } 200 201 staticFieldInitialValuesList.add(fieldIndex, initialValue); 202 } else if (staticFieldInitialValuesList != null && encodedField.isStatic() && fieldIndex < staticFieldInitialValuesList.size()) { 203 EncodedValueSubField subField = TypeUtils.makeDefaultValueForType(dexFile, 204 encodedField.getField().getFieldType().getTypeDescriptor()); 205 EncodedValue encodedValue = new EncodedValue(dexFile, subField); 206 staticFieldInitialValuesList.add(fieldIndex, encodedValue); 207 } 208 } 209 210 public void setAnnotations(AnnotationDirectoryItem annotations) { 211 this.classAnnotationsReferenceField.setReference(annotations); 212 if (annotations != null) { 213 annotations.setParent(this); 214 } 215 } 216 217 public void setClassDataItem(ClassDataItem classDataItem) { 218 this.classDataReferenceField.setReference(classDataItem); 219 if (classDataItem != null) { 220 classDataItem.setParent(this); 221 } 222 } 223 224 public void readFrom(Input in, int index) { 225 super.readFrom(in, index); 226 227 ClassDataItem classDataItem = classDataReferenceField.getReference(); 228 if (classDataItem != null) { 229 classDataItem.setParent(this); 230 } 231 232 AnnotationDirectoryItem annotationDirectoryItem = classAnnotationsReferenceField.getReference(); 233 if (annotationDirectoryItem != null) { 234 annotationDirectoryItem.setParent(this); 235 } 236 } 237 238 public static int placeClassDefItems(IndexedSection<ClassDefItem> section, int offset) { 239 ClassDefPlacer cdp = new ClassDefPlacer(section); 240 return cdp.placeSection(offset); 241 } 242 243 /** 244 * This class places the items within a ClassDefItem section, such that superclasses and interfaces are 245 * placed before sub/implementing classes 246 */ 247 private static class ClassDefPlacer { 248 private final IndexedSection<ClassDefItem> section; 249 private final HashMap<TypeIdItem, ClassDefItem> classDefsByType = new HashMap<TypeIdItem, ClassDefItem>(); 250 251 private int currentIndex = 0; 252 private int currentOffset; 253 254 public ClassDefPlacer(IndexedSection<ClassDefItem> section) { 255 this.section = section; 256 257 for (ClassDefItem classDefItem: section.items) { 258 TypeIdItem typeIdItem = classDefItem.classTypeReferenceField.getReference(); 259 classDefsByType.put(typeIdItem, classDefItem); 260 } 261 } 262 263 public int placeSection(int offset) { 264 currentOffset = offset; 265 266 if (section.dexFile.getSortAllItems()) { 267 //presort the list, to guarantee a unique ordering 268 Collections.sort(section.items, new Comparator<ClassDefItem>() { 269 public int compare(ClassDefItem classDefItem, ClassDefItem classDefItem1) { 270 return classDefItem.getClassType().compareTo(classDefItem1.getClassType()); 271 } 272 }); 273 } 274 275 for (ClassDefItem classDefItem: section.items) { 276 classDefItem.offset = -1; 277 } 278 279 for (ClassDefItem classDefItem: section.items) { 280 placeClass(classDefItem); 281 } 282 283 for (ClassDefItem classDefItem: classDefsByType.values()) { 284 section.items.set(classDefItem.getIndex(), classDefItem); 285 } 286 287 return currentOffset; 288 } 289 290 private void placeClass(ClassDefItem classDefItem) { 291 if (!classDefItem.isPlaced()) { 292 TypeIdItem superType = classDefItem.superclassTypeReferenceField.getReference(); 293 ClassDefItem superClassDefItem = classDefsByType.get(superType); 294 295 if (superClassDefItem != null) { 296 placeClass(superClassDefItem); 297 } 298 299 TypeListItem interfaces = classDefItem.classInterfacesListReferenceField.getReference(); 300 301 if (interfaces != null) { 302 for (TypeIdItem interfaceType: interfaces.getTypes()) { 303 ClassDefItem interfaceClass = classDefsByType.get(interfaceType); 304 if (interfaceClass != null) { 305 placeClass(interfaceClass); 306 } 307 } 308 } 309 310 currentOffset = classDefItem.place(currentIndex++, currentOffset); 311 } 312 } 313 314 } 315} 316