1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 Eric Lafortune (eric (at) 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.MemberSpecification; 26 import proguard.classfile.ClassConstants; 27 import proguard.classfile.util.ClassUtil; 28 import proguard.util.ListUtil; 29 30 import java.util.*; 31 32 /** 33 * This DataType represents a class member specification in Ant. 34 * 35 * @author Eric Lafortune 36 */ 37 public class MemberSpecificationElement extends DataType 38 { 39 private String access; 40 private String annotation; 41 private String type; 42 private String name; 43 private String parameters; 44 45 46 /** 47 * Adds the contents of this class member specification element to the given 48 * list. 49 * @param memberSpecifications the class member specifications to be 50 * extended. 51 * @param isMethod specifies whether this specification 52 * refers to a method. 53 * @param isConstructor specifies whether this specification 54 * refers to a constructor. 55 */ 56 public void appendTo(List memberSpecifications, 57 boolean isMethod, 58 boolean isConstructor) 59 { 60 // Get the referenced file set, or else this one. 61 MemberSpecificationElement memberSpecificationElement = isReference() ? 62 (MemberSpecificationElement)getCheckedRef(this.getClass(), 63 this.getClass().getName()) : 64 this; 65 66 // Create a new class specification. 67 String access = memberSpecificationElement.access; 68 String type = memberSpecificationElement.type; 69 String annotation = memberSpecificationElement.annotation; 70 String name = memberSpecificationElement.name; 71 String parameters = memberSpecificationElement.parameters; 72 73 // Perform some basic conversions and checks on the attributes. 74 if (annotation != null) 75 { 76 annotation = ClassUtil.internalType(annotation); 77 } 78 79 if (isMethod) 80 { 81 if (isConstructor) 82 { 83 if (type != null) 84 { 85 throw new BuildException("Type attribute not allowed in constructor specification ["+type+"]"); 86 } 87 88 if (parameters != null) 89 { 90 type = ClassConstants.EXTERNAL_TYPE_VOID; 91 } 92 93 name = ClassConstants.INTERNAL_METHOD_NAME_INIT; 94 } 95 else if ((type != null) ^ (parameters != null)) 96 { 97 throw new BuildException("Type and parameters attributes must always be present in combination in method specification"); 98 } 99 } 100 else 101 { 102 if (parameters != null) 103 { 104 throw new BuildException("Parameters attribute not allowed in field specification ["+parameters+"]"); 105 } 106 } 107 108 List parameterList = ListUtil.commaSeparatedList(parameters); 109 110 String descriptor = 111 parameters != null ? ClassUtil.internalMethodDescriptor(type, parameterList) : 112 type != null ? ClassUtil.internalType(type) : 113 null; 114 115 MemberSpecification memberSpecification = 116 new MemberSpecification(requiredAccessFlags(true, access), 117 requiredAccessFlags(false, access), 118 annotation, 119 name, 120 descriptor); 121 122 // Add it to the list. 123 memberSpecifications.add(memberSpecification); 124 } 125 126 127 // Ant task attributes. 128 129 public void setAccess(String access) 130 { 131 this.access = access; 132 } 133 134 135 public void setAnnotation(String annotation) 136 { 137 this.annotation = annotation; 138 } 139 140 141 public void setType(String type) 142 { 143 this.type = type; 144 } 145 146 147 public void setName(String name) 148 { 149 this.name = name; 150 } 151 152 153 public void setParameters(String parameters) 154 { 155 this.parameters = parameters; 156 } 157 158 159 /** 160 * @deprecated Use {@link #setParameters(String)} instead. 161 */ 162 public void setParam(String parameters) 163 { 164 this.parameters = parameters; 165 } 166 167 168 // Small utility methods. 169 170 private int requiredAccessFlags(boolean set, 171 String access) 172 throws BuildException 173 { 174 int accessFlags = 0; 175 176 if (access != null) 177 { 178 StringTokenizer tokenizer = new StringTokenizer(access, " ,"); 179 while (tokenizer.hasMoreTokens()) 180 { 181 String token = tokenizer.nextToken(); 182 183 if (token.startsWith("!") ^ set) 184 { 185 String strippedToken = token.startsWith("!") ? 186 token.substring(1) : 187 token; 188 189 int accessFlag = 190 strippedToken.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC : 191 strippedToken.equals(ClassConstants.EXTERNAL_ACC_PRIVATE) ? ClassConstants.INTERNAL_ACC_PRIVATE : 192 strippedToken.equals(ClassConstants.EXTERNAL_ACC_PROTECTED) ? ClassConstants.INTERNAL_ACC_PROTECTED : 193 strippedToken.equals(ClassConstants.EXTERNAL_ACC_STATIC) ? ClassConstants.INTERNAL_ACC_STATIC : 194 strippedToken.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL : 195 strippedToken.equals(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED) ? ClassConstants.INTERNAL_ACC_SYNCHRONIZED : 196 strippedToken.equals(ClassConstants.EXTERNAL_ACC_VOLATILE) ? ClassConstants.INTERNAL_ACC_VOLATILE : 197 strippedToken.equals(ClassConstants.EXTERNAL_ACC_TRANSIENT) ? ClassConstants.INTERNAL_ACC_TRANSIENT : 198 strippedToken.equals(ClassConstants.EXTERNAL_ACC_NATIVE) ? ClassConstants.INTERNAL_ACC_NATIVE : 199 strippedToken.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT : 200 strippedToken.equals(ClassConstants.EXTERNAL_ACC_STRICT) ? ClassConstants.INTERNAL_ACC_STRICT : 201 0; 202 203 if (accessFlag == 0) 204 { 205 throw new BuildException("Incorrect class member access modifier ["+strippedToken+"]"); 206 } 207 208 accessFlags |= accessFlag; 209 } 210 } 211 } 212 213 return accessFlags; 214 } 215 } 216