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 (http://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 apache@apache.org.
 *
 * 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
 * <http://www.apache.org/>.
 */

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.
Author:M. Dahm
Version:$Id: ClassParser.java,v 1.6 2008/05/30 17:29:14 aclement Exp $
/** * Wrapper class that parses a given Java .class file. The method <A * href ="#parse">parse</A> returns a <A href ="JavaClass.html"> * JavaClass</A> 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 <A href="ftp://java.sun.com/docs/specs/vmspec.ps"> * JVM specification 1.0</a>. 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 <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> */
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
/** 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
/** 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).
/** * Parse the given Java class file and return an object that represents * the contained data, i.e., constants, methods, fields and commands. * A <em>ClassFormatException</em> 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
/** 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
/** 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
/** 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
/** 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
/** 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
/** 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
/** Read major and minor version of compiler which created the file */
private final void readVersion() throws IOException { minor = file.readUnsignedShort(); major = file.readUnsignedShort(); } }