/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2010 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package proguard.ant; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.types.DataType; import proguard.*; import proguard.classfile.ClassConstants; import proguard.classfile.util.ClassUtil; import java.util.*; /** * This DataType represents a class specification in Ant. * * @author Eric Lafortune */ public class ClassSpecificationElement extends DataType { private static final String ANY_CLASS_KEYWORD = "*"; private String access; private String annotation; private String type; private String name; private String extendsAnnotation; private String extends_; private List fieldSpecifications = new ArrayList(); private List methodSpecifications = new ArrayList(); /** * Adds the contents of this class specification element to the given list. * @param classSpecifications the class specifications to be extended. */ public void appendTo(List classSpecifications) { // Get the referenced file set, or else this one. ClassSpecificationElement classSpecificationElement = isReference() ? (ClassSpecificationElement)getCheckedRef(this.getClass(), this.getClass().getName()) : this; ClassSpecification classSpecification = createClassSpecification(classSpecificationElement); // Add it to the list. classSpecifications.add(classSpecification); } /** * Creates a new class specification corresponding to the contents of this * class specification element. */ protected ClassSpecification createClassSpecification(ClassSpecificationElement classSpecificationElement) { String access = classSpecificationElement.access; String annotation = classSpecificationElement.annotation; String type = classSpecificationElement.type; String name = classSpecificationElement.name; String extendsAnnotation = classSpecificationElement.extendsAnnotation; String extends_ = classSpecificationElement.extends_; // For backward compatibility, allow a single "*" wildcard to match // any class. if (name != null && name.equals(ANY_CLASS_KEYWORD)) { name = null; } ClassSpecification classSpecification = new ClassSpecification(null, requiredAccessFlags(true, access, type), requiredAccessFlags(false, access, type), annotation != null ? ClassUtil.internalType(annotation) : null, name != null ? ClassUtil.internalClassName(name) : null, extendsAnnotation != null ? ClassUtil.internalType(extendsAnnotation) : null, extends_ != null ? ClassUtil.internalClassName(extends_) : null); for (int index = 0; index < fieldSpecifications.size(); index++) { classSpecification.addField((MemberSpecification)fieldSpecifications.get(index)); } for (int index = 0; index < methodSpecifications.size(); index++) { classSpecification.addMethod((MemberSpecification)methodSpecifications.get(index)); } return classSpecification; } // Ant task attributes. public void setAccess(String access) { this.access = access; } public void setAnnotation(String annotation) { this.annotation = annotation; } public void setType(String type) { this.type = type; } public void setName(String name) { this.name = name; } public void setExtendsannotation(String extendsAnnotation) { this.extendsAnnotation = extendsAnnotation; } public void setExtends(String extends_) { this.extends_ = extends_; } public void setImplements(String implements_) { this.extends_ = implements_; } // Ant task nested elements. public void addConfiguredField(MemberSpecificationElement memberSpecificationElement) { if (fieldSpecifications == null) { fieldSpecifications = new ArrayList(); } memberSpecificationElement.appendTo(fieldSpecifications, false, false); } public void addConfiguredMethod(MemberSpecificationElement memberSpecificationElement) { if (methodSpecifications == null) { methodSpecifications = new ArrayList(); } memberSpecificationElement.appendTo(methodSpecifications, true, false); } public void addConfiguredConstructor(MemberSpecificationElement memberSpecificationElement) { if (methodSpecifications == null) { methodSpecifications = new ArrayList(); } memberSpecificationElement.appendTo(methodSpecifications, true, true); } // Small utility methods. private int requiredAccessFlags(boolean set, String access, String type) throws BuildException { int accessFlags = 0; if (access != null) { StringTokenizer tokenizer = new StringTokenizer(access, " ,"); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); if (token.startsWith("!") ^ set) { String strippedToken = token.startsWith("!") ? token.substring(1) : token; int accessFlag = strippedToken.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC : strippedToken.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL : strippedToken.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT : strippedToken.equals(ClassConstants.EXTERNAL_ACC_ANNOTATION) ? ClassConstants.INTERNAL_ACC_ANNOTATTION : 0; if (accessFlag == 0) { throw new BuildException("Incorrect class access modifier ["+strippedToken+"]"); } accessFlags |= accessFlag; } } } if (type != null && (type.startsWith("!") ^ set)) { int accessFlag = type.equals("class") ? 0 : type.equals( ClassConstants.EXTERNAL_ACC_INTERFACE) || type.equals("!" + ClassConstants.EXTERNAL_ACC_INTERFACE) ? ClassConstants.INTERNAL_ACC_INTERFACE : type.equals( ClassConstants.EXTERNAL_ACC_ENUM) || type.equals("!" + ClassConstants.EXTERNAL_ACC_ENUM) ? ClassConstants.INTERNAL_ACC_ENUM : -1; if (accessFlag == -1) { throw new BuildException("Incorrect class type ["+type+"]"); } accessFlags |= accessFlag; } return accessFlags; } }