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.*;
24import proguard.*;
25
26import java.io.IOException;
27import java.util.*;
28
29/**
30 * This Task allows to define a ProGuard configuration from Ant.
31 *
32 * @author Eric Lafortune
33 */
34public class ConfigurationTask extends Task
35{
36    protected final Configuration configuration = new Configuration();
37
38
39    /**
40     * Adds the contents of this configuration task to the given configuration.
41     * @param configuration the configuration to be extended.
42     */
43    public void appendTo(Configuration configuration)
44    {
45        // Append all of these configuration entries to the given configuration.
46        configuration.programJars               = extendClassPath(configuration.programJars,
47                                                                  this.configuration.programJars);
48
49        configuration.libraryJars               = extendClassPath(configuration.libraryJars,
50                                                                  this.configuration.libraryJars);
51
52        configuration.keep                      = extendClassSpecifications(configuration.keep,
53                                                                            this.configuration.keep);
54
55        configuration.keepDirectories           = extendList(configuration.keepDirectories,
56                                                             this.configuration.keepDirectories);
57
58        configuration.whyAreYouKeeping          = extendClassSpecifications(configuration.whyAreYouKeeping,
59                                                                            this.configuration.whyAreYouKeeping);
60
61        configuration.optimizations             = extendClassSpecifications(configuration.optimizations,
62                                                                            this.configuration.optimizations);
63
64        configuration.assumeNoSideEffects       = extendClassSpecifications(configuration.assumeNoSideEffects,
65                                                                            this.configuration.assumeNoSideEffects);
66
67        configuration.keepPackageNames          = extendList(configuration.keepPackageNames,
68                                                             this.configuration.keepPackageNames);
69
70        configuration.keepAttributes            = extendList(configuration.keepAttributes,
71                                                             this.configuration.keepAttributes);
72
73        configuration.adaptClassStrings         = extendList(configuration.adaptClassStrings,
74                                                             this.configuration.adaptClassStrings);
75
76        configuration.adaptResourceFileNames    = extendList(configuration.adaptResourceFileNames,
77                                                             this.configuration.adaptResourceFileNames);
78
79        configuration.adaptResourceFileContents = extendList(configuration.adaptResourceFileContents,
80                                                             this.configuration.adaptResourceFileContents);
81
82        configuration.note                      = extendList(configuration.note,
83                                                             this.configuration.note);
84
85        configuration.warn                      = extendList(configuration.warn,
86                                                             this.configuration.warn);
87    }
88
89
90    // Ant task nested elements.
91
92    public void addConfiguredInjar(ClassPathElement classPathElement)
93    {
94        configuration.programJars = extendClassPath(configuration.programJars,
95                                                    classPathElement,
96                                                    false);
97    }
98
99
100    public void addConfiguredOutjar(ClassPathElement classPathElement)
101    {
102        configuration.programJars = extendClassPath(configuration.programJars,
103                                                    classPathElement,
104                                                    true);
105    }
106
107
108    public void addConfiguredLibraryjar(ClassPathElement classPathElement)
109    {
110        configuration.libraryJars = extendClassPath(configuration.libraryJars,
111                                                    classPathElement,
112                                                    false);
113    }
114
115
116    public void addConfiguredKeepdirectory(FilterElement filterElement)
117    {
118        configuration.keepDirectories = extendFilter(configuration.keepDirectories,
119                                                     filterElement);
120    }
121
122
123    public void addConfiguredKeepdirectories(FilterElement filterElement)
124    {
125        configuration.keepDirectories = extendFilter(configuration.keepDirectories,
126                                                     filterElement);
127    }
128
129
130    public void addConfiguredKeep(KeepSpecificationElement keepSpecificationElement)
131    {
132        configuration.keep = extendKeepSpecifications(configuration.keep,
133                                                      keepSpecificationElement,
134                                                      true,
135                                                      false);
136    }
137
138
139    public void addConfiguredKeepclassmembers(KeepSpecificationElement keepSpecificationElement)
140    {
141        configuration.keep = extendKeepSpecifications(configuration.keep,
142                                                      keepSpecificationElement,
143                                                      false,
144                                                      false);
145    }
146
147
148    public void addConfiguredKeepclasseswithmembers(KeepSpecificationElement keepSpecificationElement)
149    {
150        configuration.keep = extendKeepSpecifications(configuration.keep,
151                                                      keepSpecificationElement,
152                                                      true,
153                                                      true);
154    }
155
156
157    public void addConfiguredKeepnames(KeepSpecificationElement keepSpecificationElement)
158    {
159        // Set the shrinking flag, based on the name (backward compatibility).
160        keepSpecificationElement.setAllowshrinking(true);
161
162        configuration.keep = extendKeepSpecifications(configuration.keep,
163                                                      keepSpecificationElement,
164                                                      true,
165                                                      false);
166    }
167
168
169    public void addConfiguredKeepclassmembernames(KeepSpecificationElement keepSpecificationElement)
170    {
171        // Set the shrinking flag, based on the name (backward compatibility).
172        keepSpecificationElement.setAllowshrinking(true);
173
174        configuration.keep = extendKeepSpecifications(configuration.keep,
175                                                      keepSpecificationElement,
176                                                      false,
177                                                      false);
178    }
179
180
181    public void addConfiguredKeepclasseswithmembernames(KeepSpecificationElement keepSpecificationElement)
182    {
183        // Set the shrinking flag, based on the name (backward compatibility).
184        keepSpecificationElement.setAllowshrinking(true);
185
186        configuration.keep = extendKeepSpecifications(configuration.keep,
187                                                      keepSpecificationElement,
188                                                      true,
189                                                      true);
190    }
191
192
193    public void addConfiguredWhyareyoukeeping(ClassSpecificationElement classSpecificationElement)
194    {
195        configuration.whyAreYouKeeping = extendClassSpecifications(configuration.whyAreYouKeeping,
196                                                                   classSpecificationElement);
197    }
198
199
200    public void addConfiguredAssumenosideeffects(ClassSpecificationElement classSpecificationElement)
201    {
202        configuration.assumeNoSideEffects = extendClassSpecifications(configuration.assumeNoSideEffects,
203                                                                      classSpecificationElement);
204    }
205
206
207    public void addConfiguredOptimizations(FilterElement filterElement)
208    {
209        addConfiguredOptimization(filterElement);
210    }
211
212
213    public void addConfiguredOptimization(FilterElement filterElement)
214    {
215        configuration.optimizations = extendFilter(configuration.optimizations,
216                                                   filterElement);
217    }
218
219
220    public void addConfiguredKeeppackagename(FilterElement filterElement)
221    {
222        configuration.keepPackageNames = extendFilter(configuration.keepPackageNames,
223                                                      filterElement,
224                                                      true);
225    }
226
227
228    public void addConfiguredKeeppackagenames(FilterElement filterElement)
229    {
230        configuration.keepPackageNames = extendFilter(configuration.keepPackageNames,
231                                                      filterElement,
232                                                      true);
233    }
234
235
236    public void addConfiguredKeepattributes(FilterElement filterElement)
237    {
238        addConfiguredKeepattribute(filterElement);
239    }
240
241
242    public void addConfiguredKeepattribute(FilterElement filterElement)
243    {
244        configuration.keepAttributes = extendFilter(configuration.keepAttributes,
245                                                    filterElement);
246    }
247
248
249    public void addConfiguredAdaptclassstrings(FilterElement filterElement)
250    {
251        configuration.adaptClassStrings = extendFilter(configuration.adaptClassStrings,
252                                                       filterElement, true);
253    }
254
255
256    public void addConfiguredAdaptresourcefilenames(FilterElement filterElement)
257    {
258        configuration.adaptResourceFileNames = extendFilter(configuration.adaptResourceFileNames,
259                                                            filterElement);
260    }
261
262
263    public void addConfiguredAdaptresourcefilecontents(FilterElement filterElement)
264    {
265        configuration.adaptResourceFileContents = extendFilter(configuration.adaptResourceFileContents,
266                                                               filterElement);
267    }
268
269
270    public void addConfiguredDontnote(FilterElement filterElement)
271    {
272        configuration.note = extendFilter(configuration.note, filterElement, true);
273    }
274
275
276    public void addConfiguredDontwarn(FilterElement filterElement)
277    {
278        configuration.warn = extendFilter(configuration.warn, filterElement, true);
279    }
280
281
282    public void addConfiguredConfiguration(ConfigurationElement configurationElement)
283    {
284        configurationElement.appendTo(configuration);
285    }
286
287
288    // Implementations for Task.
289
290    public void addText(String text) throws BuildException
291    {
292        try
293        {
294            Project project = getProject();
295
296            // Replace Ant-style properties ('${...}').
297            String arg = project.replaceProperties(text);
298
299            // Get the combined system properties and Ant properties, for
300            // replacing ProGuard-style properties ('<...>').
301            Properties properties = new Properties();
302            properties.putAll(project.getProperties());
303
304            ConfigurationParser parser = new ConfigurationParser(arg,
305                                                                 "embedded configuration",
306                                                                 project.getBaseDir(),
307                                                                 properties);
308
309            try
310            {
311                parser.parse(configuration);
312            }
313            catch (ParseException ex)
314            {
315                throw new BuildException(ex.getMessage());
316            }
317            finally
318            {
319                parser.close();
320            }
321        }
322        catch (IOException ex)
323        {
324            throw new BuildException(ex.getMessage());
325        }
326    }
327
328
329    // Small utility methods.
330
331    private ClassPath extendClassPath(ClassPath        classPath,
332                                      ClassPathElement classPathElement,
333                                      boolean          output)
334    {
335        if (classPath == null)
336        {
337            classPath = new ClassPath();
338        }
339
340        classPathElement.appendClassPathEntriesTo(classPath,
341                                                  output);
342
343        return classPath;
344    }
345
346
347    private ClassPath extendClassPath(ClassPath classPath,
348                                      ClassPath additionalClassPath)
349    {
350        if (additionalClassPath != null)
351        {
352            if (classPath == null)
353            {
354                classPath = new ClassPath();
355            }
356
357            classPath.addAll(additionalClassPath);
358        }
359
360        return classPath;
361    }
362
363
364    private List extendKeepSpecifications(List                     keepSpecifications,
365                                          KeepSpecificationElement keepSpecificationElement,
366                                          boolean                  markClasses,
367                                          boolean                  markClassesConditionally)
368    {
369        if (keepSpecifications == null)
370        {
371            keepSpecifications = new ArrayList();
372        }
373
374        keepSpecificationElement.appendTo(keepSpecifications,
375                                          markClasses,
376                                          markClassesConditionally);
377
378        return keepSpecifications;
379    }
380
381
382    private List extendClassSpecifications(List                      classSpecifications,
383                                           ClassSpecificationElement classSpecificationElement)
384    {
385        if (classSpecifications == null)
386        {
387            classSpecifications = new ArrayList();
388        }
389
390        classSpecificationElement.appendTo(classSpecifications);
391
392        return classSpecifications;
393    }
394
395
396    private List extendClassSpecifications(List classSpecifications,
397                                           List additionalClassSpecifications)
398    {
399        if (additionalClassSpecifications != null)
400        {
401            if (classSpecifications == null)
402            {
403                classSpecifications = new ArrayList();
404            }
405
406            classSpecifications.addAll(additionalClassSpecifications);
407        }
408
409        return classSpecifications;
410    }
411
412
413    private List extendFilter(List          filter,
414                              FilterElement filterElement)
415    {
416        return extendFilter(filter, filterElement, false);
417    }
418
419
420    private List extendFilter(List          filter,
421                              FilterElement filterElement,
422                              boolean       internal)
423    {
424        if (filter == null)
425        {
426            filter = new ArrayList();
427        }
428
429        filterElement.appendTo(filter, internal);
430
431        return filter;
432    }
433
434
435    private List extendList(List list,
436                            List additionalList)
437    {
438        if (additionalList != null)
439        {
440            if (list == null)
441            {
442                list = new ArrayList();
443            }
444
445            list.addAll(additionalList);
446        }
447
448        return list;
449    }
450}
451