Rebasing the Inflater support on jzlib which, unlike GNU ClassPath, has correct implementation of Huffman code. Making the implementation more easily testable by turning Inflater and ZipInputStream into pure delegates. Current implementation is going to need proper long support.
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())) {