1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2009 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        // TODO: Implement method.
142        // Note that the attribute may already be present.
143//        // Create a copy of the attribute.
144//        InnerClassesAttribute newInnerClassesAttribute =
145//            new InnerClassesAttribute(constantAdder.addConstant(clazz, innerClassesAttribute.u2attributeNameIndex),
146//                                      0,
147//                                      null);
148//
149//        // Add it to the target class.
150//        attributesEditor.addClassAttribute(newInnerClassesAttribute);
151    }
152
153
154    public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
155    {
156        // Create a copy of the attribute.
157        EnclosingMethodAttribute newEnclosingMethodAttribute =
158            new EnclosingMethodAttribute(constantAdder.addConstant(clazz, enclosingMethodAttribute.u2attributeNameIndex),
159                                         constantAdder.addConstant(clazz, enclosingMethodAttribute.u2classIndex),
160                                         enclosingMethodAttribute.u2nameAndTypeIndex == 0 ? 0 :
161                                         constantAdder.addConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex));
162
163        newEnclosingMethodAttribute.referencedClass  = enclosingMethodAttribute.referencedClass;
164        newEnclosingMethodAttribute.referencedMethod = enclosingMethodAttribute.referencedMethod;
165
166        // Add it to the target class.
167        attributesEditor.addAttribute(newEnclosingMethodAttribute);
168    }
169
170
171    public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
172    {
173        // Create a copy of the attribute.
174        DeprecatedAttribute newDeprecatedAttribute =
175            new DeprecatedAttribute(constantAdder.addConstant(clazz, deprecatedAttribute.u2attributeNameIndex));
176
177        // Add it to the target.
178        attributesEditor.addAttribute(newDeprecatedAttribute);
179    }
180
181
182    public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute)
183    {
184        // Create a copy of the attribute.
185        SyntheticAttribute newSyntheticAttribute =
186            new SyntheticAttribute(constantAdder.addConstant(clazz, syntheticAttribute.u2attributeNameIndex));
187
188        // Add it to the target.
189        attributesEditor.addAttribute(newSyntheticAttribute);
190    }
191
192
193    public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
194    {
195        // Create a copy of the attribute.
196        SignatureAttribute newSignatureAttribute =
197            new SignatureAttribute(constantAdder.addConstant(clazz, signatureAttribute.u2attributeNameIndex),
198                                   constantAdder.addConstant(clazz, signatureAttribute.u2signatureIndex));
199
200        newSignatureAttribute.referencedClasses = signatureAttribute.referencedClasses;
201
202        // Add it to the target.
203        attributesEditor.addAttribute(newSignatureAttribute);
204    }
205
206
207    public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
208    {
209        // Create a copy of the attribute.
210        ConstantValueAttribute newConstantValueAttribute =
211            new ConstantValueAttribute(constantAdder.addConstant(clazz, constantValueAttribute.u2attributeNameIndex),
212                                       constantAdder.addConstant(clazz, constantValueAttribute.u2constantValueIndex));
213
214        // Add it to the target field.
215        attributesEditor.addAttribute(newConstantValueAttribute);
216    }
217
218
219    public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
220    {
221        // Create a new exceptions attribute.
222        ExceptionsAttribute newExceptionsAttribute =
223            new ExceptionsAttribute(constantAdder.addConstant(clazz, exceptionsAttribute.u2attributeNameIndex),
224                                    0,
225                                    exceptionsAttribute.u2exceptionIndexTableLength > 0 ?
226                                        new int[exceptionsAttribute.u2exceptionIndexTableLength] :
227                                        EMPTY_INTS);
228
229        // Add the exceptions.
230        exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz,
231                                                   new ExceptionAdder(targetClass,
232                                                                      newExceptionsAttribute));
233
234        // Add it to the target method.
235        attributesEditor.addAttribute(newExceptionsAttribute);
236    }
237
238
239    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
240    {
241        // Create a new code attribute.
242        CodeAttribute newCodeAttribute =
243            new CodeAttribute(constantAdder.addConstant(clazz, codeAttribute.u2attributeNameIndex),
244                              codeAttribute.u2maxStack,
245                              codeAttribute.u2maxLocals,
246                              0,
247                              EMPTY_BYTES,
248                              0,
249                              codeAttribute.u2exceptionTableLength > 0 ?
250                                  new ExceptionInfo[codeAttribute.u2exceptionTableLength] :
251                                  EMPTY_EXCEPTIONS,
252                              0,
253                              codeAttribute.u2attributesCount > 0 ?
254                                  new Attribute[codeAttribute.u2attributesCount] :
255                                  EMPTY_ATTRIBUTES);
256
257        CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer();
258
259        codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength);
260
261        // Add the instructions.
262        codeAttribute.instructionsAccept(clazz,
263                                         method,
264                                         new InstructionAdder(targetClass,
265                                                              codeAttributeComposer));
266
267        // Append a label just after the code.
268        codeAttributeComposer.appendLabel(codeAttribute.u4codeLength);
269
270        // Add the exceptions.
271        codeAttribute.exceptionsAccept(clazz,
272                                       method,
273                                       new ExceptionInfoAdder(targetClass,
274                                                              codeAttributeComposer));
275
276        codeAttributeComposer.endCodeFragment();
277
278        // Add the attributes.
279        codeAttribute.attributesAccept(clazz,
280                                       method,
281                                       new AttributeAdder(targetClass,
282                                                          targetMember,
283                                                          newCodeAttribute,
284                                                          replaceAttributes));
285
286        // Apply these changes to the new code attribute.
287        codeAttributeComposer.visitCodeAttribute(targetClass,
288                                                 (Method)targetMember,
289                                                 newCodeAttribute);
290
291        // Add the completed code attribute to the target method.
292        attributesEditor.addAttribute(newCodeAttribute);
293    }
294
295
296    public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
297    {
298        // TODO: Implement method.
299    }
300
301
302    public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
303    {
304        // TODO: Implement method.
305    }
306
307
308    public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
309    {
310        // Create a new line number table attribute.
311        LineNumberTableAttribute newLineNumberTableAttribute =
312            new LineNumberTableAttribute(constantAdder.addConstant(clazz, lineNumberTableAttribute.u2attributeNameIndex),
313                                         0,
314                                         new LineNumberInfo[lineNumberTableAttribute.u2lineNumberTableLength]);
315
316        // Add the line numbers.
317        lineNumberTableAttribute.lineNumbersAccept(clazz,
318                                                   method,
319                                                   codeAttribute,
320                                                   new LineNumberInfoAdder(newLineNumberTableAttribute));
321
322        // Add it to the target.
323        attributesEditor.addAttribute(newLineNumberTableAttribute);
324    }
325
326
327    public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
328    {
329        // Create a new local variable table attribute.
330        LocalVariableTableAttribute newLocalVariableTableAttribute =
331            new LocalVariableTableAttribute(constantAdder.addConstant(clazz, localVariableTableAttribute.u2attributeNameIndex),
332                                            0,
333                                            new LocalVariableInfo[localVariableTableAttribute.u2localVariableTableLength]);
334
335        // Add the local variables.
336        localVariableTableAttribute.localVariablesAccept(clazz,
337                                                         method,
338                                                         codeAttribute,
339                                                         new LocalVariableInfoAdder(targetClass, newLocalVariableTableAttribute));
340
341        // Add it to the target.
342        attributesEditor.addAttribute(newLocalVariableTableAttribute);
343    }
344
345
346    public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
347    {
348        // Create a new local variable type table attribute.
349        LocalVariableTypeTableAttribute newLocalVariableTypeTableAttribute =
350            new LocalVariableTypeTableAttribute(constantAdder.addConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex),
351                                            0,
352                                            new LocalVariableTypeInfo[localVariableTypeTableAttribute.u2localVariableTypeTableLength]);
353
354        // Add the local variable types.
355        localVariableTypeTableAttribute.localVariablesAccept(clazz,
356                                                             method,
357                                                             codeAttribute,
358                                                             new LocalVariableTypeInfoAdder(targetClass, newLocalVariableTypeTableAttribute));
359
360        // Add it to the target.
361        attributesEditor.addAttribute(newLocalVariableTypeTableAttribute);
362    }
363
364
365    public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
366    {
367        // Create a new annotations attribute.
368        RuntimeVisibleAnnotationsAttribute newAnnotationsAttribute =
369            new RuntimeVisibleAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeVisibleAnnotationsAttribute.u2attributeNameIndex),
370                                                   0,
371                                                   new Annotation[runtimeVisibleAnnotationsAttribute.u2annotationsCount]);
372
373        // Add the annotations.
374        runtimeVisibleAnnotationsAttribute.annotationsAccept(clazz,
375                                                             new AnnotationAdder(targetClass,
376                                                                                 newAnnotationsAttribute));
377
378        // Add it to the target.
379        attributesEditor.addAttribute(newAnnotationsAttribute);
380    }
381
382
383    public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
384    {
385        // Create a new annotations attribute.
386        RuntimeInvisibleAnnotationsAttribute newAnnotationsAttribute =
387            new RuntimeInvisibleAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeInvisibleAnnotationsAttribute.u2attributeNameIndex),
388                                                     0,
389                                                     new Annotation[runtimeInvisibleAnnotationsAttribute.u2annotationsCount]);
390
391        // Add the annotations.
392        runtimeInvisibleAnnotationsAttribute.annotationsAccept(clazz,
393                                                               new AnnotationAdder(targetClass,
394                                                                                   newAnnotationsAttribute));
395
396        // Add it to the target.
397        attributesEditor.addAttribute(newAnnotationsAttribute);
398    }
399
400
401    public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute)
402    {
403        // Create a new annotations attribute.
404        RuntimeVisibleParameterAnnotationsAttribute newParameterAnnotationsAttribute =
405            new RuntimeVisibleParameterAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeVisibleParameterAnnotationsAttribute.u2attributeNameIndex),
406                                                            0,
407                                                            new int[runtimeVisibleParameterAnnotationsAttribute.u2parametersCount],
408                                                            new Annotation[runtimeVisibleParameterAnnotationsAttribute.u2parametersCount][]);
409
410        // Add the annotations.
411        runtimeVisibleParameterAnnotationsAttribute.annotationsAccept(clazz,
412                                                                      method,
413                                                                      new AnnotationAdder(targetClass,
414                                                                                          newParameterAnnotationsAttribute));
415
416        // Add it to the target.
417        attributesEditor.addAttribute(newParameterAnnotationsAttribute);
418    }
419
420
421    public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute)
422    {
423        // Create a new annotations attribute.
424        RuntimeInvisibleParameterAnnotationsAttribute newParameterAnnotationsAttribute =
425            new RuntimeInvisibleParameterAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeInvisibleParameterAnnotationsAttribute.u2attributeNameIndex),
426                                                              0,
427                                                              new int[runtimeInvisibleParameterAnnotationsAttribute.u2parametersCount],
428                                                              new Annotation[runtimeInvisibleParameterAnnotationsAttribute.u2parametersCount][]);
429
430        // Add the annotations.
431        runtimeInvisibleParameterAnnotationsAttribute.annotationsAccept(clazz,
432                                                                        method,
433                                                                        new AnnotationAdder(targetClass,
434                                                                                            newParameterAnnotationsAttribute));
435
436        // Add it to the target.
437        attributesEditor.addAttribute(newParameterAnnotationsAttribute);
438    }
439
440
441    public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
442    {
443        // Create a new annotation default attribute.
444        AnnotationDefaultAttribute newAnnotationDefaultAttribute =
445            new AnnotationDefaultAttribute(constantAdder.addConstant(clazz, annotationDefaultAttribute.u2attributeNameIndex),
446                                           null);
447
448        // Add the annotations.
449        annotationDefaultAttribute.defaultValueAccept(clazz,
450                                                      new ElementValueAdder(targetClass,
451                                                                            newAnnotationDefaultAttribute,
452                                                                            false));
453
454        // Add it to the target.
455        attributesEditor.addAttribute(newAnnotationDefaultAttribute);
456    }
457}
458