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