• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/db-4.7.25.NC/java/src/com/sleepycat/asm/
1/***
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2005 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 *    contributors may be used to endorse or promote products derived from
16 *    this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30package com.sleepycat.asm;
31
32import java.io.InputStream;
33import java.io.IOException;
34
35/**
36 * A Java class parser to make a {@link ClassVisitor} visit an existing class.
37 * This class parses a byte array conforming to the Java class file format and
38 * calls the appropriate visit methods of a given class visitor for each field,
39 * method and bytecode instruction encountered.
40 *
41 * @author Eric Bruneton
42 * @author Eugene Kuleshov
43 */
44public class ClassReader {
45
46    /**
47     * The class to be parsed. <i>The content of this array must not be
48     * modified. This field is intended for {@link Attribute} sub classes, and
49     * is normally not needed by class generators or adapters.</i>
50     */
51    public final byte[] b;
52
53    /**
54     * The start index of each constant pool item in {@link #b b}, plus one.
55     * The one byte offset skips the constant pool item tag that indicates its
56     * type.
57     */
58    private int[] items;
59
60    /**
61     * The String objects corresponding to the CONSTANT_Utf8 items. This cache
62     * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item,
63     * which GREATLY improves performances (by a factor 2 to 3). This caching
64     * strategy could be extended to all constant pool items, but its benefit
65     * would not be so great for these items (because they are much less
66     * expensive to parse than CONSTANT_Utf8 items).
67     */
68    private String[] strings;
69
70    /**
71     * Maximum length of the strings contained in the constant pool of the
72     * class.
73     */
74    private int maxStringLength;
75
76    /**
77     * Start index of the class header information (access, name...) in
78     * {@link #b b}.
79     */
80    public final int header;
81
82    // ------------------------------------------------------------------------
83    // Constructors
84    // ------------------------------------------------------------------------
85
86    /**
87     * Constructs a new {@link ClassReader} object.
88     *
89     * @param b the bytecode of the class to be read.
90     */
91    public ClassReader(final byte[] b) {
92        this(b, 0, b.length);
93    }
94
95    /**
96     * Constructs a new {@link ClassReader} object.
97     *
98     * @param b the bytecode of the class to be read.
99     * @param off the start offset of the class data.
100     * @param len the length of the class data.
101     */
102    public ClassReader(final byte[] b, final int off, final int len) {
103        this.b = b;
104        // parses the constant pool
105        items = new int[readUnsignedShort(off + 8)];
106        int ll = items.length;
107        strings = new String[ll];
108        int max = 0;
109        int index = off + 10;
110        for (int i = 1; i < ll; ++i) {
111            items[i] = index + 1;
112            int tag = b[index];
113            int size;
114            switch (tag) {
115                case ClassWriter.FIELD:
116                case ClassWriter.METH:
117                case ClassWriter.IMETH:
118                case ClassWriter.INT:
119                case ClassWriter.FLOAT:
120                case ClassWriter.NAME_TYPE:
121                    size = 5;
122                    break;
123                case ClassWriter.LONG:
124                case ClassWriter.DOUBLE:
125                    size = 9;
126                    ++i;
127                    break;
128                case ClassWriter.UTF8:
129                    size = 3 + readUnsignedShort(index + 1);
130                    if (size > max) {
131                        max = size;
132                    }
133                    break;
134                // case ClassWriter.CLASS:
135                // case ClassWriter.STR:
136                default:
137                    size = 3;
138                    break;
139            }
140            index += size;
141        }
142        maxStringLength = max;
143        // the class header information starts just after the constant pool
144        header = index;
145    }
146
147    /**
148     * Copies the constant pool data into the given {@link ClassWriter}. Should
149     * be called before the {@link #accept(ClassVisitor,boolean)} method.
150     *
151     * @param classWriter the {@link ClassWriter} to copy constant pool into.
152     */
153    void copyPool(final ClassWriter classWriter) {
154        char[] buf = new char[maxStringLength];
155        int ll = items.length;
156        Item[] items2 = new Item[ll];
157        for (int i = 1; i < ll; i++) {
158            int index = items[i];
159            int tag = b[index - 1];
160            Item item = new Item(i);
161            int nameType;
162            switch (tag) {
163                case ClassWriter.FIELD:
164                case ClassWriter.METH:
165                case ClassWriter.IMETH:
166                    nameType = items[readUnsignedShort(index + 2)];
167                    item.set(tag,
168                            readClass(index, buf),
169                            readUTF8(nameType, buf),
170                            readUTF8(nameType + 2, buf));
171                    break;
172
173                case ClassWriter.INT:
174                    item.set(readInt(index));
175                    break;
176
177                case ClassWriter.FLOAT:
178                    item.set(Float.intBitsToFloat(readInt(index)));
179                    break;
180
181                case ClassWriter.NAME_TYPE:
182                    item.set(tag,
183                            readUTF8(index, buf),
184                            readUTF8(index + 2, buf),
185                            null);
186                    break;
187
188                case ClassWriter.LONG:
189                    item.set(readLong(index));
190                    ++i;
191                    break;
192
193                case ClassWriter.DOUBLE:
194                    item.set(Double.longBitsToDouble(readLong(index)));
195                    ++i;
196                    break;
197
198                case ClassWriter.UTF8: {
199                    String s = strings[i];
200                    if (s == null) {
201                        index = items[i];
202                        s = strings[i] = readUTF(index + 2,
203                                readUnsignedShort(index),
204                                buf);
205                    }
206                    item.set(tag, s, null, null);
207                }
208                    break;
209
210                // case ClassWriter.STR:
211                // case ClassWriter.CLASS:
212                default:
213                    item.set(tag, readUTF8(index, buf), null, null);
214                    break;
215            }
216
217            int index2 = item.hashCode % items2.length;
218            item.next = items2[index2];
219            items2[index2] = item;
220        }
221
222        int off = items[1] - 1;
223        classWriter.pool.putByteArray(b, off, header - off);
224        classWriter.items = items2;
225        classWriter.threshold = (int) (0.75d * ll);
226        classWriter.index = ll;
227    }
228
229    /**
230     * Constructs a new {@link ClassReader} object.
231     *
232     * @param is an input stream from which to read the class.
233     * @throws IOException if a problem occurs during reading.
234     */
235    public ClassReader(final InputStream is) throws IOException {
236        this(readClass(is));
237    }
238
239    /**
240     * Constructs a new {@link ClassReader} object.
241     *
242     * @param name the fully qualified name of the class to be read.
243     * @throws IOException if an exception occurs during reading.
244     */
245    public ClassReader(final String name) throws IOException {
246        this(ClassLoader.getSystemResourceAsStream(name.replace('.', '/')
247                + ".class"));
248    }
249
250    /**
251     * Reads the bytecode of a class.
252     *
253     * @param is an input stream from which to read the class.
254     * @return the bytecode read from the given input stream.
255     * @throws IOException if a problem occurs during reading.
256     */
257    private static byte[] readClass(final InputStream is) throws IOException {
258        if (is == null) {
259            throw new IOException("Class not found");
260        }
261        byte[] b = new byte[is.available()];
262        int len = 0;
263        while (true) {
264            int n = is.read(b, len, b.length - len);
265            if (n == -1) {
266                if (len < b.length) {
267                    byte[] c = new byte[len];
268                    System.arraycopy(b, 0, c, 0, len);
269                    b = c;
270                }
271                return b;
272            }
273            len += n;
274            if (len == b.length) {
275                byte[] c = new byte[b.length + 1000];
276                System.arraycopy(b, 0, c, 0, len);
277                b = c;
278            }
279        }
280    }
281
282    // ------------------------------------------------------------------------
283    // Public methods
284    // ------------------------------------------------------------------------
285
286    /**
287     * Makes the given visitor visit the Java class of this {@link ClassReader}.
288     * This class is the one specified in the constructor (see
289     * {@link #ClassReader(byte[]) ClassReader}).
290     *
291     * @param classVisitor the visitor that must visit this class.
292     * @param skipDebug <tt>true</tt> if the debug information of the class
293     *        must not be visited. In this case the
294     *        {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
295     *        {@link MethodVisitor#visitLineNumber visitLineNumber} methods will
296     *        not be called.
297     */
298    public void accept(final ClassVisitor classVisitor, final boolean skipDebug)
299    {
300        accept(classVisitor, new Attribute[0], skipDebug);
301    }
302
303    /**
304     * Makes the given visitor visit the Java class of this {@link ClassReader}.
305     * This class is the one specified in the constructor (see
306     * {@link #ClassReader(byte[]) ClassReader}).
307     *
308     * @param classVisitor the visitor that must visit this class.
309     * @param attrs prototypes of the attributes that must be parsed during the
310     *        visit of the class. Any attribute whose type is not equal to the
311     *        type of one the prototypes will be ignored.
312     * @param skipDebug <tt>true</tt> if the debug information of the class
313     *        must not be visited. In this case the
314     *        {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
315     *        {@link MethodVisitor#visitLineNumber visitLineNumber} methods will
316     *        not be called.
317     */
318    public void accept(
319        final ClassVisitor classVisitor,
320        final Attribute[] attrs,
321        final boolean skipDebug)
322    {
323        byte[] b = this.b; // the bytecode array
324        char[] c = new char[maxStringLength]; // buffer used to read strings
325        int i, j, k; // loop variables
326        int u, v, w; // indexes in b
327        Attribute attr;
328
329        int access;
330        String name;
331        String desc;
332        String attrName;
333        String signature;
334        int anns = 0;
335        int ianns = 0;
336        Attribute cattrs = null;
337
338        // visits the header
339        u = header;
340        access = readUnsignedShort(u);
341        name = readClass(u + 2, c);
342        v = items[readUnsignedShort(u + 4)];
343        String superClassName = v == 0 ? null : readUTF8(v, c);
344        String[] implementedItfs = new String[readUnsignedShort(u + 6)];
345        w = 0;
346        u += 8;
347        for (i = 0; i < implementedItfs.length; ++i) {
348            implementedItfs[i] = readClass(u, c);
349            u += 2;
350        }
351
352        // skips fields and methods
353        v = u;
354        i = readUnsignedShort(v);
355        v += 2;
356        for (; i > 0; --i) {
357            j = readUnsignedShort(v + 6);
358            v += 8;
359            for (; j > 0; --j) {
360                v += 6 + readInt(v + 2);
361            }
362        }
363        i = readUnsignedShort(v);
364        v += 2;
365        for (; i > 0; --i) {
366            j = readUnsignedShort(v + 6);
367            v += 8;
368            for (; j > 0; --j) {
369                v += 6 + readInt(v + 2);
370            }
371        }
372        // reads the class's attributes
373        signature = null;
374        String sourceFile = null;
375        String sourceDebug = null;
376        String enclosingOwner = null;
377        String enclosingName = null;
378        String enclosingDesc = null;
379
380        i = readUnsignedShort(v);
381        v += 2;
382        for (; i > 0; --i) {
383            attrName = readUTF8(v, c);
384            if (attrName.equals("SourceFile")) {
385                sourceFile = readUTF8(v + 6, c);
386            } else if (attrName.equals("Deprecated")) {
387                access |= Opcodes.ACC_DEPRECATED;
388            } else if (attrName.equals("Synthetic")) {
389                access |= Opcodes.ACC_SYNTHETIC;
390            } else if (attrName.equals("Annotation")) {
391                access |= Opcodes.ACC_ANNOTATION;
392            } else if (attrName.equals("Enum")) {
393                access |= Opcodes.ACC_ENUM;
394            } else if (attrName.equals("InnerClasses")) {
395                w = v + 6;
396            } else if (attrName.equals("Signature")) {
397                signature = readUTF8(v + 6, c);
398            } else if (attrName.equals("SourceDebugExtension")) {
399                int len = readInt(v + 2);
400                sourceDebug = readUTF(v + 6, len, new char[len]);
401            } else if (attrName.equals("EnclosingMethod")) {
402                enclosingOwner = readClass(v + 6, c);
403                int item = readUnsignedShort(v + 8);
404                if (item != 0) {
405                    enclosingName = readUTF8(items[item], c);
406                    enclosingDesc = readUTF8(items[item] + 2, c);
407                }
408            } else if (attrName.equals("RuntimeVisibleAnnotations")) {
409                anns = v + 6;
410            } else if (attrName.equals("RuntimeInvisibleAnnotations")) {
411                ianns = v + 6;
412            } else {
413                attr = readAttribute(attrs,
414                        attrName,
415                        v + 6,
416                        readInt(v + 2),
417                        c,
418                        -1,
419                        null);
420                if (attr != null) {
421                    attr.next = cattrs;
422                    cattrs = attr;
423                }
424            }
425            v += 6 + readInt(v + 2);
426        }
427        // calls the visit method
428        classVisitor.visit(readInt(4),
429                access,
430                name,
431                signature,
432                superClassName,
433                implementedItfs);
434
435        // calls the visitSource method
436        if (sourceFile != null || sourceDebug != null) {
437            classVisitor.visitSource(sourceFile, sourceDebug);
438        }
439
440        // calls the visitOuterClass method
441        if (enclosingOwner != null) {
442            classVisitor.visitOuterClass(enclosingOwner,
443                    enclosingName,
444                    enclosingDesc);
445        }
446
447        // visits the class annotations
448        for (i = 1; i >= 0; --i) {
449            v = i == 0 ? ianns : anns;
450            if (v != 0) {
451                j = readUnsignedShort(v);
452                v += 2;
453                for (; j > 0; --j) {
454                    desc = readUTF8(v, c);
455                    v += 2;
456                    v = readAnnotationValues(v,
457                            c,
458                            classVisitor.visitAnnotation(desc, i != 0));
459                }
460            }
461        }
462
463        // visits the class attributes
464        while (cattrs != null) {
465            attr = cattrs.next;
466            cattrs.next = null;
467            classVisitor.visitAttribute(cattrs);
468            cattrs = attr;
469        }
470
471        // class the visitInnerClass method
472        if (w != 0) {
473            i = readUnsignedShort(w);
474            w += 2;
475            for (; i > 0; --i) {
476                classVisitor.visitInnerClass(readUnsignedShort(w) == 0
477                        ? null
478                        : readClass(w, c), readUnsignedShort(w + 2) == 0
479                        ? null
480                        : readClass(w + 2, c), readUnsignedShort(w + 4) == 0
481                        ? null
482                        : readUTF8(w + 4, c), readUnsignedShort(w + 6));
483                w += 8;
484            }
485        }
486
487        // visits the fields
488        i = readUnsignedShort(u);
489        u += 2;
490        for (; i > 0; --i) {
491            access = readUnsignedShort(u);
492            name = readUTF8(u + 2, c);
493            desc = readUTF8(u + 4, c);
494            // visits the field's attributes and looks for a ConstantValue
495            // attribute
496            int fieldValueItem = 0;
497            signature = null;
498            anns = 0;
499            ianns = 0;
500            cattrs = null;
501
502            j = readUnsignedShort(u + 6);
503            u += 8;
504            for (; j > 0; --j) {
505                attrName = readUTF8(u, c);
506                if (attrName.equals("ConstantValue")) {
507                    fieldValueItem = readUnsignedShort(u + 6);
508                } else if (attrName.equals("Synthetic")) {
509                    access |= Opcodes.ACC_SYNTHETIC;
510                } else if (attrName.equals("Deprecated")) {
511                    access |= Opcodes.ACC_DEPRECATED;
512                } else if (attrName.equals("Enum")) {
513                    access |= Opcodes.ACC_ENUM;
514                } else if (attrName.equals("Signature")) {
515                    signature = readUTF8(u + 6, c);
516                } else if (attrName.equals("RuntimeVisibleAnnotations")) {
517                    anns = u + 6;
518                } else if (attrName.equals("RuntimeInvisibleAnnotations")) {
519                    ianns = u + 6;
520                } else {
521                    attr = readAttribute(attrs,
522                            attrName,
523                            u + 6,
524                            readInt(u + 2),
525                            c,
526                            -1,
527                            null);
528                    if (attr != null) {
529                        attr.next = cattrs;
530                        cattrs = attr;
531                    }
532                }
533                u += 6 + readInt(u + 2);
534            }
535            // reads the field's value, if any
536            Object value = (fieldValueItem == 0
537                    ? null
538                    : readConst(fieldValueItem, c));
539            // visits the field
540            FieldVisitor fv = classVisitor.visitField(access,
541                    name,
542                    desc,
543                    signature,
544                    value);
545            // visits the field annotations and attributes
546            if (fv != null) {
547                for (j = 1; j >= 0; --j) {
548                    v = j == 0 ? ianns : anns;
549                    if (v != 0) {
550                        k = readUnsignedShort(v);
551                        v += 2;
552                        for (; k > 0; --k) {
553                            desc = readUTF8(v, c);
554                            v += 2;
555                            v = readAnnotationValues(v,
556                                    c,
557                                    fv.visitAnnotation(desc, j != 0));
558                        }
559                    }
560                }
561                while (cattrs != null) {
562                    attr = cattrs.next;
563                    cattrs.next = null;
564                    fv.visitAttribute(cattrs);
565                    cattrs = attr;
566                }
567                fv.visitEnd();
568            }
569        }
570
571        // visits the methods
572        i = readUnsignedShort(u);
573        u += 2;
574        for (; i > 0; --i) {
575            int u0 = u + 6;
576            access = readUnsignedShort(u);
577            name = readUTF8(u + 2, c);
578            desc = readUTF8(u + 4, c);
579            signature = null;
580            anns = 0;
581            ianns = 0;
582            int dann = 0;
583            int mpanns = 0;
584            int impanns = 0;
585            cattrs = null;
586            v = 0;
587            w = 0;
588
589            // looks for Code and Exceptions attributes
590            j = readUnsignedShort(u + 6);
591            u += 8;
592            for (; j > 0; --j) {
593                attrName = readUTF8(u, c);
594                u += 2;
595                int attrSize = readInt(u);
596                u += 4;
597                if (attrName.equals("Code")) {
598                    v = u;
599                } else if (attrName.equals("Exceptions")) {
600                    w = u;
601                } else if (attrName.equals("Synthetic")) {
602                    access |= Opcodes.ACC_SYNTHETIC;
603                } else if (attrName.equals("Varargs")) {
604                    access |= Opcodes.ACC_VARARGS;
605                } else if (attrName.equals("Bridge")) {
606                    access |= Opcodes.ACC_BRIDGE;
607                } else if (attrName.equals("Deprecated")) {
608                    access |= Opcodes.ACC_DEPRECATED;
609                } else if (attrName.equals("Signature")) {
610                    signature = readUTF8(u, c);
611                } else if (attrName.equals("AnnotationDefault")) {
612                    dann = u;
613                } else if (attrName.equals("RuntimeVisibleAnnotations")) {
614                    anns = u;
615                } else if (attrName.equals("RuntimeInvisibleAnnotations")) {
616                    ianns = u;
617                } else if (attrName.equals("RuntimeVisibleParameterAnnotations"))
618                {
619                    mpanns = u;
620                } else if (attrName.equals("RuntimeInvisibleParameterAnnotations"))
621                {
622                    impanns = u;
623                } else {
624                    attr = readAttribute(attrs,
625                            attrName,
626                            u,
627                            attrSize,
628                            c,
629                            -1,
630                            null);
631                    if (attr != null) {
632                        attr.next = cattrs;
633                        cattrs = attr;
634                    }
635                }
636                u += attrSize;
637            }
638            // reads declared exceptions
639            String[] exceptions;
640            if (w == 0) {
641                exceptions = null;
642            } else {
643                exceptions = new String[readUnsignedShort(w)];
644                w += 2;
645                for (j = 0; j < exceptions.length; ++j) {
646                    exceptions[j] = readClass(w, c);
647                    w += 2;
648                }
649            }
650
651            // visits the method's code, if any
652            MethodVisitor mv = classVisitor.visitMethod(access,
653                    name,
654                    desc,
655                    signature,
656                    exceptions);
657
658            if (mv != null) {
659                /*
660                 * if the returned MethodVisitor is in fact a MethodWriter, it
661                 * means there is no method adapter between the reader and the
662                 * writer. If, in addition, the writer's constant pool was
663                 * copied from this reader (mw.cw.cr == this), and the signature
664                 * and exceptions of the method have not been changed, then it
665                 * is possible to skip all visit events and just copy the
666                 * original code of the method to the writer (the access, name
667                 * and descriptor can have been changed, this is not important
668                 * since they are not copied as is from the reader).
669                 */
670                if (mv instanceof MethodWriter) {
671                    MethodWriter mw = (MethodWriter) mv;
672                    if (mw.cw.cr == this) {
673                        if (signature == mw.signature) {
674                            boolean sameExceptions = false;
675                            if (exceptions == null) {
676                                sameExceptions = mw.exceptionCount == 0;
677                            } else {
678                                if (exceptions.length == mw.exceptionCount) {
679                                    sameExceptions = true;
680                                    for (j = exceptions.length - 1; j >= 0; --j)
681                                    {
682                                        w -= 2;
683                                        if (mw.exceptions[j] != readUnsignedShort(w))
684                                        {
685                                            sameExceptions = false;
686                                            break;
687                                        }
688                                    }
689                                }
690                            }
691                            if (sameExceptions) {
692                                /*
693                                 * we do not copy directly the code into
694                                 * MethodWriter to save a byte array copy
695                                 * operation. The real copy will be done in
696                                 * ClassWriter.toByteArray().
697                                 */
698                                mw.classReaderOffset = u0;
699                                mw.classReaderLength = u - u0;
700                                continue;
701                            }
702                        }
703                    }
704                }
705                if (dann != 0) {
706                    AnnotationVisitor dv = mv.visitAnnotationDefault();
707                    readAnnotationValue(dann, c, null, dv);
708                    dv.visitEnd();
709                }
710                for (j = 1; j >= 0; --j) {
711                    w = j == 0 ? ianns : anns;
712                    if (w != 0) {
713                        k = readUnsignedShort(w);
714                        w += 2;
715                        for (; k > 0; --k) {
716                            desc = readUTF8(w, c);
717                            w += 2;
718                            w = readAnnotationValues(w,
719                                    c,
720                                    mv.visitAnnotation(desc, j != 0));
721                        }
722                    }
723                }
724                if (mpanns != 0) {
725                    readParameterAnnotations(mpanns, c, true, mv);
726                }
727                if (impanns != 0) {
728                    readParameterAnnotations(impanns, c, false, mv);
729                }
730                while (cattrs != null) {
731                    attr = cattrs.next;
732                    cattrs.next = null;
733                    mv.visitAttribute(cattrs);
734                    cattrs = attr;
735                }
736            }
737
738            if (mv != null && v != 0) {
739                int maxStack = readUnsignedShort(v);
740                int maxLocals = readUnsignedShort(v + 2);
741                int codeLength = readInt(v + 4);
742                v += 8;
743
744                int codeStart = v;
745                int codeEnd = v + codeLength;
746
747                mv.visitCode();
748
749                // 1st phase: finds the labels
750                int label;
751                Label[] labels = new Label[codeLength + 1];
752                while (v < codeEnd) {
753                    int opcode = b[v] & 0xFF;
754                    switch (ClassWriter.TYPE[opcode]) {
755                        case ClassWriter.NOARG_INSN:
756                        case ClassWriter.IMPLVAR_INSN:
757                            v += 1;
758                            break;
759                        case ClassWriter.LABEL_INSN:
760                            label = v - codeStart + readShort(v + 1);
761                            if (labels[label] == null) {
762                                labels[label] = new Label();
763                            }
764                            v += 3;
765                            break;
766                        case ClassWriter.LABELW_INSN:
767                            label = v - codeStart + readInt(v + 1);
768                            if (labels[label] == null) {
769                                labels[label] = new Label();
770                            }
771                            v += 5;
772                            break;
773                        case ClassWriter.WIDE_INSN:
774                            opcode = b[v + 1] & 0xFF;
775                            if (opcode == Opcodes.IINC) {
776                                v += 6;
777                            } else {
778                                v += 4;
779                            }
780                            break;
781                        case ClassWriter.TABL_INSN:
782                            // skips 0 to 3 padding bytes
783                            w = v - codeStart;
784                            v = v + 4 - (w & 3);
785                            // reads instruction
786                            label = w + readInt(v);
787                            v += 4;
788                            if (labels[label] == null) {
789                                labels[label] = new Label();
790                            }
791                            j = readInt(v);
792                            v += 4;
793                            j = readInt(v) - j + 1;
794                            v += 4;
795                            for (; j > 0; --j) {
796                                label = w + readInt(v);
797                                v += 4;
798                                if (labels[label] == null) {
799                                    labels[label] = new Label();
800                                }
801                            }
802                            break;
803                        case ClassWriter.LOOK_INSN:
804                            // skips 0 to 3 padding bytes
805                            w = v - codeStart;
806                            v = v + 4 - (w & 3);
807                            // reads instruction
808                            label = w + readInt(v);
809                            v += 4;
810                            if (labels[label] == null) {
811                                labels[label] = new Label();
812                            }
813                            j = readInt(v);
814                            v += 4;
815                            for (; j > 0; --j) {
816                                v += 4; // skips key
817                                label = w + readInt(v);
818                                v += 4;
819                                if (labels[label] == null) {
820                                    labels[label] = new Label();
821                                }
822                            }
823                            break;
824                        case ClassWriter.VAR_INSN:
825                        case ClassWriter.SBYTE_INSN:
826                        case ClassWriter.LDC_INSN:
827                            v += 2;
828                            break;
829                        case ClassWriter.SHORT_INSN:
830                        case ClassWriter.LDCW_INSN:
831                        case ClassWriter.FIELDORMETH_INSN:
832                        case ClassWriter.TYPE_INSN:
833                        case ClassWriter.IINC_INSN:
834                            v += 3;
835                            break;
836                        case ClassWriter.ITFMETH_INSN:
837                            v += 5;
838                            break;
839                        // case MANA_INSN:
840                        default:
841                            v += 4;
842                            break;
843                    }
844                }
845                // parses the try catch entries
846                j = readUnsignedShort(v);
847                v += 2;
848                for (; j > 0; --j) {
849                    label = readUnsignedShort(v);
850                    Label start = labels[label];
851                    if (start == null) {
852                        labels[label] = start = new Label();
853                    }
854                    label = readUnsignedShort(v + 2);
855                    Label end = labels[label];
856                    if (end == null) {
857                        labels[label] = end = new Label();
858                    }
859                    label = readUnsignedShort(v + 4);
860                    Label handler = labels[label];
861                    if (handler == null) {
862                        labels[label] = handler = new Label();
863                    }
864
865                    int type = readUnsignedShort(v + 6);
866                    if (type == 0) {
867                        mv.visitTryCatchBlock(start, end, handler, null);
868                    } else {
869                        mv.visitTryCatchBlock(start,
870                                end,
871                                handler,
872                                readUTF8(items[type], c));
873                    }
874                    v += 8;
875                }
876                // parses the local variable, line number tables, and code
877                // attributes
878                int varTable = 0;
879                int varTypeTable = 0;
880                cattrs = null;
881                j = readUnsignedShort(v);
882                v += 2;
883                for (; j > 0; --j) {
884                    attrName = readUTF8(v, c);
885                    if (attrName.equals("LocalVariableTable")) {
886                        if (!skipDebug) {
887                            varTable = v + 6;
888                            k = readUnsignedShort(v + 6);
889                            w = v + 8;
890                            for (; k > 0; --k) {
891                                label = readUnsignedShort(w);
892                                if (labels[label] == null) {
893                                    labels[label] = new Label();
894                                }
895                                label += readUnsignedShort(w + 2);
896                                if (labels[label] == null) {
897                                    labels[label] = new Label();
898                                }
899                                w += 10;
900                            }
901                        }
902                    } else if (attrName.equals("LocalVariableTypeTable")) {
903                        varTypeTable = v + 6;
904                    } else if (attrName.equals("LineNumberTable")) {
905                        if (!skipDebug) {
906                            k = readUnsignedShort(v + 6);
907                            w = v + 8;
908                            for (; k > 0; --k) {
909                                label = readUnsignedShort(w);
910                                if (labels[label] == null) {
911                                    labels[label] = new Label();
912                                }
913                                labels[label].line = readUnsignedShort(w + 2);
914                                w += 4;
915                            }
916                        }
917                    } else {
918                        for (k = 0; k < attrs.length; ++k) {
919                            if (attrs[k].type.equals(attrName)) {
920                                attr = attrs[k].read(this,
921                                        v + 6,
922                                        readInt(v + 2),
923                                        c,
924                                        codeStart - 8,
925                                        labels);
926                                if (attr != null) {
927                                    attr.next = cattrs;
928                                    cattrs = attr;
929                                }
930                            }
931                        }
932                    }
933                    v += 6 + readInt(v + 2);
934                }
935
936                // 2nd phase: visits each instruction
937                v = codeStart;
938                Label l;
939                while (v < codeEnd) {
940                    w = v - codeStart;
941                    l = labels[w];
942                    if (l != null) {
943                        mv.visitLabel(l);
944                        if (!skipDebug && l.line > 0) {
945                            mv.visitLineNumber(l.line, l);
946                        }
947                    }
948                    int opcode = b[v] & 0xFF;
949                    switch (ClassWriter.TYPE[opcode]) {
950                        case ClassWriter.NOARG_INSN:
951                            mv.visitInsn(opcode);
952                            v += 1;
953                            break;
954                        case ClassWriter.IMPLVAR_INSN:
955                            if (opcode > Opcodes.ISTORE) {
956                                opcode -= 59; // ISTORE_0
957                                mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2),
958                                        opcode & 0x3);
959                            } else {
960                                opcode -= 26; // ILOAD_0
961                                mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2),
962                                        opcode & 0x3);
963                            }
964                            v += 1;
965                            break;
966                        case ClassWriter.LABEL_INSN:
967                            mv.visitJumpInsn(opcode, labels[w
968                                    + readShort(v + 1)]);
969                            v += 3;
970                            break;
971                        case ClassWriter.LABELW_INSN:
972                            mv.visitJumpInsn(opcode - 33, labels[w
973                                    + readInt(v + 1)]);
974                            v += 5;
975                            break;
976                        case ClassWriter.WIDE_INSN:
977                            opcode = b[v + 1] & 0xFF;
978                            if (opcode == Opcodes.IINC) {
979                                mv.visitIincInsn(readUnsignedShort(v + 2),
980                                        readShort(v + 4));
981                                v += 6;
982                            } else {
983                                mv.visitVarInsn(opcode,
984                                        readUnsignedShort(v + 2));
985                                v += 4;
986                            }
987                            break;
988                        case ClassWriter.TABL_INSN:
989                            // skips 0 to 3 padding bytes
990                            v = v + 4 - (w & 3);
991                            // reads instruction
992                            label = w + readInt(v);
993                            v += 4;
994                            int min = readInt(v);
995                            v += 4;
996                            int max = readInt(v);
997                            v += 4;
998                            Label[] table = new Label[max - min + 1];
999                            for (j = 0; j < table.length; ++j) {
1000                                table[j] = labels[w + readInt(v)];
1001                                v += 4;
1002                            }
1003                            mv.visitTableSwitchInsn(min,
1004                                    max,
1005                                    labels[label],
1006                                    table);
1007                            break;
1008                        case ClassWriter.LOOK_INSN:
1009                            // skips 0 to 3 padding bytes
1010                            v = v + 4 - (w & 3);
1011                            // reads instruction
1012                            label = w + readInt(v);
1013                            v += 4;
1014                            j = readInt(v);
1015                            v += 4;
1016                            int[] keys = new int[j];
1017                            Label[] values = new Label[j];
1018                            for (j = 0; j < keys.length; ++j) {
1019                                keys[j] = readInt(v);
1020                                v += 4;
1021                                values[j] = labels[w + readInt(v)];
1022                                v += 4;
1023                            }
1024                            mv.visitLookupSwitchInsn(labels[label],
1025                                    keys,
1026                                    values);
1027                            break;
1028                        case ClassWriter.VAR_INSN:
1029                            mv.visitVarInsn(opcode, b[v + 1] & 0xFF);
1030                            v += 2;
1031                            break;
1032                        case ClassWriter.SBYTE_INSN:
1033                            mv.visitIntInsn(opcode, b[v + 1]);
1034                            v += 2;
1035                            break;
1036                        case ClassWriter.SHORT_INSN:
1037                            mv.visitIntInsn(opcode, readShort(v + 1));
1038                            v += 3;
1039                            break;
1040                        case ClassWriter.LDC_INSN:
1041                            mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c));
1042                            v += 2;
1043                            break;
1044                        case ClassWriter.LDCW_INSN:
1045                            mv.visitLdcInsn(readConst(readUnsignedShort(v + 1),
1046                                    c));
1047                            v += 3;
1048                            break;
1049                        case ClassWriter.FIELDORMETH_INSN:
1050                        case ClassWriter.ITFMETH_INSN:
1051                            int cpIndex = items[readUnsignedShort(v + 1)];
1052                            String iowner = readClass(cpIndex, c);
1053                            cpIndex = items[readUnsignedShort(cpIndex + 2)];
1054                            String iname = readUTF8(cpIndex, c);
1055                            String idesc = readUTF8(cpIndex + 2, c);
1056                            if (opcode < Opcodes.INVOKEVIRTUAL) {
1057                                mv.visitFieldInsn(opcode, iowner, iname, idesc);
1058                            } else {
1059                                mv.visitMethodInsn(opcode, iowner, iname, idesc);
1060                            }
1061                            if (opcode == Opcodes.INVOKEINTERFACE) {
1062                                v += 5;
1063                            } else {
1064                                v += 3;
1065                            }
1066                            break;
1067                        case ClassWriter.TYPE_INSN:
1068                            mv.visitTypeInsn(opcode, readClass(v + 1, c));
1069                            v += 3;
1070                            break;
1071                        case ClassWriter.IINC_INSN:
1072                            mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]);
1073                            v += 3;
1074                            break;
1075                        // case MANA_INSN:
1076                        default:
1077                            mv.visitMultiANewArrayInsn(readClass(v + 1, c),
1078                                    b[v + 3] & 0xFF);
1079                            v += 4;
1080                            break;
1081                    }
1082                }
1083                l = labels[codeEnd - codeStart];
1084                if (l != null) {
1085                    mv.visitLabel(l);
1086                }
1087
1088                // visits the local variable tables
1089                if (!skipDebug && varTable != 0) {
1090                    int[] typeTable = null;
1091                    if (varTypeTable != 0) {
1092                        w = varTypeTable;
1093                        k = readUnsignedShort(w) * 3;
1094                        w += 2;
1095                        typeTable = new int[k];
1096                        while (k > 0) {
1097                            typeTable[--k] = w + 6; // signature
1098                            typeTable[--k] = readUnsignedShort(w + 8); // index
1099                            typeTable[--k] = readUnsignedShort(w); // start
1100                            w += 10;
1101                        }
1102                    }
1103                    w = varTable;
1104                    k = readUnsignedShort(w);
1105                    w += 2;
1106                    for (; k > 0; --k) {
1107                        int start = readUnsignedShort(w);
1108                        int length = readUnsignedShort(w + 2);
1109                        int index = readUnsignedShort(w + 8);
1110                        String vsignature = null;
1111                        if (typeTable != null) {
1112                            for (int a = 0; a < typeTable.length; a += 3) {
1113                                if (typeTable[a] == start
1114                                        && typeTable[a + 1] == index)
1115                                {
1116                                    vsignature = readUTF8(typeTable[a + 2], c);
1117                                    break;
1118                                }
1119                            }
1120                        }
1121                        mv.visitLocalVariable(readUTF8(w + 4, c),
1122                                readUTF8(w + 6, c),
1123                                vsignature,
1124                                labels[start],
1125                                labels[start + length],
1126                                index);
1127                        w += 10;
1128                    }
1129                }
1130                // visits the other attributes
1131                while (cattrs != null) {
1132                    attr = cattrs.next;
1133                    cattrs.next = null;
1134                    mv.visitAttribute(cattrs);
1135                    cattrs = attr;
1136                }
1137                // visits the max stack and max locals values
1138                mv.visitMaxs(maxStack, maxLocals);
1139            }
1140
1141            if (mv != null) {
1142                mv.visitEnd();
1143            }
1144        }
1145
1146        // visits the end of the class
1147        classVisitor.visitEnd();
1148    }
1149
1150    /**
1151     * Reads parameter annotations and makes the given visitor visit them.
1152     *
1153     * @param v start offset in {@link #b b} of the annotations to be read.
1154     * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1155     *        {@link #readClass(int,char[]) readClass} or
1156     *        {@link #readConst readConst}.
1157     * @param visible <tt>true</tt> if the annotations to be read are visible
1158     *        at runtime.
1159     * @param mv the visitor that must visit the annotations.
1160     */
1161    private void readParameterAnnotations(
1162        int v,
1163        final char[] buf,
1164        final boolean visible,
1165        final MethodVisitor mv)
1166    {
1167        int n = b[v++] & 0xFF;
1168        for (int i = 0; i < n; ++i) {
1169            int j = readUnsignedShort(v);
1170            v += 2;
1171            for (; j > 0; --j) {
1172                String desc = readUTF8(v, buf);
1173                v += 2;
1174                AnnotationVisitor av = mv.visitParameterAnnotation(i,
1175                        desc,
1176                        visible);
1177                v = readAnnotationValues(v, buf, av);
1178            }
1179        }
1180    }
1181
1182    /**
1183     * Reads the values of an annotation and makes the given visitor visit them.
1184     *
1185     * @param v the start offset in {@link #b b} of the values to be read
1186     *        (including the unsigned short that gives the number of values).
1187     * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1188     *        {@link #readClass(int,char[]) readClass} or
1189     *        {@link #readConst readConst}.
1190     * @param av the visitor that must visit the values.
1191     * @return the end offset of the annotations values.
1192     */
1193    private int readAnnotationValues(
1194        int v,
1195        final char[] buf,
1196        final AnnotationVisitor av)
1197    {
1198        int i = readUnsignedShort(v);
1199        v += 2;
1200        for (; i > 0; --i) {
1201            String name = readUTF8(v, buf);
1202            v += 2;
1203            v = readAnnotationValue(v, buf, name, av);
1204        }
1205        av.visitEnd();
1206        return v;
1207    }
1208
1209    /**
1210     * Reads a value of an annotation and makes the given visitor visit it.
1211     *
1212     * @param v the start offset in {@link #b b} of the value to be read (<i>not
1213     *        including the value name constant pool index</i>).
1214     * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1215     *        {@link #readClass(int,char[]) readClass} or
1216     *        {@link #readConst readConst}.
1217     * @param name the name of the value to be read.
1218     * @param av the visitor that must visit the value.
1219     * @return the end offset of the annotation value.
1220     */
1221    private int readAnnotationValue(
1222        int v,
1223        final char[] buf,
1224        final String name,
1225        final AnnotationVisitor av)
1226    {
1227        int i;
1228        switch (readByte(v++)) {
1229            case 'I': // pointer to CONSTANT_Integer
1230            case 'J': // pointer to CONSTANT_Long
1231            case 'F': // pointer to CONSTANT_Float
1232            case 'D': // pointer to CONSTANT_Double
1233                av.visit(name, readConst(readUnsignedShort(v), buf));
1234                v += 2;
1235                break;
1236            case 'B': // pointer to CONSTANT_Byte
1237                av.visit(name,
1238                        new Byte((byte) readInt(items[readUnsignedShort(v)])));
1239                v += 2;
1240                break;
1241            case 'Z': // pointer to CONSTANT_Boolean
1242                boolean b = readInt(items[readUnsignedShort(v)]) == 0;
1243                av.visit(name, b ? Boolean.FALSE : Boolean.TRUE);
1244                v += 2;
1245                break;
1246            case 'S': // pointer to CONSTANT_Short
1247                av.visit(name,
1248                        new Short((short) readInt(items[readUnsignedShort(v)])));
1249                v += 2;
1250                break;
1251            case 'C': // pointer to CONSTANT_Char
1252                av.visit(name,
1253                        new Character((char) readInt(items[readUnsignedShort(v)])));
1254                v += 2;
1255                break;
1256            case 's': // pointer to CONSTANT_Utf8
1257                av.visit(name, readUTF8(v, buf));
1258                v += 2;
1259                break;
1260            case 'e': // enum_const_value
1261                av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf));
1262                v += 4;
1263                break;
1264            case 'c': // class_info
1265                av.visit(name, Type.getType(readUTF8(v, buf)));
1266                v += 2;
1267                break;
1268            case '@': // annotation_value
1269                String desc = readUTF8(v, buf);
1270                v += 2;
1271                v = readAnnotationValues(v, buf, av.visitAnnotation(name, desc));
1272                break;
1273            case '[': // array_value
1274                int size = readUnsignedShort(v);
1275                v += 2;
1276                if (size == 0) {
1277                    av.visitArray(name).visitEnd();
1278                    return v;
1279                }
1280                switch (readByte(v++)) {
1281                    case 'B':
1282                        byte[] bv = new byte[size];
1283                        for (i = 0; i < size; i++) {
1284                            bv[i] = (byte) readInt(items[readUnsignedShort(v)]);
1285                            v += 3;
1286                        }
1287                        av.visit(name, bv);
1288                        --v;
1289                        break;
1290                    case 'Z':
1291                        boolean[] zv = new boolean[size];
1292                        for (i = 0; i < size; i++) {
1293                            zv[i] = readInt(items[readUnsignedShort(v)]) != 0;
1294                            v += 3;
1295                        }
1296                        av.visit(name, zv);
1297                        --v;
1298                        break;
1299                    case 'S':
1300                        short[] sv = new short[size];
1301                        for (i = 0; i < size; i++) {
1302                            sv[i] = (short) readInt(items[readUnsignedShort(v)]);
1303                            v += 3;
1304                        }
1305                        av.visit(name, sv);
1306                        --v;
1307                        break;
1308                    case 'C':
1309                        char[] cv = new char[size];
1310                        for (i = 0; i < size; i++) {
1311                            cv[i] = (char) readInt(items[readUnsignedShort(v)]);
1312                            v += 3;
1313                        }
1314                        av.visit(name, cv);
1315                        --v;
1316                        break;
1317                    case 'I':
1318                        int[] iv = new int[size];
1319                        for (i = 0; i < size; i++) {
1320                            iv[i] = readInt(items[readUnsignedShort(v)]);
1321                            v += 3;
1322                        }
1323                        av.visit(name, iv);
1324                        --v;
1325                        break;
1326                    case 'J':
1327                        long[] lv = new long[size];
1328                        for (i = 0; i < size; i++) {
1329                            lv[i] = readLong(items[readUnsignedShort(v)]);
1330                            v += 3;
1331                        }
1332                        av.visit(name, lv);
1333                        --v;
1334                        break;
1335                    case 'F':
1336                        float[] fv = new float[size];
1337                        for (i = 0; i < size; i++) {
1338                            fv[i] = Float.intBitsToFloat(readInt(items[readUnsignedShort(v)]));
1339                            v += 3;
1340                        }
1341                        av.visit(name, fv);
1342                        --v;
1343                        break;
1344                    case 'D':
1345                        double[] dv = new double[size];
1346                        for (i = 0; i < size; i++) {
1347                            dv[i] = Double.longBitsToDouble(readLong(items[readUnsignedShort(v)]));
1348                            v += 3;
1349                        }
1350                        av.visit(name, dv);
1351                        --v;
1352                        break;
1353                    default:
1354                        v--;
1355                        AnnotationVisitor aav = av.visitArray(name);
1356                        for (i = size; i > 0; --i) {
1357                            v = readAnnotationValue(v, buf, null, aav);
1358                        }
1359                        aav.visitEnd();
1360                }
1361        }
1362        return v;
1363    }
1364
1365    /**
1366     * Reads an attribute in {@link #b b}.
1367     *
1368     * @param attrs prototypes of the attributes that must be parsed during the
1369     *        visit of the class. Any attribute whose type is not equal to the
1370     *        type of one the prototypes is ignored (i.e. an empty
1371     *        {@link Attribute} instance is returned).
1372     * @param type the type of the attribute.
1373     * @param off index of the first byte of the attribute's content in
1374     *        {@link #b b}. The 6 attribute header bytes, containing the type
1375     *        and the length of the attribute, are not taken into account here
1376     *        (they have already been read).
1377     * @param len the length of the attribute's content.
1378     * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
1379     *        {@link #readClass(int,char[]) readClass} or
1380     *        {@link #readConst readConst}.
1381     * @param codeOff index of the first byte of code's attribute content in
1382     *        {@link #b b}, or -1 if the attribute to be read is not a code
1383     *        attribute. The 6 attribute header bytes, containing the type and
1384     *        the length of the attribute, are not taken into account here.
1385     * @param labels the labels of the method's code, or <tt>null</tt> if the
1386     *        attribute to be read is not a code attribute.
1387     * @return the attribute that has been read, or <tt>null</tt> to skip this
1388     *         attribute.
1389     */
1390    private Attribute readAttribute(
1391        final Attribute[] attrs,
1392        final String type,
1393        final int off,
1394        final int len,
1395        final char[] buf,
1396        final int codeOff,
1397        final Label[] labels)
1398    {
1399        for (int i = 0; i < attrs.length; ++i) {
1400            if (attrs[i].type.equals(type)) {
1401                return attrs[i].read(this, off, len, buf, codeOff, labels);
1402            }
1403        }
1404        return new Attribute(type).read(this, off, len, null, -1, null);
1405    }
1406
1407    // ------------------------------------------------------------------------
1408    // Utility methods: low level parsing
1409    // ------------------------------------------------------------------------
1410
1411    /**
1412     * Returns the start index of the constant pool item in {@link #b b}, plus
1413     * one. <i>This method is intended for {@link Attribute} sub classes, and is
1414     * normally not needed by class generators or adapters.</i>
1415     *
1416     * @param item the index a constant pool item.
1417     * @return the start index of the constant pool item in {@link #b b}, plus
1418     *         one.
1419     */
1420    public int getItem(final int item) {
1421        return items[item];
1422    }
1423
1424    /**
1425     * Reads a byte value in {@link #b b}. <i>This method is intended for
1426     * {@link Attribute} sub classes, and is normally not needed by class
1427     * generators or adapters.</i>
1428     *
1429     * @param index the start index of the value to be read in {@link #b b}.
1430     * @return the read value.
1431     */
1432    public int readByte(final int index) {
1433        return b[index] & 0xFF;
1434    }
1435
1436    /**
1437     * Reads an unsigned short value in {@link #b b}. <i>This method is
1438     * intended for {@link Attribute} sub classes, and is normally not needed by
1439     * class generators or adapters.</i>
1440     *
1441     * @param index the start index of the value to be read in {@link #b b}.
1442     * @return the read value.
1443     */
1444    public int readUnsignedShort(final int index) {
1445        byte[] b = this.b;
1446        return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
1447    }
1448
1449    /**
1450     * Reads a signed short value in {@link #b b}. <i>This method is intended
1451     * for {@link Attribute} sub classes, and is normally not needed by class
1452     * generators or adapters.</i>
1453     *
1454     * @param index the start index of the value to be read in {@link #b b}.
1455     * @return the read value.
1456     */
1457    public short readShort(final int index) {
1458        byte[] b = this.b;
1459        return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
1460    }
1461
1462    /**
1463     * Reads a signed int value in {@link #b b}. <i>This method is intended for
1464     * {@link Attribute} sub classes, and is normally not needed by class
1465     * generators or adapters.</i>
1466     *
1467     * @param index the start index of the value to be read in {@link #b b}.
1468     * @return the read value.
1469     */
1470    public int readInt(final int index) {
1471        byte[] b = this.b;
1472        return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
1473                | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
1474    }
1475
1476    /**
1477     * Reads a signed long value in {@link #b b}. <i>This method is intended
1478     * for {@link Attribute} sub classes, and is normally not needed by class
1479     * generators or adapters.</i>
1480     *
1481     * @param index the start index of the value to be read in {@link #b b}.
1482     * @return the read value.
1483     */
1484    public long readLong(final int index) {
1485        long l1 = readInt(index);
1486        long l0 = readInt(index + 4) & 0xFFFFFFFFL;
1487        return (l1 << 32) | l0;
1488    }
1489
1490    /**
1491     * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method
1492     * is intended for {@link Attribute} sub classes, and is normally not needed
1493     * by class generators or adapters.</i>
1494     *
1495     * @param index the start index of an unsigned short value in {@link #b b},
1496     *        whose value is the index of an UTF8 constant pool item.
1497     * @param buf buffer to be used to read the item. This buffer must be
1498     *        sufficiently large. It is not automatically resized.
1499     * @return the String corresponding to the specified UTF8 item.
1500     */
1501    public String readUTF8(int index, final char[] buf) {
1502        int item = readUnsignedShort(index);
1503        String s = strings[item];
1504        if (s != null) {
1505            return s;
1506        }
1507        index = items[item];
1508        return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf);
1509    }
1510
1511    /**
1512     * Reads UTF8 string in {@link #b b}.
1513     *
1514     * @param index start offset of the UTF8 string to be read.
1515     * @param utfLen length of the UTF8 string to be read.
1516     * @param buf buffer to be used to read the string. This buffer must be
1517     *        sufficiently large. It is not automatically resized.
1518     * @return the String corresponding to the specified UTF8 string.
1519     */
1520    private String readUTF(int index, int utfLen, char[] buf) {
1521        int endIndex = index + utfLen;
1522        byte[] b = this.b;
1523        int strLen = 0;
1524        int c, d, e;
1525        while (index < endIndex) {
1526            c = b[index++] & 0xFF;
1527            switch (c >> 4) {
1528                case 0:
1529                case 1:
1530                case 2:
1531                case 3:
1532                case 4:
1533                case 5:
1534                case 6:
1535                case 7:
1536                    // 0xxxxxxx
1537                    buf[strLen++] = (char) c;
1538                    break;
1539                case 12:
1540                case 13:
1541                    // 110x xxxx 10xx xxxx
1542                    d = b[index++];
1543                    buf[strLen++] = (char) (((c & 0x1F) << 6) | (d & 0x3F));
1544                    break;
1545                default:
1546                    // 1110 xxxx 10xx xxxx 10xx xxxx
1547                    d = b[index++];
1548                    e = b[index++];
1549                    buf[strLen++] = (char) (((c & 0x0F) << 12)
1550                            | ((d & 0x3F) << 6) | (e & 0x3F));
1551                    break;
1552            }
1553        }
1554        return new String(buf, 0, strLen);
1555    }
1556
1557    /**
1558     * Reads a class constant pool item in {@link #b b}. <i>This method is
1559     * intended for {@link Attribute} sub classes, and is normally not needed by
1560     * class generators or adapters.</i>
1561     *
1562     * @param index the start index of an unsigned short value in {@link #b b},
1563     *        whose value is the index of a class constant pool item.
1564     * @param buf buffer to be used to read the item. This buffer must be
1565     *        sufficiently large. It is not automatically resized.
1566     * @return the String corresponding to the specified class item.
1567     */
1568    public String readClass(final int index, final char[] buf) {
1569        // computes the start index of the CONSTANT_Class item in b
1570        // and reads the CONSTANT_Utf8 item designated by
1571        // the first two bytes of this CONSTANT_Class item
1572        return readUTF8(items[readUnsignedShort(index)], buf);
1573    }
1574
1575    /**
1576     * Reads a numeric or string constant pool item in {@link #b b}. <i>This
1577     * method is intended for {@link Attribute} sub classes, and is normally not
1578     * needed by class generators or adapters.</i>
1579     *
1580     * @param item the index of a constant pool item.
1581     * @param buf buffer to be used to read the item. This buffer must be
1582     *        sufficiently large. It is not automatically resized.
1583     * @return the {@link Integer}, {@link Float}, {@link Long},
1584     *         {@link Double}, {@link String} or {@link Type} corresponding to
1585     *         the given constant pool item.
1586     */
1587    public Object readConst(final int item, final char[] buf) {
1588        int index = items[item];
1589        switch (b[index - 1]) {
1590            case ClassWriter.INT:
1591                return new Integer(readInt(index));
1592            case ClassWriter.FLOAT:
1593                return new Float(Float.intBitsToFloat(readInt(index)));
1594            case ClassWriter.LONG:
1595                return new Long(readLong(index));
1596            case ClassWriter.DOUBLE:
1597                return new Double(Double.longBitsToDouble(readLong(index)));
1598            case ClassWriter.CLASS:
1599                String s = readUTF8(index, buf);
1600                return Type.getType(s.charAt(0) == '[' ? s : "L" + s + ";");
1601            // case ClassWriter.STR:
1602            default:
1603                return readUTF8(index, buf);
1604        }
1605    }
1606}
1607