- package com.sun.org.apache.bcel.internal.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 com.sun.org.apache.bcel.internal.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 ="com.sun.org.apache.bcel.internal.classfile.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.1.1 2001/10/29 19:59:57 jvanzyl 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
- * @throw 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
- * @throw 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>ClassFormatError</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
- * @throw IOException
- * @throw ClassFormatError
- */
- public JavaClass parse() throws IOException, ClassFormatError
- {
- /****************** 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 attributes of the class.
- * @throw IOException
- * @throw ClassFormatError
- */
- private final void readAttributes() throws IOException, ClassFormatError
- {
- 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.
- * @throw IOException
- * @throw ClassFormatError
- */
- private final void readClassInfo() throws IOException, ClassFormatError
- {
- 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 ClassFormatError("Class can't be both final and abstract");
-
- class_name_index = file.readUnsignedShort();
- superclass_name_index = file.readUnsignedShort();
- }
- /**
- * Read constant pool entries.
- * @throw IOException
- * @throw ClassFormatError
- */
- private final void readConstantPool() throws IOException, ClassFormatError
- {
- constant_pool = new ConstantPool(file);
- }
-
- /**
- * Read information about the fields of the class, i.e., its variables.
- * @throw IOException
- * @throw ClassFormatError
- */
- private final void readFields() throws IOException, ClassFormatError
- {
- 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.
- * @throw IOException
- * @throw ClassFormatError
- */
- private final void readID() throws IOException, ClassFormatError
- {
- int magic = 0xCAFEBABE;
-
- if(file.readInt() != magic)
- throw new ClassFormatError(file_name + " is not a Java .class file");
- }
- /**
- * Read information about the interfaces implemented by this class.
- * @throw IOException
- * @throw ClassFormatError
- */
- private final void readInterfaces() throws IOException, ClassFormatError
- {
- 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.
- * @throw IOException
- * @throw ClassFormatError
- */
- private final void readMethods() throws IOException, ClassFormatError
- {
- 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.
- * @throw IOException
- * @throw ClassFormatError
- */
- private final void readVersion() throws IOException, ClassFormatError
- {
- minor = file.readUnsignedShort();
- major = file.readUnsignedShort();
- }
- }