1/*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License.  Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16package javassist.bytecode;
17
18import java.io.DataInputStream;
19import java.io.IOException;
20import java.util.Map;
21
22/**
23 * <code>Exceptions_attribute</code>.
24 */
25public class ExceptionsAttribute extends AttributeInfo {
26    /**
27     * The name of this attribute <code>"Exceptions"</code>.
28     */
29    public static final String tag = "Exceptions";
30
31    ExceptionsAttribute(ConstPool cp, int n, DataInputStream in)
32        throws IOException
33    {
34        super(cp, n, in);
35    }
36
37    /**
38     * Constructs a copy of an exceptions attribute.
39     *
40     * @param cp                constant pool table.
41     * @param src               source attribute.
42     */
43    private ExceptionsAttribute(ConstPool cp, ExceptionsAttribute src,
44                                Map classnames) {
45        super(cp, tag);
46        copyFrom(src, classnames);
47    }
48
49    /**
50     * Constructs a new exceptions attribute.
51     *
52     * @param cp                constant pool table.
53     */
54    public ExceptionsAttribute(ConstPool cp) {
55        super(cp, tag);
56        byte[] data = new byte[2];
57        data[0] = data[1] = 0;  // empty
58        this.info = data;
59    }
60
61    /**
62     * Makes a copy.  Class names are replaced according to the
63     * given <code>Map</code> object.
64     *
65     * @param newCp     the constant pool table used by the new copy.
66     * @param classnames        pairs of replaced and substituted
67     *                          class names.  It can be <code>null</code>.
68     */
69    public AttributeInfo copy(ConstPool newCp, Map classnames) {
70        return new ExceptionsAttribute(newCp, this, classnames);
71    }
72
73    /**
74     * Copies the contents from a source attribute.
75     * Specified class names are replaced during the copy.
76     *
77     * @param srcAttr           source Exceptions attribute
78     * @param classnames        pairs of replaced and substituted
79     *                          class names.
80     */
81    private void copyFrom(ExceptionsAttribute srcAttr, Map classnames) {
82        ConstPool srcCp = srcAttr.constPool;
83        ConstPool destCp = this.constPool;
84        byte[] src = srcAttr.info;
85        int num = src.length;
86        byte[] dest = new byte[num];
87        dest[0] = src[0];
88        dest[1] = src[1];       // the number of elements.
89        for (int i = 2; i < num; i += 2) {
90            int index = ByteArray.readU16bit(src, i);
91            ByteArray.write16bit(srcCp.copy(index, destCp, classnames),
92                                 dest, i);
93        }
94
95        this.info = dest;
96    }
97
98    /**
99     * Returns <code>exception_index_table[]</code>.
100     */
101    public int[] getExceptionIndexes() {
102        byte[] blist = info;
103        int n = blist.length;
104        if (n <= 2)
105            return null;
106
107        int[] elist = new int[n / 2 - 1];
108        int k = 0;
109        for (int j = 2; j < n; j += 2)
110            elist[k++] = ((blist[j] & 0xff) << 8) | (blist[j + 1] & 0xff);
111
112        return elist;
113    }
114
115    /**
116     * Returns the names of exceptions that the method may throw.
117     */
118    public String[] getExceptions() {
119        byte[] blist = info;
120        int n = blist.length;
121        if (n <= 2)
122            return null;
123
124        String[] elist = new String[n / 2 - 1];
125        int k = 0;
126        for (int j = 2; j < n; j += 2) {
127            int index = ((blist[j] & 0xff) << 8) | (blist[j + 1] & 0xff);
128            elist[k++] = constPool.getClassInfo(index);
129        }
130
131        return elist;
132    }
133
134    /**
135     * Sets <code>exception_index_table[]</code>.
136     */
137    public void setExceptionIndexes(int[] elist) {
138        int n = elist.length;
139        byte[] blist = new byte[n * 2 + 2];
140        ByteArray.write16bit(n, blist, 0);
141        for (int i = 0; i < n; ++i)
142            ByteArray.write16bit(elist[i], blist, i * 2 + 2);
143
144        info = blist;
145    }
146
147    /**
148     * Sets the names of exceptions that the method may throw.
149     */
150    public void setExceptions(String[] elist) {
151        int n = elist.length;
152        byte[] blist = new byte[n * 2 + 2];
153        ByteArray.write16bit(n, blist, 0);
154        for (int i = 0; i < n; ++i)
155            ByteArray.write16bit(constPool.addClassInfo(elist[i]),
156                                 blist, i * 2 + 2);
157
158        info = blist;
159    }
160
161    /**
162     * Returns <code>number_of_exceptions</code>.
163     */
164    public int tableLength() { return info.length / 2 - 1; }
165
166    /**
167     * Returns the value of <code>exception_index_table[nth]</code>.
168     */
169    public int getException(int nth) {
170        int index = nth * 2 + 2;        // nth >= 0
171        return ((info[index] & 0xff) << 8) | (info[index + 1] & 0xff);
172    }
173}
174