KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > asm > ClassReader


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000,2002,2003 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  * Contact: Eric.Bruneton@rd.francetelecom.com
31  *
32  * Author: Eric Bruneton
33  */

34
35 package org.logicalcobwebs.asm;
36
37 import java.io.InputStream JavaDoc;
38 import java.io.IOException JavaDoc;
39
40 /**
41  * A Java class parser to make a {@link ClassVisitor ClassVisitor} visit an
42  * existing class. This class parses a byte array conforming to the Java class
43  * file format and calls the appropriate visit methods of a given class visitor
44  * for each field, method and bytecode instruction encountered.
45  */

46
47 public class ClassReader {
48
49   /**
50    * The class to be parsed. <i>The content of this array must not be
51    * modified.</i>
52    */

53
54   protected final byte[] b;
55
56   /**
57    * The start index of each constant pool item in {@link #b b}, plus one. The
58    * one byte offset skips the constant pool item tag that indicates its type.
59    */

60
61   private int[] items;
62
63   /**
64    * The String objects corresponding to the CONSTANT_Utf8 items. This cache
65    * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item, which
66    * GREATLY improves performances (by a factor 2 to 3). This caching strategy
67    * could be extended to all constant pool items, but its benefit would not be
68    * so great for these items (because they are much less expensive to parse
69    * than CONSTANT_Utf8 items).
70    */

71
72   private String JavaDoc[] strings;
73
74   /**
75    * Maximum length of the strings contained in the constant pool of the class.
76    */

77
78   private int maxStringLength;
79
80   /**
81    * Start index of the class header information (access, name...) in {@link #b
82    * b}.
83    */

84
85   private int header;
86
87   // --------------------------------------------------------------------------
88
// Constructors
89
// --------------------------------------------------------------------------
90

91   /**
92    * Constructs a new {@link ClassReader ClassReader} object.
93    *
94    * @param b the bytecode of the class to be read.
95    */

96
97   public ClassReader (final byte[] b) {
98     this(b, 0, b.length);
99   }
100
101   /**
102    * Constructs a new {@link ClassReader ClassReader} object.
103    *
104    * @param b the bytecode of the class to be read.
105    * @param off the start offset of the class data.
106    * @param len the length of the class data.
107    */

108
109   public ClassReader (final byte[] b, final int off, final int len) {
110     this.b = b;
111     // parses the constant pool
112
items = new int[readUnsignedShort(off + 8)];
113     strings = new String JavaDoc[items.length];
114     int max = 0;
115     int index = off + 10;
116     for (int i = 1; i < items.length; ++i) {
117       items[i] = index + 1;
118       int tag = b[index];
119       int size;
120       switch (tag) {
121         case ClassWriter.FIELD:
122         case ClassWriter.METH:
123         case ClassWriter.IMETH:
124         case ClassWriter.INT:
125         case ClassWriter.FLOAT:
126         case ClassWriter.NAME_TYPE:
127           size = 5;
128           break;
129         case ClassWriter.LONG:
130         case ClassWriter.DOUBLE:
131           size = 9;
132           ++i;
133           break;
134         case ClassWriter.UTF8:
135           size = 3 + readUnsignedShort(index + 1);
136           max = (size > max ? size : max);
137           break;
138         //case ClassWriter.CLASS:
139
//case ClassWriter.STR:
140
default:
141           size = 3;
142           break;
143       }
144       index += size;
145     }
146     maxStringLength = max;
147     // the class header information starts just after the constant pool
148
header = index;
149   }
150
151   /**
152    * Constructs a new {@link ClassReader ClassReader} object.
153    *
154    * @param is an input stream from which to read the class.
155    * @throws IOException if a problem occurs during reading.
156    */

157
158   public ClassReader (final InputStream JavaDoc is) throws IOException JavaDoc {
159     this(readClass(is));
160   }
161
162   /**
163    * Constructs a new {@link ClassReader ClassReader} object.
164    *
165    * @param name the fully qualified name of the class to be read.
166    * @throws IOException if an exception occurs during reading.
167    */

168
169   public ClassReader (final String JavaDoc name) throws IOException JavaDoc {
170     this((ClassReader.class.getClassLoader() == null
171             ? ClassLoader.getSystemClassLoader()
172             : ClassReader.class.getClassLoader())
173             .getSystemResourceAsStream(name.replace('.','/') + ".class"));
174   }
175
176   /**
177    * Reads the bytecode of a class.
178    *
179    * @param is an input stream from which to read the class.
180    * @return the bytecode read from the given input stream.
181    * @throws IOException if a problem occurs during reading.
182    */

183
184   private static byte[] readClass (final InputStream JavaDoc is) throws IOException JavaDoc {
185     if (is == null) {
186       throw new IOException JavaDoc("Class not found");
187     }
188     byte[] b = new byte[is.available()];
189     int len = 0;
190     while (true) {
191       int n = is.read(b, len, b.length - len);
192       if (n == -1) {
193         if (len < b.length) {
194           byte[] c = new byte[len];
195           System.arraycopy(b, 0, c, 0, len);
196           b = c;
197         }
198         return b;
199       } else {
200         len += n;
201         if (len == b.length) {
202           byte[] c = new byte[b.length + 1000];
203           System.arraycopy(b, 0, c, 0, len);
204           b = c;
205         }
206       }
207     }
208   }
209
210   // --------------------------------------------------------------------------
211
// Public methods
212
// --------------------------------------------------------------------------
213

214   /**
215    * Makes the given visitor visit the Java class of this {@link ClassReader
216    * ClassReader}. This class is the one specified in the constructor (see
217    * {@link #ClassReader ClassReader}).
218    *
219    * @param classVisitor the visitor that must visit this class.
220    * @param skipDebug <tt>true</tt> if the debug information of the class must
221    * not be visited. In this case the {@link CodeVisitor#visitLocalVariable
222    * visitLocalVariable} and {@link CodeVisitor#visitLineNumber
223    * visitLineNumber} methods will not be called.
224    */

225
226   public void accept (
227     final ClassVisitor classVisitor,
228     final boolean skipDebug)
229   {
230     byte[] b = this.b; // the bytecode array
231
char[] c = new char[maxStringLength]; // buffer used to read strings
232
int i, j, k; // loop variables
233
int u, v, w; // indexes in b
234
Attribute attr;
235
236     // visits the header
237
u = header;
238     int access = readUnsignedShort(u);
239     String JavaDoc className = readClass(u + 2, c);
240     v = items[readUnsignedShort(u + 4)];
241     String JavaDoc superClassName = v == 0 ? null : readUTF8(v, c);
242     String JavaDoc[] implementedItfs = new String JavaDoc[readUnsignedShort(u + 6)];
243     String JavaDoc sourceFile = null;
244     Attribute clattrs = null;
245     w = 0;
246     u += 8;
247     for (i = 0; i < implementedItfs.length; ++i) {
248       implementedItfs[i] = readClass(u, c); u += 2;
249     }
250     // skips fields and methods
251
v = u;
252     i = readUnsignedShort(v); v += 2;
253     for ( ; i > 0; --i) {
254       j = readUnsignedShort(v + 6);
255       v += 8;
256       for ( ; j > 0; --j) {
257         v += 6 + readInt(v + 2);
258       }
259     }
260     i = readUnsignedShort(v); v += 2;
261     for ( ; i > 0; --i) {
262       j = readUnsignedShort(v + 6);
263       v += 8;
264       for ( ; j > 0; --j) {
265         v += 6 + readInt(v + 2);
266       }
267     }
268     // reads the class's attributes
269
i = readUnsignedShort(v); v += 2;
270     for ( ; i > 0; --i) {
271       String JavaDoc attrName = readUTF8(v, c);
272       if (attrName.equals("SourceFile")) {
273         sourceFile = readUTF8(v + 6, c);
274       } else if (attrName.equals("Deprecated")) {
275         access |= Constants.ACC_DEPRECATED;
276       } else if (attrName.equals("InnerClasses")) {
277         w = v + 6;
278       } else {
279         attr = readAttribute(attrName, v + 6, readInt(v + 2), c);
280         attr.next = clattrs;
281         clattrs = attr;
282       }
283       v += 6 + readInt(v + 2);
284     }
285     // calls the visit method
286
classVisitor.visit(
287       access, className, superClassName, implementedItfs, sourceFile);
288
289     // visits the inner classes info
290
if (w != 0) {
291       i = readUnsignedShort(w); w += 2;
292       for ( ; i > 0; --i) {
293         classVisitor.visitInnerClass(
294           readUnsignedShort(w) == 0 ? null : readClass(w, c),
295           readUnsignedShort(w + 2) == 0 ? null : readClass(w + 2, c),
296           readUnsignedShort(w + 4) == 0 ? null : readUTF8(w + 4, c),
297           readUnsignedShort(w + 6));
298         w += 8;
299       }
300     }
301
302     // visits the fields
303
i = readUnsignedShort(u); u += 2;
304     for ( ; i > 0; --i) {
305       access = readUnsignedShort(u);
306       String JavaDoc fieldName = readUTF8(u + 2, c);
307       String JavaDoc fieldDesc = readUTF8(u + 4, c);
308       Attribute fattrs = null;
309       // visits the field's attributes and looks for a ConstantValue attribute
310
int fieldValueItem = 0;
311       j = readUnsignedShort(u + 6);
312       u += 8;
313       for ( ; j > 0; --j) {
314         String JavaDoc attrName = readUTF8(u, c);
315         if (attrName.equals("ConstantValue")) {
316           fieldValueItem = readUnsignedShort(u + 6);
317         } else if (attrName.equals("Synthetic")) {
318           access |= Constants.ACC_SYNTHETIC;
319         } else if (attrName.equals("Deprecated")) {
320           access |= Constants.ACC_DEPRECATED;
321         } else {
322           attr = readAttribute(attrName, u + 6, readInt(u + 2), c);
323           attr.next = fattrs;
324           fattrs = attr;
325         }
326         u += 6 + readInt(u + 2);
327       }
328       // reads the field's value, if any
329
Object JavaDoc value = (fieldValueItem == 0 ? null : readConst(fieldValueItem, c));
330       // visits the field
331
classVisitor.visitField(access, fieldName, fieldDesc, value, fattrs);
332     }
333
334     // visits the methods
335
i = readUnsignedShort(u); u += 2;
336     for ( ; i > 0; --i) {
337       access = readUnsignedShort(u);
338       String JavaDoc methName = readUTF8(u + 2, c);
339       String JavaDoc methDesc = readUTF8(u + 4, c);
340       Attribute mattrs = null;
341       v = 0;
342       w = 0;
343       // looks for Code and Exceptions attributes
344
j = readUnsignedShort(u + 6);
345       u += 8;
346       for ( ; j > 0; --j) {
347         String JavaDoc attrName = readUTF8(u, c); u += 2;
348         int attrSize = readInt(u); u += 4;
349         if (attrName.equals("Code")) {
350           v = u;
351         } else if (attrName.equals("Exceptions")) {
352           w = u;
353         } else if (attrName.equals("Synthetic")) {
354           access |= Constants.ACC_SYNTHETIC;
355         } else if (attrName.equals("Deprecated")) {
356           access |= Constants.ACC_DEPRECATED;
357         } else {
358           attr = readAttribute(attrName, u, attrSize, c);
359           attr.next = mattrs;
360           mattrs = attr;
361         }
362         u += attrSize;
363       }
364       // reads declared exceptions
365
String JavaDoc[] exceptions;
366       if (w == 0) {
367         exceptions = null;
368       } else {
369         exceptions = new String JavaDoc[readUnsignedShort(w)]; w += 2;
370         for (j = 0; j < exceptions.length; ++j) {
371           exceptions[j] = readClass(w, c); w += 2;
372         }
373       }
374
375       // visits the method's code, if any
376
CodeVisitor cv;
377       cv = classVisitor.visitMethod(
378         access, methName, methDesc, exceptions, mattrs);
379       if (cv != null && v != 0) {
380         int maxStack = readUnsignedShort(v);
381         int maxLocals = readUnsignedShort(v + 2);
382         int codeLength = readInt(v + 4);
383         Attribute cattrs = null;
384         v += 8;
385
386         int codeStart = v;
387         int codeEnd = v + codeLength;
388
389         // 1st phase: finds the labels
390
int label;
391         Label[] labels = new Label[codeLength + 1];
392         while (v < codeEnd) {
393           int opcode = b[v] & 0xFF;
394           switch (ClassWriter.TYPE[opcode]) {
395             case ClassWriter.NOARG_INSN:
396             case ClassWriter.IMPLVAR_INSN:
397               v += 1;
398               break;
399             case ClassWriter.LABEL_INSN:
400               label = v - codeStart + readShort(v + 1);
401               if (labels[label] == null) {
402                 labels[label] = new Label();
403               }
404               v += 3;
405               break;
406             case ClassWriter.LABELW_INSN:
407               label = v - codeStart + readInt(v + 1);
408               if (labels[label] == null) {
409                 labels[label] = new Label();
410               }
411               v += 5;
412               break;
413             case ClassWriter.WIDE_INSN:
414               opcode = b[v + 1] & 0xFF;
415               if (opcode == Constants.IINC) {
416                 v += 6;
417               } else {
418                 v += 4;
419               }
420               break;
421             case ClassWriter.TABL_INSN:
422               // skips 0 to 3 padding bytes
423
w = v - codeStart;
424               v = v + 4 - (w & 3);
425               // reads instruction
426
label = w + readInt(v); v += 4;
427               if (labels[label] == null) {
428                 labels[label] = new Label();
429               }
430               j = readInt(v); v += 4;
431               j = readInt(v) - j + 1; v += 4;
432               for ( ; j > 0; --j) {
433                 label = w + readInt(v); v += 4;
434                 if (labels[label] == null) {
435                   labels[label] = new Label();
436                 }
437               }
438               break;
439             case ClassWriter.LOOK_INSN:
440               // skips 0 to 3 padding bytes
441
w = v - codeStart;
442               v = v + 4 - (w & 3);
443               // reads instruction
444
label = w + readInt(v); v += 4;
445               if (labels[label] == null) {
446                 labels[label] = new Label();
447               }
448               j = readInt(v); v += 4;
449               for ( ; j > 0; --j) {
450                 v += 4; // skips key
451
label = w + readInt(v); v += 4;
452                 if (labels[label] == null) {
453                   labels[label] = new Label();
454                 }
455               }
456               break;
457             case ClassWriter.VAR_INSN:
458             case ClassWriter.SBYTE_INSN:
459             case ClassWriter.LDC_INSN:
460               v += 2;
461               break;
462             case ClassWriter.SHORT_INSN:
463             case ClassWriter.LDCW_INSN:
464             case ClassWriter.FIELDORMETH_INSN:
465             case ClassWriter.TYPE_INSN:
466             case ClassWriter.IINC_INSN:
467               v += 3;
468               break;
469             case ClassWriter.ITFMETH_INSN:
470               v += 5;
471               break;
472             // case MANA_INSN:
473
default:
474               v += 4;
475               break;
476           }
477         }
478         // parses the try catch entries
479
j = readUnsignedShort(v); v += 2;
480         for ( ; j > 0; --j) {
481           label = readUnsignedShort(v);
482           if (labels[label] == null) {
483             labels[label] = new Label();
484           }
485           label = readUnsignedShort(v + 2);
486           if (labels[label] == null) {
487             labels[label] = new Label();
488           }
489           label = readUnsignedShort(v + 4);
490           if (labels[label] == null) {
491             labels[label] = new Label();
492           }
493           v += 8;
494         }
495         if (!skipDebug) {
496           // parses the local variable and line number tables
497
j = readUnsignedShort(v); v += 2;
498           for ( ; j > 0; --j) {
499             String JavaDoc attrName = readUTF8(v, c);
500             if (attrName.equals("LocalVariableTable")) {
501               k = readUnsignedShort(v + 6);
502               w = v + 8;
503               for ( ; k > 0; --k) {
504                 label = readUnsignedShort(w);
505                 if (labels[label] == null) {
506                   labels[label] = new Label();
507                 }
508                 label += readUnsignedShort(w + 2);
509                 if (labels[label] == null) {
510                   labels[label] = new Label();
511                 }
512                 w += 10;
513               }
514             } else if (attrName.equals("LineNumberTable")) {
515               k = readUnsignedShort(v + 6);
516               w = v + 8;
517               for ( ; k > 0; --k) {
518                 label = readUnsignedShort(w);
519                 if (labels[label] == null) {
520                   labels[label] = new Label();
521                 }
522                 w += 4;
523               }
524             } else {
525               attr = readAttribute(attrName, v + 6, readInt(v + 2), c);
526               attr.next = cattrs;
527               cattrs = attr;
528             }
529             v += 6 + readInt(v + 2);
530           }
531         }
532
533         // 2nd phase: visits each instruction
534
v = codeStart;
535         Label l;
536         while (v < codeEnd) {
537           w = v - codeStart;
538           l = labels[w];
539           if (l != null) {
540             cv.visitLabel(l);
541           }
542           int opcode = b[v] & 0xFF;
543           switch (ClassWriter.TYPE[opcode]) {
544             case ClassWriter.NOARG_INSN:
545               cv.visitInsn(opcode);
546               v += 1;
547               break;
548             case ClassWriter.IMPLVAR_INSN:
549               if (opcode > Constants.ISTORE) {
550                 opcode -= 59; //ISTORE_0
551
cv.visitVarInsn(Constants.ISTORE + (opcode >> 2), opcode & 0x3);
552               } else {
553                 opcode -= 26; //ILOAD_0
554
cv.visitVarInsn(Constants.ILOAD + (opcode >> 2), opcode & 0x3);
555               }
556               v += 1;
557               break;
558             case ClassWriter.LABEL_INSN:
559               cv.visitJumpInsn(opcode, labels[w + readShort(v + 1)]);
560               v += 3;
561               break;
562             case ClassWriter.LABELW_INSN:
563               cv.visitJumpInsn(opcode, labels[w + readInt(v + 1)]);
564               v += 5;
565               break;
566             case ClassWriter.WIDE_INSN:
567               opcode = b[v + 1] & 0xFF;
568               if (opcode == Constants.IINC) {
569                 cv.visitIincInsn(readUnsignedShort(v + 2), readShort(v + 4));
570                 v += 6;
571               } else {
572                 cv.visitVarInsn(opcode, readUnsignedShort(v + 2));
573                 v += 4;
574               }
575               break;
576             case ClassWriter.TABL_INSN:
577               // skips 0 to 3 padding bytes
578
v = v + 4 - (w & 3);
579               // reads instruction
580
label = w + readInt(v); v += 4;
581               int min = readInt(v); v += 4;
582               int max = readInt(v); v += 4;
583               Label[] table = new Label[max - min + 1];
584               for (j = 0; j < table.length; ++j) {
585                 table[j] = labels[w + readInt(v)];
586                 v += 4;
587               }
588               cv.visitTableSwitchInsn(min, max, labels[label], table);
589               break;
590             case ClassWriter.LOOK_INSN:
591               // skips 0 to 3 padding bytes
592
v = v + 4 - (w & 3);
593               // reads instruction
594
label = w + readInt(v); v += 4;
595               j = readInt(v); v += 4;
596               int[] keys = new int[j];
597               Label[] values = new Label[j];
598               for (j = 0; j < keys.length; ++j) {
599                 keys[j] = readInt(v); v += 4;
600                 values[j] = labels[w + readInt(v)]; v += 4;
601               }
602               cv.visitLookupSwitchInsn(labels[label], keys, values);
603               break;
604             case ClassWriter.VAR_INSN:
605               cv.visitVarInsn(opcode, b[v + 1] & 0xFF);
606               v += 2;
607               break;
608             case ClassWriter.SBYTE_INSN:
609               cv.visitIntInsn(opcode, b[v + 1]);
610               v += 2;
611               break;
612             case ClassWriter.SHORT_INSN:
613               cv.visitIntInsn(opcode, readShort(v + 1));
614               v += 3;
615               break;
616             case ClassWriter.LDC_INSN:
617               cv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c));
618               v += 2;
619               break;
620             case ClassWriter.LDCW_INSN:
621               cv.visitLdcInsn(readConst(readUnsignedShort(v + 1), c));
622               v += 3;
623               break;
624             case ClassWriter.FIELDORMETH_INSN:
625             case ClassWriter.ITFMETH_INSN:
626               int cpIndex = items[readUnsignedShort(v + 1)];
627               String JavaDoc iowner = readClass(cpIndex, c);
628               cpIndex = items[readUnsignedShort(cpIndex + 2)];
629               String JavaDoc iname = readUTF8(cpIndex, c);
630               String JavaDoc idesc = readUTF8(cpIndex + 2, c);
631               if (opcode < Constants.INVOKEVIRTUAL) {
632                 cv.visitFieldInsn(opcode, iowner, iname, idesc);
633               } else {
634                 cv.visitMethodInsn(opcode, iowner, iname, idesc);
635               }
636               if (opcode == Constants.INVOKEINTERFACE) {
637                 v += 5;
638               } else {
639                 v += 3;
640               }
641               break;
642             case ClassWriter.TYPE_INSN:
643               cv.visitTypeInsn(opcode, readClass(v + 1, c));
644               v += 3;
645               break;
646             case ClassWriter.IINC_INSN:
647               cv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]);
648               v += 3;
649               break;
650             // case MANA_INSN:
651
default:
652               cv.visitMultiANewArrayInsn(readClass(v + 1, c), b[v + 3] & 0xFF);
653               v += 4;
654               break;
655           }
656         }
657         l = labels[codeEnd - codeStart];
658         if (l != null) {
659           cv.visitLabel(l);
660         }
661         // visits the try catch entries
662
j = readUnsignedShort(v); v += 2;
663         for ( ; j > 0; --j) {
664           Label start = labels[readUnsignedShort(v)];
665           Label end = labels[readUnsignedShort(v + 2)];
666           Label handler = labels[readUnsignedShort(v + 4)];
667           int type = readUnsignedShort(v + 6);
668           if (type == 0) {
669             cv.visitTryCatchBlock(start, end, handler, null);
670           } else {
671             cv.visitTryCatchBlock(start, end, handler, readUTF8(items[type], c));
672           }
673           v += 8;
674         }
675         if (!skipDebug) {
676           // visits the local variable and line number tables
677
j = readUnsignedShort(v); v += 2;
678           for ( ; j > 0; --j) {
679             String JavaDoc attrName = readUTF8(v, c);
680             if (attrName.equals("LocalVariableTable")) {
681               k = readUnsignedShort(v + 6);
682               w = v + 8;
683               for ( ; k > 0; --k) {
684                 label = readUnsignedShort(w);
685                 Label start = labels[label];
686                 label += readUnsignedShort(w + 2);
687                 Label end = labels[label];
688                 cv.visitLocalVariable(
689                   readUTF8(w + 4, c),
690                   readUTF8(w + 6, c),
691                   start,
692                   end,
693                   readUnsignedShort(w + 8));
694                 w += 10;
695               }
696             } else if (attrName.equals("LineNumberTable")) {
697               k = readUnsignedShort(v + 6);
698               w = v + 8;
699               for ( ; k > 0; --k) {
700                 cv.visitLineNumber(
701                   readUnsignedShort(w + 2),
702                   labels[readUnsignedShort(w)]);
703                 w += 4;
704               }
705             }
706             v += 6 + readInt(v + 2);
707           }
708         }
709         // visits the code attributes
710
while (cattrs != null) {
711           cv.visitAttribute(cattrs);
712           cattrs = cattrs.next;
713         }
714         // visits the max stack and max locals values
715
cv.visitMaxs(maxStack, maxLocals);
716       }
717     }
718     // visits the class attributes
719
while (clattrs != null) {
720       classVisitor.visitAttribute(clattrs);
721       clattrs = clattrs.next;
722     }
723     // visits the end of the class
724
classVisitor.visitEnd();
725   }
726
727   // --------------------------------------------------------------------------
728
// Utility methods: low level parsing
729
// --------------------------------------------------------------------------
730

731   /**
732    * Reads an unsigned short value in {@link #b b}.
733    *
734    * @param index the start index of the value to be read in {@link #b b}.
735    * @return the read value.
736    */

737
738   protected int readUnsignedShort (final int index) {
739     byte[] b = this.b;
740     return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
741   }
742
743   /**
744    * Reads a signed short value in {@link #b b}.
745    *
746    * @param index the start index of the value to be read in {@link #b b}.
747    * @return the read value.
748    */

749
750   protected short readShort (final int index) {
751     byte[] b = this.b;
752     return (short)(((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
753   }
754
755   /**
756    * Reads a signed int value in {@link #b b}.
757    *
758    * @param index the start index of the value to be read in {@link #b b}.
759    * @return the read value.
760    */

761
762   protected int readInt (final int index) {
763     byte[] b = this.b;
764     return ((b[index] & 0xFF) << 24) |
765            ((b[index + 1] & 0xFF) << 16) |
766            ((b[index + 2] & 0xFF) << 8) |
767            (b[index + 3] & 0xFF);
768   }
769
770   /**
771    * Reads a signed long value in {@link #b b}.
772    *
773    * @param index the start index of the value to be read in {@link #b b}.
774    * @return the read value.
775    */

776
777   protected long readLong (final int index) {
778     long l1 = readInt(index);
779     long l0 = readInt(index + 4) & 0xFFFFFFFFL;
780     return (l1 << 32) | l0;
781   }
782
783   /**
784    * Reads an UTF8 constant pool item in {@link #b b}.
785    *
786    * @param index the start index of an unsigned short value in {@link #b b},
787    * whose value is the index of an UTF8 constant pool item.
788    * @param buf buffer to be used to read the item. This buffer must be
789    * sufficiently large. It is not automatically resized.
790    * @return the String corresponding to the specified UTF8 item.
791    */

792
793   protected String JavaDoc readUTF8 (int index, final char[] buf) {
794     // consults cache
795
int item = readUnsignedShort(index);
796     String JavaDoc s = strings[item];
797     if (s != null) {
798       return s;
799     }
800     // computes the start index of the CONSTANT_Utf8 item in b
801
index = items[item];
802     // reads the length of the string (in bytes, not characters)
803
int utfLen = readUnsignedShort(index);
804     index += 2;
805     // parses the string bytes
806
int endIndex = index + utfLen;
807     byte[] b = this.b;
808     int strLen = 0;
809     int c, d, e;
810     while (index < endIndex) {
811       c = b[index++] & 0xFF;
812       switch (c >> 4) {
813         case 0:
814         case 1:
815         case 2:
816         case 3:
817         case 4:
818         case 5:
819         case 6:
820         case 7:
821           // 0xxxxxxx
822
buf[strLen++] = (char)c;
823           break;
824         case 12:
825         case 13:
826           // 110x xxxx 10xx xxxx
827
d = b[index++];
828           buf[strLen++] = (char)(((c & 0x1F) << 6) | (d & 0x3F));
829           break;
830         default:
831           // 1110 xxxx 10xx xxxx 10xx xxxx
832
d = b[index++];
833           e = b[index++];
834           buf[strLen++] =
835             (char)(((c & 0x0F) << 12) | ((d & 0x3F) << 6) | (e & 0x3F));
836           break;
837       }
838     }
839     s = new String JavaDoc(buf, 0, strLen);
840     strings[item] = s;
841     return s;
842   }
843
844   /**
845    * Reads a class constant pool item in {@link #b b}.
846    *
847    * @param index the start index of an unsigned short value in {@link #b b},
848    * whose value is the index of a class constant pool item.
849    * @param buf buffer to be used to read the item. This buffer must be
850    * sufficiently large. It is not automatically resized.
851    * @return the String corresponding to the specified class item.
852    */

853
854   protected String JavaDoc readClass (final int index, final char[] buf) {
855     // computes the start index of the CONSTANT_Class item in b
856
// and reads the CONSTANT_Utf8 item designated by
857
// the first two bytes of this CONSTANT_Class item
858
return readUTF8(items[readUnsignedShort(index)], buf);
859   }
860
861   /**
862    * Reads a numeric or string constant pool item in {@link #b b}.
863    *
864    * @param item the index of a constant pool item.
865    * @param buf buffer to be used to read the item. This buffer must be
866    * sufficiently large. It is not automatically resized.
867    * @return the {@link java.lang.Integer Integer}, {@link java.lang.Float
868    * Float}, {@link java.lang.Long Long}, {@link java.lang.Double Double}
869    * or {@link String String} corresponding to the given constant pool
870    * item.
871    */

872
873   protected Object JavaDoc readConst (final int item, final char[] buf) {
874     int index = items[item];
875     switch (b[index - 1]) {
876       case ClassWriter.INT:
877         return new Integer JavaDoc(readInt(index));
878       case ClassWriter.FLOAT:
879         return new Float JavaDoc(Float.intBitsToFloat(readInt(index)));
880       case ClassWriter.LONG:
881         return new Long JavaDoc(readLong(index));
882       case ClassWriter.DOUBLE:
883         return new Double JavaDoc(Double.longBitsToDouble(readLong(index)));
884       //case ClassWriter.STR:
885
default:
886         return readUTF8(index, buf);
887     }
888   }
889
890   /**
891    * Reads an attribute in {@link #b b}. The default implementation of this
892    * method returns instances of the {@link Attribute} class for all attributes.
893    *
894    * @param type the type of the attribute.
895    * @param off the first byte of the attribute's content in {@link #b b}. The
896    * 6 attribute header bytes, containing the type and the length of the
897    * attribute, are not taken into account here (they have already been
898    * read).
899    * @param len the length of the attribute's content.
900    * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, {@link
901    * #readClass readClass} or {@link #readConst readConst}.
902    * @return the attribute that has been read.
903    */

904
905   protected Attribute readAttribute (
906     final String JavaDoc type,
907     final int off,
908     final int len,
909     final char[] buf)
910   {
911     return new Attribute(type, b, off, len);
912   }
913 }
914
Popular Tags