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