001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.bcel.classfile;
020
021import java.io.DataInput;
022import java.io.DataOutputStream;
023import java.io.IOException;
024
025import org.apache.bcel.Const;
026import org.apache.bcel.Constants;
027import org.apache.bcel.util.Args;
028
029/**
030 * This class represents an entry in the exception table of the <em>Code</em> attribute and is used only there. It
031 * contains a range in which a particular exception handler is active.
032 *
033 * <pre>
034 * Code_attribute {
035 *   u2 attribute_name_index;
036 *   u4 attribute_length;
037 *   u2 max_stack;
038 *   u2 max_locals;
039 *   u4 code_length;
040 *   u1 code[code_length];
041 *   u2 exception_table_length;
042 *   {
043 *     u2 start_pc;
044 *     u2 end_pc;
045 *     u2 handler_pc;
046 *     u2 catch_type;
047 *   } exception_table[exception_table_length];
048 *   u2 attributes_count;
049 *   attribute_info attributes[attributes_count];
050 * }
051 * </pre>
052 *
053 * @see Code
054 */
055public final class CodeException implements Cloneable, Node, Constants {
056
057    /**
058     * Empty array.
059     */
060    static final CodeException[] EMPTY_ARRAY = {};
061
062    /** Range in the code the exception handler. */
063    private int startPc;
064
065    /** Active. startPc is inclusive, endPc exclusive. */
066    private int endPc;
067
068    /**
069     * Starting address of exception handler, that is, an offset from start of code.
070     */
071    private int handlerPc;
072
073    /*
074     * If this is zero the handler catches any exception, otherwise it points to the exception class which is to be caught.
075     */
076    private int catchType;
077
078    /**
079     * Constructs a new instance from another instance.
080     *
081     * @param c Source for copying.
082     */
083    public CodeException(final CodeException c) {
084        this(c.getStartPC(), c.getEndPC(), c.getHandlerPC(), c.getCatchType());
085    }
086
087    /**
088     * Constructs a new instance from a DataInput.
089     *
090     * @param file Input stream.
091     * @throws IOException if an I/O error occurs.
092     */
093    CodeException(final DataInput file) throws IOException {
094        this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort());
095    }
096
097    /**
098     * Constructs a new instance.
099     *
100     * @param startPc Range in the code the exception handler is active, startPc is inclusive while.
101     * @param endPc is exclusive.
102     * @param handlerPc Starting address of exception handler, that is, an offset from start of code.
103     * @param catchType If zero the handler catches any exception, otherwise it points to the exception class which is to be
104     *        caught.
105     */
106    public CodeException(final int startPc, final int endPc, final int handlerPc, final int catchType) {
107        this.startPc = Args.requireU2(startPc, "startPc");
108        this.endPc = Args.requireU2(endPc, "endPc");
109        this.handlerPc = Args.requireU2(handlerPc, "handlerPc");
110        this.catchType = Args.requireU2(catchType, "catchType");
111    }
112
113    /**
114     * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
115     * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
116     *
117     * @param v Visitor object.
118     */
119    @Override
120    public void accept(final Visitor v) {
121        v.visitCodeException(this);
122    }
123
124    /**
125     * Creates a deep copy of this object.
126     *
127     * @return deep copy of this object.
128     */
129    public CodeException copy() {
130        try {
131            return (CodeException) clone();
132        } catch (final CloneNotSupportedException e) {
133            // TODO should this throw?
134        }
135        return null;
136    }
137
138    /**
139     * Dumps code exception to file stream in binary format.
140     *
141     * @param file Output file stream.
142     * @throws IOException if an I/O error occurs.
143     */
144    public void dump(final DataOutputStream file) throws IOException {
145        file.writeShort(startPc);
146        file.writeShort(endPc);
147        file.writeShort(handlerPc);
148        file.writeShort(catchType);
149    }
150
151    /**
152     * Gets the type of exception that is caught.
153     *
154     * @return 0, if the handler catches any exception, otherwise it points to the exception class which is to be caught.
155     */
156    public int getCatchType() {
157        return catchType;
158    }
159
160    /**
161     * Gets the exclusive end index of the region where the handler is active.
162     *
163     * @return Exclusive end index of the region where the handler is active.
164     */
165    public int getEndPC() {
166        return endPc;
167    }
168
169    /**
170     * Gets the starting address of exception handler, relative to the code.
171     *
172     * @return Starting address of exception handler, relative to the code.
173     */
174    public int getHandlerPC() {
175        return handlerPc;
176    }
177
178    /**
179     * Gets the inclusive start index of the region where the handler is active.
180     *
181     * @return Inclusive start index of the region where the handler is active.
182     */
183    public int getStartPC() {
184        return startPc;
185    }
186
187    /**
188     * Sets the type of exception that is caught.
189     *
190     * @param catchType the type of exception that is caught.
191     */
192    public void setCatchType(final int catchType) {
193        this.catchType = catchType;
194    }
195
196    /**
197     * Sets the end of handled block.
198     *
199     * @param endPc end of handled block.
200     */
201    public void setEndPC(final int endPc) {
202        this.endPc = endPc;
203    }
204
205    /**
206     * Sets where the actual code is.
207     *
208     * @param handlerPc where the actual code is.
209     */
210    public void setHandlerPC(final int handlerPc) { // TODO unused
211        this.handlerPc = handlerPc;
212    }
213
214    /**
215     * Sets the start of handled block.
216     *
217     * @param startPc start of handled block.
218     */
219    public void setStartPC(final int startPc) { // TODO unused
220        this.startPc = startPc;
221    }
222
223    /**
224     * Gets a string representation.
225     *
226     * @return String representation.
227     */
228    @Override
229    public String toString() {
230        return "CodeException(startPc = " + startPc + ", endPc = " + endPc + ", handlerPc = " + handlerPc + ", catchType = " + catchType + ")";
231    }
232
233    /**
234     * Gets a string representation with constant pool.
235     *
236     * @param cp constant pool source.
237     * @return String representation.
238     */
239    public String toString(final ConstantPool cp) {
240        return toString(cp, true);
241    }
242
243    /**
244     * Gets a string representation with constant pool.
245     *
246     * @param cp constant pool source.
247     * @param verbose Output more if true.
248     * @return String representation.
249     */
250    public String toString(final ConstantPool cp, final boolean verbose) {
251        final String str;
252        if (catchType == 0) {
253            str = "<Any exception>(0)";
254        } else {
255            str = Utility.compactClassName(cp.getConstantString(catchType, Const.CONSTANT_Class), false) + (verbose ? "(" + catchType + ")" : "");
256        }
257        return startPc + "\t" + endPc + "\t" + handlerPc + "\t" + str;
258    }
259}