ProtoIdItem.java revision 5867263eb588f4671400895d1e6b01c01535061b
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; 33 34public class ProtoIdItem extends Item<ProtoIdItem> { 35 private int hashCode = 0; 36 37 private StringIdItem shortyDescriptor; 38 private TypeIdItem returnType; 39 private TypeListItem parameters; 40 41 /** 42 * Creates a new uninitialized <code>ProtoIdItem</code> 43 * @param dexFile The <code>DexFile</code> that this item belongs to 44 */ 45 protected ProtoIdItem(DexFile dexFile) { 46 super(dexFile); 47 } 48 49 /** 50 * Creates a new <code>ProtoIdItem</code> with the given values 51 * @param dexFile The <code>DexFile</code> that this item belongs to 52 * @param returnType the return type 53 * @param parameters a <code>TypeListItem</code> containing a list of the parameter types 54 */ 55 private ProtoIdItem(DexFile dexFile, TypeIdItem returnType, TypeListItem parameters) { 56 this(dexFile); 57 58 String shortyString = returnType.toShorty(); 59 if (parameters != null) { 60 shortyString += parameters.getShortyString(); 61 } 62 this.shortyDescriptor = StringIdItem.getInternedStringIdItem(dexFile, shortyString); 63 this.returnType = returnType; 64 this.parameters = parameters; 65 } 66 67 /** 68 * Returns a <code>ProtoIdItem</code> for the given values, and that has been interned into 69 * the given <code>DexFile</code> 70 * @param dexFile The <code>DexFile</code> that this item belongs to 71 * @param returnType the return type 72 * @param parameters a <code>TypeListItem</code> containing a list of the parameter types 73 * @return a <code>ProtoIdItem</code> for the given values, and that has been interned into 74 * the given <code>DexFile</code> 75 */ 76 public static ProtoIdItem getInternedProtoIdItem(DexFile dexFile, TypeIdItem returnType, TypeListItem parameters) { 77 ProtoIdItem protoIdItem = new ProtoIdItem(dexFile, returnType, parameters); 78 return dexFile.ProtoIdsSection.intern(protoIdItem); 79 } 80 81 /** {@inheritDoc} */ 82 protected void readItem(Input in, ReadContext readContext) { 83 shortyDescriptor = dexFile.StringIdsSection.getItemByIndex(in.readInt()); 84 returnType = dexFile.TypeIdsSection.getItemByIndex(in.readInt()); 85 parameters = (TypeListItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_TYPE_LIST, in.readInt()); 86 } 87 88 /** {@inheritDoc} */ 89 protected int placeItem(int offset) { 90 return offset + 12; 91 } 92 93 /** {@inheritDoc} */ 94 protected void writeItem(AnnotatedOutput out) { 95 if (out.annotates()) { 96 out.annotate(4, "shorty_descriptor: " + shortyDescriptor.getStringValue()); 97 out.annotate(4, "return_type: " + returnType.getTypeDescriptor()); 98 99 if (parameters == null) { 100 out.annotate(4, "parameters:"); 101 } else { 102 out.annotate(4, "parameters: " + parameters.getTypeListString("")); 103 } 104 } 105 106 out.writeInt(shortyDescriptor.getIndex()); 107 out.writeInt(returnType.getIndex()); 108 out.writeInt(parameters == null?0:parameters.getOffset()); 109 } 110 111 /** {@inheritDoc} */ 112 public ItemType getItemType() { 113 return ItemType.TYPE_PROTO_ID_ITEM; 114 } 115 116 /** {@inheritDoc} */ 117 public int compareTo(ProtoIdItem o) { 118 int result = returnType.compareTo(o.returnType); 119 if (result != 0) { 120 return result; 121 } 122 123 if (parameters == null) { 124 if (o.parameters == null) { 125 return 0; 126 } 127 return -1; 128 } else if (o.parameters == null) { 129 return 1; 130 } 131 132 return parameters.compareTo(o.parameters); 133 } 134 135 /** {@inheritDoc} */ 136 public String getConciseIdentity() { 137 return "proto_id_item: " + getPrototypeString(); 138 } 139 140 private String cachedPrototypeString = null; 141 /** 142 * @return a string in the format (TTTT..)R where TTTT.. are the parameter types and R is the return type 143 */ 144 public String getPrototypeString() { 145 if (cachedPrototypeString == null) { 146 StringBuilder sb = new StringBuilder("("); 147 if (parameters != null) { 148 sb.append(parameters.getTypeListString("")); 149 } 150 sb.append(")"); 151 sb.append(returnType.getTypeDescriptor()); 152 153 cachedPrototypeString = sb.toString(); 154 } 155 return cachedPrototypeString; 156 } 157 158 /** 159 * @return the return type of the method 160 */ 161 public TypeIdItem getReturnType() { 162 return returnType; 163 } 164 165 /** 166 * @return a <code>TypeListItem</code> containing the method parameter types 167 */ 168 public TypeListItem getParameters() { 169 return parameters; 170 } 171 172 /** 173 * @return the number of registers required for the parameters of this <code>ProtoIdItem</code> 174 */ 175 public int getParameterRegisterCount() { 176 if (parameters == null) { 177 return 0; 178 } else { 179 return parameters.getRegisterCount(); 180 } 181 } 182 183 /** 184 * calculate and cache the hashcode 185 */ 186 private void calcHashCode() { 187 hashCode = returnType.hashCode(); 188 hashCode = 31 * hashCode + (parameters==null?0:parameters.hashCode()); 189 } 190 191 @Override 192 public int hashCode() { 193 //there's a small possibility that the actual hash code will be 0. If so, we'll 194 //just end up recalculating it each time 195 if (hashCode == 0) 196 calcHashCode(); 197 return hashCode; 198 } 199 200 @Override 201 public boolean equals(Object o) { 202 if (this==o) { 203 return true; 204 } 205 if (o==null || !this.getClass().equals(o.getClass())) { 206 return false; 207 } 208 209 //This assumes that the referenced items have been interned in both objects. 210 //This is a valid assumption because all outside code must use the static 211 //"getInterned..." style methods to make new items, and any item created 212 //internally is guaranteed to be interned 213 ProtoIdItem other = (ProtoIdItem)o; 214 return (returnType == other.returnType && 215 parameters == other.parameters); 216 } 217} 218