/*
* @(#)InnerClassAttribute.java 1.13 06/10/10
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*
*/
package components;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
/*
* A class to represent the innerclass attribute of a class. The innerclass
* attribute is new in 1.2 and is documented in the 1.2 JVM Spec.
*/
public
class InnerClassAttribute extends Attribute {
//__________ CLASS METHODS
public static Attribute
readAttribute(DataInput in, int len,
UnicodeConstant name,
ConstantObject constants[]) throws IOException {
return finishReadAttribute(in, len, name, constants);
}
public static Attribute
finishReadAttribute(DataInput in, int len,
UnicodeConstant name,
ConstantObject constants[]) throws IOException {
int num = in.readUnsignedShort();
Vector entries = new Vector(num);
int i, next, anonNum;
ClassConstant innerInfo;
ClassConstant outerInfo;
UnicodeConstant innerName;
for (i=0, anonNum=1; i < num; i++) {
innerInfo = (ClassConstant)constants[in.readUnsignedShort()];
outerInfo = (ClassConstant)constants[in.readUnsignedShort()];
next = in.readUnsignedShort();
if (next == 0) { // A zero value means this is an anonymous inner class.
// Note: We are guessing at the name of the anonymous class.
// But the guess will only be the correct name if the ordering
// of the inner class attributes is the same as the ordering
// of the anonymous inner classes as they appear in the source
// file. And that is totally dependent on how the javac compiler
// wants to do it. There is nothing in the JVM spec that says it
// has to be that way. This won't hurt anything since we are just
// replacing an unused name field with a guess. The JVM doesn't
// care what is in this field.
innerName = new UnicodeConstant((new Integer(anonNum++)).toString());
} else {
innerName = (UnicodeConstant)constants[next];
}
entries.addElement(new InnerClassEntry(innerInfo,
outerInfo,
innerName,
in.readUnsignedShort()));
// entries.add(new InnerClassEntry(innerInfo,
// outerInfo,
// innerName,
// in.readUnsignedShort()));
}
return new InnerClassAttribute(name, len, entries);
}
//__________ INSTANCE VARIABLES
private Vector myInnerClassesVector;
private InnerClassEntry myInnerClassesArray[];
//__________ CONSTRUCTORS
public
InnerClassAttribute(UnicodeConstant name,
int len,
Vector entries) {
super(name, len);
myInnerClassesVector = entries;
// Save an array copy because some methods use an index value
// to find individual entries. But don't forget to update this
// array if the vector changes, like in the removeEntry method.
myInnerClassesArray = new InnerClassEntry[myInnerClassesVector.size()];
// myInnerClassesVector.toArray(myInnerClassesArray);
myInnerClassesVector.copyInto(myInnerClassesArray);
}
//__________ INSTANCE METHODS
protected int
writeData(DataOutput o) throws IOException {
int numberOfInnerClasses = myInnerClassesVector.size();
o.writeShort(numberOfInnerClasses);
Enumeration e = myInnerClassesVector.elements();
while (e.hasMoreElements()) {
((InnerClassEntry)e.nextElement()).write(o);
}
//return total number of bytes written, which is equal to
//2 (the number of bytes of the numberOfInnerClasses local
//variable) + the size of the InnerClassEntry * the number
//of inner classes.
return 2 + InnerClassEntry.SIZE * numberOfInnerClasses;
}
public void
mergeConstantsIntoSharedPool(ConstantPool sharedCP)
{
InnerClassEntry ice;
Enumeration e = myInnerClassesVector.elements();
while (e.hasMoreElements()) {
ice = (InnerClassEntry)e.nextElement();
if (ice.innerInfo != null) {
ice.innerInfo = (ClassConstant)sharedCP.add(ice.innerInfo);
}
if (ice.outerInfo != null) {
ice.outerInfo = (ClassConstant)sharedCP.add(ice.outerInfo);
}
}
// Don't forget to update the array copy now that we've changed
// the vector.
myInnerClassesVector.copyInto(myInnerClassesArray);
}
/*
* I am unsure exactly how this should operate. If innerInfo is null,
* should I still check the values of outerInfo and innerName? I would
* think that it wouldn't matter because if innerInfo is null, the other
* two should also be null.
*/
public void
countConstantReferences(boolean isRelocatable) {
super.countConstantReferences(isRelocatable);
InnerClassEntry ice;
Enumeration e = myInnerClassesVector.elements();
while (e.hasMoreElements()) {
ice = (InnerClassEntry)e.nextElement();
if (ice.innerInfo != null) {
ice.innerInfo.incReference();
}
if (ice.outerInfo != null) {
ice.outerInfo.incReference();
}
/*
* innerNameIndex not supported because utf8 cp entries
* are not kept around.
*
if (ice.innerName != null) {
ice.innerName.incReference();
}
*/
}
// Don't forget to update the array copy now that we've changed
// the vector.
myInnerClassesVector.copyInto(myInnerClassesArray);
}
/*
* This method only called just before writing output.
* Make sure that all our ClassConstant entries end up in a constant
* pool. Call super.validate so it can check its fields, too.
*/
public void
validate(){
super.validate();
InnerClassEntry ice;
Enumeration e = myInnerClassesVector.elements();
while (e.hasMoreElements()) {
ice = (InnerClassEntry)e.nextElement();
if (ice.innerInfo != null) {
ice.innerInfo.validate();
}
if (ice.outerInfo != null) {
ice.outerInfo.validate();
}
}
}
public void
removeEntry(int i) {
System.out.println("*** Removing inner class "+ myInnerClassesArray[i].getFullName());
// myInnerClassesVector.remove(myInnerClassesArray[i]);
myInnerClassesVector.removeElement(myInnerClassesArray[i]);
// Don't forget to update the array copy now that we've changed
// the vector.
myInnerClassesArray = new InnerClassEntry[myInnerClassesVector.size()];
// myInnerClassesVector.toArray(myInnerClassesArray);
myInnerClassesVector.copyInto(myInnerClassesArray);
}
public int
getInnerClassCount() {
return myInnerClassesVector.size();
}
/*
* The following four methods return information about individual
* inner class entries contained in this attribute. These methods
* call corresponding methods in the InnerClassEntry class. They
* are self-explanatory.
*/
public int
getInnerInfoIndex(int i) {
return myInnerClassesArray[i].getInnerInfoIndex();
}
public int
getOuterInfoIndex(int i) {
return myInnerClassesArray[i].getOuterInfoIndex();
}
public int
getInnerNameIndex(int i) {
return myInnerClassesArray[i].getInnerNameIndex();
}
public int
getAccessFlags(int i) {
return myInnerClassesArray[i].getAccessFlags();
}
/*
* Like the above methods, these methods return information about
* an individual inner class entry. The string returned will be
* the name of the inner class, if it has one. If the inner class
* is anonymous, it will not have a name and the string "anonymous"
* will be returned.
*/
public String
getName(int i) {
return myInnerClassesArray[i].getName();
}
/*
* Like the getName method, but return the outer class name as well.
*/
public String
getFullName(int i) {
return myInnerClassesArray[i].getFullName();
}
}