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