1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 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 * Finds the specified attribute in the target. 83 */ 84 public Attribute findAttribute(String attributeName) 85 { 86 // What's the target? 87 return 88 targetAttribute != null ? 89 findAttribute(targetAttribute.u2attributesCount, 90 targetAttribute.attributes, 91 attributeName) : 92 targetMember != null ? 93 findAttribute(targetMember.u2attributesCount, 94 targetMember.attributes, 95 attributeName) : 96 findAttribute(targetClass.u2attributesCount, 97 targetClass.attributes, 98 attributeName); 99 } 100 101 102 /** 103 * Adds the given attribute to the target. 104 */ 105 public void addAttribute(Attribute attribute) 106 { 107 // What's the target? 108 if (targetAttribute != null) 109 { 110 // Try to replace an existing attribute. 111 if (!replaceAttributes || 112 !replaceAttribute(targetAttribute.u2attributesCount, 113 targetAttribute.attributes, 114 attribute)) 115 { 116 // Otherwise append the attribute. 117 targetAttribute.attributes = 118 addAttribute(targetAttribute.u2attributesCount, 119 targetAttribute.attributes, 120 attribute); 121 122 targetAttribute.u2attributesCount++; 123 } 124 } 125 else if (targetMember != null) 126 { 127 // Try to replace an existing attribute. 128 if (!replaceAttributes || 129 !replaceAttribute(targetMember.u2attributesCount, 130 targetMember.attributes, 131 attribute)) 132 { 133 // Otherwise append the attribute. 134 targetMember.attributes = 135 addAttribute(targetMember.u2attributesCount, 136 targetMember.attributes, 137 attribute); 138 139 targetMember.u2attributesCount++; 140 } 141 } 142 else 143 { 144 // Try to replace an existing attribute. 145 if (!replaceAttributes || 146 !replaceAttribute(targetClass.u2attributesCount, 147 targetClass.attributes, 148 attribute)) 149 { 150 // Otherwise append the attribute. 151 targetClass.attributes = 152 addAttribute(targetClass.u2attributesCount, 153 targetClass.attributes, 154 attribute); 155 156 targetClass.u2attributesCount++; 157 } 158 } 159 } 160 161 162 /** 163 * Deletes the specified attribute from the target. 164 */ 165 public void deleteAttribute(String attributeName) 166 { 167 // What's the target? 168 if (targetAttribute != null) 169 { 170 targetAttribute.u2attributesCount = 171 deleteAttribute(targetAttribute.u2attributesCount, 172 targetAttribute.attributes, 173 attributeName); 174 } 175 else if (targetMember != null) 176 { 177 targetMember.u2attributesCount = 178 deleteAttribute(targetMember.u2attributesCount, 179 targetMember.attributes, 180 attributeName); 181 } 182 else 183 { 184 targetClass.u2attributesCount = 185 deleteAttribute(targetClass.u2attributesCount, 186 targetClass.attributes, 187 attributeName); 188 } 189 } 190 191 192 // Small utility methods. 193 194 /** 195 * Tries to put the given attribute in place of an existing attribute of 196 * the same name, returning whether it was present. 197 */ 198 private boolean replaceAttribute(int attributesCount, 199 Attribute[] attributes, 200 Attribute attribute) 201 { 202 // Find the attribute with the same name. 203 int index = findAttributeIndex(attributesCount, 204 attributes, 205 attribute.getAttributeName(targetClass)); 206 if (index < 0) 207 { 208 return false; 209 } 210 211 attributes[index] = attribute; 212 213 return true; 214 } 215 216 217 /** 218 * Appends the given attribute to the given array of attributes, creating a 219 * new array if necessary. 220 */ 221 private Attribute[] addAttribute(int attributesCount, 222 Attribute[] attributes, 223 Attribute attribute) 224 { 225 // Is the array too small to contain the additional attribute? 226 if (attributes.length <= attributesCount) 227 { 228 // Create a new array and copy the attributes into it. 229 Attribute[] newAttributes = new Attribute[attributesCount + 1]; 230 System.arraycopy(attributes, 0, 231 newAttributes, 0, 232 attributesCount); 233 attributes = newAttributes; 234 } 235 236 // Append the attribute. 237 attributes[attributesCount] = attribute; 238 239 return attributes; 240 } 241 242 243 /** 244 * Deletes the attributes with the given name from the given array of 245 * attributes, returning the new number of attributes. 246 */ 247 private int deleteAttribute(int attributesCount, 248 Attribute[] attributes, 249 String attributeName) 250 { 251 // Find the attribute. 252 int index = findAttributeIndex(attributesCount, 253 attributes, 254 attributeName); 255 if (index < 0) 256 { 257 return attributesCount; 258 } 259 260 // Shift the other attributes in the array. 261 System.arraycopy(attributes, index + 1, 262 attributes, index, 263 attributesCount - index - 1); 264 265 // Clear the last entry in the array. 266 attributes[--attributesCount] = null; 267 268 return attributesCount; 269 } 270 271 272 /** 273 * Finds the index of the attribute with the given name in the given 274 * array of attributes. 275 */ 276 private int findAttributeIndex(int attributesCount, 277 Attribute[] attributes, 278 String attributeName) 279 { 280 for (int index = 0; index < attributesCount; index++) 281 { 282 Attribute attribute = attributes[index]; 283 284 if (attribute.getAttributeName(targetClass).equals(attributeName)) 285 { 286 return index; 287 } 288 } 289 290 return -1; 291 } 292 293 294 /** 295 * Finds the attribute with the given name in the given 296 * array of attributes. 297 */ 298 private Attribute findAttribute(int attributesCount, 299 Attribute[] attributes, 300 String attributeName) 301 { 302 for (int index = 0; index < attributesCount; index++) 303 { 304 Attribute attribute = attributes[index]; 305 306 if (attribute.getAttributeName(targetClass).equals(attributeName)) 307 { 308 return attribute; 309 } 310 } 311 312 return null; 313 } 314} 315