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