Home | History | Annotate | Download | only in bytecode
      1 /*
      2  * Javassist, a Java-bytecode translator toolkit.
      3  * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
      4  *
      5  * The contents of this file are subject to the Mozilla Public License Version
      6  * 1.1 (the "License"); you may not use this file except in compliance with
      7  * the License.  Alternatively, the contents of this file may be used under
      8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
      9  *
     10  * Software distributed under the License is distributed on an "AS IS" basis,
     11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     12  * for the specific language governing rights and limitations under the
     13  * License.
     14  */
     15 
     16 package javassist.bytecode;
     17 
     18 import java.io.DataInputStream;
     19 import java.util.Map;
     20 import java.io.IOException;
     21 
     22 /**
     23  * <code>InnerClasses_attribute</code>.
     24  */
     25 public class InnerClassesAttribute extends AttributeInfo {
     26     /**
     27      * The name of this attribute <code>"InnerClasses"</code>.
     28      */
     29     public static final String tag = "InnerClasses";
     30 
     31     InnerClassesAttribute(ConstPool cp, int n, DataInputStream in)
     32         throws IOException
     33     {
     34         super(cp, n, in);
     35     }
     36 
     37     private InnerClassesAttribute(ConstPool cp, byte[] info) {
     38         super(cp, tag, info);
     39     }
     40 
     41     /**
     42      * Constructs an empty InnerClasses attribute.
     43      *
     44      * @see #append(String, String, String, int)
     45      */
     46     public InnerClassesAttribute(ConstPool cp) {
     47         super(cp, tag, new byte[2]);
     48         ByteArray.write16bit(0, get(), 0);
     49     }
     50 
     51     /**
     52      * Returns <code>number_of_classes</code>.
     53      */
     54     public int tableLength() { return ByteArray.readU16bit(get(), 0); }
     55 
     56     /**
     57      * Returns <code>classes[nth].inner_class_info_index</code>.
     58      */
     59     public int innerClassIndex(int nth) {
     60         return ByteArray.readU16bit(get(), nth * 8 + 2);
     61     }
     62 
     63     /**
     64      * Returns the class name indicated
     65      * by <code>classes[nth].inner_class_info_index</code>.
     66      *
     67      * @return null or the class name.
     68      */
     69     public String innerClass(int nth) {
     70         int i = innerClassIndex(nth);
     71         if (i == 0)
     72             return null;
     73         else
     74             return constPool.getClassInfo(i);
     75     }
     76 
     77     /**
     78      * Sets <code>classes[nth].inner_class_info_index</code> to
     79      * the given index.
     80      */
     81     public void setInnerClassIndex(int nth, int index) {
     82         ByteArray.write16bit(index, get(), nth * 8 + 2);
     83     }
     84 
     85     /**
     86      * Returns <code>classes[nth].outer_class_info_index</code>.
     87      */
     88     public int outerClassIndex(int nth) {
     89         return ByteArray.readU16bit(get(), nth * 8 + 4);
     90     }
     91 
     92     /**
     93      * Returns the class name indicated
     94      * by <code>classes[nth].outer_class_info_index</code>.
     95      *
     96      * @return null or the class name.
     97      */
     98     public String outerClass(int nth) {
     99         int i = outerClassIndex(nth);
    100         if (i == 0)
    101             return null;
    102         else
    103             return constPool.getClassInfo(i);
    104     }
    105 
    106     /**
    107      * Sets <code>classes[nth].outer_class_info_index</code> to
    108      * the given index.
    109      */
    110     public void setOuterClassIndex(int nth, int index) {
    111         ByteArray.write16bit(index, get(), nth * 8 + 4);
    112     }
    113 
    114     /**
    115      * Returns <code>classes[nth].inner_name_index</code>.
    116      */
    117     public int innerNameIndex(int nth) {
    118         return ByteArray.readU16bit(get(), nth * 8 + 6);
    119     }
    120 
    121     /**
    122      * Returns the simple class name indicated
    123      * by <code>classes[nth].inner_name_index</code>.
    124      *
    125      * @return null or the class name.
    126      */
    127     public String innerName(int nth) {
    128         int i = innerNameIndex(nth);
    129         if (i == 0)
    130             return null;
    131         else
    132             return constPool.getUtf8Info(i);
    133     }
    134 
    135     /**
    136      * Sets <code>classes[nth].inner_name_index</code> to
    137      * the given index.
    138      */
    139     public void setInnerNameIndex(int nth, int index) {
    140         ByteArray.write16bit(index, get(), nth * 8 + 6);
    141     }
    142 
    143     /**
    144      * Returns <code>classes[nth].inner_class_access_flags</code>.
    145      */
    146     public int accessFlags(int nth) {
    147         return ByteArray.readU16bit(get(), nth * 8 + 8);
    148     }
    149 
    150     /**
    151      * Sets <code>classes[nth].inner_class_access_flags</code> to
    152      * the given index.
    153      */
    154     public void setAccessFlags(int nth, int flags) {
    155         ByteArray.write16bit(flags, get(), nth * 8 + 8);
    156     }
    157 
    158     /**
    159      * Appends a new entry.
    160      *
    161      * @param inner     <code>inner_class_info_index</code>
    162      * @param outer     <code>outer_class_info_index</code>
    163      * @param name      <code>inner_name_index</code>
    164      * @param flags     <code>inner_class_access_flags</code>
    165      */
    166     public void append(String inner, String outer, String name, int flags) {
    167         int i = constPool.addClassInfo(inner);
    168         int o = constPool.addClassInfo(outer);
    169         int n = constPool.addUtf8Info(name);
    170         append(i, o, n, flags);
    171     }
    172 
    173     /**
    174      * Appends a new entry.
    175      *
    176      * @param inner     <code>inner_class_info_index</code>
    177      * @param outer     <code>outer_class_info_index</code>
    178      * @param name      <code>inner_name_index</code>
    179      * @param flags     <code>inner_class_access_flags</code>
    180      */
    181     public void append(int inner, int outer, int name, int flags) {
    182         byte[] data = get();
    183         int len = data.length;
    184         byte[] newData = new byte[len + 8];
    185         for (int i = 2; i < len; ++i)
    186             newData[i] = data[i];
    187 
    188         int n = ByteArray.readU16bit(data, 0);
    189         ByteArray.write16bit(n + 1, newData, 0);
    190 
    191         ByteArray.write16bit(inner, newData, len);
    192         ByteArray.write16bit(outer, newData, len + 2);
    193         ByteArray.write16bit(name, newData, len + 4);
    194         ByteArray.write16bit(flags, newData, len + 6);
    195 
    196         set(newData);
    197     }
    198 
    199     /**
    200      * Makes a copy.  Class names are replaced according to the
    201      * given <code>Map</code> object.
    202      *
    203      * @param newCp     the constant pool table used by the new copy.
    204      * @param classnames        pairs of replaced and substituted
    205      *                          class names.
    206      */
    207     public AttributeInfo copy(ConstPool newCp, Map classnames) {
    208         byte[] src = get();
    209         byte[] dest = new byte[src.length];
    210         ConstPool cp = getConstPool();
    211         InnerClassesAttribute attr = new InnerClassesAttribute(newCp, dest);
    212         int n = ByteArray.readU16bit(src, 0);
    213         ByteArray.write16bit(n, dest, 0);
    214         int j = 2;
    215         for (int i = 0; i < n; ++i) {
    216             int innerClass = ByteArray.readU16bit(src, j);
    217             int outerClass = ByteArray.readU16bit(src, j + 2);
    218             int innerName = ByteArray.readU16bit(src, j + 4);
    219             int innerAccess = ByteArray.readU16bit(src, j + 6);
    220 
    221             if (innerClass != 0)
    222                 innerClass = cp.copy(innerClass, newCp, classnames);
    223 
    224             ByteArray.write16bit(innerClass, dest, j);
    225 
    226             if (outerClass != 0)
    227                 outerClass = cp.copy(outerClass, newCp, classnames);
    228 
    229             ByteArray.write16bit(outerClass, dest, j + 2);
    230 
    231             if (innerName != 0)
    232                 innerName = cp.copy(innerName, newCp, classnames);
    233 
    234             ByteArray.write16bit(innerName, dest, j + 4);
    235             ByteArray.write16bit(innerAccess, dest, j + 6);
    236             j += 8;
    237         }
    238 
    239         return attr;
    240     }
    241 }
    242