1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. 2 * 3 * This program and the accompanying materials are made available under 4 * the terms of the Common Public License v1.0 which accompanies this distribution, 5 * and is available at http://www.eclipse.org/legal/cpl-v10.html 6 * 7 * $Id: ClassDefParser.java,v 1.1.1.1 2004/05/09 16:57:51 vlad_r Exp $ 8 */ 9 package com.vladium.jcd.parser; 10 11 import java.io.InputStream; 12 import java.io.IOException; 13 14 import com.vladium.jcd.cls.*; 15 import com.vladium.jcd.cls.attribute.*; 16 import com.vladium.jcd.cls.constant.*; 17 import com.vladium.jcd.lib.UDataInputStream; 18 import com.vladium.util.ByteArrayIStream; 19 20 // ---------------------------------------------------------------------------- 21 /** 22 * This class provides an API for parsing a stream or array of bytecodes into a 23 * {@link ClassDef} AST. 24 * 25 * @author (C) 2001, Vlad Roubtsov 26 */ 27 public 28 abstract class ClassDefParser 29 { 30 // public: ................................................................ 31 32 33 /** 34 * Parses an array of bytecodes into a {@link ClassDef}. 35 */ parseClass(final byte [] bytes)36 public static ClassDef parseClass (final byte [] bytes) 37 throws IOException 38 { 39 if (bytes == null) throw new IllegalArgumentException ("null input: bytes"); 40 41 classParser parser = new classParser (new UDataInputStream (new ByteArrayIStream (bytes))); 42 43 return parser.class_table (); 44 } 45 46 /** 47 * Parses an array of bytecodes into a {@link ClassDef}. 48 */ parseClass(final byte [] bytes, final int length)49 public static ClassDef parseClass (final byte [] bytes, final int length) 50 throws IOException 51 { 52 if (bytes == null) throw new IllegalArgumentException ("null input: bytes"); 53 54 classParser parser = new classParser (new UDataInputStream (new ByteArrayIStream (bytes, length))); 55 56 return parser.class_table (); 57 } 58 59 60 /** 61 * Parses a stream of bytecodes into a {@link ClassDef}. 62 */ parseClass(final InputStream bytes)63 public static ClassDef parseClass (final InputStream bytes) 64 throws IOException 65 { 66 if (bytes == null) throw new IllegalArgumentException ("null input: bytes"); 67 68 classParser parser = new classParser (new UDataInputStream (bytes)); 69 70 return parser.class_table (); 71 } 72 73 // protected: ............................................................. 74 75 // package: ............................................................... 76 77 78 static final boolean PARSE_SERIAL_VERSION_UID = true; 79 80 static final String SERIAL_VERSION_UID_FIELD_NAME = "serialVersionUID"; 81 static final int SERIAL_VERSION_UID_FIELD_MASK = IAccessFlags.ACC_STATIC | IAccessFlags.ACC_FINAL; 82 83 // private: ............................................................... 84 85 86 /** 87 * All the parsing work is done by this class and its class_table method. The 88 * work that needs to be done is not complicated, but is rather monotonous -- see 89 * Chapter 4 of VM spec 1.0 for the class file format. 90 */ 91 private static final class classParser 92 { classParser(final UDataInputStream bytes)93 classParser (final UDataInputStream bytes) 94 { 95 m_bytes = bytes; 96 } 97 98 class_table()99 ClassDef class_table () throws IOException 100 { 101 m_table = new ClassDef (); 102 103 104 magic (); 105 version (); 106 107 if (DEBUG) System.out.println (s_line); 108 109 constant_pool (); 110 111 if (DEBUG) System.out.println (s_line); 112 113 access_flags (); 114 this_class (); 115 super_class (); 116 117 if (DEBUG) System.out.println (s_line); 118 119 interfaces (); 120 if (DEBUG) System.out.println (s_line); 121 122 fields (); 123 if (DEBUG) System.out.println (s_line); 124 125 methods (); 126 if (DEBUG) System.out.println (s_line); 127 128 attributes (); 129 if (DEBUG) System.out.println (s_line); 130 131 return m_table; 132 } 133 134 magic()135 void magic () throws IOException 136 { 137 final long magic = m_bytes.readU4 (); 138 if (DEBUG) System.out.println ("magic: [" + Long.toHexString (magic) + ']'); 139 140 m_table.setMagic (magic); 141 } 142 143 version()144 void version () throws IOException 145 { 146 final int minor_version = m_bytes.readU2 (); 147 final int major_version = m_bytes.readU2 (); 148 149 if (DEBUG) 150 { 151 System.out.println ("major_version: [" + major_version + ']'); 152 System.out.println ("minor_version: [" + minor_version + ']'); 153 } 154 155 m_table.setVersion (new int [] {major_version, minor_version}); 156 } 157 158 constant_pool()159 void constant_pool () throws IOException 160 { 161 final int constant_pool_count = m_bytes.readU2 (); 162 if (DEBUG) System.out.println ("constant_pool_count = " + constant_pool_count + " [actual number of entries = " + (constant_pool_count - 1) + "]"); 163 164 final IConstantCollection constants = m_table.getConstants(); 165 166 for (int index = 1; index < constant_pool_count; ++ index) 167 { 168 final CONSTANT_info cp_info = CONSTANT_info.new_CONSTANT_info (m_bytes); 169 constants.add (cp_info); 170 171 if (DEBUG) System.out.println ("[" + index + "] constant: " + cp_info); 172 173 if ((cp_info instanceof CONSTANT_Long_info) || (cp_info instanceof CONSTANT_Double_info)) 174 index++; 175 } 176 } 177 178 access_flags()179 void access_flags () throws IOException 180 { 181 final int _access_flags = m_bytes.readU2 (); 182 183 m_table.setAccessFlags (_access_flags); 184 } 185 186 this_class()187 void this_class () throws IOException 188 { 189 final int _class_index = m_bytes.readU2 (); 190 if (DEBUG) System.out.println ("this_class: [" + _class_index + ']'); 191 192 m_table.setThisClassIndex (_class_index); 193 } 194 195 super_class()196 void super_class () throws IOException 197 { 198 final int _class_index = m_bytes.readU2 (); 199 if (DEBUG) System.out.println ("super_class: [" + _class_index + ']'); 200 201 m_table.setSuperClassIndex (_class_index); 202 } 203 204 interfaces()205 void interfaces () throws IOException 206 { 207 final int _interfaces_count = m_bytes.readU2 (); 208 if (DEBUG) System.out.println ("interfaces_count = " + _interfaces_count); 209 210 for (int i = 0; i < _interfaces_count; i++) 211 { 212 int _interface_index = m_bytes.readU2 (); 213 if (DEBUG) System.out.println ("[" + i + "] interface: " + _interface_index); 214 215 m_table.getInterfaces().add (_interface_index); 216 } 217 } 218 219 fields()220 void fields () throws IOException 221 { 222 final int _fields_count = m_bytes.readU2 (); 223 if (DEBUG) System.out.println ("fields_count = " + _fields_count); 224 225 final IConstantCollection constantPool = m_table.getConstants (); 226 227 for (int i = 0; i < _fields_count; i++) 228 { 229 final Field_info field_info = new Field_info (constantPool, m_bytes); 230 if (DEBUG) 231 { 232 System.out.println ("[" + i + "] field: " + field_info); 233 System.out.println (); 234 } 235 236 m_table.getFields().add (field_info); 237 238 if (PARSE_SERIAL_VERSION_UID) 239 240 if (((field_info.getAccessFlags () & SERIAL_VERSION_UID_FIELD_MASK) == SERIAL_VERSION_UID_FIELD_MASK) 241 && SERIAL_VERSION_UID_FIELD_NAME.equals (field_info.getName (m_table))) 242 { 243 final IAttributeCollection attributes = field_info.getAttributes (); 244 for (int a = 0, aLimit = attributes.size (); a < aLimit; ++ a) 245 { 246 final Attribute_info attr_info = attributes.get (a); 247 248 if (attr_info instanceof ConstantValueAttribute_info) 249 { 250 final CONSTANT_literal_info constant_value = ((ConstantValueAttribute_info) attr_info).getValue (m_table); 251 if (constant_value instanceof CONSTANT_Long_info) 252 m_table.setDeclaredSUID (((CONSTANT_Long_info) constant_value).m_value); 253 } 254 } 255 } 256 } 257 } 258 259 methods()260 void methods () throws IOException 261 { 262 final int _methods_count = m_bytes.readU2 (); 263 if (DEBUG) System.out.println ("methods_count = " + _methods_count); 264 265 final IConstantCollection constantPool = m_table.getConstants (); 266 267 for (int i = 0; i < _methods_count; i++) 268 { 269 final Method_info method_info = new Method_info (constantPool, m_bytes); 270 if (DEBUG) 271 { 272 System.out.println ("[" + i + "] method: " + method_info); 273 System.out.println (); 274 } 275 276 m_table.getMethods().add (method_info); 277 } 278 } 279 280 attributes()281 void attributes () throws IOException 282 { 283 final int _attributes_count = m_bytes.readU2 (); 284 if (DEBUG) System.out.println ("attributes_count = " + _attributes_count); 285 286 IConstantCollection constantPool = m_table.getConstants (); 287 288 for (int i = 0; i < _attributes_count; i++) 289 { 290 Attribute_info attribute_info = Attribute_info.new_Attribute_info (constantPool, m_bytes); 291 if (DEBUG) 292 { 293 System.out.println ("[" + i + "] attribute: " + attribute_info); 294 System.out.println (); 295 } 296 297 m_table.getAttributes().add (attribute_info); 298 } 299 } 300 301 302 private final UDataInputStream m_bytes; 303 private ClassDef m_table; 304 305 private static final boolean DEBUG = false; 306 private static final String s_line = "------------------------------------------------------------------------"; 307 308 } // end of static class 309 310 } // end of class 311 // ---------------------------------------------------------------------------- 312