• 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;
22 
23 import proguard.classfile.ClassPool;
24 import proguard.classfile.util.WarningPrinter;
25 import proguard.classfile.visitor.*;
26 import proguard.io.*;
27 
28 import java.io.IOException;
29 
30 /**
31  * This class reads the input class files.
32  *
33  * @author Eric Lafortune
34  */
35 public class InputReader
36 {
37     private final Configuration configuration;
38 
39 
40     /**
41      * Creates a new InputReader to read input class files as specified by the
42      * given configuration.
43      */
InputReader(Configuration configuration)44     public InputReader(Configuration configuration)
45     {
46         this.configuration = configuration;
47     }
48 
49 
50     /**
51      * Fills the given program class pool and library class pool by reading
52      * class files, based on the current configuration.
53      */
execute(ClassPool programClassPool, ClassPool libraryClassPool)54     public void execute(ClassPool programClassPool,
55                         ClassPool libraryClassPool) throws IOException
56     {
57         WarningPrinter warningPrinter = new WarningPrinter(System.err, configuration.warn);
58         WarningPrinter notePrinter    = new WarningPrinter(System.out, configuration.note);
59 
60         DuplicateClassPrinter duplicateClassPrinter = new DuplicateClassPrinter(notePrinter);
61 
62         // Android-added: Read the classes from the systemjars.
63         // These are read into the library ClassPool before the programjars so that any duplicates
64         // between these are programjars will result in the classes in the programjars being
65         // ignored.
66         // Read the system class files, if any.
67         if (configuration.systemJars != null)
68         {
69             // Prepare a data entry reader to filter all classes,
70             // which are then decoded to classes by a class reader,
71             // which are then filtered by removing any that already exist in the libraryClassPool.
72             // which are then put in the class pool by a class pool filler.
73             readInput("Reading system ",
74                       configuration.systemJars,
75                       new ClassFilter(
76                       new ClassReader(true /* isLibrary */,
77                                       configuration.skipNonPublicLibraryClasses,
78                                       configuration.skipNonPublicLibraryClassMembers,
79                                       warningPrinter,
80                       new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter,
81                       new ClassPoolFiller(libraryClassPool)))));
82         }
83 
84         // Read the program class files.
85         // Prepare a data entry reader to filter all classes,
86         // which are then decoded to classes by a class reader,
87         // which are then put in the class pool by a class pool filler.
88         readInput("Reading program ",
89                   configuration.programJars,
90                   new ClassFilter(
91                   new ClassReader(false,
92                                   configuration.skipNonPublicLibraryClasses,
93                                   configuration.skipNonPublicLibraryClassMembers,
94                                   warningPrinter,
95                   new ClassPresenceFilter(programClassPool, duplicateClassPrinter,
96                   // Android-changed: Filter out classes already read from systemjars.
97                   new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter,
98                   new ClassPoolFiller(programClassPool))))));
99 
100         // Check if we have at least some input classes.
101         if (programClassPool.size() == 0)
102         {
103             throw new IOException("The input doesn't contain any classes. Did you specify the proper '-injars' options?");
104         }
105 
106         // Read the library class files, if any.
107         if (configuration.libraryJars != null)
108         {
109             // Prepare a data entry reader to filter all classes,
110             // which are then decoded to classes by a class reader,
111             // which are then put in the class pool by a class pool filler.
112             readInput("Reading library ",
113                       configuration.libraryJars,
114                       new ClassFilter(
115                       new ClassReader(true,
116                                       configuration.skipNonPublicLibraryClasses,
117                                       configuration.skipNonPublicLibraryClassMembers,
118                                       warningPrinter,
119                       new ClassPresenceFilter(programClassPool, duplicateClassPrinter,
120                       new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter,
121                       new ClassPoolFiller(libraryClassPool))))));
122         }
123 
124         // Print out a summary of the notes, if necessary.
125         int noteCount = notePrinter.getWarningCount();
126         if (noteCount > 0)
127         {
128             System.err.println("Note: there were " + noteCount +
129                                " duplicate class definitions.");
130             System.err.println("      (http://proguard.sourceforge.net/manual/troubleshooting.html#duplicateclass)");
131         }
132 
133         // Print out a summary of the warnings, if necessary.
134         int warningCount = warningPrinter.getWarningCount();
135         if (warningCount > 0)
136         {
137             System.err.println("Warning: there were " + warningCount +
138                                " classes in incorrectly named files.");
139             System.err.println("         You should make sure all file names correspond to their class names.");
140             System.err.println("         The directory hierarchies must correspond to the package hierarchies.");
141             System.err.println("         (http://proguard.sourceforge.net/manual/troubleshooting.html#unexpectedclass)");
142 
143             if (!configuration.ignoreWarnings)
144             {
145                 System.err.println("         If you don't mind the mentioned classes not being written out,");
146                 System.err.println("         you could try your luck using the '-ignorewarnings' option.");
147                 throw new IOException("Please correct the above warnings first.");
148             }
149         }
150     }
151 
152 
153     /**
154      * Reads all input entries from the given class path.
155      */
readInput(String messagePrefix, ClassPath classPath, DataEntryReader reader)156     private void readInput(String          messagePrefix,
157                            ClassPath       classPath,
158                            DataEntryReader reader) throws IOException
159     {
160         readInput(messagePrefix,
161                   classPath,
162                   0,
163                   classPath.size(),
164                   reader);
165     }
166 
167 
168     /**
169      * Reads all input entries from the given section of the given class path.
170      */
readInput(String messagePrefix, ClassPath classPath, int fromIndex, int toIndex, DataEntryReader reader)171     public void readInput(String          messagePrefix,
172                           ClassPath       classPath,
173                           int             fromIndex,
174                           int             toIndex,
175                           DataEntryReader reader) throws IOException
176     {
177         for (int index = fromIndex; index < toIndex; index++)
178         {
179             ClassPathEntry entry = classPath.get(index);
180             if (!entry.isOutput())
181             {
182                 readInput(messagePrefix, entry, reader);
183             }
184         }
185     }
186 
187 
188     /**
189      * Reads the given input class path entry.
190      */
readInput(String messagePrefix, ClassPathEntry classPathEntry, DataEntryReader dataEntryReader)191     private void readInput(String          messagePrefix,
192                            ClassPathEntry  classPathEntry,
193                            DataEntryReader dataEntryReader) throws IOException
194     {
195         try
196         {
197             // Create a reader that can unwrap jars, wars, ears, and zips.
198             DataEntryReader reader =
199                 DataEntryReaderFactory.createDataEntryReader(messagePrefix,
200                                                              classPathEntry,
201                                                              dataEntryReader);
202 
203             // Create the data entry pump.
204             DirectoryPump directoryPump =
205                 new DirectoryPump(classPathEntry.getFile());
206 
207             // Pump the data entries into the reader.
208             directoryPump.pumpDataEntries(reader);
209         }
210         catch (IOException ex)
211         {
212             throw (IOException)new IOException("Can't read [" + classPathEntry + "] (" + ex.getMessage() + ")").initCause(ex);
213         }
214     }
215 }
216