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.*; 25 26/** 27 * This class can add and delete attributes to and from classes, fields, 28 * methods, and code attributes. Attributes to be added must be filled out 29 * beforehand, including their references to the constant pool. Existing 30 * attributes of the same type are always replaced. 31 * 32 * @author Eric Lafortune 33 */ 34public class AttributesEditor 35{ 36 private final ProgramClass targetClass; 37 private final ProgramMember targetMember; 38 private final CodeAttribute targetAttribute; 39 private final boolean replaceAttributes; 40 41 42 /** 43 * Creates a new AttributeAdder that will edit attributes in the given 44 * target class. 45 */ 46 public AttributesEditor(ProgramClass targetClass, 47 boolean replaceAttributes) 48 { 49 this(targetClass, null, null, replaceAttributes); 50 } 51 52 53 /** 54 * Creates a new AttributeAdder that will edit attributes in the given 55 * target class member. 56 */ 57 public AttributesEditor(ProgramClass targetClass, 58 ProgramMember targetMember, 59 boolean replaceAttributes) 60 { 61 this(targetClass, targetMember, null, replaceAttributes); 62 } 63 64 65 /** 66 * Creates a new AttributeAdder that will edit attributes in the given 67 * target code attribute. 68 */ 69 public AttributesEditor(ProgramClass targetClass, 70 ProgramMember targetMember, 71 CodeAttribute targetAttribute, 72 boolean replaceAttributes) 73 { 74 this.targetClass = targetClass; 75 this.targetMember = targetMember; 76 this.targetAttribute = targetAttribute; 77 this.replaceAttributes = replaceAttributes; 78 } 79 80 81 /** 82 * Adds the given attribute to the target. 83 */ 84 public void addAttribute(Attribute attribute) 85 { 86 // What's the target? 87 if (targetAttribute != null) 88 { 89 // Try to replace an existing attribute. 90 if (!replaceAttributes || 91 !replaceAttribute(targetAttribute.u2attributesCount, 92 targetAttribute.attributes, 93 attribute)) 94 { 95 // Otherwise append the attribute. 96 targetAttribute.attributes = 97 addAttribute(targetAttribute.u2attributesCount, 98 targetAttribute.attributes, 99 attribute); 100 101 targetAttribute.u2attributesCount++; 102 } 103 } 104 else if (targetMember != null) 105 { 106 // Try to replace an existing attribute. 107 if (!replaceAttributes || 108 !replaceAttribute(targetMember.u2attributesCount, 109 targetMember.attributes, 110 attribute)) 111 { 112 // Otherwise append the attribute. 113 targetMember.attributes = 114 addAttribute(targetMember.u2attributesCount, 115 targetMember.attributes, 116 attribute); 117 118 targetMember.u2attributesCount++; 119 } 120 } 121 else 122 { 123 // Try to replace an existing attribute. 124 if (!replaceAttributes || 125 !replaceAttribute(targetClass.u2attributesCount, 126 targetClass.attributes, 127 attribute)) 128 { 129 // Otherwise append the attribute. 130 targetClass.attributes = 131 addAttribute(targetClass.u2attributesCount, 132 targetClass.attributes, 133 attribute); 134 135 targetClass.u2attributesCount++; 136 } 137 } 138 } 139 140 141 /** 142 * Deletes the specified attribute from the target. 143 */ 144 public void deleteAttribute(String attributeName) 145 { 146 // What's the target? 147 if (targetAttribute != null) 148 { 149 targetAttribute.u2attributesCount = 150 deleteAttribute(targetAttribute.u2attributesCount, 151 targetAttribute.attributes, 152 attributeName); 153 } 154 else if (targetMember != null) 155 { 156 targetMember.u2attributesCount = 157 deleteAttribute(targetMember.u2attributesCount, 158 targetMember.attributes, 159 attributeName); 160 } 161 else 162 { 163 targetClass.u2attributesCount = 164 deleteAttribute(targetClass.u2attributesCount, 165 targetClass.attributes, 166 attributeName); 167 } 168 } 169 170 171 // Small utility methods. 172 173 /** 174 * Tries put the given attribute in place of an existing attribute of the 175 * same name, returning whether it was present. 176 */ 177 private boolean replaceAttribute(int attributesCount, 178 Attribute[] attributes, 179 Attribute attribute) 180 { 181 // Find the attribute with the same name. 182 int index = findAttribute(attributesCount, 183 attributes, 184 attribute.getAttributeName(targetClass)); 185 if (index < 0) 186 { 187 return false; 188 } 189 190 attributes[index] = attribute; 191 192 return true; 193 } 194 195 196 /** 197 * Appends the given attribute to the given array of attributes, creating a 198 * new array if necessary. 199 */ 200 private Attribute[] addAttribute(int attributesCount, 201 Attribute[] attributes, 202 Attribute attribute) 203 { 204 // Is the array too small to contain the additional attribute? 205 if (attributes.length <= attributesCount) 206 { 207 // Create a new array and copy the attributes into it. 208 Attribute[] newAttributes = new Attribute[attributesCount + 1]; 209 System.arraycopy(attributes, 0, 210 newAttributes, 0, 211 attributesCount); 212 attributes = newAttributes; 213 } 214 215 // Append the attribute. 216 attributes[attributesCount] = attribute; 217 218 return attributes; 219 } 220 221 222 /** 223 * Deletes the attributes with the given name from the given array of 224 * attributes, returning the new number of attributes. 225 */ 226 private int deleteAttribute(int attributesCount, 227 Attribute[] attributes, 228 String attributeName) 229 { 230 // Find the attribute. 231 int index = findAttribute(attributesCount, 232 attributes, 233 attributeName); 234 if (index < 0) 235 { 236 return attributesCount; 237 } 238 239 // Shift the other attributes in the array. 240 System.arraycopy(attributes, index + 1, 241 attributes, index, 242 attributesCount - index - 1); 243 244 // Clear the last entry in the array. 245 attributes[--attributesCount] = null; 246 247 return attributesCount; 248 } 249 250 251 /** 252 * Finds the index of the attribute with the given name in the given 253 * array of attributes. 254 */ 255 private int findAttribute(int attributesCount, 256 Attribute[] attributes, 257 String attributeName) 258 { 259 for (int index = 0; index < attributesCount; index++) 260 { 261 if (attributes[index].getAttributeName(targetClass).equals(attributeName)) 262 { 263 return index; 264 } 265 } 266 267 return -1; 268 } 269} 270