--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassParser.java Tue Aug 08 22:52:41 2017 +0000
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassParser.java Sun Aug 13 21:10:40 2017 -0700
@@ -21,10 +21,15 @@
package com.sun.org.apache.bcel.internal.classfile;
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
-import com.sun.org.apache.bcel.internal.Constants;
-import java.io.*;
-import java.util.zip.*;
+import com.sun.org.apache.bcel.internal.Const;
/**
* Wrapper class that parses a given Java .class file. The method <A
@@ -34,262 +39,274 @@
* 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">
+ * exactly with the <A href="http://docs.oracle.com/javase/specs/">
* JVM specification 1.0</a>. See this paper for
* further details about the structure of a bytecode file.
*
- * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
+ * @version $Id: ClassParser.java 1749603 2016-06-21 20:50:19Z ggregory $
*/
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;
+ private DataInputStream dataInputStream;
+ private final boolean fileOwned;
+ private final String file_name;
+ private String zip_file;
+ private int class_name_index;
+ private int superclass_name_index;
+ private int major; // Compiler version
+ private int 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 final 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 the given stream.
+ *
+ * @param inputStream Input stream
+ * @param file_name File name
+ */
+ public ClassParser(final InputStream inputStream, final String file_name) {
+ this.file_name = file_name;
+ fileOwned = false;
+ final String clazz = inputStream.getClass().getName(); // Not a very clean solution ...
+ is_zip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar.");
+ if (inputStream instanceof DataInputStream) {
+ this.dataInputStream = (DataInputStream) inputStream;
+ } else {
+ this.dataInputStream = new DataInputStream(new BufferedInputStream(inputStream, 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 class from given .class file.
+ *
+ * @param file_name file name
+ */
+ public ClassParser(final String file_name) {
+ is_zip = false;
+ this.file_name = file_name;
+ fileOwned = true;
+ }
+
- /**
- * 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();
+ /** Parse class from given .class file in a ZIP-archive
+ *
+ * @param zip_file zip file name
+ * @param file_name file name
+ */
+ public ClassParser(final String zip_file, final String file_name) {
+ is_zip = true;
+ fileOwned = true;
+ this.zip_file = zip_file;
+ this.file_name = file_name;
+ }
- // 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);
+ /**
+ * 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 {
+ ZipFile zip = null;
+ try {
+ if (fileOwned) {
+ if (is_zip) {
+ zip = new ZipFile(zip_file);
+ final ZipEntry entry = zip.getEntry(file_name);
- // 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();
+ if (entry == null) {
+ throw new IOException("File " + file_name + " not found");
+ }
- // 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();
+ dataInputStream = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry),
+ BUFSIZE));
+ } else {
+ dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(
+ file_name), BUFSIZE));
+ }
+ }
+ /****************** 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));
+ // }
+ // }
+ } finally {
+ // Read everything of interest, so close the file
+ if (fileOwned) {
+ try {
+ if (dataInputStream != null) {
+ dataInputStream.close();
+ }
+ } catch (final IOException ioe) {
+ //ignore close exceptions
+ }
+ }
+ try {
+ if (zip != null) {
+ zip.close();
+ }
+ } catch (final IOException ioe) {
+ //ignore close exceptions
+ }
+ }
+ // 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);
+ }
- /* 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 attributes of the class.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private void readAttributes() throws IOException, ClassFormatException {
+ final int attributes_count = dataInputStream.readUnsignedShort();
+ attributes = new Attribute[attributes_count];
+ for (int i = 0; i < attributes_count; i++) {
+ attributes[i] = Attribute.readAttribute(dataInputStream, constant_pool);
+ }
+ }
- /**
- * 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];
+ /**
+ * Read information about the class and its super class.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private void readClassInfo() throws IOException, ClassFormatException {
+ access_flags = dataInputStream.readUnsignedShort();
+ /* Interfaces are implicitely abstract, the flag should be set
+ * according to the JVM specification.
+ */
+ if ((access_flags & Const.ACC_INTERFACE) != 0) {
+ access_flags |= Const.ACC_ABSTRACT;
+ }
+ if (((access_flags & Const.ACC_ABSTRACT) != 0)
+ && ((access_flags & Const.ACC_FINAL) != 0)) {
+ throw new ClassFormatException("Class " + file_name + " can't be both final and abstract");
+ }
+ class_name_index = dataInputStream.readUnsignedShort();
+ superclass_name_index = dataInputStream.readUnsignedShort();
+ }
- 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;
+ /**
+ * Read constant pool entries.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private void readConstantPool() throws IOException, ClassFormatException {
+ constant_pool = new ConstantPool(dataInputStream);
+ }
+
- 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;
+ /**
+ * Read information about the fields of the class, i.e., its variables.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private void readFields() throws IOException, ClassFormatException {
+ final int fields_count = dataInputStream.readUnsignedShort();
+ fields = new Field[fields_count];
+ for (int i = 0; i < fields_count; i++) {
+ fields[i] = new Field(dataInputStream, constant_pool);
+ }
+ }
+
- interfaces_count = file.readUnsignedShort();
- interfaces = new int[interfaces_count];
+ /******************** 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 void readID() throws IOException, ClassFormatException {
+ if (dataInputStream.readInt() != Const.JVM_CLASSFILE_MAGIC) {
+ throw new ClassFormatException(file_name + " is not a Java .class file");
+ }
+ }
- 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];
+ /**
+ * Read information about the interfaces implemented by this class.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private void readInterfaces() throws IOException, ClassFormatException {
+ final int interfaces_count = dataInputStream.readUnsignedShort();
+ interfaces = new int[interfaces_count];
+ for (int i = 0; i < interfaces_count; i++) {
+ interfaces[i] = dataInputStream.readUnsignedShort();
+ }
+ }
+
- 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();
- }
+ /**
+ * Read information about the methods of the class.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private void readMethods() throws IOException, ClassFormatException {
+ final int methods_count = dataInputStream.readUnsignedShort();
+ methods = new Method[methods_count];
+ for (int i = 0; i < methods_count; i++) {
+ methods[i] = new Method(dataInputStream, constant_pool);
+ }
+ }
+
+
+ /**
+ * Read major and minor version of compiler which created the file.
+ * @throws IOException
+ * @throws ClassFormatException
+ */
+ private void readVersion() throws IOException, ClassFormatException {
+ minor = dataInputStream.readUnsignedShort();
+ major = dataInputStream.readUnsignedShort();
+ }
}