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