1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dx.dex.file;
18
19import com.android.dx.rop.annotation.Annotation;
20import com.android.dx.rop.annotation.Annotations;
21import com.android.dx.util.AnnotatedOutput;
22import com.android.dx.util.Hex;
23
24/**
25 * Set of annotations, where no annotation type appears more than once.
26 */
27public final class AnnotationSetItem extends OffsettedItem {
28    /** the required alignment for instances of this class */
29    private static final int ALIGNMENT = 4;
30
31    /** the size of an entry int the set: one {@code uint} */
32    private static final int ENTRY_WRITE_SIZE = 4;
33
34    /** {@code non-null;} the set of annotations */
35    private final Annotations annotations;
36
37    /**
38     * {@code non-null;} set of annotations as individual items in an array.
39     * <b>Note:</b> The contents have to get sorted by type id before
40     * writing.
41     */
42    private final AnnotationItem[] items;
43
44    /**
45     * Constructs an instance.
46     *
47     * @param annotations {@code non-null;} set of annotations
48     * @param dexFile {@code non-null;} dex output
49     */
50    public AnnotationSetItem(Annotations annotations, DexFile dexFile) {
51        super(ALIGNMENT, writeSize(annotations));
52
53        this.annotations = annotations;
54        this.items = new AnnotationItem[annotations.size()];
55
56        int at = 0;
57        for (Annotation a : annotations.getAnnotations()) {
58            items[at] = new AnnotationItem(a, dexFile);
59            at++;
60        }
61    }
62
63    /**
64     * Gets the write size for the given set.
65     *
66     * @param annotations {@code non-null;} the set
67     * @return {@code > 0;} the write size
68     */
69    private static int writeSize(Annotations annotations) {
70        // This includes an int size at the start of the list.
71
72        try {
73            return (annotations.size() * ENTRY_WRITE_SIZE) + 4;
74        } catch (NullPointerException ex) {
75            // Elucidate the exception.
76            throw new NullPointerException("list == null");
77        }
78    }
79
80    /**
81     * Gets the underlying annotations of this instance
82     *
83     * @return {@code non-null;} the annotations
84     */
85    public Annotations getAnnotations() {
86        return annotations;
87    }
88
89    /** {@inheritDoc} */
90    @Override
91    public int hashCode() {
92        return annotations.hashCode();
93    }
94
95    /** {@inheritDoc} */
96    @Override
97    protected int compareTo0(OffsettedItem other) {
98        AnnotationSetItem otherSet = (AnnotationSetItem) other;
99
100        return annotations.compareTo(otherSet.annotations);
101    }
102
103    /** {@inheritDoc} */
104    @Override
105    public ItemType itemType() {
106        return ItemType.TYPE_ANNOTATION_SET_ITEM;
107    }
108
109    /** {@inheritDoc} */
110    @Override
111    public String toHuman() {
112        return annotations.toString();
113    }
114
115    /** {@inheritDoc} */
116    @Override
117    public void addContents(DexFile file) {
118        MixedItemSection byteData = file.getByteData();
119        int size = items.length;
120
121        for (int i = 0; i < size; i++) {
122            items[i] = byteData.intern(items[i]);
123        }
124    }
125
126    /** {@inheritDoc} */
127    @Override
128    protected void place0(Section addedTo, int offset) {
129        // Sort the array to be in type id index order.
130        AnnotationItem.sortByTypeIdIndex(items);
131    }
132
133    /** {@inheritDoc} */
134    @Override
135    protected void writeTo0(DexFile file, AnnotatedOutput out) {
136        boolean annotates = out.annotates();
137        int size = items.length;
138
139        if (annotates) {
140            out.annotate(0, offsetString() + " annotation set");
141            out.annotate(4, "  size: " + Hex.u4(size));
142        }
143
144        out.writeInt(size);
145
146        for (int i = 0; i < size; i++) {
147            AnnotationItem item = items[i];
148            int offset = item.getAbsoluteOffset();
149
150            if (annotates) {
151                out.annotate(4, "  entries[" + Integer.toHexString(i) + "]: " +
152                        Hex.u4(offset));
153                items[i].annotateTo(out, "    ");
154            }
155
156            out.writeInt(offset);
157        }
158    }
159}
160