• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
21 package proguard.classfile.editor;
22 
23 import proguard.classfile.*;
24 
25 /**
26  * This class can add interfaces and class members to a given class.
27  * Elements to be added must be filled out beforehand, including their
28  * references to the constant pool.
29  *
30  * @author Eric Lafortune
31  */
32 public class ClassEditor
33 {
34     private static final boolean DEBUG = false;
35 
36     private ProgramClass targetClass;
37 
38 
39     /**
40      * Creates a new ClassEditor that will edit elements in the given
41      * target class.
42      */
ClassEditor(ProgramClass targetClass)43     public ClassEditor(ProgramClass targetClass)
44     {
45         this.targetClass = targetClass;
46     }
47 
48 
49     /**
50      * Adds the given interface.
51      */
addInterface(int interfaceConstantIndex)52     public void addInterface(int interfaceConstantIndex)
53     {
54         int   interfacesCount = targetClass.u2interfacesCount;
55         int[] interfaces      = targetClass.u2interfaces;
56 
57         // Make sure there is enough space for the new interface.
58         if (interfaces.length <= interfacesCount)
59         {
60             targetClass.u2interfaces = new int[interfacesCount+1];
61             System.arraycopy(interfaces, 0,
62                              targetClass.u2interfaces, 0,
63                              interfacesCount);
64             interfaces = targetClass.u2interfaces;
65         }
66 
67         if (DEBUG)
68         {
69             System.out.println(targetClass.getName()+": adding interface ["+targetClass.getClassName(interfaceConstantIndex)+"]");
70         }
71 
72         // Add the interface.
73         interfaces[targetClass.u2interfacesCount++] = interfaceConstantIndex;
74     }
75 
76     /**
77      * Removes the given interface.
78      */
removeInterface(int interfaceConstantIndex)79     public void removeInterface(int interfaceConstantIndex)
80     {
81         int   interfacesCount = targetClass.u2interfacesCount;
82         int[] interfaces      = targetClass.u2interfaces;
83 
84         int interfaceIndex = findInterfaceIndex(interfaceConstantIndex);
85 
86         // Shift the interface entries.
87         System.arraycopy(interfaces, interfaceIndex+1,
88                          interfaces, interfaceIndex,
89                          interfacesCount - interfaceIndex - 1);
90 
91         // Clear the last entry.
92         interfaces[--targetClass.u2interfacesCount] = 0;
93     }
94 
95 
96     /**
97      * Finds the index of the given interface in the target class.
98      */
99 
findInterfaceIndex(int interfaceConstantIndex)100     private int findInterfaceIndex(int interfaceConstantIndex)
101     {
102         int   interfacesCount = targetClass.u2interfacesCount;
103         int[] interfaces      = targetClass.u2interfaces;
104 
105         for (int index = 0; index < interfacesCount; index++)
106         {
107             if (interfaces[index] == interfaceConstantIndex)
108             {
109                 return index;
110             }
111         }
112 
113         return interfacesCount;
114     }
115 
116 
117     /**
118      * Adds the given field.
119      */
addField(Field field)120     public void addField(Field field)
121     {
122         int     fieldsCount = targetClass.u2fieldsCount;
123         Field[] fields      = targetClass.fields;
124 
125         // Make sure there is enough space for the new field.
126         if (fields.length <= fieldsCount)
127         {
128             targetClass.fields = new ProgramField[fieldsCount+1];
129             System.arraycopy(fields, 0,
130                              targetClass.fields, 0,
131                              fieldsCount);
132             fields = targetClass.fields;
133         }
134 
135         if (DEBUG)
136         {
137             System.out.println(targetClass.getName()+": adding field ["+field.getName(targetClass)+" "+field.getDescriptor(targetClass)+"]");
138         }
139 
140         // Add the field.
141         fields[targetClass.u2fieldsCount++] = field;
142     }
143 
144 
145     /**
146      * Removes the given field. Note that removing a field that is still being
147      * referenced can cause unpredictable effects.
148      */
removeField(Field field)149     public void removeField(Field field)
150     {
151         int     fieldsCount = targetClass.u2fieldsCount;
152         Field[] fields      = targetClass.fields;
153 
154         int fieldIndex = findFieldIndex(field);
155 
156         // Shift the field entries.
157         System.arraycopy(fields, fieldIndex+1,
158                          fields, fieldIndex,
159                          fieldsCount - fieldIndex - 1);
160 
161         // Clear the last entry.
162         fields[--targetClass.u2fieldsCount] = null;
163     }
164 
165 
166     /**
167      * Finds the index of the given field in the target class.
168      */
169 
findFieldIndex(Field field)170     private int findFieldIndex(Field field)
171     {
172         int     fieldsCount = targetClass.u2fieldsCount;
173         Field[] fields      = targetClass.fields;
174 
175         for (int index = 0; index < fieldsCount; index++)
176         {
177             if (fields[index].equals(field))
178             {
179                 return index;
180             }
181         }
182 
183         return fieldsCount;
184     }
185 
186 
187     /**
188      * Adds the given method.
189      */
addMethod(Method method)190     public void addMethod(Method method)
191     {
192         int      methodsCount = targetClass.u2methodsCount;
193         Method[] methods      = targetClass.methods;
194 
195         // Make sure there is enough space for the new method.
196         if (methods.length <= methodsCount)
197         {
198             targetClass.methods = new ProgramMethod[methodsCount+1];
199             System.arraycopy(methods, 0,
200                              targetClass.methods, 0,
201                              methodsCount);
202             methods = targetClass.methods;
203         }
204 
205         if (DEBUG)
206         {
207             System.out.println(targetClass.getName()+": adding method ["+method.getName(targetClass)+method.getDescriptor(targetClass)+"]");
208         }
209 
210         // Add the method.
211         methods[targetClass.u2methodsCount++] = method;
212     }
213 
214 
215     /**
216      * Removes the given method. Note that removing a method that is still being
217      * referenced can cause unpredictable effects.
218      */
removeMethod(Method method)219     public void removeMethod(Method method)
220     {
221         int      methodsCount = targetClass.u2methodsCount;
222         Method[] methods      = targetClass.methods;
223 
224         int methodIndex = findMethodIndex(method);
225 
226         // Shift the method entries.
227         System.arraycopy(methods, methodIndex+1,
228                          methods, methodIndex,
229                          methodsCount - methodIndex - 1);
230 
231         // Clear the last entry.
232         methods[--targetClass.u2methodsCount] = null;
233     }
234 
235 
236     /**
237      * Finds the index of the given method in the target class.
238      */
239 
findMethodIndex(Method method)240     private int findMethodIndex(Method method)
241     {
242         int      methodsCount = targetClass.u2methodsCount;
243         Method[] methods      = targetClass.methods;
244 
245         for (int index = 0; index < methodsCount; index++)
246         {
247             if (methods[index].equals(method))
248             {
249                 return index;
250             }
251         }
252 
253         return methodsCount;
254     }
255 }
256