0001: /***
0002: * ASM: a very small and fast Java bytecode manipulation framework
0003: * Copyright (c) 2000-2005 INRIA, France Telecom
0004: * All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: * 1. Redistributions of source code must retain the above copyright
0010: * notice, this list of conditions and the following disclaimer.
0011: * 2. Redistributions in binary form must reproduce the above copyright
0012: * notice, this list of conditions and the following disclaimer in the
0013: * documentation and/or other materials provided with the distribution.
0014: * 3. Neither the name of the copyright holders nor the names of its
0015: * contributors may be used to endorse or promote products derived from
0016: * this software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
0028: * THE POSSIBILITY OF SUCH DAMAGE.
0029: */package org.objectweb.asm.jip;
0030:
0031: import java.io.InputStream;
0032: import java.io.IOException;
0033:
0034: /**
0035: * A Java class parser to make a {@link ClassVisitor} visit an existing class.
0036: * This class parses a byte array conforming to the Java class file format and
0037: * calls the appropriate visit methods of a given class visitor for each field,
0038: * method and bytecode instruction encountered.
0039: *
0040: * @author Eric Bruneton
0041: * @author Eugene Kuleshov
0042: */
0043: public class ClassReader {
0044:
0045: /**
0046: * The class to be parsed. <i>The content of this array must not be
0047: * modified. This field is intended for {@link Attribute} sub classes, and
0048: * is normally not needed by class generators or adapters.</i>
0049: */
0050: public final byte[] b;
0051:
0052: /**
0053: * The start index of each constant pool item in {@link #b b}, plus one.
0054: * The one byte offset skips the constant pool item tag that indicates its
0055: * type.
0056: */
0057: private int[] items;
0058:
0059: /**
0060: * The String objects corresponding to the CONSTANT_Utf8 items. This cache
0061: * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item,
0062: * which GREATLY improves performances (by a factor 2 to 3). This caching
0063: * strategy could be extended to all constant pool items, but its benefit
0064: * would not be so great for these items (because they are much less
0065: * expensive to parse than CONSTANT_Utf8 items).
0066: */
0067: private String[] strings;
0068:
0069: /**
0070: * Maximum length of the strings contained in the constant pool of the
0071: * class.
0072: */
0073: private int maxStringLength;
0074:
0075: /**
0076: * Start index of the class header information (access, name...) in
0077: * {@link #b b}.
0078: */
0079: public final int header;
0080:
0081: // ------------------------------------------------------------------------
0082: // Constructors
0083: // ------------------------------------------------------------------------
0084:
0085: /**
0086: * Constructs a new {@link ClassReader} object.
0087: *
0088: * @param b the bytecode of the class to be read.
0089: */
0090: public ClassReader(final byte[] b) {
0091: this (b, 0, b.length);
0092: }
0093:
0094: /**
0095: * Constructs a new {@link ClassReader} object.
0096: *
0097: * @param b the bytecode of the class to be read.
0098: * @param off the start offset of the class data.
0099: * @param len the length of the class data.
0100: */
0101: public ClassReader(final byte[] b, final int off, final int len) {
0102: this .b = b;
0103: // parses the constant pool
0104: items = new int[readUnsignedShort(off + 8)];
0105: int ll = items.length;
0106: strings = new String[ll];
0107: int max = 0;
0108: int index = off + 10;
0109: for (int i = 1; i < ll; ++i) {
0110: items[i] = index + 1;
0111: int tag = b[index];
0112: int size;
0113: switch (tag) {
0114: case ClassWriter.FIELD:
0115: case ClassWriter.METH:
0116: case ClassWriter.IMETH:
0117: case ClassWriter.INT:
0118: case ClassWriter.FLOAT:
0119: case ClassWriter.NAME_TYPE:
0120: size = 5;
0121: break;
0122: case ClassWriter.LONG:
0123: case ClassWriter.DOUBLE:
0124: size = 9;
0125: ++i;
0126: break;
0127: case ClassWriter.UTF8:
0128: size = 3 + readUnsignedShort(index + 1);
0129: if (size > max) {
0130: max = size;
0131: }
0132: break;
0133: // case ClassWriter.CLASS:
0134: // case ClassWriter.STR:
0135: default:
0136: size = 3;
0137: break;
0138: }
0139: index += size;
0140: }
0141: maxStringLength = max;
0142: // the class header information starts just after the constant pool
0143: header = index;
0144: }
0145:
0146: /**
0147: * Copies the constant pool data into the given {@link ClassWriter}. Should
0148: * be called before the {@link #accept(ClassVisitor,boolean)} method.
0149: *
0150: * @param classWriter the {@link ClassWriter} to copy constant pool into.
0151: */
0152: void copyPool(final ClassWriter classWriter) {
0153: char[] buf = new char[maxStringLength];
0154: int ll = items.length;
0155: Item[] items2 = new Item[ll];
0156: for (int i = 1; i < ll; i++) {
0157: int index = items[i];
0158: int tag = b[index - 1];
0159: Item item = new Item(i);
0160: int nameType;
0161: switch (tag) {
0162: case ClassWriter.FIELD:
0163: case ClassWriter.METH:
0164: case ClassWriter.IMETH:
0165: nameType = items[readUnsignedShort(index + 2)];
0166: item.set(tag, readClass(index, buf), readUTF8(nameType,
0167: buf), readUTF8(nameType + 2, buf));
0168: break;
0169:
0170: case ClassWriter.INT:
0171: item.set(readInt(index));
0172: break;
0173:
0174: case ClassWriter.FLOAT:
0175: item.set(Float.intBitsToFloat(readInt(index)));
0176: break;
0177:
0178: case ClassWriter.NAME_TYPE:
0179: item.set(tag, readUTF8(index, buf), readUTF8(index + 2,
0180: buf), null);
0181: break;
0182:
0183: case ClassWriter.LONG:
0184: item.set(readLong(index));
0185: ++i;
0186: break;
0187:
0188: case ClassWriter.DOUBLE:
0189: item.set(Double.longBitsToDouble(readLong(index)));
0190: ++i;
0191: break;
0192:
0193: case ClassWriter.UTF8: {
0194: String s = strings[i];
0195: if (s == null) {
0196: index = items[i];
0197: s = strings[i] = readUTF(index + 2,
0198: readUnsignedShort(index), buf);
0199: }
0200: item.set(tag, s, null, null);
0201: }
0202: break;
0203:
0204: // case ClassWriter.STR:
0205: // case ClassWriter.CLASS:
0206: default:
0207: item.set(tag, readUTF8(index, buf), null, null);
0208: break;
0209: }
0210:
0211: int index2 = item.hashCode % items2.length;
0212: item.next = items2[index2];
0213: items2[index2] = item;
0214: }
0215:
0216: int off = items[1] - 1;
0217: classWriter.pool.putByteArray(b, off, header - off);
0218: classWriter.items = items2;
0219: classWriter.threshold = (int) (0.75d * ll);
0220: classWriter.index = ll;
0221: }
0222:
0223: /**
0224: * Constructs a new {@link ClassReader} object.
0225: *
0226: * @param is an input stream from which to read the class.
0227: * @throws IOException if a problem occurs during reading.
0228: */
0229: public ClassReader(final InputStream is) throws IOException {
0230: this (readClass(is));
0231: }
0232:
0233: /**
0234: * Constructs a new {@link ClassReader} object.
0235: *
0236: * @param name the fully qualified name of the class to be read.
0237: * @throws IOException if an exception occurs during reading.
0238: */
0239: public ClassReader(final String name) throws IOException {
0240: this (ClassLoader.getSystemResourceAsStream(name.replace('.',
0241: '/')
0242: + ".class"));
0243: }
0244:
0245: /**
0246: * Reads the bytecode of a class.
0247: *
0248: * @param is an input stream from which to read the class.
0249: * @return the bytecode read from the given input stream.
0250: * @throws IOException if a problem occurs during reading.
0251: */
0252: private static byte[] readClass(final InputStream is)
0253: throws IOException {
0254: if (is == null) {
0255: throw new IOException("Class not found");
0256: }
0257: byte[] b = new byte[is.available()];
0258: int len = 0;
0259: while (true) {
0260: int n = is.read(b, len, b.length - len);
0261: if (n == -1) {
0262: if (len < b.length) {
0263: byte[] c = new byte[len];
0264: System.arraycopy(b, 0, c, 0, len);
0265: b = c;
0266: }
0267: return b;
0268: }
0269: len += n;
0270: if (len == b.length) {
0271: byte[] c = new byte[b.length + 1000];
0272: System.arraycopy(b, 0, c, 0, len);
0273: b = c;
0274: }
0275: }
0276: }
0277:
0278: // ------------------------------------------------------------------------
0279: // Public methods
0280: // ------------------------------------------------------------------------
0281:
0282: /**
0283: * Makes the given visitor visit the Java class of this {@link ClassReader}.
0284: * This class is the one specified in the constructor (see
0285: * {@link #ClassReader(byte[]) ClassReader}).
0286: *
0287: * @param classVisitor the visitor that must visit this class.
0288: * @param skipDebug <tt>true</tt> if the debug information of the class
0289: * must not be visited. In this case the
0290: * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
0291: * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will
0292: * not be called.
0293: */
0294: public void accept(final ClassVisitor classVisitor,
0295: final boolean skipDebug) {
0296: accept(classVisitor, new Attribute[0], skipDebug);
0297: }
0298:
0299: /**
0300: * Makes the given visitor visit the Java class of this {@link ClassReader}.
0301: * This class is the one specified in the constructor (see
0302: * {@link #ClassReader(byte[]) ClassReader}).
0303: *
0304: * @param classVisitor the visitor that must visit this class.
0305: * @param attrs prototypes of the attributes that must be parsed during the
0306: * visit of the class. Any attribute whose type is not equal to the
0307: * type of one the prototypes will be ignored.
0308: * @param skipDebug <tt>true</tt> if the debug information of the class
0309: * must not be visited. In this case the
0310: * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
0311: * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will
0312: * not be called.
0313: */
0314: public void accept(final ClassVisitor classVisitor,
0315: final Attribute[] attrs, final boolean skipDebug) {
0316: byte[] b = this .b; // the bytecode array
0317: char[] c = new char[maxStringLength]; // buffer used to read strings
0318: int i, j, k; // loop variables
0319: int u, v, w; // indexes in b
0320: Attribute attr;
0321:
0322: int access;
0323: String name;
0324: String desc;
0325: String attrName;
0326: String signature;
0327: int anns = 0;
0328: int ianns = 0;
0329: Attribute cattrs = null;
0330:
0331: // visits the header
0332: u = header;
0333: access = readUnsignedShort(u);
0334: name = readClass(u + 2, c);
0335: v = items[readUnsignedShort(u + 4)];
0336: String super ClassName = v == 0 ? null : readUTF8(v, c);
0337: String[] implementedItfs = new String[readUnsignedShort(u + 6)];
0338: w = 0;
0339: u += 8;
0340: for (i = 0; i < implementedItfs.length; ++i) {
0341: implementedItfs[i] = readClass(u, c);
0342: u += 2;
0343: }
0344:
0345: // skips fields and methods
0346: v = u;
0347: i = readUnsignedShort(v);
0348: v += 2;
0349: for (; i > 0; --i) {
0350: j = readUnsignedShort(v + 6);
0351: v += 8;
0352: for (; j > 0; --j) {
0353: v += 6 + readInt(v + 2);
0354: }
0355: }
0356: i = readUnsignedShort(v);
0357: v += 2;
0358: for (; i > 0; --i) {
0359: j = readUnsignedShort(v + 6);
0360: v += 8;
0361: for (; j > 0; --j) {
0362: v += 6 + readInt(v + 2);
0363: }
0364: }
0365: // reads the class's attributes
0366: signature = null;
0367: String sourceFile = null;
0368: String sourceDebug = null;
0369: String enclosingOwner = null;
0370: String enclosingName = null;
0371: String enclosingDesc = null;
0372:
0373: i = readUnsignedShort(v);
0374: v += 2;
0375: for (; i > 0; --i) {
0376: attrName = readUTF8(v, c);
0377: if (attrName.equals("SourceFile")) {
0378: sourceFile = readUTF8(v + 6, c);
0379: } else if (attrName.equals("Deprecated")) {
0380: access |= Opcodes.ACC_DEPRECATED;
0381: } else if (attrName.equals("Synthetic")) {
0382: access |= Opcodes.ACC_SYNTHETIC;
0383: } else if (attrName.equals("Annotation")) {
0384: access |= Opcodes.ACC_ANNOTATION;
0385: } else if (attrName.equals("Enum")) {
0386: access |= Opcodes.ACC_ENUM;
0387: } else if (attrName.equals("InnerClasses")) {
0388: w = v + 6;
0389: } else if (attrName.equals("Signature")) {
0390: signature = readUTF8(v + 6, c);
0391: } else if (attrName.equals("SourceDebugExtension")) {
0392: int len = readInt(v + 2);
0393: sourceDebug = readUTF(v + 6, len, new char[len]);
0394: } else if (attrName.equals("EnclosingMethod")) {
0395: enclosingOwner = readClass(v + 6, c);
0396: int item = readUnsignedShort(v + 8);
0397: if (item != 0) {
0398: enclosingName = readUTF8(items[item], c);
0399: enclosingDesc = readUTF8(items[item] + 2, c);
0400: }
0401: } else if (attrName.equals("RuntimeVisibleAnnotations")) {
0402: anns = v + 6;
0403: } else if (attrName.equals("RuntimeInvisibleAnnotations")) {
0404: ianns = v + 6;
0405: } else {
0406: attr = readAttribute(attrs, attrName, v + 6,
0407: readInt(v + 2), c, -1, null);
0408: if (attr != null) {
0409: attr.next = cattrs;
0410: cattrs = attr;
0411: }
0412: }
0413: v += 6 + readInt(v + 2);
0414: }
0415: // calls the visit method
0416: classVisitor.visit(readInt(4), access, name, signature,
0417: super ClassName, implementedItfs);
0418:
0419: // calls the visitSource method
0420: if (sourceFile != null || sourceDebug != null) {
0421: classVisitor.visitSource(sourceFile, sourceDebug);
0422: }
0423:
0424: // calls the visitOuterClass method
0425: if (enclosingOwner != null) {
0426: classVisitor.visitOuterClass(enclosingOwner, enclosingName,
0427: enclosingDesc);
0428: }
0429:
0430: // visits the class annotations
0431: for (i = 1; i >= 0; --i) {
0432: v = i == 0 ? ianns : anns;
0433: if (v != 0) {
0434: j = readUnsignedShort(v);
0435: v += 2;
0436: for (; j > 0; --j) {
0437: desc = readUTF8(v, c);
0438: v += 2;
0439: v = readAnnotationValues(v, c, classVisitor
0440: .visitAnnotation(desc, i != 0));
0441: }
0442: }
0443: }
0444:
0445: // visits the class attributes
0446: while (cattrs != null) {
0447: attr = cattrs.next;
0448: cattrs.next = null;
0449: classVisitor.visitAttribute(cattrs);
0450: cattrs = attr;
0451: }
0452:
0453: // class the visitInnerClass method
0454: if (w != 0) {
0455: i = readUnsignedShort(w);
0456: w += 2;
0457: for (; i > 0; --i) {
0458: classVisitor.visitInnerClass(
0459: readUnsignedShort(w) == 0 ? null : readClass(w,
0460: c),
0461: readUnsignedShort(w + 2) == 0 ? null
0462: : readClass(w + 2, c),
0463: readUnsignedShort(w + 4) == 0 ? null
0464: : readUTF8(w + 4, c),
0465: readUnsignedShort(w + 6));
0466: w += 8;
0467: }
0468: }
0469:
0470: // visits the fields
0471: i = readUnsignedShort(u);
0472: u += 2;
0473: for (; i > 0; --i) {
0474: access = readUnsignedShort(u);
0475: name = readUTF8(u + 2, c);
0476: desc = readUTF8(u + 4, c);
0477: // visits the field's attributes and looks for a ConstantValue
0478: // attribute
0479: int fieldValueItem = 0;
0480: signature = null;
0481: anns = 0;
0482: ianns = 0;
0483: cattrs = null;
0484:
0485: j = readUnsignedShort(u + 6);
0486: u += 8;
0487: for (; j > 0; --j) {
0488: attrName = readUTF8(u, c);
0489: if (attrName.equals("ConstantValue")) {
0490: fieldValueItem = readUnsignedShort(u + 6);
0491: } else if (attrName.equals("Synthetic")) {
0492: access |= Opcodes.ACC_SYNTHETIC;
0493: } else if (attrName.equals("Deprecated")) {
0494: access |= Opcodes.ACC_DEPRECATED;
0495: } else if (attrName.equals("Enum")) {
0496: access |= Opcodes.ACC_ENUM;
0497: } else if (attrName.equals("Signature")) {
0498: signature = readUTF8(u + 6, c);
0499: } else if (attrName.equals("RuntimeVisibleAnnotations")) {
0500: anns = u + 6;
0501: } else if (attrName
0502: .equals("RuntimeInvisibleAnnotations")) {
0503: ianns = u + 6;
0504: } else {
0505: attr = readAttribute(attrs, attrName, u + 6,
0506: readInt(u + 2), c, -1, null);
0507: if (attr != null) {
0508: attr.next = cattrs;
0509: cattrs = attr;
0510: }
0511: }
0512: u += 6 + readInt(u + 2);
0513: }
0514: // reads the field's value, if any
0515: Object value = (fieldValueItem == 0 ? null : readConst(
0516: fieldValueItem, c));
0517: // visits the field
0518: FieldVisitor fv = classVisitor.visitField(access, name,
0519: desc, signature, value);
0520: // visits the field annotations and attributes
0521: if (fv != null) {
0522: for (j = 1; j >= 0; --j) {
0523: v = j == 0 ? ianns : anns;
0524: if (v != 0) {
0525: k = readUnsignedShort(v);
0526: v += 2;
0527: for (; k > 0; --k) {
0528: desc = readUTF8(v, c);
0529: v += 2;
0530: v = readAnnotationValues(v, c, fv
0531: .visitAnnotation(desc, j != 0));
0532: }
0533: }
0534: }
0535: while (cattrs != null) {
0536: attr = cattrs.next;
0537: cattrs.next = null;
0538: fv.visitAttribute(cattrs);
0539: cattrs = attr;
0540: }
0541: fv.visitEnd();
0542: }
0543: }
0544:
0545: // visits the methods
0546: i = readUnsignedShort(u);
0547: u += 2;
0548: for (; i > 0; --i) {
0549: int u0 = u + 6;
0550: access = readUnsignedShort(u);
0551: name = readUTF8(u + 2, c);
0552: desc = readUTF8(u + 4, c);
0553: signature = null;
0554: anns = 0;
0555: ianns = 0;
0556: int dann = 0;
0557: int mpanns = 0;
0558: int impanns = 0;
0559: cattrs = null;
0560: v = 0;
0561: w = 0;
0562:
0563: // looks for Code and Exceptions attributes
0564: j = readUnsignedShort(u + 6);
0565: u += 8;
0566: for (; j > 0; --j) {
0567: attrName = readUTF8(u, c);
0568: u += 2;
0569: int attrSize = readInt(u);
0570: u += 4;
0571: if (attrName.equals("Code")) {
0572: v = u;
0573: } else if (attrName.equals("Exceptions")) {
0574: w = u;
0575: } else if (attrName.equals("Synthetic")) {
0576: access |= Opcodes.ACC_SYNTHETIC;
0577: } else if (attrName.equals("Varargs")) {
0578: access |= Opcodes.ACC_VARARGS;
0579: } else if (attrName.equals("Bridge")) {
0580: access |= Opcodes.ACC_BRIDGE;
0581: } else if (attrName.equals("Deprecated")) {
0582: access |= Opcodes.ACC_DEPRECATED;
0583: } else if (attrName.equals("Signature")) {
0584: signature = readUTF8(u, c);
0585: } else if (attrName.equals("AnnotationDefault")) {
0586: dann = u;
0587: } else if (attrName.equals("RuntimeVisibleAnnotations")) {
0588: anns = u;
0589: } else if (attrName
0590: .equals("RuntimeInvisibleAnnotations")) {
0591: ianns = u;
0592: } else if (attrName
0593: .equals("RuntimeVisibleParameterAnnotations")) {
0594: mpanns = u;
0595: } else if (attrName
0596: .equals("RuntimeInvisibleParameterAnnotations")) {
0597: impanns = u;
0598: } else {
0599: attr = readAttribute(attrs, attrName, u, attrSize,
0600: c, -1, null);
0601: if (attr != null) {
0602: attr.next = cattrs;
0603: cattrs = attr;
0604: }
0605: }
0606: u += attrSize;
0607: }
0608: // reads declared exceptions
0609: String[] exceptions;
0610: if (w == 0) {
0611: exceptions = null;
0612: } else {
0613: exceptions = new String[readUnsignedShort(w)];
0614: w += 2;
0615: for (j = 0; j < exceptions.length; ++j) {
0616: exceptions[j] = readClass(w, c);
0617: w += 2;
0618: }
0619: }
0620:
0621: // visits the method's code, if any
0622: MethodVisitor mv = classVisitor.visitMethod(access, name,
0623: desc, signature, exceptions);
0624:
0625: if (mv != null) {
0626: /*
0627: * if the returned MethodVisitor is in fact a MethodWriter, it
0628: * means there is no method adapter between the reader and the
0629: * writer. If, in addition, the writer's constant pool was
0630: * copied from this reader (mw.cw.cr == this), and the signature
0631: * and exceptions of the method have not been changed, then it
0632: * is possible to skip all visit events and just copy the
0633: * original code of the method to the writer (the access, name
0634: * and descriptor can have been changed, this is not important
0635: * since they are not copied as is from the reader).
0636: */
0637: if (mv instanceof MethodWriter) {
0638: MethodWriter mw = (MethodWriter) mv;
0639: if (mw.cw.cr == this ) {
0640: if (signature == mw.signature) {
0641: boolean sameExceptions = false;
0642: if (exceptions == null) {
0643: sameExceptions = mw.exceptionCount == 0;
0644: } else {
0645: if (exceptions.length == mw.exceptionCount) {
0646: sameExceptions = true;
0647: for (j = exceptions.length - 1; j >= 0; --j) {
0648: w -= 2;
0649: if (mw.exceptions[j] != readUnsignedShort(w)) {
0650: sameExceptions = false;
0651: break;
0652: }
0653: }
0654: }
0655: }
0656: if (sameExceptions) {
0657: /*
0658: * we do not copy directly the code into
0659: * MethodWriter to save a byte array copy
0660: * operation. The real copy will be done in
0661: * ClassWriter.toByteArray().
0662: */
0663: mw.classReaderOffset = u0;
0664: mw.classReaderLength = u - u0;
0665: continue;
0666: }
0667: }
0668: }
0669: }
0670: if (dann != 0) {
0671: AnnotationVisitor dv = mv.visitAnnotationDefault();
0672: readAnnotationValue(dann, c, null, dv);
0673: dv.visitEnd();
0674: }
0675: for (j = 1; j >= 0; --j) {
0676: w = j == 0 ? ianns : anns;
0677: if (w != 0) {
0678: k = readUnsignedShort(w);
0679: w += 2;
0680: for (; k > 0; --k) {
0681: desc = readUTF8(w, c);
0682: w += 2;
0683: w = readAnnotationValues(w, c, mv
0684: .visitAnnotation(desc, j != 0));
0685: }
0686: }
0687: }
0688: if (mpanns != 0) {
0689: readParameterAnnotations(mpanns, c, true, mv);
0690: }
0691: if (impanns != 0) {
0692: readParameterAnnotations(impanns, c, false, mv);
0693: }
0694: while (cattrs != null) {
0695: attr = cattrs.next;
0696: cattrs.next = null;
0697: mv.visitAttribute(cattrs);
0698: cattrs = attr;
0699: }
0700: }
0701:
0702: if (mv != null && v != 0) {
0703: int maxStack = readUnsignedShort(v);
0704: int maxLocals = readUnsignedShort(v + 2);
0705: int codeLength = readInt(v + 4);
0706: v += 8;
0707:
0708: int codeStart = v;
0709: int codeEnd = v + codeLength;
0710:
0711: mv.visitCode();
0712:
0713: // 1st phase: finds the labels
0714: int label;
0715: Label[] labels = new Label[codeLength + 1];
0716: while (v < codeEnd) {
0717: int opcode = b[v] & 0xFF;
0718: switch (ClassWriter.TYPE[opcode]) {
0719: case ClassWriter.NOARG_INSN:
0720: case ClassWriter.IMPLVAR_INSN:
0721: v += 1;
0722: break;
0723: case ClassWriter.LABEL_INSN:
0724: label = v - codeStart + readShort(v + 1);
0725: if (labels[label] == null) {
0726: labels[label] = new Label();
0727: }
0728: v += 3;
0729: break;
0730: case ClassWriter.LABELW_INSN:
0731: label = v - codeStart + readInt(v + 1);
0732: if (labels[label] == null) {
0733: labels[label] = new Label();
0734: }
0735: v += 5;
0736: break;
0737: case ClassWriter.WIDE_INSN:
0738: opcode = b[v + 1] & 0xFF;
0739: if (opcode == Opcodes.IINC) {
0740: v += 6;
0741: } else {
0742: v += 4;
0743: }
0744: break;
0745: case ClassWriter.TABL_INSN:
0746: // skips 0 to 3 padding bytes
0747: w = v - codeStart;
0748: v = v + 4 - (w & 3);
0749: // reads instruction
0750: label = w + readInt(v);
0751: v += 4;
0752: if (labels[label] == null) {
0753: labels[label] = new Label();
0754: }
0755: j = readInt(v);
0756: v += 4;
0757: j = readInt(v) - j + 1;
0758: v += 4;
0759: for (; j > 0; --j) {
0760: label = w + readInt(v);
0761: v += 4;
0762: if (labels[label] == null) {
0763: labels[label] = new Label();
0764: }
0765: }
0766: break;
0767: case ClassWriter.LOOK_INSN:
0768: // skips 0 to 3 padding bytes
0769: w = v - codeStart;
0770: v = v + 4 - (w & 3);
0771: // reads instruction
0772: label = w + readInt(v);
0773: v += 4;
0774: if (labels[label] == null) {
0775: labels[label] = new Label();
0776: }
0777: j = readInt(v);
0778: v += 4;
0779: for (; j > 0; --j) {
0780: v += 4; // skips key
0781: label = w + readInt(v);
0782: v += 4;
0783: if (labels[label] == null) {
0784: labels[label] = new Label();
0785: }
0786: }
0787: break;
0788: case ClassWriter.VAR_INSN:
0789: case ClassWriter.SBYTE_INSN:
0790: case ClassWriter.LDC_INSN:
0791: v += 2;
0792: break;
0793: case ClassWriter.SHORT_INSN:
0794: case ClassWriter.LDCW_INSN:
0795: case ClassWriter.FIELDORMETH_INSN:
0796: case ClassWriter.TYPE_INSN:
0797: case ClassWriter.IINC_INSN:
0798: v += 3;
0799: break;
0800: case ClassWriter.ITFMETH_INSN:
0801: v += 5;
0802: break;
0803: // case MANA_INSN:
0804: default:
0805: v += 4;
0806: break;
0807: }
0808: }
0809: // parses the try catch entries
0810: j = readUnsignedShort(v);
0811: v += 2;
0812: for (; j > 0; --j) {
0813: label = readUnsignedShort(v);
0814: Label start = labels[label];
0815: if (start == null) {
0816: labels[label] = start = new Label();
0817: }
0818: label = readUnsignedShort(v + 2);
0819: Label end = labels[label];
0820: if (end == null) {
0821: labels[label] = end = new Label();
0822: }
0823: label = readUnsignedShort(v + 4);
0824: Label handler = labels[label];
0825: if (handler == null) {
0826: labels[label] = handler = new Label();
0827: }
0828:
0829: int type = readUnsignedShort(v + 6);
0830: if (type == 0) {
0831: mv
0832: .visitTryCatchBlock(start, end,
0833: handler, null);
0834: } else {
0835: mv.visitTryCatchBlock(start, end, handler,
0836: readUTF8(items[type], c));
0837: }
0838: v += 8;
0839: }
0840: // parses the local variable, line number tables, and code
0841: // attributes
0842: int varTable = 0;
0843: int varTypeTable = 0;
0844: cattrs = null;
0845: j = readUnsignedShort(v);
0846: v += 2;
0847: for (; j > 0; --j) {
0848: attrName = readUTF8(v, c);
0849: if (attrName.equals("LocalVariableTable")) {
0850: if (!skipDebug) {
0851: varTable = v + 6;
0852: k = readUnsignedShort(v + 6);
0853: w = v + 8;
0854: for (; k > 0; --k) {
0855: label = readUnsignedShort(w);
0856: if (labels[label] == null) {
0857: labels[label] = new Label();
0858: }
0859: label += readUnsignedShort(w + 2);
0860: if (labels[label] == null) {
0861: labels[label] = new Label();
0862: }
0863: w += 10;
0864: }
0865: }
0866: } else if (attrName
0867: .equals("LocalVariableTypeTable")) {
0868: varTypeTable = v + 6;
0869: } else if (attrName.equals("LineNumberTable")) {
0870: if (!skipDebug) {
0871: k = readUnsignedShort(v + 6);
0872: w = v + 8;
0873: for (; k > 0; --k) {
0874: label = readUnsignedShort(w);
0875: if (labels[label] == null) {
0876: labels[label] = new Label();
0877: }
0878: labels[label].line = readUnsignedShort(w + 2);
0879: w += 4;
0880: }
0881: }
0882: } else {
0883: for (k = 0; k < attrs.length; ++k) {
0884: if (attrs[k].type.equals(attrName)) {
0885: attr = attrs[k].read(this , v + 6,
0886: readInt(v + 2), c,
0887: codeStart - 8, labels);
0888: if (attr != null) {
0889: attr.next = cattrs;
0890: cattrs = attr;
0891: }
0892: }
0893: }
0894: }
0895: v += 6 + readInt(v + 2);
0896: }
0897:
0898: // 2nd phase: visits each instruction
0899: v = codeStart;
0900: Label l;
0901: while (v < codeEnd) {
0902: w = v - codeStart;
0903: l = labels[w];
0904: if (l != null) {
0905: mv.visitLabel(l);
0906: if (!skipDebug && l.line > 0) {
0907: mv.visitLineNumber(l.line, l);
0908: }
0909: }
0910: int opcode = b[v] & 0xFF;
0911: switch (ClassWriter.TYPE[opcode]) {
0912: case ClassWriter.NOARG_INSN:
0913: mv.visitInsn(opcode);
0914: v += 1;
0915: break;
0916: case ClassWriter.IMPLVAR_INSN:
0917: if (opcode > Opcodes.ISTORE) {
0918: opcode -= 59; // ISTORE_0
0919: mv.visitVarInsn(Opcodes.ISTORE
0920: + (opcode >> 2), opcode & 0x3);
0921: } else {
0922: opcode -= 26; // ILOAD_0
0923: mv.visitVarInsn(Opcodes.ILOAD
0924: + (opcode >> 2), opcode & 0x3);
0925: }
0926: v += 1;
0927: break;
0928: case ClassWriter.LABEL_INSN:
0929: mv.visitJumpInsn(opcode, labels[w
0930: + readShort(v + 1)]);
0931: v += 3;
0932: break;
0933: case ClassWriter.LABELW_INSN:
0934: mv.visitJumpInsn(opcode - 33, labels[w
0935: + readInt(v + 1)]);
0936: v += 5;
0937: break;
0938: case ClassWriter.WIDE_INSN:
0939: opcode = b[v + 1] & 0xFF;
0940: if (opcode == Opcodes.IINC) {
0941: mv.visitIincInsn(readUnsignedShort(v + 2),
0942: readShort(v + 4));
0943: v += 6;
0944: } else {
0945: mv.visitVarInsn(opcode,
0946: readUnsignedShort(v + 2));
0947: v += 4;
0948: }
0949: break;
0950: case ClassWriter.TABL_INSN:
0951: // skips 0 to 3 padding bytes
0952: v = v + 4 - (w & 3);
0953: // reads instruction
0954: label = w + readInt(v);
0955: v += 4;
0956: int min = readInt(v);
0957: v += 4;
0958: int max = readInt(v);
0959: v += 4;
0960: Label[] table = new Label[max - min + 1];
0961: for (j = 0; j < table.length; ++j) {
0962: table[j] = labels[w + readInt(v)];
0963: v += 4;
0964: }
0965: mv.visitTableSwitchInsn(min, max,
0966: labels[label], table);
0967: break;
0968: case ClassWriter.LOOK_INSN:
0969: // skips 0 to 3 padding bytes
0970: v = v + 4 - (w & 3);
0971: // reads instruction
0972: label = w + readInt(v);
0973: v += 4;
0974: j = readInt(v);
0975: v += 4;
0976: int[] keys = new int[j];
0977: Label[] values = new Label[j];
0978: for (j = 0; j < keys.length; ++j) {
0979: keys[j] = readInt(v);
0980: v += 4;
0981: values[j] = labels[w + readInt(v)];
0982: v += 4;
0983: }
0984: mv.visitLookupSwitchInsn(labels[label], keys,
0985: values);
0986: break;
0987: case ClassWriter.VAR_INSN:
0988: mv.visitVarInsn(opcode, b[v + 1] & 0xFF);
0989: v += 2;
0990: break;
0991: case ClassWriter.SBYTE_INSN:
0992: mv.visitIntInsn(opcode, b[v + 1]);
0993: v += 2;
0994: break;
0995: case ClassWriter.SHORT_INSN:
0996: mv.visitIntInsn(opcode, readShort(v + 1));
0997: v += 3;
0998: break;
0999: case ClassWriter.LDC_INSN:
1000: mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c));
1001: v += 2;
1002: break;
1003: case ClassWriter.LDCW_INSN:
1004: mv.visitLdcInsn(readConst(
1005: readUnsignedShort(v + 1), c));
1006: v += 3;
1007: break;
1008: case ClassWriter.FIELDORMETH_INSN:
1009: case ClassWriter.ITFMETH_INSN:
1010: int cpIndex = items[readUnsignedShort(v + 1)];
1011: String iowner = readClass(cpIndex, c);
1012: cpIndex = items[readUnsignedShort(cpIndex + 2)];
1013: String iname = readUTF8(cpIndex, c);
1014: String idesc = readUTF8(cpIndex + 2, c);
1015: if (opcode < Opcodes.INVOKEVIRTUAL) {
1016: mv.visitFieldInsn(opcode, iowner, iname,
1017: idesc);
1018: } else {
1019: mv.visitMethodInsn(opcode, iowner, iname,
1020: idesc);
1021: }
1022: if (opcode == Opcodes.INVOKEINTERFACE) {
1023: v += 5;
1024: } else {
1025: v += 3;
1026: }
1027: break;
1028: case ClassWriter.TYPE_INSN:
1029: mv.visitTypeInsn(opcode, readClass(v + 1, c));
1030: v += 3;
1031: break;
1032: case ClassWriter.IINC_INSN:
1033: mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]);
1034: v += 3;
1035: break;
1036: // case MANA_INSN:
1037: default:
1038: mv.visitMultiANewArrayInsn(readClass(v + 1, c),
1039: b[v + 3] & 0xFF);
1040: v += 4;
1041: break;
1042: }
1043: }
1044: l = labels[codeEnd - codeStart];
1045: if (l != null) {
1046: mv.visitLabel(l);
1047: }
1048:
1049: // visits the local variable tables
1050: if (!skipDebug && varTable != 0) {
1051: int[] typeTable = null;
1052: if (varTypeTable != 0) {
1053: w = varTypeTable;
1054: k = readUnsignedShort(w) * 3;
1055: w += 2;
1056: typeTable = new int[k];
1057: while (k > 0) {
1058: typeTable[--k] = w + 6; // signature
1059: typeTable[--k] = readUnsignedShort(w + 8); // index
1060: typeTable[--k] = readUnsignedShort(w); // start
1061: w += 10;
1062: }
1063: }
1064: w = varTable;
1065: k = readUnsignedShort(w);
1066: w += 2;
1067: for (; k > 0; --k) {
1068: int start = readUnsignedShort(w);
1069: int length = readUnsignedShort(w + 2);
1070: int index = readUnsignedShort(w + 8);
1071: String vsignature = null;
1072: if (typeTable != null) {
1073: for (int a = 0; a < typeTable.length; a += 3) {
1074: if (typeTable[a] == start
1075: && typeTable[a + 1] == index) {
1076: vsignature = readUTF8(
1077: typeTable[a + 2], c);
1078: break;
1079: }
1080: }
1081: }
1082: mv.visitLocalVariable(readUTF8(w + 4, c),
1083: readUTF8(w + 6, c), vsignature,
1084: labels[start], labels[start + length],
1085: index);
1086: w += 10;
1087: }
1088: }
1089: // visits the other attributes
1090: while (cattrs != null) {
1091: attr = cattrs.next;
1092: cattrs.next = null;
1093: mv.visitAttribute(cattrs);
1094: cattrs = attr;
1095: }
1096: // visits the max stack and max locals values
1097: mv.visitMaxs(maxStack, maxLocals);
1098: }
1099:
1100: if (mv != null) {
1101: mv.visitEnd();
1102: }
1103: }
1104:
1105: // visits the end of the class
1106: classVisitor.visitEnd();
1107: }
1108:
1109: /**
1110: * Reads parameter annotations and makes the given visitor visit them.
1111: *
1112: * @param v start offset in {@link #b b} of the annotations to be read.
1113: * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1114: * {@link #readClass(int,char[]) readClass} or
1115: * {@link #readConst readConst}.
1116: * @param visible <tt>true</tt> if the annotations to be read are visible
1117: * at runtime.
1118: * @param mv the visitor that must visit the annotations.
1119: */
1120: private void readParameterAnnotations(int v, final char[] buf,
1121: final boolean visible, final MethodVisitor mv) {
1122: int n = b[v++] & 0xFF;
1123: for (int i = 0; i < n; ++i) {
1124: int j = readUnsignedShort(v);
1125: v += 2;
1126: for (; j > 0; --j) {
1127: String desc = readUTF8(v, buf);
1128: v += 2;
1129: AnnotationVisitor av = mv.visitParameterAnnotation(i,
1130: desc, visible);
1131: v = readAnnotationValues(v, buf, av);
1132: }
1133: }
1134: }
1135:
1136: /**
1137: * Reads the values of an annotation and makes the given visitor visit them.
1138: *
1139: * @param v the start offset in {@link #b b} of the values to be read
1140: * (including the unsigned short that gives the number of values).
1141: * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1142: * {@link #readClass(int,char[]) readClass} or
1143: * {@link #readConst readConst}.
1144: * @param av the visitor that must visit the values.
1145: * @return the end offset of the annotations values.
1146: */
1147: private int readAnnotationValues(int v, final char[] buf,
1148: final AnnotationVisitor av) {
1149: int i = readUnsignedShort(v);
1150: v += 2;
1151: for (; i > 0; --i) {
1152: String name = readUTF8(v, buf);
1153: v += 2;
1154: v = readAnnotationValue(v, buf, name, av);
1155: }
1156: av.visitEnd();
1157: return v;
1158: }
1159:
1160: /**
1161: * Reads a value of an annotation and makes the given visitor visit it.
1162: *
1163: * @param v the start offset in {@link #b b} of the value to be read (<i>not
1164: * including the value name constant pool index</i>).
1165: * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1166: * {@link #readClass(int,char[]) readClass} or
1167: * {@link #readConst readConst}.
1168: * @param name the name of the value to be read.
1169: * @param av the visitor that must visit the value.
1170: * @return the end offset of the annotation value.
1171: */
1172: private int readAnnotationValue(int v, final char[] buf,
1173: final String name, final AnnotationVisitor av) {
1174: int i;
1175: switch (readByte(v++)) {
1176: case 'I': // pointer to CONSTANT_Integer
1177: case 'J': // pointer to CONSTANT_Long
1178: case 'F': // pointer to CONSTANT_Float
1179: case 'D': // pointer to CONSTANT_Double
1180: av.visit(name, readConst(readUnsignedShort(v), buf));
1181: v += 2;
1182: break;
1183: case 'B': // pointer to CONSTANT_Byte
1184: av.visit(name, new Byte(
1185: (byte) readInt(items[readUnsignedShort(v)])));
1186: v += 2;
1187: break;
1188: case 'Z': // pointer to CONSTANT_Boolean
1189: boolean b = readInt(items[readUnsignedShort(v)]) == 0;
1190: av.visit(name, b ? Boolean.FALSE : Boolean.TRUE);
1191: v += 2;
1192: break;
1193: case 'S': // pointer to CONSTANT_Short
1194: av.visit(name, new Short(
1195: (short) readInt(items[readUnsignedShort(v)])));
1196: v += 2;
1197: break;
1198: case 'C': // pointer to CONSTANT_Char
1199: av.visit(name, new Character(
1200: (char) readInt(items[readUnsignedShort(v)])));
1201: v += 2;
1202: break;
1203: case 's': // pointer to CONSTANT_Utf8
1204: av.visit(name, readUTF8(v, buf));
1205: v += 2;
1206: break;
1207: case 'e': // enum_const_value
1208: av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf));
1209: v += 4;
1210: break;
1211: case 'c': // class_info
1212: av.visit(name, Type.getType(readUTF8(v, buf)));
1213: v += 2;
1214: break;
1215: case '@': // annotation_value
1216: String desc = readUTF8(v, buf);
1217: v += 2;
1218: v = readAnnotationValues(v, buf, av.visitAnnotation(name,
1219: desc));
1220: break;
1221: case '[': // array_value
1222: int size = readUnsignedShort(v);
1223: v += 2;
1224: if (size == 0) {
1225: av.visitArray(name).visitEnd();
1226: return v;
1227: }
1228: switch (readByte(v++)) {
1229: case 'B':
1230: byte[] bv = new byte[size];
1231: for (i = 0; i < size; i++) {
1232: bv[i] = (byte) readInt(items[readUnsignedShort(v)]);
1233: v += 3;
1234: }
1235: av.visit(name, bv);
1236: --v;
1237: break;
1238: case 'Z':
1239: boolean[] zv = new boolean[size];
1240: for (i = 0; i < size; i++) {
1241: zv[i] = readInt(items[readUnsignedShort(v)]) != 0;
1242: v += 3;
1243: }
1244: av.visit(name, zv);
1245: --v;
1246: break;
1247: case 'S':
1248: short[] sv = new short[size];
1249: for (i = 0; i < size; i++) {
1250: sv[i] = (short) readInt(items[readUnsignedShort(v)]);
1251: v += 3;
1252: }
1253: av.visit(name, sv);
1254: --v;
1255: break;
1256: case 'C':
1257: char[] cv = new char[size];
1258: for (i = 0; i < size; i++) {
1259: cv[i] = (char) readInt(items[readUnsignedShort(v)]);
1260: v += 3;
1261: }
1262: av.visit(name, cv);
1263: --v;
1264: break;
1265: case 'I':
1266: int[] iv = new int[size];
1267: for (i = 0; i < size; i++) {
1268: iv[i] = readInt(items[readUnsignedShort(v)]);
1269: v += 3;
1270: }
1271: av.visit(name, iv);
1272: --v;
1273: break;
1274: case 'J':
1275: long[] lv = new long[size];
1276: for (i = 0; i < size; i++) {
1277: lv[i] = readLong(items[readUnsignedShort(v)]);
1278: v += 3;
1279: }
1280: av.visit(name, lv);
1281: --v;
1282: break;
1283: case 'F':
1284: float[] fv = new float[size];
1285: for (i = 0; i < size; i++) {
1286: fv[i] = Float
1287: .intBitsToFloat(readInt(items[readUnsignedShort(v)]));
1288: v += 3;
1289: }
1290: av.visit(name, fv);
1291: --v;
1292: break;
1293: case 'D':
1294: double[] dv = new double[size];
1295: for (i = 0; i < size; i++) {
1296: dv[i] = Double
1297: .longBitsToDouble(readLong(items[readUnsignedShort(v)]));
1298: v += 3;
1299: }
1300: av.visit(name, dv);
1301: --v;
1302: break;
1303: default:
1304: v--;
1305: AnnotationVisitor aav = av.visitArray(name);
1306: for (i = size; i > 0; --i) {
1307: v = readAnnotationValue(v, buf, null, aav);
1308: }
1309: aav.visitEnd();
1310: }
1311: }
1312: return v;
1313: }
1314:
1315: /**
1316: * Reads an attribute in {@link #b b}.
1317: *
1318: * @param attrs prototypes of the attributes that must be parsed during the
1319: * visit of the class. Any attribute whose type is not equal to the
1320: * type of one the prototypes is ignored (i.e. an empty
1321: * {@link Attribute} instance is returned).
1322: * @param type the type of the attribute.
1323: * @param off index of the first byte of the attribute's content in
1324: * {@link #b b}. The 6 attribute header bytes, containing the type
1325: * and the length of the attribute, are not taken into account here
1326: * (they have already been read).
1327: * @param len the length of the attribute's content.
1328: * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1329: * {@link #readClass(int,char[]) readClass} or
1330: * {@link #readConst readConst}.
1331: * @param codeOff index of the first byte of code's attribute content in
1332: * {@link #b b}, or -1 if the attribute to be read is not a code
1333: * attribute. The 6 attribute header bytes, containing the type and
1334: * the length of the attribute, are not taken into account here.
1335: * @param labels the labels of the method's code, or <tt>null</tt> if the
1336: * attribute to be read is not a code attribute.
1337: * @return the attribute that has been read, or <tt>null</tt> to skip this
1338: * attribute.
1339: */
1340: private Attribute readAttribute(final Attribute[] attrs,
1341: final String type, final int off, final int len,
1342: final char[] buf, final int codeOff, final Label[] labels) {
1343: for (int i = 0; i < attrs.length; ++i) {
1344: if (attrs[i].type.equals(type)) {
1345: return attrs[i].read(this , off, len, buf, codeOff,
1346: labels);
1347: }
1348: }
1349: return new Attribute(type).read(this , off, len, null, -1, null);
1350: }
1351:
1352: // ------------------------------------------------------------------------
1353: // Utility methods: low level parsing
1354: // ------------------------------------------------------------------------
1355:
1356: /**
1357: * Returns the start index of the constant pool item in {@link #b b}, plus
1358: * one. <i>This method is intended for {@link Attribute} sub classes, and is
1359: * normally not needed by class generators or adapters.</i>
1360: *
1361: * @param item the index a constant pool item.
1362: * @return the start index of the constant pool item in {@link #b b}, plus
1363: * one.
1364: */
1365: public int getItem(final int item) {
1366: return items[item];
1367: }
1368:
1369: /**
1370: * Reads a byte value in {@link #b b}. <i>This method is intended for
1371: * {@link Attribute} sub classes, and is normally not needed by class
1372: * generators or adapters.</i>
1373: *
1374: * @param index the start index of the value to be read in {@link #b b}.
1375: * @return the read value.
1376: */
1377: public int readByte(final int index) {
1378: return b[index] & 0xFF;
1379: }
1380:
1381: /**
1382: * Reads an unsigned short value in {@link #b b}. <i>This method is
1383: * intended for {@link Attribute} sub classes, and is normally not needed by
1384: * class generators or adapters.</i>
1385: *
1386: * @param index the start index of the value to be read in {@link #b b}.
1387: * @return the read value.
1388: */
1389: public int readUnsignedShort(final int index) {
1390: byte[] b = this .b;
1391: return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
1392: }
1393:
1394: /**
1395: * Reads a signed short value in {@link #b b}. <i>This method is intended
1396: * for {@link Attribute} sub classes, and is normally not needed by class
1397: * generators or adapters.</i>
1398: *
1399: * @param index the start index of the value to be read in {@link #b b}.
1400: * @return the read value.
1401: */
1402: public short readShort(final int index) {
1403: byte[] b = this .b;
1404: return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
1405: }
1406:
1407: /**
1408: * Reads a signed int value in {@link #b b}. <i>This method is intended for
1409: * {@link Attribute} sub classes, and is normally not needed by class
1410: * generators or adapters.</i>
1411: *
1412: * @param index the start index of the value to be read in {@link #b b}.
1413: * @return the read value.
1414: */
1415: public int readInt(final int index) {
1416: byte[] b = this .b;
1417: return ((b[index] & 0xFF) << 24)
1418: | ((b[index + 1] & 0xFF) << 16)
1419: | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
1420: }
1421:
1422: /**
1423: * Reads a signed long value in {@link #b b}. <i>This method is intended
1424: * for {@link Attribute} sub classes, and is normally not needed by class
1425: * generators or adapters.</i>
1426: *
1427: * @param index the start index of the value to be read in {@link #b b}.
1428: * @return the read value.
1429: */
1430: public long readLong(final int index) {
1431: long l1 = readInt(index);
1432: long l0 = readInt(index + 4) & 0xFFFFFFFFL;
1433: return (l1 << 32) | l0;
1434: }
1435:
1436: /**
1437: * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method
1438: * is intended for {@link Attribute} sub classes, and is normally not needed
1439: * by class generators or adapters.</i>
1440: *
1441: * @param index the start index of an unsigned short value in {@link #b b},
1442: * whose value is the index of an UTF8 constant pool item.
1443: * @param buf buffer to be used to read the item. This buffer must be
1444: * sufficiently large. It is not automatically resized.
1445: * @return the String corresponding to the specified UTF8 item.
1446: */
1447: public String readUTF8(int index, final char[] buf) {
1448: int item = readUnsignedShort(index);
1449: String s = strings[item];
1450: if (s != null) {
1451: return s;
1452: }
1453: index = items[item];
1454: return strings[item] = readUTF(index + 2,
1455: readUnsignedShort(index), buf);
1456: }
1457:
1458: /**
1459: * Reads UTF8 string in {@link #b b}.
1460: *
1461: * @param index start offset of the UTF8 string to be read.
1462: * @param utfLen length of the UTF8 string to be read.
1463: * @param buf buffer to be used to read the string. This buffer must be
1464: * sufficiently large. It is not automatically resized.
1465: * @return the String corresponding to the specified UTF8 string.
1466: */
1467: private String readUTF(int index, int utfLen, char[] buf) {
1468: int endIndex = index + utfLen;
1469: byte[] b = this .b;
1470: int strLen = 0;
1471: int c, d, e;
1472: while (index < endIndex) {
1473: c = b[index++] & 0xFF;
1474: switch (c >> 4) {
1475: case 0:
1476: case 1:
1477: case 2:
1478: case 3:
1479: case 4:
1480: case 5:
1481: case 6:
1482: case 7:
1483: // 0xxxxxxx
1484: buf[strLen++] = (char) c;
1485: break;
1486: case 12:
1487: case 13:
1488: // 110x xxxx 10xx xxxx
1489: d = b[index++];
1490: buf[strLen++] = (char) (((c & 0x1F) << 6) | (d & 0x3F));
1491: break;
1492: default:
1493: // 1110 xxxx 10xx xxxx 10xx xxxx
1494: d = b[index++];
1495: e = b[index++];
1496: buf[strLen++] = (char) (((c & 0x0F) << 12)
1497: | ((d & 0x3F) << 6) | (e & 0x3F));
1498: break;
1499: }
1500: }
1501: return new String(buf, 0, strLen);
1502: }
1503:
1504: /**
1505: * Reads a class constant pool item in {@link #b b}. <i>This method is
1506: * intended for {@link Attribute} sub classes, and is normally not needed by
1507: * class generators or adapters.</i>
1508: *
1509: * @param index the start index of an unsigned short value in {@link #b b},
1510: * whose value is the index of a class constant pool item.
1511: * @param buf buffer to be used to read the item. This buffer must be
1512: * sufficiently large. It is not automatically resized.
1513: * @return the String corresponding to the specified class item.
1514: */
1515: public String readClass(final int index, final char[] buf) {
1516: // computes the start index of the CONSTANT_Class item in b
1517: // and reads the CONSTANT_Utf8 item designated by
1518: // the first two bytes of this CONSTANT_Class item
1519: return readUTF8(items[readUnsignedShort(index)], buf);
1520: }
1521:
1522: /**
1523: * Reads a numeric or string constant pool item in {@link #b b}. <i>This
1524: * method is intended for {@link Attribute} sub classes, and is normally not
1525: * needed by class generators or adapters.</i>
1526: *
1527: * @param item the index of a constant pool item.
1528: * @param buf buffer to be used to read the item. This buffer must be
1529: * sufficiently large. It is not automatically resized.
1530: * @return the {@link Integer}, {@link Float}, {@link Long},
1531: * {@link Double}, {@link String} or {@link Type} corresponding to
1532: * the given constant pool item.
1533: */
1534: public Object readConst(final int item, final char[] buf) {
1535: int index = items[item];
1536: switch (b[index - 1]) {
1537: case ClassWriter.INT:
1538: return new Integer(readInt(index));
1539: case ClassWriter.FLOAT:
1540: return new Float(Float.intBitsToFloat(readInt(index)));
1541: case ClassWriter.LONG:
1542: return new Long(readLong(index));
1543: case ClassWriter.DOUBLE:
1544: return new Double(Double.longBitsToDouble(readLong(index)));
1545: case ClassWriter.CLASS:
1546: String s = readUTF8(index, buf);
1547: return Type.getType(s.charAt(0) == '[' ? s : "L" + s + ";");
1548: // case ClassWriter.STR:
1549: default:
1550: return readUTF8(index, buf);
1551: }
1552: }
1553: }
|