diff options
Diffstat (limited to 'src/proguard/ant/ClassSpecificationElement.java')
-rw-r--r-- | src/proguard/ant/ClassSpecificationElement.java | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/src/proguard/ant/ClassSpecificationElement.java b/src/proguard/ant/ClassSpecificationElement.java new file mode 100644 index 0000000..f4ea2ff --- /dev/null +++ b/src/proguard/ant/ClassSpecificationElement.java @@ -0,0 +1,257 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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; + } +} |