aboutsummaryrefslogtreecommitdiffstats
path: root/bcel-builder/src/org/aspectj/apache/bcel/classfile/ClassParser.java
diff options
context:
space:
mode:
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.java328
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();
+ }
+}