diff options
Diffstat (limited to 'bcel-builder/src/org/aspectj/apache/bcel/classfile/ClassParser.java')
-rw-r--r-- | bcel-builder/src/org/aspectj/apache/bcel/classfile/ClassParser.java | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/ClassParser.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/ClassParser.java new file mode 100644 index 000000000..03cb7d464 --- /dev/null +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/ClassParser.java @@ -0,0 +1,328 @@ +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 org.aspectj.apache.bcel.Constants; +import java.io.*; +import java.util.zip.*; + +/** + * 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.1 2004/11/18 14:48:11 aclement Exp $ + * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> + */ +public final class ClassParser { + private DataInputStream file; + private ZipFile zip; + private String file_name; + private int class_name_index, superclass_name_index; + private int major, minor; // Compiler version + private int access_flags; // Access rights of parsed class + private int[] interfaces; // Names of implemented interfaces + private ConstantPool constant_pool; // collection of constants + private Field[] fields; // class fields, i.e., its variables + private Method[] methods; // methods defined in the class + private Attribute[] attributes; // attributes defined in the class + private boolean is_zip; // Loaded from zip file + + private static final int BUFSIZE = 8192; + + /** + * Parse class from the given stream. + * + * @param file Input stream + * @param file_name File name + */ + public ClassParser(InputStream file, String file_name) { + this.file_name = file_name; + + String clazz = file.getClass().getName(); // Not a very clean solution ... + is_zip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar."); + + if(file instanceof DataInputStream) // Is already a data stream + this.file = (DataInputStream)file; + else + this.file = new DataInputStream(new BufferedInputStream(file, BUFSIZE)); + } + + /** Parse class from given .class file. + * + * @param file_name file name + * @throws IOException + */ + public ClassParser(String file_name) throws IOException + { + is_zip = false; + this.file_name = file_name; + file = new DataInputStream(new BufferedInputStream + (new FileInputStream(file_name), BUFSIZE)); + } + + /** Parse class from given .class file in a ZIP-archive + * + * @param file_name file name + * @throws IOException + */ + public ClassParser(String zip_file, String file_name) throws IOException + { + is_zip = true; + zip = new ZipFile(zip_file); + ZipEntry entry = zip.getEntry(file_name); + + this.file_name = file_name; + + file = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry), + 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). + * + * @return Class object representing the parsed class file + * @throws IOException + * @throws ClassFormatException + */ + 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(); + + // Check for unknown variables + //Unknown[] u = Unknown.getUnknownAttributes(); + //for(int i=0; i < u.length; i++) + // System.err.println("WARNING: " + u[i]); + + // Everything should have been read now + // if(file.available() > 0) { + // int bytes = file.available(); + // byte[] buf = new byte[bytes]; + // file.read(buf); + + // if(!(is_zip && (buf.length == 1))) { + // System.err.println("WARNING: Trailing garbage at end of " + file_name); + // System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf)); + // } + // } + + // Read everything of interest, so close the file + file.close(); + if(zip != null) + zip.close(); + + // Return the information we have gathered in a new object + return new JavaClass(class_name_index, superclass_name_index, + file_name, major, minor, access_flags, + constant_pool, interfaces, fields, + methods, attributes, is_zip? JavaClass.ZIP : JavaClass.FILE); + } + + /** + * Read information about the attributes of the class. + * @throws IOException + * @throws ClassFormatException + */ + private final void readAttributes() throws IOException, ClassFormatException + { + int attributes_count; + + attributes_count = file.readUnsignedShort(); + attributes = new Attribute[attributes_count]; + + for(int i=0; i < attributes_count; i++) + attributes[i] = Attribute.readAttribute(file, constant_pool); + } + + /** + * Read information about the class and its super class. + * @throws IOException + * @throws ClassFormatException + */ + private final void readClassInfo() throws IOException, ClassFormatException + { + access_flags = file.readUnsignedShort(); + + /* Interfaces are implicitely abstract, the flag should be set + * according to the JVM specification. + */ + if((access_flags & Constants.ACC_INTERFACE) != 0) + access_flags |= Constants.ACC_ABSTRACT; + + if(((access_flags & Constants.ACC_ABSTRACT) != 0) && + ((access_flags & Constants.ACC_FINAL) != 0 )) + throw new ClassFormatException("Class can't be both final and abstract"); + + class_name_index = file.readUnsignedShort(); + superclass_name_index = file.readUnsignedShort(); + } + /** + * Read constant pool entries. + * @throws IOException + * @throws ClassFormatException + */ + private final void readConstantPool() throws IOException, ClassFormatException + { + constant_pool = new ConstantPool(file); + } + + /** + * Read information about the fields of the class, i.e., its variables. + * @throws IOException + * @throws ClassFormatException + */ + private final void readFields() throws IOException, ClassFormatException + { + int fields_count; + + fields_count = file.readUnsignedShort(); + fields = new Field[fields_count]; + + for(int i=0; i < fields_count; i++) + fields[i] = new Field(file, constant_pool); + } + + /******************** Private utility methods **********************/ + + /** + * Check whether the header of the file is ok. + * Of course, this has to be the first action on successive file reads. + * @throws IOException + * @throws ClassFormatException + */ + private final void readID() throws IOException, ClassFormatException + { + int magic = 0xCAFEBABE; + + if(file.readInt() != magic) + throw new ClassFormatException(file_name + " is not a Java .class file"); + } + /** + * Read information about the interfaces implemented by this class. + * @throws IOException + * @throws ClassFormatException + */ + private final void readInterfaces() throws IOException, ClassFormatException + { + int interfaces_count; + + interfaces_count = file.readUnsignedShort(); + interfaces = new int[interfaces_count]; + + for(int i=0; i < interfaces_count; i++) + interfaces[i] = file.readUnsignedShort(); + } + /** + * Read information about the methods of the class. + * @throws IOException + * @throws ClassFormatException + */ + private final void readMethods() throws IOException, ClassFormatException + { + int methods_count; + + methods_count = file.readUnsignedShort(); + methods = new Method[methods_count]; + + for(int i=0; i < methods_count; i++) + methods[i] = new Method(file, constant_pool); + } + /** + * Read major and minor version of compiler which created the file. + * @throws IOException + * @throws ClassFormatException + */ + private final void readVersion() throws IOException, ClassFormatException + { + minor = file.readUnsignedShort(); + major = file.readUnsignedShort(); + } +} |