package org.nanovm.converter;
//
// NanoVMTool, Converter and Upload Tool for the NanoVM
// Copyright (C) 2005 by Till Harbaum <Till@Harbaum.org>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// 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 for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Parts of this tool are based on public domain code written by Kimberley
// Burchett: http://www.kimbly.com/code/classfile/
//
import java.io.*;
public final class ConstPoolEntry implements Cloneable {
public static final int UTF = 1;
public static final int UNICODE = 2;
public static final int INT = 3;
public static final int FLOAT = 4;
public static final int LONG = 5;
public static final int DOUBLE = 6;
public static final int CLASS = 7;
public static final int STRING = 8;
public static final int FIELDREF = 9;
public static final int METHODREF = 10;
public static final int INTERFACEMETHODREF = 11;
public static final int NAMEANDTYPE = 12;
private byte typecode = -1;
private String stringValue;
private int intValue;
private long longValue;
private float floatValue;
private double doubleValue;
private int index1, index2;
public boolean equals(Object o) {
ConstPoolEntry other;
try {
other = (ConstPoolEntry)o;
} catch (ClassCastException e) {
return false;
}
// For equality purposes, UTF and UNICODE typecodes are equivalent.
// We special case UTF and UNICODE comparison by ignoring typecode and
// just looking at stringValue.
if (stringValue != null && other.stringValue != null)
return stringValue.equals(other.stringValue);
if (typecode != other.typecode)
return false;
// This relies on fact that all unused fields are 0.
return (other.intValue == intValue &&
other.longValue == longValue &&
other.index1 == index1 &&
other.index2 == index2 &&
other.floatValue == floatValue &&
other.doubleValue == doubleValue);
}
public int hashCode() {
int result = typecode * 97;
if (stringValue != null)
result += stringValue.hashCode()*43;
result += intValue*37 + longValue*31 + index1*29 + index2*23;
return result;
}
public Object clone() {
ConstPoolEntry result = new ConstPoolEntry();
result.typecode = typecode;
result.stringValue = stringValue;
result.intValue = intValue;
result.longValue = longValue;
result.index1 = index1;
result.index2 = index2;
result.floatValue = floatValue;
result.doubleValue = doubleValue;
return result;
}
public String toString() {
if (UTF == typecode)
return "UTF \"" + stringValue + "\"";
else if (UNICODE == typecode)
return "UNICODE \"" + stringValue + "\"";
else if (INT == typecode)
return "INT " + intValue;
else if (FLOAT == typecode)
return "FLOAT " + floatValue;
else if (LONG == typecode)
return "LONG " + longValue;
else if (DOUBLE == typecode)
return "DOUBLE " + doubleValue;
else if (CLASS == typecode)
return "CLASS " + index1;
else if (STRING == typecode)
return "STRING " + index1;
else if (FIELDREF == typecode)
return "FIELDREF " + index1 + " " + index2;
else if (METHODREF == typecode)
return "METHODREF " + index1 + " " + index2;
else if (INTERFACEMETHODREF == typecode)
return "INTERFACEMETHODREF " + index1 + " " + index2;
else if (NAMEANDTYPE == typecode)
return "NAMEANDTYPE " + index1 + " " + index2;
else
return "Unknown typecode " + typecode;
}
public byte typecode() {
return typecode;
}
// used by set methods to erase evidence of any previous set method
private void clearType() {
typecode = -1;
stringValue = null;
index1 = 0;
index2 = 0;
intValue = 0;
longValue = 0;
floatValue = 0;
doubleValue = 0;
}
/**
* Some const pool entries don't actually exist -- like the ones after a
* LONG or DOUBLE, or entry 0. These entries are unused.
*/
public ConstPoolEntry setUnused() {
typecode = -1;
return this;
}
public boolean isUnused() {
return (typecode == -1);
}
public ConstPoolEntry setUTF(String value) {
clearType();
typecode = UTF;
stringValue = value;
if (null == stringValue)
throw new ConstPoolEntryError("ConstPoolEntry.setUTF called with null string");
return this;
}
public ConstPoolEntry setUnicode(String value) {
clearType();
typecode = UNICODE;
stringValue = value;
if (null == stringValue)
throw new ConstPoolEntryError("ConstPoolEntry.setUTF called with null string");
return this;
}
public ConstPoolEntry setInt(int value) {
clearType();
typecode = INT;
intValue = value;
return this;
}
public ConstPoolEntry setLong(long value) {
clearType();
typecode = LONG;
longValue = value;
return this;
}
public ConstPoolEntry setFloat(float value) {
clearType();
typecode = FLOAT;
floatValue = value;
return this;
}
public ConstPoolEntry setDouble(double value) {
clearType();
typecode = DOUBLE;
doubleValue = value;
return this;
}
public ConstPoolEntry setString(int index) {
clearType();
typecode = STRING;
index1 = index;
return this;
}
public ConstPoolEntry setClass(int index) {
clearType();
typecode = CLASS;
index1 = index;
return this;
}
public ConstPoolEntry setFieldRef(int index1, int index2) {
clearType();
typecode = FIELDREF;
this.index1 = index1;
this.index2 = index2;
return this;
}
public ConstPoolEntry setMethodRef(int index1, int index2) {
clearType();
typecode = METHODREF;
this.index1 = index1;
this.index2 = index2;
return this;
}
public ConstPoolEntry setInterfaceMethodRef(int index1, int index2) {
clearType();
typecode = INTERFACEMETHODREF;
this.index1 = index1;
this.index2 = index2;
return this;
}
public ConstPoolEntry setNameAndType(int index1, int index2) {
clearType();
typecode = NAMEANDTYPE;
this.index1 = index1;
this.index2 = index2;
return this;
}
/**
* For UTF and UNICODE entries.
*/
public String getString() {
if (UTF == typecode || UNICODE == typecode)
return stringValue;
throw getError("getString()");
}
/**
* For STRING entries.
*/
public int getStringIndex() {
if (STRING == typecode)
return index1;
throw getError("getStringIndex()");
}
/**
* For INT entries.
*/
public int getInt() {
if (INT == typecode)
return intValue;
throw getError("getInt()");
}
/**
* For LONG entries.
*/
public long getLong() {
if (LONG == typecode)
return longValue;
throw getError("getLong()");
}
/**
* For FLOAT entries.
*/
public float getFloat() {
if (FLOAT == typecode)
return floatValue;
throw getError("getFloat()");
}
/**
* For DOUBLE entries.
*/
public double getDouble() {
if (DOUBLE == typecode)
return doubleValue;
throw getError("getDouble()");
}
/**
* For INT, LONG, FLOAT, DOUBLE, UTF, or UNICODE entries,
* returns an Integer, Long, Float, Double, or String, respectively.
*/
public Object getPrimitiveTypeValue() {
if (UTF == typecode || UNICODE == typecode) return stringValue;
if (INT == typecode) return new Integer(intValue);
if (LONG == typecode) return new Long(longValue);
if (FLOAT == typecode) return new Float(floatValue);
if (DOUBLE == typecode) return new Double(doubleValue);
throw getError("getPrimitiveTypeValue()");
}
/**
* For CLASS entries.
*/
public int getClassNameIndex() {
if (CLASS == typecode)
return index1;
throw getError("getClassNameIndex()");
}
/**
* For FIELDREF, METHODREF, or INTERFACEMETHODREF entries.
*/
public int getClassIndex() {
if (FIELDREF == typecode || METHODREF == typecode
|| INTERFACEMETHODREF == typecode)
return index1;
throw getError("getClassIndex()");
}
/**
* For FIELDREF, METHODREF, or INTERFACEMETHODREF entries.
*/
public int getNameAndTypeIndex() {
if (FIELDREF == typecode || METHODREF == typecode
|| INTERFACEMETHODREF == typecode)
return index2;
throw getError("getNameAndTypeIndex()");
}
/**
* For NAMEANDTYPE entries.
*/
public int getNameIndex() {
if (NAMEANDTYPE == typecode)
return index1;
throw getError("getNameIndex()");
}
/**
* For NAMEANDTYPE entries.
*/
public int getTypeIndex() {
if (NAMEANDTYPE == typecode)
return index2;
throw getError("getTypeIndex()");
}
// utility method -- called when getXXXX() is
// called for inappropriate typecode
private ConstPoolEntryError getError(String method) {
return new ConstPoolEntryError(method +
" called on ConstPoolEntry with typecode " +
typecode());
}
public void read(DataInput in, ConstPoolEntry entry)
throws IOException {
byte tag = in.readByte();
switch (tag) {
case UTF:
entry.setUTF(in.readUTF());
break;
case UNICODE:
int length = in.readShort();
char[] chars = new char[length];
for (int i = 0; i < length; i++)
chars[i] = in.readChar();
String str = new String(chars);
entry.setUnicode(str);
break;
case INT:
entry.setInt(in.readInt());
break;
case FLOAT:
entry.setFloat(in.readFloat());
break;
case LONG:
entry.setLong(in.readLong());
break;
case DOUBLE:
entry.setDouble(in.readDouble());
break;
case CLASS:
entry.setClass(in.readShort());
break;
case STRING:
entry.setString(in.readShort());
break;
case FIELDREF:
entry.setFieldRef(in.readShort(), in.readShort());
break;
case METHODREF:
entry.setMethodRef(in.readShort(), in.readShort());
break;
case INTERFACEMETHODREF:
entry.setInterfaceMethodRef(in.readShort(), in.readShort());
break;
case NAMEANDTYPE:
entry.setNameAndType(in.readShort(), in.readShort());
break;
default:
throw new IOException("Unknown constant pool tag: " + tag);
}
}
}