• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program 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)
10  * any later version.
11  *
12  * This program 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
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 package proguard.classfile.io;
22 
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.*;
28 
29 import java.io.DataInput;
30 
31 /**
32  * This ClassVisitor fills out the LibraryClass objects that it visits with data
33  * from the given DataInput object.
34  *
35  * @author Eric Lafortune
36  */
37 public class LibraryClassReader
38 extends      SimplifiedVisitor
39 implements   ClassVisitor,
40              MemberVisitor,
41              ConstantVisitor
42 {
43     private static final LibraryField[]  EMPTY_LIBRARY_FIELDS  = new LibraryField[0];
44     private static final LibraryMethod[] EMPTY_LIBRARY_METHODS = new LibraryMethod[0];
45 
46 
47     private final RuntimeDataInput dataInput;
48     private final boolean          skipNonPublicClasses;
49     private final boolean          skipNonPublicClassMembers;
50 
51     // A global array that acts as a parameter for the visitor methods.
52     private Constant[]      constantPool;
53 
54 
55     /**
56      * Creates a new ProgramClassReader for reading from the given DataInput.
57      */
LibraryClassReader(DataInput dataInput, boolean skipNonPublicClasses, boolean skipNonPublicClassMembers)58     public LibraryClassReader(DataInput dataInput,
59                               boolean   skipNonPublicClasses,
60                               boolean   skipNonPublicClassMembers)
61     {
62         this.dataInput                 = new RuntimeDataInput(dataInput);
63         this.skipNonPublicClasses      = skipNonPublicClasses;
64         this.skipNonPublicClassMembers = skipNonPublicClassMembers;
65     }
66 
67 
68     // Implementations for ClassVisitor.
69 
visitProgramClass(ProgramClass libraryClass)70     public void visitProgramClass(ProgramClass libraryClass)
71     {
72     }
73 
74 
visitLibraryClass(LibraryClass libraryClass)75     public void visitLibraryClass(LibraryClass libraryClass)
76     {
77         // Read and check the magic number.
78         int u4magic = dataInput.readInt();
79 
80         ClassUtil.checkMagicNumber(u4magic);
81 
82         // Read and check the version numbers.
83         int u2minorVersion = dataInput.readUnsignedShort();
84         int u2majorVersion = dataInput.readUnsignedShort();
85 
86         int u4version = ClassUtil.internalClassVersion(u2majorVersion,
87                                                        u2minorVersion);
88 
89         ClassUtil.checkVersionNumbers(u4version);
90 
91         // Read the constant pool. Note that the first entry is not used.
92         int u2constantPoolCount = dataInput.readUnsignedShort();
93 
94         // Create the constant pool array.
95         constantPool = new Constant[u2constantPoolCount];
96 
97         for (int index = 1; index < u2constantPoolCount; index++)
98         {
99             Constant constant = createConstant();
100             constant.accept(libraryClass, this);
101 
102             int tag = constant.getTag();
103             if (tag == ClassConstants.CONSTANT_Class ||
104                 tag == ClassConstants.CONSTANT_Utf8)
105             {
106                 constantPool[index] = constant;
107             }
108 
109             // Long constants and double constants take up two entries in the
110             // constant pool.
111             if (tag == ClassConstants.CONSTANT_Long ||
112                 tag == ClassConstants.CONSTANT_Double)
113             {
114                 index++;
115             }
116         }
117 
118         // Read the general class information.
119         libraryClass.u2accessFlags = dataInput.readUnsignedShort();
120 
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)
125         {
126             return;
127         }
128 
129         // Read the class and super class indices.
130         int u2thisClass  = dataInput.readUnsignedShort();
131         int u2superClass = dataInput.readUnsignedShort();
132 
133         // Store their actual names.
134         libraryClass.thisClassName  = getClassName(u2thisClass);
135         libraryClass.superClassName = (u2superClass == 0) ? null :
136                                       getClassName(u2superClass);
137 
138         // Read the interfaces
139         int u2interfacesCount = dataInput.readUnsignedShort();
140 
141         libraryClass.interfaceNames = new String[u2interfacesCount];
142         for (int index = 0; index < u2interfacesCount; index++)
143         {
144             // Store the actual interface name.
145             int u2interface = dataInput.readUnsignedShort();
146             libraryClass.interfaceNames[index] = getClassName(u2interface);
147         }
148 
149         // Read the fields.
150         int u2fieldsCount = dataInput.readUnsignedShort();
151 
152         // Create the fields array.
153         LibraryField[] reusableFields = new LibraryField[u2fieldsCount];
154 
155         int visibleFieldsCount = 0;
156         for (int index = 0; index < u2fieldsCount; index++)
157         {
158             LibraryField field = new LibraryField();
159             this.visitLibraryMember(libraryClass, field);
160 
161             // Only store fields that are visible.
162             if (AccessUtil.accessLevel(field.getAccessFlags()) >=
163                 (skipNonPublicClassMembers ? AccessUtil.PROTECTED :
164                                              AccessUtil.PACKAGE_VISIBLE))
165             {
166                 reusableFields[visibleFieldsCount++] = field;
167             }
168         }
169 
170         // Copy the visible fields (if any) into a fields array of the right size.
171         if (visibleFieldsCount == 0)
172         {
173             libraryClass.fields = EMPTY_LIBRARY_FIELDS;
174         }
175         else
176         {
177             libraryClass.fields = new LibraryField[visibleFieldsCount];
178             System.arraycopy(reusableFields, 0, libraryClass.fields, 0, visibleFieldsCount);
179         }
180 
181         // Read the methods.
182         int u2methodsCount = dataInput.readUnsignedShort();
183 
184         // Create the methods array.
185         LibraryMethod[] reusableMethods = new LibraryMethod[u2methodsCount];
186 
187         int visibleMethodsCount = 0;
188         for (int index = 0; index < u2methodsCount; index++)
189         {
190             LibraryMethod method = new LibraryMethod();
191             this.visitLibraryMember(libraryClass, method);
192 
193             // Only store methods that are visible.
194             if (AccessUtil.accessLevel(method.getAccessFlags()) >=
195                 (skipNonPublicClassMembers ? AccessUtil.PROTECTED :
196                                              AccessUtil.PACKAGE_VISIBLE))
197             {
198                 reusableMethods[visibleMethodsCount++] = method;
199             }
200         }
201 
202         // Copy the visible methods (if any) into a methods array of the right size.
203         if (visibleMethodsCount == 0)
204         {
205             libraryClass.methods = EMPTY_LIBRARY_METHODS;
206         }
207         else
208         {
209             libraryClass.methods = new LibraryMethod[visibleMethodsCount];
210             System.arraycopy(reusableMethods, 0, libraryClass.methods, 0, visibleMethodsCount);
211         }
212 
213         // Skip the class attributes.
214         skipAttributes();
215     }
216 
217 
218     // Implementations for MemberVisitor.
219 
visitProgramMember(ProgramClass libraryClass, ProgramMember libraryMember)220     public void visitProgramMember(ProgramClass libraryClass, ProgramMember libraryMember)
221     {
222     }
223 
224 
visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember)225     public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember)
226     {
227         // Read the general field information.
228         libraryMember.u2accessFlags = dataInput.readUnsignedShort();
229         libraryMember.name          = getString(dataInput.readUnsignedShort());
230         libraryMember.descriptor    = getString(dataInput.readUnsignedShort());
231 
232         // Skip the field attributes.
233         skipAttributes();
234     }
235 
236 
237     // Implementations for ConstantVisitor.
238 
visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)239     public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
240     {
241         dataInput.skipBytes(4);
242     }
243 
244 
visitLongConstant(Clazz clazz, LongConstant longConstant)245     public void visitLongConstant(Clazz clazz, LongConstant longConstant)
246     {
247         dataInput.skipBytes(8);
248     }
249 
250 
visitFloatConstant(Clazz clazz, FloatConstant floatConstant)251     public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
252     {
253         dataInput.skipBytes(4);
254     }
255 
256 
visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)257     public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
258     {
259         dataInput.skipBytes(8);
260     }
261 
262 
visitStringConstant(Clazz clazz, StringConstant stringConstant)263     public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
264     {
265         dataInput.skipBytes(2);
266     }
267 
268 
visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)269     public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
270     {
271         int u2length = dataInput.readUnsignedShort();
272 
273         // Read the UTF-8 bytes.
274         byte[] bytes = new byte[u2length];
275         dataInput.readFully(bytes);
276         utf8Constant.setBytes(bytes);
277     }
278 
279 
visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)280     public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
281     {
282         dataInput.skipBytes(4);
283     }
284 
285 
visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)286     public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
287     {
288         dataInput.skipBytes(3);
289     }
290 
291 
visitAnyRefConstant(Clazz clazz, RefConstant refConstant)292     public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
293     {
294         dataInput.skipBytes(4);
295     }
296 
297 
visitClassConstant(Clazz clazz, ClassConstant classConstant)298     public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
299     {
300         classConstant.u2nameIndex = dataInput.readUnsignedShort();
301     }
302 
303 
visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)304     public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
305     {
306         dataInput.skipBytes(2);
307     }
308 
309 
visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)310     public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
311     {
312         dataInput.skipBytes(4);
313     }
314 
315 
316     // Small utility methods.
317 
318     /**
319      * Returns the class name of the ClassConstant at the specified index in the
320      * reusable constant pool.
321      */
getClassName(int constantIndex)322     private String getClassName(int constantIndex)
323     {
324         ClassConstant classEntry = (ClassConstant)constantPool[constantIndex];
325 
326         return getString(classEntry.u2nameIndex);
327     }
328 
329 
330     /**
331      * Returns the string of the Utf8Constant at the specified index in the
332      * reusable constant pool.
333      */
getString(int constantIndex)334     private String getString(int constantIndex)
335     {
336         return ((Utf8Constant)constantPool[constantIndex]).getString();
337     }
338 
339 
createConstant()340     private Constant createConstant()
341     {
342         int u1tag = dataInput.readUnsignedByte();
343 
344         switch (u1tag)
345         {
346             case ClassConstants.CONSTANT_Integer:            return new IntegerConstant();
347             case ClassConstants.CONSTANT_Float:              return new FloatConstant();
348             case ClassConstants.CONSTANT_Long:               return new LongConstant();
349             case ClassConstants.CONSTANT_Double:             return new DoubleConstant();
350             case ClassConstants.CONSTANT_String:             return new StringConstant();
351             case ClassConstants.CONSTANT_Utf8:               return new Utf8Constant();
352             case ClassConstants.CONSTANT_InvokeDynamic:      return new InvokeDynamicConstant();
353             case ClassConstants.CONSTANT_MethodHandle:       return new MethodHandleConstant();
354             case ClassConstants.CONSTANT_Fieldref:           return new FieldrefConstant();
355             case ClassConstants.CONSTANT_Methodref:          return new MethodrefConstant();
356             case ClassConstants.CONSTANT_InterfaceMethodref: return new InterfaceMethodrefConstant();
357             case ClassConstants.CONSTANT_Class:              return new ClassConstant();
358             case ClassConstants.CONSTANT_MethodType:         return new MethodTypeConstant();
359             case ClassConstants.CONSTANT_NameAndType:        return new NameAndTypeConstant();
360 
361             default: throw new RuntimeException("Unknown constant type ["+u1tag+"] in constant pool");
362         }
363     }
364 
365 
skipAttributes()366     private void skipAttributes()
367     {
368         int u2attributesCount = dataInput.readUnsignedShort();
369 
370         for (int index = 0; index < u2attributesCount; index++)
371         {
372             skipAttribute();
373         }
374     }
375 
376 
skipAttribute()377     private void skipAttribute()
378     {
379         dataInput.skipBytes(2);
380         int u4attributeLength = dataInput.readInt();
381         dataInput.skipBytes(u4attributeLength);
382     }
383 }
384