2
* ProGuard -- shrinking, optimization, obfuscation, and preverification
5
* Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
7
* This library is free software; you can redistribute it and/or modify it
8
* under the terms of the GNU General Public License as published by the Free
9
* Software Foundation; either version 2 of the License, or (at your option)
12
* This library is distributed in the hope that it will be useful, but WITHOUT
13
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17
* You should have received a copy of the GNU General Public License along
18
* with this library; if not, write to the Free Software Foundation, Inc.,
19
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
package proguard.classfile.io;
23
import proguard.classfile.*;
24
import proguard.classfile.constant.*;
25
import proguard.classfile.constant.visitor.ConstantVisitor;
26
import proguard.classfile.util.*;
27
import proguard.classfile.visitor.*;
29
import java.io.DataInput;
32
* This ClassVisitor fills out the LibraryClass objects that it visits with data
33
* from the given DataInput object.
35
* @author Eric Lafortune
37
public class LibraryClassReader
38
extends SimplifiedVisitor
39
implements ClassVisitor,
43
private static final LibraryField[] EMPTY_LIBRARY_FIELDS = new LibraryField[0];
44
private static final LibraryMethod[] EMPTY_LIBRARY_METHODS = new LibraryMethod[0];
47
private final RuntimeDataInput dataInput;
48
private final boolean skipNonPublicClasses;
49
private final boolean skipNonPublicClassMembers;
51
// A global array that acts as a parameter for the visitor methods.
52
private Constant[] constantPool;
56
* Creates a new ProgramClassReader for reading from the given DataInput.
58
public LibraryClassReader(DataInput dataInput,
59
boolean skipNonPublicClasses,
60
boolean skipNonPublicClassMembers)
62
this.dataInput = new RuntimeDataInput(dataInput);
63
this.skipNonPublicClasses = skipNonPublicClasses;
64
this.skipNonPublicClassMembers = skipNonPublicClassMembers;
68
// Implementations for ClassVisitor.
70
public void visitProgramClass(ProgramClass libraryClass)
75
public void visitLibraryClass(LibraryClass libraryClass)
77
// Read and check the magic number.
78
int u4magic = dataInput.readInt();
80
ClassUtil.checkMagicNumber(u4magic);
82
// Read and check the version numbers.
83
int u2minorVersion = dataInput.readUnsignedShort();
84
int u2majorVersion = dataInput.readUnsignedShort();
86
int u4version = ClassUtil.internalClassVersion(u2majorVersion,
89
ClassUtil.checkVersionNumbers(u4version);
91
// Read the constant pool. Note that the first entry is not used.
92
int u2constantPoolCount = dataInput.readUnsignedShort();
94
// Create the constant pool array.
95
constantPool = new Constant[u2constantPoolCount];
97
for (int index = 1; index < u2constantPoolCount; index++)
99
Constant constant = createConstant();
100
constant.accept(libraryClass, this);
102
int tag = constant.getTag();
103
if (tag == ClassConstants.CONSTANT_Class ||
104
tag == ClassConstants.CONSTANT_Utf8)
106
constantPool[index] = constant;
109
// Long constants and double constants take up two entries in the
111
if (tag == ClassConstants.CONSTANT_Long ||
112
tag == ClassConstants.CONSTANT_Double)
118
// Read the general class information.
119
libraryClass.u2accessFlags = dataInput.readUnsignedShort();
121
// We may stop parsing this library class if it's not public anyway.
122
// E.g. only about 60% of all rt.jar classes need to be parsed.
123
if (skipNonPublicClasses &&
124
AccessUtil.accessLevel(libraryClass.getAccessFlags()) < AccessUtil.PUBLIC)
129
// Read the class and super class indices.
130
int u2thisClass = dataInput.readUnsignedShort();
131
int u2superClass = dataInput.readUnsignedShort();
133
// Store their actual names.
134
libraryClass.thisClassName = getClassName(u2thisClass);
135
libraryClass.superClassName = (u2superClass == 0) ? null :
136
getClassName(u2superClass);
138
// Read the interfaces
139
int u2interfacesCount = dataInput.readUnsignedShort();
141
libraryClass.interfaceNames = new String[u2interfacesCount];
142
for (int index = 0; index < u2interfacesCount; index++)
144
// Store the actual interface name.
145
int u2interface = dataInput.readUnsignedShort();
146
libraryClass.interfaceNames[index] = getClassName(u2interface);
150
int u2fieldsCount = dataInput.readUnsignedShort();
152
// Create the fields array.
153
LibraryField[] reusableFields = new LibraryField[u2fieldsCount];
155
int visibleFieldsCount = 0;
156
for (int index = 0; index < u2fieldsCount; index++)
158
LibraryField field = new LibraryField();
159
this.visitLibraryMember(libraryClass, field);
161
// Only store fields that are visible.
162
if (AccessUtil.accessLevel(field.getAccessFlags()) >=
163
(skipNonPublicClassMembers ? AccessUtil.PROTECTED :
164
AccessUtil.PACKAGE_VISIBLE))
166
reusableFields[visibleFieldsCount++] = field;
170
// Copy the visible fields (if any) into a fields array of the right size.
171
if (visibleFieldsCount == 0)
173
libraryClass.fields = EMPTY_LIBRARY_FIELDS;
177
libraryClass.fields = new LibraryField[visibleFieldsCount];
178
System.arraycopy(reusableFields, 0, libraryClass.fields, 0, visibleFieldsCount);
182
int u2methodsCount = dataInput.readUnsignedShort();
184
// Create the methods array.
185
LibraryMethod[] reusableMethods = new LibraryMethod[u2methodsCount];
187
int visibleMethodsCount = 0;
188
for (int index = 0; index < u2methodsCount; index++)
190
LibraryMethod method = new LibraryMethod();
191
this.visitLibraryMember(libraryClass, method);
193
// Only store methods that are visible.
194
if (AccessUtil.accessLevel(method.getAccessFlags()) >=
195
(skipNonPublicClassMembers ? AccessUtil.PROTECTED :
196
AccessUtil.PACKAGE_VISIBLE))
198
reusableMethods[visibleMethodsCount++] = method;
202
// Copy the visible methods (if any) into a methods array of the right size.
203
if (visibleMethodsCount == 0)
205
libraryClass.methods = EMPTY_LIBRARY_METHODS;
209
libraryClass.methods = new LibraryMethod[visibleMethodsCount];
210
System.arraycopy(reusableMethods, 0, libraryClass.methods, 0, visibleMethodsCount);
213
// Skip the class attributes.
218
// Implementations for MemberVisitor.
220
public void visitProgramMember(ProgramClass libraryClass, ProgramMember libraryMember)
225
public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember)
227
// Read the general field information.
228
libraryMember.u2accessFlags = dataInput.readUnsignedShort();
229
libraryMember.name = getString(dataInput.readUnsignedShort());
230
libraryMember.descriptor = getString(dataInput.readUnsignedShort());
232
// Skip the field attributes.
237
// Implementations for ConstantVisitor.
239
public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
241
dataInput.skipBytes(4);
245
public void visitLongConstant(Clazz clazz, LongConstant longConstant)
247
dataInput.skipBytes(8);
251
public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
253
dataInput.skipBytes(4);
257
public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
259
dataInput.skipBytes(8);
263
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
265
dataInput.skipBytes(2);
269
public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
271
int u2length = dataInput.readUnsignedShort();
273
// Read the UTF-8 bytes.
274
byte[] bytes = new byte[u2length];
275
dataInput.readFully(bytes);
276
utf8Constant.setBytes(bytes);
280
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
282
dataInput.skipBytes(4);
286
public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
288
classConstant.u2nameIndex = dataInput.readUnsignedShort();
292
public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
294
dataInput.skipBytes(4);
298
// Small utility methods.
301
* Returns the class name of the ClassConstant at the specified index in the
302
* reusable constant pool.
304
private String getClassName(int constantIndex)
306
ClassConstant classEntry = (ClassConstant)constantPool[constantIndex];
308
return getString(classEntry.u2nameIndex);
313
* Returns the string of the Utf8Constant at the specified index in the
314
* reusable constant pool.
316
private String getString(int constantIndex)
318
return ((Utf8Constant)constantPool[constantIndex]).getString();
322
private Constant createConstant()
324
int u1tag = dataInput.readUnsignedByte();
328
case ClassConstants.CONSTANT_Utf8: return new Utf8Constant();
329
case ClassConstants.CONSTANT_Integer: return new IntegerConstant();
330
case ClassConstants.CONSTANT_Float: return new FloatConstant();
331
case ClassConstants.CONSTANT_Long: return new LongConstant();
332
case ClassConstants.CONSTANT_Double: return new DoubleConstant();
333
case ClassConstants.CONSTANT_String: return new StringConstant();
334
case ClassConstants.CONSTANT_Fieldref: return new FieldrefConstant();
335
case ClassConstants.CONSTANT_Methodref: return new MethodrefConstant();
336
case ClassConstants.CONSTANT_InterfaceMethodref: return new InterfaceMethodrefConstant();
337
case ClassConstants.CONSTANT_Class: return new ClassConstant();
338
case ClassConstants.CONSTANT_NameAndType: return new NameAndTypeConstant();
340
default: throw new RuntimeException("Unknown constant type ["+u1tag+"] in constant pool");
345
private void skipAttributes()
347
int u2attributesCount = dataInput.readUnsignedShort();
349
for (int index = 0; index < u2attributesCount; index++)
356
private void skipAttribute()
358
dataInput.skipBytes(2);
359
int u4attributeLength = dataInput.readInt();
360
dataInput.skipBytes(u4attributeLength);