~ubuntu-branches/ubuntu/oneiric/proguard/oneiric

« back to all changes in this revision

Viewing changes to src/proguard/classfile/editor/ClassFileReferenceFixer.java

  • Committer: Bazaar Package Importer
  • Author(s): Sam Clegg
  • Date: 2005-11-13 09:42:59 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20051113094259-432zf4yyw4890mmn
Tags: 3.4-1
* New upstream release (Closes: #338355)
* debian/control: bump standards version
* debian/copyright: update FSF address
* increase java stack size for proguard and proguardgui

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: ClassFileReferenceFixer.java,v 1.4 2005/06/25 22:07:51 eric Exp $
 
2
 *
 
3
 * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
 
4
 *
 
5
 * Copyright (c) 2002-2005 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.editor;
 
22
 
 
23
import proguard.classfile.*;
 
24
import proguard.classfile.attribute.*;
 
25
import proguard.classfile.attribute.annotation.*;
 
26
import proguard.classfile.util.*;
 
27
import proguard.classfile.visitor.*;
 
28
 
 
29
/**
 
30
 * This ClassFileVisitor fixes constant pool references to classes whose
 
31
 * names have changed. Descriptors of member references are not updated yet.
 
32
 *
 
33
 * @see MemberReferenceFixer
 
34
 * @author Eric Lafortune
 
35
 */
 
36
public class ClassFileReferenceFixer
 
37
  implements ClassFileVisitor,
 
38
             CpInfoVisitor,
 
39
             MemberInfoVisitor,
 
40
             AttrInfoVisitor,
 
41
             LocalVariableInfoVisitor,
 
42
             LocalVariableTypeInfoVisitor,
 
43
             AnnotationVisitor,
 
44
             ElementValueVisitor
 
45
{
 
46
    private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
 
47
 
 
48
 
 
49
    // Implementations for ClassFileVisitor.
 
50
 
 
51
    public void visitProgramClassFile(ProgramClassFile programClassFile)
 
52
    {
 
53
        // Fix the constant pool.
 
54
        programClassFile.constantPoolEntriesAccept(this);
 
55
 
 
56
        // Fix class members.
 
57
        programClassFile.fieldsAccept(this);
 
58
        programClassFile.methodsAccept(this);
 
59
 
 
60
        // Fix the attributes.
 
61
        programClassFile.attributesAccept(this);
 
62
    }
 
63
 
 
64
 
 
65
    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
 
66
    {
 
67
        // Fix class members.
 
68
        libraryClassFile.fieldsAccept(this);
 
69
        libraryClassFile.methodsAccept(this);
 
70
    }
 
71
 
 
72
 
 
73
    // Implementations for MemberInfoVisitor.
 
74
 
 
75
    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
 
76
    {
 
77
        // Has the descriptor changed?
 
78
        String descriptor    = programFieldInfo.getDescriptor(programClassFile);
 
79
        String newDescriptor = newDescriptor(descriptor,
 
80
                                             programFieldInfo.referencedClassFile);
 
81
 
 
82
        if (!descriptor.equals(newDescriptor))
 
83
        {
 
84
            // Update the descriptor.
 
85
            programFieldInfo.u2descriptorIndex =
 
86
                constantPoolEditor.addUtf8CpInfo(programClassFile, newDescriptor);
 
87
        }
 
88
 
 
89
        // Fix the attributes.
 
90
        programFieldInfo.attributesAccept(programClassFile, this);
 
91
    }
 
92
 
 
93
 
 
94
    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
 
95
    {
 
96
        // Has the descriptor changed?
 
97
        String descriptor    = programMethodInfo.getDescriptor(programClassFile);
 
98
        String newDescriptor = newDescriptor(descriptor,
 
99
                                             programMethodInfo.referencedClassFiles);
 
100
 
 
101
        if (!descriptor.equals(newDescriptor))
 
102
        {
 
103
            // Update the descriptor.
 
104
            programMethodInfo.u2descriptorIndex =
 
105
                constantPoolEditor.addUtf8CpInfo(programClassFile, newDescriptor);
 
106
        }
 
107
 
 
108
        // Fix the attributes.
 
109
        programMethodInfo.attributesAccept(programClassFile, this);
 
110
    }
 
111
 
 
112
 
 
113
    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
 
114
    {
 
115
        // Has the descriptor changed?
 
116
        String descriptor    = libraryFieldInfo.getDescriptor(libraryClassFile);
 
117
        String newDescriptor = newDescriptor(descriptor,
 
118
                                             libraryFieldInfo.referencedClassFile);
 
119
 
 
120
        // Update the descriptor.
 
121
        libraryFieldInfo.descriptor = newDescriptor;
 
122
    }
 
123
 
 
124
 
 
125
    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
 
126
    {
 
127
        // Has the descriptor changed?
 
128
        String descriptor    = libraryMethodInfo.getDescriptor(libraryClassFile);
 
129
        String newDescriptor = newDescriptor(descriptor,
 
130
                                             libraryMethodInfo.referencedClassFiles);
 
131
 
 
132
        // Update the descriptor.
 
133
        libraryMethodInfo.descriptor = newDescriptor;
 
134
    }
 
135
 
 
136
 
 
137
    // Implementations for CpInfoVisitor.
 
138
 
 
139
    public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
 
140
    public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
 
141
    public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
 
142
    public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
 
143
    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
 
144
    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
 
145
    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
 
146
    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
 
147
    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
 
148
 
 
149
 
 
150
    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
 
151
    {
 
152
        // Does the string refer to a class file, due to a Class.forName construct?
 
153
        ClassFile referencedClassFile = stringCpInfo.referencedClassFile;
 
154
        if (referencedClassFile != null)
 
155
        {
 
156
            // Reconstruct the new class name.
 
157
            String externalClassName    = stringCpInfo.getString(classFile);
 
158
            String internalClassName    = ClassUtil.internalClassName(externalClassName);
 
159
            String newInternalClassName = newClassName(internalClassName,
 
160
                                                       referencedClassFile);
 
161
 
 
162
            // Update the String entry if required.
 
163
            if (!newInternalClassName.equals(internalClassName))
 
164
            {
 
165
                String newExternalClassName = ClassUtil.externalClassName(newInternalClassName);
 
166
 
 
167
                // Refer to a new Utf8 entry.
 
168
                stringCpInfo.u2stringIndex =
 
169
                    constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
 
170
                                                     newExternalClassName);
 
171
            }
 
172
        }
 
173
    }
 
174
 
 
175
 
 
176
    public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
 
177
    {
 
178
        // Do we know the referenced class file?
 
179
        ClassFile referencedClassFile = classCpInfo.referencedClassFile;
 
180
        if (referencedClassFile != null)
 
181
        {
 
182
            // Has the class name changed?
 
183
            String className    = classCpInfo.getName(classFile);
 
184
            String newClassName = newClassName(className, referencedClassFile);
 
185
            if (!className.equals(newClassName))
 
186
            {
 
187
                // Refer to a new Utf8 entry.
 
188
                classCpInfo.u2nameIndex =
 
189
                    constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
 
190
                                                     newClassName);
 
191
            }
 
192
        }
 
193
    }
 
194
 
 
195
 
 
196
    // Implementations for AttrInfoVisitor.
 
197
 
 
198
    public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
 
199
    public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
 
200
    public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
 
201
    public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
 
202
    public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
 
203
    public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
 
204
    public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
 
205
    public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
 
206
    public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
 
207
    public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
 
208
 
 
209
 
 
210
    public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
 
211
    {
 
212
        // Fix the attributes.
 
213
        codeAttrInfo.attributesAccept(classFile, methodInfo, this);
 
214
    }
 
215
 
 
216
 
 
217
    public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
 
218
    {
 
219
        // Fix the types of the local variables.
 
220
        localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
 
221
    }
 
222
 
 
223
 
 
224
    public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
 
225
    {
 
226
        // Fix the signatures of the local variables.
 
227
        localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
 
228
    }
 
229
 
 
230
 
 
231
    public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
 
232
    {
 
233
        // Compute the new signature.
 
234
        String signature    = classFile.getCpString(signatureAttrInfo.u2signatureIndex);
 
235
        String newSignature = newDescriptor(signature,
 
236
                                            signatureAttrInfo.referencedClassFiles);
 
237
 
 
238
        if (!signature.equals(newSignature))
 
239
        {
 
240
            signatureAttrInfo.u2signatureIndex =
 
241
                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
 
242
                                                 newSignature);
 
243
        }
 
244
    }
 
245
 
 
246
 
 
247
    public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
 
248
    {
 
249
        // Fix the annotations.
 
250
        runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
 
251
    }
 
252
 
 
253
 
 
254
    public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
 
255
    {
 
256
        // Fix the annotations.
 
257
        runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
 
258
    }
 
259
 
 
260
 
 
261
    public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
 
262
    {
 
263
        // Fix the annotations.
 
264
        runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
 
265
    }
 
266
 
 
267
 
 
268
    public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
 
269
    {
 
270
        // Fix the annotations.
 
271
        runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
 
272
    }
 
273
 
 
274
 
 
275
    public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
 
276
    {
 
277
        // Fix the annotation.
 
278
        annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
 
279
    }
 
280
 
 
281
 
 
282
    // Implementations for LocalVariableInfoVisitor.
 
283
 
 
284
    public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
 
285
    {
 
286
        // Has the descriptor changed?
 
287
        String descriptor    = classFile.getCpString(localVariableInfo.u2descriptorIndex);
 
288
        String newDescriptor = newDescriptor(descriptor,
 
289
                                             localVariableInfo.referencedClassFile);
 
290
 
 
291
        if (!descriptor.equals(newDescriptor))
 
292
        {
 
293
            // Refer to a new Utf8 entry.
 
294
            localVariableInfo.u2descriptorIndex =
 
295
                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
 
296
                                                 newDescriptor);
 
297
        }
 
298
    }
 
299
 
 
300
 
 
301
    // Implementations for LocalVariableTypeInfoVisitor.
 
302
 
 
303
    public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
 
304
    {
 
305
        // Has the signature changed?
 
306
        String signature    = classFile.getCpString(localVariableTypeInfo.u2signatureIndex);
 
307
        String newSignature = newDescriptor(signature,
 
308
                                            localVariableTypeInfo.referencedClassFiles);
 
309
 
 
310
        if (!signature.equals(newSignature))
 
311
        {
 
312
            localVariableTypeInfo.u2signatureIndex =
 
313
                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
 
314
                                                 newSignature);
 
315
        }
 
316
    }
 
317
 
 
318
 
 
319
    // Implementations for AnnotationVisitor.
 
320
 
 
321
    public void visitAnnotation(ClassFile classFile, Annotation annotation)
 
322
    {
 
323
        // Compute the new type name.
 
324
        String typeName    = classFile.getCpString(annotation.u2typeIndex);
 
325
        String newTypeName = newDescriptor(typeName,
 
326
                                           annotation.referencedClassFiles);
 
327
 
 
328
        if (!typeName.equals(newTypeName))
 
329
        {
 
330
            // Refer to a new Utf8 entry.
 
331
            annotation.u2typeIndex =
 
332
                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
 
333
                                                 newTypeName);
 
334
        }
 
335
 
 
336
        // Fix the element values.
 
337
        annotation.elementValuesAccept(classFile, this);
 
338
    }
 
339
 
 
340
 
 
341
    // Implementations for ElementValueVisitor.
 
342
 
 
343
    public void visitConstantElementValue(ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue)
 
344
    {
 
345
    }
 
346
 
 
347
 
 
348
    public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
 
349
    {
 
350
        // Compute the new type name.
 
351
        String typeName    = classFile.getCpString(enumConstantElementValue.u2typeNameIndex);
 
352
        String newTypeName = newDescriptor(typeName,
 
353
                                           enumConstantElementValue.referencedClassFiles);
 
354
 
 
355
        if (!typeName.equals(newTypeName))
 
356
        {
 
357
            // Refer to a new Utf8 entry.
 
358
            enumConstantElementValue.u2typeNameIndex =
 
359
                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
 
360
                                                 newTypeName);
 
361
        }
 
362
    }
 
363
 
 
364
 
 
365
    public void visitClassElementValue(ClassFile classFile, Annotation annotation, ClassElementValue classElementValue)
 
366
    {
 
367
        // Compute the new class name.
 
368
        String className    = classFile.getCpString(classElementValue.u2classInfoIndex);
 
369
        String newClassName = newDescriptor(className,
 
370
                                            classElementValue.referencedClassFiles);
 
371
 
 
372
        if (!className.equals(newClassName))
 
373
        {
 
374
            // Refer to a new Utf8 entry.
 
375
            classElementValue.u2classInfoIndex =
 
376
                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
 
377
                                                 newClassName);
 
378
        }
 
379
    }
 
380
 
 
381
 
 
382
    public void visitAnnotationElementValue(ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue)
 
383
    {
 
384
        // Fix the annotation.
 
385
        annotationElementValue.annotationAccept(classFile, this);
 
386
    }
 
387
 
 
388
 
 
389
    public void visitArrayElementValue(ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue)
 
390
    {
 
391
        // Fix the element values.
 
392
        arrayElementValue.elementValuesAccept(classFile, annotation, this);
 
393
    }
 
394
 
 
395
 
 
396
    // Small utility methods.
 
397
 
 
398
    private static String newDescriptor(String    descriptor,
 
399
                                        ClassFile referencedClassFile)
 
400
    {
 
401
        // If there is no referenced class, the descriptor won't change.
 
402
        if (referencedClassFile == null)
 
403
        {
 
404
            return descriptor;
 
405
        }
 
406
 
 
407
        // Unravel and reconstruct the class element of the descriptor.
 
408
        DescriptorClassEnumeration descriptorClassEnumeration =
 
409
            new DescriptorClassEnumeration(descriptor);
 
410
 
 
411
        StringBuffer newDescriptorBuffer = new StringBuffer(descriptor.length());
 
412
        newDescriptorBuffer.append(descriptorClassEnumeration.nextFluff());
 
413
 
 
414
        // Only if the descriptor contains a class name (e.g. with an array of
 
415
        // primitive types), the descriptor can change.
 
416
        if (descriptorClassEnumeration.hasMoreClassNames())
 
417
        {
 
418
            String className = descriptorClassEnumeration.nextClassName();
 
419
            String fluff     = descriptorClassEnumeration.nextFluff();
 
420
 
 
421
            String newClassName = newClassName(className,
 
422
                                               referencedClassFile);
 
423
 
 
424
            newDescriptorBuffer.append(newClassName);
 
425
            newDescriptorBuffer.append(fluff);
 
426
        }
 
427
 
 
428
        return newDescriptorBuffer.toString();
 
429
    }
 
430
 
 
431
 
 
432
    private static String newDescriptor(String      descriptor,
 
433
                                        ClassFile[] referencedClassFiles)
 
434
    {
 
435
        // If there are no referenced classes, the descriptor won't change.
 
436
        if (referencedClassFiles == null ||
 
437
            referencedClassFiles.length == 0)
 
438
        {
 
439
            return descriptor;
 
440
        }
 
441
 
 
442
        // Unravel and reconstruct the class elements of the descriptor.
 
443
        DescriptorClassEnumeration descriptorClassEnumeration =
 
444
            new DescriptorClassEnumeration(descriptor);
 
445
 
 
446
        StringBuffer newDescriptorBuffer = new StringBuffer(descriptor.length());
 
447
        newDescriptorBuffer.append(descriptorClassEnumeration.nextFluff());
 
448
 
 
449
        int index = 0;
 
450
        while (descriptorClassEnumeration.hasMoreClassNames())
 
451
        {
 
452
            String className = descriptorClassEnumeration.nextClassName();
 
453
            String fluff     = descriptorClassEnumeration.nextFluff();
 
454
 
 
455
            String newClassName = newClassName(className,
 
456
                                               referencedClassFiles[index++]);
 
457
 
 
458
            newDescriptorBuffer.append(newClassName);
 
459
            newDescriptorBuffer.append(fluff);
 
460
        }
 
461
 
 
462
        return newDescriptorBuffer.toString();
 
463
    }
 
464
 
 
465
 
 
466
    /**
 
467
     * Returns the new class name based on the given class name and the new
 
468
     * name of the given referenced class file. Class names of array types
 
469
     * are handled properly.
 
470
     */
 
471
    private static String newClassName(String    className,
 
472
                                       ClassFile referencedClassFile)
 
473
    {
 
474
        // If there is no referenced class, the class name won't change.
 
475
        if (referencedClassFile == null)
 
476
        {
 
477
            return className;
 
478
        }
 
479
 
 
480
        // Reconstruct the class name.
 
481
        String newClassName = referencedClassFile.getName();
 
482
 
 
483
        // Is it an array type?
 
484
        if (className.charAt(0) == ClassConstants.INTERNAL_TYPE_ARRAY)
 
485
        {
 
486
            // Add the array prefixes and suffix "[L...;".
 
487
            newClassName =
 
488
                 className.substring(0, className.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_START)+1) +
 
489
                 newClassName +
 
490
                 ClassConstants.INTERNAL_TYPE_CLASS_END;
 
491
        }
 
492
 
 
493
        return newClassName;
 
494
    }
 
495
}