/Users/lyon/j4p/src/classUtils/dumper/ClassFile.java
|
1 package classUtils.dumper;
2
3 import futils.DirList;
4 import futils.Futil;
5 import gui.In;
6
7 import java.io.ByteArrayInputStream;
8 import java.io.DataInputStream;
9 import java.io.DataOutputStream;
10 import java.io.File;
11 import java.io.FileInputStream;
12 import java.io.FileNotFoundException;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.OutputStream;
16 import java.util.Vector;
17
18 /**
19 * This class is used to manipulate Java class
20 * files in strange and mysterious ways. Usage it
21 * typically to feed it an array of bytes that are
22 * a class file, manipulate the class, then
23 * convert the class back into bytes, and feed the
24 * final result to <TT>defineClass()</TT>.
25 *
26 * @version 1.6, 19 Aug 1995
27 */
28 public class ClassFile {
29 private int magic;
30 private short majorVersion;
31 private short minorVersion;
32 private ConstantPoolInfo constantPool[];
33 private short accessFlags;
34 private ConstantPoolInfo thisClass;
35 private ConstantPoolInfo superClass;
36 private ConstantPoolInfo interfaces[];
37 private FieldInfo fields[];
38 private MethodInfo methods[];
39 private AttributeInfo attributes[];
40 private boolean isValidClass = false;
41 public static final int ACC_PUBLIC = 0x1;
42 public static final int ACC_PRIVATE = 0x2;
43 public static final int ACC_PROTECTED = 0x4;
44 public static final int ACC_STATIC = 0x8;
45 public static final int ACC_FINAL = 0x10;
46 public static final int ACC_SYNCHRONIZED = 0x20;
47 public static final int ACC_THREADSAFE = 0x40;
48 public static final int ACC_TRANSIENT = 0x80;
49 public static final int ACC_NATIVE = 0x100;
50 public static final int ACC_INTERFACE = 0x200;
51 public static final int ACC_ABSTRACT = 0x400;
52 public boolean dumpConstants = false;
53
54 /**
55 * Read a class from InputStream <i>in</i>.
56 */
57 public boolean read(InputStream in)
58 throws IOException {
59 DataInputStream di = new DataInputStream(in);
60 int count;
61 setMagic(di.readInt());
62 if (getMagic() != 0xCAFEBABE) {
63 return (false);
64 }
65 setMajorVersion(di.readShort());
66 setMinorVersion(di.readShort());
67 count = di.readShort();
68 setConstantPool(new ConstantPoolInfo[count]);
69 getConstantPool()[0] =
70 new ConstantPoolInfo();
71 for (int i = 1;
72 i < getConstantPool().length;
73 i++) {
74 getConstantPool()[i] =
75 new ConstantPoolInfo();
76 if (!getConstantPool()[i].read(di))
77 return (false);
78
79 // These two types take up "two" spots in the table
80 if ((getConstantPool()[i].type ==
81 ConstantPoolInfo.LONG) ||
82 (getConstantPool()[i].type ==
83 ConstantPoolInfo.DOUBLE))
84 i++;
85 }
86
87 /*
88 * Update pointers in the constant table. This turns the
89 * table into a real datastructure.
90 *
91 * TODO: Have it verify that the right arguments are present
92 */
93
94 for (int i = 1;
95 i < getConstantPool().length;
96 i++) {
97 if (getConstantPool()[i] == null)
98 continue;
99 if (getConstantPool()[i].index1 > 0)
100 getConstantPool()[i].arg1 =
101 getConstantPool()[getConstantPool()[i].index1];
102 if (getConstantPool()[i].index2 > 0)
103 getConstantPool()[i].arg2 =
104 getConstantPool()[getConstantPool()[i].index2];
105 }
106 if (dumpConstants) {
107 for (int i = 1;
108 i < getConstantPool().length;
109 i++) {
110 System.out.println("C" +
111 i +
112 " - " +
113 getConstantPool()[i]);
114 }
115 }
116 setAccessFlags(di.readShort());
117 setThisClass(getConstantPool()[di.readShort()]);
118 setSuperClass(getConstantPool()[di.readShort()]);
119 /*
120 * Identify all of the interfaces implemented by this class
121 */
122
123 count = di.readShort();
124 if (count != 0) {
125 setInterfaces(new ConstantPoolInfo[count]);
126 for (int i = 0; i < count; i++) {
127 int iindex = di.readShort();
128 if ((iindex < 1) ||
129 (iindex >
130 getConstantPool().length -
131 1))
132 return (false);
133 getInterfaces()[i] =
134 getConstantPool()[iindex];
135 }
136 }
137
138 /*
139 * Identify all fields in this class.
140 */
141
142 count = di.readShort();
143 if (count != 0) {
144 setFields(new FieldInfo[count]);
145 for (int i = 0; i < count; i++) {
146 getFields()[i] = new FieldInfo();
147 if (!getFields()[i].read(di,
148 getConstantPool())) {
149 return (false);
150 }
151 }
152 }
153
154
155 /*
156
157 * Identify all the methods in this class.
158
159 */
160
161 count = di.readShort();
162 if (count != 0) {
163 setMethods(new MethodInfo[count]);
164 for (int i = 0; i < count; i++) {
165 getMethods()[i] =
166 new MethodInfo();
167 if (!getMethods()[i].read(di,
168 getConstantPool())) {
169 return (false);
170 }
171 }
172 }
173
174
175
176
177
178 /*
179
180 * Identify all of the attributes in this class
181
182 */
183
184 count = di.readShort();
185 if (count != 0) {
186 setAttributes(new AttributeInfo[count]);
187 for (int i = 0; i < count; i++) {
188 getAttributes()[i] =
189 new AttributeInfo();
190 if (!getAttributes()[i].read(di,
191 getConstantPool())) {
192 return (false);
193 }
194 }
195 }
196 setValidClass(true);
197 return (true);
198 }
199
200 /**
201 * Write the class out as a stream of bytes to
202 * the output stream. Generally you will read
203 * a class file, manipulate it in some way,
204 * and then write it out again before passing
205 * it to <TT>defineClass</TT> in some class
206 * loader.
207 */
208 public void write(OutputStream out)
209 throws IOException, Exception {
210 DataOutputStream dos = new DataOutputStream(out);
211 if (!isValidClass()) {
212 throw new Exception("ClassFile::write() - Invalid Class");
213 }
214 dos.writeInt(getMagic());
215 dos.writeShort(getMajorVersion());
216 dos.writeShort(getMinorVersion());
217 dos.writeShort(getConstantPool().length);
218 for (int i = 1;
219 i < getConstantPool().length;
220 i++) {
221 if (getConstantPool()[i] != null)
222 getConstantPool()[i].write(dos,
223 getConstantPool());
224 }
225 dos.writeShort(getAccessFlags());
226 dos.writeShort(ConstantPoolInfo.indexOf(getThisClass(),
227 getConstantPool()));
228 dos.writeShort(ConstantPoolInfo.indexOf(getSuperClass(),
229 getConstantPool()));
230 if (getInterfaces() == null)
231 dos.writeShort(0);
232 else {
233 dos.writeShort(getInterfaces().length);
234 for (int i = 0;
235 i < getInterfaces().length;
236 i++)
237 dos.writeShort(ConstantPoolInfo.indexOf(getInterfaces()[i],
238 getConstantPool()));
239 } // end else
240 if (getFields() == null) {
241 dos.writeShort(0);
242 } else {
243 dos.writeShort(getFields().length);
244 for (int i = 0;
245 i < getFields().length;
246 i++) {
247 getFields()[i].write(dos,
248 getConstantPool());
249 }
250 }
251 if (getMethods() == null) {
252 dos.writeShort(0);
253 } else {
254 dos.writeShort(getMethods().length);
255 for (int i = 0;
256 i < getMethods().length;
257 i++) {
258 getMethods()[i].write(dos,
259 getConstantPool());
260 }
261 }
262 if (getAttributes() == null) {
263 dos.writeShort(0);
264 } else {
265 dos.writeShort(getAttributes().length);
266 for (int i = 0;
267 i < getAttributes().length;
268 i++) {
269 getAttributes()[i].write(dos,
270 getConstantPool());
271 }
272 }
273 }
274
275 /**
276 * Returns a string that represents what the
277 * access flags are set for. So 0x14 returns
278 * "public final "
279 */
280 public static String accessString(short flags) {
281 StringBuffer x = new StringBuffer();
282 if ((flags & ACC_PUBLIC) != 0) {
283 x.append("public ");
284 }
285 if ((flags & ACC_PRIVATE) != 0) {
286 x.append("private ");
287 }
288 if ((flags & ACC_PROTECTED) != 0) {
289 x.append("protected ");
290 }
291 if ((flags & ACC_STATIC) != 0) {
292 x.append("static ");
293 }
294 if ((flags & ACC_FINAL) != 0) {
295 x.append("final ");
296 }
297 if ((flags & ACC_SYNCHRONIZED) != 0) {
298 x.append("synchronized ");
299 }
300 if ((flags & ACC_THREADSAFE) != 0) {
301 x.append("threadsafe ");
302 }
303 if ((flags & ACC_TRANSIENT) != 0) {
304 x.append("transient ");
305 }
306 if ((flags & ACC_NATIVE) != 0) {
307 x.append("native ");
308 }
309 if ((flags & ACC_INTERFACE) != 0) {
310 x.append("interface ");
311 }
312 if ((flags & ACC_ABSTRACT) != 0) {
313 x.append("abstract ");
314 }
315 return (x.toString());
316 }
317
318 /**
319 * Takes a type signature and a string
320 * representing a variable name and returns a
321 * declaration for that variable name. For
322 * example, passing this the strings "[B" and
323 * "myArray" will return the string "byte
324 * myArray[]"
325 */
326 public static String typeString(String typeString, String varName) {
327 int isArray = 0;
328 int ndx = 0;
329 StringBuffer x = new StringBuffer();
330 while (typeString.charAt(ndx) == '[') {
331 isArray++;
332 ndx++;
333 }
334 switch (typeString.charAt(ndx)) {
335 case 'B':
336 x.append("byte ");
337 break;
338 case 'C':
339 x.append("char ");
340 break;
341 case 'D':
342 x.append("double ");
343 break;
344 case 'F':
345 x.append("float ");
346 break;
347 case 'I':
348 x.append("int ");
349 break;
350 case 'J':
351 x.append("long ");
352 break;
353 case 'L':
354 for (int i = ndx + 1;
355 i < typeString.indexOf(';');
356 i++) {
357 if (typeString.charAt(i) !=
358 '/')
359 x.append(typeString.charAt(i));
360 else
361 x.append('.');
362 }
363 x.append(" ");
364 break;
365 case 'V':
366 x.append("void ");
367 break;
368 case 'S':
369 x.append("short ");
370 break;
371 case 'Z':
372 x.append("boolean ");
373 break;
374 }
375 x.append(varName);
376 while (isArray > 0) {
377 x.append("[]");
378 isArray--;
379 }
380 return (x.toString());
381 }
382
383 /**
384 * Returns the next signature from a string of
385 * concatenated signatures. For example if the
386 * signature was "[BII", this method would
387 * return "II"
388 */
389 public static String nextSig(String sig) {
390 int ndx = 0;
391 String x;
392 while (sig.charAt(ndx) == '[')
393 ndx++;
394 if (sig.charAt(ndx) == 'L') {
395 while (sig.charAt(ndx) != ';')
396 ndx++;
397 }
398 ndx++;
399 x = (sig.substring(ndx));
400 return (x);
401 }
402
403 /**
404 * Print the name of a class in "canonical
405 * form"
406 */
407 private String getClassName(String s) {
408 StringBuffer x;
409 if (s.charAt(0) == '[') {
410 return (typeString(s, ""));
411 }
412 x = new StringBuffer();
413 for (int j = 0; j < s.length(); j++) {
414 if (s.charAt(j) == '/')
415 x.append('.');
416 else
417 x.append(s.charAt(j));
418 }
419 return (x.toString());
420 }
421
422 public String getClassName() {
423 return getClassName(getThisClass().arg1.strValue);
424 }
425
426 /**
427 * The boring version of display().
428 */
429 public String toString() {
430 return ("Class File (Version " +
431 getMajorVersion() +
432 "." +
433 getMinorVersion() +
434 ") for class " +
435 getThisClass().arg1);
436 }
437
438 /**
439 * Write out a text version of this class.
440 */
441 public void display()
442 throws Exception {
443 int i;
444 String myClassName;
445 String packageName = null;
446 if (!isValidClass()) {
447 In.message("not a valid class");
448 throw new Exception();
449 }
450 myClassName =
451 getClassName(getThisClass().arg1.strValue);
452 if (myClassName.indexOf('.') > 0) {
453 packageName =
454 myClassName.substring(0,
455 myClassName.lastIndexOf('.'));
456 myClassName =
457 myClassName.substring(myClassName.lastIndexOf('.') +
458 1);
459 }
460 for (i = 1;
461 i < getConstantPool().length;
462 i++) {
463 if (getConstantPool()[i] == null)
464 continue;
465 if ((getConstantPool()[i] ==
466 getThisClass()) ||
467 (getConstantPool()[i] ==
468 getSuperClass()))
469 continue;
470 if (getConstantPool()[i].type ==
471 ConstantPoolInfo.CLASS) {
472 String s = getConstantPool()[i].arg1.strValue;
473 if (s.charAt(0) == '[')
474 continue;
475 s =
476 getClassName(getConstantPool()[i].arg1.strValue);
477 if ((packageName != null) &&
478 (s.startsWith(packageName)))
479 continue;
480 }
481 }
482 DataInputStream dis;
483 ConstantPoolInfo cpi;
484 if (getAttributes() != null) {
485 for (i = 0;
486 i < getAttributes().length;
487 i++) {
488 String attrName = getAttributes()[i].getName()
489 .strValue;
490 dis =
491 new DataInputStream(new ByteArrayInputStream(getAttributes()[i].getData()));
492 if (attrName.compareTo("SourceFile") ==
493 0) {
494 cpi = null;
495 try {
496 cpi =
497 getConstantPool()[dis.readShort()];
498 } catch (IOException e) {
499 }
500 }
501 }
502 }
503 }
504
505 private String getMethod(int i,
506 String myClassName) {
507 return getMethods()[i].toString(myClassName);
508 }
509
510 private String getField(int i) {
511 return getFields()[i].toString(getConstantPool());
512 }
513
514 public ConstantPoolInfo getConstantRef(short index) {
515 return (getConstantPool()[index]);
516 }
517
518 /**
519 * Add a single constant pool item and return
520 * its index. If the item is already in the
521 * pool then the index of the <i>preexisting</i>
522 * item is returned. Thus you cannot assume
523 * that a pointer to your item will be
524 * useful.
525 */
526 public short addConstantPoolItem(ConstantPoolInfo item)
527 throws Exception {
528 ConstantPoolInfo newConstantPool[];
529 ConstantPoolInfo cp;
530 cp = item.inPool(getConstantPool());
531 if (cp != null)
532 return ConstantPoolInfo.indexOf(cp,
533 getConstantPool());
534 newConstantPool =
535 new ConstantPoolInfo[getConstantPool()
536 .length +
537 1];
538 for (int i = 1;
539 i < getConstantPool().length;
540 i++) {
541 newConstantPool[i] =
542 getConstantPool()[i];
543 }
544 newConstantPool[getConstantPool().length] =
545 item;
546 setConstantPool(newConstantPool);
547 return ConstantPoolInfo.indexOf(item,
548 getConstantPool());
549 }
550
551 /**
552 * Add some items to the constant pool. This
553 * is used to add new items to the constant
554 * pool. The items references in arg1 and arg2
555 * are expected to be valid pointers (if
556 * necessary). Pruning is done to prevent
557 * adding redundant items to the list and to
558 * preserve string space. The algorithm is
559 * simple, first identify pool items
560 * containing constants in the list of items
561 * to be added that are already in the
562 * constant pool. If any are found to already
563 * exist, change the pointers in the
564 * non-constant items to point to the ones in
565 * the pool rather than the ones in the list.
566 * Next check to see if any of the
567 * non-constant items are already in the pool
568 * and if so fix up the others in the list to
569 * point to the ones in the pool. Finally, add
570 * any items (there must be at least one) from
571 * the item list that aren't already in the
572 * pool, all of the pointers will already be
573 * fixed. NOTE: Since constants in the
574 * constant pool may be referenced
575 * <i>inside</i> the opaque portion of
576 * attributes the constant table cannot be
577 * re-ordered, only extended.
578 */
579 public void addConstantPoolItems(ConstantPoolInfo items[]) {
580 ConstantPoolInfo newArg;
581 ConstantPoolInfo newConstantPool[];
582 boolean delete[] = new boolean[items.length];
583
584
585
586 /* Step one, look for matching constants */
587
588 for (int j = 0; j < items.length; j++) {
589 if ((items[j].type ==
590 ConstantPoolInfo.ASCIZ) ||
591 (items[j].type ==
592 ConstantPoolInfo.UNICODE) ||
593 (items[j].type ==
594 ConstantPoolInfo.INTEGER) ||
595 (items[j].type ==
596 ConstantPoolInfo.LONG) ||
597 (items[j].type ==
598 ConstantPoolInfo.FLOAT) ||
599 (items[j].type ==
600 ConstantPoolInfo.DOUBLE)) {
601 // Look for this item in the constant pool
602
603 delete[j] = false;
604 newArg =
605 items[j].inPool(getConstantPool());
606 if (newArg != null) {
607 // replace the references in our list.
608
609 delete[j] = true; // mark it for deletion
610 for (int i = 0;
611 i < items.length;
612 i++) {
613 if (items[i].arg1 ==
614 items[j])
615 items[i].arg1 =
616 newArg;
617 if (items[i].arg2 ==
618 items[j])
619 items[i].arg2 =
620 newArg;
621 }
622 }
623 }
624 }
625
626
627
628 /* Step two : now match everything else */
629
630 for (int j = 0; j < items.length; j++) {
631 if ((items[j].type ==
632 ConstantPoolInfo.CLASS) ||
633 (items[j].type ==
634 ConstantPoolInfo.FIELDREF) ||
635 (items[j].type ==
636 ConstantPoolInfo.METHODREF) ||
637 (items[j].type ==
638 ConstantPoolInfo.STRING) ||
639 (items[j].type ==
640 ConstantPoolInfo.INTERFACE) ||
641 (items[j].type ==
642 ConstantPoolInfo.NAMEANDTYPE)) {
643 // Look for this item in the constant pool
644
645 delete[j] = false;
646 newArg =
647 items[j].inPool(getConstantPool());
648 if (newArg != null) {
649 // replace the references in our list.
650
651 delete[j] = true; // mark it for deletion
652 for (int i = 0;
653 i < items.length;
654 i++) {
655 if (items[i].arg1 ==
656 items[j])
657 items[i].arg1 =
658 newArg;
659 if (items[i].arg2 ==
660 items[j])
661 items[i].arg2 =
662 newArg;
663 }
664 }
665 }
666 }
667
668
669
670 /* Step three: Add the surviving items to the pool */
671
672 int count = 0;
673 for (int i = 0; i < items.length; i++) {
674 if (!delete[i])
675 count++;
676 }
677
678 // count == # of survivors
679
680 newConstantPool =
681 new ConstantPoolInfo[getConstantPool()
682 .length +
683 count];
684 for (int i = 1;
685 i < getConstantPool().length;
686 i++) {
687 newConstantPool[i] =
688 getConstantPool()[i];
689 }
690
691 // newConstantPool == existing constantPool
692
693
694
695 int ndx = 0;
696 for (int i = getConstantPool().length;
697 i < newConstantPool.length;
698 i++) {
699 while (delete[ndx])
700 ndx++;
701 newConstantPool[i] = items[ndx];
702 ndx++;
703 }
704
705 // newConstantPool == existing + new
706
707 setConstantPool(newConstantPool);
708
709 // all done.
710 }
711
712 /**
713 * Add a new optional class Attribute. Items
714 * is an array of constant pool items that are
715 * first added to the constant pool. At a
716 * minimum items[0] must be an ASCIZ item with
717 * the name of the attribute. If the body of
718 * the attribute references constant pool
719 * items these should be in the item list as
720 * well.
721 */
722 public void addAttribute(AttributeInfo newAttribute) {
723 if (getAttributes() == null) {
724 setAttributes(new AttributeInfo[1]);
725 getAttributes()[0] = newAttribute;
726 } else {
727 AttributeInfo newAttrList[] = new AttributeInfo[1 +
728 getAttributes()
729 .length];
730 for (int i = 0;
731 i < getAttributes().length;
732 i++) {
733 newAttrList[i] =
734 getAttributes()[i];
735 }
736 newAttrList[getAttributes().length] =
737 newAttribute;
738 setAttributes(newAttrList);
739 }
740 }
741
742 /**
743 * Return the attribute named 'name' from the
744 * class file.
745 */
746 public AttributeInfo getAttribute(String name) {
747 if (getAttributes() == null)
748 return null;
749 for (int i = 0;
750 i < getAttributes().length;
751 i++) {
752 if (name.compareTo(getAttributes()[i].getName()
753 .toString()) ==
754 0)
755 return getAttributes()[i];
756 }
757 return (null);
758 }
759
760 /**
761 * Return a constant pool item from this
762 * class. (note does fixup of indexes to
763 * facilitate extracting nested or linked
764 * items.
765 */
766 public ConstantPoolInfo getConstantPoolItem(short index)
767 throws Exception {
768 ConstantPoolInfo cp;
769 if ((index <= 0) ||
770 (index >
771 (getConstantPool().length - 1)))
772 return (null);
773 cp = getConstantPool()[index];
774 if (cp.arg1 != null)
775 cp.index1 =
776 ConstantPoolInfo.indexOf(cp.arg1,
777 getConstantPool());
778 if (cp.arg2 != null)
779 cp.index2 =
780 ConstantPoolInfo.indexOf(cp.arg2,
781 getConstantPool());
782 return cp;
783 }
784
785
786
787 /* Examples of mysterious things you can do to a class file before
788
789 * writing it back out. These methods are not currently functional.
790
791 * (that would be too easy :-)
792
793 */
794
795
796
797 /**
798 * Map occurences of class <i>oldClass</i> to
799 * occurrences of class <i>newClass</i>. This
800 * method is used to retarget accesses to one
801 * class, seamlessly to another. The format
802 * for the class name is slash (/) separated
803 * so the class <tt>util.ClassFile</tt> would
804 * be represented as <tt>util/ClassFile</tt>
805 */
806 public void mapClass(String oldClass,
807 String newClass) {
808 for (int i = 0;
809 i < getConstantPool().length;
810 i++) {
811 if (getConstantPool()[i].type ==
812 ConstantPoolInfo.CLASS) {
813 String cname = getConstantPool()[i].arg1.strValue;
814 if (cname.compareTo(oldClass) ==
815 0) {
816 getConstantPool()[i].arg1.strValue =
817 newClass;
818 }
819 }
820 }
821 }
822
823 /**
824 * Map occurences of package <i>oldPackage</i>
825 * to package <i>newPackage</i>. The format
826 * for the package name is slash (/) separated
827 * so the package <tt>java.util</tt> would be
828 * represented as <tt>java/util</tt>
829 */
830 public void mapPackage(String oldPackage,
831 String newPackage) {
832 for (int i = 0;
833 i < getConstantPool().length;
834 i++) {
835 if (getConstantPool()[i].type ==
836 ConstantPoolInfo.CLASS) {
837 String cname = getConstantPool()[i].arg1.strValue;
838 if (cname.startsWith(oldPackage)) {
839 getConstantPool()[i].arg1.strValue =
840 newPackage +
841 cname.substring(cname.lastIndexOf('/'));
842 }
843 }
844 }
845 }
846
847 /**
848 * Delete a named method from this class. This
849 * method is used to excise specific methods
850 * from the loaded class. The actual method
851 * code remains, however the method signature
852 * is deleted from the constant pool. If this
853 * method is called by a class the exception
854 * IncompatibleClassChangeException is
855 * generated by the runtime.
856 */
857 public void deleteMethod(String name,
858 String signature) {
859 for (int i = 0;
860 i < getConstantPool().length;
861 i++) {
862 if (getConstantPool()[i].type ==
863 ConstantPoolInfo.CLASS) {
864 }
865 }
866 }
867
868 int getMagic() {
869 return magic;
870 }
871
872 void setMagic(int magic) {
873 this.magic = magic;
874 }
875
876 short getMajorVersion() {
877 return majorVersion;
878 }
879
880 void setMajorVersion(short majorVersion) {
881 this.majorVersion = majorVersion;
882 }
883
884 short getMinorVersion() {
885 return minorVersion;
886 }
887
888 void setMinorVersion(short minorVersion) {
889 this.minorVersion = minorVersion;
890 }
891
892 ConstantPoolInfo[] getConstantPool() {
893 return constantPool;
894 }
895
896 void setConstantPool(ConstantPoolInfo[] constantPool) {
897 this.constantPool = constantPool;
898 }
899
900 short getAccessFlags() {
901 return accessFlags;
902 }
903
904 void setAccessFlags(short accessFlags) {
905 this.accessFlags = accessFlags;
906 }
907
908 ConstantPoolInfo getThisClass() {
909 return thisClass;
910 }
911
912 void setThisClass(ConstantPoolInfo thisClass) {
913 this.thisClass = thisClass;
914 }
915
916 ConstantPoolInfo getSuperClass() {
917 return superClass;
918 }
919
920 void setSuperClass(ConstantPoolInfo superClass) {
921 this.superClass = superClass;
922 }
923
924 ConstantPoolInfo[] getInterfaces() {
925 return interfaces;
926 }
927
928 void setInterfaces(ConstantPoolInfo[] interfaces) {
929 this.interfaces = interfaces;
930 }
931
932 FieldInfo[] getFields() {
933 return fields;
934 }
935
936 void setFields(FieldInfo[] fields) {
937 this.fields = fields;
938 }
939
940 MethodInfo[] getMethods() {
941 return methods;
942 }
943
944 void setMethods(MethodInfo[] methods) {
945 this.methods = methods;
946 }
947
948 AttributeInfo[] getAttributes() {
949 return attributes;
950 }
951
952 void setAttributes(AttributeInfo[] attributes) {
953 this.attributes = attributes;
954 }
955
956 boolean isValidClass() {
957 return isValidClass;
958 }
959
960 void setValidClass(boolean validClass) {
961 isValidClass = validClass;
962 }
963
964 public static void testGetClassFiles() {
965 ClassFile cf[] = getClassFiles();
966 for (int i = 0; i < cf.length; i++)
967 System.out.println(cf[i]);
968 }
969
970 public static ClassFile[] getClassFiles() {
971 DirList dl = new DirList(".class");
972 File f[] = dl.getFilesNotDirectories();
973 Vector v = new Vector();
974 for (int i = 0; i < f.length; i++)
975 v.addElement(getClassFile(f[i]));
976 ClassFile cf[] = new ClassFile[v.size()];
977 v.copyInto(cf);
978 return cf;
979 }
980
981 public static ClassFile getClassFile() {
982 return getClassFile(Futil.getFileInputStream("Select a classfile"));
983 }
984
985 public static ClassFile getClassFile(File f) {
986 ClassFile cf = null;
987 try {
988 cf = getClassFile(new FileInputStream(f));
989 } catch (FileNotFoundException e) {
990 e.printStackTrace();
991 }
992 return cf;
993 }
994
995 public static ClassFile getClassFile(FileInputStream fis) {
996 ClassFile cf = null;
997 try {
998 cf = readClassFile(fis);
999 fis.close();
1000 } catch (Exception e) {
1001 In.message(e);
1002 }
1003 return cf;
1004 }
1005
1006 public static ClassFile readClassFile(InputStream fis) throws Exception {
1007 ClassFile cf = new ClassFile();
1008 if (!cf.read(fis)) {
1009 System.out.println("Couldn't load");
1010 }
1011 cf.display();
1012 return cf;
1013 }
1014
1015 public boolean hasMainMethod() {
1016 MethodInfo mi[] = getMethods();
1017 Vector v = new Vector();
1018 if (mi == null) return false;
1019 for (int i = 0; i < mi.length; i++) {
1020 String ms = mi[i].toString();
1021 boolean b = ms.indexOf("public") >= 0;
1022 boolean b1 = ms.indexOf("static") >= 0;
1023 boolean b3 = ms.indexOf("main") >= 0;
1024 boolean b4 = ms.indexOf("java.lang.String ") >= 0;
1025 boolean b5 = ms.indexOf("void") >= 0;
1026 if (b && b1 && b3 && b4 && b5)
1027 v.addElement(mi[i]);
1028 }
1029 if (v.size() == 0) return false;
1030 return true;
1031 }
1032
1033 public static void main(String[] args) {
1034 testGetClassFiles();
1035 }
1036 }
1037
1038