    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}