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, i.e., 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, i.e., 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     * @return deep copy of this object
126     */
127    public CodeException copy() {
128        try {
129            return (CodeException) clone();
130        } catch (final CloneNotSupportedException e) {
131            // TODO should this throw?
132        }
133        return null;
134    }
135
136    /**
137     * Dumps code exception to file stream in binary format.
138     *
139     * @param file Output file stream
140     * @throws IOException if an I/O error occurs.
141     */
142    public void dump(final DataOutputStream file) throws IOException {
143        file.writeShort(startPc);
144        file.writeShort(endPc);
145        file.writeShort(handlerPc);
146        file.writeShort(catchType);
147    }
148
149    /**
150     * @return 0, if the handler catches any exception, otherwise it points to the exception class which is to be caught.
151     */
152    public int getCatchType() {
153        return catchType;
154    }
155
156    /**
157     * @return Exclusive end index of the region where the handler is active.
158     */
159    public int getEndPC() {
160        return endPc;
161    }
162
163    /**
164     * @return Starting address of exception handler, relative to the code.
165     */
166    public int getHandlerPC() {
167        return handlerPc;
168    }
169
170    /**
171     * @return Inclusive start index of the region where the handler is active.
172     */
173    public int getStartPC() {
174        return startPc;
175    }
176
177    /**
178     * @param catchType the type of exception that is caught
179     */
180    public void setCatchType(final int catchType) {
181        this.catchType = catchType;
182    }
183
184    /**
185     * @param endPc end of handled block
186     */
187    public void setEndPC(final int endPc) {
188        this.endPc = endPc;
189    }
190
191    /**
192     * @param handlerPc where the actual code is
193     */
194    public void setHandlerPC(final int handlerPc) { // TODO unused
195        this.handlerPc = handlerPc;
196    }
197
198    /**
199     * @param startPc start of handled block
200     */
201    public void setStartPC(final int startPc) { // TODO unused
202        this.startPc = startPc;
203    }
204
205    /**
206     * @return String representation.
207     */
208    @Override
209    public String toString() {
210        return "CodeException(startPc = " + startPc + ", endPc = " + endPc + ", handlerPc = " + handlerPc + ", catchType = " + catchType + ")";
211    }
212
213    public String toString(final ConstantPool cp) {
214        return toString(cp, true);
215    }
216
217    /**
218     * @param cp constant pool source.
219     * @param verbose Output more if true.
220     * @return String representation.
221     */
222    public String toString(final ConstantPool cp, final boolean verbose) {
223        final String str;
224        if (catchType == 0) {
225            str = "<Any exception>(0)";
226        } else {
227            str = Utility.compactClassName(cp.getConstantString(catchType, Const.CONSTANT_Class), false) + (verbose ? "(" + catchType + ")" : "");
228        }
229        return startPc + "\t" + endPc + "\t" + handlerPc + "\t" + str;
230    }
231}