1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2008 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.dex.file;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.annotation.Annotation;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.annotation.AnnotationVisibility;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.annotation.NameValuePair;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.Constant;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstString;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.ByteArrayAnnotatedOutput;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.AnnotatedOutput;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Arrays;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Comparator;
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Single annotation, which consists of a type and a set of name-value
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * element pairs.
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class AnnotationItem extends OffsettedItem {
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** annotation visibility constant: visible at build time only */
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static final int VISIBILITY_BUILD = 0;
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** annotation visibility constant: visible at runtime */
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static final int VISIBILITY_RUNTIME = 1;
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** annotation visibility constant: visible at runtime only to system */
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static final int VISIBILITY_SYSTEM = 2;
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** the required alignment for instances of this class */
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static final int ALIGNMENT = 1;
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} unique instance of {@link #TypeIdSorter} */
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static final TypeIdSorter TYPE_ID_SORTER = new TypeIdSorter();
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} the annotation to represent */
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final Annotation annotation;
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code null-ok;} type reference for the annotation type; set during
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@link #addContents}
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private TypeIdItem type;
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code null-ok;} encoded form, ready for writing to a file; set during
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@link #place0}
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private byte[] encodedForm;
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Comparator that sorts (outer) instances by type id index.
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static class TypeIdSorter implements Comparator<AnnotationItem> {
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int compare(AnnotationItem item1, AnnotationItem item2) {
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int index1 = item1.type.getIndex();
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int index2 = item2.type.getIndex();
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (index1 < index2) {
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return -1;
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else if (index1 > index2) {
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return 1;
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return 0;
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Sorts an array of instances, in place, by type id index,
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * ignoring all other aspects of the elements. This is only valid
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * to use after type id indices are known.
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param array {@code non-null;} array to sort
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static void sortByTypeIdIndex(AnnotationItem[] array) {
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Arrays.sort(array, TYPE_ID_SORTER);
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an instance.
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param annotation {@code non-null;} annotation to represent
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public AnnotationItem(Annotation annotation) {
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * The write size isn't known up-front because (the variable-lengthed)
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * leb128 type is used to represent some things.
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        super(ALIGNMENT, -1);
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (annotation == null) {
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("annotation == null");
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.annotation = annotation;
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.type = null;
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.encodedForm = null;
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public ItemType itemType() {
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return ItemType.TYPE_ANNOTATION_ITEM;
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int hashCode() {
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return annotation.hashCode();
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected int compareTo0(OffsettedItem other) {
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        AnnotationItem otherAnnotation = (AnnotationItem) other;
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return annotation.compareTo(otherAnnotation.annotation);
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String toHuman() {
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return annotation.toHuman();
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void addContents(DexFile file) {
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        type = file.getTypeIds().intern(annotation.getType());
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ValueEncoder.addContents(file, annotation);
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected void place0(Section addedTo, int offset) {
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Encode the data and note the size.
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out);
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        encoder.writeAnnotation(annotation, false);
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        encodedForm = out.toByteArray();
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Add one for the visibility byte in front of the encoded annotation.
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        setWriteSize(encodedForm.length + 1);
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Write a (listing file) annotation for this instance to the given
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * output, that consumes no bytes of output. This is for annotating
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * a reference to this instance at the point of the reference.
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param out {@code non-null;} where to output to
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param prefix {@code non-null;} prefix for each line of output
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void annotateTo(AnnotatedOutput out, String prefix) {
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        out.annotate(0, prefix + "visibility: " +
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                annotation.getVisibility().toHuman());
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        out.annotate(0, prefix + "type: " + annotation.getType().toHuman());
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (NameValuePair pair : annotation.getNameValuePairs()) {
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CstString name = pair.getName();
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Constant value = pair.getValue();
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.annotate(0, prefix + name.toHuman() + ": " +
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    ValueEncoder.constantToHuman(value));
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected void writeTo0(DexFile file, AnnotatedOutput out) {
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean annotates = out.annotates();
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        AnnotationVisibility visibility = annotation.getVisibility();
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (annotates) {
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.annotate(0, offsetString() + " annotation");
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.annotate(1, "  visibility: VISBILITY_" + visibility);
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        switch (visibility) {
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            case BUILD:   out.writeByte(VISIBILITY_BUILD); break;
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            case RUNTIME: out.writeByte(VISIBILITY_RUNTIME); break;
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            case SYSTEM:  out.writeByte(VISIBILITY_SYSTEM); break;
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            default: {
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                // EMBEDDED shouldn't appear at the top level.
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new RuntimeException("shouldn't happen");
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (annotates) {
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * The output is to be annotated, so redo the work previously
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * done by place0(), except this time annotations will actually
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * get emitted.
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            ValueEncoder encoder = new ValueEncoder(file, out);
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            encoder.writeAnnotation(annotation, true);
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.write(encodedForm);
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
219