diff options
Diffstat (limited to 'src/proguard/InputReader.java')
-rw-r--r-- | src/proguard/InputReader.java | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/src/proguard/InputReader.java b/src/proguard/InputReader.java new file mode 100644 index 0000000..c088324 --- /dev/null +++ b/src/proguard/InputReader.java @@ -0,0 +1,233 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * + * 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 + { + // Check if we have at least some input classes. + if (configuration.programJars == null) + { + throw new IOException("The input is empty. You have to specify one or more '-injars' options"); + } + + // Perform some sanity checks on the class paths. + checkInputOutput(configuration.libraryJars, + configuration.programJars); + checkInputOutput(configuration.programJars, + configuration.programJars); + + WarningPrinter warningPrinter = new WarningPrinter(System.err, configuration.warn); + WarningPrinter notePrinter = new WarningPrinter(System.out, configuration.note); + + DuplicateClassPrinter duplicateClassPrinter = new DuplicateClassPrinter(notePrinter); + + // 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, + 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."); + } + + // 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."); + + 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."); + } + } + } + + + /** + * Performs some sanity checks on the class paths. + */ + private void checkInputOutput(ClassPath inputClassPath, + ClassPath outputClassPath) + throws IOException + { + if (inputClassPath == null || + outputClassPath == null) + { + return; + } + + for (int index1 = 0; index1 < inputClassPath.size(); index1++) + { + ClassPathEntry entry1 = inputClassPath.get(index1); + if (!entry1.isOutput()) + { + for (int index2 = 0; index2 < outputClassPath.size(); index2++) + { + ClassPathEntry entry2 = outputClassPath.get(index2); + if (entry2.isOutput() && + entry2.getName().equals(entry1.getName())) + { + throw new IOException("Input jars and output jars must be different ["+entry1.getName()+"]"); + } + } + } + } + } + + + /** + * 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 new IOException("Can't read [" + classPathEntry + "] (" + ex.getMessage() + ")"); + } + } +} |