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.drools.asm;
0030:
0031: import java.io.IOException;
0032: import java.io.InputStream;
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: this .items = new int[readUnsignedShort(off + 8)];
0105: final int ll = this .items.length;
0106: this .strings = new String[ll];
0107: int max = 0;
0108: int index = off + 10;
0109: for (int i = 1; i < ll; ++i) {
0110: this .items[i] = index + 1;
0111: final 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: this .maxStringLength = max;
0142: // the class header information starts just after the constant pool
0143: this .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: final char[] buf = new char[this .maxStringLength];
0154: final int ll = this .items.length;
0155: final Item[] items2 = new Item[ll];
0156: for (int i = 1; i < ll; i++) {
0157: int index = this .items[i];
0158: final int tag = this .b[index - 1];
0159: final 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 = this .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 = this .strings[i];
0195: if (s == null) {
0196: index = this .items[i];
0197: s = this .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: final int index2 = item.hashCode % items2.length;
0212: item.next = items2[index2];
0213: items2[index2] = item;
0214: }
0215:
0216: final int off = this .items[1] - 1;
0217: classWriter.pool.putByteArray(this .b, off, this .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: final int n = is.read(b, len, b.length - len);
0261: if (n == -1) {
0262: if (len < b.length) {
0263: final 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: final 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: final byte[] b = this .b; // the bytecode array
0317: final char[] c = new char[this .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 = this .header;
0333: access = readUnsignedShort(u);
0334: name = readClass(u + 2, c);
0335: v = this .items[readUnsignedShort(u + 4)];
0336: final String super ClassName = v == 0 ? null : readUTF8(v, c);
0337: final 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: final 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: final int item = readUnsignedShort(v + 8);
0397: if (item != 0) {
0398: enclosingName = readUTF8(this .items[item], c);
0399: enclosingDesc = readUTF8(this .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: final Object value = (fieldValueItem == 0 ? null
0516: : readConst(fieldValueItem, c));
0517: // visits the field
0518: final FieldVisitor fv = classVisitor.visitField(access,
0519: name, 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: final 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: final 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: final MethodVisitor mv = classVisitor.visitMethod(access,
0623: name, 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: final 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: final AnnotationVisitor dv = mv
0672: .visitAnnotationDefault();
0673: readAnnotationValue(dann, c, null, dv);
0674: dv.visitEnd();
0675: }
0676: for (j = 1; j >= 0; --j) {
0677: w = j == 0 ? ianns : anns;
0678: if (w != 0) {
0679: k = readUnsignedShort(w);
0680: w += 2;
0681: for (; k > 0; --k) {
0682: desc = readUTF8(w, c);
0683: w += 2;
0684: w = readAnnotationValues(w, c, mv
0685: .visitAnnotation(desc, j != 0));
0686: }
0687: }
0688: }
0689: if (mpanns != 0) {
0690: readParameterAnnotations(mpanns, c, true, mv);
0691: }
0692: if (impanns != 0) {
0693: readParameterAnnotations(impanns, c, false, mv);
0694: }
0695: while (cattrs != null) {
0696: attr = cattrs.next;
0697: cattrs.next = null;
0698: mv.visitAttribute(cattrs);
0699: cattrs = attr;
0700: }
0701: }
0702:
0703: if (mv != null && v != 0) {
0704: final int maxStack = readUnsignedShort(v);
0705: final int maxLocals = readUnsignedShort(v + 2);
0706: final int codeLength = readInt(v + 4);
0707: v += 8;
0708:
0709: final int codeStart = v;
0710: final int codeEnd = v + codeLength;
0711:
0712: mv.visitCode();
0713:
0714: // 1st phase: finds the labels
0715: int label;
0716: final Label[] labels = new Label[codeLength + 1];
0717: while (v < codeEnd) {
0718: int opcode = b[v] & 0xFF;
0719: switch (ClassWriter.TYPE[opcode]) {
0720: case ClassWriter.NOARG_INSN:
0721: case ClassWriter.IMPLVAR_INSN:
0722: v += 1;
0723: break;
0724: case ClassWriter.LABEL_INSN:
0725: label = v - codeStart + readShort(v + 1);
0726: if (labels[label] == null) {
0727: labels[label] = new Label();
0728: }
0729: v += 3;
0730: break;
0731: case ClassWriter.LABELW_INSN:
0732: label = v - codeStart + readInt(v + 1);
0733: if (labels[label] == null) {
0734: labels[label] = new Label();
0735: }
0736: v += 5;
0737: break;
0738: case ClassWriter.WIDE_INSN:
0739: opcode = b[v + 1] & 0xFF;
0740: if (opcode == Opcodes.IINC) {
0741: v += 6;
0742: } else {
0743: v += 4;
0744: }
0745: break;
0746: case ClassWriter.TABL_INSN:
0747: // skips 0 to 3 padding bytes
0748: w = v - codeStart;
0749: v = v + 4 - (w & 3);
0750: // reads instruction
0751: label = w + readInt(v);
0752: v += 4;
0753: if (labels[label] == null) {
0754: labels[label] = new Label();
0755: }
0756: j = readInt(v);
0757: v += 4;
0758: j = readInt(v) - j + 1;
0759: v += 4;
0760: for (; j > 0; --j) {
0761: label = w + readInt(v);
0762: v += 4;
0763: if (labels[label] == null) {
0764: labels[label] = new Label();
0765: }
0766: }
0767: break;
0768: case ClassWriter.LOOK_INSN:
0769: // skips 0 to 3 padding bytes
0770: w = v - codeStart;
0771: v = v + 4 - (w & 3);
0772: // reads instruction
0773: label = w + readInt(v);
0774: v += 4;
0775: if (labels[label] == null) {
0776: labels[label] = new Label();
0777: }
0778: j = readInt(v);
0779: v += 4;
0780: for (; j > 0; --j) {
0781: v += 4; // skips key
0782: label = w + readInt(v);
0783: v += 4;
0784: if (labels[label] == null) {
0785: labels[label] = new Label();
0786: }
0787: }
0788: break;
0789: case ClassWriter.VAR_INSN:
0790: case ClassWriter.SBYTE_INSN:
0791: case ClassWriter.LDC_INSN:
0792: v += 2;
0793: break;
0794: case ClassWriter.SHORT_INSN:
0795: case ClassWriter.LDCW_INSN:
0796: case ClassWriter.FIELDORMETH_INSN:
0797: case ClassWriter.TYPE_INSN:
0798: case ClassWriter.IINC_INSN:
0799: v += 3;
0800: break;
0801: case ClassWriter.ITFMETH_INSN:
0802: v += 5;
0803: break;
0804: // case MANA_INSN:
0805: default:
0806: v += 4;
0807: break;
0808: }
0809: }
0810: // parses the try catch entries
0811: j = readUnsignedShort(v);
0812: v += 2;
0813: for (; j > 0; --j) {
0814: label = readUnsignedShort(v);
0815: Label start = labels[label];
0816: if (start == null) {
0817: labels[label] = start = new Label();
0818: }
0819: label = readUnsignedShort(v + 2);
0820: Label end = labels[label];
0821: if (end == null) {
0822: labels[label] = end = new Label();
0823: }
0824: label = readUnsignedShort(v + 4);
0825: Label handler = labels[label];
0826: if (handler == null) {
0827: labels[label] = handler = new Label();
0828: }
0829:
0830: final int type = readUnsignedShort(v + 6);
0831: if (type == 0) {
0832: mv
0833: .visitTryCatchBlock(start, end,
0834: handler, null);
0835: } else {
0836: mv.visitTryCatchBlock(start, end, handler,
0837: readUTF8(this .items[type], c));
0838: }
0839: v += 8;
0840: }
0841: // parses the local variable, line number tables, and code
0842: // attributes
0843: int varTable = 0;
0844: int varTypeTable = 0;
0845: cattrs = null;
0846: j = readUnsignedShort(v);
0847: v += 2;
0848: for (; j > 0; --j) {
0849: attrName = readUTF8(v, c);
0850: if (attrName.equals("LocalVariableTable")) {
0851: if (!skipDebug) {
0852: varTable = v + 6;
0853: k = readUnsignedShort(v + 6);
0854: w = v + 8;
0855: for (; k > 0; --k) {
0856: label = readUnsignedShort(w);
0857: if (labels[label] == null) {
0858: labels[label] = new Label();
0859: }
0860: label += readUnsignedShort(w + 2);
0861: if (labels[label] == null) {
0862: labels[label] = new Label();
0863: }
0864: w += 10;
0865: }
0866: }
0867: } else if (attrName
0868: .equals("LocalVariableTypeTable")) {
0869: varTypeTable = v + 6;
0870: } else if (attrName.equals("LineNumberTable")) {
0871: if (!skipDebug) {
0872: k = readUnsignedShort(v + 6);
0873: w = v + 8;
0874: for (; k > 0; --k) {
0875: label = readUnsignedShort(w);
0876: if (labels[label] == null) {
0877: labels[label] = new Label();
0878: }
0879: labels[label].line = readUnsignedShort(w + 2);
0880: w += 4;
0881: }
0882: }
0883: } else {
0884: for (k = 0; k < attrs.length; ++k) {
0885: if (attrs[k].type.equals(attrName)) {
0886: attr = attrs[k].read(this , v + 6,
0887: readInt(v + 2), c,
0888: codeStart - 8, labels);
0889: if (attr != null) {
0890: attr.next = cattrs;
0891: cattrs = attr;
0892: }
0893: }
0894: }
0895: }
0896: v += 6 + readInt(v + 2);
0897: }
0898:
0899: // 2nd phase: visits each instruction
0900: v = codeStart;
0901: Label l;
0902: while (v < codeEnd) {
0903: w = v - codeStart;
0904: l = labels[w];
0905: if (l != null) {
0906: mv.visitLabel(l);
0907: if (!skipDebug && l.line > 0) {
0908: mv.visitLineNumber(l.line, l);
0909: }
0910: }
0911: int opcode = b[v] & 0xFF;
0912: switch (ClassWriter.TYPE[opcode]) {
0913: case ClassWriter.NOARG_INSN:
0914: mv.visitInsn(opcode);
0915: v += 1;
0916: break;
0917: case ClassWriter.IMPLVAR_INSN:
0918: if (opcode > Opcodes.ISTORE) {
0919: opcode -= 59; // ISTORE_0
0920: mv.visitVarInsn(Opcodes.ISTORE
0921: + (opcode >> 2), opcode & 0x3);
0922: } else {
0923: opcode -= 26; // ILOAD_0
0924: mv.visitVarInsn(Opcodes.ILOAD
0925: + (opcode >> 2), opcode & 0x3);
0926: }
0927: v += 1;
0928: break;
0929: case ClassWriter.LABEL_INSN:
0930: mv.visitJumpInsn(opcode, labels[w
0931: + readShort(v + 1)]);
0932: v += 3;
0933: break;
0934: case ClassWriter.LABELW_INSN:
0935: mv.visitJumpInsn(opcode - 33, labels[w
0936: + readInt(v + 1)]);
0937: v += 5;
0938: break;
0939: case ClassWriter.WIDE_INSN:
0940: opcode = b[v + 1] & 0xFF;
0941: if (opcode == Opcodes.IINC) {
0942: mv.visitIincInsn(readUnsignedShort(v + 2),
0943: readShort(v + 4));
0944: v += 6;
0945: } else {
0946: mv.visitVarInsn(opcode,
0947: readUnsignedShort(v + 2));
0948: v += 4;
0949: }
0950: break;
0951: case ClassWriter.TABL_INSN:
0952: // skips 0 to 3 padding bytes
0953: v = v + 4 - (w & 3);
0954: // reads instruction
0955: label = w + readInt(v);
0956: v += 4;
0957: final int min = readInt(v);
0958: v += 4;
0959: final int max = readInt(v);
0960: v += 4;
0961: final Label[] table = new Label[max - min + 1];
0962: for (j = 0; j < table.length; ++j) {
0963: table[j] = labels[w + readInt(v)];
0964: v += 4;
0965: }
0966: mv.visitTableSwitchInsn(min, max,
0967: labels[label], table);
0968: break;
0969: case ClassWriter.LOOK_INSN:
0970: // skips 0 to 3 padding bytes
0971: v = v + 4 - (w & 3);
0972: // reads instruction
0973: label = w + readInt(v);
0974: v += 4;
0975: j = readInt(v);
0976: v += 4;
0977: final int[] keys = new int[j];
0978: final Label[] values = new Label[j];
0979: for (j = 0; j < keys.length; ++j) {
0980: keys[j] = readInt(v);
0981: v += 4;
0982: values[j] = labels[w + readInt(v)];
0983: v += 4;
0984: }
0985: mv.visitLookupSwitchInsn(labels[label], keys,
0986: values);
0987: break;
0988: case ClassWriter.VAR_INSN:
0989: mv.visitVarInsn(opcode, b[v + 1] & 0xFF);
0990: v += 2;
0991: break;
0992: case ClassWriter.SBYTE_INSN:
0993: mv.visitIntInsn(opcode, b[v + 1]);
0994: v += 2;
0995: break;
0996: case ClassWriter.SHORT_INSN:
0997: mv.visitIntInsn(opcode, readShort(v + 1));
0998: v += 3;
0999: break;
1000: case ClassWriter.LDC_INSN:
1001: mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c));
1002: v += 2;
1003: break;
1004: case ClassWriter.LDCW_INSN:
1005: mv.visitLdcInsn(readConst(
1006: readUnsignedShort(v + 1), c));
1007: v += 3;
1008: break;
1009: case ClassWriter.FIELDORMETH_INSN:
1010: case ClassWriter.ITFMETH_INSN:
1011: int cpIndex = this .items[readUnsignedShort(v + 1)];
1012: final String iowner = readClass(cpIndex, c);
1013: cpIndex = this .items[readUnsignedShort(cpIndex + 2)];
1014: final String iname = readUTF8(cpIndex, c);
1015: final String idesc = readUTF8(cpIndex + 2, c);
1016: if (opcode < Opcodes.INVOKEVIRTUAL) {
1017: mv.visitFieldInsn(opcode, iowner, iname,
1018: idesc);
1019: } else {
1020: mv.visitMethodInsn(opcode, iowner, iname,
1021: idesc);
1022: }
1023: if (opcode == Opcodes.INVOKEINTERFACE) {
1024: v += 5;
1025: } else {
1026: v += 3;
1027: }
1028: break;
1029: case ClassWriter.TYPE_INSN:
1030: mv.visitTypeInsn(opcode, readClass(v + 1, c));
1031: v += 3;
1032: break;
1033: case ClassWriter.IINC_INSN:
1034: mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]);
1035: v += 3;
1036: break;
1037: // case MANA_INSN:
1038: default:
1039: mv.visitMultiANewArrayInsn(readClass(v + 1, c),
1040: b[v + 3] & 0xFF);
1041: v += 4;
1042: break;
1043: }
1044: }
1045: l = labels[codeEnd - codeStart];
1046: if (l != null) {
1047: mv.visitLabel(l);
1048: }
1049:
1050: // visits the local variable tables
1051: if (!skipDebug && varTable != 0) {
1052: int[] typeTable = null;
1053: if (varTypeTable != 0) {
1054: w = varTypeTable;
1055: k = readUnsignedShort(w) * 3;
1056: w += 2;
1057: typeTable = new int[k];
1058: while (k > 0) {
1059: typeTable[--k] = w + 6; // signature
1060: typeTable[--k] = readUnsignedShort(w + 8); // index
1061: typeTable[--k] = readUnsignedShort(w); // start
1062: w += 10;
1063: }
1064: }
1065: w = varTable;
1066: k = readUnsignedShort(w);
1067: w += 2;
1068: for (; k > 0; --k) {
1069: final int start = readUnsignedShort(w);
1070: final int length = readUnsignedShort(w + 2);
1071: final int index = readUnsignedShort(w + 8);
1072: String vsignature = null;
1073: if (typeTable != null) {
1074: for (int a = 0; a < typeTable.length; a += 3) {
1075: if (typeTable[a] == start
1076: && typeTable[a + 1] == index) {
1077: vsignature = readUTF8(
1078: typeTable[a + 2], c);
1079: break;
1080: }
1081: }
1082: }
1083: mv.visitLocalVariable(readUTF8(w + 4, c),
1084: readUTF8(w + 6, c), vsignature,
1085: labels[start], labels[start + length],
1086: index);
1087: w += 10;
1088: }
1089: }
1090: // visits the other attributes
1091: while (cattrs != null) {
1092: attr = cattrs.next;
1093: cattrs.next = null;
1094: mv.visitAttribute(cattrs);
1095: cattrs = attr;
1096: }
1097: // visits the min stack and min locals values
1098: mv.visitMaxs(maxStack, maxLocals);
1099: }
1100:
1101: if (mv != null) {
1102: mv.visitEnd();
1103: }
1104: }
1105:
1106: // visits the end of the class
1107: classVisitor.visitEnd();
1108: }
1109:
1110: /**
1111: * Reads parameter annotations and makes the given visitor visit them.
1112: *
1113: * @param v start offset in {@link #b b} of the annotations to be read.
1114: * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1115: * {@link #readClass(int,char[]) readClass} or
1116: * {@link #readConst readConst}.
1117: * @param visible <tt>true</tt> if the annotations to be read are visible
1118: * at runtime.
1119: * @param mv the visitor that must visit the annotations.
1120: */
1121: private void readParameterAnnotations(int v, final char[] buf,
1122: final boolean visible, final MethodVisitor mv) {
1123: final int n = this .b[v++] & 0xFF;
1124: for (int i = 0; i < n; ++i) {
1125: int j = readUnsignedShort(v);
1126: v += 2;
1127: for (; j > 0; --j) {
1128: final String desc = readUTF8(v, buf);
1129: v += 2;
1130: final AnnotationVisitor av = mv
1131: .visitParameterAnnotation(i, desc, visible);
1132: v = readAnnotationValues(v, buf, av);
1133: }
1134: }
1135: }
1136:
1137: /**
1138: * Reads the values of an annotation and makes the given visitor visit them.
1139: *
1140: * @param v the start offset in {@link #b b} of the values to be read
1141: * (including the unsigned short that gives the number of values).
1142: * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1143: * {@link #readClass(int,char[]) readClass} or
1144: * {@link #readConst readConst}.
1145: * @param av the visitor that must visit the values.
1146: * @return the end offset of the annotations values.
1147: */
1148: private int readAnnotationValues(int v, final char[] buf,
1149: final AnnotationVisitor av) {
1150: int i = readUnsignedShort(v);
1151: v += 2;
1152: for (; i > 0; --i) {
1153: final String name = readUTF8(v, buf);
1154: v += 2;
1155: v = readAnnotationValue(v, buf, name, av);
1156: }
1157: av.visitEnd();
1158: return v;
1159: }
1160:
1161: /**
1162: * Reads a value of an annotation and makes the given visitor visit it.
1163: *
1164: * @param v the start offset in {@link #b b} of the value to be read (<i>not
1165: * including the value name constant pool index</i>).
1166: * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1167: * {@link #readClass(int,char[]) readClass} or
1168: * {@link #readConst readConst}.
1169: * @param name the name of the value to be read.
1170: * @param av the visitor that must visit the value.
1171: * @return the end offset of the annotation value.
1172: */
1173: private int readAnnotationValue(int v, final char[] buf,
1174: final String name, final AnnotationVisitor av) {
1175: int i;
1176: switch (readByte(v++)) {
1177: case 'I': // pointer to CONSTANT_Integer
1178: case 'J': // pointer to CONSTANT_Long
1179: case 'F': // pointer to CONSTANT_Float
1180: case 'D': // pointer to CONSTANT_Double
1181: av.visit(name, readConst(readUnsignedShort(v), buf));
1182: v += 2;
1183: break;
1184: case 'B': // pointer to CONSTANT_Byte
1185: av.visit(name, new Byte(
1186: (byte) readInt(this .items[readUnsignedShort(v)])));
1187: v += 2;
1188: break;
1189: case 'Z': // pointer to CONSTANT_Boolean
1190: final boolean b = readInt(this .items[readUnsignedShort(v)]) == 0;
1191: av.visit(name, b ? Boolean.FALSE : Boolean.TRUE);
1192: v += 2;
1193: break;
1194: case 'S': // pointer to CONSTANT_Short
1195: av.visit(name, new Short(
1196: (short) readInt(this .items[readUnsignedShort(v)])));
1197: v += 2;
1198: break;
1199: case 'C': // pointer to CONSTANT_Char
1200: av.visit(name, new Character(
1201: (char) readInt(this .items[readUnsignedShort(v)])));
1202: v += 2;
1203: break;
1204: case 's': // pointer to CONSTANT_Utf8
1205: av.visit(name, readUTF8(v, buf));
1206: v += 2;
1207: break;
1208: case 'e': // enum_const_value
1209: av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf));
1210: v += 4;
1211: break;
1212: case 'c': // class_info
1213: av.visit(name, Type.getType(readUTF8(v, buf)));
1214: v += 2;
1215: break;
1216: case '@': // annotation_value
1217: final String desc = readUTF8(v, buf);
1218: v += 2;
1219: v = readAnnotationValues(v, buf, av.visitAnnotation(name,
1220: desc));
1221: break;
1222: case '[': // array_value
1223: final int size = readUnsignedShort(v);
1224: v += 2;
1225: if (size == 0) {
1226: av.visitArray(name).visitEnd();
1227: return v;
1228: }
1229: switch (readByte(v++)) {
1230: case 'B':
1231: final byte[] bv = new byte[size];
1232: for (i = 0; i < size; i++) {
1233: bv[i] = (byte) readInt(this .items[readUnsignedShort(v)]);
1234: v += 3;
1235: }
1236: av.visit(name, bv);
1237: --v;
1238: break;
1239: case 'Z':
1240: final boolean[] zv = new boolean[size];
1241: for (i = 0; i < size; i++) {
1242: zv[i] = readInt(this .items[readUnsignedShort(v)]) != 0;
1243: v += 3;
1244: }
1245: av.visit(name, zv);
1246: --v;
1247: break;
1248: case 'S':
1249: final short[] sv = new short[size];
1250: for (i = 0; i < size; i++) {
1251: sv[i] = (short) readInt(this .items[readUnsignedShort(v)]);
1252: v += 3;
1253: }
1254: av.visit(name, sv);
1255: --v;
1256: break;
1257: case 'C':
1258: final char[] cv = new char[size];
1259: for (i = 0; i < size; i++) {
1260: cv[i] = (char) readInt(this .items[readUnsignedShort(v)]);
1261: v += 3;
1262: }
1263: av.visit(name, cv);
1264: --v;
1265: break;
1266: case 'I':
1267: final int[] iv = new int[size];
1268: for (i = 0; i < size; i++) {
1269: iv[i] = readInt(this .items[readUnsignedShort(v)]);
1270: v += 3;
1271: }
1272: av.visit(name, iv);
1273: --v;
1274: break;
1275: case 'J':
1276: final long[] lv = new long[size];
1277: for (i = 0; i < size; i++) {
1278: lv[i] = readLong(this .items[readUnsignedShort(v)]);
1279: v += 3;
1280: }
1281: av.visit(name, lv);
1282: --v;
1283: break;
1284: case 'F':
1285: final float[] fv = new float[size];
1286: for (i = 0; i < size; i++) {
1287: fv[i] = Float
1288: .intBitsToFloat(readInt(this .items[readUnsignedShort(v)]));
1289: v += 3;
1290: }
1291: av.visit(name, fv);
1292: --v;
1293: break;
1294: case 'D':
1295: final double[] dv = new double[size];
1296: for (i = 0; i < size; i++) {
1297: dv[i] = Double
1298: .longBitsToDouble(readLong(this .items[readUnsignedShort(v)]));
1299: v += 3;
1300: }
1301: av.visit(name, dv);
1302: --v;
1303: break;
1304: default:
1305: v--;
1306: final AnnotationVisitor aav = av.visitArray(name);
1307: for (i = size; i > 0; --i) {
1308: v = readAnnotationValue(v, buf, null, aav);
1309: }
1310: aav.visitEnd();
1311: }
1312: }
1313: return v;
1314: }
1315:
1316: /**
1317: * Reads an attribute in {@link #b b}.
1318: *
1319: * @param attrs prototypes of the attributes that must be parsed during the
1320: * visit of the class. Any attribute whose type is not equal to the
1321: * type of one the prototypes is ignored (i.e. an empty
1322: * {@link Attribute} instance is returned).
1323: * @param type the type of the attribute.
1324: * @param off index of the first byte of the attribute's content in
1325: * {@link #b b}. The 6 attribute header bytes, containing the type
1326: * and the length of the attribute, are not taken into account here
1327: * (they have already been read).
1328: * @param len the length of the attribute's content.
1329: * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1330: * {@link #readClass(int,char[]) readClass} or
1331: * {@link #readConst readConst}.
1332: * @param codeOff index of the first byte of code's attribute content in
1333: * {@link #b b}, or -1 if the attribute to be read is not a code
1334: * attribute. The 6 attribute header bytes, containing the type and
1335: * the length of the attribute, are not taken into account here.
1336: * @param labels the labels of the method's code, or <tt>null</tt> if the
1337: * attribute to be read is not a code attribute.
1338: * @return the attribute that has been read, or <tt>null</tt> to skip this
1339: * attribute.
1340: */
1341: private Attribute readAttribute(final Attribute[] attrs,
1342: final String type, final int off, final int len,
1343: final char[] buf, final int codeOff, final Label[] labels) {
1344: for (int i = 0; i < attrs.length; ++i) {
1345: if (attrs[i].type.equals(type)) {
1346: return attrs[i].read(this , off, len, buf, codeOff,
1347: labels);
1348: }
1349: }
1350: return new Attribute(type).read(this , off, len, null, -1, null);
1351: }
1352:
1353: // ------------------------------------------------------------------------
1354: // Utility methods: low level parsing
1355: // ------------------------------------------------------------------------
1356:
1357: /**
1358: * Returns the start index of the constant pool item in {@link #b b}, plus
1359: * one. <i>This method is intended for {@link Attribute} sub classes, and is
1360: * normally not needed by class generators or adapters.</i>
1361: *
1362: * @param item the index a constant pool item.
1363: * @return the start index of the constant pool item in {@link #b b}, plus
1364: * one.
1365: */
1366: public int getItem(final int item) {
1367: return this .items[item];
1368: }
1369:
1370: /**
1371: * Reads a byte value in {@link #b b}. <i>This method is intended for
1372: * {@link Attribute} sub classes, and is normally not needed by class
1373: * generators or adapters.</i>
1374: *
1375: * @param index the start index of the value to be read in {@link #b b}.
1376: * @return the read value.
1377: */
1378: public int readByte(final int index) {
1379: return this .b[index] & 0xFF;
1380: }
1381:
1382: /**
1383: * Reads an unsigned short value in {@link #b b}. <i>This method is
1384: * intended for {@link Attribute} sub classes, and is normally not needed by
1385: * class generators or adapters.</i>
1386: *
1387: * @param index the start index of the value to be read in {@link #b b}.
1388: * @return the read value.
1389: */
1390: public int readUnsignedShort(final int index) {
1391: final byte[] b = this .b;
1392: return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
1393: }
1394:
1395: /**
1396: * Reads a signed short value in {@link #b b}. <i>This method is intended
1397: * for {@link Attribute} sub classes, and is normally not needed by class
1398: * generators or adapters.</i>
1399: *
1400: * @param index the start index of the value to be read in {@link #b b}.
1401: * @return the read value.
1402: */
1403: public short readShort(final int index) {
1404: final byte[] b = this .b;
1405: return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
1406: }
1407:
1408: /**
1409: * Reads a signed int value in {@link #b b}. <i>This method is intended for
1410: * {@link Attribute} sub classes, and is normally not needed by class
1411: * generators or adapters.</i>
1412: *
1413: * @param index the start index of the value to be read in {@link #b b}.
1414: * @return the read value.
1415: */
1416: public int readInt(final int index) {
1417: final byte[] b = this .b;
1418: return ((b[index] & 0xFF) << 24)
1419: | ((b[index + 1] & 0xFF) << 16)
1420: | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
1421: }
1422:
1423: /**
1424: * Reads a signed long value in {@link #b b}. <i>This method is intended
1425: * for {@link Attribute} sub classes, and is normally not needed by class
1426: * generators or adapters.</i>
1427: *
1428: * @param index the start index of the value to be read in {@link #b b}.
1429: * @return the read value.
1430: */
1431: public long readLong(final int index) {
1432: final long l1 = readInt(index);
1433: final long l0 = readInt(index + 4) & 0xFFFFFFFFL;
1434: return (l1 << 32) | l0;
1435: }
1436:
1437: /**
1438: * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method
1439: * is intended for {@link Attribute} sub classes, and is normally not needed
1440: * by class generators or adapters.</i>
1441: *
1442: * @param index the start index of an unsigned short value in {@link #b b},
1443: * whose value is the index of an UTF8 constant pool item.
1444: * @param buf buffer to be used to read the item. This buffer must be
1445: * sufficiently large. It is not automatically resized.
1446: * @return the String corresponding to the specified UTF8 item.
1447: */
1448: public String readUTF8(int index, final char[] buf) {
1449: final int item = readUnsignedShort(index);
1450: final String s = this .strings[item];
1451: if (s != null) {
1452: return s;
1453: }
1454: index = this .items[item];
1455: return this .strings[item] = readUTF(index + 2,
1456: readUnsignedShort(index), buf);
1457: }
1458:
1459: /**
1460: * Reads UTF8 string in {@link #b b}.
1461: *
1462: * @param index start offset of the UTF8 string to be read.
1463: * @param utfLen length of the UTF8 string to be read.
1464: * @param buf buffer to be used to read the string. This buffer must be
1465: * sufficiently large. It is not automatically resized.
1466: * @return the String corresponding to the specified UTF8 string.
1467: */
1468: private String readUTF(int index, final int utfLen, final char[] buf) {
1469: final int endIndex = index + utfLen;
1470: final byte[] b = this .b;
1471: int strLen = 0;
1472: int c, d, e;
1473: while (index < endIndex) {
1474: c = b[index++] & 0xFF;
1475: switch (c >> 4) {
1476: case 0:
1477: case 1:
1478: case 2:
1479: case 3:
1480: case 4:
1481: case 5:
1482: case 6:
1483: case 7:
1484: // 0xxxxxxx
1485: buf[strLen++] = (char) c;
1486: break;
1487: case 12:
1488: case 13:
1489: // 110x xxxx 10xx xxxx
1490: d = b[index++];
1491: buf[strLen++] = (char) (((c & 0x1F) << 6) | (d & 0x3F));
1492: break;
1493: default:
1494: // 1110 xxxx 10xx xxxx 10xx xxxx
1495: d = b[index++];
1496: e = b[index++];
1497: buf[strLen++] = (char) (((c & 0x0F) << 12)
1498: | ((d & 0x3F) << 6) | (e & 0x3F));
1499: break;
1500: }
1501: }
1502: return new String(buf, 0, strLen);
1503: }
1504:
1505: /**
1506: * Reads a class constant pool item in {@link #b b}. <i>This method is
1507: * intended for {@link Attribute} sub classes, and is normally not needed by
1508: * class generators or adapters.</i>
1509: *
1510: * @param index the start index of an unsigned short value in {@link #b b},
1511: * whose value is the index of a class constant pool item.
1512: * @param buf buffer to be used to read the item. This buffer must be
1513: * sufficiently large. It is not automatically resized.
1514: * @return the String corresponding to the specified class item.
1515: */
1516: public String readClass(final int index, final char[] buf) {
1517: // computes the start index of the CONSTANT_Class item in b
1518: // and reads the CONSTANT_Utf8 item designated by
1519: // the first two bytes of this CONSTANT_Class item
1520: return readUTF8(this .items[readUnsignedShort(index)], buf);
1521: }
1522:
1523: /**
1524: * Reads a numeric or string constant pool item in {@link #b b}. <i>This
1525: * method is intended for {@link Attribute} sub classes, and is normally not
1526: * needed by class generators or adapters.</i>
1527: *
1528: * @param item the index of a constant pool item.
1529: * @param buf buffer to be used to read the item. This buffer must be
1530: * sufficiently large. It is not automatically resized.
1531: * @return the {@link Integer}, {@link Float}, {@link Long},
1532: * {@link Double}, {@link String} or {@link Type} corresponding to
1533: * the given constant pool item.
1534: */
1535: public Object readConst(final int item, final char[] buf) {
1536: final int index = this .items[item];
1537: switch (this .b[index - 1]) {
1538: case ClassWriter.INT:
1539: return new Integer(readInt(index));
1540: case ClassWriter.FLOAT:
1541: return new Float(Float.intBitsToFloat(readInt(index)));
1542: case ClassWriter.LONG:
1543: return new Long(readLong(index));
1544: case ClassWriter.DOUBLE:
1545: return new Double(Double.longBitsToDouble(readLong(index)));
1546: case ClassWriter.CLASS:
1547: final String s = readUTF8(index, buf);
1548: return Type.getType(s.charAt(0) == '[' ? s : "L" + s + ";");
1549: // case ClassWriter.STR:
1550: default:
1551: return readUTF8(index, buf);
1552: }
1553: }
1554: }
|