Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.ArrayList;
import java.util.List;
import java.util.Map;
import org.fife.rsta.ac.java.classreader.attributes.*;
import org.fife.rsta.ac.java.classreader.constantpool.*;
/**
* Class representing a ClassFile structure.
*
* @author Robert Futrell
* @version 1.0
*/
public class ClassFile implements AccessFlags {
private static final boolean DEBUG = false;
/**
* The class file's minor version number.
*/
private int minorVersion; // u2
/**
* The class file's major version number.
*/
private int majorVersion; // u2
/**
* Constant pool infos.
*/
private ConstantPoolInfo[] constantPool; // Length constant_pool_count-1 !!
/**
* Permissions and properties of this class or interface.
*/
private int accessFlags; // u2
/**
* Index into {@link #constantPool} for a ConstantClassInfo
* structure representing the class or interface defined in this class file.
*/
private int thisClass; // u2
/**
* Index into {@link #constantPool} for a ConstantClassInfo
* structure representing the superclass of this class or interface. If
* this value is 0 then this class must be class
* java.lang.Object. If this is an interface, then this index
* must point to information about class java.lang.Object.
*/
private int superClass; // u2
/**
* Indices into {@code constantPool} for ConstantClassInfos
* representing the implemented interfaces of this class or interface.
*/
int[] interfaces; // u2[]
/**
* Structures giving complete descriptions of the fields in this class
* or interface.
*/
private FieldInfo[] fields;
/**
* Structures giving complete descriptions of the methods in this class or
* interface.
*/
private MethodInfo[] methods;
/**
* Whether this class is deprecated.
*/
private boolean deprecated;
/**
* Attributes of this class or interface.
*/
private AttributeInfo[] attributes;
/**
* Parameter types, such as "String" in List<String>.
*/
private List paramTypes;
/**
* A mapping of type parameters to type arguments. This is set via
* {@link #setTypeParamsToTypeArgs(Map)} during code completion of members of an
* instance variable whose type is represented by this class file. This
* ClassFile doesn't use this field itself; rather, it's there
* for consumers (such as the Java code completion API) to use.
*/
private Map typeMap;
public static final String DEPRECATED = "Deprecated";
public static final String ENCLOSING_METHOD = "EnclosingMethod";
public static final String INNER_CLASSES = "InnerClasses";
public static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
public static final String SIGNATURE = "Signature";
public static final String SOURCE_FILE = "SourceFile";
public static final String BOOTSTRAP_METHODS = "BootstrapMethods";
/**
* The 4-byte class file header, "CAFEBABE".
*/
private static final byte[] HEADER = { (byte)0xCA, (byte)0xFE,
(byte)0xBA, (byte)0xBE };
public ClassFile(File classFile) throws IOException {
try (DataInputStream in = new DataInputStream(new BufferedInputStream(
new FileInputStream(classFile)))) {
init(in);
}
}
public ClassFile(DataInputStream in) throws IOException {
init(in);
}
private void debugPrint(String text) {
if (DEBUG) {
System.out.println(text);
}
}
/**
* Returns the access flags for this class or interface.
*
* @return The access flags, as a bit field.
* @see AccessFlags
*/
public int getAccessFlags() {
return accessFlags;
}
/**
* Returns the specified attribute of this class file.
*
* @param index The index of the attribute.
* @return The attribute.
* @see #getAttributeCount()
*/
public AttributeInfo getAttribute(int index) {
return attributes[index];
}
/**
* Returns the number of attributes of this class file.
*
* @return The number of attributes.
* @see #getAttribute(int)
*/
public int getAttributeCount() {
return attributes==null ? 0 : attributes.length;
}
/**
* Returns the name of this class or interface.
*
* @param fullyQualified Whether the name should be fully-qualified.
* @return The name of this class or interface.
* @see #getSuperClassName(boolean)
*/
public String getClassName(boolean fullyQualified) {
return getClassNameFromConstantPool(thisClass, fullyQualified);
}
/**
* Given an index into the constant pool of a {@link ConstantClassInfo},
* this method returns the fully-qualified name of the class it points to.
*
* @param cpIndex The index into the constant pool. Note that
* this value is 1-based.
* @param fullyQualified Whether the returned class name should be fully
* qualified.
* @return The fully-qualified class or interface name.
*/
protected String getClassNameFromConstantPool(int cpIndex,
boolean fullyQualified) {
ConstantPoolInfo cpi = getConstantPoolInfo(cpIndex);
if (cpi instanceof ConstantClassInfo) {
ConstantClassInfo cci = (ConstantClassInfo)cpi;
int index = cci.getNameIndex();
ConstantUtf8Info cui = (ConstantUtf8Info)getConstantPoolInfo(index);
String className = cui.getRepresentedString(false);
if (fullyQualified) {
className = className.replace('/', '.');
}
else {
className = className.substring(className.lastIndexOf('/')+1);
}
return className.replace('$', '.');
}
// cpi is never null
throw new InternalError("Expected ConstantClassInfo, found " +
cpi.getClass().toString());
}
/**
* Returns the size of the constant pool, plus 1.
*
* @return The size of the constant pool, plus 1.
* @see #getConstantPoolInfo(int)
*/
public int getConstantPoolCount() {
return constantPool.length + 1;
}
/**
* Returns the constant pool entry at the specified index. Note that
* constant pool entries are 1-based (that is, valid indices
* are 1 - getConstantPoolCount()-1).
*
* @param index The index into the constant pool to retrieve.
* @return The constant pool entry, or null if
* index is 0 (e.g. this
* ClassFile object represents
* java.lang.Object).
* @see #getConstantPoolCount()
*/
public ConstantPoolInfo getConstantPoolInfo(int index) {
return index!=0 ? constantPool[index-1] : null;
}
/**
* Returns the number of fields declared in this class file.
*
* @return The number of fields.
* @see #getFieldInfo(int)
*/
public int getFieldCount() {
return fields==null ? 0 : fields.length;
}
/**
* Returns the specified field's information.
*
* @param index The index of the field info.
* @return The field's information.
* @see #getFieldCount()
* @see #getFieldInfoByName(String)
*/
public FieldInfo getFieldInfo(int index) {
return fields[index];
}
/**
* Returns a field's information by name.
*
* @param name The name of the field.
* @return The field's information.
* @see #getFieldCount()
* @see #getFieldInfo(int)
*/
public FieldInfo getFieldInfoByName(String name) {
for (int i=0; inull
* if none. This is a list of {@link MethodInfo}s.
* @see #getMethodInfoByName(String, int)
*/
public List getMethodInfoByName(String name) {
return getMethodInfoByName(name, -1);
}
/**
* Returns all method overloads with the specified name and number of
* arguments.
*
* @param name The method name.
* @param argCount The number of arguments. If this is less than zero,
* all overloads will be returned, regardless of argument count.
* @return Any method overloads with the given name and argument count, or
* null if none. This is a list of
* {@link MethodInfo}s.
* @see #getMethodInfoByName(String)
*/
public List getMethodInfoByName(String name, int argCount) {
List methods = null;
for (int i=0; i(1); // Usually just 1
}
methods.add(info);
}
}
}
return methods;
}
/**
* Returns the package for this class or interface.
*
* @return The package, or null if this class or interface
* is not in a package.
* @see #getClassName(boolean)
*/
public String getPackageName() {
String className = getClassName(true);
int dot = className.lastIndexOf('.');
return dot==-1 ? null : className.substring(0, dot);
}
public List getParamTypes() {
return paramTypes;
}
/**
* Returns the fully-qualified name of the superclass of this class or
* interface.
*
* @param fullyQualified Whether the returned value should be fully
* qualified.
* @return The name of the superclass of this class or interface. If this
* is an interface, then "java.lang.Object" is
* returned. If this class file represents
* java.lang.Object, then null is
* returned.
* @see #getClassName(boolean)
*/
public String getSuperClassName(boolean fullyQualified) {
if (superClass==0) { // This is java.lang.Object
return null;
}
return getClassNameFromConstantPool(superClass, fullyQualified);
}
/**
* Returns the currently set type argument for the specified type parameter.
*
* @param typeParam The type parameter.
* @return The type argument, or "Object" if no type
* parameters have been set. This is because, if the user types,
* say, "java.util.List list;" in Java 5+, the
* type defaults to Object. The code completion API
* may set the type argument mapping to null if no
* type arguments are scanned, thus we need to return
* Object in this case.
* @see #setTypeParamsToTypeArgs(Map)
*/
public String getTypeArgument(String typeParam) {
// If no type arguments are specified for a class that's supposed to
// have them (according to calling code), return "Object", as Java
// assumes this.
return typeMap==null ? "Object" : typeMap.get(typeParam);
}
/**
* Returns the string value represented by a ConstantUtf8Info
* entry in the constant pool.
*
* @param index The index into the constant pool of a
* ConstantUtf8Info structure. This should be
* 1-based.
* @return The string represented.
*/
public String getUtf8ValueFromConstantPool(int index) {
ConstantPoolInfo cpi = getConstantPoolInfo(index);
ConstantUtf8Info cui = (ConstantUtf8Info)cpi;
return cui.getRepresentedString(false);
}
/**
* Returns the version number of this class, as a string.
*
* @return The class's version number, in the form
* major.minor.
*/
public String getVersionString() {
return majorVersion + "." + minorVersion;
}
/**
* Parses the class file from a given input stream.
*
* @param in The input stream to read from.
* @throws IOException If an error occurs reading the class file.
*/
private void init(DataInputStream in) throws IOException {
readHeader(in);
readVersion(in);
readConstantPoolInfos(in);
readAccessFlags(in);
readThisClass(in);
readSuperClass(in);
readInterfaces(in);
readFields(in);
readMethods(in);
readAttributes(in);
}
/**
* Returns whether this class is deprecated.
*
* @return Whether this class is deprecated.
*/
public boolean isDeprecated() {
return deprecated;
}
/**
* Reads this class or interface's access flags.
*
* @param in The input stream to read from.
* @throws IOException If an error occurs reading the access flags.
*/
private void readAccessFlags(DataInputStream in) throws IOException {
accessFlags = in.readUnsignedShort();
debugPrint("Access flags: " + accessFlags);
}
/**
* Reads a single attribute of this class file.
*
* @param in The input stream to read from.
* @return The attribute.
* @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 = getUtf8ValueFromConstantPool(attributeNameIndex);
debugPrint("Found class attribute: " + attrName);
if (SOURCE_FILE.equals(attrName)) { // 4.7.7
int sourceFileIndex = in.readUnsignedShort();
ai = new SourceFile(this, sourceFileIndex);
}
else if (BOOTSTRAP_METHODS.equals(attrName)) { // 4.7.23
//String name = getClassFile().getClassName(false) + "." + getName();
//System.out.println(name + ": Attribute " + attrName + " not supported");
Util.skipBytes(in, attributeLength);
//ai = null;
}
else if (SIGNATURE.equals(attrName)) { // 4.8.8
int signatureIndex = in.readUnsignedShort();
String sig = getUtf8ValueFromConstantPool(signatureIndex);
//System.out.println("... Signature: " + sig);
ai = new Signature(this, sig);
paramTypes = ((Signature)ai).getClassParamTypes();
}
else if (INNER_CLASSES.equals(attrName)) { // 4.8.5
//String name = getClassName(false) + "." + getName();
//System.out.println(name + ": Attribute " + attrName + " not supported");
Util.skipBytes(in, attributeLength);
//ai = null;
}
else if (ENCLOSING_METHOD.equals(attrName)) { // 4.8.6
//String name = getClassName(false) + "." + getName();
//System.out.println(name + ": Attribute " + attrName + " not supported");
Util.skipBytes(in, attributeLength); // 2 u2's, class_index and method_index
//ai = null;
}
else if (DEPRECATED.equals(attrName)) { // 4.7.10
// No need to read anything else, attributeLength==0
deprecated = true;
}
else if (RUNTIME_VISIBLE_ANNOTATIONS.equals(attrName)) { // 4.8.15
//String name = getClassFile().getClassName(false) + "." + getName();
//System.out.println(name + ": Attribute " + attrName + " not supported");
Util.skipBytes(in, attributeLength);
//ai = null;
}
// TODO: Handle other useful Attribute types, if any.
else { // An unknown/unsupported attribute.
debugPrint("Unsupported class attribute: "+ attrName);
ai = AttributeInfo.readUnsupportedAttribute(this, in, attrName,
attributeLength);
}
return ai;
}
/**
* Reads this class file's attributes.
*
* @param in The input stream to read from.
* @throws IOException If an IO error occurs.
*/
private void readAttributes(DataInputStream in) throws IOException {
int attributeCount = in.readUnsignedShort();
if (attributeCount>0) {
attributes = new AttributeInfo[attributeCount];
for (int i=0; i0) {
fields = new FieldInfo[fieldCount];
for (int i=0; i0xCAFEBABE class file header.
*
* @param in The input stream to read from.
* @throws IOException If the header is invalid.
*/
private void readHeader(DataInputStream in) throws IOException {
for (byte b1 : HEADER) {
byte b = in.readByte();
if (b != b1) {
throw new IOException("\"CAFEBABE\" header not found");
}
}
}
/**
* Reads the array of indices into the constant pool for the names of the
* interfaces implemented by this class or interface.
*
* @param in The input stream to read from.
* @throws IOException If an IO error occurs reading the input stream.
*/
private void readInterfaces(DataInputStream in) throws IOException {
int interfaceCount = in.readUnsignedShort();
if (interfaceCount>0) {
interfaces = new int[interfaceCount];
for (int i=0; i0) {
methods = new MethodInfo[methodCount];
for (int i=0; iClassFile
* does not directly use this field; it is there for code completion API's
* to use to extract the necessary types of arguments, return values, etc.,
* of methods (see the {@link MethodInfo} class).
*
* @param typeMap A mapping of type parameters to type arguments (both
* Strings).
* @see #getTypeArgument(String)
*/
public void setTypeParamsToTypeArgs(Map typeMap) {
this.typeMap = typeMap;
for (int i=0; i