001: /*
002: * @(#)InnerClassAttribute.java 1.13 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package components;
029:
030: import java.io.DataInput;
031: import java.io.DataOutput;
032: import java.io.IOException;
033: import java.util.Enumeration;
034: import java.util.Vector;
035:
036: /*
037: * A class to represent the innerclass attribute of a class. The innerclass
038: * attribute is new in 1.2 and is documented in the 1.2 JVM Spec.
039: */
040: public class InnerClassAttribute extends Attribute {
041: //__________ CLASS METHODS
042: public static Attribute readAttribute(DataInput in, int len,
043: UnicodeConstant name, ConstantObject constants[])
044: throws IOException {
045: return finishReadAttribute(in, len, name, constants);
046: }
047:
048: public static Attribute finishReadAttribute(DataInput in, int len,
049: UnicodeConstant name, ConstantObject constants[])
050: throws IOException {
051: int num = in.readUnsignedShort();
052: Vector entries = new Vector(num);
053: int i, next, anonNum;
054: ClassConstant innerInfo;
055: ClassConstant outerInfo;
056: UnicodeConstant innerName;
057:
058: for (i = 0, anonNum = 1; i < num; i++) {
059: innerInfo = (ClassConstant) constants[in
060: .readUnsignedShort()];
061: outerInfo = (ClassConstant) constants[in
062: .readUnsignedShort()];
063:
064: next = in.readUnsignedShort();
065: if (next == 0) { // A zero value means this is an anonymous inner class.
066: // Note: We are guessing at the name of the anonymous class.
067: // But the guess will only be the correct name if the ordering
068: // of the inner class attributes is the same as the ordering
069: // of the anonymous inner classes as they appear in the source
070: // file. And that is totally dependent on how the javac compiler
071: // wants to do it. There is nothing in the JVM spec that says it
072: // has to be that way. This won't hurt anything since we are just
073: // replacing an unused name field with a guess. The JVM doesn't
074: // care what is in this field.
075: innerName = new UnicodeConstant(
076: (new Integer(anonNum++)).toString());
077: } else {
078: innerName = (UnicodeConstant) constants[next];
079: }
080:
081: entries.addElement(new InnerClassEntry(innerInfo,
082: outerInfo, innerName, in.readUnsignedShort()));
083: // entries.add(new InnerClassEntry(innerInfo,
084: // outerInfo,
085: // innerName,
086: // in.readUnsignedShort()));
087: }
088:
089: return new InnerClassAttribute(name, len, entries);
090: }
091:
092: //__________ INSTANCE VARIABLES
093: private Vector myInnerClassesVector;
094: private InnerClassEntry myInnerClassesArray[];
095:
096: //__________ CONSTRUCTORS
097: public InnerClassAttribute(UnicodeConstant name, int len,
098: Vector entries) {
099: super (name, len);
100: myInnerClassesVector = entries;
101:
102: // Save an array copy because some methods use an index value
103: // to find individual entries. But don't forget to update this
104: // array if the vector changes, like in the removeEntry method.
105: myInnerClassesArray = new InnerClassEntry[myInnerClassesVector
106: .size()];
107: // myInnerClassesVector.toArray(myInnerClassesArray);
108: myInnerClassesVector.copyInto(myInnerClassesArray);
109: }
110:
111: //__________ INSTANCE METHODS
112: protected int writeData(DataOutput o) throws IOException {
113: int numberOfInnerClasses = myInnerClassesVector.size();
114: o.writeShort(numberOfInnerClasses);
115:
116: Enumeration e = myInnerClassesVector.elements();
117: while (e.hasMoreElements()) {
118: ((InnerClassEntry) e.nextElement()).write(o);
119: }
120:
121: //return total number of bytes written, which is equal to
122: //2 (the number of bytes of the numberOfInnerClasses local
123: //variable) + the size of the InnerClassEntry * the number
124: //of inner classes.
125: return 2 + InnerClassEntry.SIZE * numberOfInnerClasses;
126: }
127:
128: public void mergeConstantsIntoSharedPool(ConstantPool sharedCP) {
129: InnerClassEntry ice;
130: Enumeration e = myInnerClassesVector.elements();
131: while (e.hasMoreElements()) {
132: ice = (InnerClassEntry) e.nextElement();
133:
134: if (ice.innerInfo != null) {
135: ice.innerInfo = (ClassConstant) sharedCP
136: .add(ice.innerInfo);
137: }
138: if (ice.outerInfo != null) {
139: ice.outerInfo = (ClassConstant) sharedCP
140: .add(ice.outerInfo);
141: }
142: }
143:
144: // Don't forget to update the array copy now that we've changed
145: // the vector.
146: myInnerClassesVector.copyInto(myInnerClassesArray);
147: }
148:
149: /*
150: * I am unsure exactly how this should operate. If innerInfo is null,
151: * should I still check the values of outerInfo and innerName? I would
152: * think that it wouldn't matter because if innerInfo is null, the other
153: * two should also be null.
154: */
155: public void countConstantReferences(boolean isRelocatable) {
156: super .countConstantReferences(isRelocatable);
157:
158: InnerClassEntry ice;
159: Enumeration e = myInnerClassesVector.elements();
160: while (e.hasMoreElements()) {
161: ice = (InnerClassEntry) e.nextElement();
162:
163: if (ice.innerInfo != null) {
164: ice.innerInfo.incReference();
165: }
166: if (ice.outerInfo != null) {
167: ice.outerInfo.incReference();
168: }
169: /*
170: * innerNameIndex not supported because utf8 cp entries
171: * are not kept around.
172: *
173: if (ice.innerName != null) {
174: ice.innerName.incReference();
175: }
176: */
177: }
178:
179: // Don't forget to update the array copy now that we've changed
180: // the vector.
181: myInnerClassesVector.copyInto(myInnerClassesArray);
182: }
183:
184: /*
185: * This method only called just before writing output.
186: * Make sure that all our ClassConstant entries end up in a constant
187: * pool. Call super.validate so it can check its fields, too.
188: */
189: public void validate() {
190: super .validate();
191: InnerClassEntry ice;
192: Enumeration e = myInnerClassesVector.elements();
193: while (e.hasMoreElements()) {
194: ice = (InnerClassEntry) e.nextElement();
195:
196: if (ice.innerInfo != null) {
197: ice.innerInfo.validate();
198: }
199: if (ice.outerInfo != null) {
200: ice.outerInfo.validate();
201: }
202: }
203: }
204:
205: public void removeEntry(int i) {
206: System.out.println("*** Removing inner class "
207: + myInnerClassesArray[i].getFullName());
208: // myInnerClassesVector.remove(myInnerClassesArray[i]);
209: myInnerClassesVector.removeElement(myInnerClassesArray[i]);
210:
211: // Don't forget to update the array copy now that we've changed
212: // the vector.
213: myInnerClassesArray = new InnerClassEntry[myInnerClassesVector
214: .size()];
215: // myInnerClassesVector.toArray(myInnerClassesArray);
216: myInnerClassesVector.copyInto(myInnerClassesArray);
217: }
218:
219: public int getInnerClassCount() {
220: return myInnerClassesVector.size();
221: }
222:
223: /*
224: * The following four methods return information about individual
225: * inner class entries contained in this attribute. These methods
226: * call corresponding methods in the InnerClassEntry class. They
227: * are self-explanatory.
228: */
229:
230: public int getInnerInfoIndex(int i) {
231: return myInnerClassesArray[i].getInnerInfoIndex();
232: }
233:
234: public int getOuterInfoIndex(int i) {
235: return myInnerClassesArray[i].getOuterInfoIndex();
236: }
237:
238: public int getInnerNameIndex(int i) {
239: return myInnerClassesArray[i].getInnerNameIndex();
240: }
241:
242: public int getAccessFlags(int i) {
243: return myInnerClassesArray[i].getAccessFlags();
244: }
245:
246: /*
247: * Like the above methods, these methods return information about
248: * an individual inner class entry. The string returned will be
249: * the name of the inner class, if it has one. If the inner class
250: * is anonymous, it will not have a name and the string "anonymous"
251: * will be returned.
252: */
253: public String getName(int i) {
254: return myInnerClassesArray[i].getName();
255: }
256:
257: /*
258: * Like the getName method, but return the outer class name as well.
259: */
260: public String getFullName(int i) {
261: return myInnerClassesArray[i].getFullName();
262: }
263: }
|