1 /* 2 * [The "BSD licence"] 3 * Copyright (c) 2010 Ben Gruver (JesusFreke) 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 29 package org.jf.dexlib; 30 31 import org.jf.dexlib.Util.AnnotatedOutput; 32 import org.jf.dexlib.Util.Input; 33 34 public class FieldIdItem extends Item<FieldIdItem> { 35 private int hashCode = 0; 36 37 private TypeIdItem classType; 38 private TypeIdItem fieldType; 39 private StringIdItem fieldName; 40 41 /** 42 * Creates a new uninitialized <code>FieldIdItem</code> 43 * @param dexFile The <code>DexFile</code> that this item belongs to 44 */ FieldIdItem(DexFile dexFile)45 protected FieldIdItem(DexFile dexFile) { 46 super(dexFile); 47 } 48 49 /** 50 * Creates a new <code>FieldIdItem</code> for the given class, type and name 51 * @param dexFile The <code>DexFile</code> that this item belongs to 52 * @param classType the class that the field is a member of 53 * @param fieldType the type of the field 54 * @param fieldName the name of the field 55 */ FieldIdItem(DexFile dexFile, TypeIdItem classType, TypeIdItem fieldType, StringIdItem fieldName)56 private FieldIdItem(DexFile dexFile, TypeIdItem classType, TypeIdItem fieldType, StringIdItem fieldName) { 57 this(dexFile); 58 59 assert classType.dexFile == dexFile; 60 assert fieldType.dexFile == dexFile; 61 assert fieldName.dexFile == dexFile; 62 63 this.classType = classType; 64 this.fieldType = fieldType; 65 this.fieldName = fieldName; 66 } 67 68 /** 69 * Returns a <code>FieldIdItem</code> for the given values, and that has been interned into 70 * the given <code>DexFile</code> 71 * @param dexFile The <code>DexFile</code> that this item belongs to 72 * @param classType the class that the field is a member of 73 * @param fieldType the type of the field 74 * @param fieldName the name of the field 75 * @return a <code>FieldIdItem</code> for the given values, and that has been interned into 76 * the given <code>DexFile</code> 77 */ internFieldIdItem(DexFile dexFile, TypeIdItem classType, TypeIdItem fieldType, StringIdItem fieldName)78 public static FieldIdItem internFieldIdItem(DexFile dexFile, TypeIdItem classType, TypeIdItem fieldType, 79 StringIdItem fieldName) { 80 FieldIdItem fieldIdItem = new FieldIdItem(dexFile, classType, fieldType, fieldName); 81 return dexFile.FieldIdsSection.intern(fieldIdItem); 82 } 83 84 /** 85 * Looks up a <code>FieldIdItem</code> from the given <code>DexFile</code> for the given 86 * values 87 * @param dexFile The <code>DexFile</code> that this item belongs to 88 * @param classType the class that the field is a member of 89 * @param fieldType the type of the field 90 * @param fieldName the name of the field 91 * @return a <code>FieldIdItem</code> from the given <code>DexFile</code> for the given 92 * values, or null if it doesn't exist 93 */ lookupFieldIdItem(DexFile dexFile, TypeIdItem classType, TypeIdItem fieldType, StringIdItem fieldName)94 public static FieldIdItem lookupFieldIdItem(DexFile dexFile, TypeIdItem classType, TypeIdItem fieldType, 95 StringIdItem fieldName) { 96 FieldIdItem fieldIdItem = new FieldIdItem(dexFile, classType, fieldType, fieldName); 97 return dexFile.FieldIdsSection.getInternedItem(fieldIdItem); 98 } 99 100 /** {@inheritDoc} */ readItem(Input in, ReadContext readContext)101 protected void readItem(Input in, ReadContext readContext) { 102 classType = dexFile.TypeIdsSection.getItemByIndex(in.readShort()); 103 fieldType = dexFile.TypeIdsSection.getItemByIndex(in.readShort()); 104 fieldName = dexFile.StringIdsSection.getItemByIndex(in.readInt()); 105 } 106 107 /** {@inheritDoc} */ placeItem(int offset)108 protected int placeItem(int offset) { 109 return offset + 8; 110 } 111 112 /** {@inheritDoc} */ writeItem(AnnotatedOutput out)113 protected void writeItem(AnnotatedOutput out) { 114 if (out.annotates()) { 115 out.annotate(2, "class_type: " + classType.getTypeDescriptor()); 116 out.annotate(2, "field_type: " + fieldType.getTypeDescriptor()); 117 out.annotate(4, "field_name: " + fieldName.getStringValue()); 118 } 119 120 out.writeShort(classType.getIndex()); 121 out.writeShort(fieldType.getIndex()); 122 out.writeInt(fieldName.getIndex()); 123 } 124 125 /** {@inheritDoc} */ getItemType()126 public ItemType getItemType() { 127 return ItemType.TYPE_FIELD_ID_ITEM; 128 } 129 130 /** {@inheritDoc} */ getConciseIdentity()131 public String getConciseIdentity() { 132 return getFieldString(); 133 } 134 135 /** {@inheritDoc} */ compareTo(FieldIdItem o)136 public int compareTo(FieldIdItem o) { 137 int result = classType.compareTo(o.classType); 138 if (result != 0) { 139 return result; 140 } 141 142 result = fieldName.compareTo(o.fieldName); 143 if (result != 0) { 144 return result; 145 } 146 147 return fieldType.compareTo(o.fieldType); 148 } 149 150 /** 151 * @return the class that this field is a member of 152 */ getContainingClass()153 public TypeIdItem getContainingClass() { 154 return classType; 155 } 156 157 /** 158 * @return the type of this field 159 */ getFieldType()160 public TypeIdItem getFieldType() { 161 return fieldType; 162 } 163 164 /** 165 * @return the field name 166 */ getFieldName()167 public StringIdItem getFieldName() { 168 return fieldName; 169 } 170 171 String cachedFieldString = null; 172 /** 173 * @return a string formatted like LclassName;->fieldName:fieldType 174 */ getFieldString()175 public String getFieldString() { 176 if (cachedFieldString == null) { 177 String typeDescriptor = classType.getTypeDescriptor(); 178 String fieldName = this.fieldName.getStringValue(); 179 String fieldType = this.fieldType.getTypeDescriptor(); 180 181 StringBuffer sb = new StringBuffer(typeDescriptor.length() + fieldName.length() + fieldType.length() + 3); 182 sb.append(typeDescriptor); 183 sb.append("->"); 184 sb.append(fieldName); 185 sb.append(":"); 186 sb.append(fieldType); 187 cachedFieldString = sb.toString(); 188 } 189 return cachedFieldString; 190 } 191 192 /** 193 * calculate and cache the hashcode 194 */ calcHashCode()195 private void calcHashCode() { 196 hashCode = classType.hashCode(); 197 hashCode = 31 * hashCode + fieldType.hashCode(); 198 hashCode = 31 * hashCode + fieldName.hashCode(); 199 } 200 201 @Override hashCode()202 public int hashCode() { 203 //there's a small possibility that the actual hash code will be 0. If so, we'll 204 //just end up recalculating it each time 205 if (hashCode == 0) 206 calcHashCode(); 207 return hashCode; 208 } 209 210 @Override equals(Object o)211 public boolean equals(Object o) { 212 if (this==o) { 213 return true; 214 } 215 if (o==null || !this.getClass().equals(o.getClass())) { 216 return false; 217 } 218 219 //This assumes that the referenced items have been interned in both objects. 220 //This is a valid assumption because all outside code must use the static 221 //"getInterned..." style methods to make new items, and any item created 222 //internally is guaranteed to be interned 223 FieldIdItem other = (FieldIdItem)o; 224 return (classType == other.classType && 225 fieldType == other.fieldType && 226 fieldName == other.fieldName); 227 } 228 }