001: /*
002: * ProGuard -- shrinking, optimization, obfuscation, and preverification
003: * of Java bytecode.
004: *
005: * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
006: *
007: * This library is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the Free
009: * Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This library is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
015: * more details.
016: *
017: * You should have received a copy of the GNU General Public License along
018: * with this library; if not, write to the Free Software Foundation, Inc.,
019: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: package proguard.classfile.io;
022:
023: import proguard.classfile.*;
024: import proguard.classfile.constant.*;
025: import proguard.classfile.constant.visitor.ConstantVisitor;
026: import proguard.classfile.util.*;
027: import proguard.classfile.visitor.*;
028:
029: import java.io.DataInput;
030:
031: /**
032: * This ClassVisitor fills out the LibraryClass objects that it visits with data
033: * from the given DataInput object.
034: *
035: * @author Eric Lafortune
036: */
037: public class LibraryClassReader extends SimplifiedVisitor implements
038: ClassVisitor, MemberVisitor, ConstantVisitor {
039: private static final LibraryField[] EMPTY_LIBRARY_FIELDS = new LibraryField[0];
040: private static final LibraryMethod[] EMPTY_LIBRARY_METHODS = new LibraryMethod[0];
041:
042: private final RuntimeDataInput dataInput;
043: private final boolean skipNonPublicClasses;
044: private final boolean skipNonPublicClassMembers;
045:
046: // A global array that acts as a parameter for the visitor methods.
047: private Constant[] constantPool;
048:
049: /**
050: * Creates a new ProgramClassReader for reading from the given DataInput.
051: */
052: public LibraryClassReader(DataInput dataInput,
053: boolean skipNonPublicClasses,
054: boolean skipNonPublicClassMembers) {
055: this .dataInput = new RuntimeDataInput(dataInput);
056: this .skipNonPublicClasses = skipNonPublicClasses;
057: this .skipNonPublicClassMembers = skipNonPublicClassMembers;
058: }
059:
060: // Implementations for ClassVisitor.
061:
062: public void visitProgramClass(ProgramClass libraryClass) {
063: }
064:
065: public void visitLibraryClass(LibraryClass libraryClass) {
066: // Read and check the magic number.
067: int u4magic = dataInput.readInt();
068:
069: ClassUtil.checkMagicNumber(u4magic);
070:
071: // Read and check the version numbers.
072: int u2minorVersion = dataInput.readUnsignedShort();
073: int u2majorVersion = dataInput.readUnsignedShort();
074:
075: int u4version = ClassUtil.internalClassVersion(u2majorVersion,
076: u2minorVersion);
077:
078: ClassUtil.checkVersionNumbers(u4version);
079:
080: // Read the constant pool. Note that the first entry is not used.
081: int u2constantPoolCount = dataInput.readUnsignedShort();
082:
083: // Create the constant pool array.
084: constantPool = new Constant[u2constantPoolCount];
085:
086: for (int index = 1; index < u2constantPoolCount; index++) {
087: Constant constant = createConstant();
088: constant.accept(libraryClass, this );
089:
090: int tag = constant.getTag();
091: if (tag == ClassConstants.CONSTANT_Class
092: || tag == ClassConstants.CONSTANT_Utf8) {
093: constantPool[index] = constant;
094: }
095:
096: // Long constants and double constants take up two entries in the
097: // constant pool.
098: if (tag == ClassConstants.CONSTANT_Long
099: || tag == ClassConstants.CONSTANT_Double) {
100: index++;
101: }
102: }
103:
104: // Read the general class information.
105: libraryClass.u2accessFlags = dataInput.readUnsignedShort();
106:
107: // We may stop parsing this library class if it's not public anyway.
108: // E.g. only about 60% of all rt.jar classes need to be parsed.
109: if (skipNonPublicClasses
110: && AccessUtil
111: .accessLevel(libraryClass.getAccessFlags()) < AccessUtil.PUBLIC) {
112: return;
113: }
114:
115: // Read the class and super class indices.
116: int u2this Class = dataInput.readUnsignedShort();
117: int u2super Class = dataInput.readUnsignedShort();
118:
119: // Store their actual names.
120: libraryClass.this ClassName = getClassName(u2this Class);
121: libraryClass.super ClassName = (u2super Class == 0) ? null
122: : getClassName(u2super Class);
123:
124: // Read the interfaces
125: int u2interfacesCount = dataInput.readUnsignedShort();
126:
127: libraryClass.interfaceNames = new String[u2interfacesCount];
128: for (int index = 0; index < u2interfacesCount; index++) {
129: // Store the actual interface name.
130: int u2interface = dataInput.readUnsignedShort();
131: libraryClass.interfaceNames[index] = getClassName(u2interface);
132: }
133:
134: // Read the fields.
135: int u2fieldsCount = dataInput.readUnsignedShort();
136:
137: // Create the fields array.
138: LibraryField[] reusableFields = new LibraryField[u2fieldsCount];
139:
140: int visibleFieldsCount = 0;
141: for (int index = 0; index < u2fieldsCount; index++) {
142: LibraryField field = new LibraryField();
143: this .visitLibraryMember(libraryClass, field);
144:
145: // Only store fields that are visible.
146: if (AccessUtil.accessLevel(field.getAccessFlags()) >= (skipNonPublicClassMembers ? AccessUtil.PROTECTED
147: : AccessUtil.PACKAGE_VISIBLE)) {
148: reusableFields[visibleFieldsCount++] = field;
149: }
150: }
151:
152: // Copy the visible fields (if any) into a fields array of the right size.
153: if (visibleFieldsCount == 0) {
154: libraryClass.fields = EMPTY_LIBRARY_FIELDS;
155: } else {
156: libraryClass.fields = new LibraryField[visibleFieldsCount];
157: System.arraycopy(reusableFields, 0, libraryClass.fields, 0,
158: visibleFieldsCount);
159: }
160:
161: // Read the methods.
162: int u2methodsCount = dataInput.readUnsignedShort();
163:
164: // Create the methods array.
165: LibraryMethod[] reusableMethods = new LibraryMethod[u2methodsCount];
166:
167: int visibleMethodsCount = 0;
168: for (int index = 0; index < u2methodsCount; index++) {
169: LibraryMethod method = new LibraryMethod();
170: this .visitLibraryMember(libraryClass, method);
171:
172: // Only store methods that are visible.
173: if (AccessUtil.accessLevel(method.getAccessFlags()) >= (skipNonPublicClassMembers ? AccessUtil.PROTECTED
174: : AccessUtil.PACKAGE_VISIBLE)) {
175: reusableMethods[visibleMethodsCount++] = method;
176: }
177: }
178:
179: // Copy the visible methods (if any) into a methods array of the right size.
180: if (visibleMethodsCount == 0) {
181: libraryClass.methods = EMPTY_LIBRARY_METHODS;
182: } else {
183: libraryClass.methods = new LibraryMethod[visibleMethodsCount];
184: System.arraycopy(reusableMethods, 0, libraryClass.methods,
185: 0, visibleMethodsCount);
186: }
187:
188: // Skip the class attributes.
189: skipAttributes();
190: }
191:
192: // Implementations for MemberVisitor.
193:
194: public void visitProgramMember(ProgramClass libraryClass,
195: ProgramMember libraryMember) {
196: }
197:
198: public void visitLibraryMember(LibraryClass libraryClass,
199: LibraryMember libraryMember) {
200: // Read the general field information.
201: libraryMember.u2accessFlags = dataInput.readUnsignedShort();
202: libraryMember.name = getString(dataInput.readUnsignedShort());
203: libraryMember.descriptor = getString(dataInput
204: .readUnsignedShort());
205:
206: // Skip the field attributes.
207: skipAttributes();
208: }
209:
210: // Implementations for ConstantVisitor.
211:
212: public void visitIntegerConstant(Clazz clazz,
213: IntegerConstant integerConstant) {
214: dataInput.skipBytes(4);
215: }
216:
217: public void visitLongConstant(Clazz clazz, LongConstant longConstant) {
218: dataInput.skipBytes(8);
219: }
220:
221: public void visitFloatConstant(Clazz clazz,
222: FloatConstant floatConstant) {
223: dataInput.skipBytes(4);
224: }
225:
226: public void visitDoubleConstant(Clazz clazz,
227: DoubleConstant doubleConstant) {
228: dataInput.skipBytes(8);
229: }
230:
231: public void visitStringConstant(Clazz clazz,
232: StringConstant stringConstant) {
233: dataInput.skipBytes(2);
234: }
235:
236: public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) {
237: int u2length = dataInput.readUnsignedShort();
238:
239: // Read the UTF-8 bytes.
240: byte[] bytes = new byte[u2length];
241: dataInput.readFully(bytes);
242: utf8Constant.setBytes(bytes);
243: }
244:
245: public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) {
246: dataInput.skipBytes(4);
247: }
248:
249: public void visitClassConstant(Clazz clazz,
250: ClassConstant classConstant) {
251: classConstant.u2nameIndex = dataInput.readUnsignedShort();
252: }
253:
254: public void visitNameAndTypeConstant(Clazz clazz,
255: NameAndTypeConstant nameAndTypeConstant) {
256: dataInput.skipBytes(4);
257: }
258:
259: // Small utility methods.
260:
261: /**
262: * Returns the class name of the ClassConstant at the specified index in the
263: * reusable constant pool.
264: */
265: private String getClassName(int constantIndex) {
266: ClassConstant classEntry = (ClassConstant) constantPool[constantIndex];
267:
268: return getString(classEntry.u2nameIndex);
269: }
270:
271: /**
272: * Returns the string of the Utf8Constant at the specified index in the
273: * reusable constant pool.
274: */
275: private String getString(int constantIndex) {
276: return ((Utf8Constant) constantPool[constantIndex]).getString();
277: }
278:
279: private Constant createConstant() {
280: int u1tag = dataInput.readUnsignedByte();
281:
282: switch (u1tag) {
283: case ClassConstants.CONSTANT_Utf8:
284: return new Utf8Constant();
285: case ClassConstants.CONSTANT_Integer:
286: return new IntegerConstant();
287: case ClassConstants.CONSTANT_Float:
288: return new FloatConstant();
289: case ClassConstants.CONSTANT_Long:
290: return new LongConstant();
291: case ClassConstants.CONSTANT_Double:
292: return new DoubleConstant();
293: case ClassConstants.CONSTANT_String:
294: return new StringConstant();
295: case ClassConstants.CONSTANT_Fieldref:
296: return new FieldrefConstant();
297: case ClassConstants.CONSTANT_Methodref:
298: return new MethodrefConstant();
299: case ClassConstants.CONSTANT_InterfaceMethodref:
300: return new InterfaceMethodrefConstant();
301: case ClassConstants.CONSTANT_Class:
302: return new ClassConstant();
303: case ClassConstants.CONSTANT_NameAndType:
304: return new NameAndTypeConstant();
305:
306: default:
307: throw new RuntimeException("Unknown constant type ["
308: + u1tag + "] in constant pool");
309: }
310: }
311:
312: private void skipAttributes() {
313: int u2attributesCount = dataInput.readUnsignedShort();
314:
315: for (int index = 0; index < u2attributesCount; index++) {
316: skipAttribute();
317: }
318: }
319:
320: private void skipAttribute() {
321: dataInput.skipBytes(2);
322: int u4attributeLength = dataInput.readInt();
323: dataInput.skipBytes(u4attributeLength);
324: }
325: }
|