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  * @see InnerClasses
  36  */
  37 public final class InnerClass implements Cloneable, Node {
  38 
  39     private int inner_class_index;
  40     private int outer_class_index;
  41     private int inner_name_index;
  42     private int inner_access_flags;
  43 
  44 
  45     /**
  46      * Initialize from another object.
  47      */
  48     public InnerClass(final InnerClass c) {
  49         this(c.getInnerClassIndex(), c.getOuterClassIndex(), c.getInnerNameIndex(), c
  50                 .getInnerAccessFlags());
  51     }
  52 
  53 
  54     /**
  55      * Construct object from file stream.
  56      * @param file Input stream
  57      * @throws IOException
  58      */
  59     InnerClass(final DataInput file) throws IOException {
  60         this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file
  61                 .readUnsignedShort());
  62     }
  63 
  64 
  65     /**
  66      * @param inner_class_index Class index in constant pool of inner class
  67      * @param outer_class_index Class index in constant pool of outer class
  68      * @param inner_name_index  Name index in constant pool of inner class
  69      * @param inner_access_flags Access flags of inner class
  70      */
  71     public InnerClass(final int inner_class_index, final int outer_class_index, final int inner_name_index,
  72             final int inner_access_flags) {
  73         this.inner_class_index = inner_class_index;
  74         this.outer_class_index = outer_class_index;
  75         this.inner_name_index = inner_name_index;
  76         this.inner_access_flags = inner_access_flags;
  77     }
  78 
  79 
  80     /**
  81      * Called by objects that are traversing the nodes of the tree implicitely
  82      * defined by the contents of a Java class. I.e., the hierarchy of methods,
  83      * fields, attributes, etc. spawns a tree of objects.
  84      *
  85      * @param v Visitor object
  86      */
  87     @Override
  88     public void accept( final Visitor v ) {
  89         v.visitInnerClass(this);
  90     }
  91 
  92 
  93     /**
  94      * Dump inner class attribute to file stream in binary format.
  95      *
  96      * @param file Output file stream
  97      * @throws IOException
  98      */
  99     public void dump( final DataOutputStream file ) throws IOException {
 100         file.writeShort(inner_class_index);
 101         file.writeShort(outer_class_index);
 102         file.writeShort(inner_name_index);
 103         file.writeShort(inner_access_flags);
 104     }
 105 
 106 
 107     /**
 108      * @return access flags of inner class.
 109      */
 110     public int getInnerAccessFlags() {
 111         return inner_access_flags;
 112     }
 113 
 114 
 115     /**
 116      * @return class index of inner class.
 117      */
 118     public int getInnerClassIndex() {
 119         return inner_class_index;
 120     }
 121 
 122 
 123     /**
 124      * @return name index of inner class.
 125      */
 126     public int getInnerNameIndex() {
 127         return inner_name_index;
 128     }
 129 
 130 
 131     /**
 132      * @return class index of outer class.
 133      */
 134     public int getOuterClassIndex() {
 135         return outer_class_index;
 136     }
 137 
 138 
 139     /**
 140      * @param inner_access_flags access flags for this inner class
 141      */
 142     public void setInnerAccessFlags( final int inner_access_flags ) {
 143         this.inner_access_flags = inner_access_flags;
 144     }
 145 
 146 
 147     /**
 148      * @param inner_class_index index into the constant pool for this class
 149      */
 150     public void setInnerClassIndex( final int inner_class_index ) {
 151         this.inner_class_index = inner_class_index;
 152     }
 153 
 154 
 155     /**
 156      * @param inner_name_index index into the constant pool for this class's name
 157      */
 158     public void setInnerNameIndex( final int inner_name_index ) { // TODO unused
 159         this.inner_name_index = inner_name_index;
 160     }
 161 
 162 
 163     /**
 164      * @param outer_class_index index into the constant pool for the owning class
 165      */
 166     public void setOuterClassIndex( final int outer_class_index ) { // TODO unused
 167         this.outer_class_index = outer_class_index;
 168     }
 169 
 170 
 171     /**
 172      * @return String representation.
 173      */
 174     @Override
 175     public String toString() {
 176         return "InnerClass(" + inner_class_index + ", " + outer_class_index + ", "
 177                 + inner_name_index + ", " + inner_access_flags + ")";
 178     }
 179 
 180 
 181     /**
 182      * @return Resolved string representation
 183      */
 184     public String toString( final ConstantPool constant_pool ) {
 185         String outer_class_name;
 186         String inner_name;
 187         String inner_class_name = constant_pool.getConstantString(inner_class_index,
 188                 Const.CONSTANT_Class);
 189         inner_class_name = Utility.compactClassName(inner_class_name, false);
 190         if (outer_class_index != 0) {
 191             outer_class_name = constant_pool.getConstantString(outer_class_index,
 192                     Const.CONSTANT_Class);
 193             outer_class_name = " of class " + Utility.compactClassName(outer_class_name, false);
 194         } else {
 195             outer_class_name = "";
 196         }
 197         if (inner_name_index != 0) {
 198             inner_name = ((ConstantUtf8) constant_pool.getConstant(inner_name_index,
 199                     Const.CONSTANT_Utf8)).getBytes();
 200         } else {
 201             inner_name = "(anonymous)";
 202         }
 203         String access = Utility.accessToString(inner_access_flags, true);
 204         access = access.isEmpty() ? "" : (access + " ");
 205         return "  " + access + inner_name + "=class " + inner_class_name + outer_class_name;
 206     }
 207 
 208 
 209     /**
 210      * @return deep copy of this object
 211      */
 212     public InnerClass copy() {
 213         try {
 214             return (InnerClass) clone();
 215         } catch (final CloneNotSupportedException e) {
 216             // TODO should this throw?
 217         }
 218         return null;
 219     }
 220 }