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