Source Code Cross Referenced for ClassReader.java in  » Development » Retrotranslator » net » sf » retrotranslator » runtime » asm » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Development » Retrotranslator » net.sf.retrotranslator.runtime.asm 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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 net.sf.retrotranslator.runtime.asm;
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:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.