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.constant.*;
25import proguard.classfile.constant.visitor.ConstantVisitor;
26import proguard.util.ListUtil;
27
28/**
29 * This ConstantVisitor adds all constants that it visits to the constant pool
30 * of a given target class.
31 *
32 * @author Eric Lafortune
33 */
34public class ConstantAdder
35implements   ConstantVisitor
36{
37    private final ConstantPoolEditor constantPoolEditor;
38
39    private int constantIndex;
40
41
42    /**
43     * Creates a new ConstantAdder that will copy constants into the given
44     * target class.
45     */
46    public ConstantAdder(ProgramClass targetClass)
47    {
48        constantPoolEditor = new ConstantPoolEditor(targetClass);
49    }
50
51
52    /**
53     * Adds a copy of the specified constant in the given class and returns
54     * its index. If the specified index is 0, the returned value is 0 too.
55     */
56    public int addConstant(Clazz clazz, int constantIndex)
57    {
58        clazz.constantPoolEntryAccept(constantIndex, this);
59
60        return this.constantIndex;
61    }
62
63
64    /**
65     * Adds a copy of the given constant in the given class and returns
66     * its index.
67     */
68    public int addConstant(Clazz clazz, Constant constant)
69    {
70        constant.accept(clazz, this);
71
72        return this.constantIndex;
73    }
74
75
76    /**
77     * Returns the index of the most recently created constant in the constant
78     * pool of the target class.
79     */
80    public int getConstantIndex()
81    {
82        return constantIndex;
83    }
84
85
86    // Implementations for ConstantVisitor.
87
88    public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
89    {
90        constantIndex =
91            constantPoolEditor.addIntegerConstant(integerConstant.getValue());
92    }
93
94
95    public void visitLongConstant(Clazz clazz, LongConstant longConstant)
96    {
97        constantIndex =
98            constantPoolEditor.addLongConstant(longConstant.getValue());
99    }
100
101
102    public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
103    {
104        constantIndex =
105            constantPoolEditor.addFloatConstant(floatConstant.getValue());
106    }
107
108
109    public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
110    {
111        constantIndex =
112            constantPoolEditor.addDoubleConstant(doubleConstant.getValue());
113    }
114
115
116    public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
117    {
118        constantIndex =
119            constantPoolEditor.addStringConstant(stringConstant.getString(clazz),
120                                                 stringConstant.referencedClass,
121                                                 stringConstant.referencedMember);
122    }
123
124
125    public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
126    {
127        constantIndex =
128            constantPoolEditor.addUtf8Constant(utf8Constant.getString());
129    }
130
131
132    public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
133    {
134        // First add the name and type constant.
135        clazz.constantPoolEntryAccept(invokeDynamicConstant.u2nameAndTypeIndex, this);
136
137        // Copy the referenced classes.
138        Clazz[] referencedClasses     = invokeDynamicConstant.referencedClasses;
139        Clazz[] referencedClassesCopy = null;
140        if (referencedClasses != null)
141        {
142            referencedClassesCopy = new Clazz[referencedClasses.length];
143            System.arraycopy(referencedClasses, 0,
144                             referencedClassesCopy, 0,
145                             referencedClasses.length);
146        }
147
148        // Then add the actual invoke dynamic constant.
149        constantIndex =
150            constantPoolEditor.addInvokeDynamicConstant(invokeDynamicConstant.getBootstrapMethodAttributeIndex(),
151                                                        constantIndex,
152                                                        referencedClassesCopy);
153    }
154
155
156    public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
157    {
158        // First add the field ref, interface method ref, or method ref
159        // constant.
160        clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this);
161
162        // Then add the actual method handle constant.
163        constantIndex =
164            constantPoolEditor.addMethodHandleConstant(methodHandleConstant.getReferenceKind(),
165                                                       constantIndex);
166    }
167
168
169    public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
170    {
171        // First add the referenced class constant, with its own referenced class.
172        clazz.constantPoolEntryAccept(fieldrefConstant.u2classIndex, this);
173
174        // Then add the actual field reference constant, with its referenced
175        // class and class member.
176        constantIndex =
177            constantPoolEditor.addFieldrefConstant(constantIndex,
178                                                   fieldrefConstant.getName(clazz),
179                                                   fieldrefConstant.getType(clazz),
180                                                   fieldrefConstant.referencedClass,
181                                                   fieldrefConstant.referencedMember);
182    }
183
184
185    public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant)
186    {
187        // First add the referenced class constant, with its own referenced class.
188        clazz.constantPoolEntryAccept(interfaceMethodrefConstant.u2classIndex, this);
189
190        // Then add the actual interface method reference constant, with its
191        // referenced class and class member.
192        constantIndex =
193            constantPoolEditor.addInterfaceMethodrefConstant(constantIndex,
194                                                             interfaceMethodrefConstant.getName(clazz),
195                                                             interfaceMethodrefConstant.getType(clazz),
196                                                             interfaceMethodrefConstant.referencedClass,
197                                                             interfaceMethodrefConstant.referencedMember);
198    }
199
200
201    public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
202    {
203        // First add the referenced class constant, with its own referenced class.
204        clazz.constantPoolEntryAccept(methodrefConstant.u2classIndex, this);
205
206        // Then add the actual method reference constant, with its referenced
207        // class and class member.
208        constantIndex =
209            constantPoolEditor.addMethodrefConstant(constantIndex,
210                                                    methodrefConstant.getName(clazz),
211                                                    methodrefConstant.getType(clazz),
212                                                    methodrefConstant.referencedClass,
213                                                    methodrefConstant.referencedMember);
214    }
215
216
217    public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
218    {
219        // Add the class constant, with its referenced class..
220        constantIndex =
221            constantPoolEditor.addClassConstant(classConstant.getName(clazz),
222                                                classConstant.referencedClass);
223    }
224
225
226    public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
227    {
228        constantIndex =
229            constantPoolEditor.addMethodTypeConstant(methodTypeConstant.getType(clazz));
230    }
231
232
233    public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
234    {
235        constantIndex =
236            constantPoolEditor.addNameAndTypeConstant(nameAndTypeConstant.getName(clazz),
237                                                      nameAndTypeConstant.getType(clazz));
238    }
239}
240