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
29package org.jf.dexlib;
30
31import org.jf.dexlib.Util.AnnotatedOutput;
32import org.jf.dexlib.Util.Input;
33import org.jf.dexlib.Util.Utf8Utils;
34
35public class StringIdItem extends Item<StringIdItem> {
36    private StringDataItem stringDataItem;
37
38   /**
39     * Creates a new uninitialized <code>StringIdItem</code>
40     * @param dexFile The <code>DexFile</code> that this item belongs to
41     */
42    protected StringIdItem(DexFile dexFile) {
43        super(dexFile);
44    }
45
46    /**
47     * Creates a new <code>StringIdItem</code> for the given <code>StringDataItem</code>
48     * @param dexFile The <code>DexFile</code> that this item belongs to
49     * @param stringDataItem The <code>StringDataItem</code> that this <code>StringIdItem</code> represents
50     */
51    protected StringIdItem(DexFile dexFile, StringDataItem stringDataItem) {
52        super(dexFile);
53        this.stringDataItem = stringDataItem;
54    }
55
56    /**
57     * Returns a <code>StringIdItem</code> for the given values, and that has been interned into
58     * the given <code>DexFile</code>
59     * @param dexFile The <code>DexFile</code> that this item will belong to
60     * @param stringValue The string value that this item represents
61     * @return a <code>StringIdItem</code> for the given values, and that has been interned into
62     * the given <code>DexFile</code>
63     */
64    public static StringIdItem internStringIdItem(DexFile dexFile, String stringValue) {
65        StringDataItem stringDataItem = StringDataItem.internStringDataItem(dexFile, stringValue);
66        if (stringDataItem == null) {
67            return null;
68        }
69        StringIdItem stringIdItem = new StringIdItem(dexFile, stringDataItem);
70        return dexFile.StringIdsSection.intern(stringIdItem);
71    }
72
73    /**
74     * Looks up the <code>StringIdItem</code> from the given <code>DexFile</code> for the given
75     * string value
76     * @param dexFile the <code>Dexfile</code> to find the string value in
77     * @param stringValue The string value to look up
78     * @return a <code>StringIdItem</code> from the given <code>DexFile</code> for the given
79     * string value, or null if it doesn't exist
80     */
81    public static StringIdItem lookupStringIdItem(DexFile dexFile, String stringValue) {
82        StringDataItem stringDataItem = StringDataItem.lookupStringDataItem(dexFile, stringValue);
83        if (stringDataItem == null) {
84            return null;
85        }
86        StringIdItem stringIdItem = new StringIdItem(dexFile, stringDataItem);
87        return dexFile.StringIdsSection.getInternedItem(stringIdItem);
88    }
89
90    /** {@inheritDoc} */
91    protected void readItem(Input in, ReadContext readContext) {
92        int stringDataOffset = in.readInt();
93
94        stringDataItem = (StringDataItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_STRING_DATA_ITEM,
95                stringDataOffset);
96    }
97
98    /** {@inheritDoc} */
99    protected int placeItem(int offset) {
100        return offset + 4;
101    }
102
103    /** {@inheritDoc} */
104    protected void writeItem(AnnotatedOutput out) {
105        if (out.annotates()) {
106            out.annotate(4, stringDataItem.getConciseIdentity());
107        }
108
109        out.writeInt(stringDataItem.getOffset());
110    }
111
112    /** {@inheritDoc} */
113    public ItemType getItemType() {
114        return ItemType.TYPE_STRING_ID_ITEM;
115    }
116
117    /** {@inheritDoc} */
118    public String getConciseIdentity() {
119        return "string_id_item: " + Utf8Utils.escapeString(getStringValue());
120    }
121
122    /** {@inheritDoc} */
123    public int compareTo(StringIdItem o) {
124        //sort by the string value
125        return getStringValue().compareTo(o.getStringValue());
126    }
127
128    /**
129     * Get the <code>String</code> value that this <code>StringIdItem</code> represents
130     * @return the <code>String</code> value that this <code>StringIdItem</code> represents
131     */
132    public String getStringValue() {
133        return stringDataItem.getStringValue();
134    }
135
136    /**
137     * Get the <code>StringDataItem</code> that this <code>StringIdItem</code> references
138     * @return the <code>StringDataItem</code> that this <code>StringIdItem</code> references
139     */
140    public StringDataItem getStringDataItem() {
141        return stringDataItem;
142    }
143
144    @Override
145    public int hashCode() {
146        return stringDataItem.hashCode();
147    }
148
149    @Override
150    public boolean equals(Object o) {
151        if (this==o) {
152            return true;
153        }
154        if (o==null || !this.getClass().equals(o.getClass())) {
155            return false;
156        }
157
158        //This assumes that the referenced items have been interned in both objects.
159        //This is a valid assumption because all outside code must use the static
160        //"getInterned..." style methods to make new items, and any item created
161        //internally is guaranteed to be interned
162        StringIdItem other = (StringIdItem)o;
163        return stringDataItem == other.stringDataItem;
164    }
165}
166