Home | History | Annotate | Download | only in dexlib
      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 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.internStringIdItem(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 internProtoIdItem(DexFile dexFile, TypeIdItem returnType, TypeListItem parameters) {
     77         ProtoIdItem protoIdItem = new ProtoIdItem(dexFile, returnType, parameters);
     78         return dexFile.ProtoIdsSection.intern(protoIdItem);
     79     }
     80 
     81     /**
     82      * Looks up the <code>ProtoIdItem</code> from the given <code>DexFile</code> for the given
     83      * values
     84      * @param dexFile the <code>Dexfile</code> to find the type in
     85      * @param returnType the return type
     86      * @param parameters a <code>TypeListItem</code> containing a list of the parameter types
     87      * @return a <code>ProtoIdItem</code> from the given <code>DexFile</code> for the given
     88      * values, or null if it doesn't exist
     89      */
     90     public static ProtoIdItem lookupProtoIdItem(DexFile dexFile, TypeIdItem returnType, TypeListItem parameters) {
     91         ProtoIdItem protoIdItem = new ProtoIdItem(dexFile, returnType, parameters);
     92         return dexFile.ProtoIdsSection.getInternedItem(protoIdItem);
     93     }
     94 
     95     /** {@inheritDoc} */
     96     protected void readItem(Input in, ReadContext readContext) {
     97         shortyDescriptor = dexFile.StringIdsSection.getItemByIndex(in.readInt());
     98         returnType = dexFile.TypeIdsSection.getItemByIndex(in.readInt());
     99         parameters = (TypeListItem)readContext.getOptionalOffsettedItemByOffset(ItemType.TYPE_TYPE_LIST, in.readInt());
    100     }
    101 
    102     /** {@inheritDoc} */
    103     protected int placeItem(int offset) {
    104         return offset + 12;
    105     }
    106 
    107     /** {@inheritDoc} */
    108     protected void writeItem(AnnotatedOutput out) {
    109         if (out.annotates()) {
    110             out.annotate(4, "shorty_descriptor: " + shortyDescriptor.getStringValue());
    111             out.annotate(4, "return_type: " + returnType.getTypeDescriptor());
    112 
    113             if (parameters == null) {
    114                 out.annotate(4, "parameters:");
    115             } else {
    116                 out.annotate(4, "parameters: " + parameters.getTypeListString(""));
    117             }
    118         }
    119 
    120         out.writeInt(shortyDescriptor.getIndex());
    121         out.writeInt(returnType.getIndex());
    122         out.writeInt(parameters == null?0:parameters.getOffset());
    123     }
    124 
    125     /** {@inheritDoc} */
    126     public ItemType getItemType() {
    127         return ItemType.TYPE_PROTO_ID_ITEM;
    128     }
    129 
    130     /** {@inheritDoc} */
    131     public int compareTo(ProtoIdItem o) {
    132         int result = returnType.compareTo(o.returnType);
    133         if (result != 0) {
    134             return result;
    135         }
    136 
    137         if (parameters == null) {
    138             if (o.parameters == null) {
    139                 return 0;
    140             }
    141             return -1;
    142         } else if (o.parameters == null) {
    143             return 1;
    144         }
    145 
    146         return parameters.compareTo(o.parameters);
    147     }
    148 
    149     /** {@inheritDoc} */
    150     public String getConciseIdentity() {
    151         return "proto_id_item: " + getPrototypeString();
    152     }
    153 
    154     private String cachedPrototypeString = null;
    155     /**
    156      * @return a string in the format (TTTT..)R where TTTT.. are the parameter types and R is the return type
    157      */
    158     public String getPrototypeString() {
    159         if (cachedPrototypeString == null) {
    160             StringBuilder sb = new StringBuilder("(");
    161             if (parameters != null) {
    162                 sb.append(parameters.getTypeListString(""));
    163             }
    164             sb.append(")");
    165             sb.append(returnType.getTypeDescriptor());
    166 
    167             cachedPrototypeString = sb.toString();
    168         }
    169         return cachedPrototypeString;
    170     }
    171 
    172     /**
    173      * @return the return type of the method
    174      */
    175     public TypeIdItem getReturnType() {
    176         return returnType;
    177     }
    178 
    179     /**
    180      * @return a <code>TypeListItem</code> containing the method parameter types
    181      */
    182     public TypeListItem getParameters() {
    183         return parameters;
    184     }
    185 
    186     /**
    187      * @return the number of registers required for the parameters of this <code>ProtoIdItem</code>
    188      */
    189     public int getParameterRegisterCount() {
    190         if (parameters == null) {
    191             return 0;
    192         } else {
    193             return parameters.getRegisterCount();
    194         }
    195     }
    196 
    197     /**
    198      * calculate and cache the hashcode
    199      */
    200     private void calcHashCode() {
    201         hashCode = returnType.hashCode();
    202         hashCode = 31 * hashCode + (parameters==null?0:parameters.hashCode());
    203     }
    204 
    205     @Override
    206     public int hashCode() {
    207         //there's a small possibility that the actual hash code will be 0. If so, we'll
    208         //just end up recalculating it each time
    209         if (hashCode == 0)
    210             calcHashCode();
    211         return hashCode;
    212     }
    213 
    214     @Override
    215     public boolean equals(Object o) {
    216         if (this==o) {
    217             return true;
    218         }
    219         if (o==null || !this.getClass().equals(o.getClass())) {
    220             return false;
    221         }
    222 
    223         //This assumes that the referenced items have been interned in both objects.
    224         //This is a valid assumption because all outside code must use the static
    225         //"getInterned..." style methods to make new items, and any item created
    226         //internally is guaranteed to be interned
    227         ProtoIdItem other = (ProtoIdItem)o;
    228         return (returnType == other.returnType &&
    229                 parameters == other.parameters);
    230     }
    231 }
    232