1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.jdo.impl.enhancer.classfile;
20
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Vector;
24 import java.util.Hashtable;
25 import java.util.Enumeration;
26 import java.io.*;
27 import java.security.MessageDigest;
28 import java.security.DigestOutputStream;
29 import java.security.NoSuchAlgorithmException;
30 import java.io.DataOutputStream;
31
32
33 /***
34 * ClassFile models the structure of a class as represented within
35 * a class file.
36 */
37 final public class ClassFile implements VMConstants, Serializable {
38
39
40 public static final int magic = 0xcafebabe;
41
42
43
44 public static final short[] [] jdkMajorMinorVersions = new short[][] {
45 new short[] {45,3},
46 new short[] {46,0},
47 new short[] {47,0},
48 new short[] {48,0}
49 };
50 public static final List jdkVersions =
51 convertMajorMinorVersions(jdkMajorMinorVersions);
52
53 public static final String supportedVersions = printSupportedVersions();
54
55 private int majorVersion = 0;
56 private int minorVersion = 0;
57
58
59 private ConstantPool constantPool = new ConstantPool();
60
61
62 private int accessFlags = 0;
63
64
65 private ConstClass thisClassName;
66
67
68 private ConstClass superClassName;
69
70
71
72
73 private Vector classInterfaces = new Vector();
74
75
76
77
78 private Vector classFields = new Vector();
79
80
81
82
83 private Vector classMethods = new Vector();
84
85
86 private AttributeVector classAttributes = new AttributeVector();
87
88 /*** Static methods
89 * Added for major.minor compatibility checking
90 */
91 private static List convertMajorMinorVersions(short[][] majorMinor) {
92 int length = majorMinor.length;
93 List result = new ArrayList(length);
94 for (int i = 0; i < length; i++) {
95 result.add(new Integer(majorMinor[i][0] * 65536 + majorMinor[i][1]));
96 }
97 return result;
98 }
99
100 private static boolean isSupportedVersion(short major, short minor) {
101 Integer version = new Integer(major*65536 + minor);
102 return jdkVersions.contains(version);
103 }
104
105 public static final String printSupportedVersions() {
106 StringBuffer buf = new StringBuffer("{");
107 int length = jdkMajorMinorVersions.length;
108 for (int i = 0; i < length; i++) {
109 int major = jdkMajorMinorVersions[i][0];
110 int minor = jdkMajorMinorVersions[i][1];
111 buf.append("{"); buf.append(major); buf.append(",");
112 buf.append(minor); buf.append("}");
113 }
114 buf.append("}");
115 return buf.toString();
116 }
117
118
119
120
121
122 /***
123 * Return the constant pool for the class file
124 */
125 public ConstantPool pool() {
126 return constantPool;
127 }
128
129 /***
130 * Return the access flags for the class - see VMConstants
131 */
132 public int access() {
133 return accessFlags;
134 }
135
136 /***
137 * Is the class final?
138 */
139 final public boolean isFinal() {
140 return (accessFlags & ACCFinal) != 0;
141 }
142
143 /***
144 * Is the class an interface?
145 */
146 final public boolean isInterface() {
147 return (accessFlags & ACCInterface) != 0;
148 }
149
150 /***
151 * Is the class public?
152 */
153 final public boolean isPublic() {
154 return (accessFlags & ACCPublic) != 0;
155 }
156
157 /***
158 * Is the class abstract?
159 */
160 final public boolean isAbstract() {
161 return (accessFlags & ACCAbstract) != 0;
162 }
163
164
165 /***
166 * Set the access flags for the class - see VMConstants
167 */
168 public void setAccessFlags (int flags) {
169 accessFlags = flags;
170 }
171
172 /***
173 * Return the name of the class
174 */
175 public ConstClass className() {
176 return thisClassName;
177 }
178
179 /***
180 * Return the name of the class as a string
181 */
182
183 public String classNameString() {
184 return (thisClassName == null) ? null : thisClassName.asString();
185 }
186
187 /***
188 * Return the name of the super class
189 */
190 public ConstClass superName() {
191 return superClassName;
192 }
193
194 /***
195 * Return the name of the super class as a string
196 */
197 public String superNameString() {
198 return (superClassName == null) ? null : superClassName.asString();
199 }
200
201 /***
202 * Set the name of the super class
203 */
204 public void setSuperName(ConstClass superCl) {
205 superClassName = superCl;
206 }
207
208 /***
209 * Return the list of the interfaces which the class implements
210 * The contents are ConstClass objects
211 */
212 public Vector interfaces() {
213 return classInterfaces;
214 }
215
216 /***
217 * Add an interface to the list of the interfaces which the class implements
218 */
219 public void addInterface (ConstClass iface) {
220 classInterfaces.addElement(iface);
221 }
222
223 /***
224 * Return the list of the fields which the class contains
225 * The contents are ClassField objects
226 */
227 public Vector fields() {
228 return classFields;
229 }
230
231 /***
232 * Add a field to the list of the fields which the class contains
233 */
234 public void addField (ClassField field) {
235 classFields.addElement(field);
236 }
237
238 /***
239 * Add a field to the list of the fields which the class contains,
240 * at the index'th position.
241 */
242 public void addField(ClassField field, int index) {
243 classFields.insertElementAt(field, index);
244 }
245
246 /***
247 * Return the list of the methods which the class defines
248 * The contents are ClassMethod objects
249 */
250 public Vector methods() {
251 return classMethods;
252 }
253
254 /***
255 * Look for a method with the specified name and type signature
256 */
257 public ClassMethod findMethod(String methodName, String methodSig) {
258 for (Enumeration e = methods().elements(); e.hasMoreElements();) {
259 ClassMethod method = (ClassMethod) e.nextElement();
260 if (method.name().asString().equals(methodName) &&
261 method.signature().asString().equals(methodSig))
262 return method;
263 }
264 return null;
265 }
266
267 /***
268 * Add a method to the list of the methods which the class defines
269 */
270 public void addMethod(ClassMethod method) {
271 classMethods.addElement(method);
272 }
273
274 /***
275 * Look for a field with the specified name
276 */
277 public ClassField findField(String fieldName) {
278 for (Enumeration e = fields().elements(); e.hasMoreElements();) {
279 ClassField field = (ClassField) e.nextElement();
280 if (field.name().asString().equals(fieldName))
281 return field;
282 }
283 return null;
284 }
285
286 /***
287 * Return the list of the attributes associated with the class
288 */
289 public AttributeVector attributes() {
290 return classAttributes;
291 }
292
293 /***
294 * Returns the class name in user ('.' delimited) form.
295 */
296
297 public String userClassName()
298 {
299 return userClassFromVMClass(classNameString());
300 }
301
302 /***
303 * Returns the class name in user ('.' delimited) form.
304 */
305
306 static public String userClassFromVMClass(String vmName)
307 {
308 return vmName.replace('/', '.');
309 }
310
311 /***
312 * Returns the class name in VM ('/' delimited) form.
313 */
314
315 static public String vmClassFromUserClass(String userName)
316 {
317 return userName.replace('.', '/');
318 }
319
320 /***
321 * Returns the vm package name for this class.
322 */
323
324 public String pkg()
325 {
326 return</strong> packageOf(classNameString());
327 }
328
329 /***
330 * Returns the vm package name for the vm class name.
331 */
332
333 static public String packageOf(String vmName)/package-summary.html">ong> public String packageOf(String vmName)
334 {
335 int last = vmName.lastIndexOf('/');
336 if (last < 0)
337 return "";
338 return vmName.substring(0, last);
339 }
340
341
342
343
344 /***
345 * Construct a ClassFile from an input stream
346 */
347 public ClassFile(DataInputStream data) throws ClassFormatError {
348 this(data, true);
349 }
350
351 public ClassFile(DataInputStream data,
352 boolean allowJDK12ClassFiles) throws ClassFormatError {
353 try {
354 int thisMagic = data.readInt();
355 if (thisMagic != magic)
356 throw new ClassFormatError("Bad magic value for input");
357
358 short thisMinorVersion = data.readShort();
359 short thisMajorVersion = data.readShort();
360
361
362
363 if (isSupportedVersion(thisMajorVersion, thisMinorVersion)) {
364 minorVersion = thisMinorVersion;
365 majorVersion = thisMajorVersion;
366 } else {
367 throw new ClassFormatError("Bad version number: {" +
368 thisMajorVersion + "," +
369 thisMinorVersion +
370 "} expected one of: " +
371 supportedVersions);
372 }
373
374 readConstants(data);
375 accessFlags = data.readUnsignedShort();
376 thisClassName = (ConstClass)
377 constantPool.constantAt(data.readUnsignedShort());
378 superClassName = (ConstClass)
379 constantPool.constantAt(data.readUnsignedShort());
380 readInterfaces(data);
381 readFields(data);
382 readMethods(data);
383 classAttributes = AttributeVector.readAttributes(data, constantPool);
384 } catch (IOException e) {
385 throw new ClassFormatError("IOException during reading: " +
386 e.getMessage());
387 }
388
389
390
391 }
392
393 /***
394 * Construct a bare bones class, ready for additions
395 */
396 public ClassFile(String cname, String supername) {
397 thisClassName = constantPool.addClass(cname);
398 superClassName = constantPool.addClass(supername);
399
400
401
402 }
403
404 /***
405 * Write the Class file to the data output stream
406 */
407 public
408 void write (DataOutputStream buff) throws IOException {
409 buff.writeInt(magic);
410 buff.writeShort(minorVersion);
411 buff.writeShort(majorVersion);
412 constantPool.write(buff);
413 buff.writeShort(accessFlags);
414 buff.writeShort(thisClassName.getIndex());
415
416
417 buff.writeShort(superClassName == null ? 0 : superClassName.getIndex());
418
419 writeInterfaces(buff);
420 writeFields(buff);
421 writeMethods(buff);
422 classAttributes.write(buff);
423 }
424
425 /***
426 * Returns a byte array representation of this class.
427 */
428 public byte[] getBytes() throws java.io.IOException {
429
430
431 String writeClassToDirectory =
432 System.getProperty("filter.writeClassToDirectory");
433 if (writeClassToDirectory != null) {
434 String filename = writeClassToDirectory + java.io.File.separator +
435 thisClassName.asString() + ".class";
436 System.err.println("Writing class to file " + filename);
437 DataOutputStream stream = new DataOutputStream(
438 new java.io.FileOutputStream(filename));
439 write(stream);
440 stream.close();
441 }
442
443
444
445 ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
446 write(new DataOutputStream(byteStream));
447
448 return byteStream.toByteArray();
449 }
450
451
452 public void print(PrintStream out) {
453 print(out, 0);
454 }
455
456
457 public void print(PrintStream out, int indent) {
458 constantPool.print(out, indent);
459 out.println();
460
461 ClassPrint.spaces(out, indent);
462 out.println("majorVersion = " + Integer.toString(majorVersion));
463 ClassPrint.spaces(out, indent);
464 out.println("minorVersion = " + Integer.toString(minorVersion));
465 ClassPrint.spaces(out, indent);
466 out.println("accessFlags = " + Integer.toString(accessFlags));
467 ClassPrint.spaces(out, indent);
468 out.println("className = " + thisClassName.asString());
469 ClassPrint.spaces(out, indent);
470 out.println("superClassName = " + superClassName.asString());
471 ClassPrint.spaces(out, indent);
472 out.print("Interfaces =");
473 for (int i=0; i<classInterfaces.size(); i++) {
474 out.print(" "
475 + ((ConstClass)classInterfaces.elementAt(i)).asString());
476 }
477 out.println();
478
479 ClassPrint.spaces(out, indent);
480 out.println("fields =");
481 for (int i=0; i<classFields.size(); i++) {
482 ((ClassField) classFields.elementAt(i)).print(out, indent + 3);
483 }
484
485 ClassPrint.spaces(out, indent);
486 out.println("methods =");
487 for (int i=0; i<classMethods.size(); i++) {
488 ((ClassMethod) classMethods.elementAt(i)).print(out, indent + 3);
489 }
490
491 ClassPrint.spaces(out, indent);
492 out.println("attributes =");
493 classAttributes.print(out, indent + 3);
494
495 }
496
497
498
499 public void summarize(PrintStream out, int indent) {
500 constantPool.summarize(out, indent);
501 int codeSize = 0;
502 for (int i=0; i<classMethods.size(); i++) {
503 codeSize += ((ClassMethod)classMethods.elementAt(i)).codeSize();
504 }
505 ClassPrint.spaces(out, indent);
506 out.println(classMethods.size() + " methods in "
507 + codeSize + " bytes");
508 ClassPrint.spaces(out, indent);
509 out.println(classFields.size() + " fields");
510 }
511
512 /* package local methods *//package-summary/html">class="comment"> package local methods *//package-summary.html">
513
514
515
516
517 private void readConstants (DataInputStream data) throws IOException {
518 constantPool = new ConstantPool(data);
519 }
520
521 private void readInterfaces(DataInputStream data) throws IOException {
522 int nInterfaces = data.readUnsignedShort();
523 while (nInterfaces-- > 0) {
524 int interfaceIndex = data.readUnsignedShort();
525 ConstClass ci = null;
526 if (interfaceIndex != 0)
527 ci = (ConstClass) constantPool.constantAt(interfaceIndex);
528 classInterfaces.addElement(ci);
529 }
530 }
531
532 private void writeInterfaces(DataOutputStream data) throws IOException {
533 data.writeShort(classInterfaces.size());
534 for (int i=0; i<classInterfaces.size(); i++) {
535 ConstClass ci = (ConstClass) classInterfaces.elementAt(i);
536 int interfaceIndex = 0;
537 if (ci != null)
538 interfaceIndex = ci.getIndex();
539 data.writeShort(interfaceIndex);
540 }
541 }
542
543 private void readFields(DataInputStream data) throws IOException {
544 int nFields = data.readUnsignedShort();
545 while (nFields-- > 0) {
546 classFields.addElement (ClassField.read(data, constantPool));
547 }
548 }
549
550 private void writeFields (DataOutputStream data) throws IOException {
551 data.writeShort(classFields.size());
552 for (int i=0; i<classFields.size(); i++)
553 ((ClassField)classFields.elementAt(i)).write(data);
554 }
555
556 private void readMethods (DataInputStream data) throws IOException {
557 int nMethods = data.readUnsignedShort();
558 while (nMethods-- > 0) {
559 classMethods.addElement (ClassMethod.read(data, constantPool));
560 }
561 }
562
563 private void writeMethods (DataOutputStream data) throws IOException {
564 data.writeShort(classMethods.size());
565 for (int i=0; i<classMethods.size(); i++)
566 ((ClassMethod)classMethods.elementAt(i)).write(data);
567 }
568
569 }
570
571 abstract class ArraySorter {
572 protected ArraySorter() {}
573
574
575 abstract int size();
576
577
578 abstract int compare(int o1Index, int o2Index);
579
580
581 abstract void swap(int o1Index, int o2Index);
582
583 void sortArray() {
584 sortArray(0, size()-1);
585 }
586
587 private void sortArray(int start, int end) {
588 if (end > start) {
589 swap(start, (start+end)/2);
590 int last = start;
591 for (int i = start+1; i<=end; i++) {
592 if (compare(i, start) < 0)
593 swap (++last, i);
594 }
595 swap(start, last);
596 sortArray(start, last-1);
597 sortArray(last+1, end);
598 }
599 }
600 }
601
602 class InterfaceArraySorter extends ArraySorter {
603 private ConstClass theArray[];
604
605 InterfaceArraySorter(ConstClass[] interfaces) {
606 theArray = interfaces;
607 }
608
609
610 int size() { return theArray.length; }
611
612
613 int compare(int o1Index, int o2Index) {
614 return theArray[o1Index].asString().compareTo(
615 theArray[o2Index].asString());
616 }
617
618
619 void swap(int o1Index, int o2Index) {
620 ConstClass tmp = theArray[o1Index];
621 theArray[o1Index] = theArray[o2Index];
622 theArray[o2Index] = tmp;
623 }
624 }
625
626 class FieldArraySorter extends ArraySorter {
627 private ClassField theArray[];
628
629 FieldArraySorter(ClassField[] fields) {
630 theArray = fields;
631 }
632
633
634 int size() { return theArray.length; }
635
636
637 int compare(int o1Index, int o2Index) {
638 return theArray[o1Index].name().asString().compareTo(
639 theArray[o2Index].name().asString());
640 }
641
642
643 void swap(int o1Index, int o2Index) {
644 ClassField tmp = theArray[o1Index];
645 theArray[o1Index] = theArray[o2Index];
646 theArray[o2Index] = tmp;
647 }
648 }
649
650 class MethodArraySorter extends ArraySorter {
651 private ClassMethod theArray[];
652
653 MethodArraySorter(ClassMethod[] methods) {
654 theArray = methods;
655 }
656
657
658 int size() { return theArray.length; }
659
660
661 int compare(int o1Index, int o2Index) {
662 int cmp = theArray[o1Index].name().asString().compareTo(
663 theArray[o2Index].name().asString());
664 if (cmp == 0) {
665 cmp = theArray[o1Index].signature().asString().compareTo(
666 theArray[o2Index].signature().asString());
667 }
668 return cmp;
669 }
670
671
672 void swap(int o1Index, int o2Index) {
673 ClassMethod tmp = theArray[o1Index];
674 theArray[o1Index] = theArray[o2Index];
675 theArray[o2Index] = tmp;
676 }
677 }