Source code: com/chaoswg/xtc4y/classdesc/ClassDescriptor.java
1 //$Header: /cvsroot/xtc4y/xtc4y/src/com/chaoswg/xtc4y/classdesc/ClassDescriptor.java,v 1.2 2003/08/25 10:50:14 toggm Exp $
2 /******************************************************************************
3 * XTC4y - eXtreme Testing Collection 4 you *
4 * -------------------------------------------------------------------------- *
5 * URL: http://www.chaoswg.com/xtc4y *
6 * Author: Mike Toggweiler (2.dog@gmx.ch) *
7 * *
8 * Last Updated: $Date: 2003/08/25 10:50:14 $, by $Author: toggm $ *
9 * Version: $Revision: 1.2 $ *
10 * -------------------------------------------------------------------------- *
11 * COPYRIGHT: (c) 2003 by Mike Toggweiler *
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 *****************************************************************************/
18 package com.chaoswg.xtc4y.classdesc;
19
20 import java.util.Vector;
21
22 import java.io.ByteArrayOutputStream;
23 import java.io.DataInputStream;
24 import java.io.DataOutputStream;
25 import java.io.IOException;
26
27 /**
28 * This container class represents the content of a class file in a readable
29 * and reditable way.
30 * For further informations about the java class fiel format, see the
31 * <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html">Java Virtual Machine Specification</a> §4. All mentioned references
32 * refere to the chapters and subchapters in this book.
33 * @author Mike Toggweiler
34 **/
35 public class ClassDescriptor {
36 /**
37 * Every class has to begin with this magic number
38 **/
39 public final static int MAGIC_NUMBER = 0xCAFEBABE;
40
41 private short minorVersion;
42 private short majorVersion;
43 private ClassAccessFlags classAccess;
44 private ClassCPEntry thisClass;
45 private ClassCPEntry superClass;
46 private Vector interfaces;
47 private Vector fields;
48 private Vector methods;
49 private Vector attributes;
50
51 /**
52 * Construct a new initial classDescriptor
53 **/
54 public ClassDescriptor() {
55 reset();
56 }
57
58 /**
59 * Construct a new ClassDescriptor and intialize it reading from a
60 * DataInputstream
61 * @param dis the DataInputStream to read from
62 **/
63 public ClassDescriptor(DataInputStream dis) throws IOException {
64 initialize(dis);
65 }
66
67 /**
68 * reset all variables to default values
69 **/
70 protected void reset() {
71 //initialise default values
72 minorVersion = 0;
73 majorVersion = 46;
74 classAccess = new ClassAccessFlags((short)0);
75 thisClass = null;
76 superClass = null;
77 interfaces = new Vector();
78 fields = new Vector();
79 methods = new Vector();
80 attributes = new Vector();
81 }
82
83 /**
84 * Initialize a ClassDescriptor by reading from a DataInputStream
85 * @param dis DataInputStream to read from
86 **/
87 public void initialize(DataInputStream dis) throws IOException {
88 reset();
89 //read the magic number
90 int magic = dis.readInt();
91 if (magic != MAGIC_NUMBER) {
92 throw new ClassFormatError("Magic number mismatch");
93 }
94
95 //minor
96 minorVersion = (short)dis.readUnsignedShort();
97 //major
98 majorVersion = (short)dis.readUnsignedShort();
99
100 //initialize constant pool
101 ConstantPool constantPool = new ConstantPool(dis);
102
103 //access_flags
104 classAccess = new ClassAccessFlags(dis);
105
106 //this_class
107 short classIndex = (short)dis.readUnsignedShort();
108 thisClass = (ClassCPEntry)constantPool.getCPEntryAt(classIndex);
109 constantPool.setThisClass(thisClass);
110 //super_class
111 short superIndex = (short)dis.readUnsignedShort();
112 if (superIndex != 0) {
113 superClass =
114 (ClassCPEntry)constantPool.getCPEntryAt(superIndex);
115 }
116 else {
117 superClass = null;
118 }
119
120 //interface_count
121 int ifCount = dis.readUnsignedShort();
122 //interfaces[interface_count]
123 interfaces.clear();
124 for (int i=0; i<ifCount; ++i) {
125 //interface
126 interfaces.add(new InterfaceInfo(dis, constantPool));
127 }
128
129 //fields_count
130 int fCount = dis.readUnsignedShort();
131 fields.clear();
132 //field_info[fields_count]
133 for (int i=0; i<fCount; ++i) {
134 //field_info
135 fields.add(new FieldInfo(dis, constantPool));
136 }
137
138 //methods_count
139 int mCount = dis.readUnsignedShort();
140 methods.clear();
141 //methods[methods_count]
142 for (int i=0; i<mCount; ++i) {
143 //method
144 methods.add(new MethodInfo(dis, constantPool));
145 }
146
147 //attributes_count
148 int aCount = dis.readUnsignedShort();
149 attributes.clear();
150 //attributes[attributes_count]
151 for (int i=0; i<aCount; ++i) {
152 attributes.add(new AttributeInfo(dis, constantPool));
153 }
154 }
155
156 /**
157 * Print the class onto a DataOutputStream
158 * @param dos the DataOutputStream to write on
159 **/
160 public void writeClass(DataOutputStream dos) throws IOException {
161 //magic_number
162 dos.writeInt(MAGIC_NUMBER);
163 //minor
164 dos.writeShort(minorVersion);
165 //major
166 dos.writeShort(majorVersion);
167
168 ConstantPool cp = new ConstantPool();
169 ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
170 DataOutputStream dos2 = new DataOutputStream(baos2);
171 ByteArrayOutputStream baos3 = new ByteArrayOutputStream();
172 DataOutputStream dos3 = new DataOutputStream(baos3);
173 cp.setThisClass(thisClass);
174
175 //let all register their variables and print on a dummy stream
176 //access_flags
177 classAccess.write(dos2);
178
179 //this_class
180 dos2.writeShort(cp.addCPEntry(thisClass));
181 //super_class
182 if (superClass != null) {
183 dos2.writeShort(cp.addCPEntry(superClass));
184 }
185 else {
186 dos2.writeShort((short)0);
187 }
188
189 //interface_count
190 dos2.writeShort(interfaces.size());
191 //interfaces[interface_count]
192 for (int i=0; i<interfaces.size(); ++i) {
193 //interface
194 ((InterfaceInfo)interfaces.elementAt(i)).write(dos2, cp);
195 }
196
197 //fields_count
198 dos2.writeShort(fields.size());
199 //field_info[fields_count]
200 for (int i=0; i<fields.size(); ++i) {
201 //field_info
202 ((FieldInfo)fields.elementAt(i)).write(dos2, cp);
203 }
204 //methods_count
205 dos2.writeShort(methods.size());
206 //methods[methods_count]
207 for (int i=0; i<methods.size(); ++i) {
208 //method
209 ((MethodInfo)methods.elementAt(i)).write(dos2, cp);
210 }
211
212 //attributes_count
213 dos2.writeShort(attributes.size());
214 //attributes[attributes_count]
215 for (int i=0; i<attributes.size(); ++i) {
216 ((AttributeInfo)attributes.elementAt(i)).write(dos2, cp);
217 }
218
219 //print out constant pool
220 cp.write(dos3);
221 //print out size of constant pool + 1
222 dos.writeShort(cp.getSize()+1);
223
224 //print out constant pool
225 byte[] constantPool = baos3.toByteArray();
226 dos.write(constantPool);
227 //print out previously created code
228 dos.write(baos2.toByteArray());
229
230 dos2.close();
231 baos2.close();
232 dos3.close();
233 baos3.close();
234 }
235
236 /**
237 * Set the minor version
238 * @param minor version to set
239 **/
240 public void setMinorVersion(short minor) {
241 minorVersion = minor;
242 }
243
244 /**
245 * @return the minor version
246 **/
247 public short getMinorVersion() {
248 return minorVersion;
249 }
250
251 /**
252 * Set the major version
253 * @param major version to set
254 **/
255 public void setMajorVersion(short major) {
256 majorVersion = major;
257 }
258
259 /**
260 * @return the major version
261 **/
262 public short getMajorVersion() {
263 return majorVersion;
264 }
265
266 /**
267 * set the classAccessFlag
268 **/
269 public void setClassAccess(ClassAccessFlags flags) {
270 classAccess = flags;
271 }
272
273 /**
274 * @return the classAccessFlag
275 **/
276 public ClassAccessFlags getClassAccessFlags() {
277 return classAccess;
278 }
279
280 /**
281 * Set the class
282 * @param cl the class cp entry representing this class
283 **/
284 public void setThisClass(ClassCPEntry cl) {
285 thisClass = cl;
286 }
287
288 /**
289 * @return the classCP Entry for this class
290 **/
291 public ClassCPEntry getThisClass() {
292 return thisClass;
293 }
294
295 /**
296 * Set the super class, null if no super class is present
297 * @param cl a class cp entry representing the super class
298 **/
299 public void setSuperClass(ClassCPEntry cl) {
300 superClass = cl;
301 }
302
303 /**
304 * @return the super class or null if no class is present
305 **/
306 public ClassCPEntry getSuperClass() {
307 return superClass;
308 }
309
310 /**
311 * Add an interface
312 * @param ifc an InterfaceInfo describing the direct super interface
313 **/
314 public void addInterface(InterfaceInfo ifc) {
315 interfaces.add(ifc);
316 }
317 /**
318 * @return an array of InterfaceInfos representing the direct super
319 * interfaces
320 **/
321 public InterfaceInfo[] getInterfaces() {
322 return ((InterfaceInfo[])
323 interfaces.toArray(new InterfaceInfo[interfaces.size()]));
324 }
325
326 /**
327 * Remove an interface
328 * @param ifc the interface to remove
329 **/
330 public void removeInterface(InterfaceInfo ifc) {
331 interfaces.remove(ifc);
332 }
333
334 /**
335 * Add a field to this class
336 * @param field the field to add
337 **/
338 public void addField(FieldInfo field) {
339 //TBD: check if field is not already defined (define equals method
340 //in the FieldInfo class and check against contains)
341 fields.add(field);
342 }
343
344 /**
345 * @return an array of Fields currently defined in this class
346 **/
347 public FieldInfo[] getFields() {
348 return ((FieldInfo[])fields.toArray(new FieldInfo[fields.size()]));
349 }
350
351 /**
352 * Remove a Field from the current class
353 * @param field the FieldInfo to remove
354 **/
355 public void removeField(FieldInfo field) {
356 fields.remove(field);
357 }
358
359 /**
360 * Add a method to this class
361 * @param method the method to add
362 **/
363 public void addMethod(MethodInfo method) {
364 methods.add(method);
365 }
366
367 /**
368 * @return an array of Methods currently defined in this class
369 **/
370 public MethodInfo[] getMethods() {
371 return ((MethodInfo[])methods.toArray(new MethodInfo[methods.size()]));
372 }
373
374 /**
375 * Remove a Method from the current class
376 * @param method the MethodInfo to remove
377 **/
378 public void removeMethod(MethodInfo method) {
379 methods.remove(method);
380 }
381
382 /**
383 * Add an attribute to this class
384 * @param attribute the attribute to add
385 **/
386 public void addAttribute(AttributeInfo attribute) {
387 attributes.add(attribute);
388 }
389
390 /**
391 * @return an array of Attributes currently defined in this class
392 **/
393 public AttributeInfo[] getAttributes() {
394 return
395 ((AttributeInfo[])
396 attributes.toArray(new AttributeInfo[attributes.size()]));
397 }
398
399 /**
400 * Remove an attribute from the current class
401 * @param attribute the AttributeInfo to remove
402 **/
403 public void removeAttribute(AttributeInfo attribute) {
404 attributes.remove(attribute);
405 }
406
407 /**
408 * Print the class descriptor in a readable way
409 **/
410 public String toString() {
411 String ret = "";
412 ret += "Minor: " + minorVersion + "\n";
413 ret += "Major: " + majorVersion + "\n";
414 ret += "ClassAccessFlag: " + classAccess + "\n";
415 ret += "ThisClass:" + thisClass + "\n";
416 ret += "SuperClass:" + superClass + "\n";
417 ret += "Interfaces:\n";
418 for (int i=0; i<interfaces.size(); ++i) {
419 ret += " " + i + " " + interfaces.elementAt(i) + "\n";
420 }
421 ret += "Fields:\n";
422 for (int i=0; i<fields.size(); ++i) {
423 ret += " " + i + " " + fields.elementAt(i) + "\n";
424 }
425 ret += "Methods:\n";
426 for (int i=0; i<methods.size(); ++i) {
427 ret += " " + i + " " + methods.elementAt(i) + "\n";
428 }
429 ret += "Attributes:\n";
430 for (int i=0; i<attributes.size(); ++i) {
431 ret += " " + i + " " + attributes.elementAt(i) + "\n";
432 }
433 return ret;
434 }
435 }