ClassDataItem.java revision ec857fcecd0e0d03de6a6bf63625867d4ecaec1c
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.Util.*; 32 33import java.util.ArrayList; 34import java.util.Collections; 35import java.util.List; 36 37public class ClassDataItem extends OffsettedItem<ClassDataItem> { 38 private final ArrayList<EncodedField> staticFieldList = new ArrayList<EncodedField>(); 39 private final ArrayList<EncodedField> instanceFieldList = new ArrayList<EncodedField>(); 40 private final ArrayList<EncodedMethod> directMethodList = new ArrayList<EncodedMethod>(); 41 private final ArrayList<EncodedMethod> virtualMethodList = new ArrayList<EncodedMethod>(); 42 43 private final ListSizeField staticFieldsCountField; 44 private final ListSizeField instanceFieldsCountField; 45 private final ListSizeField directMethodsCountField; 46 private final ListSizeField virtualMethodsCountField; 47 private final EncodedMemberList<EncodedField> staticFieldsListField; 48 private final EncodedMemberList<EncodedField> instanceFieldsListField; 49 private final EncodedMemberList<EncodedMethod> directMethodsListField; 50 private final EncodedMemberList<EncodedMethod> virtualMethodsListField; 51 52 private ClassDefItem parent = null; 53 54 public ClassDataItem(final DexFile dexFile, int offset) { 55 super(offset); 56 57 fields = new Field[] { 58 staticFieldsCountField = new ListSizeField(staticFieldList, 59 new Leb128Field("static_fields_size")), 60 instanceFieldsCountField = new ListSizeField(instanceFieldList, 61 new Leb128Field("instance_fields_size")), 62 directMethodsCountField = new ListSizeField(directMethodList, 63 new Leb128Field("direct_methods_size")), 64 virtualMethodsCountField = new ListSizeField(virtualMethodList, 65 new Leb128Field("virtual_methods_size")), 66 staticFieldsListField = new EncodedMemberList<EncodedField>(staticFieldList, "static_fields") { 67 protected EncodedField make(EncodedField previousField) { 68 return new EncodedField(dexFile, previousField); 69 } 70 }, 71 instanceFieldsListField = new EncodedMemberList<EncodedField>(instanceFieldList, "instance_fields") { 72 protected EncodedField make(EncodedField previousField) { 73 return new EncodedField(dexFile, previousField); 74 } 75 }, 76 directMethodsListField = new EncodedMemberList<EncodedMethod>(directMethodList, "direct_methods") { 77 protected EncodedMethod make(EncodedMethod previousMethod) { 78 return new EncodedMethod(dexFile, previousMethod); 79 } 80 }, 81 virtualMethodsListField = new EncodedMemberList<EncodedMethod>(virtualMethodList, "virtual_methods") { 82 protected EncodedMethod make(EncodedMethod previousMethod) { 83 return new EncodedMethod(dexFile, previousMethod); 84 } 85 } 86 }; 87 } 88 89 public void addMethod(EncodedMethod encodedMethod) { 90 if (encodedMethod.isDirect()) { 91 directMethodList.add(encodedMethod); 92 } else { 93 virtualMethodList.add(encodedMethod); 94 } 95 } 96 97 public int addField(EncodedField encodedField) { 98 if (encodedField.isStatic()) { 99 int index = Collections.binarySearch(staticFieldList, encodedField); 100 if (index >= 0) { 101 throw new RuntimeException("A static field of that name and type is already present"); 102 } 103 index = (index + 1) * -1; 104 staticFieldList.add(index, encodedField); 105 return index; 106 } else { 107 int index = Collections.binarySearch(instanceFieldList, encodedField); 108 if (index >= 0) { 109 throw new RuntimeException("An instance field of that name and type is already present"); 110 } 111 index = (index + 1) * -1; 112 instanceFieldList.add(index, encodedField); 113 return index; 114 } 115 } 116 117 public List<EncodedField> getStaticFields() { 118 return Collections.unmodifiableList(staticFieldList); 119 } 120 121 public List<EncodedField> getInstanceFields() { 122 return Collections.unmodifiableList(instanceFieldList); 123 } 124 125 public List<EncodedMethod> getDirectMethods() { 126 return Collections.unmodifiableList(directMethodList); 127 } 128 129 public List<EncodedMethod> getVirtualMethods() { 130 return Collections.unmodifiableList(virtualMethodList); 131 } 132 133 private static abstract class EncodedMember<T extends EncodedMember<T>> extends CompositeField<T> implements Field<T>, Comparable<T> 134 { 135 public EncodedMember(String fieldName) { 136 super(fieldName); 137 } 138 139 protected abstract void setPreviousMember(T previousMember); 140 } 141 142 private static abstract class EncodedMemberList<T extends EncodedMember<T>> implements Field<EncodedMemberList<T>> { 143 private final ArrayList<T> list; 144 private final String fieldName; 145 146 public EncodedMemberList(ArrayList<T> list, String fieldName) { 147 this.list = list; 148 this.fieldName = fieldName; 149 } 150 151 public void writeTo(AnnotatedOutput out) { 152 out.annotate(0, fieldName + ":"); 153 int i=0; 154 for (T field: list) { 155 out.annotate(0, "[0x" + Integer.toHexString(i) + "]"); 156 field.writeTo(out); 157 i++; 158 } 159 } 160 161 protected abstract T make(T previousField); 162 163 public void readFrom(Input in) { 164 for (int i = 0; i < list.size(); i++) { 165 T previousField = null; 166 if (i > 0) { 167 previousField = list.get(i-1); 168 } 169 T field = make(previousField); 170 list.set(i, field); 171 field.readFrom(in); 172 } 173 } 174 175 public int place(int offset) { 176 Collections.sort(list); 177 178 T previousMember = null; 179 for (T encodedMember: list) { 180 encodedMember.setPreviousMember(previousMember); 181 offset = encodedMember.place(offset); 182 previousMember = encodedMember; 183 } 184 return offset; 185 } 186 187 public void copyTo(DexFile dexFile, EncodedMemberList<T> copy) { 188 copy.list.clear(); 189 copy.list.ensureCapacity(list.size()); 190 for (int i = 0; i < list.size(); i++) { 191 T previousField = null; 192 if (i > 0) { 193 previousField = copy.list.get(i-1); 194 } 195 T fieldCopy = copy.make(previousField); 196 list.get(i).copyTo(dexFile, fieldCopy); 197 copy.list.add(fieldCopy); 198 } 199 } 200 201 public int hashCode() { 202 int h = 1; 203 for (int i = 0; i < list.size(); i++) { 204 h = h * 31 + list.get(i).hashCode(); 205 } 206 return h; 207 } 208 209 public boolean equals(Object o) { 210 if (!(o instanceof EncodedMemberList)) { 211 return false; 212 } 213 214 EncodedMemberList<T> other = (EncodedMemberList<T>)o; 215 if (list.size() != other.list.size()) { 216 return false; 217 } 218 219 for (int i = 0; i < list.size(); i++) { 220 if (!list.get(i).equals(other.list.get(i))) { 221 return false; 222 } 223 } 224 return true; 225 } 226 } 227 228 public static class EncodedField extends EncodedMember<EncodedField> { 229 private final IndexedItemReference<FieldIdItem> fieldReferenceField; 230 private final Leb128DeltaField fieldIndexField; 231 private final Leb128Field accessFlagsField; 232 233 public EncodedField(DexFile dexFile, final EncodedField previousField) { 234 super("encoded_field"); 235 Leb128DeltaField previousIndexField = null; 236 if (previousField != null) { 237 previousIndexField = previousField.fieldIndexField; 238 } 239 240 241 fields = new Field[] { 242 fieldReferenceField = new IndexedItemReference<FieldIdItem>(dexFile.FieldIdsSection, 243 fieldIndexField = new Leb128DeltaField(previousIndexField, null), "field_idx_diff"), 244 accessFlagsField = new Leb128Field("access_flags") 245 }; 246 } 247 248 public EncodedField(DexFile dexFile, FieldIdItem field, int accessFlags) { 249 super("encoded_field"); 250 fields = new Field[] { 251 this.fieldReferenceField = new IndexedItemReference<FieldIdItem>(dexFile, field, 252 fieldIndexField = new Leb128DeltaField(null), "field_idx_diff"), 253 this.accessFlagsField = new Leb128Field(accessFlags, "access_flags") 254 }; 255 } 256 257 protected void setPreviousMember(EncodedField previousField) { 258 if (previousField != null) { 259 fieldIndexField.setPreviousField(previousField.fieldIndexField); 260 } else { 261 fieldIndexField.setPreviousField(null); 262 } 263 } 264 265 public int compareTo(EncodedField other) 266 { 267 return fieldReferenceField.getReference().compareTo(other.fieldReferenceField.getReference()); 268 } 269 270 public boolean isStatic() { 271 return (accessFlagsField.getCachedValue() & AccessFlags.STATIC.getValue()) != 0; 272 } 273 274 public FieldIdItem getField() { 275 return fieldReferenceField.getReference(); 276 } 277 278 public int getAccessFlags() { 279 return accessFlagsField.getCachedValue(); 280 } 281 } 282 283 public static class EncodedMethod extends EncodedMember<EncodedMethod> { 284 private final IndexedItemReference<MethodIdItem> methodReferenceField; 285 private final Leb128DeltaField methodIndexField; 286 private final Leb128Field accessFlagsField; 287 private final OffsettedItemReference<CodeItem> codeItemReferenceField; 288 289 public EncodedMethod(DexFile dexFile, final EncodedMethod previousMethod) { 290 super("encedod_method"); 291 Leb128DeltaField previousIndexField = null; 292 if (previousMethod != null) { 293 previousIndexField = previousMethod.methodIndexField; 294 } 295 296 fields = new Field[] { 297 methodReferenceField = new IndexedItemReference<MethodIdItem>(dexFile.MethodIdsSection, 298 methodIndexField = new Leb128DeltaField(previousIndexField, null), "method_idx_diff"), 299 accessFlagsField = new Leb128Field("access_flags"), 300 codeItemReferenceField = new OffsettedItemReference<CodeItem>(dexFile.CodeItemsSection, 301 new Leb128Field(null), "code_off") 302 }; 303 } 304 305 public EncodedMethod(DexFile dexFile, MethodIdItem methodIdItem, int accessFlags, CodeItem codeItem) { 306 super("encoded_method"); 307 fields = new Field[] { 308 this.methodReferenceField = new IndexedItemReference<MethodIdItem>(dexFile, methodIdItem, 309 methodIndexField = new Leb128DeltaField(null), "method_idx_diff"), 310 this.accessFlagsField = new Leb128Field(accessFlags, "access_flags"), 311 this.codeItemReferenceField = new OffsettedItemReference<CodeItem>(dexFile, codeItem, 312 new Leb128Field(null), "code_off") 313 }; 314 315 if (codeItem != null) { 316 codeItem.setParent(methodIdItem); 317 } 318 } 319 320 protected void setPreviousMember(EncodedMethod previousMethod) { 321 if (previousMethod != null) { 322 methodIndexField.setPreviousField(previousMethod.methodIndexField); 323 } else { 324 methodIndexField.setPreviousField(null); 325 } 326 } 327 328 public int compareTo(EncodedMethod other) { 329 return methodReferenceField.getReference().compareTo(other.methodReferenceField.getReference()); 330 } 331 332 public boolean isDirect() { 333 return ((accessFlagsField.getCachedValue() & (AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue() | 334 AccessFlags.CONSTRUCTOR.getValue())) != 0); 335 } 336 337 public void readFrom(Input in) { 338 super.readFrom(in); 339 CodeItem codeItem = codeItemReferenceField.getReference(); 340 if (codeItem != null) { 341 codeItem.setParent(methodReferenceField.getReference()); 342 } 343 } 344 345 public int getAccessFlags() { 346 return accessFlagsField.getCachedValue(); 347 } 348 349 public MethodIdItem getMethod() { 350 return methodReferenceField.getReference(); 351 } 352 353 public CodeItem getCodeItem() { 354 return codeItemReferenceField.getReference(); 355 } 356 } 357 358 359 /** 360 * An Leb128 integer that encodes its value as the difference between 361 * itself and the previous Leb128DeltaField in the list. The first 362 * item encodes the value as per normal 363 */ 364 protected static class Leb128DeltaField extends Leb128Field { 365 private Leb128DeltaField previousField = null; 366 367 public Leb128DeltaField(String fieldName) { 368 super(fieldName); 369 } 370 371 public void readFrom(Input in) { 372 super.readFrom(in); 373 value += getPreviousValue(); 374 } 375 376 public int place(int offset) { 377 return offset + Leb128Utils.unsignedLeb128Size(value - getPreviousValue()); 378 } 379 380 private int getPreviousValue() { 381 if (previousField == null) { 382 return 0; 383 } 384 return previousField.value; 385 } 386 387 public void writeValue(Output out) { 388 out.writeUnsignedLeb128(value - getPreviousValue()); 389 } 390 391 public Leb128DeltaField(Leb128DeltaField previousField, String fieldName) { 392 super(fieldName); 393 this.previousField = previousField; 394 } 395 396 public void setPreviousField(Leb128DeltaField previousField) { 397 this.previousField = previousField; 398 } 399 } 400 401 protected int getAlignment() { 402 return 1; 403 } 404 405 public ItemType getItemType() { 406 return ItemType.TYPE_CLASS_DATA_ITEM; 407 } 408 409 public String getConciseIdentity() { 410 return "class_data_item @0x" + Integer.toHexString(getOffset()); 411 } 412 413 protected void setParent(ClassDefItem classDefItem) { 414 this.parent = classDefItem; 415 } 416 417 public int compareTo(ClassDataItem other) { 418 if (parent == null) { 419 if (other.parent == null) { 420 return 0; 421 } 422 return -1; 423 } 424 if (other.parent == null) { 425 return 1; 426 } 427 return parent.compareTo(other.parent); 428 } 429} 430