javap/src/main/java/org/apidesign/javap/ClassData.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 01 Dec 2012 08:52:30 +0100
branchreflection
changeset 225 25e350c6385f
parent 169 6f2aef4cf160
child 228 c40f70283620
permissions -rw-r--r--
Adding each constructor function field
     1 /*
     2  * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 
    26 
    27 package org.apidesign.javap;
    28 
    29 import java.io.*;
    30 
    31 /**
    32  * Central data repository of the Java Disassembler.
    33  * Stores all the information in java class file.
    34  *
    35  * @author  Sucheta Dambalkar (Adopted code from jdis)
    36  */
    37 public final class ClassData implements RuntimeConstants {
    38 
    39     private int magic;
    40     private int minor_version;
    41     private int major_version;
    42     private int cpool_count;
    43     private Object cpool[];
    44     private int access;
    45     private int this_class = 0;;
    46     private int super_class;
    47     private int interfaces_count;
    48     private int[] interfaces = new int[0];;
    49     private int fields_count;
    50     private FieldData[] fields;
    51     private int methods_count;
    52     private MethodData[] methods;
    53     private InnerClassData[] innerClasses;
    54     private int attributes_count;
    55     private AttrData[] attrs;
    56     private String classname;
    57     private String superclassname;
    58     private int source_cpx=0;
    59     private byte tags[];
    60     private Hashtable indexHashAscii = new Hashtable();
    61     private String pkgPrefix="";
    62     private int pkgPrefixLen=0;
    63 
    64     /**
    65      * Read classfile to disassemble.
    66      */
    67     public ClassData(InputStream infile) throws IOException {
    68         this.read(new DataInputStream(infile));
    69     }
    70 
    71     /**
    72      * Reads and stores class file information.
    73      */
    74     public void read(DataInputStream in) throws IOException {
    75         // Read the header
    76         magic = in.readInt();
    77         if (magic != JAVA_MAGIC) {
    78             throw new ClassFormatError("wrong magic: " +
    79                                        toHex(magic) + ", expected " +
    80                                        toHex(JAVA_MAGIC));
    81         }
    82         minor_version = in.readShort();
    83         major_version = in.readShort();
    84         if (major_version != JAVA_VERSION) {
    85         }
    86 
    87         // Read the constant pool
    88         readCP(in);
    89         access = in.readUnsignedShort();
    90         this_class = in.readUnsignedShort();
    91         super_class = in.readUnsignedShort();
    92 
    93         //Read interfaces.
    94         interfaces_count = in.readUnsignedShort();
    95         if(interfaces_count > 0){
    96             interfaces = new int[interfaces_count];
    97         }
    98         for (int i = 0; i < interfaces_count; i++) {
    99             interfaces[i]=in.readShort();
   100         }
   101 
   102         // Read the fields
   103         readFields(in);
   104 
   105         // Read the methods
   106         readMethods(in);
   107 
   108         // Read the attributes
   109         attributes_count = in.readUnsignedShort();
   110         attrs=new AttrData[attributes_count];
   111         for (int k = 0; k < attributes_count; k++) {
   112             int name_cpx=in.readUnsignedShort();
   113             if (getTag(name_cpx)==CONSTANT_UTF8
   114                 && getString(name_cpx).equals("SourceFile")
   115                 ){      if (in.readInt()!=2)
   116                     throw new ClassFormatError("invalid attr length");
   117                 source_cpx=in.readUnsignedShort();
   118                 AttrData attr=new AttrData(this);
   119                 attr.read(name_cpx);
   120                 attrs[k]=attr;
   121 
   122             } else if (getTag(name_cpx)==CONSTANT_UTF8
   123                        && getString(name_cpx).equals("InnerClasses")
   124                        ){       int length=in.readInt();
   125                        int num=in.readUnsignedShort();
   126                        if (2+num*8 != length)
   127                            throw new ClassFormatError("invalid attr length");
   128                        innerClasses=new InnerClassData[num];
   129                        for (int j = 0; j < num; j++) {
   130                            InnerClassData innerClass=new InnerClassData(this);
   131                            innerClass.read(in);
   132                            innerClasses[j]=innerClass;
   133                        }
   134                        AttrData attr=new AttrData(this);
   135                        attr.read(name_cpx);
   136                        attrs[k]=attr;
   137             } else {
   138                 AttrData attr=new AttrData(this);
   139                 attr.read(name_cpx, in);
   140                 attrs[k]=attr;
   141             }
   142         }
   143         in.close();
   144     } // end ClassData.read()
   145 
   146     /**
   147      * Reads and stores constant pool info.
   148      */
   149     void readCP(DataInputStream in) throws IOException {
   150         cpool_count = in.readUnsignedShort();
   151         tags = new byte[cpool_count];
   152         cpool = new Object[cpool_count];
   153         for (int i = 1; i < cpool_count; i++) {
   154             byte tag = in.readByte();
   155 
   156             switch(tags[i] = tag) {
   157             case CONSTANT_UTF8:
   158                 String str=in.readUTF();
   159                 indexHashAscii.put(cpool[i] = str, new Integer(i));
   160                 break;
   161             case CONSTANT_INTEGER:
   162                 cpool[i] = new Integer(in.readInt());
   163                 break;
   164             case CONSTANT_FLOAT:
   165                 cpool[i] = new Float(in.readFloat());
   166                 break;
   167             case CONSTANT_LONG:
   168                 cpool[i++] = new Long(in.readLong());
   169                 break;
   170             case CONSTANT_DOUBLE:
   171                 cpool[i++] = new Double(in.readDouble());
   172                 break;
   173             case CONSTANT_CLASS:
   174             case CONSTANT_STRING:
   175                 cpool[i] = new CPX(in.readUnsignedShort());
   176                 break;
   177 
   178             case CONSTANT_FIELD:
   179             case CONSTANT_METHOD:
   180             case CONSTANT_INTERFACEMETHOD:
   181             case CONSTANT_NAMEANDTYPE:
   182                 cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
   183                 break;
   184 
   185             case 0:
   186             default:
   187                 throw new ClassFormatError("invalid constant type: " + (int)tags[i]);
   188             }
   189         }
   190     }
   191 
   192     /**
   193      * Reads and strores field info.
   194      */
   195     protected void readFields(DataInputStream in) throws IOException {
   196         int fields_count = in.readUnsignedShort();
   197         fields=new FieldData[fields_count];
   198         for (int k = 0; k < fields_count; k++) {
   199             FieldData field=new FieldData(this);
   200             field.read(in);
   201             fields[k]=field;
   202         }
   203     }
   204 
   205     /**
   206      * Reads and strores Method info.
   207      */
   208     protected void readMethods(DataInputStream in) throws IOException {
   209         int methods_count = in.readUnsignedShort();
   210         methods=new MethodData[methods_count];
   211         for (int k = 0; k < methods_count ; k++) {
   212             MethodData method=new MethodData(this);
   213             method.read(in);
   214             methods[k]=method;
   215         }
   216     }
   217 
   218     /**
   219      * get a string
   220      */
   221     public String getString(int n) {
   222         if (n == 0) {
   223             return null; 
   224         } else {
   225             return (String)cpool[n];
   226         }
   227     }
   228 
   229     /**
   230      * get the type of constant given an index
   231      */
   232     public byte getTag(int n) {
   233         try{
   234             return tags[n];
   235         } catch (ArrayIndexOutOfBoundsException e) {
   236             return (byte)100;
   237         }
   238     }
   239 
   240     static final String hexString="0123456789ABCDEF";
   241 
   242     public static char hexTable[]=hexString.toCharArray();
   243 
   244     static String toHex(long val, int width) {
   245         StringBuffer s = new StringBuffer();
   246         for (int i=width-1; i>=0; i--)
   247             s.append(hexTable[((int)(val>>(4*i)))&0xF]);
   248         return "0x"+s.toString();
   249     }
   250 
   251     static String toHex(long val) {
   252         int width;
   253         for (width=16; width>0; width--) {
   254             if ((val>>(width-1)*4)!=0) break;
   255         }
   256         return toHex(val, width);
   257     }
   258 
   259     static String toHex(int val) {
   260         int width;
   261         for (width=8; width>0; width--) {
   262             if ((val>>(width-1)*4)!=0) break;
   263         }
   264         return toHex(val, width);
   265     }
   266 
   267     /**
   268      * Returns the name of this class.
   269      */
   270     public String getClassName() {
   271         String res=null;
   272         if (this_class==0) {
   273             return res;
   274         }
   275         int tcpx;
   276         try {
   277             if (tags[this_class]!=CONSTANT_CLASS) {
   278                 return res; //"<CP["+cpx+"] is not a Class> ";
   279             }
   280             tcpx=((CPX)cpool[this_class]).cpx;
   281         } catch (ArrayIndexOutOfBoundsException e) {
   282             return res; // "#"+cpx+"// invalid constant pool index";
   283         } catch (Throwable e) {
   284             return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   285         }
   286 
   287         try {
   288             return (String)(cpool[tcpx]);
   289         } catch (ArrayIndexOutOfBoundsException e) {
   290             return  res; // "class #"+scpx+"// invalid constant pool index";
   291         } catch (ClassCastException e) {
   292             return  res; // "class #"+scpx+"// invalid constant pool reference";
   293         } catch (Throwable e) {
   294             return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   295         }
   296 
   297     }
   298 
   299     /**
   300      * Returns the name of class at perticular index.
   301      */
   302     public String getClassName(int cpx) {
   303         String res="#"+cpx;
   304         if (cpx==0) {
   305             return res;
   306         }
   307         int scpx;
   308         try {
   309             if (tags[cpx]!=CONSTANT_CLASS) {
   310                 return res; //"<CP["+cpx+"] is not a Class> ";
   311             }
   312             scpx=((CPX)cpool[cpx]).cpx;
   313         } catch (ArrayIndexOutOfBoundsException e) {
   314             return res; // "#"+cpx+"// invalid constant pool index";
   315         } catch (Throwable e) {
   316             return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   317         }
   318         res="#"+scpx;
   319         try {
   320             return (String)(cpool[scpx]);
   321         } catch (ArrayIndexOutOfBoundsException e) {
   322             return  res; // "class #"+scpx+"// invalid constant pool index";
   323         } catch (ClassCastException e) {
   324             return  res; // "class #"+scpx+"// invalid constant pool reference";
   325         } catch (Throwable e) {
   326             return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   327         }
   328     }
   329 
   330     /**
   331      * Returns true if it is a class
   332      */
   333     public boolean isClass() {
   334         if((access & ACC_INTERFACE) == 0) return true;
   335         return false;
   336     }
   337 
   338     /**
   339      * Returns true if it is a interface.
   340      */
   341     public boolean isInterface(){
   342         if((access & ACC_INTERFACE) != 0) return true;
   343         return false;
   344     }
   345 
   346     /**
   347      * Returns true if this member is public, false otherwise.
   348      */
   349     public boolean isPublic(){
   350         return (access & ACC_PUBLIC) != 0;
   351     }
   352 
   353     /**
   354      * Returns the access of this class or interface.
   355      */
   356     public String[] getAccess(){
   357         Vector v = new Vector();
   358         if ((access & ACC_PUBLIC)   !=0) v.addElement("public");
   359         if ((access & ACC_FINAL)    !=0) v.addElement("final");
   360         if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract");
   361         String[] accflags = new String[v.size()];
   362         v.copyInto(accflags);
   363         return accflags;
   364     }
   365 
   366     /**
   367      * Returns list of innerclasses.
   368      */
   369     public InnerClassData[] getInnerClasses(){
   370         return innerClasses;
   371     }
   372 
   373     /**
   374      * Returns list of attributes.
   375      */
   376     final AttrData[] getAttributes(){
   377         return attrs;
   378     }
   379     
   380     public byte[] findAnnotationData(boolean classRetention) {
   381         String n = classRetention ?
   382             "RuntimeInvisibleAnnotations" : // NOI18N
   383             "RuntimeVisibleAnnotations"; // NOI18N
   384         return findAttr(n, attrs);
   385     }
   386 
   387     /**
   388      * Returns true if superbit is set.
   389      */
   390     public boolean isSuperSet(){
   391         if ((access & ACC_SUPER)   !=0) return true;
   392         return false;
   393     }
   394 
   395     /**
   396      * Returns super class name.
   397      */
   398     public String getSuperClassName(){
   399         String res=null;
   400         if (super_class==0) {
   401             return res;
   402         }
   403         int scpx;
   404         try {
   405             if (tags[super_class]!=CONSTANT_CLASS) {
   406                 return res; //"<CP["+cpx+"] is not a Class> ";
   407             }
   408             scpx=((CPX)cpool[super_class]).cpx;
   409         } catch (ArrayIndexOutOfBoundsException e) {
   410             return res; // "#"+cpx+"// invalid constant pool index";
   411         } catch (Throwable e) {
   412             return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   413         }
   414 
   415         try {
   416             return (String)(cpool[scpx]);
   417         } catch (ArrayIndexOutOfBoundsException e) {
   418             return  res; // "class #"+scpx+"// invalid constant pool index";
   419         } catch (ClassCastException e) {
   420             return  res; // "class #"+scpx+"// invalid constant pool reference";
   421         } catch (Throwable e) {
   422             return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   423         }
   424     }
   425 
   426     /**
   427      * Returns list of super interfaces.
   428      */
   429     public String[] getSuperInterfaces(){
   430         String interfacenames[] = new String[interfaces.length];
   431         int interfacecpx = -1;
   432         for(int i = 0; i < interfaces.length; i++){
   433             interfacecpx=((CPX)cpool[interfaces[i]]).cpx;
   434             interfacenames[i] = (String)(cpool[interfacecpx]);
   435         }
   436         return interfacenames;
   437     }
   438 
   439     /**
   440      * Returns string at prticular constant pool index.
   441      */
   442     public String getStringValue(int cpoolx) {
   443         try {
   444             return ((String)cpool[cpoolx]);
   445         } catch (ArrayIndexOutOfBoundsException e) {
   446             return "//invalid constant pool index:"+cpoolx;
   447         } catch (ClassCastException e) {
   448             return "//invalid constant pool ref:"+cpoolx;
   449         }
   450     }
   451 
   452     /**
   453      * Returns list of field info.
   454      */
   455     public  FieldData[] getFields(){
   456         return fields;
   457     }
   458 
   459     /**
   460      * Returns list of method info.
   461      */
   462     public  MethodData[] getMethods(){
   463         return methods;
   464     }
   465 
   466     /**
   467      * Returns constant pool entry at that index.
   468      */
   469     public CPX2 getCpoolEntry(int cpx){
   470         return ((CPX2)(cpool[cpx]));
   471     }
   472 
   473     public Object getCpoolEntryobj(int cpx){
   474         return (cpool[cpx]);
   475     }
   476 
   477     /**
   478      * Returns index of this class.
   479      */
   480     public int getthis_cpx(){
   481         return this_class;
   482     }
   483 
   484     /**
   485      * Returns string at that index.
   486      */
   487     public String StringValue(int cpx) {
   488         return stringValue(cpx, false);
   489     }
   490     public String stringValue(int cpx, boolean textual) {
   491         if (cpx==0) return "#0";
   492         int tag;
   493         Object x;
   494         String suffix="";
   495         try {
   496             tag=tags[cpx];
   497             x=cpool[cpx];
   498         } catch (IndexOutOfBoundsException e) {
   499             return "<Incorrect CP index:"+cpx+">";
   500         }
   501 
   502         if (x==null) return "<NULL>";
   503         switch (tag) {
   504         case CONSTANT_UTF8: {
   505             if (!textual) {
   506                 return (String)x;
   507             }
   508             StringBuilder sb=new StringBuilder();
   509             String s=(String)x;
   510             for (int k=0; k<s.length(); k++) {
   511                 char c=s.charAt(k);
   512                 switch (c) {
   513                 case '\\': sb.append('\\').append('\\'); break;
   514                 case '\t': sb.append('\\').append('t'); break;
   515                 case '\n': sb.append('\\').append('n'); break;
   516                 case '\r': sb.append('\\').append('r'); break;
   517                 case '\"': sb.append('\\').append('\"'); break;
   518                 default: sb.append(c);
   519                 }
   520             }
   521             return sb.toString();
   522         }
   523         case CONSTANT_DOUBLE: {
   524             Double d=(Double)x;
   525             String sd=d.toString();
   526             if (textual) {
   527                 return sd;
   528             }
   529             return sd+"d";
   530         }
   531         case CONSTANT_FLOAT: {
   532             Float f=(Float)x;
   533             String sf=(f).toString();
   534             if (textual) {
   535                 return sf;
   536             }
   537             return sf+"f";
   538         }
   539         case CONSTANT_LONG: {
   540             Long ln = (Long)x;
   541             if (textual) {
   542                 return ln.toString();
   543             }
   544             return ln.toString()+'l';
   545         }
   546         case CONSTANT_INTEGER: {
   547             Integer in = (Integer)x;
   548             return in.toString();
   549         }
   550         case CONSTANT_CLASS:
   551             String jn = javaName(getClassName(cpx));
   552             if (textual) {
   553                 return jn.replace('/', '_') + ".$class";
   554             }
   555             return jn;
   556         case CONSTANT_STRING:
   557             String sv = stringValue(((CPX)x).cpx, textual);
   558             if (textual) {
   559                 return '"' + sv + '"';
   560             } else {
   561                 return sv;
   562             }
   563         case CONSTANT_FIELD:
   564         case CONSTANT_METHOD:
   565         case CONSTANT_INTERFACEMETHOD:
   566             //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
   567              return javaName(getClassName(((CPX2)x).cpx1))+"."+StringValue(((CPX2)x).cpx2);
   568 
   569         case CONSTANT_NAMEANDTYPE:
   570             return getName(((CPX2)x).cpx1)+":"+StringValue(((CPX2)x).cpx2);
   571         default:
   572             return "UnknownTag"; //TBD
   573         }
   574     }
   575 
   576     /**
   577      * Returns resolved java type name.
   578      */
   579     public String javaName(String name) {
   580         if( name==null) return "null";
   581         int len=name.length();
   582         if (len==0) return "\"\"";
   583         int cc='/';
   584     fullname: { // xxx/yyy/zzz
   585             int cp;
   586             for (int k=0; k<len; k += Character.charCount(cp)) {
   587                 cp=name.codePointAt(k);
   588                 if (cc=='/') {
   589                     if (!isJavaIdentifierStart(cp)) break fullname;
   590                 } else if (cp!='/') {
   591                     if (!isJavaIdentifierPart(cp)) break fullname;
   592                 }
   593                 cc=cp;
   594             }
   595             return name;
   596         }
   597         return "\""+name+"\"";
   598     }
   599 
   600     public String getName(int cpx) {
   601         String res;
   602         try {
   603             return javaName((String)cpool[cpx]); //.replace('/','.');
   604         } catch (ArrayIndexOutOfBoundsException e) {
   605             return "<invalid constant pool index:"+cpx+">";
   606         } catch (ClassCastException e) {
   607             return "<invalid constant pool ref:"+cpx+">";
   608         }
   609     }
   610 
   611     /**
   612      * Returns unqualified class name.
   613      */
   614     public String getShortClassName(int cpx) {
   615         String classname=javaName(getClassName(cpx));
   616         pkgPrefixLen=classname.lastIndexOf("/")+1;
   617         if (pkgPrefixLen!=0) {
   618             pkgPrefix=classname.substring(0,pkgPrefixLen);
   619             if (classname.startsWith(pkgPrefix)) {
   620                 return classname.substring(pkgPrefixLen);
   621             }
   622         }
   623         return classname;
   624     }
   625 
   626     /**
   627      * Returns source file name.
   628      */
   629     public String getSourceName(){
   630         return getName(source_cpx);
   631     }
   632 
   633     /**
   634      * Returns package name.
   635      */
   636     public String getPkgName(){
   637         String classname=getClassName(this_class);
   638         pkgPrefixLen=classname.lastIndexOf("/")+1;
   639         if (pkgPrefixLen!=0) {
   640             pkgPrefix=classname.substring(0,pkgPrefixLen);
   641             return("package  "+pkgPrefix.substring(0,pkgPrefixLen-1)+";\n");
   642         }else return null;
   643     }
   644 
   645     /**
   646      * Returns total constant pool entry count.
   647      */
   648     public int getCpoolCount(){
   649         return cpool_count;
   650     }
   651 
   652     /**
   653      * Returns minor version of class file.
   654      */
   655     public int getMinor_version(){
   656         return minor_version;
   657     }
   658 
   659     /**
   660      * Returns major version of class file.
   661      */
   662     public int getMajor_version(){
   663         return major_version;
   664     }
   665 
   666     private boolean isJavaIdentifierStart(int cp) {
   667         return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z');
   668     }
   669 
   670     private boolean isJavaIdentifierPart(int cp) {
   671         return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9');
   672     }
   673 
   674     public String[] getNameAndType(int indx) {
   675         return getNameAndType(indx, 0, new String[2]);
   676     }
   677     
   678     private String[] getNameAndType(int indx, int at, String[] arr) {
   679         CPX2 c2 = getCpoolEntry(indx);
   680         arr[at] = StringValue(c2.cpx1);
   681         arr[at + 1] = StringValue(c2.cpx2);
   682         return arr;
   683     }
   684 
   685     public String[] getFieldInfoName(int indx) {
   686         CPX2 c2 = getCpoolEntry(indx);
   687         String[] arr = new String[3];
   688         arr[0] = getClassName(c2.cpx1);
   689         return getNameAndType(c2.cpx2, 1, arr);
   690     }
   691 
   692     static byte[] findAttr(String n, AttrData[] attrs) {
   693         for (AttrData ad : attrs) {
   694             if (n.equals(ad.getAttrName())) {
   695                 return ad.getData();
   696             }
   697         }
   698         return null;
   699     }
   700 }