~ubuntu-branches/ubuntu/trusty/proguard/trusty

« back to all changes in this revision

Viewing changes to src/proguard/classfile/io/LibraryClassReader.java

  • Committer: Bazaar Package Importer
  • Author(s): Sam Clegg
  • Date: 2008-05-15 10:39:48 UTC
  • mfrom: (1.2.1 upstream) (3.1.3 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080515103948-nipob41uk77osuu2
* New upstream release
* Fix build of ant task (Closes: #459829)
  Thanks to Hans van Kranenburg <debian@knorrie.org>

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ProGuard -- shrinking, optimization, obfuscation, and preverification
 
3
 *             of Java bytecode.
 
4
 *
 
5
 * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
 
6
 *
 
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)
 
10
 * any later version.
 
11
 *
 
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
 
15
 * more details.
 
16
 *
 
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
 
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
     */
 
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
 
 
70
    public void visitProgramClass(ProgramClass libraryClass)
 
71
    {
 
72
    }
 
73
 
 
74
 
 
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
 
 
220
    public void visitProgramMember(ProgramClass libraryClass, ProgramMember libraryMember)
 
221
    {
 
222
    }
 
223
 
 
224
 
 
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
 
 
239
    public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
 
240
    {
 
241
        dataInput.skipBytes(4);
 
242
    }
 
243
 
 
244
 
 
245
    public void visitLongConstant(Clazz clazz, LongConstant longConstant)
 
246
    {
 
247
        dataInput.skipBytes(8);
 
248
    }
 
249
 
 
250
 
 
251
    public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
 
252
    {
 
253
        dataInput.skipBytes(4);
 
254
    }
 
255
 
 
256
 
 
257
    public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
 
258
    {
 
259
        dataInput.skipBytes(8);
 
260
    }
 
261
 
 
262
 
 
263
    public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
 
264
    {
 
265
        dataInput.skipBytes(2);
 
266
    }
 
267
 
 
268
 
 
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
 
 
280
    public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
 
281
    {
 
282
        dataInput.skipBytes(4);
 
283
    }
 
284
 
 
285
 
 
286
    public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
 
287
    {
 
288
        classConstant.u2nameIndex = dataInput.readUnsignedShort();
 
289
    }
 
290
 
 
291
 
 
292
    public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
 
293
    {
 
294
        dataInput.skipBytes(4);
 
295
    }
 
296
 
 
297
 
 
298
    // Small utility methods.
 
299
 
 
300
    /**
 
301
     * Returns the class name of the ClassConstant at the specified index in the
 
302
     * reusable constant pool.
 
303
     */
 
304
    private String getClassName(int constantIndex)
 
305
    {
 
306
        ClassConstant classEntry = (ClassConstant)constantPool[constantIndex];
 
307
 
 
308
        return getString(classEntry.u2nameIndex);
 
309
    }
 
310
 
 
311
 
 
312
    /**
 
313
     * Returns the string of the Utf8Constant at the specified index in the
 
314
     * reusable constant pool.
 
315
     */
 
316
    private String getString(int constantIndex)
 
317
    {
 
318
        return ((Utf8Constant)constantPool[constantIndex]).getString();
 
319
    }
 
320
 
 
321
 
 
322
    private Constant createConstant()
 
323
    {
 
324
        int u1tag = dataInput.readUnsignedByte();
 
325
 
 
326
        switch (u1tag)
 
327
        {
 
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();
 
339
 
 
340
            default: throw new RuntimeException("Unknown constant type ["+u1tag+"] in constant pool");
 
341
        }
 
342
    }
 
343
 
 
344
 
 
345
    private void skipAttributes()
 
346
    {
 
347
        int u2attributesCount = dataInput.readUnsignedShort();
 
348
 
 
349
        for (int index = 0; index < u2attributesCount; index++)
 
350
        {
 
351
            skipAttribute();
 
352
        }
 
353
    }
 
354
 
 
355
 
 
356
    private void skipAttribute()
 
357
    {
 
358
        dataInput.skipBytes(2);
 
359
        int u4attributeLength = dataInput.readInt();
 
360
        dataInput.skipBytes(u4attributeLength);
 
361
    }
 
362
}