    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}