1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2013 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 */
21package proguard.classfile.editor;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.*;
25import proguard.classfile.attribute.annotation.*;
26import proguard.classfile.attribute.preverification.*;
27import proguard.classfile.attribute.visitor.AttributeVisitor;
28import proguard.classfile.util.SimplifiedVisitor;
29
30/**
31 * This AttributeVisitor adds all attributes that it visits to the given
32 * target class, class member, or attribute.
33 *
34 * @author Eric Lafortune
35 */
36public class AttributeAdder
37extends      SimplifiedVisitor
38implements   AttributeVisitor
39{
40    private static final byte[]          EMPTY_BYTES       = new byte[0];
41    private static final int[]           EMPTY_INTS        = new int[0];
42    private static final Attribute[]     EMPTY_ATTRIBUTES  = new Attribute[0];
43    private static final ExceptionInfo[] EMPTY_EXCEPTIONS  = new ExceptionInfo[0];
44
45
46    private final ProgramClass  targetClass;
47    private final ProgramMember targetMember;
48    private final CodeAttribute targetCodeAttribute;
49    private final boolean       replaceAttributes;
50
51    private final ConstantAdder    constantAdder;
52    private final AttributesEditor attributesEditor;
53
54
55    /**
56     * Creates a new AttributeAdder that will copy attributes into the given
57     * target class.
58     */
59    public AttributeAdder(ProgramClass targetClass,
60                          boolean      replaceAttributes)
61    {
62        this(targetClass, null, null, replaceAttributes);
63    }
64
65
66    /**
67     * Creates a new AttributeAdder that will copy attributes into the given
68     * target class member.
69     */
70    public AttributeAdder(ProgramClass  targetClass,
71                          ProgramMember targetMember,
72                          boolean       replaceAttributes)
73    {
74        this(targetClass, targetMember, null, replaceAttributes);
75    }
76
77
78    /**
79     * Creates a new AttributeAdder that will copy attributes into the given
80     * target attribute.
81     */
82    public AttributeAdder(ProgramClass  targetClass,
83                          ProgramMember targetMember,
84                          CodeAttribute targetCodeAttribute,
85                          boolean       replaceAttributes)
86    {
87        this.targetClass         = targetClass;
88        this.targetMember        = targetMember;
89        this.targetCodeAttribute = targetCodeAttribute;
90        this.replaceAttributes   = replaceAttributes;
91
92        constantAdder    = new ConstantAdder(targetClass);
93        attributesEditor = new AttributesEditor(targetClass,
94                                                targetMember,
95                                                targetCodeAttribute,
96                                                replaceAttributes);
97    }
98
99
100    // Implementations for AttributeVisitor.
101
102    public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute)
103    {
104        // Create a copy of the attribute.
105        UnknownAttribute newUnknownAttribute =
106            new UnknownAttribute(constantAdder.addConstant(clazz, unknownAttribute.u2attributeNameIndex),
107                                 unknownAttribute.u4attributeLength,
108                                 unknownAttribute.info);
109
110        // Add it to the target class.
111        attributesEditor.addAttribute(newUnknownAttribute);
112    }
113
114
115    public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
116    {
117        // Create a copy of the attribute.
118        SourceFileAttribute newSourceFileAttribute =
119            new SourceFileAttribute(constantAdder.addConstant(clazz, sourceFileAttribute.u2attributeNameIndex),
120                                    constantAdder.addConstant(clazz, sourceFileAttribute.u2sourceFileIndex));
121
122        // Add it to the target class.
123        attributesEditor.addAttribute(newSourceFileAttribute);
124    }
125
126
127    public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
128    {
129        // Create a copy of the attribute.
130        SourceDirAttribute newSourceDirAttribute =
131            new SourceDirAttribute(constantAdder.addConstant(clazz, sourceDirAttribute.u2attributeNameIndex),
132                                   constantAdder.addConstant(clazz, sourceDirAttribute.u2sourceDirIndex));
133
134        // Add it to the target class.
135        attributesEditor.addAttribute(newSourceDirAttribute);
136    }
137
138
139    public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
140    {
141        // Create a copy of the attribute.
142        InnerClassesAttribute newInnerClassesAttribute =
143            new InnerClassesAttribute(constantAdder.addConstant(clazz, innerClassesAttribute.u2attributeNameIndex),
144                                      0,
145                                      null);
146
147        // Add it to the target class.
148        attributesEditor.addAttribute(newInnerClassesAttribute);
149    }
150
151
152    public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
153    {
154        // Create a copy of the attribute.
155        EnclosingMethodAttribute newEnclosingMethodAttribute =
156            new EnclosingMethodAttribute(constantAdder.addConstant(clazz, enclosingMethodAttribute.u2attributeNameIndex),
157                                         constantAdder.addConstant(clazz, enclosingMethodAttribute.u2classIndex),
158                                         enclosingMethodAttribute.u2nameAndTypeIndex == 0 ? 0 :
159                                         constantAdder.addConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex));
160
161        newEnclosingMethodAttribute.referencedClass  = enclosingMethodAttribute.referencedClass;
162        newEnclosingMethodAttribute.referencedMethod = enclosingMethodAttribute.referencedMethod;
163
164        // Add it to the target class.
165        attributesEditor.addAttribute(newEnclosingMethodAttribute);
166    }
167
168
169    public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
170    {
171        // Create a copy of the attribute.
172        DeprecatedAttribute newDeprecatedAttribute =
173            new DeprecatedAttribute(constantAdder.addConstant(clazz, deprecatedAttribute.u2attributeNameIndex));
174
175        // Add it to the target.
176        attributesEditor.addAttribute(newDeprecatedAttribute);
177    }
178
179
180    public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute)
181    {
182        // Create a copy of the attribute.
183        SyntheticAttribute newSyntheticAttribute =
184            new SyntheticAttribute(constantAdder.addConstant(clazz, syntheticAttribute.u2attributeNameIndex));
185
186        // Add it to the target.
187        attributesEditor.addAttribute(newSyntheticAttribute);
188    }
189
190
191    public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
192    {
193        // Create a copy of the attribute.
194        SignatureAttribute newSignatureAttribute =
195            new SignatureAttribute(constantAdder.addConstant(clazz, signatureAttribute.u2attributeNameIndex),
196                                   constantAdder.addConstant(clazz, signatureAttribute.u2signatureIndex));
197
198        newSignatureAttribute.referencedClasses = signatureAttribute.referencedClasses;
199
200        // Add it to the target.
201        attributesEditor.addAttribute(newSignatureAttribute);
202    }
203
204
205    public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
206    {
207        // Create a copy of the attribute.
208        ConstantValueAttribute newConstantValueAttribute =
209            new ConstantValueAttribute(constantAdder.addConstant(clazz, constantValueAttribute.u2attributeNameIndex),
210                                       constantAdder.addConstant(clazz, constantValueAttribute.u2constantValueIndex));
211
212        // Add it to the target field.
213        attributesEditor.addAttribute(newConstantValueAttribute);
214    }
215
216
217    public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
218    {
219        // Create a new exceptions attribute.
220        ExceptionsAttribute newExceptionsAttribute =
221            new ExceptionsAttribute(constantAdder.addConstant(clazz, exceptionsAttribute.u2attributeNameIndex),
222                                    0,
223                                    exceptionsAttribute.u2exceptionIndexTableLength > 0 ?
224                                        new int[exceptionsAttribute.u2exceptionIndexTableLength] :
225                                        EMPTY_INTS);
226
227        // Add the exceptions.
228        exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz,
229                                                   new ExceptionAdder(targetClass,
230                                                                      newExceptionsAttribute));
231
232        // Add it to the target method.
233        attributesEditor.addAttribute(newExceptionsAttribute);
234    }
235
236
237    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
238    {
239        // Create a new code attribute.
240        CodeAttribute newCodeAttribute =
241            new CodeAttribute(constantAdder.addConstant(clazz, codeAttribute.u2attributeNameIndex),
242                              codeAttribute.u2maxStack,
243                              codeAttribute.u2maxLocals,
244                              0,
245                              EMPTY_BYTES,
246                              0,
247                              codeAttribute.u2exceptionTableLength > 0 ?
248                                  new ExceptionInfo[codeAttribute.u2exceptionTableLength] :
249                                  EMPTY_EXCEPTIONS,
250                              0,
251                              codeAttribute.u2attributesCount > 0 ?
252                                  new Attribute[codeAttribute.u2attributesCount] :
253                                  EMPTY_ATTRIBUTES);
254
255        CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer();
256
257        codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength + 32);
258
259        // Add the instructions.
260        codeAttribute.instructionsAccept(clazz,
261                                         method,
262                                         new InstructionAdder(targetClass,
263                                                              codeAttributeComposer));
264
265        // Append a label just after the code.
266        codeAttributeComposer.appendLabel(codeAttribute.u4codeLength);
267
268        // Add the exceptions.
269        codeAttribute.exceptionsAccept(clazz,
270                                       method,
271                                       new ExceptionInfoAdder(targetClass,
272                                                              codeAttributeComposer));
273
274        codeAttributeComposer.endCodeFragment();
275
276        // Add the attributes.
277        codeAttribute.attributesAccept(clazz,
278                                       method,
279                                       new AttributeAdder(targetClass,
280                                                          targetMember,
281                                                          newCodeAttribute,
282                                                          replaceAttributes));
283
284        // Apply these changes to the new code attribute.
285        codeAttributeComposer.visitCodeAttribute(targetClass,
286                                                 (Method)targetMember,
287                                                 newCodeAttribute);
288
289        // Add the completed code attribute to the target method.
290        attributesEditor.addAttribute(newCodeAttribute);
291    }
292
293
294    public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
295    {
296        // TODO: Implement method.
297    }
298
299
300    public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
301    {
302        // TODO: Implement method.
303    }
304
305
306    public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
307    {
308        // Create a new line number table attribute.
309        LineNumberTableAttribute newLineNumberTableAttribute =
310            new LineNumberTableAttribute(constantAdder.addConstant(clazz, lineNumberTableAttribute.u2attributeNameIndex),
311                                         0,
312                                         new LineNumberInfo[lineNumberTableAttribute.u2lineNumberTableLength]);
313
314        // Add the line numbers.
315        lineNumberTableAttribute.lineNumbersAccept(clazz,
316                                                   method,
317                                                   codeAttribute,
318                                                   new LineNumberInfoAdder(newLineNumberTableAttribute));
319
320        // Add it to the target.
321        attributesEditor.addAttribute(newLineNumberTableAttribute);
322    }
323
324
325    public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
326    {
327        // Create a new local variable table attribute.
328        LocalVariableTableAttribute newLocalVariableTableAttribute =
329            new LocalVariableTableAttribute(constantAdder.addConstant(clazz, localVariableTableAttribute.u2attributeNameIndex),
330                                            0,
331                                            new LocalVariableInfo[localVariableTableAttribute.u2localVariableTableLength]);
332
333        // Add the local variables.
334        localVariableTableAttribute.localVariablesAccept(clazz,
335                                                         method,
336                                                         codeAttribute,
337                                                         new LocalVariableInfoAdder(targetClass, newLocalVariableTableAttribute));
338
339        // Add it to the target.
340        attributesEditor.addAttribute(newLocalVariableTableAttribute);
341    }
342
343
344    public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
345    {
346        // Create a new local variable type table attribute.
347        LocalVariableTypeTableAttribute newLocalVariableTypeTableAttribute =
348            new LocalVariableTypeTableAttribute(constantAdder.addConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex),
349                                            0,
350                                            new LocalVariableTypeInfo[localVariableTypeTableAttribute.u2localVariableTypeTableLength]);
351
352        // Add the local variable types.
353        localVariableTypeTableAttribute.localVariablesAccept(clazz,
354                                                             method,
355                                                             codeAttribute,
356                                                             new LocalVariableTypeInfoAdder(targetClass, newLocalVariableTypeTableAttribute));
357
358        // Add it to the target.
359        attributesEditor.addAttribute(newLocalVariableTypeTableAttribute);
360    }
361
362
363    public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
364    {
365        // Create a new annotations attribute.
366        RuntimeVisibleAnnotationsAttribute newAnnotationsAttribute =
367            new RuntimeVisibleAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeVisibleAnnotationsAttribute.u2attributeNameIndex),
368                                                   0,
369                                                   new Annotation[runtimeVisibleAnnotationsAttribute.u2annotationsCount]);
370
371        // Add the annotations.
372        runtimeVisibleAnnotationsAttribute.annotationsAccept(clazz,
373                                                             new AnnotationAdder(targetClass,
374                                                                                 newAnnotationsAttribute));
375
376        // Add it to the target.
377        attributesEditor.addAttribute(newAnnotationsAttribute);
378    }
379
380
381    public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
382    {
383        // Create a new annotations attribute.
384        RuntimeInvisibleAnnotationsAttribute newAnnotationsAttribute =
385            new RuntimeInvisibleAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeInvisibleAnnotationsAttribute.u2attributeNameIndex),
386                                                     0,
387                                                     new Annotation[runtimeInvisibleAnnotationsAttribute.u2annotationsCount]);
388
389        // Add the annotations.
390        runtimeInvisibleAnnotationsAttribute.annotationsAccept(clazz,
391                                                               new AnnotationAdder(targetClass,
392                                                                                   newAnnotationsAttribute));
393
394        // Add it to the target.
395        attributesEditor.addAttribute(newAnnotationsAttribute);
396    }
397
398
399    public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute)
400    {
401        // Create a new annotations attribute.
402        RuntimeVisibleParameterAnnotationsAttribute newParameterAnnotationsAttribute =
403            new RuntimeVisibleParameterAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeVisibleParameterAnnotationsAttribute.u2attributeNameIndex),
404                                                            0,
405                                                            new int[runtimeVisibleParameterAnnotationsAttribute.u2parametersCount],
406                                                            new Annotation[runtimeVisibleParameterAnnotationsAttribute.u2parametersCount][]);
407
408        // Add the annotations.
409        runtimeVisibleParameterAnnotationsAttribute.annotationsAccept(clazz,
410                                                                      method,
411                                                                      new AnnotationAdder(targetClass,
412                                                                                          newParameterAnnotationsAttribute));
413
414        // Add it to the target.
415        attributesEditor.addAttribute(newParameterAnnotationsAttribute);
416    }
417
418
419    public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute)
420    {
421        // Create a new annotations attribute.
422        RuntimeInvisibleParameterAnnotationsAttribute newParameterAnnotationsAttribute =
423            new RuntimeInvisibleParameterAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeInvisibleParameterAnnotationsAttribute.u2attributeNameIndex),
424                                                              0,
425                                                              new int[runtimeInvisibleParameterAnnotationsAttribute.u2parametersCount],
426                                                              new Annotation[runtimeInvisibleParameterAnnotationsAttribute.u2parametersCount][]);
427
428        // Add the annotations.
429        runtimeInvisibleParameterAnnotationsAttribute.annotationsAccept(clazz,
430                                                                        method,
431                                                                        new AnnotationAdder(targetClass,
432                                                                                            newParameterAnnotationsAttribute));
433
434        // Add it to the target.
435        attributesEditor.addAttribute(newParameterAnnotationsAttribute);
436    }
437
438
439    public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
440    {
441        // Create a new annotation default attribute.
442        AnnotationDefaultAttribute newAnnotationDefaultAttribute =
443            new AnnotationDefaultAttribute(constantAdder.addConstant(clazz, annotationDefaultAttribute.u2attributeNameIndex),
444                                           null);
445
446        // Add the annotations.
447        annotationDefaultAttribute.defaultValueAccept(clazz,
448                                                      new ElementValueAdder(targetClass,
449                                                                            newAnnotationDefaultAttribute,
450                                                                            false));
451
452        // Add it to the target.
453        attributesEditor.addAttribute(newAnnotationDefaultAttribute);
454    }
455}
456