| /* |
| * ProGuard -- shrinking, optimization, obfuscation, and preverification |
| * of Java bytecode. |
| * |
| * Copyright (c) 2002-2014 Eric Lafortune ([email protected]) |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| package proguard; |
| |
| import proguard.classfile.ClassPool; |
| import proguard.classfile.util.WarningPrinter; |
| import proguard.classfile.visitor.*; |
| import proguard.io.*; |
| |
| import java.io.IOException; |
| |
| /** |
| * This class reads the input class files. |
| * |
| * @author Eric Lafortune |
| */ |
| public class InputReader |
| { |
| private final Configuration configuration; |
| |
| |
| /** |
| * Creates a new InputReader to read input class files as specified by the |
| * given configuration. |
| */ |
| public InputReader(Configuration configuration) |
| { |
| this.configuration = configuration; |
| } |
| |
| |
| /** |
| * Fills the given program class pool and library class pool by reading |
| * class files, based on the current configuration. |
| */ |
| public void execute(ClassPool programClassPool, |
| ClassPool libraryClassPool) throws IOException |
| { |
| WarningPrinter warningPrinter = new WarningPrinter(System.err, configuration.warn); |
| WarningPrinter notePrinter = new WarningPrinter(System.out, configuration.note); |
| |
| DuplicateClassPrinter duplicateClassPrinter = new DuplicateClassPrinter(notePrinter); |
| |
| // Android-added: Read the classes from the systemjars. |
| // These are read into the library ClassPool before the programjars so that any duplicates |
| // between these are programjars will result in the classes in the programjars being |
| // ignored. |
| // Read the system class files, if any. |
| if (configuration.systemJars != null) |
| { |
| // Prepare a data entry reader to filter all classes, |
| // which are then decoded to classes by a class reader, |
| // which are then filtered by removing any that already exist in the libraryClassPool. |
| // which are then put in the class pool by a class pool filler. |
| readInput("Reading system ", |
| configuration.systemJars, |
| new ClassFilter( |
| new ClassReader(true /* isLibrary */, |
| configuration.skipNonPublicLibraryClasses, |
| configuration.skipNonPublicLibraryClassMembers, |
| warningPrinter, |
| new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter, |
| new ClassPoolFiller(libraryClassPool))))); |
| } |
| |
| // Read the program class files. |
| // Prepare a data entry reader to filter all classes, |
| // which are then decoded to classes by a class reader, |
| // which are then put in the class pool by a class pool filler. |
| readInput("Reading program ", |
| configuration.programJars, |
| new ClassFilter( |
| new ClassReader(false, |
| configuration.skipNonPublicLibraryClasses, |
| configuration.skipNonPublicLibraryClassMembers, |
| warningPrinter, |
| new ClassPresenceFilter(programClassPool, duplicateClassPrinter, |
| // Android-changed: Filter out classes already read from systemjars. |
| new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter, |
| new ClassPoolFiller(programClassPool)))))); |
| |
| // Check if we have at least some input classes. |
| if (programClassPool.size() == 0) |
| { |
| throw new IOException("The input doesn't contain any classes. Did you specify the proper '-injars' options?"); |
| } |
| |
| // Read the library class files, if any. |
| if (configuration.libraryJars != null) |
| { |
| // Prepare a data entry reader to filter all classes, |
| // which are then decoded to classes by a class reader, |
| // which are then put in the class pool by a class pool filler. |
| readInput("Reading library ", |
| configuration.libraryJars, |
| new ClassFilter( |
| new ClassReader(true, |
| configuration.skipNonPublicLibraryClasses, |
| configuration.skipNonPublicLibraryClassMembers, |
| warningPrinter, |
| new ClassPresenceFilter(programClassPool, duplicateClassPrinter, |
| new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter, |
| new ClassPoolFiller(libraryClassPool)))))); |
| } |
| |
| // Print out a summary of the notes, if necessary. |
| int noteCount = notePrinter.getWarningCount(); |
| if (noteCount > 0) |
| { |
| System.err.println("Note: there were " + noteCount + |
| " duplicate class definitions."); |
| System.err.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#duplicateclass)"); |
| } |
| |
| // Print out a summary of the warnings, if necessary. |
| int warningCount = warningPrinter.getWarningCount(); |
| if (warningCount > 0) |
| { |
| System.err.println("Warning: there were " + warningCount + |
| " classes in incorrectly named files."); |
| System.err.println(" You should make sure all file names correspond to their class names."); |
| System.err.println(" The directory hierarchies must correspond to the package hierarchies."); |
| System.err.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#unexpectedclass)"); |
| |
| if (!configuration.ignoreWarnings) |
| { |
| System.err.println(" If you don't mind the mentioned classes not being written out,"); |
| System.err.println(" you could try your luck using the '-ignorewarnings' option."); |
| throw new IOException("Please correct the above warnings first."); |
| } |
| } |
| } |
| |
| |
| /** |
| * Reads all input entries from the given class path. |
| */ |
| private void readInput(String messagePrefix, |
| ClassPath classPath, |
| DataEntryReader reader) throws IOException |
| { |
| readInput(messagePrefix, |
| classPath, |
| 0, |
| classPath.size(), |
| reader); |
| } |
| |
| |
| /** |
| * Reads all input entries from the given section of the given class path. |
| */ |
| public void readInput(String messagePrefix, |
| ClassPath classPath, |
| int fromIndex, |
| int toIndex, |
| DataEntryReader reader) throws IOException |
| { |
| for (int index = fromIndex; index < toIndex; index++) |
| { |
| ClassPathEntry entry = classPath.get(index); |
| if (!entry.isOutput()) |
| { |
| readInput(messagePrefix, entry, reader); |
| } |
| } |
| } |
| |
| |
| /** |
| * Reads the given input class path entry. |
| */ |
| private void readInput(String messagePrefix, |
| ClassPathEntry classPathEntry, |
| DataEntryReader dataEntryReader) throws IOException |
| { |
| try |
| { |
| // Create a reader that can unwrap jars, wars, ears, and zips. |
| DataEntryReader reader = |
| DataEntryReaderFactory.createDataEntryReader(messagePrefix, |
| classPathEntry, |
| dataEntryReader); |
| |
| // Create the data entry pump. |
| DirectoryPump directoryPump = |
| new DirectoryPump(classPathEntry.getFile()); |
| |
| // Pump the data entries into the reader. |
| directoryPump.pumpDataEntries(reader); |
| } |
| catch (IOException ex) |
| { |
| throw (IOException)new IOException("Can't read [" + classPathEntry + "] (" + ex.getMessage() + ")").initCause(ex); |
| } |
| } |
| } |