• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }