TypeListItem.java revision 4d68e05fb5e3262c58bc9896befe910698daa6a8
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.Input; 32import org.jf.dexlib.Util.AnnotatedOutput; 33import org.jf.dexlib.Util.ReadOnlyArrayList; 34 35import java.util.List; 36 37public class TypeListItem extends Item<TypeListItem> { 38 private int hashCode = 0; 39 40 private TypeIdItem[] typeList; 41 42 /** 43 * Creates a new uninitialized <code>TypeListItem</code> 44 * @param dexFile The <code>DexFile</code> that this item belongs to 45 */ 46 protected TypeListItem(DexFile dexFile) { 47 super(dexFile); 48 } 49 50 /** 51 * Creates a new <code>TypeListItem</code> for the given string 52 * @param dexFile The <code>DexFile</code> that this item belongs to 53 * @param typeList A list of the types that this <code>TypeListItem</code> represents 54 */ 55 private TypeListItem(DexFile dexFile, List<TypeIdItem> typeList) { 56 super(dexFile); 57 58 this.typeList = new TypeIdItem[typeList.size()]; 59 typeList.toArray(this.typeList); 60 } 61 62 /** 63 * Returns a <code>TypeListItem</code> for the given values, and that has been interned into 64 * the given <code>DexFile</code> 65 * @param dexFile The <code>DexFile</code> that this item belongs to 66 * @param typeList A list of the types that this <code>TypeListItem</code> represents 67 * @return a <code>TypeListItem</code> for the given values, and that has been interned into 68 * the given <code>DexFile</code> 69 */ 70 public static TypeListItem getInternedTypeListItem(DexFile dexFile, List<TypeIdItem> typeList) { 71 TypeListItem typeListItem = new TypeListItem(dexFile, typeList); 72 return dexFile.TypeListsSection.intern(typeListItem); 73 } 74 75 /** {@inheritDoc} */ 76 protected void readItem(Input in, ReadContext readContext) { 77 int size = in.readInt(); 78 typeList = new TypeIdItem[size]; 79 for (int i=0; i<size; i++) { 80 int typeIndex = in.readShort(); 81 typeList[i] = dexFile.TypeIdsSection.getItemByIndex(typeIndex); 82 } 83 } 84 85 /** {@inheritDoc} */ 86 protected int placeItem(int offset) { 87 return offset + 4 + typeList.length * 2; 88 } 89 90 /** {@inheritDoc} */ 91 protected void writeItem(AnnotatedOutput out) { 92 //yes, the code to write the item is duplicated. This eliminates the need to iterate over the list twice 93 94 if (out.annotates()) { 95 out.annotate(4, "size: 0x" + Integer.toHexString(typeList.length) + " (" + typeList.length +")"); 96 97 for (TypeIdItem typeIdItem: typeList) { 98 out.annotate(2, "type_id_item: " + typeIdItem.getTypeDescriptor()); 99 } 100 } 101 out.writeInt(typeList.length); 102 for (TypeIdItem typeIdItem: typeList) { 103 out.writeShort(typeIdItem.getIndex()); 104 } 105 } 106 107 /** {@inheritDoc} */ 108 public ItemType getItemType() { 109 return ItemType.TYPE_TYPE_LIST; 110 } 111 112 /** {@inheritDoc} */ 113 public String getConciseIdentity() { 114 return "type_list: " + getTypeListString(""); 115 } 116 117 /** {@inheritDoc} */ 118 public int compareTo(TypeListItem o) { 119 if (o == null) { 120 return 1; 121 } 122 123 int thisSize = typeList.length; 124 int otherSize = o.typeList.length; 125 int size = Math.min(thisSize, otherSize); 126 127 for (int i = 0; i < size; i++) { 128 int result = typeList[i].compareTo(o.typeList[i]); 129 if (result != 0) { 130 return result; 131 } 132 } 133 134 if (thisSize < otherSize) { 135 return -1; 136 } else if (thisSize > otherSize) { 137 return 1; 138 } else { 139 return 0; 140 } 141 } 142 143 /** 144 * @return the number of registers required for this <code>TypeListItem</code> 145 */ 146 public int getRegisterCount() { 147 int wordCount = 0; 148 for (TypeIdItem typeIdItem: typeList) { 149 wordCount += typeIdItem.getRegisterCount(); 150 } 151 return wordCount; 152 } 153 154 /** 155 * @return a string consisting of the type descriptors in this <code>TypeListItem</code> 156 * that are separated by the given separator 157 * @param separator the separator between each type 158 */ 159 public String getTypeListString(String separator) { 160 int size = 0; 161 for (TypeIdItem typeIdItem: typeList) { 162 size += typeIdItem.getTypeDescriptor().length(); 163 size += separator.length(); 164 } 165 166 StringBuilder sb = new StringBuilder(size); 167 for (TypeIdItem typeIdItem: typeList) { 168 sb.append(typeIdItem.getTypeDescriptor()); 169 sb.append(separator); 170 } 171 if (typeList.length > 0) { 172 sb.delete(sb.length() - separator.length(), sb.length()); 173 } 174 return sb.toString(); 175 } 176 177 /** 178 * @return a string consisting of the shorty form of the type descriptors in this 179 * <code>TypeListItem</code> that are directly concatenated together 180 */ 181 public String getShortyString() { 182 StringBuilder sb = new StringBuilder(); 183 for (TypeIdItem typeIdItem: typeList) { 184 sb.append(typeIdItem.toShorty()); 185 } 186 return sb.toString(); 187 } 188 189 /** 190 * @param index the index of the <code>TypeIdItem</code> to get 191 * @return the <code>TypeIdItem</code> at the given index 192 */ 193 public TypeIdItem getTypeIdItem(int index) { 194 return typeList[index]; 195 } 196 197 /** 198 * @return the number of types in this <code>TypeListItem</code> 199 */ 200 public int getTypeCount() { 201 return typeList.length; 202 } 203 204 /** 205 * @return an array of the <code>TypeIdItems</code> in this <code>TypeListItem</code> 206 */ 207 public List<TypeIdItem> getTypes() { 208 return new ReadOnlyArrayList<TypeIdItem>(typeList); 209 } 210 211 /** 212 * calculate and cache the hashcode 213 */ 214 private void calcHashCode() { 215 int hashCode = 1; 216 217 for (TypeIdItem typeIdItem: typeList) { 218 hashCode = 31 * hashCode + typeIdItem.hashCode(); 219 } 220 this.hashCode = hashCode; 221 } 222 223 @Override 224 public int hashCode() { 225 //there's a small possibility that the actual hash code will be 0. If so, we'll 226 //just end up recalculating it each time 227 if (hashCode == 0) 228 calcHashCode(); 229 return hashCode; 230 } 231 232 @Override 233 public boolean equals(Object o) { 234 if (this==o) { 235 return true; 236 } 237 if (o==null || !this.getClass().equals(o.getClass())) { 238 return false; 239 } 240 241 //This assumes that the referenced items have been interned in both objects. 242 //This is a valid assumption because all outside code must use the static 243 //"getInterned..." style methods to make new items, and any item created 244 //internally is guaranteed to be interned 245 TypeListItem other = (TypeListItem)o; 246 if (typeList.length != other.typeList.length) { 247 return false; 248 } 249 250 for (int i=0; i<typeList.length; i++) { 251 if (typeList[i] != other.typeList[i]) { 252 return false; 253 } 254 } 255 return true; 256 } 257} 258