001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.bytecode;
031:
032: import com.caucho.util.*;
033: import com.caucho.vfs.*;
034:
035: import java.util.logging.Level;
036: import java.util.logging.Logger;
037:
038: import java.io.*;
039:
040: /**
041: * Scans for matching classes.
042: */
043: public class ByteCodeClassScanner {
044: static private final Logger log = Logger
045: .getLogger(ByteCodeClassScanner.class.getName());
046: static private final L10N L = new L10N(ByteCodeClassScanner.class);
047:
048: private final String _className;
049:
050: private final InputStream _is;
051:
052: private final ByteCodeClassMatcher _matcher;
053:
054: private CharBuffer _cb = new CharBuffer();
055:
056: public ByteCodeClassScanner(String className, InputStream is,
057: ByteCodeClassMatcher matcher) {
058: _className = className;
059:
060: _is = is;
061:
062: _matcher = matcher;
063: }
064:
065: public boolean scan() {
066: try {
067: int magic = readInt();
068:
069: if (magic != JavaClass.MAGIC)
070: throw error(L.l("bad magic number in class file"));
071:
072: _is.skip(2); // major
073: _is.skip(2); // minor
074:
075: return parseConstantPool();
076: } catch (Exception e) {
077: log.log(Level.WARNING, "failed scanning class "
078: + _className + "\n" + e.toString(), e);
079:
080: return false;
081: }
082: }
083:
084: /**
085: * Parses the constant pool.
086: */
087: public boolean parseConstantPool() throws IOException {
088: int count = readShort();
089:
090: int i = 1;
091: while (i < count) {
092: int code = _is.read();
093:
094: if (code == ByteCodeParser.CP_LONG
095: || code == ByteCodeParser.CP_DOUBLE)
096: i += 2;
097: else
098: i += 1;
099:
100: switch (code) {
101: case ByteCodeParser.CP_CLASS:
102: // int utf8Index = readShort();
103:
104: _is.skip(2);
105: break;
106:
107: case ByteCodeParser.CP_FIELD_REF:
108: // int classIndex = readShort();
109: // int nameAndTypeIndex = readShort();
110:
111: _is.skip(4);
112: break;
113:
114: case ByteCodeParser.CP_METHOD_REF:
115: // int classIndex = readShort();
116: // int nameAndTypeIndex = readShort();
117:
118: _is.skip(4);
119: break;
120:
121: case ByteCodeParser.CP_INTERFACE_METHOD_REF:
122: // int classIndex = readShort();
123: // int nameAndTypeIndex = readShort();
124:
125: _is.skip(4);
126: break;
127:
128: case ByteCodeParser.CP_STRING:
129: // int stringIndex = readShort();
130:
131: _is.skip(2);
132: break;
133:
134: case ByteCodeParser.CP_INTEGER:
135: _is.skip(4);
136: break;
137:
138: case ByteCodeParser.CP_FLOAT:
139: _is.skip(4);
140: break;
141:
142: case ByteCodeParser.CP_LONG:
143: _is.skip(8);
144: break;
145:
146: case ByteCodeParser.CP_DOUBLE:
147: _is.skip(8);
148: break;
149:
150: case ByteCodeParser.CP_NAME_AND_TYPE:
151: // int nameIndex = readShort();
152: // int descriptorIndex = readShort();
153:
154: _is.skip(4);
155: break;
156:
157: case ByteCodeParser.CP_UTF8: {
158: int length = readShort();
159:
160: if (parseUtf8ForAnnotation(_cb, length)) {
161: if (_matcher.isMatch(_cb))
162: return true;
163: }
164:
165: break;
166: }
167:
168: default:
169: throw error(L
170: .l("'{0}' is an unknown constant pool type.",
171: code));
172: }
173: }
174:
175: return false;
176: }
177:
178: /**
179: * Parses the UTF.
180: */
181: private boolean parseUtf8ForAnnotation(CharBuffer cb, int len)
182: throws IOException {
183: InputStream is = _is;
184:
185: int ch = is.read();
186: len -= 1;
187:
188: // only scan annotations
189: if (ch != 'L') {
190: is.skip(len);
191: return false;
192: }
193:
194: cb.ensureCapacity(len);
195:
196: char[] cBuf = cb.getBuffer();
197: int cLen = 0;
198:
199: while (len > 0) {
200: int d1 = is.read();
201:
202: if (d1 == '/') {
203: cBuf[cLen++] = '.';
204:
205: len--;
206: } else if (d1 < 0x80) {
207: cBuf[cLen++] = (char) d1;
208:
209: len--;
210: } else if (d1 < 0xe0) {
211: int d2 = is.read() & 0x3f;
212:
213: cBuf[cLen++] = (char) (((d1 & 0x1f) << 6) + (d2));
214:
215: len -= 2;
216: } else if (d1 < 0xf0) {
217: int d2 = is.read() & 0x3f;
218: int d3 = is.read() & 0x3f;
219:
220: cBuf[cLen++] = (char) (((d1 & 0xf) << 12) + (d2 << 6) + d3);
221:
222: len -= 3;
223: } else
224: throw new IllegalStateException();
225: }
226:
227: if (cLen > 0 && cBuf[cLen - 1] == ';') {
228: cb.setLength(cLen - 1);
229:
230: return true;
231: } else
232: return false;
233: }
234:
235: /**
236: * Parses a 32-bit int.
237: */
238: private int readInt() throws IOException {
239: return ((_is.read() << 24) | (_is.read() << 16)
240: | (_is.read() << 8) | (_is.read()));
241: }
242:
243: /**
244: * Parses a 16-bit int.
245: */
246: private int readShort() throws IOException {
247: int c1 = _is.read();
248: int c2 = _is.read();
249:
250: return ((c1 << 8) | c2);
251: }
252:
253: /**
254: * Returns an error message.
255: */
256: private IllegalStateException error(String message) {
257: return new IllegalStateException(_className + ": " + message);
258: }
259: }
|