1. package com.sun.org.apache.bcel.internal.classfile;
  2. /* ====================================================================
  3. * The Apache Software License, Version 1.1
  4. *
  5. * Copyright (c) 2001 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Apache" and "Apache Software Foundation" and
  28. * "Apache BCEL" must not be used to endorse or promote products
  29. * derived from this software without prior written permission. For
  30. * written permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * "Apache BCEL", nor may "Apache" appear in their name, without
  34. * prior written permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation. For more
  52. * information on the Apache Software Foundation, please see
  53. * <http://www.apache.org/>.
  54. */
  55. import com.sun.org.apache.bcel.internal.Constants;
  56. import java.io.*;
  57. import java.util.zip.*;
  58. /**
  59. * Wrapper class that parses a given Java .class file. The method
  60. * <A href ="#parse">parse</A> returns a
  61. * <A href ="com.sun.org.apache.bcel.internal.classfile.JavaClass.html">
  62. * JavaClass</A> object on success. When an I/O error or an
  63. * inconsistency occurs an appropiate exception is propagated back
  64. * to the caller.
  65. *
  66. * The structure and the names comply, except for a few conveniences,
  67. * exactly with the <A href="ftp://java.sun.com/docs/specs/vmspec.ps">
  68. * JVM specification 1.0</a>. See this paper for
  69. * further details about the structure of a bytecode file.
  70. *
  71. * @version $Id: ClassParser.java,v 1.1.1.1 2001/10/29 19:59:57 jvanzyl Exp $
  72. * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  73. */
  74. public final class ClassParser {
  75. private DataInputStream file;
  76. private ZipFile zip;
  77. private String file_name;
  78. private int class_name_index, superclass_name_index;
  79. private int major, minor; // Compiler version
  80. private int access_flags; // Access rights of parsed class
  81. private int[] interfaces; // Names of implemented interfaces
  82. private ConstantPool constant_pool; // collection of constants
  83. private Field[] fields; // class fields, i.e., its variables
  84. private Method[] methods; // methods defined in the class
  85. private Attribute[] attributes; // attributes defined in the class
  86. private boolean is_zip; // Loaded from zip file
  87. private static final int BUFSIZE = 8192;
  88. /**
  89. * Parse class from the given stream.
  90. *
  91. * @param file Input stream
  92. * @param file_name File name
  93. */
  94. public ClassParser(InputStream file, String file_name) {
  95. this.file_name = file_name;
  96. String clazz = file.getClass().getName(); // Not a very clean solution ...
  97. is_zip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar.");
  98. if(file instanceof DataInputStream) // Is already a data stream
  99. this.file = (DataInputStream)file;
  100. else
  101. this.file = new DataInputStream(new BufferedInputStream(file, BUFSIZE));
  102. }
  103. /** Parse class from given .class file.
  104. *
  105. * @param file_name file name
  106. * @throw IOException
  107. */
  108. public ClassParser(String file_name) throws IOException
  109. {
  110. is_zip = false;
  111. this.file_name = file_name;
  112. file = new DataInputStream(new BufferedInputStream
  113. (new FileInputStream(file_name), BUFSIZE));
  114. }
  115. /** Parse class from given .class file in a ZIP-archive
  116. *
  117. * @param file_name file name
  118. * @throw IOException
  119. */
  120. public ClassParser(String zip_file, String file_name) throws IOException
  121. {
  122. is_zip = true;
  123. zip = new ZipFile(zip_file);
  124. ZipEntry entry = zip.getEntry(file_name);
  125. this.file_name = file_name;
  126. file = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry),
  127. BUFSIZE));
  128. }
  129. /**
  130. * Parse the given Java class file and return an object that represents
  131. * the contained data, i.e., constants, methods, fields and commands.
  132. * A <em>ClassFormatError</em> is raised, if the file is not a valid
  133. * .class file. (This does not include verification of the byte code as it
  134. * is performed by the java interpreter).
  135. *
  136. * @return Class object representing the parsed class file
  137. * @throw IOException
  138. * @throw ClassFormatError
  139. */
  140. public JavaClass parse() throws IOException, ClassFormatError
  141. {
  142. /****************** Read headers ********************************/
  143. // Check magic tag of class file
  144. readID();
  145. // Get compiler version
  146. readVersion();
  147. /****************** Read constant pool and related **************/
  148. // Read constant pool entries
  149. readConstantPool();
  150. // Get class information
  151. readClassInfo();
  152. // Get interface information, i.e., implemented interfaces
  153. readInterfaces();
  154. /****************** Read class fields and methods ***************/
  155. // Read class fields, i.e., the variables of the class
  156. readFields();
  157. // Read class methods, i.e., the functions in the class
  158. readMethods();
  159. // Read class attributes
  160. readAttributes();
  161. // Check for unknown variables
  162. //Unknown[] u = Unknown.getUnknownAttributes();
  163. //for(int i=0; i < u.length; i++)
  164. // System.err.println("WARNING: " + u[i]);
  165. // Everything should have been read now
  166. // if(file.available() > 0) {
  167. // int bytes = file.available();
  168. // byte[] buf = new byte[bytes];
  169. // file.read(buf);
  170. // if(!(is_zip && (buf.length == 1))) {
  171. // System.err.println("WARNING: Trailing garbage at end of " + file_name);
  172. // System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf));
  173. // }
  174. // }
  175. // Read everything of interest, so close the file
  176. file.close();
  177. if(zip != null)
  178. zip.close();
  179. // Return the information we have gathered in a new object
  180. return new JavaClass(class_name_index, superclass_name_index,
  181. file_name, major, minor, access_flags,
  182. constant_pool, interfaces, fields,
  183. methods, attributes, is_zip? JavaClass.ZIP : JavaClass.FILE);
  184. }
  185. /**
  186. * Read information about the attributes of the attributes of the class.
  187. * @throw IOException
  188. * @throw ClassFormatError
  189. */
  190. private final void readAttributes() throws IOException, ClassFormatError
  191. {
  192. int attributes_count;
  193. attributes_count = file.readUnsignedShort();
  194. attributes = new Attribute[attributes_count];
  195. for(int i=0; i < attributes_count; i++)
  196. attributes[i] = Attribute.readAttribute(file, constant_pool);
  197. }
  198. /**
  199. * Read information about the class and its super class.
  200. * @throw IOException
  201. * @throw ClassFormatError
  202. */
  203. private final void readClassInfo() throws IOException, ClassFormatError
  204. {
  205. access_flags = file.readUnsignedShort();
  206. /* Interfaces are implicitely abstract, the flag should be set
  207. * according to the JVM specification.
  208. */
  209. if((access_flags & Constants.ACC_INTERFACE) != 0)
  210. access_flags |= Constants.ACC_ABSTRACT;
  211. if(((access_flags & Constants.ACC_ABSTRACT) != 0) &&
  212. ((access_flags & Constants.ACC_FINAL) != 0 ))
  213. throw new ClassFormatError("Class can't be both final and abstract");
  214. class_name_index = file.readUnsignedShort();
  215. superclass_name_index = file.readUnsignedShort();
  216. }
  217. /**
  218. * Read constant pool entries.
  219. * @throw IOException
  220. * @throw ClassFormatError
  221. */
  222. private final void readConstantPool() throws IOException, ClassFormatError
  223. {
  224. constant_pool = new ConstantPool(file);
  225. }
  226. /**
  227. * Read information about the fields of the class, i.e., its variables.
  228. * @throw IOException
  229. * @throw ClassFormatError
  230. */
  231. private final void readFields() throws IOException, ClassFormatError
  232. {
  233. int fields_count;
  234. fields_count = file.readUnsignedShort();
  235. fields = new Field[fields_count];
  236. for(int i=0; i < fields_count; i++)
  237. fields[i] = new Field(file, constant_pool);
  238. }
  239. /******************** Private utility methods **********************/
  240. /**
  241. * Check whether the header of the file is ok.
  242. * Of course, this has to be the first action on successive file reads.
  243. * @throw IOException
  244. * @throw ClassFormatError
  245. */
  246. private final void readID() throws IOException, ClassFormatError
  247. {
  248. int magic = 0xCAFEBABE;
  249. if(file.readInt() != magic)
  250. throw new ClassFormatError(file_name + " is not a Java .class file");
  251. }
  252. /**
  253. * Read information about the interfaces implemented by this class.
  254. * @throw IOException
  255. * @throw ClassFormatError
  256. */
  257. private final void readInterfaces() throws IOException, ClassFormatError
  258. {
  259. int interfaces_count;
  260. interfaces_count = file.readUnsignedShort();
  261. interfaces = new int[interfaces_count];
  262. for(int i=0; i < interfaces_count; i++)
  263. interfaces[i] = file.readUnsignedShort();
  264. }
  265. /**
  266. * Read information about the methods of the class.
  267. * @throw IOException
  268. * @throw ClassFormatError
  269. */
  270. private final void readMethods() throws IOException, ClassFormatError
  271. {
  272. int methods_count;
  273. methods_count = file.readUnsignedShort();
  274. methods = new Method[methods_count];
  275. for(int i=0; i < methods_count; i++)
  276. methods[i] = new Method(file, constant_pool);
  277. }
  278. /**
  279. * Read major and minor version of compiler which created the file.
  280. * @throw IOException
  281. * @throw ClassFormatError
  282. */
  283. private final void readVersion() throws IOException, ClassFormatError
  284. {
  285. minor = file.readUnsignedShort();
  286. major = file.readUnsignedShort();
  287. }
  288. }