org.aspectj.apache.bcel.classfile.ClassParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
Tools from the AspectJ project
package org.aspectj.apache.bcel.classfile;
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (https://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache BCEL" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact [email protected].
*
* 5. Products derived from this software may not be called "Apache",
* "Apache BCEL", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* .
*/
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.aspectj.apache.bcel.Constants;
/**
* Wrapper class that parses a given Java .class file. The method parse returns a
* JavaClass object on success. When an I/O error or an
* inconsistency occurs an appropiate exception is propagated back to
* the caller.
*
* The structure and the names comply, except for a few conveniences,
* exactly with the
* JVM specification 1.0. See this paper for
* further details about the structure of a bytecode file.
*
* @version $Id: ClassParser.java,v 1.6 2008/05/30 17:29:14 aclement Exp $
* @author M. Dahm
*/
public final class ClassParser {
private DataInputStream file;
private String filename;
private int classnameIndex;
private int superclassnameIndex;
private int major, minor;
private int accessflags;
private int[] interfaceIndices;
private ConstantPool cpool;
private Field[] fields;
private Method[] methods;
private Attribute[] attributes;
private static final int BUFSIZE = 8192;
/** Parse class from the given stream */
public ClassParser(InputStream file, String filename) {
this.filename = filename;
if (file instanceof DataInputStream) this.file = (DataInputStream)file;
else this.file = new DataInputStream(new BufferedInputStream(file,BUFSIZE));
}
public ClassParser(ByteArrayInputStream baos, String filename) {
this.filename = filename;
this.file = new DataInputStream(baos);
}
/** Parse class from given .class file */
public ClassParser(String file_name) throws IOException {
this.filename = file_name;
file = new DataInputStream(new BufferedInputStream(new FileInputStream(file_name),BUFSIZE));
}
/**
* Parse the given Java class file and return an object that represents
* the contained data, i.e., constants, methods, fields and commands.
* A ClassFormatException is raised, if the file is not a valid
* .class file. (This does not include verification of the byte code as it
* is performed by the java interpreter).
*/
public JavaClass parse() throws IOException, ClassFormatException {
/****************** Read headers ********************************/
// Check magic tag of class file
readID();
// Get compiler version
readVersion();
/****************** Read constant pool and related **************/
// Read constant pool entries
readConstantPool();
// Get class information
readClassInfo();
// Get interface information, i.e., implemented interfaces
readInterfaces();
/****************** Read class fields and methods ***************/
// Read class fields, i.e., the variables of the class
readFields();
// Read class methods, i.e., the functions in the class
readMethods();
// Read class attributes
readAttributes();
// Read everything of interest, so close the file
file.close();
// Return the information we have gathered in a new object
JavaClass jc= new JavaClass(classnameIndex, superclassnameIndex,
filename, major, minor, accessflags,
cpool, interfaceIndices, fields,
methods, attributes);
return jc;
}
/** Read information about the attributes of the class */
private final void readAttributes() {
attributes = AttributeUtils.readAttributes(file,cpool);
}
/** Read information about the class and its super class */
private final void readClassInfo() throws IOException {
accessflags = file.readUnsignedShort();
/* Interfaces are implicitely abstract, the flag should be set
* according to the JVM specification */
if((accessflags & Constants.ACC_INTERFACE) != 0)
accessflags |= Constants.ACC_ABSTRACT;
// don't police it like this... leave higher level verification code to check it.
// if(((access_flags & Constants.ACC_ABSTRACT) != 0) &&
// ((access_flags & Constants.ACC_FINAL) != 0 ))
// throw new ClassFormatException("Class can't be both final and abstract");
classnameIndex = file.readUnsignedShort();
superclassnameIndex = file.readUnsignedShort();
}
private final void readConstantPool() throws IOException {
try {
cpool = new ConstantPool(file);
} catch (ClassFormatException cfe) {
// add some context if we can
cfe.printStackTrace();
if (filename!=null) {
String newmessage = "File: '"+filename+"': "+cfe.getMessage();
throw new ClassFormatException(newmessage); // this loses the old stack trace but I dont think that matters!
}
throw cfe;
}
}
/** Read information about the fields of the class */
private final void readFields() throws IOException, ClassFormatException {
int fieldCount = file.readUnsignedShort();
if (fieldCount == 0) {
fields = Field.NoFields;
} else {
fields = new Field[fieldCount];
for(int i=0; i < fieldCount; i++)
fields[i] = new Field(file, cpool);
}
}
/** Check whether the header of the file is ok. Of course, this has
* to be the first action on successive file reads */
private final void readID() throws IOException {
int magic = 0xCAFEBABE;
if (file.readInt() != magic)
throw new ClassFormatException(filename + " is not a Java .class file");
}
private static final int[] NO_INTERFACES = new int[0];
/** Read information about the interfaces implemented by this class */
private final void readInterfaces() throws IOException {
int interfacesCount = file.readUnsignedShort();
if (interfacesCount==0) {
interfaceIndices = NO_INTERFACES;
} else {
interfaceIndices = new int[interfacesCount];
for(int i=0; i < interfacesCount; i++)
interfaceIndices[i] = file.readUnsignedShort();
}
}
/** Read information about the methods of the class */
private final void readMethods() throws IOException {
int methodsCount = file.readUnsignedShort();
if (methodsCount==0) {
methods = Method.NoMethods;
} else {
methods = new Method[methodsCount];
for(int i=0; i < methodsCount; i++)
methods[i] = new Method(file, cpool);
}
}
/** Read major and minor version of compiler which created the file */
private final void readVersion() throws IOException {
minor = file.readUnsignedShort();
major = file.readUnsignedShort();
}
}