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 16package javassist.bytecode; 17 18import java.io.DataInputStream; 19import java.util.Map; 20import java.io.IOException; 21 22/** 23 * <code>InnerClasses_attribute</code>. 24 */ 25public 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