JavaScriptBody does not honor Object.equals. Keeping original Java code only
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.
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.
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).
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.
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
27 package org.apidesign.javap;
32 * Central data repository of the Java Disassembler.
33 * Stores all the information in java class file.
35 * @author Sucheta Dambalkar (Adopted code from jdis)
37 public final class ClassData implements RuntimeConstants {
40 private int minor_version;
41 private int major_version;
42 private int cpool_count;
43 private Object cpool[];
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;
60 private Hashtable indexHashAscii = new Hashtable();
61 private String pkgPrefix="";
62 private int pkgPrefixLen=0;
65 * Read classfile to disassemble.
67 public ClassData(InputStream infile) throws IOException {
68 this.read(new DataInputStream(infile));
72 * Reads and stores class file information.
74 public void read(DataInputStream in) throws IOException {
77 if (magic != JAVA_MAGIC) {
78 throw new ClassFormatError("wrong magic: " +
79 toHex(magic) + ", expected " +
82 minor_version = in.readShort();
83 major_version = in.readShort();
84 if (major_version != JAVA_VERSION) {
87 // Read the constant pool
89 access = in.readUnsignedShort();
90 this_class = in.readUnsignedShort();
91 super_class = in.readUnsignedShort();
94 interfaces_count = in.readUnsignedShort();
95 if(interfaces_count > 0){
96 interfaces = new int[interfaces_count];
98 for (int i = 0; i < interfaces_count; i++) {
99 interfaces[i]=in.readShort();
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);
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);
132 innerClasses[j]=innerClass;
134 AttrData attr=new AttrData(this);
138 AttrData attr=new AttrData(this);
139 attr.read(name_cpx, in);
144 } // end ClassData.read()
147 * Reads and stores constant pool info.
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();
156 switch(tags[i] = tag) {
158 String str=in.readUTF();
159 indexHashAscii.put(cpool[i] = str, new Integer(i));
161 case CONSTANT_INTEGER:
162 cpool[i] = new Integer(in.readInt());
165 cpool[i] = new Float(in.readFloat());
168 cpool[i++] = new Long(in.readLong());
170 case CONSTANT_DOUBLE:
171 cpool[i++] = new Double(in.readDouble());
174 case CONSTANT_STRING:
175 cpool[i] = new CPX(in.readUnsignedShort());
179 case CONSTANT_METHOD:
180 case CONSTANT_INTERFACEMETHOD:
181 case CONSTANT_NAMEANDTYPE:
182 cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
187 throw new ClassFormatError("invalid constant type: " + (int)tags[i]);
193 * Reads and strores field info.
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);
206 * Reads and strores Method info.
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);
221 public String getString(int n) {
225 return (String)cpool[n];
230 * get the type of constant given an index
232 public byte getTag(int n) {
235 } catch (ArrayIndexOutOfBoundsException e) {
240 static final String hexString="0123456789ABCDEF";
242 public static char hexTable[]=hexString.toCharArray();
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();
251 static String toHex(long val) {
253 for (width=16; width>0; width--) {
254 if ((val>>(width-1)*4)!=0) break;
256 return toHex(val, width);
259 static String toHex(int val) {
261 for (width=8; width>0; width--) {
262 if ((val>>(width-1)*4)!=0) break;
264 return toHex(val, width);
268 * Returns the name of this class.
270 public String getClassName() {
277 if (tags[this_class]!=CONSTANT_CLASS) {
278 return res; //"<CP["+cpx+"] is not a Class> ";
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";
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";
300 * Returns the name of class at perticular index.
302 public String getClassName(int cpx) {
309 if (tags[cpx]!=CONSTANT_CLASS) {
310 return res; //"<CP["+cpx+"] is not a Class> ";
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";
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";
330 public int getAccessFlags() {
335 * Returns true if it is a class
337 public boolean isClass() {
338 if((access & ACC_INTERFACE) == 0) return true;
343 * Returns true if it is a interface.
345 public boolean isInterface(){
346 if((access & ACC_INTERFACE) != 0) return true;
351 * Returns true if this member is public, false otherwise.
353 public boolean isPublic(){
354 return (access & ACC_PUBLIC) != 0;
358 * Returns the access of this class or interface.
360 public String[] getAccess(){
361 Vector v = new Vector();
362 if ((access & ACC_PUBLIC) !=0) v.addElement("public");
363 if ((access & ACC_FINAL) !=0) v.addElement("final");
364 if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract");
365 String[] accflags = new String[v.size()];
366 v.copyInto(accflags);
371 * Returns list of innerclasses.
373 public InnerClassData[] getInnerClasses(){
378 * Returns list of attributes.
380 final AttrData[] getAttributes(){
384 public byte[] findAnnotationData(boolean classRetention) {
385 String n = classRetention ?
386 "RuntimeInvisibleAnnotations" : // NOI18N
387 "RuntimeVisibleAnnotations"; // NOI18N
388 return findAttr(n, attrs);
392 * Returns true if superbit is set.
394 public boolean isSuperSet(){
395 if ((access & ACC_SUPER) !=0) return true;
400 * Returns super class name.
402 public String getSuperClassName(){
404 if (super_class==0) {
409 if (tags[super_class]!=CONSTANT_CLASS) {
410 return res; //"<CP["+cpx+"] is not a Class> ";
412 scpx=((CPX)cpool[super_class]).cpx;
413 } catch (ArrayIndexOutOfBoundsException e) {
414 return res; // "#"+cpx+"// invalid constant pool index";
415 } catch (Throwable e) {
416 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
420 return (String)(cpool[scpx]);
421 } catch (ArrayIndexOutOfBoundsException e) {
422 return res; // "class #"+scpx+"// invalid constant pool index";
423 } catch (ClassCastException e) {
424 return res; // "class #"+scpx+"// invalid constant pool reference";
425 } catch (Throwable e) {
426 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
431 * Returns list of super interfaces.
433 public String[] getSuperInterfaces(){
434 String interfacenames[] = new String[interfaces.length];
435 int interfacecpx = -1;
436 for(int i = 0; i < interfaces.length; i++){
437 interfacecpx=((CPX)cpool[interfaces[i]]).cpx;
438 interfacenames[i] = (String)(cpool[interfacecpx]);
440 return interfacenames;
444 * Returns string at prticular constant pool index.
446 public String getStringValue(int cpoolx) {
448 return ((String)cpool[cpoolx]);
449 } catch (ArrayIndexOutOfBoundsException e) {
450 return "//invalid constant pool index:"+cpoolx;
451 } catch (ClassCastException e) {
452 return "//invalid constant pool ref:"+cpoolx;
457 * Returns list of field info.
459 public FieldData[] getFields(){
464 * Returns list of method info.
466 public MethodData[] getMethods(){
471 * Returns constant pool entry at that index.
473 public CPX2 getCpoolEntry(int cpx){
474 return ((CPX2)(cpool[cpx]));
477 public Object getCpoolEntryobj(int cpx){
482 * Returns index of this class.
484 public int getthis_cpx(){
489 * Returns string at that index.
491 public String StringValue(int cpx) {
492 return stringValue(cpx, false);
494 public String stringValue(int cpx, boolean textual) {
495 return stringValue(cpx, textual, null);
497 public String stringValue(int cpx, String[] classRefs) {
498 return stringValue(cpx, true, classRefs);
500 private String stringValue(int cpx, boolean textual, String[] refs) {
501 if (cpx==0) return "#0";
508 } catch (IndexOutOfBoundsException e) {
509 return "<Incorrect CP index:"+cpx+">";
512 if (x==null) return "<NULL>";
514 case CONSTANT_UTF8: {
518 StringBuilder sb=new StringBuilder();
520 for (int k=0; k<s.length(); k++) {
523 case '\\': sb.append('\\').append('\\'); break;
524 case '\t': sb.append('\\').append('t'); break;
525 case '\n': sb.append('\\').append('n'); break;
526 case '\r': sb.append('\\').append('r'); break;
527 case '\"': sb.append('\\').append('\"'); break;
528 default: sb.append(c);
531 return sb.toString();
533 case CONSTANT_DOUBLE: {
535 String sd=d.toString();
541 case CONSTANT_FLOAT: {
543 String sf=(f).toString();
549 case CONSTANT_LONG: {
552 return ln.toString();
554 return ln.toString()+'l';
556 case CONSTANT_INTEGER: {
557 Integer in = (Integer)x;
558 return in.toString();
561 String jn = getClassName(cpx);
569 case CONSTANT_STRING:
570 String sv = stringValue(((CPX)x).cpx, textual);
572 return '"' + sv + '"';
577 case CONSTANT_METHOD:
578 case CONSTANT_INTERFACEMETHOD:
579 //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
580 return javaName(getClassName(((CPX2)x).cpx1))+"."+StringValue(((CPX2)x).cpx2);
582 case CONSTANT_NAMEANDTYPE:
583 return getName(((CPX2)x).cpx1)+":"+StringValue(((CPX2)x).cpx2);
585 return "UnknownTag"; //TBD
590 * Returns resolved java type name.
592 public String javaName(String name) {
593 if( name==null) return "null";
594 int len=name.length();
595 if (len==0) return "\"\"";
597 fullname: { // xxx/yyy/zzz
599 for (int k=0; k<len; k += Character.charCount(cp)) {
600 cp=name.codePointAt(k);
602 if (!isJavaIdentifierStart(cp)) break fullname;
603 } else if (cp!='/') {
604 if (!isJavaIdentifierPart(cp)) break fullname;
610 return "\""+name+"\"";
613 public String getName(int cpx) {
616 return javaName((String)cpool[cpx]); //.replace('/','.');
617 } catch (ArrayIndexOutOfBoundsException e) {
618 return "<invalid constant pool index:"+cpx+">";
619 } catch (ClassCastException e) {
620 return "<invalid constant pool ref:"+cpx+">";
625 * Returns unqualified class name.
627 public String getShortClassName(int cpx) {
628 String classname=javaName(getClassName(cpx));
629 pkgPrefixLen=classname.lastIndexOf("/")+1;
630 if (pkgPrefixLen!=0) {
631 pkgPrefix=classname.substring(0,pkgPrefixLen);
632 if (classname.startsWith(pkgPrefix)) {
633 return classname.substring(pkgPrefixLen);
640 * Returns source file name.
642 public String getSourceName(){
643 return getName(source_cpx);
647 * Returns package name.
649 public String getPkgName(){
650 String classname=getClassName(this_class);
651 pkgPrefixLen=classname.lastIndexOf("/")+1;
652 if (pkgPrefixLen!=0) {
653 pkgPrefix=classname.substring(0,pkgPrefixLen);
654 return("package "+pkgPrefix.substring(0,pkgPrefixLen-1)+";\n");
659 * Returns total constant pool entry count.
661 public int getCpoolCount(){
666 * Returns minor version of class file.
668 public int getMinor_version(){
669 return minor_version;
673 * Returns major version of class file.
675 public int getMajor_version(){
676 return major_version;
679 private boolean isJavaIdentifierStart(int cp) {
680 return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z');
683 private boolean isJavaIdentifierPart(int cp) {
684 return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9');
687 public String[] getNameAndType(int indx) {
688 return getNameAndType(indx, 0, new String[2]);
691 private String[] getNameAndType(int indx, int at, String[] arr) {
692 CPX2 c2 = getCpoolEntry(indx);
693 arr[at] = StringValue(c2.cpx1);
694 arr[at + 1] = StringValue(c2.cpx2);
698 public String[] getFieldInfoName(int indx) {
699 CPX2 c2 = getCpoolEntry(indx);
700 String[] arr = new String[3];
701 arr[0] = getClassName(c2.cpx1);
702 return getNameAndType(c2.cpx2, 1, arr);
705 static byte[] findAttr(String n, AttrData[] attrs) {
706 for (AttrData ad : attrs) {
707 if (n.equals(ad.getAttrName())) {