< prev index next >

src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassParser.java

Print this page

        

@@ -19,93 +19,97 @@
  * limitations under the License.
  */
 
 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
  * 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">
+ * 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 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 boolean         is_zip; // Loaded from zip file
-
+    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 inputStream Input stream
    * @param file_name File name
    */
-  public ClassParser(InputStream file, String file_name) {
+    public ClassParser(final InputStream inputStream, final String file_name) {
     this.file_name = file_name;
-
-    String clazz = file.getClass().getName(); // Not a very clean solution ...
+        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(file instanceof DataInputStream) // Is already a data stream
-      this.file = (DataInputStream)file;
-    else
-      this.file = new DataInputStream(new BufferedInputStream(file, BUFSIZE));
+        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
-  {
+    public ClassParser(final String file_name) {
     is_zip = false;
     this.file_name = file_name;
-    file = new DataInputStream(new BufferedInputStream
-                               (new FileInputStream(file_name), BUFSIZE));
+        fileOwned = true;
   }
 
+
   /** Parse class from given .class file in a ZIP-archive
    *
+     * @param zip_file zip file name
    * @param file_name file name
-   * @throws IOException
    */
-  public ClassParser(String zip_file, String file_name) throws IOException
-  {
+    public ClassParser(final String zip_file, final String file_name) {
     is_zip = true;
-    zip = new ZipFile(zip_file);
-    ZipEntry entry = zip.getEntry(file_name);
-
+        fileOwned = true;
+        this.zip_file = zip_file;
     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

@@ -113,183 +117,196 @@
    *
    * @return Class object representing the parsed class file
    * @throws  IOException
    * @throws  ClassFormatException
    */
-  public JavaClass parse() throws IOException, 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 (entry == null) {
+                        throw new IOException("File " + file_name + " not found");
+                    }
+
+                    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++)
+            //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
-    file.close();
-    if(zip != null)
+            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);
+        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();
+    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(file, constant_pool);
+        for (int i = 0; i < attributes_count; i++) {
+            attributes[i] = Attribute.readAttribute(dataInputStream, 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();
-
+    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 & Constants.ACC_INTERFACE) != 0)
-      access_flags |= Constants.ACC_ABSTRACT;
+        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();
+    }
 
-    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);
+    private void readConstantPool() throws IOException, ClassFormatException {
+        constant_pool = new ConstantPool(dataInputStream);
   }
 
+
   /**
    * 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();
+    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(file, constant_pool);
+        for (int i = 0; i < fields_count; i++) {
+            fields[i] = new Field(dataInputStream, constant_pool);
+        }
   }
 
-  /******************** Private utility methods **********************/
 
+    /******************** 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)
+    private void readID() throws IOException, ClassFormatException {
+        if (dataInputStream.readInt() != Const.JVM_CLASSFILE_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();
+    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] = file.readUnsignedShort();
+        for (int i = 0; i < interfaces_count; i++) {
+            interfaces[i] = dataInputStream.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();
+    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(file, constant_pool);
+        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 final void readVersion() throws IOException, ClassFormatException
-  {
-    minor = file.readUnsignedShort();
-    major = file.readUnsignedShort();
+    private void readVersion() throws IOException, ClassFormatException {
+        minor = dataInputStream.readUnsignedShort();
+        major = dataInputStream.readUnsignedShort();
   }
 }
< prev index next >