001: /*
002: * ConstantPool.java
003: *
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
005: *
006: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
007: *
008: * The contents of this file are subject to the terms of either the GNU
009: * General Public License Version 2 only ("GPL") or the Common
010: * Development and Distribution License("CDDL") (collectively, the
011: * "License"). You may not use this file except in compliance with the
012: * License. You can obtain a copy of the License at
013: * http://www.netbeans.org/cddl-gplv2.html
014: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
015: * specific language governing permissions and limitations under the
016: * License. When distributing the software, include this License Header
017: * Notice in each file and include the License file at
018: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
019: * particular file as subject to the "Classpath" exception as provided
020: * by Sun in the GPL Version 2 section of the License file that
021: * accompanied this code. If applicable, add the following below the
022: * License Header, with the fields enclosed by brackets [] replaced by
023: * your own identifying information:
024: * "Portions Copyrighted [year] [name of copyright owner]"
025: *
026: * Contributor(s):
027: *
028: * The Original Software is NetBeans. The Initial Developer of the Original
029: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
030: * Microsystems, Inc. All Rights Reserved.
031: *
032: * If you wish your version of this file to be governed by only the CDDL
033: * or only the GPL Version 2, indicate your decision by adding
034: * "[Contributor] elects to include this software in this distribution
035: * under the [CDDL or GPL Version 2] license." If you do not indicate a
036: * single choice of license, a recipient has the option to distribute
037: * your version of this file under either the CDDL, the GPL Version 2 or
038: * to extend the choice of license to its licensees as provided above.
039: * However, if you add GPL Version 2 code and therefore, elected the GPL
040: * Version 2 license, then the option applies only if the new code is
041: * made subject to such option by the copyright holder.
042: *
043: * Contributor(s): Thomas Ball
044: *
045: * Version: $Revision$
046: */
047:
048: package org.netbeans.modules.classfile;
049:
050: import java.io.*;
051: import java.util.*;
052:
053: /**
054: * Class representing a Java class file constant pool.
055: *
056: * @author Thomas Ball
057: */
058: public final class ConstantPool {
059:
060: private static final int CONSTANT_POOL_START = 1;
061:
062: // Constant Type enums (JVM spec table 4.3)
063: static final int CONSTANT_Utf8 = 1;
064: static final int CONSTANT_Integer = 3;
065: static final int CONSTANT_Float = 4;
066: static final int CONSTANT_Long = 5;
067: static final int CONSTANT_Double = 6;
068: static final int CONSTANT_Class = 7;
069: static final int CONSTANT_String = 8;
070: static final int CONSTANT_FieldRef = 9;
071: static final int CONSTANT_MethodRef = 10;
072: static final int CONSTANT_InterfaceMethodRef = 11;
073: static final int CONSTANT_NameAndType = 12;
074:
075: CPEntry[] cpEntries;
076:
077: int constantPoolCount = 0;
078:
079: /**
080: * Create a ConstantPool object from a stream of bytes.
081: *
082: * @param size number of entries in this constant pool.
083: * @param bytes a stream of bytes defining the constant pool.
084: */
085: /* package-private */ConstantPool(int size, InputStream bytes)
086: throws IOException {
087: if (size < 0)
088: throw new IllegalArgumentException(
089: "size cannot be negative");
090: if (bytes == null)
091: throw new IllegalArgumentException(
092: "byte stream not specified");
093: constantPoolCount = size;
094: cpEntries = new CPEntry[constantPoolCount];
095: load(bytes);
096: }
097:
098: /**
099: * Create a new ConstantPool object with no entries.
100: * NOTE: not supported until classfile writing is.
101: */
102: /*public*/ConstantPool() {
103: constantPoolCount = CONSTANT_POOL_START;
104: cpEntries = new CPEntry[constantPoolCount];
105: }
106:
107: /**
108: * Get the CPEntry at a specific constant pool index.
109: *
110: * @param index the constant pool index for the entry
111: */
112: public final CPEntry get(int index) {
113: if (index <= 0 || index >= cpEntries.length)
114: throw new IndexOutOfBoundsException(Integer.toString(index));
115: return cpEntries[index];
116: }
117:
118: /**
119: * Get the CPClassInfo at a specific index.
120: *
121: * @param index the constant pool index for the entry
122: */
123: public final CPClassInfo getClass(int index) {
124: if (index <= 0)
125: throw new IndexOutOfBoundsException(Integer.toString(index));
126: return (CPClassInfo) get(index);
127: }
128:
129: /* Return an array of all constants of a specified class type.
130: *
131: * @param type the constant pool type to return.
132: */
133: public final Collection getAllConstants(Class classType) {
134: return Collections
135: .unmodifiableCollection(getAllConstantsImpl(classType));
136: }
137:
138: private Collection<CPEntry> getAllConstantsImpl(Class classType) {
139: int n = cpEntries.length;
140: Collection<CPEntry> c = new ArrayList<CPEntry>(n);
141: for (int i = CONSTANT_POOL_START; i < n; i++) {
142: if (cpEntries[i] != null
143: && cpEntries[i].getClass().equals(classType)) {
144: c.add(cpEntries[i]);
145: }
146: }
147: return c;
148: }
149:
150: /* Return the collection of all unique class references in pool.
151: *
152: * @return a Set of ClassNames specifying the referenced classnames.
153: *
154: * @deprecated use <code>ClassFile.getAllClassNames()</code>,
155: * as all class references cannot be reliably determined from just
156: * the constant pool structure.
157: */
158: public final Set getAllClassNames() {
159: Set<ClassName> set = new HashSet<ClassName>();
160:
161: // include all class name constants
162: Collection c = getAllConstantsImpl(CPClassInfo.class);
163: for (Iterator i = c.iterator(); i.hasNext();) {
164: CPClassInfo ci = (CPClassInfo) i.next();
165: set.add(ci.getClassName());
166: }
167: return Collections.unmodifiableSet(set);
168: }
169:
170: final String getString(int index) {
171: CPUTF8Info utf = (CPUTF8Info) cpEntries[index];
172: return utf.getName();
173: }
174:
175: private void load(InputStream cpBytes) throws IOException {
176: try {
177: ConstantPoolReader cpr = new ConstantPoolReader(cpBytes);
178:
179: // Read in pool entries.
180: for (int i = CONSTANT_POOL_START; i < constantPoolCount; i++) {
181: CPEntry newEntry = getConstantPoolEntry(cpr);
182: cpEntries[i] = newEntry;
183:
184: if (newEntry.usesTwoSlots())
185: i++;
186: }
187:
188: // Resolve pool entries.
189: for (int i = CONSTANT_POOL_START; i < constantPoolCount; i++) {
190: CPEntry entry = cpEntries[i];
191: if (entry == null) {
192: continue;
193: }
194: entry.resolve(cpEntries);
195: }
196: } catch (IllegalArgumentException ioe) {
197: throw new InvalidClassFormatException(ioe);
198: } catch (IndexOutOfBoundsException iobe) {
199: throw new InvalidClassFormatException(iobe);
200: }
201: }
202:
203: private CPEntry getConstantPoolEntry(ConstantPoolReader cpr)
204: throws IOException {
205: CPEntry newEntry;
206: byte type = cpr.readByte();
207: switch (type) {
208: case CONSTANT_Utf8:
209: newEntry = new CPUTF8Info(this , cpr.readRawUTF());
210: break;
211:
212: case CONSTANT_Integer:
213: newEntry = new CPIntegerInfo(this , cpr.readInt());
214: break;
215:
216: case CONSTANT_Float:
217: newEntry = new CPFloatInfo(this , cpr.readFloat());
218: break;
219:
220: case CONSTANT_Long:
221: newEntry = new CPLongInfo(this , cpr.readLong());
222: break;
223:
224: case CONSTANT_Double:
225: newEntry = new CPDoubleInfo(this , cpr.readDouble());
226: break;
227:
228: case CONSTANT_Class: {
229: int nameIndex = cpr.readUnsignedShort();
230: newEntry = new CPClassInfo(this , nameIndex);
231: break;
232: }
233:
234: case CONSTANT_String: {
235: int nameIndex = cpr.readUnsignedShort();
236: newEntry = new CPStringInfo(this , nameIndex);
237: break;
238: }
239:
240: case CONSTANT_FieldRef: {
241: int classIndex = cpr.readUnsignedShort();
242: int natIndex = cpr.readUnsignedShort();
243: newEntry = new CPFieldInfo(this , classIndex, natIndex);
244: break;
245: }
246:
247: case CONSTANT_MethodRef: {
248: int classIndex = cpr.readUnsignedShort();
249: int natIndex = cpr.readUnsignedShort();
250: newEntry = new CPMethodInfo(this , classIndex, natIndex);
251: break;
252: }
253:
254: case CONSTANT_InterfaceMethodRef: {
255: int classIndex = cpr.readUnsignedShort();
256: int natIndex = cpr.readUnsignedShort();
257: newEntry = new CPInterfaceMethodInfo(this , classIndex,
258: natIndex);
259: break;
260: }
261:
262: case CONSTANT_NameAndType: {
263: int nameIndex = cpr.readUnsignedShort();
264: int descIndex = cpr.readUnsignedShort();
265: newEntry = new CPNameAndTypeInfo(this , nameIndex, descIndex);
266: break;
267: }
268:
269: default:
270: throw new IllegalArgumentException(
271: "invalid constant pool type: " + type);
272: }
273:
274: return newEntry;
275: }
276: }
|