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.ant; 22 23import org.apache.tools.ant.BuildException; 24import org.apache.tools.ant.types.DataType; 25import proguard.MemberSpecification; 26import proguard.classfile.*; 27import proguard.classfile.util.ClassUtil; 28import proguard.util.ListUtil; 29 30import java.util.*; 31 32/** 33 * This DataType represents a class member specification in Ant. 34 * 35 * @author Eric Lafortune 36 */ 37public 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 member 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 = JavaConstants.TYPE_VOID; 91 } 92 93 name = ClassConstants.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(JavaConstants.ACC_PUBLIC) ? ClassConstants.ACC_PUBLIC : 191 strippedToken.equals(JavaConstants.ACC_PRIVATE) ? ClassConstants.ACC_PRIVATE : 192 strippedToken.equals(JavaConstants.ACC_PROTECTED) ? ClassConstants.ACC_PROTECTED : 193 strippedToken.equals(JavaConstants.ACC_STATIC) ? ClassConstants.ACC_STATIC : 194 strippedToken.equals(JavaConstants.ACC_FINAL) ? ClassConstants.ACC_FINAL : 195 strippedToken.equals(JavaConstants.ACC_SYNCHRONIZED) ? ClassConstants.ACC_SYNCHRONIZED : 196 strippedToken.equals(JavaConstants.ACC_VOLATILE) ? ClassConstants.ACC_VOLATILE : 197 strippedToken.equals(JavaConstants.ACC_TRANSIENT) ? ClassConstants.ACC_TRANSIENT : 198 strippedToken.equals(JavaConstants.ACC_BRIDGE) ? ClassConstants.ACC_BRIDGE : 199 strippedToken.equals(JavaConstants.ACC_VARARGS) ? ClassConstants.ACC_VARARGS : 200 strippedToken.equals(JavaConstants.ACC_NATIVE) ? ClassConstants.ACC_NATIVE : 201 strippedToken.equals(JavaConstants.ACC_ABSTRACT) ? ClassConstants.ACC_ABSTRACT : 202 strippedToken.equals(JavaConstants.ACC_STRICT) ? ClassConstants.ACC_STRICT : 203 strippedToken.equals(JavaConstants.ACC_SYNTHETIC) ? ClassConstants.ACC_SYNTHETIC : 204 0; 205 206 if (accessFlag == 0) 207 { 208 throw new BuildException("Incorrect class member access modifier ["+strippedToken+"]"); 209 } 210 211 accessFlags |= accessFlag; 212 } 213 } 214 } 215 216 return accessFlags; 217 } 218} 219