AnnotationSetItem.java revision 00fc68adf2e39aeb9fed35293f2576bbe729ec4b
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.Input;
32import org.jf.dexlib.Util.AnnotatedOutput;
33
34import java.util.List;
35
36public class AnnotationSetItem extends Item<AnnotationSetItem> {
37    private int hashCode = 0;
38
39    private AnnotationItem[] annotations;
40
41    /**
42     * Creates a new uninitialized <code>AnnotationSetItem</code>
43     * @param dexFile The <code>DexFile</code> that this item belongs to
44     */
45    protected AnnotationSetItem(DexFile dexFile) {
46        super(dexFile);
47    }
48
49    /**
50     * Creates a new <code>AnnotationSetItem</code> for the given annotations
51     * @param dexFile The <code>DexFile</code> that this item belongs to
52     * @param annotations The annotations for this <code>AnnotationSetItem</code>
53     */
54    private AnnotationSetItem(DexFile dexFile, AnnotationItem[] annotations) {
55        super(dexFile);
56        this.annotations = annotations;
57    }
58
59    /**
60     * Returns an <code>AnnotationSetItem</code> for the given annotations, and that has been interned into the given
61     * <code>DexFile</code>
62     * @param dexFile The <code>DexFile</code> that this item belongs to
63     * @param annotations The annotations for this <code>AnnotationSetItem</code>
64     * @return an <code>AnnotationSetItem</code> for the given annotations
65     */
66    public static AnnotationSetItem internAnnotationSetItem(DexFile dexFile, List<AnnotationItem> annotations) {
67        AnnotationItem[] annotationsArray = new AnnotationItem[annotations.size()];
68        annotations.toArray(annotationsArray);
69        AnnotationSetItem annotationSetItem = new AnnotationSetItem(dexFile, annotationsArray);
70        return dexFile.AnnotationSetsSection.intern(annotationSetItem);
71    }
72
73    /** {@inheritDoc} */
74    protected void readItem(Input in, ReadContext readContext) {
75        annotations = new AnnotationItem[in.readInt()];
76
77        for (int i=0; i<annotations.length; i++) {
78            annotations[i] = (AnnotationItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_ANNOTATION_ITEM,
79                    in.readInt());
80        }
81    }
82
83    /** {@inheritDoc} */
84    protected int placeItem(int offset) {
85        return offset + 4 + annotations.length * 4;
86    }
87
88    /** {@inheritDoc} */
89    protected void writeItem(AnnotatedOutput out) {
90        if (out.annotates()) {
91            out.annotate(4, "size: 0x" + Integer.toHexString(annotations.length) + " (" + annotations.length + ")");
92            for (AnnotationItem annotationItem: annotations) {
93                out.annotate(4, "annotation_off: 0x" + Integer.toHexString(annotationItem.getOffset()) + " - " +
94                        annotationItem.getEncodedAnnotation().annotationType.getTypeDescriptor());
95            }
96        }
97        out.writeInt(annotations.length);
98        for (AnnotationItem annotationItem: annotations) {
99            out.writeInt(annotationItem.getOffset());
100        }
101    }
102
103    /** {@inheritDoc} */
104    public ItemType getItemType() {
105        return ItemType.TYPE_ANNOTATION_SET_ITEM;
106    }
107
108    /** {@inheritDoc} */
109    public String getConciseIdentity() {
110        return "annotation_set_item @0x" + Integer.toHexString(getOffset());
111    }
112
113/** {@inheritDoc} */
114    public int compareTo(AnnotationSetItem o) {
115        if (o == null) {
116            return 1;
117        }
118
119        int comp = annotations.length - o.annotations.length;
120        if (comp == 0) {
121            for (int i=0; i<annotations.length; i++) {
122                comp = annotations[i].compareTo(o.annotations[i]);
123                if (comp != 0) {
124                    return comp;
125                }
126            }
127        }
128        return comp;
129    }
130
131    /**
132     * @return An array of the <code>AnnotationItem</code> objects in this <code>AnnotationSetItem</code>
133     */
134    public AnnotationItem[] getAnnotations() {
135        return annotations;
136    }
137
138    /**
139     * calculate and cache the hashcode
140     */
141    private void calcHashCode() {
142        hashCode = 0;
143        for (AnnotationItem annotationItem: annotations) {
144            hashCode = hashCode * 31 + annotationItem.hashCode();
145        }
146    }
147
148    @Override
149    public int hashCode() {
150        //there's a small possibility that the actual hash code will be 0. If so, we'll
151        //just end up recalculating it each time
152        if (hashCode == 0)
153            calcHashCode();
154        return hashCode;
155    }
156
157    @Override
158    public boolean equals(Object o) {
159        if (this==o) {
160            return true;
161        }
162        if (o==null || !this.getClass().equals(o.getClass())) {
163            return false;
164        }
165
166        AnnotationSetItem other = (AnnotationSetItem)o;
167        return (this.compareTo(other) == 0);
168    }
169}
170