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