KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > ProGuard


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.ClassPool;
24 import proguard.classfile.editor.*;
25 import proguard.classfile.visitor.*;
26 import proguard.obfuscate.Obfuscator;
27 import proguard.optimize.Optimizer;
28 import proguard.preverify.*;
29 import proguard.shrink.Shrinker;
30
31 import java.io.*;
32
33 /**
34  * Tool for shrinking, optimizing, obfuscating, and preverifying Java classes.
35  *
36  * @author Eric Lafortune
37  */

38 public class ProGuard
39 {
40     public static final String JavaDoc VERSION = "ProGuard, version 4.0 beta5";
41
42     private Configuration configuration;
43     private ClassPool programClassPool = new ClassPool();
44     private ClassPool libraryClassPool = new ClassPool();
45
46
47     /**
48      * Creates a new ProGuard object to process jars as specified by the given
49      * configuration.
50      */

51     public ProGuard(Configuration configuration)
52     {
53         this.configuration = configuration;
54     }
55
56
57     /**
58      * Performs all subsequent ProGuard operations.
59      */

60     public void execute() throws IOException
61     {
62         System.out.println(VERSION);
63
64         GPL.check();
65
66         if (configuration.printConfiguration != null)
67         {
68             printConfiguration();
69         }
70
71         if (configuration.programJars != null &&
72             configuration.programJars.hasOutput() &&
73             new UpToDateChecker(configuration).check())
74         {
75             return;
76         }
77
78         readInput();
79
80         if (configuration.shrink ||
81             configuration.optimize ||
82             configuration.obfuscate ||
83             configuration.preverify)
84         {
85             initialize();
86         }
87
88         if (configuration.targetClassVersion != 0)
89         {
90             target();
91         }
92
93         if (configuration.printSeeds != null)
94         {
95             printSeeds();
96         }
97
98         if (configuration.shrink)
99         {
100             shrink();
101         }
102
103         if (configuration.preverify)
104         {
105             inlineSubroutines();
106         }
107
108         if (configuration.optimize)
109         {
110             for (int optimizationPass = 0;
111                  optimizationPass < configuration.optimizationPasses;
112                  optimizationPass++)
113             {
114                 if (!optimize())
115                 {
116                     // Stop optimizing if the code doesn't improve any further.
117
break;
118                 }
119
120                 // Shrink again, if we may.
121
if (configuration.shrink)
122                 {
123                     // Don't print any usage this time around.
124
configuration.printUsage = null;
125                     configuration.whyAreYouKeeping = null;
126
127                     shrink();
128                 }
129             }
130         }
131
132         if (configuration.obfuscate)
133         {
134             obfuscate();
135         }
136
137         if (configuration.preverify)
138         {
139             preverify();
140         }
141
142         if (configuration.shrink ||
143             configuration.optimize ||
144             configuration.obfuscate ||
145             configuration.preverify)
146         {
147             sortClassElements();
148         }
149
150         if (configuration.programJars.hasOutput())
151         {
152             writeOutput();
153         }
154
155         if (configuration.dump != null)
156         {
157             dump();
158         }
159     }
160
161
162     /**
163      * Prints out the configuration that ProGuard is using.
164      */

165     private void printConfiguration() throws IOException
166     {
167         if (configuration.verbose)
168         {
169             System.out.println("Printing configuration to [" + fileName(configuration.printConfiguration) + "]...");
170         }
171
172         PrintStream ps = createPrintStream(configuration.printConfiguration);
173         try
174         {
175             new ConfigurationWriter(ps).write(configuration);
176         }
177         finally
178         {
179             closePrintStream(ps);
180         }
181     }
182
183
184     /**
185      * Reads the input class files.
186      */

187     private void readInput() throws IOException
188     {
189         if (configuration.verbose)
190         {
191             System.out.println("Reading input...");
192         }
193
194         // Fill the program class pool and the library class pool.
195
new InputReader(configuration).execute(programClassPool, libraryClassPool);
196     }
197
198
199     /**
200      * Initializes the cross-references between all classes, performs some
201      * basic checks, and shrinks the library class pool.
202      */

203     private void initialize() throws IOException
204     {
205         if (configuration.verbose)
206         {
207             System.out.println("Initializing...");
208         }
209
210         new Initializer(configuration).execute(programClassPool, libraryClassPool);
211     }
212
213
214     /**
215      * Sets that target versions of the program classes.
216      */

217     private void target() throws IOException
218     {
219         if (configuration.verbose)
220         {
221             System.out.println("Setting target versions...");
222         }
223
224         new Targeter(configuration).execute(programClassPool);
225     }
226
227
228     /**
229      * Prints out classes and class members that are used as seeds in the
230      * shrinking and obfuscation steps.
231      */

232     private void printSeeds() throws IOException
233     {
234         if (configuration.verbose)
235         {
236             System.out.println("Printing kept classes, fields, and methods...");
237         }
238
239         // Check if we have at least some keep commands.
240
if (configuration.keep == null)
241         {
242             throw new IOException("You have to specify '-keep' options for the shrinking step.");
243         }
244
245         PrintStream ps = createPrintStream(configuration.printSeeds);
246         try
247         {
248             // Create a visitor for printing out the seeds. We're printing out
249
// the program elements that are preserved against shrinking,
250
// optimization, or obfuscation.
251
SimpleClassPrinter printer = new SimpleClassPrinter(false, ps);
252             ClassPoolVisitor classPoolvisitor =
253                 ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
254                                                                         new ProgramClassFilter(printer),
255                                                                         new ProgramMemberFilter(printer),
256                                                                         true,
257                                                                         true,
258                                                                         true);
259
260             // Print out the seeds.
261
programClassPool.accept(classPoolvisitor);
262             libraryClassPool.accept(classPoolvisitor);
263         }
264         finally
265         {
266             closePrintStream(ps);
267         }
268     }
269
270
271     /**
272      * Performs the shrinking step.
273      */

274     private void shrink() throws IOException
275     {
276         if (configuration.verbose)
277         {
278             System.out.println("Shrinking...");
279
280             // We'll print out some explanation, if requested.
281
if (configuration.whyAreYouKeeping != null)
282             {
283                 System.out.println("Explaining why classes and class members are being kept...");
284             }
285
286             // We'll print out the usage, if requested.
287
if (configuration.printUsage != null)
288             {
289                 System.out.println("Printing usage to [" + fileName(configuration.printUsage) + "]...");
290             }
291         }
292
293         // Perform the actual shrinking.
294
programClassPool =
295             new Shrinker(configuration).execute(programClassPool, libraryClassPool);
296     }
297
298
299     /**
300      * Performs the subroutine inlining step.
301      */

302     private void inlineSubroutines()
303     {
304         if (configuration.verbose)
305         {
306             System.out.println("Inlining subroutines...");
307         }
308
309         // Perform the actual inlining.
310
new SubroutineInliner(configuration).execute(programClassPool);
311     }
312
313
314     /**
315      * Performs the optimization step.
316      */

317     private boolean optimize() throws IOException
318     {
319         if (configuration.verbose)
320         {
321             System.out.println("Optimizing...");
322         }
323
324         // Perform the actual optimization.
325
return new Optimizer(configuration).execute(programClassPool, libraryClassPool);
326     }
327
328
329     /**
330      * Performs the obfuscation step.
331      */

332     private void obfuscate() throws IOException
333     {
334         if (configuration.verbose)
335         {
336             System.out.println("Obfuscating...");
337
338             // We'll apply a mapping, if requested.
339
if (configuration.applyMapping != null)
340             {
341                 System.out.println("Applying mapping [" + fileName(configuration.applyMapping) + "]");
342             }
343
344             // We'll print out the mapping, if requested.
345
if (configuration.printMapping != null)
346             {
347                 System.out.println("Printing mapping to [" + fileName(configuration.printMapping) + "]...");
348             }
349         }
350
351         // Perform the actual obfuscation.
352
new Obfuscator(configuration).execute(programClassPool, libraryClassPool);
353     }
354
355
356     /**
357      * Performs the preverification step.
358      */

359     private void preverify()
360     {
361         if (configuration.verbose)
362         {
363             System.out.println("Preverifying...");
364         }
365
366         // Perform the actual preverification.
367
new Preverifier(configuration).execute(programClassPool);
368     }
369
370
371     /**
372      * Sorts the elements of all program classes.
373      */

374     private void sortClassElements()
375     {
376         programClassPool.classesAccept(new ClassElementSorter());
377     }
378
379
380     /**
381      * Writes the output class files.
382      */

383     private void writeOutput() throws IOException
384     {
385         if (configuration.verbose)
386         {
387             System.out.println("Writing output...");
388         }
389
390         // Write out the program class pool.
391
new OutputWriter(configuration).execute(programClassPool);
392     }
393
394
395     /**
396      * Prints out the contents of the program classes.
397      */

398     private void dump() throws IOException
399     {
400         if (configuration.verbose)
401         {
402             System.out.println("Printing classes to [" + fileName(configuration.dump) + "]...");
403         }
404
405         PrintStream ps = createPrintStream(configuration.dump);
406         try
407         {
408             programClassPool.classesAccept(new ClassPrinter(ps));
409         }
410         finally
411         {
412             closePrintStream(ps);
413         }
414     }
415
416
417     /**
418      * Returns a print stream for the given file, or the standard output if
419      * the file name is empty.
420      */

421     private PrintStream createPrintStream(File file)
422     throws FileNotFoundException
423     {
424         return isFile(file) ?
425             new PrintStream(new BufferedOutputStream(new FileOutputStream(file))) :
426             System.out;
427     }
428
429
430     /**
431      * Closes the given print stream, or closes it if is the standard output.
432      * @param printStream
433      */

434     private void closePrintStream(PrintStream printStream)
435     {
436         if (printStream == System.out)
437         {
438             printStream.flush();
439         }
440         else
441         {
442             printStream.close();
443         }
444     }
445
446
447     /**
448      * Returns the absolute file name for the given file, or the standard output
449      * if the file name is empty.
450      */

451     private String JavaDoc fileName(File file)
452     {
453         return isFile(file) ?
454             file.getAbsolutePath() :
455             "standard output";
456     }
457
458
459     /**
460      * Returns whether the given file is actually a file, or just a placeholder
461      * for the standard output.
462      */

463     private boolean isFile(File file)
464     {
465         return file.getPath().length() > 0;
466     }
467
468
469     /**
470      * The main method for ProGuard.
471      */

472     public static void main(String JavaDoc[] args)
473     {
474         if (args.length == 0)
475         {
476             System.out.println(VERSION);
477             System.out.println("Usage: java proguard.ProGuard [options ...]");
478             System.exit(1);
479         }
480
481         // Create the default options.
482
Configuration configuration = new Configuration();
483
484         try
485         {
486             // Parse the options specified in the command line arguments.
487
ConfigurationParser parser = new ConfigurationParser(args);
488
489             try
490             {
491                 parser.parse(configuration);
492
493                 // Execute ProGuard with these options.
494
new ProGuard(configuration).execute();
495             }
496             finally
497             {
498                 parser.close();
499             }
500         }
501         catch (Exception JavaDoc ex)
502         {
503             if (configuration.verbose)
504             {
505                 // Print a verbose stack trace.
506
ex.printStackTrace();
507             }
508             else
509             {
510                 // Print just the stack trace message.
511
System.err.println("Error: "+ex.getMessage());
512             }
513
514             System.exit(1);
515         }
516
517         System.exit(0);
518     }
519 }
520
Popular Tags