1    
2    /**
3    
4      The author of this software is Ian Kaplan
5      Bear Products International
6      www.bearcave.com
7      iank@bearcave.com
8    
9      Copyright (c) Ian Kaplan, 1999, 2000
10   
11     See copyright file for usage and licensing
12   
13   */
14   
15   
16   package classfile;
17   
18   import java.util.Vector;
19   import java.io.*;
20   import util.*;
21   import jconst.*;
22   import attr.*;
23   
24   
25   
26   /**
27   
28      The classFileHeader contains the class file header information.
29      This information is:
30   
31   <pre>
32         u4 magic          -- magic number, the famous 0xcafebabe
33         u2 minor_version
34         u2 major_version
35   </pre>
36   
37     @author Ian Kaplan
38   
39    */
40   class classFileHeader extends dataRead {
41     private int magic;
42     private short minor_version;
43     private short major_version;
44   
45     classFileHeader( DataInputStream dStream ) {
46       magic = readU4( dStream );
47       minor_version = (short)readU2( dStream );
48       major_version = (short)readU2( dStream );
49     } // classFileHeader constructor
50   
51     void pr() {
52       System.out.println("magic number: 0x" + Integer.toHexString( magic ));
53       System.out.println("Java version " + major_version + "." + minor_version );
54     }
55   
56   } // classFileHeader
57   
58   
59   
60   
61   /** 
62      Read the JVM class file information that defines the class header.
63      This information is the access modifier information (access_flags),
64      the class name (this_class), the super class (super_class) and the
65      interface list (interface_count and interfaces[]).  Note that if
66      the interface_flags field is ACC_INTERFACE its not a class but an
67      interface.
68   
69     @author Ian Kaplan
70   
71    */
72   class classDeclSec extends dataRead implements access_and_modifier_flags {
73     private int accessFlags = 0;
74     private constBase thisClass = null;
75     private constBase superClass = null;
76     private constBase interfaces[] = null;
77   
78     classDeclSec( DataInputStream dStream, constPool constPoolSec ) {
79       int thisClassIx;
80       int superClassIx;
81       int interfaceCnt;
82       
83       accessFlags = readU2( dStream );
84       thisClassIx = readU2( dStream );
85       superClassIx = readU2( dStream );
86   
87       thisClass = constPoolSec.constPoolElem( thisClassIx );
88       superClass = constPoolSec.constPoolElem( superClassIx );
89   
90       interfaceCnt = readU2( dStream );
91   
92       if (interfaceCnt > 0) {
93         int ix;
94   
95         interfaces = new constBase[ interfaceCnt ];
96         for (int i = 0; i < interfaceCnt; i++) {
97   	ix = readU2( dStream );
98   	interfaces[ i ] = constPoolSec.constPoolElem( ix );
99         }
100      }
101    } // classDeclSec constructor
102  
103  
104    String getClassName() {
105      String name = null;
106  
107      if (thisClass != null) {
108        if (thisClass instanceof constClass_or_String) {
109  	name = objNameFormat.toDotSeparator( thisClass.getString() );
110        }
111      }
112  
113      return name;
114    } // getClassName
115  
116    /**
117       Print the class modifiers
118     */
119    private void pr_modifiers( int mod ) {
120      String modStr;
121  
122      modStr = accString.toString( mod, false /* not a method */  );
123      if (modStr != null) {
124        System.out.print( modStr );
125      }
126    } // pr_modifiers
127  
128  
129    void pr() {
130      pr_modifiers( accessFlags );
131      if ((accessFlags & ACC_INTERFACE) == 0) {
132        if (accessFlags > 0) {
133  	System.out.print(" ");
134        }
135        System.out.print("class ");
136      }
137  
138      System.out.print( getClassName() );
139      
140      // only print the super class if it is NOT java.lang.Object
141      if (superClass != null) {
142        if (superClass instanceof constClass_or_String) {
143  	if (superClass.getString().compareTo( "java/lang/Object" ) != 0) {
144  	  String superClassName;
145  
146  	  superClassName = superClass.getString();
147  	  superClassName = objNameFormat.toDotSeparator(superClassName);
148  	  System.out.print(" extends " + superClassName );
149  	}
150        }
151      }
152  
153      if (interfaces != null) {
154        boolean firstName = true;
155  
156        System.out.print(" implements ");
157  
158        for (int i = 0; i < interfaces.length; i++) {
159  	if (! firstName) {
160  	  System.out.print(", ");
161  	}
162  	else {
163  	  firstName = false;
164  	}
165  	if (interfaces[i] != null) {
166  	  if (interfaces[i] instanceof constClass_or_String) {
167  	    interfaces[i].prString();
168  	  }
169  	  else {
170  	    System.out.println(" classDeclSec: interfaces[" + i + "] is a " +
171  			       interfaces[i].getClass().getName() );
172  	  }
173  	}
174  	else {
175  	  System.out.print("<null>");
176  	}
177        } // for
178      }
179      System.out.println(" {");
180    } // pr
181  
182  } // classDeclSec
183  
184  
185  
186  /**
187  
188     As described in the JVM Specification, the field_info
189     is:
190  
191  <pre>
192     field_info {
193       u2 access_flags;
194       u2 name_index;        (Utf8 in the constant pool)
195       u2 descriptor_index;  (Utf8 in the constant pool)
196       u2 attributes_cnt;
197       attribute_info attributes[ attributes_cnt ];
198     }
199  </pre>
200  
201  <p>
202     The only attribute defined for the attributes table of a
203     field_info structure by the JVM Specification is the 
204     ConstantValue attribute
205  
206    @author Ian Kaplan
207  
208   */
209  class fieldInfo extends dataRead {
210    int access_flags = 0;
211    constUtf8 name = null;
212    constUtf8 descriptor = null;
213    attrInfo attributes[] = null;
214  
215    fieldInfo( DataInputStream dStream, constPool constPoolSec ) {
216      int name_index;
217      int desc_index;
218      int attr_cnt;
219      constBase obj;
220  
221      access_flags = readU2( dStream );
222      name_index   = readU2( dStream );
223      desc_index   = readU2( dStream );
224      attr_cnt     = readU2( dStream );
225      
226      obj = constPoolSec.constPoolElem( name_index );
227      if (obj != null && obj instanceof constUtf8) {
228        name = (constUtf8)obj;
229      }
230  
231      obj = constPoolSec.constPoolElem( desc_index );
232      if (obj != null && obj instanceof constUtf8) {
233        descriptor = (constUtf8)obj;
234      }
235  
236      if (attr_cnt > 0) {
237        attributes = new attrInfo[ attr_cnt ];
238        for (int i = 0; i < attr_cnt; i++) {
239  	attributes[i] = attrFactory.allocAttr( dStream, constPoolSec );
240  	if (attributes[i].getName().compareTo( "ConstantValue" ) != 0 &&
241  	    attributes[i].getName().compareTo( "Synthetic" ) != 0     &&
242  	    attributes[i].getName().compareTo( "Deprecated" ) != 0 ) {
243  	  errorMessage.errorPrint("fieldInfo: field info attribute expected");
244  	  errorMessage.errorPrint("fieldInfo: attr name = " + 
245  				  attributes[i].getName() );
246  	}
247        }
248      }
249    } // fieldInfo constructor
250  
251  
252  
253    /**
254       Create a string for the field in something like Java
255       source format.  Field strings have the format:
256  <pre>
257           <access-modifiers> <type> <name>
258  </pre>
259  
260  <p>
261       The access modifiers are described by the access_flags.
262       The type is described by the descriptor and the name
263       is referenced by the "name" object.
264  
265      @Return return a the field in something like Java source format
266     */
267    String fieldString() {
268      String modStr;  // access/modifiers (e.g., private static)
269      String typeStr; // type
270      StringBuffer fieldStr = new StringBuffer();
271  
272      modStr = accString.toString( access_flags, false /* not a method */ );
273      typeStr = typeDesc.decodeFieldDesc( descriptor.getString() );
274      if (modStr != null) {
275        fieldStr.append( modStr );
276        fieldStr.append(" ");
277      }
278      fieldStr.append( typeStr );
279      fieldStr.append(" ");
280      fieldStr.append( name.getString() );
281  
282      /*
283         Process the attribute table information
284       */
285      boolean isSynthetic = false;
286      boolean isDeprecated = false;
287      constValueAttr constAttr;
288      constBase constVal;
289      boolean firstConst = true;
290      String initVal = null;
291      String tmp = null;
292  
293      if (attributes != null) {
294        for (int i = 0; i < attributes.length; i++) {
295  	if (attributes[i] instanceof constValueAttr) {
296  	  constAttr = (constValueAttr)attributes[i];
297  	  constVal = constAttr.getConstVal();
298  	  if (constVal instanceof constClass_or_String ) {
299  	    tmp = ((constClass_or_String)constVal).getPrintableString();
300  	  }
301  	  else {
302  	    tmp = constVal.getString();
303  	  }
304  	  if (firstConst) {
305  	    firstConst = false;
306  	    initVal = tmp;
307  	  }
308  	  else {
309  	    initVal = initVal + ", " + tmp;
310  	  }
311  	}
312  	else if (attributes[i] instanceof synthAttr) {
313  	  isSynthetic = true;
314  	}
315  	else if (attributes[i] instanceof deprecAttr) {
316  	  isDeprecated = true;
317  	}
318        } // for
319        
320        if (accData.isStatic( access_flags) && initVal != null) {
321  	fieldStr.append(" = ");
322  	fieldStr.append( initVal );
323        } // if static
324        fieldStr.append(";");
325        if (isSynthetic || isDeprecated )
326  	fieldStr.append(" //");
327        if (isSynthetic) {
328  	fieldStr.append(" Synthetic");
329        }
330        if (isDeprecated) {
331  	fieldStr.append(", Deprecated");
332        }
333      } // if attributes != null
334      else
335        fieldStr.append(";");
336      return fieldStr.toString();
337    } // fieldString
338  
339   
340    /**
341      Print the field
342     */
343    void pr() {
344      System.out.println( fieldString() );
345    } // pr
346  
347  } // fieldInfo
348  
349  
350  
351  /** 
352     Read the class field section and build representative
353     classes.  The class field section is composed of a
354     field count and an array of field_info data structures.
355  
356  <pre>
357        u2 field_cnt;
358        field_info fields[ field_cnt ];
359  </pre>
360  
361    @author Ian Kaplan
362  
363   */
364  class classFieldSec extends dataRead {
365    private fieldInfo classFields[] = null;
366  
367    classFieldSec( DataInputStream dStream, constPool constPoolSec ) {
368      int field_cnt;
369  
370      field_cnt = readU2( dStream );
371      if (field_cnt > 0) {
372        classFields = new fieldInfo[ field_cnt ];
373      }
374  
375      // initialize the fieldInfo array
376      for (int i = 0; i < field_cnt; i++) {
377        classFields[i] = new fieldInfo( dStream, constPoolSec );
378      } // for
379  
380    } // classFieldSec constructor
381  
382  
383  
384    /** Print the class fields
385      */
386    void pr() {
387      if (classFields != null) {
388        fieldInfo info;
389  
390        for (int i = 0; i < classFields.length; i++) {
391  	info = classFields[i];
392  	System.out.print("   ");
393  	if (info != null) {
394  	  info.pr();
395  	}
396  	else {
397  	  System.out.println("\nclassFieldSec: pr - null at classFields[" + i + "]");
398  	}
399        }
400      }
401    } // pr
402  
403  } // classFieldSec
404  
405  
406  
407  /**
408  
409     The fields of the methodInfo structure are the same as those of the
410     fieldInfo structure.  However, the semantics of the two structures
411     differ enough that they are implemented by two different objects.
412     For example, in the case of the fieldInfo structure only the
413     constValueAttr is allowed.  The attributes that are allowed for a
414     methodInfo attribute are:
415  
416        <ul>
417        <li>
418        Code
419        </li>
420        <li>
421        Exceptions
422        </li>
423        <li>
424        Synthetic
425        </li>
426        <li>
427        Deprecated
428        </li>
429        </ul>
430  
431  <p>
432     Allowed access modifiers for a method are:
433  
434        <ul>
435        <li>
436        private
437        </li>
438        <li>
439        protected
440        </li>
441        <li>
442        public
443        </li>
444        </ul>
445  
446  <p>
447  Other modifiers are
448   
449  <ul>
450        <li>
451        abstract
452        </li>
453        <li>
454        final
455        </li>
456        <li>
457        native
458        </li>
459        <li>
460        static
461        </li>
462        <li>
463        strict
464        </li>
465        <li>
466        synchronized
467        </li>
468  <ul>
469  
470  <pre>
471     method_info {
472       u2 access_flags;
473       u2 name_index;        (Utf8 in the constant pool)
474       u2 descriptor_index;  (Utf8 in the constant pool)
475       u2 attributes_cnt;
476       attribute_info attributes[ attributes_cnt ];
477     }
478  </pre>
479  <p>
480     There should not be more than one code attribute for a method.
481     Code attributes are special in that they provide extra information
482     about the method in the code attribute attribute table.  For example,
483     the code attribute contains information about the local variables
484     in the method.
485  
486    @author Ian Kaplan
487   */
488  class methodInfo extends dataRead implements access_and_modifier_flags {
489    int access_flags = 0;
490    constUtf8 name = null;
491    String constructorName = null;
492    constUtf8 descriptor = null;
493    attrInfo attributes[] = null;
494    codeAttr codeAttribute = null;
495  
496  
497    methodInfo( DataInputStream dStream, constPool constPoolSec ) {
498      int name_index;
499      int desc_index;
500      int attr_cnt;
501      constBase obj;
502  
503      access_flags = readU2( dStream );
504      name_index   = readU2( dStream );
505      desc_index   = readU2( dStream );
506      attr_cnt     = readU2( dStream );
507      
508      obj = constPoolSec.constPoolElem( name_index );
509      if (obj != null && obj instanceof constUtf8) {
510        name = (constUtf8)obj;
511      }
512  
513      obj = constPoolSec.constPoolElem( desc_index );
514      if (obj != null && obj instanceof constUtf8) {
515        descriptor = (constUtf8)obj;
516      }
517  
518      // methodInfo objects differ from fieldInfo objects in
519      // the allowed attributes.
520      if (attr_cnt > 0) {
521        attributes = new attrInfo[ attr_cnt ];
522        for (int i = 0; i < attr_cnt; i++) {
523  	attributes[i] = attrFactory.allocAttr( dStream, constPoolSec );
524  	if (attributes[i] instanceof codeAttr)
525  	  codeAttribute = (codeAttr)attributes[i];
526        } // for
527      }
528    } // methodInfo constructor
529  
530  
531    /**
532      Class constructors have the internal name "<init>".  Return
533      true if this is the name of the current constructor.
534     */
535    public boolean isConstructor() {
536      return (name.getString().compareTo("<init>") == 0);
537    }
538  
539  
540    /**
541      Set the name of the constructor name
542      */
543    public void setConstructorName( String newName ) {
544      constructorName = newName;
545    }
546  
547  
548    /**
549      @return return the constructor name
550      */
551    public String getConstructorName() {
552      return constructorName;
553    }
554  
555  
556    /**
557      If there are synthetic or deprecated attributes in
558      the method attribute table, return a comment string
559      showing the appropriate attribute.  Otherwise return
560      null.
561      */
562    private String commentString() {
563      String str = null;
564  
565      if (attributes != null) {
566        for (int i = 0; i < attributes.length; i++) {
567  	if (attributes[i] instanceof synthAttr) {
568  	  if (str == null)
569  	    str = "// ";
570  	  else
571  	    str = str + ", ";
572  	  str = str + "synthetic";
573  	}
574  	if (attributes[i] instanceof deprecAttr) {
575  	  if (str == null)
576  	    str = "// ";
577  	  else
578  	    str = str + ", ";
579  	  str = str + "deprecated";
580  	}
581        }
582      }
583      return str;
584    } // commentString
585  
586  
587    /**
588      Return a string containing "\n     throws <exception-class-list>"
589      if the method has associated exceptions.  Otherwise return
590      null.
591  <p>
592      The exception attribute has a table of exceptions that are
593      associated with the class method.  So there should only
594      be one exceptions attribute associated with a given
595      method.
596      */
597    private String exceptionString() {
598      String str = null;
599      
600      if (attributes != null) {
601        String exceptList = null;  // exception list
602  
603        for (int i = 0; i < attributes.length; i++) {
604  	if (attributes[i] instanceof exceptAttr) {
605  	  exceptAttr eAttr;
606  	  constClass_or_String exceptTab[];
607  
608  	  eAttr = (exceptAttr)attributes[i];
609  	  exceptTab = eAttr.getExceptTab();
610  	  if (exceptTab != null && exceptTab.length > 0) {
611  	    String className;
612  
613  	    // build exception list
614  	    for (int j = 0; j < exceptTab.length; j++) {
615  	      className = exceptTab[j].getString();
616  	      className = objNameFormat.toDotSeparator( className );
617  	      if (exceptList == null) {
618  		exceptList = className;
619  	      }
620  	      else {
621  		exceptList = exceptList + ", " + className;
622  	      }
623  	    } // for
624  	  }
625  	  break;
626  	}
627        } // for
628        if (exceptList != null) {
629  	str = "\n     throws " + exceptList;
630        }
631      }
632      return str;
633    } // exceptionString
634  
635  
636    /**
637      The methodTypes class is used by the methodTypes method
638      to return the argument list string and the return type
639      that are built from the method descriptor.
640  <p>
641      A StringBuffer object is used for argList with the thought
642      that appending to a string buffer may cause less memory
643      garbage and be faster.  But this could be a mistaken idea.
644  
645      */
646    class methodTypes {
647      public StringBuffer argList;
648      public String returnType;
649  
650      methodTypes() {
651        argList = new StringBuffer();
652      }
653    } // methodTypes
654  
655  
656    /**
657      Decode the method descriptor and return the argument list
658      and return type.
659  <p>
660      The method descriptor describes the arguments to the method.
661      The format for the method descriptor is:
662  
663        '(' (type-descriptor)* ')' return-type
664  
665      The method argument descriptor starts with '(' and consists
666      of zero or more type descriptions.  Types are described by
667      either a single letter (see util.typeDesc class) or
668      an object path terminated by a semicolon.  In the same way,
669      the return type will either be an object path, an atomic
670      type or "void", which is indicated by the letter 'V'.
671      See section 4.3.3 of the JVM Spec.
672  
673      Note that the character that denotes an object path start is
674      "L".  So lets say we have the following method declaration:
675  
676        myObj foo(int i, double d, long l, barObj b, char c) {...}
677  
678      This method would have the method descriptor
679  
680         (IDJLmypkg/barObj;C)Lmypkg/myObj;
681  
682      The descriptor arguments are enclosed by parenthesis.  The
683      IDJ represents the int, double and long arguments.  The barObj
684      argument is represented by the "Lmypkg/barObj;", where 'L'
685      denotes the start of the object path and ';' terminates the
686      path.
687  
688     */
689    private methodTypes decodeMethodDesc( String methodDesc ) {
690      methodTypes types = null;
691  
692      if (methodDesc != null) {
693        int len = methodDesc.length();
694        int ix = 0;
695  
696        types = new methodTypes();
697        
698        if (methodDesc.charAt(ix) == '(') {
699  	String typeName;
700  	char ch;
701  	int dimCnt;  // array dimension count
702  	boolean first_type = true;
703  
704  	for (ix++; ix < len && methodDesc.charAt(ix) != ')'; ix++) {
705  	  ch = methodDesc.charAt(ix);
706  	  dimCnt = 0;
707  
708  	  // pick up the array dimension description
709  	  while (ch == '[') {
710  	    dimCnt++;
711  	    ix++;
712  	    ch = methodDesc.charAt(ix);
713  	  }
714  
715  	  if (ch == 'L') { // The type is a class (represented by a class path)
716  	    String objName;
717  	    int jx;
718  
719  	    ix++; // ix is now the String index following the 'L'
720  	    // find the string index of the next ';' which terminates
721  	    // the object name
722  	    for (jx = ix; jx < len && methodDesc.charAt(jx) != ';'; jx++)
723  	      /* nada */;
724  
725  	    objName = methodDesc.substring(ix, jx);
726  	    typeName = objNameFormat.toDotSeparator( objName );
727  	    ix = jx;  // ix now points to the ';'
728  	  } 
729  	  else if (typeDesc.isTypeChar( ch )) {
730  	    // the character is a base type character, so get the
731  	    // corresponding type name.
732  	    typeName = typeDesc.charToType( ch );
733  	  }
734  	  else {
735  	    errorMessage.errorPrint("decodeMethodDesc: unexpected char");
736  	    typeName = null;
737  	  }
738  	  // add the array dimensions to the end of the type
739  	  for (int i = 0; i < dimCnt; i++) {
740  	    typeName = typeName + "[]";
741  	  }
742  	  if (typeName != null) {
743  	    if (first_type) {
744  	      first_type = false;
745  	      types.argList.append( typeName );
746  	    }
747  	    else {
748  	      types.argList.append(", ");
749  	      types.argList.append( typeName );
750  	    }
751  	  }
752  	} // for
753  	if (ix < len && methodDesc.charAt(ix) == ')') {
754  	  // get the return type
755  	  ix++;
756  
757  	  ch = methodDesc.charAt(ix);
758  	  if (ch == 'V') // return type is void
759  	    types.returnType = "void";
760  	  else if (ch == 'L') {
761  	    ix++;
762  	    typeName = methodDesc.substring( ix );
763  	    types.returnType = objNameFormat.toDotSeparator( typeName );
764  	  } 
765  	  else if (typeDesc.isTypeChar( ch )) {
766  	    types.returnType = typeDesc.charToType( ch );
767  	  }
768  	}
769  	else
770  	  errorMessage.errorPrint("decodeMethodDesc: ')' expected");
771        }
772        else
773  	errorMessage.errorPrint("decodeMethodDesc: '(' expected");
774      }
775  
776      return types;
777    } // decodeMethodDesc
778  
779  
780    /**
781      This method is passed the string that should be used
782      to terminate the method declaration.  If there are local
783      variable declarations in the codeAttribute table (e.g., the
784      class was compiled with debug) the terminal string will
785      be " {".  If there are no local variables or the class was
786      compiled without debug the terminal character will be ";"
787  
788      @Return a string representing the method declaration
789      */
790    String methodString(String terminalStr ) {
791      StringBuffer methodBuf = new StringBuffer();
792  
793      // modifiers (e.g., private, native, etc...).  May be null
794      String modifiers = accString.toString( access_flags, true );
795      methodTypes types = decodeMethodDesc( descriptor.getString() );
796  
797      // add any method modifiers (e.g., private, protected, ...)
798      if (modifiers != null) {
799        methodBuf.append( modifiers);
800        methodBuf.append(" ");
801      }
802  
803      // Add the return type and method name.  All methods have a type 
804      // (if no return value, then void) do this should never be null.
805      methodBuf.append( types.returnType);
806      methodBuf.append( " " );
807      if (constructorName == null)
808        methodBuf.append( name.getString() );
809      else
810        methodBuf.append( constructorName );
811      methodBuf.append( "(" );
812  
813      if (types.argList != null) {
814        methodBuf.append( types.argList.toString() );
815      }
816  
817      methodBuf.append(")");
818  
819      // get synthetic/deprecated comment
820      String cmntStr = commentString();
821      // get any exceptions
822      String excptStr = exceptionString();
823  
824      if (excptStr == null) { // there are no exceptions
825        methodBuf.append( terminalStr );
826      }
827  
828      // Append the a comment re. synthetic or deprecated attributes
829      if (cmntStr != null) {
830        methodBuf.append(" ");
831        methodBuf.append( cmntStr );
832      }
833  
834      // Append the exception part of the method declaration.
835      // If the exception exists there will be a carriage return
836      // and an indent placed between the method declaration and
837      // the exception declaration.
838      if (excptStr != null) {
839        methodBuf.append( excptStr );
840        methodBuf.append( terminalStr );
841      }
842  
843      return methodBuf.toString();
844    } // methodString
845  
846  
847    /**
848      Print method declaration (e.g., private int foobar( int x )
849      and any local variables.
850  
851     */
852    void pr() {
853      final String indent1 = "   ";
854      final String indent2 = "     ";
855      boolean printed_header = false;
856  
857      if (codeAttribute != null) {      // print local variables
858        Vector localVarVec = codeAttribute.getLocalVarVec();
859  
860        if (localVarVec != null) {
861  	int len = localVarVec.size();
862  	String localVar;
863  
864  	if (len > 0) {
865  	  System.out.println(indent1 + methodString( " {" ) );
866  	  printed_header = true;
867  	}
868         
869  	for (int i = 0; i < len; i++) {
870  	  localVar = (String)localVarVec.elementAt( i );
871  	  System.out.println( indent2 + localVar);
872  	}
873        }
874      }
875      if (! printed_header)
876        System.out.println(indent1 + methodString( ";" ) );
877      else
878        System.out.println( indent1 + "}" );
879    } // pr
880  
881  } // methodInfo
882  
883  
884  /**
885  
886     Read the class method section and build representative
887     classes.  The class method section is composed of a 
888     method count and array of method_info data structures.
889  
890  <pre>
891        u2 method_cnt;
892        method_info methods[ method_cnt ];
893  </pre>
894  
895    @author Ian Kaplan
896   */
897  class classMethodSec extends dataRead {
898    methodInfo classMethods[];
899  
900    classMethodSec( DataInputStream dStream, 
901  		  constPool constPoolSec,
902  		  String className ) {
903      int methodCnt;
904  
905      methodCnt = readU2( dStream );
906      if (methodCnt > 0) {
907        classMethods = new methodInfo[ methodCnt ];
908      }
909  
910      for (int i = 0; i < methodCnt; i++) {
911        classMethods[i] = new methodInfo( dStream, constPoolSec );
912        if (classMethods[i].isConstructor())
913  	classMethods[i].setConstructorName( className );
914      }
915    } // classMethodSec constructor
916  
917  
918    void pr() {
919      if (classMethods != null) {
920        // print a blank line between the class members and the methods
921        System.out.println();
922        for (int i = 0; i < classMethods.length; i++) {
923  	classMethods[i].pr();
924        }
925      }
926    } // pr
927  
928  } // classMethodSec
929  
930  
931  
932  
933  /** 
934  
935   The classAttrSec object contains the attribute table that ends the
936   class file.  The only attributes that appear in this section are the
937   SourceFile attribute (srcFileAttr object), the InnerClasses attribute
938   or the Depreciated attribute.
939  
940   */
941  class classAttrSec extends dataRead {
942    attrInfo classAttrTab[] = null;
943  
944    classAttrSec( DataInputStream dStream, constPool constPoolSec ) {
945  
946      int numAttr = readU2( dStream );
947      
948      if (numAttr > 0) {
949        classAttrTab = new attrInfo[ numAttr ];
950        for (int i = 0; i < numAttr; i++) {
951  	classAttrTab[i] = attrFactory.allocAttr( dStream, constPoolSec );
952        }
953      }
954    } // classAttrSec
955  
956    /** 
957  
958      Return the name of the source file that generated the class file.
959      There should only be one source file in the ClassFile attribute
960      table.
961  
962      @return a String for the source file name.
963  
964     */
965    String getSrcFileName() {
966      String name = null;
967  
968      if (classAttrTab != null) {
969        for (int i = 0; i < classAttrTab.length; i++) {
970  	if (classAttrTab[i] instanceof srcFileAttr) {
971  	  srcFileAttr src;
972  
973  	  src = (srcFileAttr)classAttrTab[i];
974  	  name = src.getFileName();
975  	  break;
976  	}
977        } // for
978      }
979      
980      return name;
981    } // getSrcFileName
982  
983  } // classAttrSec
984  
985  
986  
987  
988  
989  /**
990  
991    The classFile object contains the information from a
992    single Java class file.  The class file format is
993    described in The Java Virtual Machine Specification,
994    Second Edition, Lindholm and elin, Addison and Westley
995  
996  <p>
997    A class file contains a single ClassFile structure: 
998  
999  <pre>
1000     ClassFile {
1001         u4 magic;
1002         u2 minor_version;
1003         u2 major_version;
1004         u2 constant_pool_count;
1005         cp_info constant_pool[constant_pool_count-1];
1006         u2 access_flags;
1007         u2 this_class;
1008         u2 super_class;
1009         u2 interfaces_count;
1010         u2 interfaces[interfaces_count];
1011         u2 fields_count;
1012         field_info fields[fields_count];
1013         u2 methods_count;
1014         method_info methods[methods_count];
1015         u2 attributes_count;
1016         attribute_info attributes[attributes_count];
1017     }
1018 </pre>
1019 
1020 */
1021 public class classFile {
1022   classFileHeader header = null;
1023   constPool classConstPool = null;
1024   classDeclSec classDecl = null;
1025   classFieldSec classFields = null;
1026   classMethodSec classMethods = null;
1027   classAttrSec classAttrs = null;
1028   String className = null;
1029 
1030 
1031   /**
1032 
1033      classFile constructor.
1034 
1035 <p>
1036      The classFile constructor allocates a set of objects
1037      which corresponds to the various sections of the Java
1038      class file.  Each of these objects reads its own section
1039      and builds any data structures needed (e.g., tables) to
1040      represent the information.
1041 
1042    */
1043   public classFile(DataInputStream dStream) {
1044 
1045     // u4 magic;
1046     // u2 minor_version;
1047     // u2 major_version;
1048     header = new classFileHeader( dStream );
1049 
1050     // u2 constant_pool_count;
1051     // cp_info constant_pool[constant_pool_count-1];
1052     classConstPool = new constPool( dStream );
1053 
1054     // u2 access_flags;
1055     // u2 this_class;
1056     // u2 super_class;
1057     // u2 interfaces_count;
1058     // u2 interfaces[interfaces_count];
1059     classDecl = new classDeclSec( dStream, classConstPool );
1060 
1061     // u2 fields_count;
1062     // field_info fields[fields_count];
1063     classFields = new classFieldSec(dStream, classConstPool);
1064 
1065     className = classDecl.getClassName();
1066 
1067     // u2 methods_count;
1068     // method_info methods[methods_count];
1069     classMethods = new classMethodSec(dStream, classConstPool, className );
1070 
1071     // u2 attributes_count;
1072     // attribute_info attributes[attributes_count];
1073     classAttrs = new classAttrSec(dStream, classConstPool);
1074   } // classFile
1075 
1076   /**
1077     Print the class file in a source format resembling
1078     Java.
1079 
1080     */
1081   public void pr() {
1082     String srcFile;
1083 
1084     srcFile = classAttrs.getSrcFileName();
1085     if (srcFile != null) {
1086       System.out.println("Compiled from " + srcFile + "\n");
1087       classDecl.pr();
1088       classFields.pr();
1089       classMethods.pr();
1090       System.out.println(" } // " + className + "\n");
1091     }
1092   } // pr
1093 
1094 } // classFile
1095