• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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