~ubuntu-branches/ubuntu/maverick/proguard/maverick

« back to all changes in this revision

Viewing changes to src/proguard/ProGuard.java

  • Committer: Bazaar Package Importer
  • Author(s): Sam Clegg
  • Date: 2005-11-13 09:42:59 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20051113094259-432zf4yyw4890mmn
Tags: 3.4-1
* New upstream release (Closes: #338355)
* debian/control: bump standards version
* debian/copyright: update FSF address
* increase java stack size for proguard and proguardgui

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: ProGuard.java,v 1.84 2004/12/11 16:35:23 eric Exp $
 
1
/* $Id: ProGuard.java,v 1.101 2005/10/22 11:53:39 eric Exp $
2
2
 *
3
3
 * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
4
4
 *
5
 
 * Copyright (c) 2002-2004 Eric Lafortune (eric@graphics.cornell.edu)
 
5
 * Copyright (c) 2002-2005 Eric Lafortune (eric@graphics.cornell.edu)
6
6
 *
7
7
 * This program is free software; you can redistribute it and/or modify it
8
8
 * under the terms of the GNU General Public License as published by the Free
9
9
 * Software Foundation; either version 2 of the License, or (at your option)
10
10
 * any later version.
11
11
 *
 
12
 *
12
13
 * This program is distributed in the hope that it will be useful, but WITHOUT
13
14
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
15
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20
21
 */
21
22
package proguard;
22
23
 
23
 
import proguard.classfile.*;
24
 
import proguard.classfile.attribute.*;
25
 
import proguard.classfile.editor.*;
26
 
import proguard.classfile.instruction.*;
 
24
import proguard.classfile.ClassPool;
 
25
import proguard.classfile.attribute.AllAttrInfoVisitor;
 
26
import proguard.classfile.editor.ConstantPoolSorter;
 
27
import proguard.classfile.instruction.AllInstructionVisitor;
27
28
import proguard.classfile.util.*;
28
29
import proguard.classfile.visitor.*;
29
30
import proguard.io.*;
30
 
import proguard.obfuscate.*;
31
 
import proguard.optimize.*;
32
 
import proguard.optimize.evaluation.*;
33
 
import proguard.optimize.peephole.*;
34
 
import proguard.shrink.*;
 
31
import proguard.obfuscate.Obfuscator;
 
32
import proguard.optimize.Optimizer;
 
33
import proguard.shrink.Shrinker;
 
34
import proguard.util.ClassNameListMatcher;
35
35
 
36
36
import java.io.*;
37
 
 
 
37
import java.util.*;
38
38
 
39
39
/**
40
40
 * Tool for shrinking, optimizing, and obfuscating Java class files.
43
43
 */
44
44
public class ProGuard
45
45
{
46
 
    public static final String VERSION = "ProGuard, version 3.2";
 
46
    public static final String VERSION = "ProGuard, version 3.4";
47
47
 
48
48
    private Configuration configuration;
49
49
    private ClassPool     programClassPool = new ClassPool();
67
67
    {
68
68
        System.out.println(VERSION);
69
69
 
 
70
        GPL.check();
 
71
 
70
72
        readInput();
71
73
 
 
74
        // The defaultPackage option implies the allowAccessModification option.
 
75
        if (configuration.defaultPackage != null)
 
76
        {
 
77
            configuration.allowAccessModification = true;
 
78
        }
 
79
 
72
80
        if (configuration.shrink   ||
73
81
            configuration.optimize ||
74
82
            configuration.obfuscate)
93
101
            // Shrink again, if we may.
94
102
            if (configuration.shrink)
95
103
            {
96
 
                configuration.printUsage = null;
 
104
                // Don't print any usage this time around.
 
105
                configuration.printUsage       = null;
 
106
                configuration.whyAreYouKeeping = null;
97
107
 
98
108
                shrink();
99
109
            }
157
167
                      configuration.libraryJars,
158
168
                      createDataEntryClassPoolFiller(true));
159
169
        }
160
 
 
161
 
        // The defaultPackage option implies the allowAccessModification option.
162
 
        if (configuration.defaultPackage != null)
163
 
        {
164
 
            configuration.allowAccessModification = true;
165
 
        }
166
170
    }
167
171
 
168
172
 
185
189
            new ClassFileReader(isLibrary,
186
190
                                configuration.skipNonPublicLibraryClasses,
187
191
                                configuration.skipNonPublicLibraryClassMembers,
 
192
                                configuration.note,
188
193
            new ClassPoolFiller(classPool, configuration.note)));
189
194
    }
190
195
 
241
246
 
242
247
            // Create the data entry pump.
243
248
            DirectoryPump directoryPump =
244
 
                new DirectoryPump(new File(classPathEntry.getName()));
 
249
                new DirectoryPump(classPathEntry.getFile());
245
250
 
246
251
            // Pump the data entries into the reader.
247
252
            directoryPump.pumpDataEntries(reader);
258
263
     */
259
264
    private void initialize() throws IOException
260
265
    {
 
266
        if (configuration.verbose)
 
267
        {
 
268
            System.out.println("Initializing...");
 
269
        }
 
270
 
 
271
        int originalLibraryClassPoolSize = libraryClassPool.size();
 
272
 
261
273
        // Initialize the class hierarchy for program class files.
262
274
        ClassFileHierarchyInitializer classFileHierarchyInitializer =
263
275
            new ClassFileHierarchyInitializer(programClassPool,
266
278
 
267
279
        programClassPool.classFilesAccept(classFileHierarchyInitializer);
268
280
 
269
 
        // Initialize the rest of the class hierarchy.
 
281
        // Initialize the class hierarchy for library class files.
270
282
        ClassFileHierarchyInitializer classFileHierarchyInitializer2 =
271
283
            new ClassFileHierarchyInitializer(programClassPool,
272
284
                                              libraryClassPool,
274
286
 
275
287
        libraryClassPool.classFilesAccept(classFileHierarchyInitializer2);
276
288
 
277
 
        // Initialize the other class references.
 
289
        // Initialize the Class.forName and .class references.
 
290
        ClassFileClassForNameReferenceInitializer classFileClassForNameReferenceInitializer =
 
291
            new ClassFileClassForNameReferenceInitializer(programClassPool,
 
292
                                                          libraryClassPool,
 
293
                                                          configuration.note,
 
294
                                                          createNoteExceptionMatcher(configuration.keep));
 
295
 
 
296
        programClassPool.classFilesAccept(
 
297
            new AllMethodVisitor(
 
298
            new AllAttrInfoVisitor(
 
299
            new AllInstructionVisitor(classFileClassForNameReferenceInitializer))));
 
300
 
 
301
        // Initialize the class references from program class members and attributes.
278
302
        ClassFileReferenceInitializer classFileReferenceInitializer =
279
303
            new ClassFileReferenceInitializer(programClassPool,
280
304
                                              libraryClassPool,
281
 
                                              configuration.warn,
282
 
                                              configuration.note);
 
305
                                              configuration.warn);
283
306
 
284
307
        programClassPool.classFilesAccept(classFileReferenceInitializer);
285
308
 
286
 
        int noteCount = classFileReferenceInitializer.getNoteCount();
 
309
        // Reinitialize the library class pool with only those library classes
 
310
        // whose hierarchies are referenced by the program classes.
 
311
        ClassPool newLibraryClassPool = new ClassPool();
 
312
        programClassPool.classFilesAccept(
 
313
            new AllCpInfoVisitor(
 
314
            new ReferencedClassFileVisitor(
 
315
            new LibraryClassFileFilter(
 
316
            new ClassFileHierarchyTraveler(true, true, true, false,
 
317
            new LibraryClassFileFilter(
 
318
            new ClassPoolFiller(newLibraryClassPool, false)))))));
 
319
 
 
320
        libraryClassPool = newLibraryClassPool;
 
321
 
 
322
        // Initialize the class references from library class members.
 
323
        ClassFileReferenceInitializer classFileReferenceInitializer2 =
 
324
            new ClassFileReferenceInitializer(programClassPool,
 
325
                                              libraryClassPool,
 
326
                                              false);
 
327
 
 
328
        libraryClassPool.classFilesAccept(classFileReferenceInitializer2);
 
329
 
 
330
        int noteCount = classFileClassForNameReferenceInitializer.getNoteCount();
287
331
        if (noteCount > 0)
288
332
        {
289
333
            System.err.println("Note: there were " + noteCount +
322
366
        // Discard unused library classes.
323
367
        if (configuration.verbose)
324
368
        {
325
 
                    System.out.println("Removing unused library classes...");
326
 
                    System.out.println("    Original number of library classes: " + libraryClassPool.size());
 
369
            System.out.println("Removed unused library classes...");
 
370
            System.out.println("  Original number of library classes: " + originalLibraryClassPoolSize);
 
371
            System.out.println("  Final number of library classes:    " + libraryClassPool.size());
327
372
        }
328
 
 
329
 
        // Reinitialize the library class pool with only those library classes
330
 
        // whose hierarchies are referenced by the program classes.
331
 
        ClassPool newLibraryClassPool = new ClassPool();
332
 
        programClassPool.classFilesAccept(
333
 
            new AllCpInfoVisitor(
334
 
            new ReferencedClassFileVisitor(
335
 
            new LibraryClassFileFilter(
336
 
            new ClassFileHierarchyTraveler(true, true, true, false,
337
 
            new LibraryClassFileFilter(
338
 
            new ClassPoolFiller(newLibraryClassPool, false)))))));
339
 
 
340
 
        libraryClassPool = newLibraryClassPool;
341
 
 
342
 
        if (configuration.verbose)
 
373
    }
 
374
 
 
375
 
 
376
    /**
 
377
     * Extracts a list of exceptions for which not to print notes, from the
 
378
     * keep configuration.
 
379
     */
 
380
    private ClassNameListMatcher createNoteExceptionMatcher(List noteExceptions)
 
381
    {
 
382
        if (noteExceptions != null)
343
383
        {
344
 
            System.out.println("    Final number of library classes:    " + libraryClassPool.size());
 
384
            List noteExceptionNames = new ArrayList(noteExceptions.size());
 
385
            for (int index = 0; index < noteExceptions.size(); index++)
 
386
            {
 
387
                ClassSpecification classSpecification = (ClassSpecification)noteExceptions.get(index);
 
388
                if (classSpecification.markClassFiles)
 
389
                {
 
390
                    // If the class itself is being kept, it's ok.
 
391
                    String className = classSpecification.className;
 
392
                    if (className != null)
 
393
                    {
 
394
                        noteExceptionNames.add(className);
 
395
                    }
 
396
 
 
397
                    // If all of its extensions are being kept, it's ok too.
 
398
                    String extendsClassName = classSpecification.extendsClassName;
 
399
                    if (extendsClassName != null)
 
400
                    {
 
401
                        noteExceptionNames.add(extendsClassName);
 
402
                    }
 
403
                }
 
404
            }
 
405
 
 
406
            if (noteExceptionNames.size() > 0)
 
407
            {
 
408
                return new ClassNameListMatcher(noteExceptionNames);
 
409
            }
345
410
        }
 
411
 
 
412
        return null;
346
413
    }
347
414
 
348
415
 
363
430
            throw new IOException("You have to specify '-keep' options for the shrinking step.");
364
431
        }
365
432
 
366
 
        PrintStream ps = configuration.printSeeds.length() > 0 ?
 
433
        PrintStream ps = isFile(configuration.printSeeds) ?
367
434
            new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printSeeds))) :
368
435
            System.out;
369
436
 
394
461
        if (configuration.verbose)
395
462
        {
396
463
            System.out.println("Shrinking...");
397
 
        }
398
 
 
399
 
        // Check if we have at least some keep commands.
400
 
        if (configuration.keep == null)
401
 
        {
402
 
            throw new IOException("You have to specify '-keep' options for the shrinking step.");
403
 
        }
404
 
 
405
 
        // Clean up any old visitor info.
406
 
        ClassFileCleaner classFileCleaner = new ClassFileCleaner();
407
 
        programClassPool.classFilesAccept(classFileCleaner);
408
 
        libraryClassPool.classFilesAccept(classFileCleaner);
409
 
 
410
 
        // Create a visitor for marking the seeds.
411
 
        UsageMarker usageMarker = new UsageMarker();
412
 
        ClassPoolVisitor classPoolvisitor =
413
 
            ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
414
 
                                                                    usageMarker,
415
 
                                                                    usageMarker);
416
 
        // Mark the seeds.
417
 
        programClassPool.accept(classPoolvisitor);
418
 
        libraryClassPool.accept(classPoolvisitor);
419
 
 
420
 
        // Mark interfaces that have to be kept.
421
 
        programClassPool.classFilesAccept(new InterfaceUsageMarker());
422
 
 
423
 
        // Mark the inner class information that has to be kept.
424
 
        programClassPool.classFilesAccept(new InnerUsageMarker());
425
 
 
426
 
        if (configuration.printUsage != null)
427
 
        {
428
 
            if (configuration.verbose)
 
464
 
 
465
            // We'll print out some explanation, if requested.
 
466
            if (configuration.whyAreYouKeeping != null)
 
467
            {
 
468
                System.out.println("Explaining why classes and class members are being kept...");
 
469
            }
 
470
 
 
471
            // We'll print out the usage, if requested.
 
472
            if (configuration.printUsage != null)
429
473
            {
430
474
                System.out.println("Printing usage" +
431
 
                                   (configuration.printUsage.length() > 0 ?
432
 
                                       " to [" + configuration.printUsage + "]" :
 
475
                                   (isFile(configuration.printUsage) ?
 
476
                                       " to [" + configuration.printUsage.getAbsolutePath() + "]" :
433
477
                                       "..."));
434
478
            }
435
 
 
436
 
            PrintStream ps = configuration.printUsage.length() > 0 ?
437
 
                new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printUsage))) :
438
 
                System.out;
439
 
 
440
 
            // Print out items that will be removed.
441
 
            programClassPool.classFilesAcceptAlphabetically(new UsagePrinter(true, ps));
442
 
 
443
 
            if (ps != System.out)
444
 
            {
445
 
                ps.close();
446
 
            }
447
 
        }
448
 
 
449
 
        // Discard unused program classes.
450
 
        if (configuration.verbose)
451
 
        {
452
 
            System.out.println("Removing unused program classes and class elements...");
453
 
            System.out.println("    Original number of program classes: " + programClassPool.size());
454
 
        }
455
 
 
456
 
        ClassPool newProgramClassPool = new ClassPool();
457
 
        programClassPool.classFilesAccept(
458
 
            new UsedClassFileFilter(
459
 
            new MultiClassFileVisitor(
460
 
            new ClassFileVisitor[] {
461
 
                new ClassFileShrinker(1024),
462
 
                new ClassPoolFiller(newProgramClassPool, false)
463
 
            })));
464
 
        programClassPool = newProgramClassPool;
465
 
 
466
 
        if (configuration.verbose)
467
 
        {
468
 
            System.out.println("    Final number of program classes:    " + programClassPool.size());
469
 
        }
 
479
        }
 
480
 
 
481
        // Check if we have at least some keep commands.
 
482
        if (configuration.keep == null)
 
483
        {
 
484
            throw new IOException("You have to specify '-keep' options for the shrinking step.");
 
485
        }
 
486
 
 
487
        int originalProgramClassPoolSize = programClassPool.size();
 
488
 
 
489
        // Perform the actual shrinking.
 
490
        programClassPool = new Shrinker(configuration).execute(programClassPool, libraryClassPool);
470
491
 
471
492
        // Check if we have at least some output class files.
472
 
        if (programClassPool.size() == 0)
 
493
        int newProgramClassPoolSize = programClassPool.size();
 
494
        if (newProgramClassPoolSize == 0)
473
495
        {
474
496
            throw new IOException("The output jar is empty. Did you specify the proper '-keep' options?");
475
497
        }
 
498
 
 
499
        if (configuration.verbose)
 
500
        {
 
501
            System.out.println("Removed unused program classes and class elements...");
 
502
            System.out.println("  Original number of program classes: " + originalProgramClassPoolSize);
 
503
            System.out.println("  Final number of program classes:    " + newProgramClassPoolSize);
 
504
        }
476
505
    }
477
506
 
478
507
 
486
515
            System.out.println("Optimizing...");
487
516
        }
488
517
 
489
 
        // Clean up any old visitor info.
490
 
        ClassFileCleaner classFileCleaner = new ClassFileCleaner();
491
 
        programClassPool.classFilesAccept(classFileCleaner);
492
 
        libraryClassPool.classFilesAccept(classFileCleaner);
493
 
 
494
518
        // Check if we have at least some keep commands.
495
 
        if (configuration.keep == null)
 
519
        if (configuration.keep         == null &&
 
520
            configuration.keepNames    == null &&
 
521
            configuration.applyMapping == null &&
 
522
            configuration.printMapping == null)
496
523
        {
497
524
            throw new IOException("You have to specify '-keep' options for the optimization step.");
498
525
        }
499
526
 
500
 
        // Create a visitor for marking the seeds.
501
 
        KeepMarker keepMarker = new KeepMarker();
502
 
        ClassPoolVisitor classPoolvisitor =
503
 
            ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
504
 
                                                                    keepMarker,
505
 
                                                                    keepMarker);
506
 
 
507
 
        // Mark the seeds.
508
 
        programClassPool.accept(classPoolvisitor);
509
 
        libraryClassPool.accept(classPoolvisitor);
510
 
 
511
 
        // Make class files and methods final, as far as possible.
512
 
        programClassPool.classFilesAccept(new ClassFileFinalizer());
513
 
 
514
 
        // Mark all fields that are write-only.
515
 
        programClassPool.classFilesAccept(
516
 
            new AllMethodVisitor(
517
 
            new AllAttrInfoVisitor(
518
 
            new AllInstructionVisitor(
519
 
            new WriteOnlyFieldMarker()))));
520
 
 
521
 
        if (configuration.assumeNoSideEffects != null)
522
 
        {
523
 
            // Create a visitor for marking methods that don't have any side effects.
524
 
            NoSideEffectMethodMarker noSideEffectMethodMarker = new NoSideEffectMethodMarker();
525
 
            ClassPoolVisitor noClassPoolvisitor =
526
 
                ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.assumeNoSideEffects,
527
 
                                                                        null,
528
 
                                                                        noSideEffectMethodMarker);
529
 
 
530
 
            // Mark the seeds.
531
 
            programClassPool.accept(noClassPoolvisitor);
532
 
            libraryClassPool.accept(noClassPoolvisitor);
533
 
        }
534
 
 
535
 
        // Mark all methods that have side effects.
536
 
        programClassPool.accept(new SideEffectMethodMarker());
537
 
 
538
 
        // Mark all interfaces that have single implementations.
539
 
        programClassPool.classFilesAccept(new SingleImplementationMarker(configuration.allowAccessModification));
540
 
 
541
 
        // Inline interfaces with single implementations.
542
 
        // First update the references to classes and class members.
543
 
        // Then update the class member descriptors.
544
 
        programClassPool.classFilesAccept(new AllMethodVisitor(
545
 
                                          new AllAttrInfoVisitor(
546
 
                                          new SingleImplementationInliner())));
547
 
        programClassPool.classFilesAccept(new AllMemberInfoVisitor(
548
 
                                          new SingleImplementationInliner()));
549
 
 
550
 
        // Perform partial evaluation.
551
 
        programClassPool.classFilesAccept(new AllMethodVisitor(
552
 
                                          new PartialEvaluator()));
553
 
 
554
 
        // Create a branch target marker and a code attribute editor that can
555
 
        // be reused for all code attributes.
556
 
        BranchTargetFinder branchTargetFinder = new BranchTargetFinder(1024);
557
 
        CodeAttrInfoEditor codeAttrInfoEditor = new CodeAttrInfoEditor(1024);
558
 
 
559
 
        // Visit all code attributes.
560
 
        // First let the branch marker mark all branch targets.
561
 
        // Then perform peephole optimisations on the instructions:
562
 
        // - Remove push/pop instruction pairs.
563
 
        // - Remove load/store instruction pairs.
564
 
        // - Replace store/load instruction pairs by dup/store instructions.
565
 
        // - Replace branches to return instructions by return instructions.
566
 
        // - Remove nop instructions.
567
 
        // - Inline simple getters and setters.
568
 
        // Finally apply all changes to the code.
569
 
        programClassPool.classFilesAccept(
570
 
            new AllMethodVisitor(
571
 
            new AllAttrInfoVisitor(
572
 
            new MultiAttrInfoVisitor(
573
 
            new AttrInfoVisitor[]
574
 
            {
575
 
                branchTargetFinder,
576
 
                new CodeAttrInfoEditorResetter(codeAttrInfoEditor),
577
 
                new AllInstructionVisitor(
578
 
                new MultiInstructionVisitor(
579
 
                new InstructionVisitor[]
580
 
                {
581
 
                    new PushPopRemover(branchTargetFinder, codeAttrInfoEditor),
582
 
                    new LoadStoreRemover(branchTargetFinder, codeAttrInfoEditor),
583
 
                    new StoreLoadReplacer(branchTargetFinder, codeAttrInfoEditor),
584
 
                    new GotoReturnReplacer(codeAttrInfoEditor),
585
 
                    new NopRemover(codeAttrInfoEditor),
586
 
                    new GetterSetterInliner(codeAttrInfoEditor, configuration.allowAccessModification),
587
 
                })),
588
 
                codeAttrInfoEditor
589
 
            }))));
 
527
        // Perform the actual optimization.
 
528
        new Optimizer(configuration).execute(programClassPool, libraryClassPool);
590
529
    }
591
530
 
592
531
 
598
537
        if (configuration.verbose)
599
538
        {
600
539
            System.out.println("Obfuscating...");
601
 
        }
602
 
 
603
 
        // Check if we have at least some keep commands.
604
 
        if (configuration.keep      == null &&
605
 
            configuration.keepNames == null)
606
 
        {
607
 
            throw new IOException("You have to specify '-keep' options for the obfuscation step.");
608
 
        }
609
 
 
610
 
        // Clean up any old visitor info.
611
 
        ClassFileCleaner classFileCleaner = new ClassFileCleaner();
612
 
        programClassPool.classFilesAccept(classFileCleaner);
613
 
        libraryClassPool.classFilesAccept(classFileCleaner);
614
 
 
615
 
        // Link all class members that should get the same names.
616
 
        programClassPool.classFilesAccept(new BottomClassFileFilter(
617
 
                                          new MemberInfoLinker()));
618
 
 
619
 
        // Create a visitor for marking the seeds.
620
 
        NameMarker nameMarker = new NameMarker();
621
 
        ClassPoolVisitor classPoolvisitor =
622
 
            new MultiClassPoolVisitor(new ClassPoolVisitor[]
623
 
            {
624
 
                ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
625
 
                                                                        nameMarker,
626
 
                                                                        nameMarker),
627
 
                ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keepNames,
628
 
                                                                        nameMarker,
629
 
                                                                        nameMarker)
630
 
            });
631
 
 
632
 
        // Mark the seeds.
633
 
        programClassPool.accept(classPoolvisitor);
634
 
        libraryClassPool.accept(classPoolvisitor);
635
 
 
636
 
        // Apply the mapping, if one has been specified.
637
 
        if (configuration.applyMapping != null)
638
 
        {
639
 
            if (configuration.verbose)
640
 
            {
641
 
                System.out.println("Applying mapping [" + configuration.applyMapping + "]");
642
 
            }
643
 
 
644
 
            MappingReader    reader = new MappingReader(configuration.applyMapping);
645
 
            MappingProcessor keeper =
646
 
                new MultiMappingProcessor(new MappingProcessor[]
647
 
                {
648
 
                    new MappingKeeper(programClassPool),
649
 
                    new MappingKeeper(libraryClassPool),
650
 
                });
651
 
 
652
 
            reader.pump(keeper);
653
 
        }
654
 
 
655
 
        // Mark attributes that have to be kept.
656
 
        AttributeUsageMarker attributeUsageMarker = new AttributeUsageMarker();
657
 
        if (configuration.keepAttributes != null)
658
 
        {
659
 
            if (configuration.keepAttributes.size() != 0)
660
 
            {
661
 
                attributeUsageMarker.setKeepAttributes(configuration.keepAttributes);
662
 
            }
663
 
            else
664
 
            {
665
 
                attributeUsageMarker.setKeepAllAttributes();
666
 
            }
667
 
        }
668
 
        programClassPool.classFilesAccept(attributeUsageMarker);
669
 
 
670
 
        // Remove the attributes that can be discarded.
671
 
        programClassPool.classFilesAccept(new AttributeShrinker());
672
 
 
673
 
        if (configuration.verbose)
674
 
        {
675
 
            System.out.println("Renaming program classes and class elements...");
676
 
        }
677
 
 
678
 
        // Come up with new names for all class files.
679
 
        programClassPool.classFilesAccept(new ClassFileObfuscator(programClassPool,
680
 
                                                                  configuration.defaultPackage,
681
 
                                                                  configuration.useMixedCaseClassNames));
682
 
 
683
 
        // Come up with new names for all class members.
684
 
        programClassPool.classFilesAccept(new BottomClassFileFilter(
685
 
                                          new MemberInfoObfuscator(configuration.overloadAggressively,
686
 
                                                                   configuration.obfuscationDictionary)));
687
 
 
688
 
        // Print out the mapping, if requested.
689
 
        if (configuration.printMapping != null)
690
 
        {
691
 
            if (configuration.verbose)
 
540
 
 
541
            // We'll apply a mapping, if requested.
 
542
            if (configuration.applyMapping != null)
 
543
            {
 
544
                System.out.println("Applying mapping [" + configuration.applyMapping.getAbsolutePath() + "]");
 
545
            }
 
546
 
 
547
            // We'll print out the mapping, if requested.
 
548
            if (configuration.printMapping != null)
692
549
            {
693
550
                System.out.println("Printing mapping" +
694
 
                                   (configuration.printMapping.length() > 0 ?
695
 
                                       " to [" + configuration.printMapping + "]" :
 
551
                                   (isFile(configuration.printMapping) ?
 
552
                                       " to [" + configuration.printMapping.getAbsolutePath() + "]" :
696
553
                                       "..."));
697
554
            }
698
 
 
699
 
            PrintStream ps = configuration.printMapping.length() > 0 ?
700
 
                new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printMapping))) :
701
 
                System.out;
702
 
 
703
 
            // Print out items that will be removed.
704
 
            programClassPool.classFilesAcceptAlphabetically(new MappingPrinter(ps));
705
 
 
706
 
            if (ps != System.out)
707
 
            {
708
 
                ps.close();
709
 
            }
710
555
        }
711
556
 
712
 
        // Actually apply these new names.
713
 
        programClassPool.classFilesAccept(new ClassFileRenamer(configuration.defaultPackage != null,
714
 
                                                               configuration.newSourceFileAttribute));
715
 
 
716
 
        // Mark NameAndType constant pool entries that have to be kept
717
 
        // and remove the other ones.
718
 
        programClassPool.classFilesAccept(new NameAndTypeUsageMarker());
719
 
        programClassPool.classFilesAccept(new NameAndTypeShrinker(1024));
720
 
 
721
 
        // Mark Utf8 constant pool entries that have to be kept
722
 
        // and remove the other ones.
723
 
        programClassPool.classFilesAccept(new Utf8UsageMarker());
724
 
        programClassPool.classFilesAccept(new Utf8Shrinker(1024));
 
557
        // Perform the actual obfuscation.
 
558
        new Obfuscator(configuration).execute(programClassPool, libraryClassPool);
725
559
    }
726
560
 
727
561
 
730
564
     */
731
565
    private void sortConstantPools()
732
566
    {
 
567
        // TODO: Avoid duplicate constant pool entries.
733
568
        programClassPool.classFilesAccept(new ConstantPoolSorter(1024));
734
569
    }
735
570
 
778
613
                    ClassPathEntry otherEntry = programJars.get(inIndex);
779
614
 
780
615
                    if (!otherEntry.isOutput() &&
781
 
                        entry.getName().equals(otherEntry.getName()))
 
616
                        entry.getFile().equals(otherEntry.getFile()))
782
617
                    {
783
618
                        throw new IOException("The output jar [" + entry.getName() +
784
619
                                              "] must be different from all input jars.");
849
684
                                    new DataEntryCopier(writer));
850
685
 
851
686
            // Read and handle the specified input entries.
852
 
            readInput("Copying resources from program ",
 
687
            readInput("  Copying resources from program ",
853
688
                      classPath,
854
689
                      fromInputIndex,
855
690
                      fromOutputIndex,
873
708
        if (configuration.verbose)
874
709
        {
875
710
            System.out.println("Printing classes" +
876
 
                               (configuration.dump.length() > 0 ?
877
 
                                   " to [" + configuration.dump + "]" :
 
711
                               (isFile(configuration.dump) ?
 
712
                                   " to [" + configuration.dump.getAbsolutePath() + "]" :
878
713
                                   "..."));
879
714
        }
880
715
 
881
 
        PrintStream ps = configuration.dump.length() > 0 ?
 
716
        PrintStream ps = isFile(configuration.dump) ?
882
717
            new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.dump))) :
883
718
            System.out;
884
719
 
885
720
        programClassPool.classFilesAccept(new ClassFilePrinter(ps));
886
721
 
887
 
        if (configuration.dump.length() > 0)
 
722
        if (isFile(configuration.dump))
888
723
        {
889
724
            ps.close();
890
725
        }
892
727
 
893
728
 
894
729
    /**
 
730
     * Returns whether the given file is actually a file, or just a placeholder
 
731
     * for the standard output.
 
732
     */
 
733
    private boolean isFile(File file)
 
734
    {
 
735
        return file.getPath().length() > 0;
 
736
    }
 
737
 
 
738
 
 
739
    /**
895
740
     * The main method for ProGuard.
896
741
     */
897
742
    public static void main(String[] args)
898
743
    {
899
744
        if (args.length == 0)
900
745
        {
 
746
            System.out.println(VERSION);
901
747
            System.out.println("Usage: java proguard.ProGuard [options ...]");
902
748
            System.exit(1);
903
749
        }
909
755
        {
910
756
            // Parse the options specified in the command line arguments.
911
757
            ConfigurationParser parser = new ConfigurationParser(args);
912
 
            parser.parse(configuration);
913
 
 
914
 
            // Execute ProGuard with these options.
915
 
            ProGuard proGuard = new ProGuard(configuration);
916
 
            proGuard.execute();
 
758
 
 
759
            try
 
760
            {
 
761
                parser.parse(configuration);
 
762
 
 
763
                // Execute ProGuard with these options.
 
764
                new ProGuard(configuration).execute();
 
765
            }
 
766
            finally
 
767
            {
 
768
                parser.close();
 
769
            }
917
770
        }
918
771
        catch (Exception ex)
919
772
        {