blob: 341407489b4bb32471ca8084f44ef52cf2396e63 [file] [log] [blame]
/*
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
* Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
*
* 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);
// 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.");
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);
}
}
}