--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/sun/tools/javap/ClassData.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,663 @@
+/*
+ * Copyright 2002-2004 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+package sun.tools.javap;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * Central data repository of the Java Disassembler.
+ * Stores all the information in java class file.
+ *
+ * @author Sucheta Dambalkar (Adopted code from jdis)
+ */
+public class ClassData implements RuntimeConstants {
+
+ private int magic;
+ private int minor_version;
+ private int major_version;
+ private int cpool_count;
+ private Object cpool[];
+ private int access;
+ private int this_class = 0;;
+ private int super_class;
+ private int interfaces_count;
+ private int[] interfaces = new int[0];;
+ private int fields_count;
+ private FieldData[] fields;
+ private int methods_count;
+ private MethodData[] methods;
+ private InnerClassData[] innerClasses;
+ private int attributes_count;
+ private AttrData[] attrs;
+ private String classname;
+ private String superclassname;
+ private int source_cpx=0;
+ private byte tags[];
+ private Hashtable indexHashAscii = new Hashtable();
+ private String pkgPrefix="";
+ private int pkgPrefixLen=0;
+
+ /**
+ * Read classfile to disassemble.
+ */
+ public ClassData(InputStream infile){
+ try{
+ this.read(new DataInputStream(infile));
+ }catch (FileNotFoundException ee) {
+ error("cant read file");
+ }catch (Error ee) {
+ ee.printStackTrace();
+ error("fatal error");
+ } catch (Exception ee) {
+ ee.printStackTrace();
+ error("fatal exception");
+ }
+ }
+
+ /**
+ * Reads and stores class file information.
+ */
+ public void read(DataInputStream in) throws IOException {
+ // Read the header
+ magic = in.readInt();
+ if (magic != JAVA_MAGIC) {
+ throw new ClassFormatError("wrong magic: " +
+ toHex(magic) + ", expected " +
+ toHex(JAVA_MAGIC));
+ }
+ minor_version = in.readShort();
+ major_version = in.readShort();
+ if (major_version != JAVA_VERSION) {
+ }
+
+ // Read the constant pool
+ readCP(in);
+ access = in.readUnsignedShort();
+ this_class = in.readUnsignedShort();
+ super_class = in.readUnsignedShort();
+
+ //Read interfaces.
+ interfaces_count = in.readUnsignedShort();
+ if(interfaces_count > 0){
+ interfaces = new int[interfaces_count];
+ }
+ for (int i = 0; i < interfaces_count; i++) {
+ interfaces[i]=in.readShort();
+ }
+
+ // Read the fields
+ readFields(in);
+
+ // Read the methods
+ readMethods(in);
+
+ // Read the attributes
+ attributes_count = in.readUnsignedShort();
+ attrs=new AttrData[attributes_count];
+ for (int k = 0; k < attributes_count; k++) {
+ int name_cpx=in.readUnsignedShort();
+ if (getTag(name_cpx)==CONSTANT_UTF8
+ && getString(name_cpx).equals("SourceFile")
+ ){ if (in.readInt()!=2)
+ throw new ClassFormatError("invalid attr length");
+ source_cpx=in.readUnsignedShort();
+ AttrData attr=new AttrData(this);
+ attr.read(name_cpx);
+ attrs[k]=attr;
+
+ } else if (getTag(name_cpx)==CONSTANT_UTF8
+ && getString(name_cpx).equals("InnerClasses")
+ ){ int length=in.readInt();
+ int num=in.readUnsignedShort();
+ if (2+num*8 != length)
+ throw new ClassFormatError("invalid attr length");
+ innerClasses=new InnerClassData[num];
+ for (int j = 0; j < num; j++) {
+ InnerClassData innerClass=new InnerClassData(this);
+ innerClass.read(in);
+ innerClasses[j]=innerClass;
+ }
+ AttrData attr=new AttrData(this);
+ attr.read(name_cpx);
+ attrs[k]=attr;
+ } else {
+ AttrData attr=new AttrData(this);
+ attr.read(name_cpx, in);
+ attrs[k]=attr;
+ }
+ }
+ in.close();
+ } // end ClassData.read()
+
+ /**
+ * Reads and stores constant pool info.
+ */
+ void readCP(DataInputStream in) throws IOException {
+ cpool_count = in.readUnsignedShort();
+ tags = new byte[cpool_count];
+ cpool = new Object[cpool_count];
+ for (int i = 1; i < cpool_count; i++) {
+ byte tag = in.readByte();
+
+ switch(tags[i] = tag) {
+ case CONSTANT_UTF8:
+ String str=in.readUTF();
+ indexHashAscii.put(cpool[i] = str, new Integer(i));
+ break;
+ case CONSTANT_INTEGER:
+ cpool[i] = new Integer(in.readInt());
+ break;
+ case CONSTANT_FLOAT:
+ cpool[i] = new Float(in.readFloat());
+ break;
+ case CONSTANT_LONG:
+ cpool[i++] = new Long(in.readLong());
+ break;
+ case CONSTANT_DOUBLE:
+ cpool[i++] = new Double(in.readDouble());
+ break;
+ case CONSTANT_CLASS:
+ case CONSTANT_STRING:
+ cpool[i] = new CPX(in.readUnsignedShort());
+ break;
+
+ case CONSTANT_FIELD:
+ case CONSTANT_METHOD:
+ case CONSTANT_INTERFACEMETHOD:
+ case CONSTANT_NAMEANDTYPE:
+ cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
+ break;
+
+ case 0:
+ default:
+ throw new ClassFormatError("invalid constant type: " + (int)tags[i]);
+ }
+ }
+ }
+
+ /**
+ * Reads and strores field info.
+ */
+ protected void readFields(DataInputStream in) throws IOException {
+ int fields_count = in.readUnsignedShort();
+ fields=new FieldData[fields_count];
+ for (int k = 0; k < fields_count; k++) {
+ FieldData field=new FieldData(this);
+ field.read(in);
+ fields[k]=field;
+ }
+ }
+
+ /**
+ * Reads and strores Method info.
+ */
+ protected void readMethods(DataInputStream in) throws IOException {
+ int methods_count = in.readUnsignedShort();
+ methods=new MethodData[methods_count];
+ for (int k = 0; k < methods_count ; k++) {
+ MethodData method=new MethodData(this);
+ method.read(in);
+ methods[k]=method;
+ }
+ }
+
+ /**
+ * get a string
+ */
+ public String getString(int n) {
+ return (n == 0) ? null : (String)cpool[n];
+ }
+
+ /**
+ * get the type of constant given an index
+ */
+ public byte getTag(int n) {
+ try{
+ return tags[n];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return (byte)100;
+ }
+ }
+
+ static final String hexString="0123456789ABCDEF";
+
+ public static char hexTable[]=hexString.toCharArray();
+
+ static String toHex(long val, int width) {
+ StringBuffer s = new StringBuffer();
+ for (int i=width-1; i>=0; i--)
+ s.append(hexTable[((int)(val>>(4*i)))&0xF]);
+ return "0x"+s.toString();
+ }
+
+ static String toHex(long val) {
+ int width;
+ for (width=16; width>0; width--) {
+ if ((val>>(width-1)*4)!=0) break;
+ }
+ return toHex(val, width);
+ }
+
+ static String toHex(int val) {
+ int width;
+ for (width=8; width>0; width--) {
+ if ((val>>(width-1)*4)!=0) break;
+ }
+ return toHex(val, width);
+ }
+
+ public void error(String msg) {
+ System.err.println("ERROR:" +msg);
+ }
+
+ /**
+ * Returns the name of this class.
+ */
+ public String getClassName() {
+ String res=null;
+ if (this_class==0) {
+ return res;
+ }
+ int tcpx;
+ try {
+ if (tags[this_class]!=CONSTANT_CLASS) {
+ return res; //"<CP["+cpx+"] is not a Class> ";
+ }
+ tcpx=((CPX)cpool[this_class]).cpx;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return res; // "#"+cpx+"// invalid constant pool index";
+ } catch (Throwable e) {
+ return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
+ }
+
+ try {
+ return (String)(cpool[tcpx]);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return res; // "class #"+scpx+"// invalid constant pool index";
+ } catch (ClassCastException e) {
+ return res; // "class #"+scpx+"// invalid constant pool reference";
+ } catch (Throwable e) {
+ return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
+ }
+
+ }
+
+ /**
+ * Returns the name of class at perticular index.
+ */
+ public String getClassName(int cpx) {
+ String res="#"+cpx;
+ if (cpx==0) {
+ return res;
+ }
+ int scpx;
+ try {
+ if (tags[cpx]!=CONSTANT_CLASS) {
+ return res; //"<CP["+cpx+"] is not a Class> ";
+ }
+ scpx=((CPX)cpool[cpx]).cpx;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return res; // "#"+cpx+"// invalid constant pool index";
+ } catch (Throwable e) {
+ return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
+ }
+ res="#"+scpx;
+ try {
+ return (String)(cpool[scpx]);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return res; // "class #"+scpx+"// invalid constant pool index";
+ } catch (ClassCastException e) {
+ return res; // "class #"+scpx+"// invalid constant pool reference";
+ } catch (Throwable e) {
+ return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
+ }
+ }
+
+ /**
+ * Returns true if it is a class
+ */
+ public boolean isClass() {
+ if((access & ACC_INTERFACE) == 0) return true;
+ return false;
+ }
+
+ /**
+ * Returns true if it is a interface.
+ */
+ public boolean isInterface(){
+ if((access & ACC_INTERFACE) != 0) return true;
+ return false;
+ }
+
+ /**
+ * Returns true if this member is public, false otherwise.
+ */
+ public boolean isPublic(){
+ return (access & ACC_PUBLIC) != 0;
+ }
+
+ /**
+ * Returns the access of this class or interface.
+ */
+ public String[] getAccess(){
+ Vector v = new Vector();
+ if ((access & ACC_PUBLIC) !=0) v.addElement("public");
+ if ((access & ACC_FINAL) !=0) v.addElement("final");
+ if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract");
+ String[] accflags = new String[v.size()];
+ v.copyInto(accflags);
+ return accflags;
+ }
+
+ /**
+ * Returns list of innerclasses.
+ */
+ public InnerClassData[] getInnerClasses(){
+ return innerClasses;
+ }
+
+ /**
+ * Returns list of attributes.
+ */
+ public AttrData[] getAttributes(){
+ return attrs;
+ }
+
+ /**
+ * Returns true if superbit is set.
+ */
+ public boolean isSuperSet(){
+ if ((access & ACC_SUPER) !=0) return true;
+ return false;
+ }
+
+ /**
+ * Returns super class name.
+ */
+ public String getSuperClassName(){
+ String res=null;
+ if (super_class==0) {
+ return res;
+ }
+ int scpx;
+ try {
+ if (tags[super_class]!=CONSTANT_CLASS) {
+ return res; //"<CP["+cpx+"] is not a Class> ";
+ }
+ scpx=((CPX)cpool[super_class]).cpx;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return res; // "#"+cpx+"// invalid constant pool index";
+ } catch (Throwable e) {
+ return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
+ }
+
+ try {
+ return (String)(cpool[scpx]);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return res; // "class #"+scpx+"// invalid constant pool index";
+ } catch (ClassCastException e) {
+ return res; // "class #"+scpx+"// invalid constant pool reference";
+ } catch (Throwable e) {
+ return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
+ }
+ }
+
+ /**
+ * Returns list of super interfaces.
+ */
+ public String[] getSuperInterfaces(){
+ String interfacenames[] = new String[interfaces.length];
+ int interfacecpx = -1;
+ for(int i = 0; i < interfaces.length; i++){
+ interfacecpx=((CPX)cpool[interfaces[i]]).cpx;
+ interfacenames[i] = (String)(cpool[interfacecpx]);
+ }
+ return interfacenames;
+ }
+
+ /**
+ * Returns string at prticular constant pool index.
+ */
+ public String getStringValue(int cpoolx) {
+ try {
+ return ((String)cpool[cpoolx]);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return "//invalid constant pool index:"+cpoolx;
+ } catch (ClassCastException e) {
+ return "//invalid constant pool ref:"+cpoolx;
+ }
+ }
+
+ /**
+ * Returns list of field info.
+ */
+ public FieldData[] getFields(){
+ return fields;
+ }
+
+ /**
+ * Returns list of method info.
+ */
+ public MethodData[] getMethods(){
+ return methods;
+ }
+
+ /**
+ * Returns constant pool entry at that index.
+ */
+ public CPX2 getCpoolEntry(int cpx){
+ return ((CPX2)(cpool[cpx]));
+ }
+
+ public Object getCpoolEntryobj(int cpx){
+ return (cpool[cpx]);
+ }
+
+ /**
+ * Returns index of this class.
+ */
+ public int getthis_cpx(){
+ return this_class;
+ }
+
+ public String TagString (int tag) {
+ String res=Tables.tagName(tag);
+ if (res==null) return "BOGUS_TAG:"+tag;
+ return res;
+ }
+
+ /**
+ * Returns string at that index.
+ */
+ public String StringValue(int cpx) {
+ if (cpx==0) return "#0";
+ int tag;
+ Object x;
+ String suffix="";
+ try {
+ tag=tags[cpx];
+ x=cpool[cpx];
+ } catch (IndexOutOfBoundsException e) {
+ return "<Incorrect CP index:"+cpx+">";
+ }
+
+ if (x==null) return "<NULL>";
+ switch (tag) {
+ case CONSTANT_UTF8: {
+ StringBuffer sb=new StringBuffer();
+ String s=(String)x;
+ for (int k=0; k<s.length(); k++) {
+ char c=s.charAt(k);
+ switch (c) {
+ case '\t': sb.append('\\').append('t'); break;
+ case '\n': sb.append('\\').append('n'); break;
+ case '\r': sb.append('\\').append('r'); break;
+ case '\"': sb.append('\\').append('\"'); break;
+ default: sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+ case CONSTANT_DOUBLE: {
+ Double d=(Double)x;
+ String sd=d.toString();
+ return sd+"d";
+ }
+ case CONSTANT_FLOAT: {
+ Float f=(Float)x;
+ String sf=(f).toString();
+ return sf+"f";
+ }
+ case CONSTANT_LONG: {
+ Long ln = (Long)x;
+ return ln.toString()+'l';
+ }
+ case CONSTANT_INTEGER: {
+ Integer in = (Integer)x;
+ return in.toString();
+ }
+ case CONSTANT_CLASS:
+ return javaName(getClassName(cpx));
+ case CONSTANT_STRING:
+ return StringValue(((CPX)x).cpx);
+ case CONSTANT_FIELD:
+ case CONSTANT_METHOD:
+ case CONSTANT_INTERFACEMETHOD:
+ //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
+ return javaName(getClassName(((CPX2)x).cpx1))+"."+StringValue(((CPX2)x).cpx2);
+
+ case CONSTANT_NAMEANDTYPE:
+ return getName(((CPX2)x).cpx1)+":"+StringValue(((CPX2)x).cpx2);
+ default:
+ return "UnknownTag"; //TBD
+ }
+ }
+
+ /**
+ * Returns resolved java type name.
+ */
+ public String javaName(String name) {
+ if( name==null) return "null";
+ int len=name.length();
+ if (len==0) return "\"\"";
+ int cc='/';
+ fullname: { // xxx/yyy/zzz
+ int cp;
+ for (int k=0; k<len; k += Character.charCount(cp)) {
+ cp=name.codePointAt(k);
+ if (cc=='/') {
+ if (!Character.isJavaIdentifierStart(cp)) break fullname;
+ } else if (cp!='/') {
+ if (!Character.isJavaIdentifierPart(cp)) break fullname;
+ }
+ cc=cp;
+ }
+ return name;
+ }
+ return "\""+name+"\"";
+ }
+
+ public String getName(int cpx) {
+ String res;
+ try {
+ return javaName((String)cpool[cpx]); //.replace('/','.');
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return "<invalid constant pool index:"+cpx+">";
+ } catch (ClassCastException e) {
+ return "<invalid constant pool ref:"+cpx+">";
+ }
+ }
+
+ /**
+ * Returns unqualified class name.
+ */
+ public String getShortClassName(int cpx) {
+ String classname=javaName(getClassName(cpx));
+ pkgPrefixLen=classname.lastIndexOf("/")+1;
+ if (pkgPrefixLen!=0) {
+ pkgPrefix=classname.substring(0,pkgPrefixLen);
+ if (classname.startsWith(pkgPrefix)) {
+ return classname.substring(pkgPrefixLen);
+ }
+ }
+ return classname;
+ }
+
+ /**
+ * Returns source file name.
+ */
+ public String getSourceName(){
+ return getName(source_cpx);
+ }
+
+ /**
+ * Returns package name.
+ */
+ public String getPkgName(){
+ String classname=getClassName(this_class);
+ pkgPrefixLen=classname.lastIndexOf("/")+1;
+ if (pkgPrefixLen!=0) {
+ pkgPrefix=classname.substring(0,pkgPrefixLen);
+ return("package "+pkgPrefix.substring(0,pkgPrefixLen-1)+";\n");
+ }else return null;
+ }
+
+ /**
+ * Returns total constant pool entry count.
+ */
+ public int getCpoolCount(){
+ return cpool_count;
+ }
+
+ public String StringTag(int cpx) {
+ byte tag=0;
+ String str=null;
+ try {
+ if (cpx==0) throw new IndexOutOfBoundsException();
+ tag=tags[cpx];
+ return TagString(tag);
+ } catch (IndexOutOfBoundsException e) {
+ str="Incorrect CP index:"+cpx;
+ }
+ return str;
+ }
+
+ /**
+ * Returns minor version of class file.
+ */
+ public int getMinor_version(){
+ return minor_version;
+ }
+
+ /**
+ * Returns major version of class file.
+ */
+ public int getMajor_version(){
+ return major_version;
+ }
+}