KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > bytecode > ByteCodeClassScanner


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.bytecode;
31
32 import com.caucho.log.Log;
33 import com.caucho.util.CharBuffer;
34 import com.caucho.util.L10N;
35
36 import java.util.logging.Level JavaDoc;
37 import java.util.logging.Logger JavaDoc;
38
39 /**
40  * Scans for matching classes.
41  */

42 public class ByteCodeClassScanner {
43   static private final Logger JavaDoc log = Log.open(ByteCodeClassScanner.class);
44   static private final L10N L = new L10N(ByteCodeClassScanner.class);
45
46   private final String JavaDoc _className;
47
48   private final byte []_buffer;
49   private final int _length;
50
51   private final ByteCodeClassMatcher _matcher;
52
53   private int []_cpOffset = new int[256];
54   private int _index;
55
56   private CharBuffer _cb = new CharBuffer();
57
58   public ByteCodeClassScanner(String JavaDoc className,
59                   byte []buffer, int offset, int length,
60                   ByteCodeClassMatcher matcher)
61   {
62     _className = className;
63     
64     _buffer = buffer;
65     _index = offset;
66     _length = length;
67
68     _matcher = matcher;
69   }
70
71   public boolean scan()
72   {
73     try {
74       int magic = readInt();
75
76       if (magic != JavaClass.MAGIC)
77     throw error(L.l("bad magic number in class file"));
78
79       int minor = readShort();
80       int major = readShort();
81
82       parseConstantPool();
83
84       int accessFlags = readShort();
85       int thisClassIndex = readShort();
86
87       String JavaDoc thisName = parseClass(thisClassIndex).toString();
88
89       if (_matcher.isClassMatch(thisName))
90     return true;
91     
92       int superClassIndex = readShort();
93
94       int interfaceCount = readShort();
95       for (int i = 0; i < interfaceCount; i++) {
96     int classIndex = readShort();
97       }
98
99       int fieldCount = readShort();
100       for (int i = 0; i < fieldCount; i++) {
101     if (parseField())
102       return true;
103       }
104
105       int methodCount = readShort();
106       for (int i = 0; i < methodCount; i++) {
107     if (parseMethod())
108       return true;
109       }
110
111       int attrCount = readShort();
112       for (int i = 0; i < attrCount; i++) {
113     if (parseAttribute())
114       return true;
115       }
116
117       return false;
118     } catch (Exception JavaDoc e) {
119       log.warning("failed scanning class " + _className);
120       log.log(Level.WARNING, e.toString(), e);
121
122       return false;
123     }
124   }
125
126   /**
127    * Parses the constant pool.
128    */

129   public boolean parseConstantPool()
130   {
131     int count = readShort();
132
133     int i = 1;
134     while (i < count) {
135       int code = read();
136       
137       parseConstantPoolEntry(code, i);
138
139       if (code == ByteCodeParser.CP_LONG || code == ByteCodeParser.CP_DOUBLE)
140     i += 2;
141       else
142     i += 1;
143     }
144
145     /*
146     for (i = 1; i < count; i++) {
147       int offset = _cpOffset[i];
148
149       if (offset == 0)
150     continue;
151
152       int code = _buffer[offset];
153
154       if (code == ByteCodeParser.CP_CLASS) {
155     int nameIndex = ((_buffer[offset + 1] & 0xff) * 256 +
156              (_buffer[offset + 2] & 0xff));
157
158     CharBuffer name = parseUTF8(nameIndex);
159
160     if (_matcher.isMatch(name))
161       return true;
162       }
163     }
164     */

165
166     return false;
167   }
168
169   /**
170    * Parses a constant pool entry.
171    */

172   private boolean parseConstantPoolEntry(int tag, int i)
173   {
174     switch (tag) {
175     case ByteCodeParser.CP_CLASS:
176       {
177     if (_cpOffset.length <= i) {
178       int []offset = new int[2 * i];
179       System.arraycopy(_cpOffset, 0, offset, 0, _cpOffset.length);
180       _cpOffset = offset;
181     }
182     
183     _cpOffset[i] = _index - 1;
184
185     _index += 2;
186
187     return false;
188       }
189       
190     case ByteCodeParser.CP_FIELD_REF:
191       {
192     // int classIndex = readShort();
193
// int nameAndTypeIndex = readShort();
194

195     _index += 4;
196
197     return false;
198       }
199       
200     case ByteCodeParser.CP_METHOD_REF:
201       {
202     // int classIndex = readShort();
203
// int nameAndTypeIndex = readShort();
204

205     _index += 4;
206     
207     return false;
208       }
209       
210     case ByteCodeParser.CP_INTERFACE_METHOD_REF:
211       {
212     // int classIndex = readShort();
213
// int nameAndTypeIndex = readShort();
214

215     _index += 4;
216     
217     return false;
218       }
219       
220     case ByteCodeParser.CP_STRING:
221       {
222     // int stringIndex = readShort();
223

224     _index += 2;
225
226     return false;
227       }
228       
229     case ByteCodeParser.CP_INTEGER:
230       {
231     _index += 4;
232
233     return false;
234       }
235       
236     case ByteCodeParser.CP_FLOAT:
237       {
238     _index += 4;
239
240     return false;
241       }
242       
243     case ByteCodeParser.CP_LONG:
244       {
245     _index += 8;
246
247     return false;
248       }
249       
250     case ByteCodeParser.CP_DOUBLE:
251       {
252     _index += 8;
253
254     return false;
255       }
256       
257     case ByteCodeParser.CP_NAME_AND_TYPE:
258       {
259     // int nameIndex = readShort();
260
// int descriptorIndex = readShort();
261

262     _index += 4;
263
264     return false;
265       }
266       
267     case ByteCodeParser.CP_UTF8:
268       {
269     if (_cpOffset.length <= i) {
270       int []offset = new int[2 * i + 1];
271       System.arraycopy(_cpOffset, 0, offset, 0, _cpOffset.length);
272       _cpOffset = offset;
273     }
274     
275     _cpOffset[i] = _index - 1;
276     
277     int length = readShort();
278
279     _index += length;
280
281     return false;
282       }
283
284     default:
285       throw error(L.l("'{0}' is an unknown constant pool type.",
286               tag));
287     }
288   }
289
290   /**
291    * Parses a field entry.
292    */

293   private boolean parseField()
294   {
295     int accessFlags = readShort();
296     int nameIndex = readShort();
297     int descriptorIndex = readShort();
298
299     int attributesCount = readShort();
300
301     for (int i = 0; i < attributesCount; i++) {
302       if (parseAttribute())
303     return true;
304     }
305
306     return false;
307   }
308
309   /**
310    * Parses a method entry.
311    */

312   private boolean parseMethod()
313   {
314     int accessFlags = readShort();
315     int nameIndex = readShort();
316     int descriptorIndex = readShort();
317
318     int attributesCount = readShort();
319     for (int i = 0; i < attributesCount; i++) {
320       if (parseAttribute())
321     return true;
322     }
323
324     return false;
325   }
326
327   /**
328    * Parses an attribute.
329    */

330   boolean parseAttribute()
331   {
332     int nameIndex = readShort();
333
334     int length = readInt();
335     int start = _index;
336
337     CharBuffer name = parseUTF8(nameIndex, 0);
338
339     if (name != null && name.matches("RuntimeVisibleAnnotations")) {
340       int n = readShort();
341
342       for (int i = 0; i < n; i++) {
343     if (parseAttributeImpl())
344       return true;
345       }
346     }
347     
348     _index = start + length;
349
350     return false;
351     
352     /*
353     String name = _cp.getUtf8(nameIndex).getValue();
354
355     if (name.equals("Code")) {
356       CodeAttribute code = new CodeAttribute(name);
357       code.read(this);
358       return code;
359     }
360     else if (name.equals("Exceptions")) {
361       ExceptionsAttribute code = new ExceptionsAttribute(name);
362       code.read(this);
363       return code;
364     }
365     */

366     
367   }
368
369   /**
370    * Parses an attribute.
371    */

372   private boolean parseAttributeImpl()
373   {
374     int type = readShort();
375
376     CharBuffer name = name = parseUTF8(type, 1);
377     name.setLength(name.length() - 1);
378
379     if (_matcher.isMatch(name))
380       return true;
381       
382     int nPairs = readShort();
383     for (int j = 0; j < nPairs; j++) {
384       int valueName = readShort();
385       
386       parseElementValue();
387     }
388
389     return false;
390   }
391
392   private void parseElementValue()
393   {
394     int tag = read();
395
396     switch (tag) {
397     case 's':
398       _index += 2;
399       break;
400     case 'e':
401       _index += 4;
402       break;
403     case 'c':
404       _index += 2;
405       break;
406     case 'Z':
407     case 'B':
408     case 'S':
409     case 'I':
410     case 'J':
411     case 'C':
412     case 'F':
413     case 'D':
414       _index += 2;
415       break;
416     case '@':
417       // read annotation value
418
parseAttributeImpl();
419       break;
420     case '[':
421       {
422     int n = readShort();
423     for (int i = 0; i < n; i++)
424       parseElementValue();
425       }
426       break;
427     default:
428       System.out.println("UNKNOWN: " + (char) tag);
429       throw new IllegalStateException JavaDoc();
430     }
431   }
432
433   /**
434    * Parses the UTF, specifically the class.
435    */

436   private CharBuffer parseClass(int index)
437   {
438     int offset = _cpOffset[index] + 1;
439
440     return parseUTF8((_buffer[offset] & 0xff) * 256 +
441              (_buffer[offset + 1] & 0xff),
442              0);
443   }
444   
445   /**
446    * Parses the UTF, specifically the class.
447    */

448   private CharBuffer parseUTF8(int index, int skip)
449   {
450     int offset = _cpOffset[index] + 1;
451
452     byte []bBuf = _buffer;
453     
454     int len = ((bBuf[offset] & 0xff) << 8) + (bBuf[offset + 1] & 0xff);
455
456     _cb.ensureCapacity(len);
457
458     offset += 2;
459     int end = offset + len;
460
461     char []cBuf = _cb.getBuffer();
462     int cLen = -skip;
463
464     while (offset < end) {
465       int d1 = bBuf[offset] & 0xff;
466
467       if (d1 < 0x80) {
468     if (d1 == '/')
469       d1 = '.';
470
471     if (cLen < 0)
472       cLen++;
473     else
474       cBuf[cLen++] = (char) d1;
475
476     offset++;
477       }
478       else if (d1 < 0xe0) {
479     int d2 = bBuf[offset + 1] & 0x3f;
480
481     if (cLen < 0)
482       cLen++;
483     else
484       cBuf[cLen++] = (char) (((d1 & 0x1f) << 6) +
485                  ((d2)));
486
487     offset += 2;
488       }
489       else if (d1 < 0xf0) {
490     int d2 = bBuf[offset + 1] & 0x3f;
491     int d3 = bBuf[offset + 1] & 0x3f;
492
493     if (cLen < 0)
494       cLen++;
495     else
496       cBuf[cLen++] = (char) (((d1 & 0xf) << 12) +
497                  ((d2 << 6)) +
498                  ((d3)));
499
500     offset += 2;
501       }
502       else
503     throw new IllegalStateException JavaDoc();
504     }
505     
506     _cb.setLength(cLen);
507     
508     return _cb;
509   }
510
511   /**
512    * Parses a 64-bit int.
513    */

514   private long readLong()
515   {
516     return (((long) read() << 56) |
517         ((long) read() << 48) |
518         ((long) read() << 40) |
519         ((long) read() << 32) |
520         ((long) read() << 24) |
521         ((long) read() << 16) |
522         ((long) read() << 8) |
523         ((long) read()));
524   }
525
526   /**
527    * Parses a 32-bit int.
528    */

529   private int readInt()
530   {
531     return ((read() << 24) |
532         (read() << 16) |
533         (read() << 8) |
534         (read()));
535   }
536
537   /**
538    * Parses a 16-bit int.
539    */

540   private int readShort()
541   {
542     int c1 = read();
543     int c2 = read();
544
545     return ((c1 << 8) | c2);
546   }
547
548   /**
549    * Reads the next byte.
550    */

551   private int read()
552   {
553     if (_index < _length)
554       return _buffer[_index++] & 0xff;
555     else
556       return -1;
557   }
558
559   /**
560    * Returns an error message.
561    */

562   private IllegalStateException JavaDoc error(String JavaDoc message)
563   {
564     return new IllegalStateException JavaDoc(message);
565   }
566 }
567
Popular Tags