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