Home | History | Annotate | Download | only in parser
      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      */
     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      */
     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      */
     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     {
     93         classParser (final UDataInputStream bytes)
     94         {
     95             m_bytes = bytes;
     96         }
     97 
     98 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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