org.aspectj.apache.bcel.classfile.ClassParser.java Source code

Java tutorial

Introduction

Here is the source code for org.aspectj.apache.bcel.classfile.ClassParser.java

Source

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 <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 */
    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 <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 */
    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();
    }

}