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 */
017
018package org.apache.bcel.classfile;
019
020import java.io.DataInput;
021import java.io.DataOutputStream;
022import java.io.IOException;
023
024import org.apache.bcel.Const;
025
026/**
027 * This class represents the table of exceptions that are thrown by a
028 * method. This attribute may be used once per method.  The name of
029 * this class is <em>ExceptionTable</em> for historical reasons; The
030 * Java Virtual Machine Specification, Second Edition defines this
031 * attribute using the name <em>Exceptions</em> (which is inconsistent
032 * with the other classes).
033 *
034 * @see     Code
035 */
036public final class ExceptionTable extends Attribute {
037
038    private int[] exceptionIndexTable; // constant pool
039
040
041    /**
042     * Initialize from another object. Note that both objects use the same
043     * references (shallow copy). Use copy() for a physical copy.
044     */
045    public ExceptionTable(final ExceptionTable c) {
046        this(c.getNameIndex(), c.getLength(), c.getExceptionIndexTable(), c.getConstantPool());
047    }
048
049
050    /**
051     * @param name_index Index in constant pool
052     * @param length Content length in bytes
053     * @param exceptionIndexTable Table of indices in constant pool
054     * @param constant_pool Array of constants
055     */
056    public ExceptionTable(final int name_index, final int length, final int[] exceptionIndexTable,
057            final ConstantPool constant_pool) {
058        super(Const.ATTR_EXCEPTIONS, name_index, length, constant_pool);
059        this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : new int[0];
060    }
061
062
063    /**
064     * Construct object from input stream.
065     * @param nameIndex Index in constant pool
066     * @param length Content length in bytes
067     * @param input Input stream
068     * @param constantPool Array of constants
069     * @throws IOException
070     */
071    ExceptionTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
072        this(nameIndex, length, (int[]) null, constantPool);
073        final int number_of_exceptions = input.readUnsignedShort();
074        exceptionIndexTable = new int[number_of_exceptions];
075        for (int i = 0; i < number_of_exceptions; i++) {
076            exceptionIndexTable[i] = input.readUnsignedShort();
077        }
078    }
079
080
081    /**
082     * Called by objects that are traversing the nodes of the tree implicitely
083     * defined by the contents of a Java class. I.e., the hierarchy of methods,
084     * fields, attributes, etc. spawns a tree of objects.
085     *
086     * @param v Visitor object
087     */
088    @Override
089    public void accept( final Visitor v ) {
090        v.visitExceptionTable(this);
091    }
092
093
094    /**
095     * Dump exceptions attribute to file stream in binary format.
096     *
097     * @param file Output file stream
098     * @throws IOException
099     */
100    @Override
101    public void dump( final DataOutputStream file ) throws IOException {
102        super.dump(file);
103        file.writeShort(exceptionIndexTable.length);
104        for (final int index : exceptionIndexTable) {
105            file.writeShort(index);
106        }
107    }
108
109
110    /**
111     * @return Array of indices into constant pool of thrown exceptions.
112     */
113    public int[] getExceptionIndexTable() {
114        return exceptionIndexTable;
115    }
116
117
118    /**
119     * @return Length of exception table.
120     */
121    public int getNumberOfExceptions() {
122        return exceptionIndexTable == null ? 0 : exceptionIndexTable.length;
123    }
124
125
126    /**
127     * @return class names of thrown exceptions
128     */
129    public String[] getExceptionNames() {
130        final String[] names = new String[exceptionIndexTable.length];
131        for (int i = 0; i < exceptionIndexTable.length; i++) {
132            names[i] = super.getConstantPool().getConstantString(exceptionIndexTable[i],
133                    Const.CONSTANT_Class).replace('/', '.');
134        }
135        return names;
136    }
137
138
139    /**
140     * @param exceptionIndexTable the list of exception indexes
141     * Also redefines number_of_exceptions according to table length.
142     */
143    public void setExceptionIndexTable( final int[] exceptionIndexTable ) {
144        this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : new int[0];
145    }
146
147
148    /**
149     * @return String representation, i.e., a list of thrown exceptions.
150     */
151    @Override
152    public String toString() {
153        final StringBuilder buf = new StringBuilder();
154        String str;
155        buf.append("Exceptions: ");
156        for (int i = 0; i < exceptionIndexTable.length; i++) {
157            str = super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class);
158            buf.append(Utility.compactClassName(str, false));
159            if (i < exceptionIndexTable.length - 1) {
160                buf.append(", ");
161            }
162        }
163        return buf.toString();
164    }
165
166
167    /**
168     * @return deep copy of this attribute
169     */
170    @Override
171    public Attribute copy( final ConstantPool _constant_pool ) {
172        final ExceptionTable c = (ExceptionTable) clone();
173        if (exceptionIndexTable != null) {
174            c.exceptionIndexTable = new int[exceptionIndexTable.length];
175            System.arraycopy(exceptionIndexTable, 0, c.exceptionIndexTable, 0,
176                    exceptionIndexTable.length);
177        }
178        c.setConstantPool(_constant_pool);
179        return c;
180    }
181}