/* * Javassist, a Java-bytecode translator toolkit. * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. Alternatively, the contents of this file may be used under * the terms of the GNU Lesser General Public License Version 2.1 or later, * or the Apache License Version 2.0. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. */ package javassist.bytecode; import java.io.DataInputStream; import java.util.Map; import java.io.IOException; /** * <code>InnerClasses_attribute</code>. */ public class InnerClassesAttribute extends AttributeInfo { /** * The name of this attribute <code>"InnerClasses"</code>. */ public static final String tag = "InnerClasses"; InnerClassesAttribute(ConstPool cp, int n, DataInputStream in) throws IOException { super(cp, n, in); } private InnerClassesAttribute(ConstPool cp, byte[] info) { super(cp, tag, info); } /** * Constructs an empty InnerClasses attribute. * * @see #append(String, String, String, int) */ public InnerClassesAttribute(ConstPool cp) { super(cp, tag, new byte[2]); ByteArray.write16bit(0, get(), 0); } /** * Returns <code>number_of_classes</code>. */ public int tableLength() { return ByteArray.readU16bit(get(), 0); } /** * Returns <code>classes[nth].inner_class_info_index</code>. */ public int innerClassIndex(int nth) { return ByteArray.readU16bit(get(), nth * 8 + 2); } /** * Returns the class name indicated * by <code>classes[nth].inner_class_info_index</code>. * * @return null or the class name. */ public String innerClass(int nth) { int i = innerClassIndex(nth); if (i == 0) return null; else return constPool.getClassInfo(i); } /** * Sets <code>classes[nth].inner_class_info_index</code> to * the given index. */ public void setInnerClassIndex(int nth, int index) { ByteArray.write16bit(index, get(), nth * 8 + 2); } /** * Returns <code>classes[nth].outer_class_info_index</code>. */ public int outerClassIndex(int nth) { return ByteArray.readU16bit(get(), nth * 8 + 4); } /** * Returns the class name indicated * by <code>classes[nth].outer_class_info_index</code>. * * @return null or the class name. */ public String outerClass(int nth) { int i = outerClassIndex(nth); if (i == 0) return null; else return constPool.getClassInfo(i); } /** * Sets <code>classes[nth].outer_class_info_index</code> to * the given index. */ public void setOuterClassIndex(int nth, int index) { ByteArray.write16bit(index, get(), nth * 8 + 4); } /** * Returns <code>classes[nth].inner_name_index</code>. */ public int innerNameIndex(int nth) { return ByteArray.readU16bit(get(), nth * 8 + 6); } /** * Returns the simple class name indicated * by <code>classes[nth].inner_name_index</code>. * * @return null or the class name. */ public String innerName(int nth) { int i = innerNameIndex(nth); if (i == 0) return null; else return constPool.getUtf8Info(i); } /** * Sets <code>classes[nth].inner_name_index</code> to * the given index. */ public void setInnerNameIndex(int nth, int index) { ByteArray.write16bit(index, get(), nth * 8 + 6); } /** * Returns <code>classes[nth].inner_class_access_flags</code>. */ public int accessFlags(int nth) { return ByteArray.readU16bit(get(), nth * 8 + 8); } /** * Sets <code>classes[nth].inner_class_access_flags</code> to * the given index. */ public void setAccessFlags(int nth, int flags) { ByteArray.write16bit(flags, get(), nth * 8 + 8); } /** * Appends a new entry. * * @param inner <code>inner_class_info_index</code> * @param outer <code>outer_class_info_index</code> * @param name <code>inner_name_index</code> * @param flags <code>inner_class_access_flags</code> */ public void append(String inner, String outer, String name, int flags) { int i = constPool.addClassInfo(inner); int o = constPool.addClassInfo(outer); int n = constPool.addUtf8Info(name); append(i, o, n, flags); } /** * Appends a new entry. * * @param inner <code>inner_class_info_index</code> * @param outer <code>outer_class_info_index</code> * @param name <code>inner_name_index</code> * @param flags <code>inner_class_access_flags</code> */ public void append(int inner, int outer, int name, int flags) { byte[] data = get(); int len = data.length; byte[] newData = new byte[len + 8]; for (int i = 2; i < len; ++i) newData[i] = data[i]; int n = ByteArray.readU16bit(data, 0); ByteArray.write16bit(n + 1, newData, 0); ByteArray.write16bit(inner, newData, len); ByteArray.write16bit(outer, newData, len + 2); ByteArray.write16bit(name, newData, len + 4); ByteArray.write16bit(flags, newData, len + 6); set(newData); } /** * Makes a copy. Class names are replaced according to the * given <code>Map</code> object. * * @param newCp the constant pool table used by the new copy. * @param classnames pairs of replaced and substituted * class names. */ public AttributeInfo copy(ConstPool newCp, Map classnames) { byte[] src = get(); byte[] dest = new byte[src.length]; ConstPool cp = getConstPool(); InnerClassesAttribute attr = new InnerClassesAttribute(newCp, dest); int n = ByteArray.readU16bit(src, 0); ByteArray.write16bit(n, dest, 0); int j = 2; for (int i = 0; i < n; ++i) { int innerClass = ByteArray.readU16bit(src, j); int outerClass = ByteArray.readU16bit(src, j + 2); int innerName = ByteArray.readU16bit(src, j + 4); int innerAccess = ByteArray.readU16bit(src, j + 6); if (innerClass != 0) innerClass = cp.copy(innerClass, newCp, classnames); ByteArray.write16bit(innerClass, dest, j); if (outerClass != 0) outerClass = cp.copy(outerClass, newCp, classnames); ByteArray.write16bit(outerClass, dest, j + 2); if (innerName != 0) innerName = cp.copy(innerName, newCp, classnames); ByteArray.write16bit(innerName, dest, j + 4); ByteArray.write16bit(innerAccess, dest, j + 6); j += 8; } return attr; } }