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 */ 019 020package org.apache.bcel.classfile; 021 022import java.io.DataInput; 023import java.io.DataOutputStream; 024import java.io.IOException; 025import java.util.Arrays; 026import java.util.Iterator; 027import java.util.stream.Stream; 028 029import org.apache.bcel.Const; 030import org.apache.bcel.util.Args; 031 032// The new table is used when generic types are about... 033 034//LocalVariableTable_attribute { 035// u2 attribute_name_index; 036// u4 attribute_length; 037// u2 local_variable_table_length; 038// { u2 start_pc; 039// u2 length; 040// u2 name_index; 041// u2 descriptor_index; 042// u2 index; 043// } local_variable_table[local_variable_table_length]; 044// } 045 046//LocalVariableTypeTable_attribute { 047// u2 attribute_name_index; 048// u4 attribute_length; 049// u2 local_variable_type_table_length; 050// { 051// u2 start_pc; 052// u2 length; 053// u2 name_index; 054// u2 signature_index; 055// u2 index; 056// } localVariableTypeTable[local_variable_type_table_length]; 057// } 058// J5TODO: Needs some testing ! 059 060/** 061 * Represents the LocalVariableTypeTable attribute. 062 * 063 * @since 6.0 064 */ 065public class LocalVariableTypeTable extends Attribute implements Iterable<LocalVariable> { 066 067 private static final LocalVariable[] EMPTY_ARRAY = {}; 068 069 private LocalVariable[] localVariableTypeTable; // variables 070 071 LocalVariableTypeTable(final int nameIdx, final int len, final DataInput input, final ConstantPool cpool) throws IOException { 072 this(nameIdx, len, (LocalVariable[]) null, cpool); 073 final int localVariableTypeTableLength = input.readUnsignedShort(); 074 localVariableTypeTable = new LocalVariable[localVariableTypeTableLength]; 075 for (int i = 0; i < localVariableTypeTableLength; i++) { 076 localVariableTypeTable[i] = new LocalVariable(input, cpool); 077 } 078 } 079 080 /** 081 * Constructs a new LocalVariableTypeTable. 082 * 083 * @param nameIndex index into constant pool. 084 * @param length content length in bytes. 085 * @param localVariableTypeTable The local variable type table. 086 * @param constantPool The constant pool. 087 */ 088 public LocalVariableTypeTable(final int nameIndex, final int length, final LocalVariable[] localVariableTypeTable, final ConstantPool constantPool) { 089 super(Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE, nameIndex, length, constantPool); 090 this.localVariableTypeTable = localVariableTypeTable != null ? localVariableTypeTable : LocalVariable.EMPTY_ARRAY; 091 Args.requireU2(this.localVariableTypeTable.length, "localVariableTypeTable.length"); 092 } 093 094 /** 095 * Constructs a copy. 096 * 097 * @param c The instance to copy. 098 */ 099 public LocalVariableTypeTable(final LocalVariableTypeTable c) { 100 this(c.getNameIndex(), c.getLength(), c.getLocalVariableTypeTable(), c.getConstantPool()); 101 } 102 103 @Override 104 public void accept(final Visitor v) { 105 v.visitLocalVariableTypeTable(this); 106 } 107 108 /** 109 * @return deep copy of this attribute. 110 */ 111 @Override 112 public Attribute copy(final ConstantPool constantPool) { 113 final LocalVariableTypeTable c = (LocalVariableTypeTable) clone(); 114 c.localVariableTypeTable = new LocalVariable[localVariableTypeTable.length]; 115 Arrays.setAll(c.localVariableTypeTable, i -> localVariableTypeTable[i].copy()); 116 c.setConstantPool(constantPool); 117 return c; 118 } 119 120 @Override 121 public final void dump(final DataOutputStream file) throws IOException { 122 super.dump(file); 123 file.writeShort(Args.requireU2(localVariableTypeTable.length, "localVariableTypeTable.length")); 124 for (final LocalVariable variable : localVariableTypeTable) { 125 variable.dump(file); 126 } 127 } 128 129 /** 130 * Gets the local variable for the given index. 131 * 132 * @param index The index. 133 * @return The local variable or null if not found. 134 */ 135 public final LocalVariable getLocalVariable(final int index) { 136 for (final LocalVariable variable : localVariableTypeTable) { 137 if (variable.getIndex() == index) { 138 return variable; 139 } 140 } 141 return null; 142 } 143 144 /** 145 * Gets the local variable type table. 146 * 147 * @return The local variable type table. 148 */ 149 public final LocalVariable[] getLocalVariableTypeTable() { 150 return localVariableTypeTable; 151 } 152 153 /** 154 * Gets the table length. 155 * 156 * @return The table length. 157 */ 158 public final int getTableLength() { 159 return localVariableTypeTable == null ? 0 : localVariableTypeTable.length; 160 } 161 162 @Override 163 public Iterator<LocalVariable> iterator() { 164 return Stream.of(localVariableTypeTable).iterator(); 165 } 166 167 /** 168 * Sets the local variable table. 169 * 170 * @param localVariableTable The local variable table to set. 171 */ 172 public final void setLocalVariableTable(final LocalVariable[] localVariableTable) { 173 this.localVariableTypeTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY; 174 } 175 176 /** 177 * @return String representation. 178 */ 179 @Override 180 public final String toString() { 181 final StringBuilder buf = new StringBuilder(); 182 for (int i = 0; i < localVariableTypeTable.length; i++) { 183 buf.append(localVariableTypeTable[i].toStringShared(true)); 184 if (i < localVariableTypeTable.length - 1) { 185 buf.append('\n'); 186 } 187 } 188 return buf.toString(); 189 } 190}