Wed, 02 Jul 2008 12:56:02 -0700
6719955: Update copyright year
Summary: Update copyright year for files that have been modified in 2008
Reviewed-by: ohair, tbell
1 /*
2 * Copyright 2002-2008 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
27 package sun.tools.javap;
29 import java.util.*;
30 import java.io.*;
32 /**
33 * Central data repository of the Java Disassembler.
34 * Stores all the information in java class file.
35 *
36 * @author Sucheta Dambalkar (Adopted code from jdis)
37 */
38 public class ClassData implements RuntimeConstants {
40 private int magic;
41 private int minor_version;
42 private int major_version;
43 private int cpool_count;
44 private Object cpool[];
45 private int access;
46 private int this_class = 0;;
47 private int super_class;
48 private int interfaces_count;
49 private int[] interfaces = new int[0];;
50 private int fields_count;
51 private FieldData[] fields;
52 private int methods_count;
53 private MethodData[] methods;
54 private InnerClassData[] innerClasses;
55 private int attributes_count;
56 private AttrData[] attrs;
57 private String classname;
58 private String superclassname;
59 private int source_cpx=0;
60 private byte tags[];
61 private Hashtable<Object,Integer> indexHashAscii = new Hashtable<Object,Integer>();
62 private String pkgPrefix="";
63 private int pkgPrefixLen=0;
65 /**
66 * Read classfile to disassemble.
67 */
68 public ClassData(InputStream infile){
69 try{
70 this.read(new DataInputStream(infile));
71 }catch (FileNotFoundException ee) {
72 error("cant read file");
73 }catch (Error ee) {
74 ee.printStackTrace();
75 error("fatal error");
76 } catch (Exception ee) {
77 ee.printStackTrace();
78 error("fatal exception");
79 }
80 }
82 /**
83 * Reads and stores class file information.
84 */
85 public void read(DataInputStream in) throws IOException {
86 // Read the header
87 magic = in.readInt();
88 if (magic != JAVA_MAGIC) {
89 throw new ClassFormatError("wrong magic: " +
90 toHex(magic) + ", expected " +
91 toHex(JAVA_MAGIC));
92 }
93 minor_version = in.readShort();
94 major_version = in.readShort();
95 if (major_version != JAVA_VERSION) {
96 }
98 // Read the constant pool
99 readCP(in);
100 access = in.readUnsignedShort();
101 this_class = in.readUnsignedShort();
102 super_class = in.readUnsignedShort();
104 //Read interfaces.
105 interfaces_count = in.readUnsignedShort();
106 if(interfaces_count > 0){
107 interfaces = new int[interfaces_count];
108 }
109 for (int i = 0; i < interfaces_count; i++) {
110 interfaces[i]=in.readShort();
111 }
113 // Read the fields
114 readFields(in);
116 // Read the methods
117 readMethods(in);
119 // Read the attributes
120 attributes_count = in.readUnsignedShort();
121 attrs=new AttrData[attributes_count];
122 for (int k = 0; k < attributes_count; k++) {
123 int name_cpx=in.readUnsignedShort();
124 if (getTag(name_cpx)==CONSTANT_UTF8
125 && getString(name_cpx).equals("SourceFile")
126 ){ if (in.readInt()!=2)
127 throw new ClassFormatError("invalid attr length");
128 source_cpx=in.readUnsignedShort();
129 AttrData attr=new AttrData(this);
130 attr.read(name_cpx);
131 attrs[k]=attr;
133 } else if (getTag(name_cpx)==CONSTANT_UTF8
134 && getString(name_cpx).equals("InnerClasses")
135 ){ int length=in.readInt();
136 int num=in.readUnsignedShort();
137 if (2+num*8 != length)
138 throw new ClassFormatError("invalid attr length");
139 innerClasses=new InnerClassData[num];
140 for (int j = 0; j < num; j++) {
141 InnerClassData innerClass=new InnerClassData(this);
142 innerClass.read(in);
143 innerClasses[j]=innerClass;
144 }
145 AttrData attr=new AttrData(this);
146 attr.read(name_cpx);
147 attrs[k]=attr;
148 } else {
149 AttrData attr=new AttrData(this);
150 attr.read(name_cpx, in);
151 attrs[k]=attr;
152 }
153 }
154 in.close();
155 } // end ClassData.read()
157 /**
158 * Reads and stores constant pool info.
159 */
160 void readCP(DataInputStream in) throws IOException {
161 cpool_count = in.readUnsignedShort();
162 tags = new byte[cpool_count];
163 cpool = new Object[cpool_count];
164 for (int i = 1; i < cpool_count; i++) {
165 byte tag = in.readByte();
167 switch(tags[i] = tag) {
168 case CONSTANT_UTF8:
169 String str=in.readUTF();
170 indexHashAscii.put(cpool[i] = str, i);
171 break;
172 case CONSTANT_INTEGER:
173 cpool[i] = Integer.valueOf(in.readInt());
174 break;
175 case CONSTANT_FLOAT:
176 cpool[i] = Float.valueOf(in.readFloat());
177 break;
178 case CONSTANT_LONG:
179 cpool[i++] = Long.valueOf(in.readLong());
180 break;
181 case CONSTANT_DOUBLE:
182 cpool[i++] = Double.valueOf(in.readDouble());
183 break;
184 case CONSTANT_CLASS:
185 case CONSTANT_STRING:
186 cpool[i] = new CPX(in.readUnsignedShort());
187 break;
189 case CONSTANT_FIELD:
190 case CONSTANT_METHOD:
191 case CONSTANT_INTERFACEMETHOD:
192 case CONSTANT_NAMEANDTYPE:
193 cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
194 break;
196 case 0:
197 default:
198 throw new ClassFormatError("invalid constant type: " + (int)tags[i]);
199 }
200 }
201 }
203 /**
204 * Reads and strores field info.
205 */
206 protected void readFields(DataInputStream in) throws IOException {
207 int fields_count = in.readUnsignedShort();
208 fields=new FieldData[fields_count];
209 for (int k = 0; k < fields_count; k++) {
210 FieldData field=new FieldData(this);
211 field.read(in);
212 fields[k]=field;
213 }
214 }
216 /**
217 * Reads and strores Method info.
218 */
219 protected void readMethods(DataInputStream in) throws IOException {
220 int methods_count = in.readUnsignedShort();
221 methods=new MethodData[methods_count];
222 for (int k = 0; k < methods_count ; k++) {
223 MethodData method=new MethodData(this);
224 method.read(in);
225 methods[k]=method;
226 }
227 }
229 /**
230 * get a string
231 */
232 public String getString(int n) {
233 return (n == 0) ? null : (String)cpool[n];
234 }
236 /**
237 * get the type of constant given an index
238 */
239 public byte getTag(int n) {
240 try{
241 return tags[n];
242 } catch (ArrayIndexOutOfBoundsException e) {
243 return (byte)100;
244 }
245 }
247 static final String hexString="0123456789ABCDEF";
249 public static char hexTable[]=hexString.toCharArray();
251 static String toHex(long val, int width) {
252 StringBuffer s = new StringBuffer();
253 for (int i=width-1; i>=0; i--)
254 s.append(hexTable[((int)(val>>(4*i)))&0xF]);
255 return "0x"+s.toString();
256 }
258 static String toHex(long val) {
259 int width;
260 for (width=16; width>0; width--) {
261 if ((val>>(width-1)*4)!=0) break;
262 }
263 return toHex(val, width);
264 }
266 static String toHex(int val) {
267 int width;
268 for (width=8; width>0; width--) {
269 if ((val>>(width-1)*4)!=0) break;
270 }
271 return toHex(val, width);
272 }
274 public void error(String msg) {
275 System.err.println("ERROR:" +msg);
276 }
278 /**
279 * Returns the name of this class.
280 */
281 public String getClassName() {
282 String res=null;
283 if (this_class==0) {
284 return res;
285 }
286 int tcpx;
287 try {
288 if (tags[this_class]!=CONSTANT_CLASS) {
289 return res; //"<CP["+cpx+"] is not a Class> ";
290 }
291 tcpx=((CPX)cpool[this_class]).cpx;
292 } catch (ArrayIndexOutOfBoundsException e) {
293 return res; // "#"+cpx+"// invalid constant pool index";
294 } catch (Throwable e) {
295 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
296 }
298 try {
299 return (String)(cpool[tcpx]);
300 } catch (ArrayIndexOutOfBoundsException e) {
301 return res; // "class #"+scpx+"// invalid constant pool index";
302 } catch (ClassCastException e) {
303 return res; // "class #"+scpx+"// invalid constant pool reference";
304 } catch (Throwable e) {
305 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
306 }
308 }
310 /**
311 * Returns the name of class at perticular index.
312 */
313 public String getClassName(int cpx) {
314 String res="#"+cpx;
315 if (cpx==0) {
316 return res;
317 }
318 int scpx;
319 try {
320 if (tags[cpx]!=CONSTANT_CLASS) {
321 return res; //"<CP["+cpx+"] is not a Class> ";
322 }
323 scpx=((CPX)cpool[cpx]).cpx;
324 } catch (ArrayIndexOutOfBoundsException e) {
325 return res; // "#"+cpx+"// invalid constant pool index";
326 } catch (Throwable e) {
327 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
328 }
329 res="#"+scpx;
330 try {
331 return (String)(cpool[scpx]);
332 } catch (ArrayIndexOutOfBoundsException e) {
333 return res; // "class #"+scpx+"// invalid constant pool index";
334 } catch (ClassCastException e) {
335 return res; // "class #"+scpx+"// invalid constant pool reference";
336 } catch (Throwable e) {
337 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
338 }
339 }
341 /**
342 * Returns true if it is a class
343 */
344 public boolean isClass() {
345 if((access & ACC_INTERFACE) == 0) return true;
346 return false;
347 }
349 /**
350 * Returns true if it is a interface.
351 */
352 public boolean isInterface(){
353 if((access & ACC_INTERFACE) != 0) return true;
354 return false;
355 }
357 /**
358 * Returns true if this member is public, false otherwise.
359 */
360 public boolean isPublic(){
361 return (access & ACC_PUBLIC) != 0;
362 }
364 /**
365 * Returns the access of this class or interface.
366 */
367 public String[] getAccess(){
368 Vector<String> v = new Vector<String>();
369 if ((access & ACC_PUBLIC) !=0) v.addElement("public");
370 if ((access & ACC_FINAL) !=0) v.addElement("final");
371 if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract");
372 String[] accflags = new String[v.size()];
373 v.copyInto(accflags);
374 return accflags;
375 }
377 /**
378 * Returns list of innerclasses.
379 */
380 public InnerClassData[] getInnerClasses(){
381 return innerClasses;
382 }
384 /**
385 * Returns list of attributes.
386 */
387 public AttrData[] getAttributes(){
388 return attrs;
389 }
391 /**
392 * Returns true if superbit is set.
393 */
394 public boolean isSuperSet(){
395 if ((access & ACC_SUPER) !=0) return true;
396 return false;
397 }
399 /**
400 * Returns super class name.
401 */
402 public String getSuperClassName(){
403 String res=null;
404 if (super_class==0) {
405 return res;
406 }
407 int scpx;
408 try {
409 if (tags[super_class]!=CONSTANT_CLASS) {
410 return res; //"<CP["+cpx+"] is not a Class> ";
411 }
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";
417 }
419 try {
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";
427 }
428 }
430 /**
431 * Returns list of super interfaces.
432 */
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]);
439 }
440 return interfacenames;
441 }
443 /**
444 * Returns string at prticular constant pool index.
445 */
446 public String getStringValue(int cpoolx) {
447 try {
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;
453 }
454 }
456 /**
457 * Returns list of field info.
458 */
459 public FieldData[] getFields(){
460 return fields;
461 }
463 /**
464 * Returns list of method info.
465 */
466 public MethodData[] getMethods(){
467 return methods;
468 }
470 /**
471 * Returns constant pool entry at that index.
472 */
473 public CPX2 getCpoolEntry(int cpx){
474 return ((CPX2)(cpool[cpx]));
475 }
477 public Object getCpoolEntryobj(int cpx){
478 return (cpool[cpx]);
479 }
481 /**
482 * Returns index of this class.
483 */
484 public int getthis_cpx(){
485 return this_class;
486 }
488 public String TagString (int tag) {
489 String res=Tables.tagName(tag);
490 if (res==null) return "BOGUS_TAG:"+tag;
491 return res;
492 }
494 /**
495 * Returns string at that index.
496 */
497 public String StringValue(int cpx) {
498 if (cpx==0) return "#0";
499 int tag;
500 Object x;
501 String suffix="";
502 try {
503 tag=tags[cpx];
504 x=cpool[cpx];
505 } catch (IndexOutOfBoundsException e) {
506 return "<Incorrect CP index:"+cpx+">";
507 }
509 if (x==null) return "<NULL>";
510 switch (tag) {
511 case CONSTANT_UTF8: {
512 StringBuffer sb=new StringBuffer();
513 String s=(String)x;
514 for (int k=0; k<s.length(); k++) {
515 char c=s.charAt(k);
516 switch (c) {
517 case '\t': sb.append('\\').append('t'); break;
518 case '\n': sb.append('\\').append('n'); break;
519 case '\r': sb.append('\\').append('r'); break;
520 case '\"': sb.append('\\').append('\"'); break;
521 default: sb.append(c);
522 }
523 }
524 return sb.toString();
525 }
526 case CONSTANT_DOUBLE: {
527 Double d=(Double)x;
528 String sd=d.toString();
529 return sd+"d";
530 }
531 case CONSTANT_FLOAT: {
532 Float f=(Float)x;
533 String sf=(f).toString();
534 return sf+"f";
535 }
536 case CONSTANT_LONG: {
537 Long ln = (Long)x;
538 return ln.toString()+'l';
539 }
540 case CONSTANT_INTEGER: {
541 Integer in = (Integer)x;
542 return in.toString();
543 }
544 case CONSTANT_CLASS:
545 return javaName(getClassName(cpx));
546 case CONSTANT_STRING:
547 return StringValue(((CPX)x).cpx);
548 case CONSTANT_FIELD:
549 case CONSTANT_METHOD:
550 case CONSTANT_INTERFACEMETHOD:
551 //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
552 return javaName(getClassName(((CPX2)x).cpx1))+"."+StringValue(((CPX2)x).cpx2);
554 case CONSTANT_NAMEANDTYPE:
555 return getName(((CPX2)x).cpx1)+":"+StringValue(((CPX2)x).cpx2);
556 default:
557 return "UnknownTag"; //TBD
558 }
559 }
561 /**
562 * Returns resolved java type name.
563 */
564 public String javaName(String name) {
565 if( name==null) return "null";
566 int len=name.length();
567 if (len==0) return "\"\"";
568 int cc='/';
569 fullname: { // xxx/yyy/zzz
570 int cp;
571 for (int k=0; k<len; k += Character.charCount(cp)) {
572 cp=name.codePointAt(k);
573 if (cc=='/') {
574 if (!Character.isJavaIdentifierStart(cp)) break fullname;
575 } else if (cp!='/') {
576 if (!Character.isJavaIdentifierPart(cp)) break fullname;
577 }
578 cc=cp;
579 }
580 return name;
581 }
582 return "\""+name+"\"";
583 }
585 public String getName(int cpx) {
586 String res;
587 try {
588 return javaName((String)cpool[cpx]); //.replace('/','.');
589 } catch (ArrayIndexOutOfBoundsException e) {
590 return "<invalid constant pool index:"+cpx+">";
591 } catch (ClassCastException e) {
592 return "<invalid constant pool ref:"+cpx+">";
593 }
594 }
596 /**
597 * Returns unqualified class name.
598 */
599 public String getShortClassName(int cpx) {
600 String classname=javaName(getClassName(cpx));
601 pkgPrefixLen=classname.lastIndexOf("/")+1;
602 if (pkgPrefixLen!=0) {
603 pkgPrefix=classname.substring(0,pkgPrefixLen);
604 if (classname.startsWith(pkgPrefix)) {
605 return classname.substring(pkgPrefixLen);
606 }
607 }
608 return classname;
609 }
611 /**
612 * Returns source file name.
613 */
614 public String getSourceName(){
615 return getName(source_cpx);
616 }
618 /**
619 * Returns package name.
620 */
621 public String getPkgName(){
622 String classname=getClassName(this_class);
623 pkgPrefixLen=classname.lastIndexOf("/")+1;
624 if (pkgPrefixLen!=0) {
625 pkgPrefix=classname.substring(0,pkgPrefixLen);
626 return("package "+pkgPrefix.substring(0,pkgPrefixLen-1)+";\n");
627 }else return null;
628 }
630 /**
631 * Returns total constant pool entry count.
632 */
633 public int getCpoolCount(){
634 return cpool_count;
635 }
637 public String StringTag(int cpx) {
638 byte tag=0;
639 String str=null;
640 try {
641 if (cpx==0) throw new IndexOutOfBoundsException();
642 tag=tags[cpx];
643 return TagString(tag);
644 } catch (IndexOutOfBoundsException e) {
645 str="Incorrect CP index:"+cpx;
646 }
647 return str;
648 }
650 /**
651 * Returns minor version of class file.
652 */
653 public int getMinor_version(){
654 return minor_version;
655 }
657 /**
658 * Returns major version of class file.
659 */
660 public int getMajor_version(){
661 return major_version;
662 }
663 }