/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