001: /*
002: * Copyright 2002-2004 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.tools.javap;
027:
028: import java.util.*;
029: import java.io.*;
030:
031: /**
032: * Central data repository of the Java Disassembler.
033: * Stores all the information in java class file.
034: *
035: * @author Sucheta Dambalkar (Adopted code from jdis)
036: */
037: public class ClassData implements RuntimeConstants {
038:
039: private int magic;
040: private int minor_version;
041: private int major_version;
042: private int cpool_count;
043: private Object cpool[];
044: private int access;
045: private int this _class = 0;;
046: private int super _class;
047: private int interfaces_count;
048: private int[] interfaces = new int[0];;
049: private int fields_count;
050: private FieldData[] fields;
051: private int methods_count;
052: private MethodData[] methods;
053: private InnerClassData[] innerClasses;
054: private int attributes_count;
055: private AttrData[] attrs;
056: private String classname;
057: private String super classname;
058: private int source_cpx = 0;
059: private byte tags[];
060: private Hashtable indexHashAscii = new Hashtable();
061: private String pkgPrefix = "";
062: private int pkgPrefixLen = 0;
063:
064: /**
065: * Read classfile to disassemble.
066: */
067: public ClassData(InputStream infile) {
068: try {
069: this .read(new DataInputStream(infile));
070: } catch (FileNotFoundException ee) {
071: error("cant read file");
072: } catch (Error ee) {
073: ee.printStackTrace();
074: error("fatal error");
075: } catch (Exception ee) {
076: ee.printStackTrace();
077: error("fatal exception");
078: }
079: }
080:
081: /**
082: * Reads and stores class file information.
083: */
084: public void read(DataInputStream in) throws IOException {
085: // Read the header
086: magic = in.readInt();
087: if (magic != JAVA_MAGIC) {
088: throw new ClassFormatError("wrong magic: " + toHex(magic)
089: + ", expected " + toHex(JAVA_MAGIC));
090: }
091: minor_version = in.readShort();
092: major_version = in.readShort();
093: if (major_version != JAVA_VERSION) {
094: }
095:
096: // Read the constant pool
097: readCP(in);
098: access = in.readUnsignedShort();
099: this _class = in.readUnsignedShort();
100: super _class = in.readUnsignedShort();
101:
102: //Read interfaces.
103: interfaces_count = in.readUnsignedShort();
104: if (interfaces_count > 0) {
105: interfaces = new int[interfaces_count];
106: }
107: for (int i = 0; i < interfaces_count; i++) {
108: interfaces[i] = in.readShort();
109: }
110:
111: // Read the fields
112: readFields(in);
113:
114: // Read the methods
115: readMethods(in);
116:
117: // Read the attributes
118: attributes_count = in.readUnsignedShort();
119: attrs = new AttrData[attributes_count];
120: for (int k = 0; k < attributes_count; k++) {
121: int name_cpx = in.readUnsignedShort();
122: if (getTag(name_cpx) == CONSTANT_UTF8
123: && getString(name_cpx).equals("SourceFile")) {
124: if (in.readInt() != 2)
125: throw new ClassFormatError("invalid attr length");
126: source_cpx = in.readUnsignedShort();
127: AttrData attr = new AttrData(this );
128: attr.read(name_cpx);
129: attrs[k] = attr;
130:
131: } else if (getTag(name_cpx) == CONSTANT_UTF8
132: && getString(name_cpx).equals("InnerClasses")) {
133: int length = in.readInt();
134: int num = in.readUnsignedShort();
135: if (2 + num * 8 != length)
136: throw new ClassFormatError("invalid attr length");
137: innerClasses = new InnerClassData[num];
138: for (int j = 0; j < num; j++) {
139: InnerClassData innerClass = new InnerClassData(this );
140: innerClass.read(in);
141: innerClasses[j] = innerClass;
142: }
143: AttrData attr = new AttrData(this );
144: attr.read(name_cpx);
145: attrs[k] = attr;
146: } else {
147: AttrData attr = new AttrData(this );
148: attr.read(name_cpx, in);
149: attrs[k] = attr;
150: }
151: }
152: in.close();
153: } // end ClassData.read()
154:
155: /**
156: * Reads and stores constant pool info.
157: */
158: void readCP(DataInputStream in) throws IOException {
159: cpool_count = in.readUnsignedShort();
160: tags = new byte[cpool_count];
161: cpool = new Object[cpool_count];
162: for (int i = 1; i < cpool_count; i++) {
163: byte tag = in.readByte();
164:
165: switch (tags[i] = tag) {
166: case CONSTANT_UTF8:
167: String str = in.readUTF();
168: indexHashAscii.put(cpool[i] = str, new Integer(i));
169: break;
170: case CONSTANT_INTEGER:
171: cpool[i] = new Integer(in.readInt());
172: break;
173: case CONSTANT_FLOAT:
174: cpool[i] = new Float(in.readFloat());
175: break;
176: case CONSTANT_LONG:
177: cpool[i++] = new Long(in.readLong());
178: break;
179: case CONSTANT_DOUBLE:
180: cpool[i++] = new Double(in.readDouble());
181: break;
182: case CONSTANT_CLASS:
183: case CONSTANT_STRING:
184: cpool[i] = new CPX(in.readUnsignedShort());
185: break;
186:
187: case CONSTANT_FIELD:
188: case CONSTANT_METHOD:
189: case CONSTANT_INTERFACEMETHOD:
190: case CONSTANT_NAMEANDTYPE:
191: cpool[i] = new CPX2(in.readUnsignedShort(), in
192: .readUnsignedShort());
193: break;
194:
195: case 0:
196: default:
197: throw new ClassFormatError("invalid constant type: "
198: + (int) tags[i]);
199: }
200: }
201: }
202:
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: }
215:
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: }
228:
229: /**
230: * get a string
231: */
232: public String getString(int n) {
233: return (n == 0) ? null : (String) cpool[n];
234: }
235:
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: }
246:
247: static final String hexString = "0123456789ABCDEF";
248:
249: public static char hexTable[] = hexString.toCharArray();
250:
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: }
257:
258: static String toHex(long val) {
259: int width;
260: for (width = 16; width > 0; width--) {
261: if ((val >> (width - 1) * 4) != 0)
262: break;
263: }
264: return toHex(val, width);
265: }
266:
267: static String toHex(int val) {
268: int width;
269: for (width = 8; width > 0; width--) {
270: if ((val >> (width - 1) * 4) != 0)
271: break;
272: }
273: return toHex(val, width);
274: }
275:
276: public void error(String msg) {
277: System.err.println("ERROR:" + msg);
278: }
279:
280: /**
281: * Returns the name of this class.
282: */
283: public String getClassName() {
284: String res = null;
285: if (this _class == 0) {
286: return res;
287: }
288: int tcpx;
289: try {
290: if (tags[this _class] != CONSTANT_CLASS) {
291: return res; //"<CP["+cpx+"] is not a Class> ";
292: }
293: tcpx = ((CPX) cpool[this _class]).cpx;
294: } catch (ArrayIndexOutOfBoundsException e) {
295: return res; // "#"+cpx+"// invalid constant pool index";
296: } catch (Throwable e) {
297: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
298: }
299:
300: try {
301: return (String) (cpool[tcpx]);
302: } catch (ArrayIndexOutOfBoundsException e) {
303: return res; // "class #"+scpx+"// invalid constant pool index";
304: } catch (ClassCastException e) {
305: return res; // "class #"+scpx+"// invalid constant pool reference";
306: } catch (Throwable e) {
307: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
308: }
309:
310: }
311:
312: /**
313: * Returns the name of class at perticular index.
314: */
315: public String getClassName(int cpx) {
316: String res = "#" + cpx;
317: if (cpx == 0) {
318: return res;
319: }
320: int scpx;
321: try {
322: if (tags[cpx] != CONSTANT_CLASS) {
323: return res; //"<CP["+cpx+"] is not a Class> ";
324: }
325: scpx = ((CPX) cpool[cpx]).cpx;
326: } catch (ArrayIndexOutOfBoundsException e) {
327: return res; // "#"+cpx+"// invalid constant pool index";
328: } catch (Throwable e) {
329: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
330: }
331: res = "#" + scpx;
332: try {
333: return (String) (cpool[scpx]);
334: } catch (ArrayIndexOutOfBoundsException e) {
335: return res; // "class #"+scpx+"// invalid constant pool index";
336: } catch (ClassCastException e) {
337: return res; // "class #"+scpx+"// invalid constant pool reference";
338: } catch (Throwable e) {
339: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
340: }
341: }
342:
343: /**
344: * Returns true if it is a class
345: */
346: public boolean isClass() {
347: if ((access & ACC_INTERFACE) == 0)
348: return true;
349: return false;
350: }
351:
352: /**
353: * Returns true if it is a interface.
354: */
355: public boolean isInterface() {
356: if ((access & ACC_INTERFACE) != 0)
357: return true;
358: return false;
359: }
360:
361: /**
362: * Returns true if this member is public, false otherwise.
363: */
364: public boolean isPublic() {
365: return (access & ACC_PUBLIC) != 0;
366: }
367:
368: /**
369: * Returns the access of this class or interface.
370: */
371: public String[] getAccess() {
372: Vector v = new Vector();
373: if ((access & ACC_PUBLIC) != 0)
374: v.addElement("public");
375: if ((access & ACC_FINAL) != 0)
376: v.addElement("final");
377: if ((access & ACC_ABSTRACT) != 0)
378: v.addElement("abstract");
379: String[] accflags = new String[v.size()];
380: v.copyInto(accflags);
381: return accflags;
382: }
383:
384: /**
385: * Returns list of innerclasses.
386: */
387: public InnerClassData[] getInnerClasses() {
388: return innerClasses;
389: }
390:
391: /**
392: * Returns list of attributes.
393: */
394: public AttrData[] getAttributes() {
395: return attrs;
396: }
397:
398: /**
399: * Returns true if superbit is set.
400: */
401: public boolean isSuperSet() {
402: if ((access & ACC_SUPER) != 0)
403: return true;
404: return false;
405: }
406:
407: /**
408: * Returns super class name.
409: */
410: public String getSuperClassName() {
411: String res = null;
412: if (super _class == 0) {
413: return res;
414: }
415: int scpx;
416: try {
417: if (tags[super _class] != CONSTANT_CLASS) {
418: return res; //"<CP["+cpx+"] is not a Class> ";
419: }
420: scpx = ((CPX) cpool[super _class]).cpx;
421: } catch (ArrayIndexOutOfBoundsException e) {
422: return res; // "#"+cpx+"// invalid constant pool index";
423: } catch (Throwable e) {
424: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
425: }
426:
427: try {
428: return (String) (cpool[scpx]);
429: } catch (ArrayIndexOutOfBoundsException e) {
430: return res; // "class #"+scpx+"// invalid constant pool index";
431: } catch (ClassCastException e) {
432: return res; // "class #"+scpx+"// invalid constant pool reference";
433: } catch (Throwable e) {
434: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
435: }
436: }
437:
438: /**
439: * Returns list of super interfaces.
440: */
441: public String[] getSuperInterfaces() {
442: String interfacenames[] = new String[interfaces.length];
443: int interfacecpx = -1;
444: for (int i = 0; i < interfaces.length; i++) {
445: interfacecpx = ((CPX) cpool[interfaces[i]]).cpx;
446: interfacenames[i] = (String) (cpool[interfacecpx]);
447: }
448: return interfacenames;
449: }
450:
451: /**
452: * Returns string at prticular constant pool index.
453: */
454: public String getStringValue(int cpoolx) {
455: try {
456: return ((String) cpool[cpoolx]);
457: } catch (ArrayIndexOutOfBoundsException e) {
458: return "//invalid constant pool index:" + cpoolx;
459: } catch (ClassCastException e) {
460: return "//invalid constant pool ref:" + cpoolx;
461: }
462: }
463:
464: /**
465: * Returns list of field info.
466: */
467: public FieldData[] getFields() {
468: return fields;
469: }
470:
471: /**
472: * Returns list of method info.
473: */
474: public MethodData[] getMethods() {
475: return methods;
476: }
477:
478: /**
479: * Returns constant pool entry at that index.
480: */
481: public CPX2 getCpoolEntry(int cpx) {
482: return ((CPX2) (cpool[cpx]));
483: }
484:
485: public Object getCpoolEntryobj(int cpx) {
486: return (cpool[cpx]);
487: }
488:
489: /**
490: * Returns index of this class.
491: */
492: public int getthis _cpx() {
493: return this _class;
494: }
495:
496: public String TagString(int tag) {
497: String res = Tables.tagName(tag);
498: if (res == null)
499: return "BOGUS_TAG:" + tag;
500: return res;
501: }
502:
503: /**
504: * Returns string at that index.
505: */
506: public String StringValue(int cpx) {
507: if (cpx == 0)
508: return "#0";
509: int tag;
510: Object x;
511: String suffix = "";
512: try {
513: tag = tags[cpx];
514: x = cpool[cpx];
515: } catch (IndexOutOfBoundsException e) {
516: return "<Incorrect CP index:" + cpx + ">";
517: }
518:
519: if (x == null)
520: return "<NULL>";
521: switch (tag) {
522: case CONSTANT_UTF8: {
523: StringBuffer sb = new StringBuffer();
524: String s = (String) x;
525: for (int k = 0; k < s.length(); k++) {
526: char c = s.charAt(k);
527: switch (c) {
528: case '\t':
529: sb.append('\\').append('t');
530: break;
531: case '\n':
532: sb.append('\\').append('n');
533: break;
534: case '\r':
535: sb.append('\\').append('r');
536: break;
537: case '\"':
538: sb.append('\\').append('\"');
539: break;
540: default:
541: sb.append(c);
542: }
543: }
544: return sb.toString();
545: }
546: case CONSTANT_DOUBLE: {
547: Double d = (Double) x;
548: String sd = d.toString();
549: return sd + "d";
550: }
551: case CONSTANT_FLOAT: {
552: Float f = (Float) x;
553: String sf = (f).toString();
554: return sf + "f";
555: }
556: case CONSTANT_LONG: {
557: Long ln = (Long) x;
558: return ln.toString() + 'l';
559: }
560: case CONSTANT_INTEGER: {
561: Integer in = (Integer) x;
562: return in.toString();
563: }
564: case CONSTANT_CLASS:
565: return javaName(getClassName(cpx));
566: case CONSTANT_STRING:
567: return StringValue(((CPX) x).cpx);
568: case CONSTANT_FIELD:
569: case CONSTANT_METHOD:
570: case CONSTANT_INTERFACEMETHOD:
571: //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
572: return javaName(getClassName(((CPX2) x).cpx1)) + "."
573: + StringValue(((CPX2) x).cpx2);
574:
575: case CONSTANT_NAMEANDTYPE:
576: return getName(((CPX2) x).cpx1) + ":"
577: + StringValue(((CPX2) x).cpx2);
578: default:
579: return "UnknownTag"; //TBD
580: }
581: }
582:
583: /**
584: * Returns resolved java type name.
585: */
586: public String javaName(String name) {
587: if (name == null)
588: return "null";
589: int len = name.length();
590: if (len == 0)
591: return "\"\"";
592: int cc = '/';
593: fullname: { // xxx/yyy/zzz
594: int cp;
595: for (int k = 0; k < len; k += Character.charCount(cp)) {
596: cp = name.codePointAt(k);
597: if (cc == '/') {
598: if (!Character.isJavaIdentifierStart(cp))
599: break fullname;
600: } else if (cp != '/') {
601: if (!Character.isJavaIdentifierPart(cp))
602: break fullname;
603: }
604: cc = cp;
605: }
606: return name;
607: }
608: return "\"" + name + "\"";
609: }
610:
611: public String getName(int cpx) {
612: String res;
613: try {
614: return javaName((String) cpool[cpx]); //.replace('/','.');
615: } catch (ArrayIndexOutOfBoundsException e) {
616: return "<invalid constant pool index:" + cpx + ">";
617: } catch (ClassCastException e) {
618: return "<invalid constant pool ref:" + cpx + ">";
619: }
620: }
621:
622: /**
623: * Returns unqualified class name.
624: */
625: public String getShortClassName(int cpx) {
626: String classname = javaName(getClassName(cpx));
627: pkgPrefixLen = classname.lastIndexOf("/") + 1;
628: if (pkgPrefixLen != 0) {
629: pkgPrefix = classname.substring(0, pkgPrefixLen);
630: if (classname.startsWith(pkgPrefix)) {
631: return classname.substring(pkgPrefixLen);
632: }
633: }
634: return classname;
635: }
636:
637: /**
638: * Returns source file name.
639: */
640: public String getSourceName() {
641: return getName(source_cpx);
642: }
643:
644: /**
645: * Returns package name.
646: */
647: public String getPkgName() {
648: String classname = getClassName(this _class);
649: pkgPrefixLen = classname.lastIndexOf("/") + 1;
650: if (pkgPrefixLen != 0) {
651: pkgPrefix = classname.substring(0, pkgPrefixLen);
652: return ("package "
653: + pkgPrefix.substring(0, pkgPrefixLen - 1) + ";\n");
654: } else
655: return null;
656: }
657:
658: /**
659: * Returns total constant pool entry count.
660: */
661: public int getCpoolCount() {
662: return cpool_count;
663: }
664:
665: public String StringTag(int cpx) {
666: byte tag = 0;
667: String str = null;
668: try {
669: if (cpx == 0)
670: throw new IndexOutOfBoundsException();
671: tag = tags[cpx];
672: return TagString(tag);
673: } catch (IndexOutOfBoundsException e) {
674: str = "Incorrect CP index:" + cpx;
675: }
676: return str;
677: }
678:
679: /**
680: * Returns minor version of class file.
681: */
682: public int getMinor_version() {
683: return minor_version;
684: }
685:
686: /**
687: * Returns major version of class file.
688: */
689: public int getMajor_version() {
690: return major_version;
691: }
692: }
|