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.DataOutputStream;
20import java.io.IOException;
21import java.util.ArrayList;
22import java.util.Map;
23
24class ExceptionTableEntry {
25    int startPc;
26    int endPc;
27    int handlerPc;
28    int catchType;
29
30    ExceptionTableEntry(int start, int end, int handle, int type) {
31        startPc = start;
32        endPc = end;
33        handlerPc = handle;
34        catchType = type;
35    }
36}
37
38/**
39 * <code>exception_table[]</code> of <code>Code_attribute</code>.
40 */
41public class ExceptionTable implements Cloneable {
42    private ConstPool constPool;
43    private ArrayList entries;
44
45    /**
46     * Constructs an <code>exception_table[]</code>.
47     *
48     * @param cp        constant pool table.
49     */
50    public ExceptionTable(ConstPool cp) {
51        constPool = cp;
52        entries = new ArrayList();
53    }
54
55    ExceptionTable(ConstPool cp, DataInputStream in) throws IOException {
56        constPool = cp;
57        int length = in.readUnsignedShort();
58        ArrayList list = new ArrayList(length);
59        for (int i = 0; i < length; ++i) {
60            int start = in.readUnsignedShort();
61            int end = in.readUnsignedShort();
62            int handle = in.readUnsignedShort();
63            int type = in.readUnsignedShort();
64            list.add(new ExceptionTableEntry(start, end, handle, type));
65        }
66
67        entries = list;
68    }
69
70    /**
71     * Creates and returns a copy of this object.
72     * The constant pool object is shared between this object
73     * and the cloned object.
74     */
75    public Object clone() throws CloneNotSupportedException {
76        ExceptionTable r = (ExceptionTable)super.clone();
77        r.entries = new ArrayList(entries);
78        return r;
79    }
80
81    /**
82     * Returns <code>exception_table_length</code>, which is the number
83     * of entries in the <code>exception_table[]</code>.
84     */
85    public int size() {
86        return entries.size();
87    }
88
89    /**
90     * Returns <code>startPc</code> of the <i>n</i>-th entry.
91     *
92     * @param nth               the <i>n</i>-th (&gt;= 0).
93     */
94    public int startPc(int nth) {
95        ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth);
96        return e.startPc;
97    }
98
99    /**
100     * Sets <code>startPc</code> of the <i>n</i>-th entry.
101     *
102     * @param nth               the <i>n</i>-th (&gt;= 0).
103     * @param value             new value.
104     */
105    public void setStartPc(int nth, int value) {
106        ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth);
107        e.startPc = value;
108    }
109
110    /**
111     * Returns <code>endPc</code> of the <i>n</i>-th entry.
112     *
113     * @param nth               the <i>n</i>-th (&gt;= 0).
114     */
115    public int endPc(int nth) {
116        ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth);
117        return e.endPc;
118    }
119
120    /**
121     * Sets <code>endPc</code> of the <i>n</i>-th entry.
122     *
123     * @param nth               the <i>n</i>-th (&gt;= 0).
124     * @param value             new value.
125     */
126    public void setEndPc(int nth, int value) {
127        ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth);
128        e.endPc = value;
129    }
130
131    /**
132     * Returns <code>handlerPc</code> of the <i>n</i>-th entry.
133     *
134     * @param nth               the <i>n</i>-th (&gt;= 0).
135     */
136    public int handlerPc(int nth) {
137        ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth);
138        return e.handlerPc;
139    }
140
141    /**
142     * Sets <code>handlerPc</code> of the <i>n</i>-th entry.
143     *
144     * @param nth               the <i>n</i>-th (&gt;= 0).
145     * @param value             new value.
146     */
147    public void setHandlerPc(int nth, int value) {
148        ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth);
149        e.handlerPc = value;
150    }
151
152    /**
153     * Returns <code>catchType</code> of the <i>n</i>-th entry.
154     *
155     * @param nth               the <i>n</i>-th (&gt;= 0).
156     * @return an index into the <code>constant_pool</code> table,
157     *          or zero if this exception handler is for all exceptions.
158     */
159    public int catchType(int nth) {
160        ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth);
161        return e.catchType;
162    }
163
164    /**
165     * Sets <code>catchType</code> of the <i>n</i>-th entry.
166     *
167     * @param nth               the <i>n</i>-th (&gt;= 0).
168     * @param value             new value.
169     */
170    public void setCatchType(int nth, int value) {
171        ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth);
172        e.catchType = value;
173    }
174
175    /**
176     * Copies the given exception table at the specified position
177     * in the table.
178     *
179     * @param index     index (&gt;= 0) at which the entry is to be inserted.
180     * @param offset    the offset added to the code position.
181     */
182    public void add(int index, ExceptionTable table, int offset) {
183        int len = table.size();
184        while (--len >= 0) {
185            ExceptionTableEntry e
186                = (ExceptionTableEntry)table.entries.get(len);
187            add(index, e.startPc + offset, e.endPc + offset,
188                e.handlerPc + offset, e.catchType);
189        }
190    }
191
192    /**
193     * Adds a new entry at the specified position in the table.
194     *
195     * @param index     index (&gt;= 0) at which the entry is to be inserted.
196     * @param start     <code>startPc</code>
197     * @param end       <code>endPc</code>
198     * @param handler   <code>handlerPc</code>
199     * @param type      <code>catchType</code>
200     */
201    public void add(int index, int start, int end, int handler, int type) {
202        if (start < end)
203            entries.add(index,
204                    new ExceptionTableEntry(start, end, handler, type));
205    }
206
207    /**
208     * Appends a new entry at the end of the table.
209     *
210     * @param start     <code>startPc</code>
211     * @param end       <code>endPc</code>
212     * @param handler   <code>handlerPc</code>
213     * @param type      <code>catchType</code>
214     */
215    public void add(int start, int end, int handler, int type) {
216        if (start < end)
217            entries.add(new ExceptionTableEntry(start, end, handler, type));
218    }
219
220    /**
221     * Removes the entry at the specified position in the table.
222     *
223     * @param index     the index of the removed entry.
224     */
225    public void remove(int index) {
226        entries.remove(index);
227    }
228
229    /**
230     * Makes a copy of this <code>exception_table[]</code>.
231     * Class names are replaced according to the
232     * given <code>Map</code> object.
233     *
234     * @param newCp     the constant pool table used by the new copy.
235     * @param classnames        pairs of replaced and substituted
236     *                          class names.
237     */
238    public ExceptionTable copy(ConstPool newCp, Map classnames) {
239        ExceptionTable et = new ExceptionTable(newCp);
240        ConstPool srcCp = constPool;
241        int len = size();
242        for (int i = 0; i < len; ++i) {
243            ExceptionTableEntry e = (ExceptionTableEntry)entries.get(i);
244            int type = srcCp.copy(e.catchType, newCp, classnames);
245            et.add(e.startPc, e.endPc, e.handlerPc, type);
246        }
247
248        return et;
249    }
250
251    void shiftPc(int where, int gapLength, boolean exclusive) {
252        int len = size();
253        for (int i = 0; i < len; ++i) {
254            ExceptionTableEntry e = (ExceptionTableEntry)entries.get(i);
255            e.startPc = shiftPc(e.startPc, where, gapLength, exclusive);
256            e.endPc = shiftPc(e.endPc, where, gapLength, exclusive);
257            e.handlerPc = shiftPc(e.handlerPc, where, gapLength, exclusive);
258        }
259    }
260
261    private static int shiftPc(int pc, int where, int gapLength,
262                               boolean exclusive) {
263        if (pc > where || (exclusive && pc == where))
264            pc += gapLength;
265
266        return pc;
267    }
268
269    void write(DataOutputStream out) throws IOException {
270        int len = size();
271        out.writeShort(len);            // exception_table_length
272        for (int i = 0; i < len; ++i) {
273            ExceptionTableEntry e = (ExceptionTableEntry)entries.get(i);
274            out.writeShort(e.startPc);
275            out.writeShort(e.endPc);
276            out.writeShort(e.handlerPc);
277            out.writeShort(e.catchType);
278        }
279    }
280}
281