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