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