blob: e9d9b1b3df8561b5b9894b251a111ab1956314a7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.debugger.jpda.projects;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.openide.util.Exceptions;
/**
* Structured representation of the class constant pool.
*
* @author Martin Entlicher
*/
public class ConstantPool {
private static final byte TAG_UTF8 = 1;
private static final byte TAG_INTEGER = 3;
private static final byte TAG_FLOAT = 4;
private static final byte TAG_LONG = 5;
private static final byte TAG_DOUBLE = 6;
private static final byte TAG_CLASS = 7;
private static final byte TAG_STRING = 8;
private static final byte TAG_FIELDREF = 9;
private static final byte TAG_METHODREF = 10;
private static final byte TAG_INTERFACEREF = 11;
private static final byte TAG_NAMETYPE = 12;
private static final byte TAG_METHODHANDLE = 15;
private static final byte TAG_METHODTYPE = 16;
private static final byte TAG_CONSTANTDYNAMIC = 17;
private static final byte TAG_INVOKEDYNAMIC = 18;
private static final byte TAG_MODULE = 19;
private static final byte TAG_PACKAGE = 20;
private final List<ConstantPool.Entry> entries;
private final String description;
private ConstantPool(List<ConstantPool.Entry> entries, String description) {
this.entries = entries;
this.description = description;
}
public ConstantPool.Entry getEntry(int index) {
return entries.get(index);
}
/**
* @param index Index to constant pool entries
* @return method name
* @throws IndexOutOfBoundsException when the constant pool size is smaller than index.
*/
public String getMethodName(int index) {
try {
EntryFieldMethodRef methodRef = (EntryFieldMethodRef) entries.get(index);
return ((EntryUTF8) entries.get(((EntryNameType) entries.get(methodRef.nameAndTypeIndex)).getNameIndex())).getUTF8();
} catch (RuntimeException re) {
throw Exceptions.attachMessage(re, description);
}
}
/**
* @param index Index to constant pool entries
* @return method name
* @throws IndexOutOfBoundsException when the constant pool size is smaller than index.
*/
public String getMethodDescriptor(int index) {
try {
EntryFieldMethodRef methodRef = (EntryFieldMethodRef) entries.get(index);
return ((EntryUTF8) entries.get(((EntryNameType) entries.get(methodRef.nameAndTypeIndex)).getDescriptorIndex())).getUTF8();
} catch (RuntimeException re) {
throw Exceptions.attachMessage(re, description);
}
}
public static ConstantPool parse(byte[] bytes, String description) {
List<ConstantPool.Entry> entries = new ArrayList<ConstantPool.Entry>();
DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes));
entries.add(new EntryNULL());
try {
do {
byte tagByte;
try {
tagByte = in.readByte();
} catch (EOFException eof) {
break;
}
ConstantPool.Entry entry;
switch(tagByte) {
case TAG_UTF8:
entry = new EntryUTF8(in.readUTF());
break;
case TAG_INTEGER:
entry = new EntryInteger(in.readInt());
break;
case TAG_LONG:
entry = new EntryLong(in.readLong());
entries.add(entry);
entry = new EntryNULL(); // Long takes TWO constant pool entries!?!
break;
case TAG_FLOAT:
entry = new EntryFloat(in.readFloat());
break;
case TAG_DOUBLE:
entry = new EntryDouble(in.readDouble());
entries.add(entry);
entry = new EntryNULL(); // Double takes TWO constant pool entries!?!
break;
case TAG_CLASS:
entry = new EntryClass(in.readShort());
break;
case TAG_STRING:
entry = new EntryString(in.readShort());
break;
case TAG_NAMETYPE:
entry = new EntryNameType(in.readShort(), in.readShort());
break;
case TAG_FIELDREF:
case TAG_METHODREF:
case TAG_INTERFACEREF:
entry = new EntryFieldMethodRef(tagByte, in.readShort(), in.readShort());
break;
case TAG_METHODHANDLE:
entry = new EntryMethodHandle(in);
break;
case TAG_METHODTYPE:
entry = new EntryMethodType(in);
break;
case TAG_CONSTANTDYNAMIC:
entry = new EntryConstantDynamic(in);
break;
case TAG_INVOKEDYNAMIC:
entry = new EntryInvokeDynamic(in);
break;
case TAG_MODULE:
entry = new EntryModule(in.readShort());
break;
case TAG_PACKAGE:
entry = new EntryPackage(in.readShort());
break;
case 0:
default:
Logger.getLogger(ConstantPool.class.getName()).warning("Unknown tag byte: "+tagByte);
entry = new EntryNULL();
}
entries.add(entry);
} while(true);
} catch (IOException ioex) {
// Should not occur
Exceptions.printStackTrace(ioex);
}
return new ConstantPool(entries, description);
}
// Entries inner classes
public abstract static class Entry {
private final byte tag;
protected Entry(byte tag) {
this.tag = tag;
}
public final byte getTag() {
return tag;
}
}
public static class EntryNULL extends Entry {
public EntryNULL() {
super((byte) 0);
}
}
public static class EntryUTF8 extends Entry {
private String utf8;
public EntryUTF8(String utf8) {
super(TAG_UTF8);
this.utf8 = utf8;
}
public String getUTF8() {
return utf8;
}
}
public static class EntryInteger extends Entry {
private int i;
public EntryInteger(int i) {
super(TAG_INTEGER);
this.i = i;
}
public int getInteger() {
return i;
}
}
public static class EntryLong extends Entry {
private long l;
public EntryLong(long l) {
super(TAG_LONG);
this.l = l;
}
public long getLong() {
return l;
}
}
public static class EntryFloat extends Entry {
private float f;
public EntryFloat(float f) {
super(TAG_FLOAT);
this.f = f;
}
public float getFloat() {
return f;
}
}
public static class EntryDouble extends Entry {
private double d;
public EntryDouble(double d) {
super(TAG_DOUBLE);
this.d = d;
}
public double getDouble() {
return d;
}
}
public static class EntryClass extends Entry {
/** Refrence to TAG_UTF8 entry */
private short classRef;
public EntryClass(short classRef) {
super(TAG_CLASS);
this.classRef = classRef;
}
public short getClassRef() {
return classRef;
}
}
/**
* @since 1.41
*/
public static final class EntryModule extends Entry {
/** Reference to TAG_UTF8 entry */
private short nameIndex;
public EntryModule(short nameIndex) {
super(TAG_MODULE);
this.nameIndex = nameIndex;
}
public short getModuleRef() {
return nameIndex;
}
}
/**
* @since 1.41
*/
public static final class EntryPackage extends Entry {
/** Reference to TAG_UTF8 entry */
private short nameIndex;
public EntryPackage(short nameIndex) {
super(TAG_PACKAGE);
this.nameIndex = nameIndex;
}
public short getPackageRef() {
return nameIndex;
}
}
public static class EntryString extends Entry {
/** Refrence to TAG_UTF8 entry */
private short stringRef;
public EntryString(short stringRef) {
super(TAG_STRING);
this.stringRef = stringRef;
}
public short getStringRef() {
return stringRef;
}
}
public static class EntryNameType extends Entry {
private short nameIndex;
private short descriptorIndex;
public EntryNameType(short nameIndex, short descriptorIndex) {
super(TAG_NAMETYPE);
this.nameIndex = nameIndex;
this.descriptorIndex = descriptorIndex;
}
public short getNameIndex() {
return nameIndex;
}
public short getDescriptorIndex() {
return descriptorIndex;
}
}
public static class EntryFieldMethodRef extends Entry {
private short classIndex;
private short nameAndTypeIndex;
public EntryFieldMethodRef(byte type, short classIndex, short nameAndTypeIndex) {
super(type);
this.classIndex = classIndex;
this.nameAndTypeIndex = nameAndTypeIndex;
}
}
public static class BytesEntry extends Entry {
protected final byte[] bytes;
public BytesEntry(byte type, DataInputStream in, int length) throws IOException {
super(type);
byte[] b = new byte[length];
int l = in.read(b, 0, length);
while (l < length) {
l += in.read(b, l, length - l);
}
bytes = b;
}
}
public static class EntryMethodHandle extends BytesEntry {
public EntryMethodHandle(DataInputStream in) throws IOException {
super(TAG_METHODHANDLE, in, 3);
}
}
public static class EntryMethodType extends BytesEntry {
public EntryMethodType(DataInputStream in) throws IOException {
super(TAG_METHODTYPE, in, 2);
}
}
public static class EntryInvokeDynamic extends BytesEntry {
public EntryInvokeDynamic(DataInputStream in) throws IOException {
super(TAG_INVOKEDYNAMIC, in, 4);
}
}
public static class EntryConstantDynamic extends BytesEntry {
public EntryConstantDynamic(DataInputStream in) throws IOException {
super(TAG_CONSTANTDYNAMIC, in, 4);
}
}
}