KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > ConfigurationWriter


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 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;
22
23 import proguard.classfile.*;
24 import proguard.classfile.util.*;
25 import proguard.util.*;
26
27 import java.io.*;
28 import java.util.*;
29
30
31 /**
32  * This class writes ProGuard configurations to a file.
33  *
34  * @author Eric Lafortune
35  */

36 public class ConfigurationWriter
37 {
38     private static final String JavaDoc[] KEEP_OPTIONS = new String JavaDoc[]
39     {
40         ConfigurationConstants.KEEP_OPTION,
41         ConfigurationConstants.KEEP_CLASS_MEMBERS_OPTION,
42         ConfigurationConstants.KEEP_CLASSES_WITH_MEMBERS_OPTION
43     };
44
45
46     private PrintWriter writer;
47     private File baseDir;
48
49
50     /**
51      * Creates a new ConfigurationWriter for the given file name.
52      */

53     public ConfigurationWriter(File configurationFile) throws IOException
54     {
55         this(new PrintWriter(new FileWriter(configurationFile)));
56
57         baseDir = configurationFile.getParentFile();
58     }
59
60
61     /**
62      * Creates a new ConfigurationWriter for the given OutputStream.
63      */

64     public ConfigurationWriter(OutputStream outputStream) throws IOException
65     {
66         this(new PrintWriter(outputStream));
67     }
68
69
70     /**
71      * Creates a new ConfigurationWriter for the given PrintWriter.
72      */

73     public ConfigurationWriter(PrintWriter writer) throws IOException
74     {
75         this.writer = writer;
76     }
77
78
79     /**
80      * Closes this ConfigurationWriter.
81      */

82     public void close() throws IOException
83     {
84         writer.close();
85     }
86
87
88     /**
89      * Writes the given configuration.
90      * @param configuration the configuration that is to be written out.
91      * @throws IOException if an IO error occurs while writing the configuration.
92      */

93     public void write(Configuration configuration) throws IOException
94     {
95         // Write the program class path (input and output entries).
96
writeJarOptions(ConfigurationConstants.INJARS_OPTION,
97                         ConfigurationConstants.OUTJARS_OPTION,
98                         configuration.programJars);
99         writer.println();
100
101         // Write the library class path (output entries only).
102
writeJarOptions(ConfigurationConstants.LIBRARYJARS_OPTION,
103                         ConfigurationConstants.LIBRARYJARS_OPTION,
104                         configuration.libraryJars);
105         writer.println();
106
107         // Write the other options.
108
writeOption(ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION, !configuration.skipNonPublicLibraryClasses);
109         writeOption(ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION, !configuration.skipNonPublicLibraryClassMembers);
110         writeOption(ConfigurationConstants.TARGET_OPTION, ClassUtil.externalClassVersion(configuration.targetClassVersion));
111         writeOption(ConfigurationConstants.FORCE_PROCESSING_OPTION, configuration.lastModified == Long.MAX_VALUE);
112
113         writeOption(ConfigurationConstants.DONT_SHRINK_OPTION, !configuration.shrink);
114         writeOption(ConfigurationConstants.PRINT_USAGE_OPTION, configuration.printUsage);
115
116         writeOption(ConfigurationConstants.DONT_OPTIMIZE_OPTION, !configuration.optimize);
117         writeOption(ConfigurationConstants.OPTIMIZATION_PASSES, configuration.optimizationPasses);
118         writeOption(ConfigurationConstants.ALLOW_ACCESS_MODIFICATION_OPTION, configuration.allowAccessModification);
119
120         writeOption(ConfigurationConstants.DONT_OBFUSCATE_OPTION, !configuration.obfuscate);
121         writeOption(ConfigurationConstants.PRINT_MAPPING_OPTION, configuration.printMapping);
122         writeOption(ConfigurationConstants.APPLY_MAPPING_OPTION, configuration.applyMapping);
123         writeOption(ConfigurationConstants.OBFUSCATION_DICTIONARY_OPTION, configuration.obfuscationDictionary);
124         writeOption(ConfigurationConstants.OVERLOAD_AGGRESSIVELY_OPTION, configuration.overloadAggressively);
125         writeOption(ConfigurationConstants.USE_UNIQUE_CLASS_MEMBER_NAMES_OPTION, configuration.useUniqueClassMemberNames);
126         writeOption(ConfigurationConstants.DONT_USE_MIXED_CASE_CLASS_NAMES_OPTION, !configuration.useMixedCaseClassNames);
127         writeOption(ConfigurationConstants.FLATTEN_PACKAGE_HIERARCHY_OPTION, configuration.flattenPackageHierarchy == null ? null : ClassUtil.externalClassName(configuration.flattenPackageHierarchy));
128         writeOption(ConfigurationConstants.REPACKAGE_CLASSES_OPTION, configuration.repackageClasses == null ? null : ClassUtil.externalClassName(configuration.repackageClasses));
129         writeOption(ConfigurationConstants.KEEP_ATTRIBUTES_OPTION, ListUtil.commaSeparatedString(configuration.keepAttributes));
130         writeOption(ConfigurationConstants.RENAME_SOURCE_FILE_ATTRIBUTE_OPTION, configuration.newSourceFileAttribute);
131         writeOption(ConfigurationConstants.ADAPT_RESOURCE_FILE_NAMES_OPTION, ListUtil.commaSeparatedString(configuration.adaptResourceFileNames));
132         writeOption(ConfigurationConstants.ADAPT_RESOURCE_FILE_CONTENTS_OPTION, ListUtil.commaSeparatedString(configuration.adaptResourceFileContents));
133
134         writeOption(ConfigurationConstants.DONT_PREVERIFY_OPTION, !configuration.preverify);
135         writeOption(ConfigurationConstants.MICRO_EDITION_OPTION, configuration.microEdition);
136
137         writeOption(ConfigurationConstants.VERBOSE_OPTION, configuration.verbose);
138         writeOption(ConfigurationConstants.DONT_NOTE_OPTION, !configuration.note);
139         writeOption(ConfigurationConstants.DONT_WARN_OPTION, !configuration.warn);
140         writeOption(ConfigurationConstants.IGNORE_WARNINGS_OPTION, configuration.ignoreWarnings);
141         writeOption(ConfigurationConstants.PRINT_CONFIGURATION_OPTION, configuration.printConfiguration);
142         writeOption(ConfigurationConstants.DUMP_OPTION, configuration.dump);
143
144         writeOption(ConfigurationConstants.PRINT_SEEDS_OPTION, configuration.printSeeds);
145         writer.println();
146
147         // Write the "why are you keeping" options.
148
writeOptions(ConfigurationConstants.WHY_ARE_YOU_KEEPING_OPTION, configuration.whyAreYouKeeping);
149
150         // Write the keep options.
151
writeOptions(KEEP_OPTIONS, configuration.keep);
152
153         // Write the "no side effect methods" options.
154
writeOptions(ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION, configuration.assumeNoSideEffects);
155
156         writer.flush();
157     }
158
159
160     private void writeJarOptions(String JavaDoc inputEntryOptionName,
161                                  String JavaDoc outputEntryOptionName,
162                                  ClassPath classPath)
163     {
164         if (classPath != null)
165         {
166             for (int index = 0; index < classPath.size(); index++)
167             {
168                 ClassPathEntry entry = classPath.get(index);
169                 String JavaDoc optionName = entry.isOutput() ?
170                      outputEntryOptionName :
171                      inputEntryOptionName;
172
173                 writer.print(optionName);
174                 writer.print(' ');
175                 writer.print(relativeFileName(entry.getFile()));
176
177                 // Append the filters, if any.
178
boolean filtered = false;
179
180                 filtered = writeFilter(filtered, entry.getZipFilter());
181                 filtered = writeFilter(filtered, entry.getEarFilter());
182                 filtered = writeFilter(filtered, entry.getWarFilter());
183                 filtered = writeFilter(filtered, entry.getJarFilter());
184                 filtered = writeFilter(filtered, entry.getFilter());
185
186                 if (filtered)
187                 {
188                     writer.print(ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD);
189                 }
190
191                 writer.println();
192             }
193         }
194     }
195
196
197     private boolean writeFilter(boolean filtered, String JavaDoc filter)
198     {
199         if (filtered)
200         {
201             writer.print(ConfigurationConstants.SEPARATOR_KEYWORD);
202         }
203
204         if (filter != null)
205         {
206             if (!filtered)
207             {
208                 writer.print(ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD);
209             }
210
211             writer.print(quotedString(filter));
212
213             filtered = true;
214         }
215
216         return filtered;
217     }
218
219
220     private void writeOption(String JavaDoc optionName, boolean flag)
221     {
222         if (flag)
223         {
224             writer.println(optionName);
225         }
226     }
227
228
229     private void writeOption(String JavaDoc optionName, int argument)
230     {
231         if (argument != 1)
232         {
233             writer.print(optionName);
234             writer.print(' ');
235             writer.println(argument);
236         }
237     }
238
239
240     private void writeOption(String JavaDoc optionName, String JavaDoc arguments)
241     {
242         if (arguments != null)
243         {
244             writer.print(optionName);
245             writer.print(' ');
246             writer.println(quotedString(arguments));
247         }
248     }
249
250
251     private void writeOption(String JavaDoc optionName, File file)
252     {
253         if (file != null)
254         {
255             if (file.getPath().length() > 0)
256             {
257                 writer.print(optionName);
258                 writer.print(' ');
259                 writer.println(relativeFileName(file));
260             }
261             else
262             {
263                 writer.println(optionName);
264             }
265         }
266     }
267
268
269     private void writeOptions(String JavaDoc[] optionNames,
270                               List keepSpecifications)
271     {
272         if (keepSpecifications != null)
273         {
274             for (int index = 0; index < keepSpecifications.size(); index++)
275             {
276                 writeOption(optionNames, (KeepSpecification)keepSpecifications.get(index));
277             }
278         }
279     }
280
281
282     private void writeOption(String JavaDoc[] optionNames,
283                              KeepSpecification keepSpecification)
284     {
285         // Compose the option name.
286
String JavaDoc optionName = optionNames[keepSpecification.markConditionally ? 2 :
287                                         keepSpecification.markClasses ? 0 :
288                                                                               1];
289
290         if (keepSpecification.allowShrinking)
291         {
292             optionName += ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD +
293                           ConfigurationConstants.ALLOW_SHRINKING_SUBOPTION;
294         }
295
296         if (keepSpecification.allowOptimization)
297         {
298             optionName += ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD +
299                           ConfigurationConstants.ALLOW_OPTIMIZATION_SUBOPTION;
300         }
301
302         if (keepSpecification.allowObfuscation)
303         {
304             optionName += ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD +
305                           ConfigurationConstants.ALLOW_OBFUSCATION_SUBOPTION;
306         }
307
308         // Write out the option with the proper class specification.
309
writeOption(optionName, keepSpecification);
310     }
311
312
313     private void writeOptions(String JavaDoc optionName,
314                               List classSpecifications)
315     {
316         if (classSpecifications != null)
317         {
318             for (int index = 0; index < classSpecifications.size(); index++)
319             {
320                 writeOption(optionName, (ClassSpecification)classSpecifications.get(index));
321             }
322         }
323     }
324
325
326     private void writeOption(String JavaDoc optionName,
327                              ClassSpecification classSpecification)
328     {
329         writer.println();
330
331         // Write out the comments for this option.
332
writeComments(classSpecification.comments);
333
334         writer.print(optionName);
335         writer.print(' ');
336
337         // Write out the required annotation, if any.
338
if (classSpecification.annotationType != null)
339         {
340             writer.print(ConfigurationConstants.ANNOTATION_KEYWORD);
341             writer.print(ClassUtil.externalType(classSpecification.annotationType));
342             writer.print(' ');
343         }
344
345         // Write out the class access flags.
346
writer.print(ClassUtil.externalClassAccessFlags(classSpecification.requiredUnsetAccessFlags,
347                                                         ConfigurationConstants.NEGATOR_KEYWORD));
348
349         writer.print(ClassUtil.externalClassAccessFlags(classSpecification.requiredSetAccessFlags));
350
351         // Write out the class keyword, if we didn't write the interface
352
// keyword earlier.
353
if (((classSpecification.requiredSetAccessFlags |
354               classSpecification.requiredUnsetAccessFlags) &
355              ClassConstants.INTERNAL_ACC_INTERFACE) == 0)
356         {
357             writer.print(ConfigurationConstants.CLASS_KEYWORD);
358         }
359
360         writer.print(' ');
361
362         // Write out the class name.
363
writer.print(classSpecification.className != null ?
364             ClassUtil.externalClassName(classSpecification.className) :
365             ConfigurationConstants.ANY_CLASS_KEYWORD);
366
367         // Write out the extends template, if any.
368
if (classSpecification.extendsAnnotationType != null ||
369             classSpecification.extendsClassName != null)
370         {
371             writer.print(' ');
372             writer.print(ConfigurationConstants.EXTENDS_KEYWORD);
373             writer.print(' ');
374
375             // Write out the required extends annotation, if any.
376
if (classSpecification.extendsAnnotationType != null)
377             {
378                 writer.print(ConfigurationConstants.ANNOTATION_KEYWORD);
379                 writer.print(ClassUtil.externalType(classSpecification.extendsAnnotationType));
380                 writer.print(' ');
381             }
382
383             // Write out the extended class name.
384
writer.print(classSpecification.extendsClassName != null ?
385                 ClassUtil.externalClassName(classSpecification.extendsClassName) :
386                 ConfigurationConstants.ANY_CLASS_KEYWORD);
387         }
388
389         // Write out the keep field and keep method options, if any.
390
if (classSpecification.fieldSpecifications != null ||
391             classSpecification.methodSpecifications != null)
392         {
393             writer.print(' ');
394             writer.println(ConfigurationConstants.OPEN_KEYWORD);
395
396             writeFieldSpecification( classSpecification.fieldSpecifications);
397             writeMethodSpecification(classSpecification.methodSpecifications);
398
399             writer.println(ConfigurationConstants.CLOSE_KEYWORD);
400         }
401         else
402         {
403             writer.println();
404         }
405     }
406
407
408
409     private void writeComments(String JavaDoc comments)
410     {
411         if (comments != null)
412         {
413             int index = 0;
414             while (index < comments.length())
415             {
416                 int breakIndex = comments.indexOf('\n', index);
417                 if (breakIndex < 0)
418                 {
419                     breakIndex = comments.length();
420                 }
421
422                 writer.print('#');
423
424                 if (comments.charAt(index) != ' ')
425                 {
426                     writer.print(' ');
427                 }
428
429                 writer.println(comments.substring(index, breakIndex));
430
431                 index = breakIndex + 1;
432             }
433         }
434     }
435
436
437     private void writeFieldSpecification(List memberSpecifications)
438     {
439         if (memberSpecifications != null)
440         {
441             for (int index = 0; index < memberSpecifications.size(); index++)
442             {
443                 MemberSpecification memberSpecification =
444                     (MemberSpecification)memberSpecifications.get(index);
445
446                 writer.print(" ");
447
448                 // Write out the required annotation, if any.
449
if (memberSpecification.annotationType != null)
450                 {
451                     writer.print(ConfigurationConstants.ANNOTATION_KEYWORD);
452                     writer.println(ClassUtil.externalType(memberSpecification.annotationType));
453                     writer.print(" ");
454                 }
455
456                 // Write out the field access flags.
457
writer.print(ClassUtil.externalFieldAccessFlags(memberSpecification.requiredUnsetAccessFlags,
458                                                                 ConfigurationConstants.NEGATOR_KEYWORD));
459
460                 writer.print(ClassUtil.externalFieldAccessFlags(memberSpecification.requiredSetAccessFlags));
461
462                 // Write out the field name and descriptor.
463
String JavaDoc name = memberSpecification.name;
464                 String JavaDoc descriptor = memberSpecification.descriptor;
465
466                 if (name == null)
467                 {
468                     name = ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD;
469                 }
470
471                 writer.print(descriptor != null ?
472                     ClassUtil.externalFullFieldDescription(0,
473                                                            name,
474                                                            descriptor) :
475                     ConfigurationConstants.ANY_FIELD_KEYWORD);
476
477                 writer.println(ConfigurationConstants.SEPARATOR_KEYWORD);
478             }
479         }
480     }
481
482
483     private void writeMethodSpecification(List memberSpecifications)
484     {
485         if (memberSpecifications != null)
486         {
487             for (int index = 0; index < memberSpecifications.size(); index++)
488             {
489                 MemberSpecification memberSpecification =
490                     (MemberSpecification)memberSpecifications.get(index);
491
492                 writer.print(" ");
493
494                 // Write out the required annotation, if any.
495
if (memberSpecification.annotationType != null)
496                 {
497                     writer.print(ConfigurationConstants.ANNOTATION_KEYWORD);
498                     writer.println(ClassUtil.externalType(memberSpecification.annotationType));
499                     writer.print(" ");
500                 }
501
502                 // Write out the method access flags.
503
writer.print(ClassUtil.externalMethodAccessFlags(memberSpecification.requiredUnsetAccessFlags,
504                                                                  ConfigurationConstants.NEGATOR_KEYWORD));
505
506                 writer.print(ClassUtil.externalMethodAccessFlags(memberSpecification.requiredSetAccessFlags));
507
508                 // Write out the method name and descriptor.
509
String JavaDoc name = memberSpecification.name;
510                 String JavaDoc descriptor = memberSpecification.descriptor;
511
512                 if (name == null)
513                 {
514                     name = ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD;
515                 }
516
517                 writer.print(descriptor != null ?
518                     ClassUtil.externalFullMethodDescription(ClassConstants.INTERNAL_METHOD_NAME_INIT,
519                                                             0,
520                                                             name,
521                                                             descriptor) :
522                     ConfigurationConstants.ANY_METHOD_KEYWORD);
523
524                 writer.println(ConfigurationConstants.SEPARATOR_KEYWORD);
525             }
526         }
527     }
528
529
530     /**
531      * Returns a relative file name of the given file, if possible.
532      * The file name is also quoted, if necessary.
533      */

534     private String JavaDoc relativeFileName(File file)
535     {
536         String JavaDoc fileName = file.getAbsolutePath();
537
538         // See if we can convert the file name into a relative file name.
539
if (baseDir != null)
540         {
541             String JavaDoc baseDirName = baseDir.getAbsolutePath() + File.separator;
542             if (fileName.startsWith(baseDirName))
543             {
544                 fileName = fileName.substring(baseDirName.length());
545             }
546         }
547
548         return quotedString(fileName);
549     }
550
551
552     /**
553      * Returns a quoted version of the given string, if necessary.
554      */

555     private String JavaDoc quotedString(String JavaDoc string)
556     {
557         return string.length() == 0 ||
558                string.indexOf(' ') >= 0 ||
559                string.indexOf('@') >= 0 ||
560                string.indexOf('{') >= 0 ||
561                string.indexOf('}') >= 0 ||
562                string.indexOf('(') >= 0 ||
563                string.indexOf(')') >= 0 ||
564                string.indexOf(':') >= 0 ||
565                string.indexOf(';') >= 0 ? ("'" + string + "'") :
566                                            ( string );
567     }
568
569
570     /**
571      * A main method for testing configuration writing.
572      */

573     public static void main(String JavaDoc[] args) {
574         try
575         {
576             ConfigurationWriter writer = new ConfigurationWriter(new File(args[0]));
577
578             writer.write(new Configuration());
579         }
580         catch (Exception JavaDoc ex)
581         {
582             ex.printStackTrace();
583         }
584     }
585 }
586
Popular Tags