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 colection of local variables in a
028 * method. This attribute is contained in the <em>Code</em> attribute.
029 *
030 * @version $Id: LocalVariableTable.java 1749603 2016-06-21 20:50:19Z ggregory $
031 * @see     Code
032 * @see LocalVariable
033 */
034public class LocalVariableTable extends Attribute {
035
036    private LocalVariable[] local_variable_table; // variables
037
038
039    /**
040     * Initialize from another object. Note that both objects use the same
041     * references (shallow copy). Use copy() for a physical copy.
042     */
043    public LocalVariableTable(final LocalVariableTable c) {
044        this(c.getNameIndex(), c.getLength(), c.getLocalVariableTable(), c.getConstantPool());
045    }
046
047
048    /**
049     * @param name_index Index in constant pool to `LocalVariableTable'
050     * @param length Content length in bytes
051     * @param local_variable_table Table of local variables
052     * @param constant_pool Array of constants
053     */
054    public LocalVariableTable(final int name_index, final int length, final LocalVariable[] local_variable_table,
055            final ConstantPool constant_pool) {
056        super(Const.ATTR_LOCAL_VARIABLE_TABLE, name_index, length, constant_pool);
057        this.local_variable_table = local_variable_table;
058    }
059
060
061    /**
062     * Construct object from input stream.
063     * @param name_index Index in constant pool
064     * @param length Content length in bytes
065     * @param input Input stream
066     * @param constant_pool Array of constants
067     * @throws IOException
068     */
069    LocalVariableTable(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
070            throws IOException {
071        this(name_index, length, (LocalVariable[]) null, constant_pool);
072        final int local_variable_table_length = input.readUnsignedShort();
073        local_variable_table = new LocalVariable[local_variable_table_length];
074        for (int i = 0; i < local_variable_table_length; i++) {
075            local_variable_table[i] = new LocalVariable(input, constant_pool);
076        }
077    }
078
079
080    /**
081     * Called by objects that are traversing the nodes of the tree implicitely
082     * defined by the contents of a Java class. I.e., the hierarchy of methods,
083     * fields, attributes, etc. spawns a tree of objects.
084     *
085     * @param v Visitor object
086     */
087    @Override
088    public void accept( final Visitor v ) {
089        v.visitLocalVariableTable(this);
090    }
091
092
093    /**
094     * Dump local variable table attribute to file stream in binary format.
095     *
096     * @param file Output file stream
097     * @throws IOException
098     */
099    @Override
100    public final void dump( final DataOutputStream file ) throws IOException {
101        super.dump(file);
102        file.writeShort(local_variable_table.length);
103        for (final LocalVariable variable : local_variable_table) {
104            variable.dump(file);
105        }
106    }
107
108
109    /**
110     * @return Array of local variables of method.
111     */
112    public final LocalVariable[] getLocalVariableTable() {
113        return local_variable_table;
114    }
115
116
117    /** 
118     * 
119     * @param index the variable slot
120     * 
121     * @return the first LocalVariable that matches the slot or null if not found
122     * 
123     * @deprecated since 5.2 because multiple variables can share the
124     *             same slot, use getLocalVariable(int index, int pc) instead.
125     */
126    @java.lang.Deprecated
127    public final LocalVariable getLocalVariable( final int index ) {
128        for (final LocalVariable variable : local_variable_table) {
129            if (variable.getIndex() == index) {
130                return variable;
131            }
132        }
133        return null;
134    }
135
136
137    /** 
138     * 
139     * @param index the variable slot
140     * @param pc the current pc that this variable is alive
141     * 
142     * @return the LocalVariable that matches or null if not found
143     */
144    public final LocalVariable getLocalVariable( final int index, final int pc ) {
145        for (final LocalVariable variable : local_variable_table) {
146            if (variable.getIndex() == index) {
147                final int start_pc = variable.getStartPC();
148                final int end_pc = start_pc + variable.getLength();
149                if ((pc >= start_pc) && (pc <= end_pc)) {
150                    return variable;
151                }
152            }
153        }
154        return null;
155    }
156
157
158    public final void setLocalVariableTable( final LocalVariable[] local_variable_table ) {
159        this.local_variable_table = local_variable_table;
160    }
161
162
163    /**
164     * @return String representation.
165     */
166    @Override
167    public final String toString() {
168        final StringBuilder buf = new StringBuilder();
169        for (int i = 0; i < local_variable_table.length; i++) {
170            buf.append(local_variable_table[i]);
171            if (i < local_variable_table.length - 1) {
172                buf.append('\n');
173            }
174        }
175        return buf.toString();
176    }
177
178
179    /**
180     * @return deep copy of this attribute
181     */
182    @Override
183    public Attribute copy( final ConstantPool _constant_pool ) {
184        final LocalVariableTable c = (LocalVariableTable) clone();
185        c.local_variable_table = new LocalVariable[local_variable_table.length];
186        for (int i = 0; i < local_variable_table.length; i++) {
187            c.local_variable_table[i] = local_variable_table[i].copy();
188        }
189        c.setConstantPool(_constant_pool);
190        return c;
191    }
192
193
194    public final int getTableLength() {
195        return local_variable_table == null ? 0 : local_variable_table.length;
196    }
197}