1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 package org.apache.bcel.classfile; 19 20 import java.io.DataInput; 21 import java.io.DataOutputStream; 22 import java.io.IOException; 23 24 import org.apache.bcel.Const; 25 26 /** 27 * This class represents a inner class attribute, i.e., the class 28 * indices of the inner and outer classes, the name and the attributes 29 * of the inner class. 30 * 31 * @version $Id$ 32 * @see InnerClasses 33 */ 34 public final class InnerClass implements Cloneable, Node { 35 36 private int inner_class_index; 37 private int outer_class_index; 38 private int inner_name_index; 39 private int inner_access_flags; 40 41 42 /** 43 * Initialize from another object. 44 */ InnerClass(final InnerClass c)45 public InnerClass(final InnerClass c) { 46 this(c.getInnerClassIndex(), c.getOuterClassIndex(), c.getInnerNameIndex(), c 47 .getInnerAccessFlags()); 48 } 49 50 51 /** 52 * Construct object from file stream. 53 * @param file Input stream 54 * @throws IOException 55 */ InnerClass(final DataInput file)56 InnerClass(final DataInput file) throws IOException { 57 this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file 58 .readUnsignedShort()); 59 } 60 61 62 /** 63 * @param inner_class_index Class index in constant pool of inner class 64 * @param outer_class_index Class index in constant pool of outer class 65 * @param inner_name_index Name index in constant pool of inner class 66 * @param inner_access_flags Access flags of inner class 67 */ InnerClass(final int inner_class_index, final int outer_class_index, final int inner_name_index, final int inner_access_flags)68 public InnerClass(final int inner_class_index, final int outer_class_index, final int inner_name_index, 69 final int inner_access_flags) { 70 this.inner_class_index = inner_class_index; 71 this.outer_class_index = outer_class_index; 72 this.inner_name_index = inner_name_index; 73 this.inner_access_flags = inner_access_flags; 74 } 75 76 77 /** 78 * Called by objects that are traversing the nodes of the tree implicitely 79 * defined by the contents of a Java class. I.e., the hierarchy of methods, 80 * fields, attributes, etc. spawns a tree of objects. 81 * 82 * @param v Visitor object 83 */ 84 @Override accept( final Visitor v )85 public void accept( final Visitor v ) { 86 v.visitInnerClass(this); 87 } 88 89 90 /** 91 * Dump inner class attribute to file stream in binary format. 92 * 93 * @param file Output file stream 94 * @throws IOException 95 */ dump( final DataOutputStream file )96 public final void dump( final DataOutputStream file ) throws IOException { 97 file.writeShort(inner_class_index); 98 file.writeShort(outer_class_index); 99 file.writeShort(inner_name_index); 100 file.writeShort(inner_access_flags); 101 } 102 103 104 /** 105 * @return access flags of inner class. 106 */ getInnerAccessFlags()107 public final int getInnerAccessFlags() { 108 return inner_access_flags; 109 } 110 111 112 /** 113 * @return class index of inner class. 114 */ getInnerClassIndex()115 public final int getInnerClassIndex() { 116 return inner_class_index; 117 } 118 119 120 /** 121 * @return name index of inner class. 122 */ getInnerNameIndex()123 public final int getInnerNameIndex() { 124 return inner_name_index; 125 } 126 127 128 /** 129 * @return class index of outer class. 130 */ getOuterClassIndex()131 public final int getOuterClassIndex() { 132 return outer_class_index; 133 } 134 135 136 /** 137 * @param inner_access_flags access flags for this inner class 138 */ setInnerAccessFlags( final int inner_access_flags )139 public final void setInnerAccessFlags( final int inner_access_flags ) { 140 this.inner_access_flags = inner_access_flags; 141 } 142 143 144 /** 145 * @param inner_class_index index into the constant pool for this class 146 */ setInnerClassIndex( final int inner_class_index )147 public final void setInnerClassIndex( final int inner_class_index ) { 148 this.inner_class_index = inner_class_index; 149 } 150 151 152 /** 153 * @param inner_name_index index into the constant pool for this class's name 154 */ setInnerNameIndex( final int inner_name_index )155 public final void setInnerNameIndex( final int inner_name_index ) { // TODO unused 156 this.inner_name_index = inner_name_index; 157 } 158 159 160 /** 161 * @param outer_class_index index into the constant pool for the owning class 162 */ setOuterClassIndex( final int outer_class_index )163 public final void setOuterClassIndex( final int outer_class_index ) { // TODO unused 164 this.outer_class_index = outer_class_index; 165 } 166 167 168 /** 169 * @return String representation. 170 */ 171 @Override toString()172 public final String toString() { 173 return "InnerClass(" + inner_class_index + ", " + outer_class_index + ", " 174 + inner_name_index + ", " + inner_access_flags + ")"; 175 } 176 177 178 /** 179 * @return Resolved string representation 180 */ toString( final ConstantPool constant_pool )181 public final String toString( final ConstantPool constant_pool ) { 182 String outer_class_name; 183 String inner_name; 184 String inner_class_name = constant_pool.getConstantString(inner_class_index, 185 Const.CONSTANT_Class); 186 inner_class_name = Utility.compactClassName(inner_class_name); 187 if (outer_class_index != 0) { 188 outer_class_name = constant_pool.getConstantString(outer_class_index, 189 Const.CONSTANT_Class); 190 outer_class_name = " of class " + Utility.compactClassName(outer_class_name); 191 } else { 192 outer_class_name = ""; 193 } 194 if (inner_name_index != 0) { 195 inner_name = ((ConstantUtf8) constant_pool.getConstant(inner_name_index, 196 Const.CONSTANT_Utf8)).getBytes(); 197 } else { 198 inner_name = "(anonymous)"; 199 } 200 String access = Utility.accessToString(inner_access_flags, true); 201 access = access.isEmpty() ? "" : (access + " "); 202 return " " + access + inner_name + "=class " + inner_class_name + outer_class_name; 203 } 204 205 206 /** 207 * @return deep copy of this object 208 */ copy()209 public InnerClass copy() { 210 try { 211 return (InnerClass) clone(); 212 } catch (final CloneNotSupportedException e) { 213 // TODO should this throw? 214 } 215 return null; 216 } 217 } 218