KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > asm > ClassReader


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  */

30 package com.tc.asm;
31
32 import java.io.InputStream JavaDoc;
33 import java.io.IOException JavaDoc;
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  */

44 public 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 JavaDoc[] 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 JavaDoc[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 JavaDoc 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 JavaDoc is) throws IOException JavaDoc {
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 JavaDoc name) throws IOException JavaDoc {
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 JavaDoc is) throws IOException JavaDoc {
258         if (is == null) {
259             throw new IOException JavaDoc("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 JavaDoc name;
331         String JavaDoc desc;
332         String JavaDoc attrName;
333         String JavaDoc 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 JavaDoc superClassName = v == 0 ? null : readUTF8(v, c);
344         String JavaDoc[] implementedItfs = new String JavaDoc[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 JavaDoc sourceFile = null;
375         String JavaDoc sourceDebug = null;
376         String JavaDoc enclosingOwner = null;
377         String JavaDoc enclosingName = null;
378         String JavaDoc 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 JavaDoc 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 JavaDoc[] exceptions;
640             if (w == 0) {
641                 exceptions = null;
642             } else {
643                 exceptions = new String JavaDoc[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 JavaDoc iowner = readClass(cpIndex, c);
1053                            cpIndex = items[readUnsignedShort(cpIndex + 2)];
1054                            String JavaDoc iname = readUTF8(cpIndex, c);
1055                            String JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc((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 JavaDoc((short) readInt(items[readUnsignedShort(v)])));
1249                v += 2;
1250                break;
1251            case 'C': // pointer to CONSTANT_Char
1252
av.visit(name,
1253                        new Character JavaDoc((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 JavaDoc 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 JavaDoc 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 JavaDoc readUTF8(int index, final char[] buf) {
1502        int item = readUnsignedShort(index);
1503        String JavaDoc 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 JavaDoc 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 JavaDoc(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 JavaDoc 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 JavaDoc 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 JavaDoc(readInt(index));
1592            case ClassWriter.FLOAT:
1593                return new Float JavaDoc(Float.intBitsToFloat(readInt(index)));
1594            case ClassWriter.LONG:
1595                return new Long JavaDoc(readLong(index));
1596            case ClassWriter.DOUBLE:
1597                return new Double JavaDoc(Double.longBitsToDouble(readLong(index)));
1598            case ClassWriter.CLASS:
1599                String JavaDoc 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
Popular Tags