diff -r eea0065bcc1a -r d382dacfd73f rt/javap/src/main/java/org/apidesign/javap/ClassData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/javap/src/main/java/org/apidesign/javap/ClassData.java Tue Feb 26 16:54:16 2013 +0100 @@ -0,0 +1,713 @@ +/* + * Copyright (c) 2002, 2004, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.apidesign.javap; + +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 final 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) throws IOException { + this.read(new DataInputStream(infile)); + } + + /** + * 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) { + if (n == 0) { + return null; + } else { + return (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); + } + + /** + * 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; //" "; + } + 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; //" "; + } + 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"; + } + } + + public int getAccessFlags() { + return access; + } + + /** + * 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. + */ + final AttrData[] getAttributes(){ + return attrs; + } + + public byte[] findAnnotationData(boolean classRetention) { + String n = classRetention ? + "RuntimeInvisibleAnnotations" : // NOI18N + "RuntimeVisibleAnnotations"; // NOI18N + return findAttr(n, 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; //" "; + } + 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; + } + + /** + * Returns string at that index. + */ + public String StringValue(int cpx) { + return stringValue(cpx, false); + } + public String stringValue(int cpx, boolean textual) { + return stringValue(cpx, textual, null); + } + public String stringValue(int cpx, String[] classRefs) { + return stringValue(cpx, true, classRefs); + } + private String stringValue(int cpx, boolean textual, String[] refs) { + if (cpx==0) return "#0"; + int tag; + Object x; + String suffix=""; + try { + tag=tags[cpx]; + x=cpool[cpx]; + } catch (IndexOutOfBoundsException e) { + return ""; + } + + if (x==null) return ""; + switch (tag) { + case CONSTANT_UTF8: { + if (!textual) { + return (String)x; + } + StringBuilder sb=new StringBuilder(); + String s=(String)x; + for (int k=0; k"; + } catch (ClassCastException e) { + return ""; + } + } + + /** + * 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; + } + + /** + * 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; + } + + private boolean isJavaIdentifierStart(int cp) { + return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z'); + } + + private boolean isJavaIdentifierPart(int cp) { + return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9'); + } + + public String[] getNameAndType(int indx) { + return getNameAndType(indx, 0, new String[2]); + } + + private String[] getNameAndType(int indx, int at, String[] arr) { + CPX2 c2 = getCpoolEntry(indx); + arr[at] = StringValue(c2.cpx1); + arr[at + 1] = StringValue(c2.cpx2); + return arr; + } + + public String[] getFieldInfoName(int indx) { + CPX2 c2 = getCpoolEntry(indx); + String[] arr = new String[3]; + arr[0] = getClassName(c2.cpx1); + return getNameAndType(c2.cpx2, 1, arr); + } + + static byte[] findAttr(String n, AttrData[] attrs) { + for (AttrData ad : attrs) { + if (n.equals(ad.getAttrName())) { + return ad.getData(); + } + } + return null; + } +}