• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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