286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/Apackage com.sun.org.apache.bcel.internal.classfile;
286N/A
286N/A/* ====================================================================
286N/A * The Apache Software License, Version 1.1
286N/A *
286N/A * Copyright (c) 2001 The Apache Software Foundation. All rights
286N/A * reserved.
286N/A *
286N/A * Redistribution and use in source and binary forms, with or without
286N/A * modification, are permitted provided that the following conditions
286N/A * are met:
286N/A *
286N/A * 1. Redistributions of source code must retain the above copyright
286N/A * notice, this list of conditions and the following disclaimer.
286N/A *
286N/A * 2. Redistributions in binary form must reproduce the above copyright
286N/A * notice, this list of conditions and the following disclaimer in
286N/A * the documentation and/or other materials provided with the
286N/A * distribution.
286N/A *
286N/A * 3. The end-user documentation included with the redistribution,
286N/A * if any, must include the following acknowledgment:
286N/A * "This product includes software developed by the
286N/A * Apache Software Foundation (http://www.apache.org/)."
286N/A * Alternately, this acknowledgment may appear in the software itself,
286N/A * if and wherever such third-party acknowledgments normally appear.
286N/A *
286N/A * 4. The names "Apache" and "Apache Software Foundation" and
286N/A * "Apache BCEL" must not be used to endorse or promote products
286N/A * derived from this software without prior written permission. For
286N/A * written permission, please contact apache@apache.org.
286N/A *
286N/A * 5. Products derived from this software may not be called "Apache",
286N/A * "Apache BCEL", nor may "Apache" appear in their name, without
286N/A * prior written permission of the Apache Software Foundation.
286N/A *
286N/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
286N/A * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
286N/A * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
286N/A * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
286N/A * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
286N/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
286N/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
286N/A * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
286N/A * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
286N/A * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
286N/A * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
286N/A * SUCH DAMAGE.
286N/A * ====================================================================
286N/A *
286N/A * This software consists of voluntary contributions made by many
286N/A * individuals on behalf of the Apache Software Foundation. For more
286N/A * information on the Apache Software Foundation, please see
286N/A * <http://www.apache.org/>.
286N/A */
286N/A
286N/Aimport com.sun.org.apache.bcel.internal.Constants;
286N/Aimport java.io.*;
286N/Aimport java.util.zip.*;
286N/A
286N/A/**
286N/A * Wrapper class that parses a given Java .class file. The method <A
286N/A * href ="#parse">parse</A> returns a <A href ="JavaClass.html">
286N/A * JavaClass</A> object on success. When an I/O error or an
286N/A * inconsistency occurs an appropiate exception is propagated back to
286N/A * the caller.
286N/A *
286N/A * The structure and the names comply, except for a few conveniences,
286N/A * exactly with the <A href="ftp://java.sun.com/docs/specs/vmspec.ps">
286N/A * JVM specification 1.0</a>. See this paper for
286N/A * further details about the structure of a bytecode file.
286N/A *
286N/A * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
286N/A */
286N/Apublic final class ClassParser {
286N/A private DataInputStream file;
286N/A private ZipFile zip;
286N/A private String file_name;
286N/A private int class_name_index, superclass_name_index;
286N/A private int major, minor; // Compiler version
286N/A private int access_flags; // Access rights of parsed class
286N/A private int[] interfaces; // Names of implemented interfaces
286N/A private ConstantPool constant_pool; // collection of constants
286N/A private Field[] fields; // class fields, i.e., its variables
286N/A private Method[] methods; // methods defined in the class
286N/A private Attribute[] attributes; // attributes defined in the class
286N/A private boolean is_zip; // Loaded from zip file
286N/A
286N/A private static final int BUFSIZE = 8192;
286N/A
286N/A /**
286N/A * Parse class from the given stream.
286N/A *
286N/A * @param file Input stream
286N/A * @param file_name File name
286N/A */
286N/A public ClassParser(InputStream file, String file_name) {
286N/A this.file_name = file_name;
286N/A
286N/A String clazz = file.getClass().getName(); // Not a very clean solution ...
286N/A is_zip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar.");
286N/A
286N/A if(file instanceof DataInputStream) // Is already a data stream
286N/A this.file = (DataInputStream)file;
286N/A else
286N/A this.file = new DataInputStream(new BufferedInputStream(file, BUFSIZE));
286N/A }
286N/A
286N/A /** Parse class from given .class file.
286N/A *
286N/A * @param file_name file name
286N/A * @throws IOException
286N/A */
286N/A public ClassParser(String file_name) throws IOException
286N/A {
286N/A is_zip = false;
286N/A this.file_name = file_name;
286N/A file = new DataInputStream(new BufferedInputStream
286N/A (new FileInputStream(file_name), BUFSIZE));
286N/A }
286N/A
286N/A /** Parse class from given .class file in a ZIP-archive
286N/A *
286N/A * @param file_name file name
286N/A * @throws IOException
286N/A */
286N/A public ClassParser(String zip_file, String file_name) throws IOException
286N/A {
286N/A is_zip = true;
286N/A zip = new ZipFile(zip_file);
286N/A ZipEntry entry = zip.getEntry(file_name);
286N/A
286N/A this.file_name = file_name;
286N/A
286N/A file = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry),
286N/A BUFSIZE));
286N/A }
286N/A
286N/A /**
286N/A * Parse the given Java class file and return an object that represents
286N/A * the contained data, i.e., constants, methods, fields and commands.
286N/A * A <em>ClassFormatException</em> is raised, if the file is not a valid
286N/A * .class file. (This does not include verification of the byte code as it
286N/A * is performed by the java interpreter).
286N/A *
286N/A * @return Class object representing the parsed class file
286N/A * @throws IOException
286N/A * @throws ClassFormatException
286N/A */
286N/A public JavaClass parse() throws IOException, ClassFormatException
286N/A {
286N/A /****************** Read headers ********************************/
286N/A // Check magic tag of class file
286N/A readID();
286N/A
286N/A // Get compiler version
286N/A readVersion();
286N/A
286N/A /****************** Read constant pool and related **************/
286N/A // Read constant pool entries
286N/A readConstantPool();
286N/A
286N/A // Get class information
286N/A readClassInfo();
286N/A
286N/A // Get interface information, i.e., implemented interfaces
286N/A readInterfaces();
286N/A
286N/A /****************** Read class fields and methods ***************/
286N/A // Read class fields, i.e., the variables of the class
286N/A readFields();
286N/A
286N/A // Read class methods, i.e., the functions in the class
286N/A readMethods();
286N/A
286N/A // Read class attributes
286N/A readAttributes();
286N/A
286N/A // Check for unknown variables
286N/A //Unknown[] u = Unknown.getUnknownAttributes();
286N/A //for(int i=0; i < u.length; i++)
286N/A // System.err.println("WARNING: " + u[i]);
286N/A
286N/A // Everything should have been read now
286N/A // if(file.available() > 0) {
286N/A // int bytes = file.available();
286N/A // byte[] buf = new byte[bytes];
286N/A // file.read(buf);
286N/A
286N/A // if(!(is_zip && (buf.length == 1))) {
286N/A // System.err.println("WARNING: Trailing garbage at end of " + file_name);
286N/A // System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf));
286N/A // }
286N/A // }
286N/A
286N/A // Read everything of interest, so close the file
286N/A file.close();
286N/A if(zip != null)
286N/A zip.close();
286N/A
286N/A // Return the information we have gathered in a new object
286N/A return new JavaClass(class_name_index, superclass_name_index,
286N/A file_name, major, minor, access_flags,
286N/A constant_pool, interfaces, fields,
286N/A methods, attributes, is_zip? JavaClass.ZIP : JavaClass.FILE);
286N/A }
286N/A
286N/A /**
286N/A * Read information about the attributes of the class.
286N/A * @throws IOException
286N/A * @throws ClassFormatException
286N/A */
286N/A private final void readAttributes() throws IOException, ClassFormatException
286N/A {
286N/A int attributes_count;
286N/A
286N/A attributes_count = file.readUnsignedShort();
286N/A attributes = new Attribute[attributes_count];
286N/A
286N/A for(int i=0; i < attributes_count; i++)
286N/A attributes[i] = Attribute.readAttribute(file, constant_pool);
286N/A }
286N/A
286N/A /**
286N/A * Read information about the class and its super class.
286N/A * @throws IOException
286N/A * @throws ClassFormatException
286N/A */
286N/A private final void readClassInfo() throws IOException, ClassFormatException
286N/A {
286N/A access_flags = file.readUnsignedShort();
286N/A
286N/A /* Interfaces are implicitely abstract, the flag should be set
286N/A * according to the JVM specification.
286N/A */
286N/A if((access_flags & Constants.ACC_INTERFACE) != 0)
286N/A access_flags |= Constants.ACC_ABSTRACT;
286N/A
286N/A if(((access_flags & Constants.ACC_ABSTRACT) != 0) &&
286N/A ((access_flags & Constants.ACC_FINAL) != 0 ))
286N/A throw new ClassFormatException("Class can't be both final and abstract");
286N/A
286N/A class_name_index = file.readUnsignedShort();
286N/A superclass_name_index = file.readUnsignedShort();
286N/A }
286N/A /**
286N/A * Read constant pool entries.
286N/A * @throws IOException
286N/A * @throws ClassFormatException
286N/A */
286N/A private final void readConstantPool() throws IOException, ClassFormatException
286N/A {
286N/A constant_pool = new ConstantPool(file);
286N/A }
286N/A
286N/A /**
286N/A * Read information about the fields of the class, i.e., its variables.
286N/A * @throws IOException
286N/A * @throws ClassFormatException
286N/A */
286N/A private final void readFields() throws IOException, ClassFormatException
286N/A {
286N/A int fields_count;
286N/A
286N/A fields_count = file.readUnsignedShort();
286N/A fields = new Field[fields_count];
286N/A
286N/A for(int i=0; i < fields_count; i++)
286N/A fields[i] = new Field(file, constant_pool);
286N/A }
286N/A
286N/A /******************** Private utility methods **********************/
286N/A
286N/A /**
286N/A * Check whether the header of the file is ok.
286N/A * Of course, this has to be the first action on successive file reads.
286N/A * @throws IOException
286N/A * @throws ClassFormatException
286N/A */
286N/A private final void readID() throws IOException, ClassFormatException
286N/A {
286N/A int magic = 0xCAFEBABE;
286N/A
286N/A if(file.readInt() != magic)
286N/A throw new ClassFormatException(file_name + " is not a Java .class file");
286N/A }
286N/A /**
286N/A * Read information about the interfaces implemented by this class.
286N/A * @throws IOException
286N/A * @throws ClassFormatException
286N/A */
286N/A private final void readInterfaces() throws IOException, ClassFormatException
286N/A {
286N/A int interfaces_count;
286N/A
286N/A interfaces_count = file.readUnsignedShort();
286N/A interfaces = new int[interfaces_count];
286N/A
286N/A for(int i=0; i < interfaces_count; i++)
286N/A interfaces[i] = file.readUnsignedShort();
286N/A }
286N/A /**
286N/A * Read information about the methods of the class.
286N/A * @throws IOException
286N/A * @throws ClassFormatException
286N/A */
286N/A private final void readMethods() throws IOException, ClassFormatException
286N/A {
286N/A int methods_count;
286N/A
286N/A methods_count = file.readUnsignedShort();
286N/A methods = new Method[methods_count];
286N/A
286N/A for(int i=0; i < methods_count; i++)
286N/A methods[i] = new Method(file, constant_pool);
286N/A }
286N/A /**
286N/A * Read major and minor version of compiler which created the file.
286N/A * @throws IOException
286N/A * @throws ClassFormatException
286N/A */
286N/A private final void readVersion() throws IOException, ClassFormatException
286N/A {
286N/A minor = file.readUnsignedShort();
286N/A major = file.readUnsignedShort();
286N/A }
286N/A}