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 */ 21 package proguard.ant; 22 23 import org.apache.tools.ant.BuildException; 24 import org.apache.tools.ant.types.DataType; 25 import proguard.*; 26 import proguard.classfile.*; 27 import proguard.classfile.util.ClassUtil; 28 29 import java.util.*; 30 31 /** 32 * This DataType represents a class specification in Ant. 33 * 34 * @author Eric Lafortune 35 */ 36 public class ClassSpecificationElement extends DataType 37 { 38 private static final String ANY_CLASS_KEYWORD = "*"; 39 40 private String access; 41 private String annotation; 42 private String type; 43 private String name; 44 private String extendsAnnotation; 45 private String extends_; 46 private List fieldSpecifications = new ArrayList(); 47 private List methodSpecifications = new ArrayList(); 48 49 50 /** 51 * Adds the contents of this class specification element to the given list. 52 * @param classSpecifications the class specifications to be extended. 53 */ appendTo(List classSpecifications)54 public void appendTo(List classSpecifications) 55 { 56 // Get the referenced file set, or else this one. 57 ClassSpecificationElement classSpecificationElement = isReference() ? 58 (ClassSpecificationElement)getCheckedRef(this.getClass(), 59 this.getClass().getName()) : 60 this; 61 62 ClassSpecification classSpecification = 63 createClassSpecification(classSpecificationElement); 64 65 // Add it to the list. 66 classSpecifications.add(classSpecification); 67 } 68 69 70 /** 71 * Creates a new class specification corresponding to the contents of this 72 * class specification element. 73 */ createClassSpecification(ClassSpecificationElement classSpecificationElement)74 protected ClassSpecification createClassSpecification(ClassSpecificationElement classSpecificationElement) 75 { 76 String access = classSpecificationElement.access; 77 String annotation = classSpecificationElement.annotation; 78 String type = classSpecificationElement.type; 79 String name = classSpecificationElement.name; 80 String extendsAnnotation = classSpecificationElement.extendsAnnotation; 81 String extends_ = classSpecificationElement.extends_; 82 83 // For backward compatibility, allow a single "*" wildcard to match 84 // any class. 85 if (name != null && 86 name.equals(ANY_CLASS_KEYWORD)) 87 { 88 name = null; 89 } 90 91 ClassSpecification classSpecification = 92 new ClassSpecification(null, 93 requiredAccessFlags(true, access, type), 94 requiredAccessFlags(false, access, type), 95 annotation != null ? ClassUtil.internalType(annotation) : null, 96 name != null ? ClassUtil.internalClassName(name) : null, 97 extendsAnnotation != null ? ClassUtil.internalType(extendsAnnotation) : null, 98 extends_ != null ? ClassUtil.internalClassName(extends_) : null); 99 100 for (int index = 0; index < fieldSpecifications.size(); index++) 101 { 102 classSpecification.addField((MemberSpecification)fieldSpecifications.get(index)); 103 } 104 105 for (int index = 0; index < methodSpecifications.size(); index++) 106 { 107 classSpecification.addMethod((MemberSpecification)methodSpecifications.get(index)); 108 } 109 110 return classSpecification; 111 } 112 113 114 // Ant task attributes. 115 setAccess(String access)116 public void setAccess(String access) 117 { 118 this.access = access; 119 } 120 121 setAnnotation(String annotation)122 public void setAnnotation(String annotation) 123 { 124 this.annotation = annotation; 125 } 126 127 setType(String type)128 public void setType(String type) 129 { 130 this.type = type; 131 } 132 133 setName(String name)134 public void setName(String name) 135 { 136 this.name = name; 137 } 138 139 setExtendsannotation(String extendsAnnotation)140 public void setExtendsannotation(String extendsAnnotation) 141 { 142 this.extendsAnnotation = extendsAnnotation; 143 } 144 145 setExtends(String extends_)146 public void setExtends(String extends_) 147 { 148 this.extends_ = extends_; 149 } 150 151 setImplements(String implements_)152 public void setImplements(String implements_) 153 { 154 this.extends_ = implements_; 155 } 156 157 158 // Ant task nested elements. 159 addConfiguredField(MemberSpecificationElement memberSpecificationElement)160 public void addConfiguredField(MemberSpecificationElement memberSpecificationElement) 161 { 162 if (fieldSpecifications == null) 163 { 164 fieldSpecifications = new ArrayList(); 165 } 166 167 memberSpecificationElement.appendTo(fieldSpecifications, 168 false, 169 false); 170 } 171 172 addConfiguredMethod(MemberSpecificationElement memberSpecificationElement)173 public void addConfiguredMethod(MemberSpecificationElement memberSpecificationElement) 174 { 175 if (methodSpecifications == null) 176 { 177 methodSpecifications = new ArrayList(); 178 } 179 180 memberSpecificationElement.appendTo(methodSpecifications, 181 true, 182 false); 183 } 184 185 addConfiguredConstructor(MemberSpecificationElement memberSpecificationElement)186 public void addConfiguredConstructor(MemberSpecificationElement memberSpecificationElement) 187 { 188 if (methodSpecifications == null) 189 { 190 methodSpecifications = new ArrayList(); 191 } 192 193 memberSpecificationElement.appendTo(methodSpecifications, 194 true, 195 true); 196 } 197 198 199 // Small utility methods. 200 requiredAccessFlags(boolean set, String access, String type)201 private int requiredAccessFlags(boolean set, 202 String access, 203 String type) 204 throws BuildException 205 { 206 int accessFlags = 0; 207 208 if (access != null) 209 { 210 StringTokenizer tokenizer = new StringTokenizer(access, " ,"); 211 while (tokenizer.hasMoreTokens()) 212 { 213 String token = tokenizer.nextToken(); 214 215 if (token.startsWith("!") ^ set) 216 { 217 String strippedToken = token.startsWith("!") ? 218 token.substring(1) : 219 token; 220 221 int accessFlag = 222 strippedToken.equals(JavaConstants.ACC_PUBLIC) ? ClassConstants.ACC_PUBLIC : 223 strippedToken.equals(JavaConstants.ACC_FINAL) ? ClassConstants.ACC_FINAL : 224 strippedToken.equals(JavaConstants.ACC_ABSTRACT) ? ClassConstants.ACC_ABSTRACT : 225 strippedToken.equals(JavaConstants.ACC_SYNTHETIC) ? ClassConstants.ACC_SYNTHETIC : 226 strippedToken.equals(JavaConstants.ACC_ANNOTATION) ? ClassConstants.ACC_ANNOTATTION : 227 0; 228 229 if (accessFlag == 0) 230 { 231 throw new BuildException("Incorrect class access modifier ["+strippedToken+"]"); 232 } 233 234 accessFlags |= accessFlag; 235 } 236 } 237 } 238 239 if (type != null && (type.startsWith("!") ^ set)) 240 { 241 int accessFlag = 242 type.equals("class") ? 0 : 243 type.equals( JavaConstants.ACC_INTERFACE) || 244 type.equals("!" + JavaConstants.ACC_INTERFACE) ? ClassConstants.ACC_INTERFACE : 245 type.equals( JavaConstants.ACC_ENUM) || 246 type.equals("!" + JavaConstants.ACC_ENUM) ? ClassConstants.ACC_ENUM : 247 -1; 248 249 if (accessFlag == -1) 250 { 251 throw new BuildException("Incorrect class type ["+type+"]"); 252 } 253 254 accessFlags |= accessFlag; 255 } 256 257 return accessFlags; 258 } 259 } 260