/*
* 03/21/2010
*
* Copyright (C) 2010 Robert Futrell
* robert_futrell at users.sourceforge.net
* http://fifesoft.com/rsyntaxtextarea
*
* This library is distributed under a modified BSD license. See the included
* RSTALanguageSupport.License.txt file for details.
*/
package org.fife.rsta.ac.java.classreader;
import java.io.*;
import java.util.*;
import org.fife.rsta.ac.java.classreader.attributes.*;
import org.fife.rsta.ac.java.classreader.constantpool.ConstantUtf8Info;
/**
* Represents a "field_info" structure as defined by the Java VM spec.
*
* @author Robert Futrell
* @version 1.0
*/
public class FieldInfo extends MemberInfo {
/**
* Index into the constant pool of a {@link ConstantUtf8Info} structure
* representing the field name, as a simple name.
*/
private int nameIndex; // u2
/**
* Index into the constant pool of a {@link ConstantUtf8Info} structure
* representing a valid field descriptor.
*/
private int descriptorIndex; // u2
/**
* An array of attributes of this field.
*/
private List attributes;
public static final String CONSTANT_VALUE = "ConstantValue";
/**
* Constructor.
*
* @see AccessFlags
*/
public FieldInfo(ClassFile cf, int accessFlags, int nameIndex,
int descriptorIndex) {
super(cf, accessFlags);
this.nameIndex = nameIndex;
this.descriptorIndex = descriptorIndex;
attributes = new ArrayList(1); // Usually 0 or 1?
}
/**
* Adds the specified attribute to this field.
*
* @param info Information about the attribute.
*/
public void addAttribute(AttributeInfo info) {
attributes.add(info);
}
/**
* Returns the specified attribute.
*
* @param index The index of the attribute.
* @return The attribute.
*/
public AttributeInfo getAttribute(int index) {
return (AttributeInfo)attributes.get(index);
}
/**
* Returns the number of attributes of this field.
*
* @return The number of attributes.
*/
public int getAttributeCount() {
return attributes.size();
}
public String getConstantValueAsString() {
ConstantValue cv = getConstantValueAttributeInfo();
return cv==null ? null : cv.getConstantValueAsString();
}
/**
* Returns the {@link ConstantValue} attribute info for this field, if any.
*
* @return The <code>ConstantValue</code> attribute, or <code>null</code>
* if there isn't one.
*/
private ConstantValue getConstantValueAttributeInfo() {
for (int i=0; i<getAttributeCount(); i++) {
AttributeInfo ai = (AttributeInfo)attributes.get(i);
if (ai instanceof ConstantValue) {
return (ConstantValue)ai;
}
}
return null;
}
/**
* Returns the field descriptor of this field.
*
* @return The field descriptor of this field.
*/
public String getDescriptor() {
return cf.getUtf8ValueFromConstantPool(descriptorIndex);
}
/**
* {@inheritDoc}
*/
public String getName() {
return cf.getUtf8ValueFromConstantPool(nameIndex);
}
/**
* Returns the index into the constant pool of a {@link ConstantUtf8Info}
* structure representing the field name, as a simple name.
*
* @return The index into the constant pool.
*/
public int getNameIndex() {
return nameIndex;
}
/**
* Returns the type of this field, as determined from its field descriptor.
*
* @return The type of this field.
*/
public String getTypeString(boolean qualified) {
StringBuffer sb = new StringBuffer();
String descriptor = getDescriptor();
int braceCount = descriptor.lastIndexOf('[') + 1;
switch (descriptor.charAt(braceCount)) {
// BaseType
case 'B':
sb.append("byte");
break;
case 'C':
sb.append("char");
break;
case 'D':
sb.append("double");
break;
case 'F':
sb.append("float");
break;
case 'I':
sb.append("int");
break;
case 'J':
sb.append("long");
break;
case 'S':
sb.append("short");
break;
case 'Z':
sb.append("boolean");
break;
// ObjectType
case 'L':
String clazz = descriptor.substring(braceCount+1,
descriptor.length()-1);
if(qualified) {
clazz = clazz.replace('/', '.');
}
else {
clazz = clazz.substring(clazz.lastIndexOf('/')+1);
}
sb.append(clazz);
break;
// Invalid field descriptor
default:
sb.append("UNSUPPORTED_TYPE_").append(descriptor);
break;
}
for (int i=0; i<braceCount; i++) {
sb.append("[]");
}
return sb.toString();
}
public boolean isConstant() {
return getConstantValueAttributeInfo()!=null;
}
/**
* Reads a <code>FieldInfo</code> structure from the specified input
* stream.
*
* @param cf The class file containing this field.
* @param in The input stream to read from.
* @return The field information read.
* @throws IOException If an IO error occurs.
*/
public static FieldInfo read(ClassFile cf, DataInputStream in)
throws IOException {
FieldInfo info = new FieldInfo(cf, in.readUnsignedShort(),
in.readUnsignedShort(),
in.readUnsignedShort());
int attrCount = in.readUnsignedShort();
for (int i=0; i<attrCount; i++) {
AttributeInfo ai = info.readAttribute(in);
if (ai!=null) {
info.addAttribute(ai);
}
}
return info;
}
/**
* Reads an attribute for this field from an input stream.
*
* @param in The input stream to read from.
* @return The attribute read, possibly <code>null</code> if it was known
* to be unimportant for our purposes.
* @throws IOException If an IO error occurs.
*/
private AttributeInfo readAttribute(DataInputStream in) throws IOException {
AttributeInfo ai = null;
int attributeNameIndex = in.readUnsignedShort();
int attributeLength = in.readInt();
String attrName = cf.getUtf8ValueFromConstantPool(attributeNameIndex);
if (CONSTANT_VALUE.equals(attrName)) { // 4.7.2
int constantValueIndex = in.readUnsignedShort();
ConstantValue cv = new ConstantValue(cf, constantValueIndex);
ai = cv;
}
// Attributes common to all members, or unhandled attributes.
else {
ai = super.readAttribute(in, attrName, attributeLength);
}
return ai;
}
}