1/*
2 * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 * This file is available under and governed by the GNU General Public
28 * License version 2 only, as published by the Free Software Foundation.
29 * However, the following notice accompanied the original version of this
30 * file:
31 *
32 * ASM: a very small and fast Java bytecode manipulation framework
33 * Copyright (c) 2000-2007 INRIA, France Telecom
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 *    notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 *    notice, this list of conditions and the following disclaimer in the
43 *    documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the copyright holders nor the names of its
45 *    contributors may be used to endorse or promote products derived from
46 *    this software without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
49 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
52 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
58 * THE POSSIBILITY OF SUCH DAMAGE.
59 */
60package com.sun.xml.internal.ws.org.objectweb.asm;
61
62/**
63 * An {@link AnnotationVisitor} that generates annotations in bytecode form.
64 *
65 * @author Eric Bruneton
66 * @author Eugene Kuleshov
67 */
68final class AnnotationWriter implements AnnotationVisitor {
69
70    /**
71     * The class writer to which this annotation must be added.
72     */
73    private final ClassWriter cw;
74
75    /**
76     * The number of values in this annotation.
77     */
78    private int size;
79
80    /**
81     * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
82     * writers used for annotation default and annotation arrays use unnamed
83     * values.
84     */
85    private final boolean named;
86
87    /**
88     * The annotation values in bytecode form. This byte vector only contains
89     * the values themselves, i.e. the number of values must be stored as a
90     * unsigned short just before these bytes.
91     */
92    private final ByteVector bv;
93
94    /**
95     * The byte vector to be used to store the number of values of this
96     * annotation. See {@link #bv}.
97     */
98    private final ByteVector parent;
99
100    /**
101     * Where the number of values of this annotation must be stored in
102     * {@link #parent}.
103     */
104    private final int offset;
105
106    /**
107     * Next annotation writer. This field is used to store annotation lists.
108     */
109    AnnotationWriter next;
110
111    /**
112     * Previous annotation writer. This field is used to store annotation lists.
113     */
114    AnnotationWriter prev;
115
116    // ------------------------------------------------------------------------
117    // Constructor
118    // ------------------------------------------------------------------------
119
120    /**
121     * Constructs a new {@link AnnotationWriter}.
122     *
123     * @param cw the class writer to which this annotation must be added.
124     * @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise.
125     * @param bv where the annotation values must be stored.
126     * @param parent where the number of annotation values must be stored.
127     * @param offset where in <tt>parent</tt> the number of annotation values must
128     *      be stored.
129     */
130    AnnotationWriter(
131        final ClassWriter cw,
132        final boolean named,
133        final ByteVector bv,
134        final ByteVector parent,
135        final int offset)
136    {
137        this.cw = cw;
138        this.named = named;
139        this.bv = bv;
140        this.parent = parent;
141        this.offset = offset;
142    }
143
144    // ------------------------------------------------------------------------
145    // Implementation of the AnnotationVisitor interface
146    // ------------------------------------------------------------------------
147
148    public void visit(final String name, final Object value) {
149        ++size;
150        if (named) {
151            bv.putShort(cw.newUTF8(name));
152        }
153        if (value instanceof String) {
154            bv.put12('s', cw.newUTF8((String) value));
155        } else if (value instanceof Byte) {
156            bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
157        } else if (value instanceof Boolean) {
158            int v = ((Boolean) value).booleanValue() ? 1 : 0;
159            bv.put12('Z', cw.newInteger(v).index);
160        } else if (value instanceof Character) {
161            bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
162        } else if (value instanceof Short) {
163            bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
164        } else if (value instanceof Type) {
165            bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
166        } else if (value instanceof byte[]) {
167            byte[] v = (byte[]) value;
168            bv.put12('[', v.length);
169            for (int i = 0; i < v.length; i++) {
170                bv.put12('B', cw.newInteger(v[i]).index);
171            }
172        } else if (value instanceof boolean[]) {
173            boolean[] v = (boolean[]) value;
174            bv.put12('[', v.length);
175            for (int i = 0; i < v.length; i++) {
176                bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
177            }
178        } else if (value instanceof short[]) {
179            short[] v = (short[]) value;
180            bv.put12('[', v.length);
181            for (int i = 0; i < v.length; i++) {
182                bv.put12('S', cw.newInteger(v[i]).index);
183            }
184        } else if (value instanceof char[]) {
185            char[] v = (char[]) value;
186            bv.put12('[', v.length);
187            for (int i = 0; i < v.length; i++) {
188                bv.put12('C', cw.newInteger(v[i]).index);
189            }
190        } else if (value instanceof int[]) {
191            int[] v = (int[]) value;
192            bv.put12('[', v.length);
193            for (int i = 0; i < v.length; i++) {
194                bv.put12('I', cw.newInteger(v[i]).index);
195            }
196        } else if (value instanceof long[]) {
197            long[] v = (long[]) value;
198            bv.put12('[', v.length);
199            for (int i = 0; i < v.length; i++) {
200                bv.put12('J', cw.newLong(v[i]).index);
201            }
202        } else if (value instanceof float[]) {
203            float[] v = (float[]) value;
204            bv.put12('[', v.length);
205            for (int i = 0; i < v.length; i++) {
206                bv.put12('F', cw.newFloat(v[i]).index);
207            }
208        } else if (value instanceof double[]) {
209            double[] v = (double[]) value;
210            bv.put12('[', v.length);
211            for (int i = 0; i < v.length; i++) {
212                bv.put12('D', cw.newDouble(v[i]).index);
213            }
214        } else {
215            Item i = cw.newConstItem(value);
216            bv.put12(".s.IFJDCS".charAt(i.type), i.index);
217        }
218    }
219
220    public void visitEnum(
221        final String name,
222        final String desc,
223        final String value)
224    {
225        ++size;
226        if (named) {
227            bv.putShort(cw.newUTF8(name));
228        }
229        bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
230    }
231
232    public AnnotationVisitor visitAnnotation(
233        final String name,
234        final String desc)
235    {
236        ++size;
237        if (named) {
238            bv.putShort(cw.newUTF8(name));
239        }
240        // write tag and type, and reserve space for values count
241        bv.put12('@', cw.newUTF8(desc)).putShort(0);
242        return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
243    }
244
245    public AnnotationVisitor visitArray(final String name) {
246        ++size;
247        if (named) {
248            bv.putShort(cw.newUTF8(name));
249        }
250        // write tag, and reserve space for array size
251        bv.put12('[', 0);
252        return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
253    }
254
255    public void visitEnd() {
256        if (parent != null) {
257            byte[] data = parent.data;
258            data[offset] = (byte) (size >>> 8);
259            data[offset + 1] = (byte) size;
260        }
261    }
262
263    // ------------------------------------------------------------------------
264    // Utility methods
265    // ------------------------------------------------------------------------
266
267    /**
268     * Returns the size of this annotation writer list.
269     *
270     * @return the size of this annotation writer list.
271     */
272    int getSize() {
273        int size = 0;
274        AnnotationWriter aw = this;
275        while (aw != null) {
276            size += aw.bv.length;
277            aw = aw.next;
278        }
279        return size;
280    }
281
282    /**
283     * Puts the annotations of this annotation writer list into the given byte
284     * vector.
285     *
286     * @param out where the annotations must be put.
287     */
288    void put(final ByteVector out) {
289        int n = 0;
290        int size = 2;
291        AnnotationWriter aw = this;
292        AnnotationWriter last = null;
293        while (aw != null) {
294            ++n;
295            size += aw.bv.length;
296            aw.visitEnd(); // in case user forgot to call visitEnd
297            aw.prev = last;
298            last = aw;
299            aw = aw.next;
300        }
301        out.putInt(size);
302        out.putShort(n);
303        aw = last;
304        while (aw != null) {
305            out.putByteArray(aw.bv.data, 0, aw.bv.length);
306            aw = aw.prev;
307        }
308    }
309
310    /**
311     * Puts the given annotation lists into the given byte vector.
312     *
313     * @param panns an array of annotation writer lists.
314     * @param off index of the first annotation to be written.
315     * @param out where the annotations must be put.
316     */
317    static void put(
318        final AnnotationWriter[] panns,
319        final int off,
320        final ByteVector out)
321    {
322        int size = 1 + 2 * (panns.length - off);
323        for (int i = off; i < panns.length; ++i) {
324            size += panns[i] == null ? 0 : panns[i].getSize();
325        }
326        out.putInt(size).putByte(panns.length - off);
327        for (int i = off; i < panns.length; ++i) {
328            AnnotationWriter aw = panns[i];
329            AnnotationWriter last = null;
330            int n = 0;
331            while (aw != null) {
332                ++n;
333                aw.visitEnd(); // in case user forgot to call visitEnd
334                aw.prev = last;
335                last = aw;
336                aw = aw.next;
337            }
338            out.putShort(n);
339            aw = last;
340            while (aw != null) {
341                out.putByteArray(aw.bv.data, 0, aw.bv.length);
342                aw = aw.prev;
343            }
344        }
345    }
346}
347