diff options
Diffstat (limited to 'src/proguard/io')
31 files changed, 2895 insertions, 0 deletions
diff --git a/src/proguard/io/CascadingDataEntryWriter.java b/src/proguard/io/CascadingDataEntryWriter.java new file mode 100644 index 0000000..15719e6 --- /dev/null +++ b/src/proguard/io/CascadingDataEntryWriter.java @@ -0,0 +1,94 @@ +/* + * 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.io; + +import java.io.*; + +/** + * This DataEntryWriter delegates to a given DataEntryWriter, or failing that, + * to another given DataEntryWriter. + * + * @author Eric Lafortune + */ +public class CascadingDataEntryWriter implements DataEntryWriter +{ + private DataEntryWriter dataEntryWriter1; + private DataEntryWriter dataEntryWriter2; + + + /** + * Creates a new CascadingDataEntryWriter. + * @param dataEntryWriter1 the DataEntryWriter to which the writing will be + * delegated first. + * @param dataEntryWriter2 the DataEntryWriter to which the writing will be + * delegated, if the first one can't provide an + * output stream. + */ + public CascadingDataEntryWriter(DataEntryWriter dataEntryWriter1, + DataEntryWriter dataEntryWriter2) + { + this.dataEntryWriter1 = dataEntryWriter1; + this.dataEntryWriter2 = dataEntryWriter2; + } + + + // Implementations for DataEntryWriter. + + + public boolean createDirectory(DataEntry dataEntry) throws IOException + { + // Try to create a directory with the first data entry writer, or + // otherwise with the second data entry writer. + return dataEntryWriter1.createDirectory(dataEntry) || + dataEntryWriter2.createDirectory(dataEntry); + } + + + public OutputStream getOutputStream(DataEntry dataEntry) throws IOException + { + return getOutputStream(dataEntry, null); + } + + + public OutputStream getOutputStream(DataEntry dataEntry, + Finisher finisher) throws IOException + { + // Try to get an output stream from the first data entry writer. + OutputStream outputStream = + dataEntryWriter1.getOutputStream(dataEntry, finisher); + + // Return it, if it's not null. Otherwise try to get an output stream + // from the second data entry writer. + return outputStream != null ? + outputStream : + dataEntryWriter2.getOutputStream(dataEntry, finisher); + } + + + public void close() throws IOException + { + dataEntryWriter1.close(); + dataEntryWriter2.close(); + + dataEntryWriter1 = null; + dataEntryWriter2 = null; + } +} diff --git a/src/proguard/io/ClassFilter.java b/src/proguard/io/ClassFilter.java new file mode 100644 index 0000000..bf591ab --- /dev/null +++ b/src/proguard/io/ClassFilter.java @@ -0,0 +1,59 @@ +/* + * 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.io; + +import proguard.classfile.ClassConstants; +import proguard.util.ExtensionMatcher; + +import java.io.IOException; + + +/** + * This DataEntryReader delegates to one of two other DataEntryReader instances, + * depending on the extension of the data entry. + * + * @author Eric Lafortune + */ +public class ClassFilter extends FilteredDataEntryReader +{ + /** + * Creates a new ClassFilter that delegates reading classes to the + * given reader. + */ + public ClassFilter(DataEntryReader classReader) + { + this(classReader, null); + } + + + /** + * Creates a new ClassFilter that delegates to either of the two given + * readers. + */ + public ClassFilter(DataEntryReader classReader, + DataEntryReader dataEntryReader) + { + super(new DataEntryNameFilter( + new ExtensionMatcher(ClassConstants.CLASS_FILE_EXTENSION)), + classReader, + dataEntryReader); + } +} diff --git a/src/proguard/io/ClassReader.java b/src/proguard/io/ClassReader.java new file mode 100644 index 0000000..e21968c --- /dev/null +++ b/src/proguard/io/ClassReader.java @@ -0,0 +1,115 @@ +/* + * 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.io; + +import proguard.classfile.*; +import proguard.classfile.io.*; +import proguard.classfile.util.*; +import proguard.classfile.visitor.ClassVisitor; + +import java.io.*; + +/** + * This DataEntryReader applies a given ClassVisitor to the class + * definitions that it reads. + * <p> + * Class files are read as ProgramClass objects or LibraryClass objects, + * depending on the <code>isLibrary</code> flag. + * <p> + * In case of libraries, only public classes are considered, if the + * <code>skipNonPublicLibraryClasses</code> flag is set. + * + * @author Eric Lafortune + */ +public class ClassReader implements DataEntryReader +{ + private final boolean isLibrary; + private final boolean skipNonPublicLibraryClasses; + private final boolean skipNonPublicLibraryClassMembers; + private final WarningPrinter warningPrinter; + private final ClassVisitor classVisitor; + + + /** + * Creates a new DataEntryClassFilter for reading the specified + * Clazz objects. + */ + public ClassReader(boolean isLibrary, + boolean skipNonPublicLibraryClasses, + boolean skipNonPublicLibraryClassMembers, + WarningPrinter warningPrinter, + ClassVisitor classVisitor) + { + this.isLibrary = isLibrary; + this.skipNonPublicLibraryClasses = skipNonPublicLibraryClasses; + this.skipNonPublicLibraryClassMembers = skipNonPublicLibraryClassMembers; + this.warningPrinter = warningPrinter; + this.classVisitor = classVisitor; + } + + + // Implementations for DataEntryReader. + + public void read(DataEntry dataEntry) throws IOException + { + try + { + // Get the input stream. + InputStream inputStream = dataEntry.getInputStream(); + + // Wrap it into a data input stream. + DataInputStream dataInputStream = new DataInputStream(inputStream); + + // Create a Clazz representation. + Clazz clazz; + if (isLibrary) + { + clazz = new LibraryClass(); + clazz.accept(new LibraryClassReader(dataInputStream, skipNonPublicLibraryClasses, skipNonPublicLibraryClassMembers)); + } + else + { + clazz = new ProgramClass(); + clazz.accept(new ProgramClassReader(dataInputStream)); + } + + // Apply the visitor, if we have a real class. + String className = clazz.getName(); + if (className != null) + { + if (!dataEntry.getName().replace(File.pathSeparatorChar, ClassConstants.INTERNAL_PACKAGE_SEPARATOR).equals(className+ClassConstants.CLASS_FILE_EXTENSION) && + warningPrinter != null) + { + warningPrinter.print(className, + "Warning: class [" + dataEntry.getName() + "] unexpectedly contains class [" + ClassUtil.externalClassName(className) + "]"); + } + + clazz.accept(classVisitor); + } + + dataEntry.closeInputStream(); + } + catch (Exception ex) + { + throw new IOException("Can't process class ["+dataEntry.getName()+"] ("+ex.getMessage()+")"); + } + } +} diff --git a/src/proguard/io/ClassRewriter.java b/src/proguard/io/ClassRewriter.java new file mode 100644 index 0000000..bd19e1d --- /dev/null +++ b/src/proguard/io/ClassRewriter.java @@ -0,0 +1,80 @@ +/* + * 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.io; + +import proguard.classfile.*; +import proguard.classfile.io.ProgramClassWriter; + +import java.io.*; + + +/** + * This DataEntryReader reads class entries and writes their corresponding + * versions from the ClassPool to a given DataEntryWriter. + * + * @author Eric Lafortune + */ +public class ClassRewriter implements DataEntryReader +{ + private final ClassPool classPool; + private final DataEntryWriter dataEntryWriter; + + + public ClassRewriter(ClassPool classPool, + DataEntryWriter dataEntryWriter) + { + this.classPool = classPool; + this.dataEntryWriter = dataEntryWriter; + } + + + // Implementations for DataEntryReader. + + public void read(DataEntry dataEntry) throws IOException + { + String inputName = dataEntry.getName(); + String className = inputName.substring(0, inputName.length() - ClassConstants.CLASS_FILE_EXTENSION.length()); + + // Find the modified class corrsponding to the input entry. + ProgramClass programClass = (ProgramClass)classPool.getClass(className); + if (programClass != null) + { + // Rename the data entry if necessary. + String newClassName = programClass.getName(); + if (!className.equals(newClassName)) + { + dataEntry = new RenamedDataEntry(dataEntry, newClassName + ClassConstants.CLASS_FILE_EXTENSION); + } + + // Get the output entry corresponding to this input entry. + OutputStream outputStream = dataEntryWriter.getOutputStream(dataEntry); + if (outputStream != null) + { + // Write the class to the output entry. + DataOutputStream classOutputStream = new DataOutputStream(outputStream); + + new ProgramClassWriter(classOutputStream).visitProgramClass(programClass); + + classOutputStream.flush(); + } + } + } +} diff --git a/src/proguard/io/DataEntry.java b/src/proguard/io/DataEntry.java new file mode 100644 index 0000000..af0e373 --- /dev/null +++ b/src/proguard/io/DataEntry.java @@ -0,0 +1,62 @@ +/* + * 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.io; + +import java.io.*; + +/** + * This interface describes a data entry, e.g. a ZIP entry, a file, or a + * directory. + * + * @author Eric Lafortune + */ +public interface DataEntry +{ + /** + * Returns the name of this data entry. + */ + public String getName(); + + /** + * Returns whether the data entry represents a directory. + */ + public boolean isDirectory(); + + + /** + * Returns an input stream for reading the content of this data entry. + * The data entry may not represent a directory. + */ + public InputStream getInputStream() throws IOException; + + + /** + * Closes the previously retrieved InputStream. + */ + public void closeInputStream() throws IOException; + + + /** + * Returns the parent of this data entry, or <code>null</null> if it doesn't + * have one. + */ + public DataEntry getParent(); +} diff --git a/src/proguard/io/DataEntryCopier.java b/src/proguard/io/DataEntryCopier.java new file mode 100644 index 0000000..faaa555 --- /dev/null +++ b/src/proguard/io/DataEntryCopier.java @@ -0,0 +1,247 @@ +/* + * 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.io; + +import proguard.util.ExtensionMatcher; + +import java.io.*; + + +/** + * This DataEntryReader writes the ZIP entries and files that it reads to a + * given DataEntryWriter. + * + * @author Eric Lafortune + */ +public class DataEntryCopier implements DataEntryReader +{ + private static final int BUFFER_SIZE = 1024; + + private final DataEntryWriter dataEntryWriter; + private final byte[] buffer = new byte[BUFFER_SIZE]; + + + + public DataEntryCopier(DataEntryWriter dataEntryWriter) + { + this.dataEntryWriter = dataEntryWriter; + } + + + // Implementations for DataEntryReader. + + public void read(DataEntry dataEntry) throws IOException + { + try + { + if (dataEntry.isDirectory()) + { + dataEntryWriter.createDirectory(dataEntry); + } + else + { + // Get the output entry corresponding to this input entry. + OutputStream outputStream = dataEntryWriter.getOutputStream(dataEntry); + if (outputStream != null) + { + InputStream inputStream = dataEntry.getInputStream(); + + // Copy the data from the input entry to the output entry. + copyData(inputStream, outputStream); + + // Close the data entries. + dataEntry.closeInputStream(); + } + } + } + catch (IOException ex) + { + System.err.println("Warning: can't write resource [" + dataEntry.getName() + "] (" + ex.getMessage() + ")"); + } + } + + + /** + * Copies all data that it can read from the given input stream to the + * given output stream. + */ + protected void copyData(InputStream inputStream, + OutputStream outputStream) + throws IOException + { + while (true) + { + int count = inputStream.read(buffer); + if (count < 0) + { + break; + } + outputStream.write(buffer, 0, count); + } + + outputStream.flush(); + } + + + /** + * A main method for testing file/jar/war/directory copying. + */ + public static void main(String[] args) + { + try + { + String input = args[0]; + String output = args[1]; + + boolean outputIsJar = output.endsWith(".jar"); + boolean outputIsWar = output.endsWith(".war"); + boolean outputIsEar = output.endsWith(".ear"); + boolean outputIsZip = output.endsWith(".zip"); + + DataEntryWriter writer = new DirectoryWriter(new File(output), + outputIsJar || + outputIsWar || + outputIsEar || + outputIsZip); + + if (!outputIsJar) + { + // Zip up any zips, if necessary. + DataEntryWriter zipWriter = new JarWriter(writer); + if (outputIsZip) + { + // Always zip. + writer = zipWriter; + } + else + { + // Only zip up zips. + writer = new FilteredDataEntryWriter(new DataEntryParentFilter( + new DataEntryNameFilter( + new ExtensionMatcher(".zip"))), + zipWriter, + writer); + } + + // Zip up any wars, if necessary. + DataEntryWriter warWriter = new JarWriter(writer); + if (outputIsWar) + { + // Always zip. + writer = warWriter; + } + else + { + // Only zip up wars. + writer = new FilteredDataEntryWriter(new DataEntryParentFilter( + new DataEntryNameFilter( + new ExtensionMatcher(".war"))), + warWriter, + writer); + } + } + + // Zip up any jars, if necessary. + DataEntryWriter jarWriter = new JarWriter(writer); + if (outputIsJar) + { + // Always zip. + writer = jarWriter; + } + else + { + // Only zip up jars. + writer = new FilteredDataEntryWriter(new DataEntryParentFilter( + new DataEntryNameFilter( + new ExtensionMatcher(".jar"))), + jarWriter, + writer); + } + + + // Create the copying DataEntryReader. + DataEntryReader reader = new DataEntryCopier(writer); + + + boolean inputIsJar = input.endsWith(".jar"); + boolean inputIsWar = input.endsWith(".war"); + boolean inputIsZip = input.endsWith(".zip"); + + // Unzip any jars, if necessary. + DataEntryReader jarReader = new JarReader(reader); + if (inputIsJar) + { + // Always unzip. + reader = jarReader; + } + else + { + // Only unzip jar entries. + reader = new FilteredDataEntryReader(new DataEntryNameFilter( + new ExtensionMatcher(".jar")), + jarReader, + reader); + + // Unzip any wars, if necessary. + DataEntryReader warReader = new JarReader(reader); + if (inputIsWar) + { + // Always unzip. + reader = warReader; + } + else + { + // Only unzip war entries. + reader = new FilteredDataEntryReader(new DataEntryNameFilter( + new ExtensionMatcher(".war")), + warReader, + reader); + } + + // Unzip any zips, if necessary. + DataEntryReader zipReader = new JarReader(reader); + if (inputIsZip) + { + // Always unzip. + reader = zipReader; + } + else + { + // Only unzip zip entries. + reader = new FilteredDataEntryReader(new DataEntryNameFilter( + new ExtensionMatcher(".zip")), + zipReader, + reader); + } + } + + DirectoryPump directoryReader = new DirectoryPump(new File(input)); + + directoryReader.pumpDataEntries(reader); + + writer.close(); + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } +} diff --git a/src/proguard/io/DataEntryDirectoryFilter.java b/src/proguard/io/DataEntryDirectoryFilter.java new file mode 100644 index 0000000..bb36f3e --- /dev/null +++ b/src/proguard/io/DataEntryDirectoryFilter.java @@ -0,0 +1,40 @@ +/* + * 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.io; + +import proguard.util.StringMatcher; + +/** + * This DataEntryFilter filters data entries based on whether they represent + * directories. + * + * @author Eric Lafortune + */ +public class DataEntryDirectoryFilter +implements DataEntryFilter +{ + // Implementations for DataEntryFilter. + + public boolean accepts(DataEntry dataEntry) + { + return dataEntry != null && dataEntry.isDirectory(); + } +}
\ No newline at end of file diff --git a/src/proguard/io/DataEntryFilter.java b/src/proguard/io/DataEntryFilter.java new file mode 100644 index 0000000..ddcd0be --- /dev/null +++ b/src/proguard/io/DataEntryFilter.java @@ -0,0 +1,38 @@ +/* + * 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.io; + + +/** + * This interface provides a method to filter data entries. + * + * @author Eric Lafortune + */ +public interface DataEntryFilter +{ + /** + * Checks whether the filter accepts the given data entry. + * @param dataEntry the data entry to filter. + * @return a boolean indicating whether the filter accepts the given data + * entry. + */ + public boolean accepts(DataEntry dataEntry); +} diff --git a/src/proguard/io/DataEntryNameFilter.java b/src/proguard/io/DataEntryNameFilter.java new file mode 100644 index 0000000..d6afd2e --- /dev/null +++ b/src/proguard/io/DataEntryNameFilter.java @@ -0,0 +1,54 @@ +/* + * 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.io; + +import proguard.util.StringMatcher; + +/** + * This DataEntryFilter filters data entries based on whether their names match + * a given StringMatcher. + * + * @author Eric Lafortune + */ +public class DataEntryNameFilter +implements DataEntryFilter +{ + private final StringMatcher stringMatcher; + + + /** + * Creates a new DataEntryNameFilter. + * @param stringMatcher the string matcher that will be applied to the names + * of the filtered data entries. + */ + public DataEntryNameFilter(StringMatcher stringMatcher) + { + this.stringMatcher = stringMatcher; + } + + + // Implementations for DataEntryFilter. + + public boolean accepts(DataEntry dataEntry) + { + return dataEntry != null && stringMatcher.matches(dataEntry.getName()); + } +} diff --git a/src/proguard/io/DataEntryObfuscator.java b/src/proguard/io/DataEntryObfuscator.java new file mode 100644 index 0000000..aa63af1 --- /dev/null +++ b/src/proguard/io/DataEntryObfuscator.java @@ -0,0 +1,131 @@ +/* + * 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.io; + +import proguard.classfile.*; +import proguard.classfile.util.ClassUtil; + +import java.io.IOException; +import java.util.Map; + +/** + * This DataEntryReader delegates to another DataEntryReader, renaming the + * data entries based on the renamed classes in the given ClassPool. + * + * @author Eric Lafortune + */ +public class DataEntryObfuscator implements DataEntryReader +{ + private final ClassPool classPool; + private final Map packagePrefixMap; + private final DataEntryReader dataEntryReader; + + + /** + * Creates a new DataEntryObfuscator. + * @param classPool the class pool that maps from old names to new + * names. + * @param packagePrefixMap the map from old package prefixes to new package + * prefixes. + * @param dataEntryReader the DataEntryReader to which calls will be + * delegated. + */ + public DataEntryObfuscator(ClassPool classPool, + Map packagePrefixMap, + DataEntryReader dataEntryReader) + { + this.classPool = classPool; + this.packagePrefixMap = packagePrefixMap; + this.dataEntryReader = dataEntryReader; + } + + + // Implementations for DataEntryReader. + + public void read(DataEntry dataEntry) throws IOException + { + // Delegate to the actual data entry reader. + dataEntryReader.read(renamedDataEntry(dataEntry)); + } + + + /** + * Create a renamed data entry, if possible. + */ + private DataEntry renamedDataEntry(DataEntry dataEntry) + { + String dataEntryName = dataEntry.getName(); + + // Try to find a corresponding class name by removing increasingly + // long suffixes, + for (int suffixIndex = dataEntryName.length() - 1; + suffixIndex > 0; + suffixIndex--) + { + char c = dataEntryName.charAt(suffixIndex); + if (!Character.isLetterOrDigit(c)) + { + // Chop off the suffix. + String className = dataEntryName.substring(0, suffixIndex); + + // Did we get to the package separator? + if (c == ClassConstants.INTERNAL_PACKAGE_SEPARATOR) + { + break; + } + + // Is there a class corresponding to the data entry? + Clazz clazz = classPool.getClass(className); + if (clazz != null) + { + // Did the class get a new name? + String newClassName = clazz.getName(); + if (!className.equals(newClassName)) + { + // Return a renamed data entry. + String newDataEntryName = + newClassName + dataEntryName.substring(suffixIndex); + + return new RenamedDataEntry(dataEntry, newDataEntryName); + } + + // Otherwise stop looking. + break; + } + } + } + + // Did the package get a new name? + String packagePrefix = ClassUtil.internalPackagePrefix(dataEntryName); + String newPackagePrefix = (String)packagePrefixMap.get(packagePrefix); + if (newPackagePrefix != null && + !packagePrefix.equals(newPackagePrefix)) + { + // Return a renamed data entry. + String newDataEntryName = + newPackagePrefix + dataEntryName.substring(packagePrefix.length()); + + return new RenamedDataEntry(dataEntry, newDataEntryName); + } + + return dataEntry; + } +} diff --git a/src/proguard/io/DataEntryParentFilter.java b/src/proguard/io/DataEntryParentFilter.java new file mode 100644 index 0000000..fbeac4f --- /dev/null +++ b/src/proguard/io/DataEntryParentFilter.java @@ -0,0 +1,51 @@ +/* + * 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.io; + +/** + * This DataEntryFilter delegates filtering to a DataEntryFilter for its parent. + * + * @author Eric Lafortune + */ +public class DataEntryParentFilter +implements DataEntryFilter +{ + private final DataEntryFilter dataEntryFilter; + + + /** + * Creates a new ParentFilter. + * @param dataEntryFilter the filter that will be applied to the data + * entry's parent. + */ + public DataEntryParentFilter(DataEntryFilter dataEntryFilter) + { + this.dataEntryFilter = dataEntryFilter; + } + + + // Implementations for DataEntryFilter. + + public boolean accepts(DataEntry dataEntry) + { + return dataEntry != null && dataEntryFilter.accepts(dataEntry.getParent()); + } +} diff --git a/src/proguard/io/DataEntryPump.java b/src/proguard/io/DataEntryPump.java new file mode 100644 index 0000000..bfe22a3 --- /dev/null +++ b/src/proguard/io/DataEntryPump.java @@ -0,0 +1,43 @@ +/* + * 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.io; + +import java.io.IOException; + + +/** + * This interface provides a method to pump data entries. The implementation + * determines the source and the type of the data entries. Typical examples + * are zip entries coming from a zip file of file entries coming from a + * directory structure. The reader can for instance collect the classes, + * or copy the resource files that are presented. + * + * @author Eric Lafortune + */ +public interface DataEntryPump +{ + /** + * Applies the given DataEntryReader to all data entries that the + * implementation can provide. + */ + public void pumpDataEntries(DataEntryReader dataEntryReader) + throws IOException; +} diff --git a/src/proguard/io/DataEntryReader.java b/src/proguard/io/DataEntryReader.java new file mode 100644 index 0000000..e77f7bf --- /dev/null +++ b/src/proguard/io/DataEntryReader.java @@ -0,0 +1,38 @@ +/* + * 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.io; + +import java.io.IOException; + + +/** + * This interface provides methods for reading data entries. The implementation + * determines what to do with the read data, if anything. + * + * @author Eric Lafortune + */ +public interface DataEntryReader +{ + /** + * Reads the given data entry. + */ + public void read(DataEntry dataEntry) throws IOException; +} diff --git a/src/proguard/io/DataEntryRenamer.java b/src/proguard/io/DataEntryRenamer.java new file mode 100644 index 0000000..45c61ee --- /dev/null +++ b/src/proguard/io/DataEntryRenamer.java @@ -0,0 +1,104 @@ +/* + * 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.io; + +import proguard.classfile.ClassConstants; + +import java.io.IOException; +import java.util.Map; + +/** + * This DataEntryReader delegates to another DataEntryReader, renaming the + * data entries based on the given map. Entries whose name does not appear + * in the map may be passed to an alternative DataEntryReader. + * + * @author Eric Lafortune + */ +public class DataEntryRenamer implements DataEntryReader +{ + private final Map nameMap; + private final DataEntryReader renamedDataEntryReader; + private final DataEntryReader missingDataEntryReader; + + + /** + * Creates a new DataEntryRenamer. + * @param nameMap the map from old names to new names. + * @param renamedDataEntryReader the DataEntryReader to which renamed data + * entries will be passed. + */ + public DataEntryRenamer(Map nameMap, + DataEntryReader renamedDataEntryReader) + { + this(nameMap, renamedDataEntryReader, null); + } + + + /** + * Creates a new DataEntryRenamer. + * @param nameMap the map from old names to new names. + * @param renamedDataEntryReader the DataEntryReader to which renamed data + * entries will be passed. + * @param missingDataEntryReader the optional DataEntryReader to which data + * entries that can't be renamed will be + * passed. + */ + public DataEntryRenamer(Map nameMap, + DataEntryReader renamedDataEntryReader, + DataEntryReader missingDataEntryReader) + { + this.nameMap = nameMap; + this.renamedDataEntryReader = renamedDataEntryReader; + this.missingDataEntryReader = missingDataEntryReader; + } + + + // Implementations for DataEntryReader. + + public void read(DataEntry dataEntry) throws IOException + { + String name = dataEntry.getName(); + + // Add a directory separator if necessary. + if (dataEntry.isDirectory() && + name.length() > 0) + { + name += ClassConstants.INTERNAL_PACKAGE_SEPARATOR; + } + + String newName = (String)nameMap.get(name); + if (newName != null) + { + // Add remove the directory separator if necessary. + if (dataEntry.isDirectory() && + newName.length() > 0) + { + newName = newName.substring(0, newName.length() - 1); + } + + renamedDataEntryReader.read(new RenamedDataEntry(dataEntry, newName)); + } + else if (missingDataEntryReader != null) + { + missingDataEntryReader.read(dataEntry); + } + } +}
\ No newline at end of file diff --git a/src/proguard/io/DataEntryRewriter.java b/src/proguard/io/DataEntryRewriter.java new file mode 100644 index 0000000..eefced4 --- /dev/null +++ b/src/proguard/io/DataEntryRewriter.java @@ -0,0 +1,148 @@ +/* + * 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.io; + +import proguard.classfile.*; + +import java.io.*; + +/** + * This DataEntryReader writes the resource data entries that it reads to a + * given DataEntryWriter, updating their contents based on the renamed classes + * in the given ClassPool. + * + * @author Eric Lafortune + */ +public class DataEntryRewriter extends DataEntryCopier +{ + private final ClassPool classPool; + + + /** + * Creates a new DataEntryRewriter. + */ + public DataEntryRewriter(ClassPool classPool, + DataEntryWriter dataEntryWriter) + { + super(dataEntryWriter); + + this.classPool = classPool; + } + + + // Implementations for DataEntryCopier. + + protected void copyData(InputStream inputStream, + OutputStream outputStream) + throws IOException + { + Reader reader = new BufferedReader(new InputStreamReader(inputStream)); + Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream)); + + copyData(reader, writer); + + writer.flush(); + outputStream.flush(); + } + + + /** + * Copies all data that it can read from the given reader to the given + * writer. + */ + protected void copyData(Reader reader, + Writer writer) + throws IOException + { + StringBuffer word = new StringBuffer(); + + while (true) + { + int i = reader.read(); + if (i < 0) + { + break; + } + + // Is the character part of a word? + char c = (char)i; + if (Character.isJavaIdentifierPart(c) || + c == '.' || + c == '-') + { + // Collect the characters in this word. + word.append(c); + } + else + { + // Write out the updated word, if any. + writeUpdatedWord(writer, word.toString()); + word.setLength(0); + + // Write out the character that terminated it. + writer.write(c); + } + } + + // Write out the final word. + writeUpdatedWord(writer, word.toString()); + } + + + // Small utility methods. + + /** + * Writes the given word to the given writer, after having adapted it, + * based on the renamed class names. + */ + private void writeUpdatedWord(Writer writer, String word) + throws IOException + { + if (word.length() > 0) + { + String newWord = word; + + boolean containsDots = word.indexOf('.') >= 0; + + // Replace dots by forward slashes. + String className = containsDots ? + word.replace('.', ClassConstants.INTERNAL_PACKAGE_SEPARATOR) : + word; + + // Find the class corrsponding to the word. + Clazz clazz = classPool.getClass(className); + if (clazz != null) + { + // Update the word if necessary. + String newClassName = clazz.getName(); + if (!className.equals(newClassName)) + { + // Replace forward slashes by dots. + newWord = containsDots ? + newClassName.replace(ClassConstants.INTERNAL_PACKAGE_SEPARATOR, '.') : + newClassName; + } + } + + writer.write(newWord); + } + } +} diff --git a/src/proguard/io/DataEntryWriter.java b/src/proguard/io/DataEntryWriter.java new file mode 100644 index 0000000..9ecf79b --- /dev/null +++ b/src/proguard/io/DataEntryWriter.java @@ -0,0 +1,73 @@ +/* + * 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.io; + +import java.io.*; + + +/** + * This interface provides methods for writing data entries, such as ZIP entries + * or files. The implementation determines to which type of data entry the + * data will be written. + * + * @author Eric Lafortune + */ +public interface DataEntryWriter +{ + /** + * Creates a directory. + * @param dataEntry the data entry for which the directory is to be created. + * @return whether the directory has been created. + */ + public boolean createDirectory(DataEntry dataEntry) throws IOException; + + + /** + * Returns an output stream for writing data. The caller must not close + * the output stream; closing the output stream is the responsibility of + * the implementation of this interface. + * @param dataEntry the data entry for which the output stream is to be created. + * @return the output stream. The stream may be <code>null</code> to indicate + * that the data entry should not be written. + */ + public OutputStream getOutputStream(DataEntry dataEntry) throws IOException; + + + /** + * Returns an output stream for writing data. The caller must not close + * the output stream; closing the output stream is the responsibility of + * the implementation of this interface. + * @param dataEntry the data entry for which the output stream is to be created. + * @param finisher the optional finisher that will be called before this + * class closes the output stream (at some later point in + * time) that will be returned (now). + * @return the output stream. The stream may be <code>null</code> to indicate + * that the data entry should not be written. + */ + public OutputStream getOutputStream(DataEntry dataEntry, + Finisher finisher) throws IOException; + + + /** + * Finishes writing all data entries. + */ + public void close() throws IOException; +} diff --git a/src/proguard/io/DirectoryFilter.java b/src/proguard/io/DirectoryFilter.java new file mode 100644 index 0000000..a45d1aa --- /dev/null +++ b/src/proguard/io/DirectoryFilter.java @@ -0,0 +1,58 @@ +/* + * 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.io; + +import proguard.classfile.ClassConstants; +import proguard.util.ExtensionMatcher; + +import java.io.IOException; + + +/** + * This DataEntryReader delegates to one of two other DataEntryReader instances, + * depending on whether the data entry represents a directory or not. + * + * @author Eric Lafortune + */ +public class DirectoryFilter extends FilteredDataEntryReader +{ + /** + * Creates a new ClassFilter that delegates reading directories to the + * given reader. + */ + public DirectoryFilter(DataEntryReader directoryReader) + { + this (directoryReader, null); + } + + + /** + * Creates a new ClassFilter that delegates to either of the two given + * readers. + */ + public DirectoryFilter(DataEntryReader directoryReader, + DataEntryReader otherReader) + { + super(new DataEntryDirectoryFilter(), + directoryReader, + otherReader); + } +}
\ No newline at end of file diff --git a/src/proguard/io/DirectoryPump.java b/src/proguard/io/DirectoryPump.java new file mode 100644 index 0000000..cab2ff3 --- /dev/null +++ b/src/proguard/io/DirectoryPump.java @@ -0,0 +1,78 @@ +/* + * 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.io; + +import java.io.*; + + +/** + * This class can read a given file or directory, recursively, applying a given + * DataEntryReader to all files it comes across. + * + * @author Eric Lafortune + */ +public class DirectoryPump implements DataEntryPump +{ + private final File directory; + + + public DirectoryPump(File directory) + { + this.directory = directory; + } + + + // Implementations for DataEntryPump. + + public void pumpDataEntries(DataEntryReader dataEntryReader) + throws IOException + { + if (!directory.exists()) + { + throw new IOException("No such file or directory"); + } + + readFiles(directory, dataEntryReader); + } + + + /** + * Reads the given subdirectory recursively, applying the given DataEntryReader + * to all files that are encountered. + */ + private void readFiles(File file, DataEntryReader dataEntryReader) + throws IOException + { + // Pass the file data entry to the reader. + dataEntryReader.read(new FileDataEntry(directory, file)); + + if (file.isDirectory()) + { + // Recurse into the subdirectory. + File[] files = file.listFiles(); + + for (int index = 0; index < files.length; index++) + { + readFiles(files[index], dataEntryReader); + } + } + } +} diff --git a/src/proguard/io/DirectoryWriter.java b/src/proguard/io/DirectoryWriter.java new file mode 100644 index 0000000..c6605df --- /dev/null +++ b/src/proguard/io/DirectoryWriter.java @@ -0,0 +1,165 @@ +/* + * 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.io; + +import proguard.classfile.ClassConstants; + +import java.io.*; + + +/** + * This DataEntryWriter writes data entries to individual files in a given + * directory. + * + * @author Eric Lafortune + */ +public class DirectoryWriter implements DataEntryWriter +{ + private final File baseFile; + private final boolean isFile; + + private File currentFile; + private OutputStream currentOutputStream; + private Finisher currentFinisher; + + + /** + * Creates a new DirectoryWriter. + * @param baseFile the base directory to which all files will be written. + */ + public DirectoryWriter(File baseFile, + boolean isFile) + { + this.baseFile = baseFile; + this.isFile = isFile; + } + + + // Implementations for DataEntryWriter. + + public boolean createDirectory(DataEntry dataEntry) throws IOException + { + // Should we close the current file? + if (!isFile && + currentFile != null) + { + closeEntry(); + } + + File directory = getFile(dataEntry); + if (!directory.exists() && + !directory.mkdirs()) + { + throw new IOException("Can't create directory [" + directory.getPath() + "]"); + } + + return true; + } + + + public OutputStream getOutputStream(DataEntry dataEntry) throws IOException + { + return getOutputStream(dataEntry, null); + } + + + public OutputStream getOutputStream(DataEntry dataEntry, + Finisher finisher) throws IOException + { + File file = getFile(dataEntry); + + // Should we close the current file? + if (!isFile && + currentFile != null && + !currentFile.equals(file)) + { + closeEntry(); + } + + // Do we need a new stream? + if (currentOutputStream == null) + { + // Make sure the parent directories exist. + File parentDirectory = file.getParentFile(); + if (parentDirectory != null && + !parentDirectory.exists() && + !parentDirectory.mkdirs()) + { + throw new IOException("Can't create directory [" + parentDirectory.getPath() + "]"); + } + + // Open a new output stream for writing to the file. + currentOutputStream = + new BufferedOutputStream( + new FileOutputStream(file)); + + currentFinisher = finisher; + currentFile = file; + } + + return currentOutputStream; + } + + + public void close() throws IOException + { + // Close the file stream, if any. + closeEntry(); + } + + + // Small utility methods. + + /** + * Returns the file for the given data entry. + */ + private File getFile(DataEntry dataEntry) + { + // Use the specified file, or construct a new file. + return isFile ? + baseFile : + new File(baseFile, + dataEntry.getName().replace(ClassConstants.INTERNAL_PACKAGE_SEPARATOR, + File.separatorChar)); + } + + + /** + * Closes the previous file, if any. + */ + private void closeEntry() throws IOException + { + // Close the file stream, if any. + if (currentOutputStream != null) + { + // Let any finisher finish up first. + if (currentFinisher != null) + { + currentFinisher.finish(); + currentFinisher = null; + } + + currentOutputStream.close(); + currentOutputStream = null; + currentFile = null; + } + } +} diff --git a/src/proguard/io/FileDataEntry.java b/src/proguard/io/FileDataEntry.java new file mode 100644 index 0000000..d0449ee --- /dev/null +++ b/src/proguard/io/FileDataEntry.java @@ -0,0 +1,96 @@ +/* + * 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.io; + +import proguard.classfile.ClassConstants; + +import java.io.*; + +/** + * This <code>DataEntry</code> represents a file. + * + * @author Eric Lafortune + */ +public class FileDataEntry implements DataEntry +{ + private final File directory; + private final File file; + private InputStream inputStream; + + + public FileDataEntry(File directory, + File file) + { + this.directory = directory; + this.file = file; + } + + + // Implementations for DataEntry. + + public String getName() + { + // Chop the directory name from the file name and get the right separators. + return file.equals(directory) ? + file.getName() : + file.getPath() + .substring(directory.getPath().length() + File.separator.length()) + .replace(File.separatorChar, ClassConstants.INTERNAL_PACKAGE_SEPARATOR); + } + + + public boolean isDirectory() + { + return file.isDirectory(); + } + + + public InputStream getInputStream() throws IOException + { + if (inputStream == null) + { + inputStream = new BufferedInputStream(new FileInputStream(file)); + } + + return inputStream; + } + + + public void closeInputStream() throws IOException + { + inputStream.close(); + inputStream = null; + } + + + public DataEntry getParent() + { + return null; + } + + + // Implementations for Object. + + public String toString() + { + return getName(); + } +} diff --git a/src/proguard/io/FilteredDataEntryReader.java b/src/proguard/io/FilteredDataEntryReader.java new file mode 100644 index 0000000..11da0d4 --- /dev/null +++ b/src/proguard/io/FilteredDataEntryReader.java @@ -0,0 +1,90 @@ +/* + * 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.io; + +import java.io.IOException; + + +/** + * This DataEntryReader delegates to one of two other DataEntryReader instances, + * depending on whether the data entry passes through a given data entry filter + * or not. + * + * @author Eric Lafortune + */ +public class FilteredDataEntryReader implements DataEntryReader +{ + private final DataEntryFilter dataEntryFilter; + private final DataEntryReader acceptedDataEntryReader; + private final DataEntryReader rejectedDataEntryReader; + + + /** + * Creates a new FilteredDataEntryReader with only a reader for accepted + * data entries. + * @param dataEntryFilter the data entry filter. + * @param acceptedDataEntryReader the DataEntryReader to which the reading + * will be delegated if the filter accepts + * the data entry. May be <code>null</code>. + */ + public FilteredDataEntryReader(DataEntryFilter dataEntryFilter, + DataEntryReader acceptedDataEntryReader) + { + this(dataEntryFilter, acceptedDataEntryReader, null); + } + + + /** + * Creates a new FilteredDataEntryReader. + * @param dataEntryFilter the data entry filter. + * @param acceptedDataEntryReader the DataEntryReader to which the reading + * will be delegated if the filter accepts + * the data entry. May be <code>null</code>. + * @param rejectedDataEntryReader the DataEntryReader to which the reading + * will be delegated if the filter does not + * accept the data entry. May be + * <code>null</code>. + */ + public FilteredDataEntryReader(DataEntryFilter dataEntryFilter, + DataEntryReader acceptedDataEntryReader, + DataEntryReader rejectedDataEntryReader) + { + this.dataEntryFilter = dataEntryFilter; + this.acceptedDataEntryReader = acceptedDataEntryReader; + this.rejectedDataEntryReader = rejectedDataEntryReader; + } + + + // Implementations for DataEntryReader. + + public void read(DataEntry dataEntry) + throws IOException + { + DataEntryReader dataEntryReader = dataEntryFilter.accepts(dataEntry) ? + acceptedDataEntryReader : + rejectedDataEntryReader; + + if (dataEntryReader != null) + { + dataEntryReader.read(dataEntry); + } + } +} diff --git a/src/proguard/io/FilteredDataEntryWriter.java b/src/proguard/io/FilteredDataEntryWriter.java new file mode 100644 index 0000000..40a8c64 --- /dev/null +++ b/src/proguard/io/FilteredDataEntryWriter.java @@ -0,0 +1,125 @@ +/* + * 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.io; + +import java.io.*; + +/** + * This DataEntryWriter delegates to one of two other DataEntryWriter instances, + * depending on whether the data entry passes through a given data entry filter + * or not. + * + * @author Eric Lafortune + */ +public class FilteredDataEntryWriter implements DataEntryWriter +{ + private final DataEntryFilter dataEntryFilter; + private DataEntryWriter acceptedDataEntryWriter; + private DataEntryWriter rejectedDataEntryWriter; + + + /** + * Creates a new FilteredDataEntryWriter with only a writer for accepted + * data entries. + * @param dataEntryFilter the data entry filter. + * @param acceptedDataEntryWriter the DataEntryWriter to which the writing + * will be delegated if the filter accepts + * the data entry. May be <code>null</code>. + */ + public FilteredDataEntryWriter(DataEntryFilter dataEntryFilter, + DataEntryWriter acceptedDataEntryWriter) + { + this(dataEntryFilter, acceptedDataEntryWriter, null); + } + + + /** + * Creates a new FilteredDataEntryWriter. + * @param dataEntryFilter the data entry filter. + * @param acceptedDataEntryWriter the DataEntryWriter to which the writing + * will be delegated if the filter accepts + * the data entry. May be <code>null</code>. + * @param rejectedDataEntryWriter the DataEntryWriter to which the writing + * will be delegated if the filter does not + * accept the data entry. May be + * <code>null</code>. + */ + public FilteredDataEntryWriter(DataEntryFilter dataEntryFilter, + DataEntryWriter acceptedDataEntryWriter, + DataEntryWriter rejectedDataEntryWriter) + { + this.dataEntryFilter = dataEntryFilter; + this.acceptedDataEntryWriter = acceptedDataEntryWriter; + this.rejectedDataEntryWriter = rejectedDataEntryWriter; + } + + + // Implementations for DataEntryWriter. + + public boolean createDirectory(DataEntry dataEntry) throws IOException + { + // Get the right data entry writer. + DataEntryWriter dataEntryWriter = dataEntryFilter.accepts(dataEntry) ? + acceptedDataEntryWriter : + rejectedDataEntryWriter; + + // Delegate to it, if it's not null. + return dataEntryWriter != null && + dataEntryWriter.createDirectory(dataEntry); + } + + + public OutputStream getOutputStream(DataEntry dataEntry) throws IOException + { + return getOutputStream(dataEntry, null); + } + + + public OutputStream getOutputStream(DataEntry dataEntry, + Finisher finisher) throws IOException + { + // Get the right data entry writer. + DataEntryWriter dataEntryWriter = dataEntryFilter.accepts(dataEntry) ? + acceptedDataEntryWriter : + rejectedDataEntryWriter; + + // Delegate to it, if it's not null. + return dataEntryWriter != null ? + dataEntryWriter.getOutputStream(dataEntry, finisher) : + null; + } + + + public void close() throws IOException + { + if (acceptedDataEntryWriter != null) + { + acceptedDataEntryWriter.close(); + acceptedDataEntryWriter = null; + } + + if (rejectedDataEntryWriter != null) + { + rejectedDataEntryWriter.close(); + rejectedDataEntryWriter = null; + } + } +} diff --git a/src/proguard/io/Finisher.java b/src/proguard/io/Finisher.java new file mode 100644 index 0000000..8c4cc1e --- /dev/null +++ b/src/proguard/io/Finisher.java @@ -0,0 +1,37 @@ +/* + * 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.io; + +import java.io.IOException; + +/** + * This interface specifies a listener that is called to finish an output stream + * before it is closed. + * + * @author Eric Lafortune + */ +public interface Finisher +{ + /** + * Finishes an output stream right before it is closed. + */ + public void finish() throws IOException; +} diff --git a/src/proguard/io/JarReader.java b/src/proguard/io/JarReader.java new file mode 100644 index 0000000..f96b4aa --- /dev/null +++ b/src/proguard/io/JarReader.java @@ -0,0 +1,75 @@ +/* + * 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.io; + +import java.io.IOException; +import java.util.zip.*; + +/** + * This DataEntryReader lets a given DataEntryReader read all data entries of + * the read jar/war/zip data entries. + * + * @author Eric Lafortune + */ +public class JarReader implements DataEntryReader +{ + private final DataEntryReader dataEntryReader; + + + /** + * Creates a new JarReader. + */ + public JarReader(DataEntryReader dataEntryReader) + { + this.dataEntryReader = dataEntryReader; + } + + + // Implementation for DataEntryReader. + + public void read(DataEntry dataEntry) throws IOException + { + ZipInputStream zipInputStream = new ZipInputStream(dataEntry.getInputStream()); + + try + { + // Get all entries from the input jar. + while (true) + { + // Can we get another entry? + ZipEntry zipEntry = zipInputStream.getNextEntry(); + if (zipEntry == null) + { + break; + } + + // Delegate the actual reading to the data entry reader. + dataEntryReader.read(new ZipDataEntry(dataEntry, + zipEntry, + zipInputStream)); + } + } + finally + { + dataEntry.closeInputStream(); + } + } +} diff --git a/src/proguard/io/JarWriter.java b/src/proguard/io/JarWriter.java new file mode 100644 index 0000000..3e40cdf --- /dev/null +++ b/src/proguard/io/JarWriter.java @@ -0,0 +1,235 @@ +/* + * 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.io; + +import proguard.classfile.ClassConstants; + +import java.io.*; +import java.util.*; +import java.util.jar.*; +import java.util.zip.*; + + +/** + * This DataEntryWriter sends data entries to a given jar/zip file. + * The manifest and comment properties can optionally be set. + * + * @author Eric Lafortune + */ +public class JarWriter implements DataEntryWriter, Finisher +{ + private final DataEntryWriter dataEntryWriter; + private final Manifest manifest; + private final String comment; + + private OutputStream currentParentOutputStream; + private ZipOutputStream currentJarOutputStream; + private Finisher currentFinisher; + private DataEntry currentDataEntry; + + // The names of the jar entries that are already in the jar. + private final Set jarEntryNames = new HashSet(); + + + /** + * Creates a new JarWriter without manifest or comment. + */ + public JarWriter(DataEntryWriter dataEntryWriter) + { + this(dataEntryWriter, null, null); + } + + + /** + * Creates a new JarWriter. + */ + public JarWriter(DataEntryWriter dataEntryWriter, + Manifest manifest, + String comment) + { + this.dataEntryWriter = dataEntryWriter; + this.manifest = manifest; + this.comment = comment; + } + + + // Implementations for DataEntryWriter. + + public boolean createDirectory(DataEntry dataEntry) throws IOException + { + //Make sure we can start with a new entry. + if (!prepareEntry(dataEntry)) + { + return false; + } + + // Close the previous ZIP entry, if any. + closeEntry(); + + // Get the directory entry name. + String name = dataEntry.getName() + ClassConstants.INTERNAL_PACKAGE_SEPARATOR; + + // We have to check if the name is already used, because + // ZipOutputStream doesn't handle this case properly (it throws + // an exception which can be caught, but the ZipDataEntry is + // remembered anyway). + if (jarEntryNames.add(name)) + { + // Create a new directory entry. + currentJarOutputStream.putNextEntry(new ZipEntry(name)); + currentJarOutputStream.closeEntry(); + } + + // Clear the finisher. + currentFinisher = null; + currentDataEntry = null; + + return true; + } + + + public OutputStream getOutputStream(DataEntry dataEntry) throws IOException + { + return getOutputStream(dataEntry, null); + } + + + public OutputStream getOutputStream(DataEntry dataEntry, + Finisher finisher) throws IOException + { + //Make sure we can start with a new entry. + if (!prepareEntry(dataEntry)) + { + return null; + } + + // Do we need a new entry? + if (!dataEntry.equals(currentDataEntry)) + { + // Close the previous ZIP entry, if any. + closeEntry(); + + // Get the entry name. + String name = dataEntry.getName(); + + // We have to check if the name is already used, because + // ZipOutputStream doesn't handle this case properly (it throws + // an exception which can be caught, but the ZipDataEntry is + // remembered anyway). + if (!jarEntryNames.add(name)) + { + throw new IOException("Duplicate zip entry ["+dataEntry+"]"); + } + + // Create a new entry. + currentJarOutputStream.putNextEntry(new ZipEntry(name)); + + // Set up the finisher for the entry. + currentFinisher = finisher; + currentDataEntry = dataEntry; + } + + return currentJarOutputStream; + } + + + public void finish() throws IOException + { + // Finish the entire ZIP stream, if any. + if (currentJarOutputStream != null) + { + // Close the previous ZIP entry, if any. + closeEntry(); + + // Finish the entire ZIP stream. + currentJarOutputStream.finish(); + currentJarOutputStream = null; + currentParentOutputStream = null; + jarEntryNames.clear(); + } + } + + + public void close() throws IOException + { + // Close the parent stream. + dataEntryWriter.close(); + } + + + // Small utility methods. + + /** + * Makes sure the current output stream is set up for the given entry. + */ + private boolean prepareEntry(DataEntry dataEntry) throws IOException + { + // Get the parent stream, new or exisiting. + // This may finish our own jar output stream. + OutputStream parentOutputStream = + dataEntryWriter.getOutputStream(dataEntry.getParent(), this); + + // Did we get a stream? + if (parentOutputStream == null) + { + return false; + } + + // Do we need a new stream? + if (currentParentOutputStream == null) + { + currentParentOutputStream = parentOutputStream; + + // Create a new jar stream, with a manifest, if set. + currentJarOutputStream = manifest != null ? + new JarOutputStream(parentOutputStream, manifest) : + new ZipOutputStream(parentOutputStream); + + // Add a comment, if set. + if (comment != null) + { + currentJarOutputStream.setComment(comment); + } + } + + return true; + } + + + /** + * Closes the previous ZIP entry, if any. + */ + private void closeEntry() throws IOException + { + if (currentDataEntry != null) + { + // Let any finisher finish up first. + if (currentFinisher != null) + { + currentFinisher.finish(); + currentFinisher = null; + } + + currentJarOutputStream.closeEntry(); + currentDataEntry = null; + } + } +} diff --git a/src/proguard/io/ManifestRewriter.java b/src/proguard/io/ManifestRewriter.java new file mode 100644 index 0000000..f10307e --- /dev/null +++ b/src/proguard/io/ManifestRewriter.java @@ -0,0 +1,216 @@ +/* + * 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.io; + +import proguard.classfile.*; + +import java.io.*; + +/** + * This DataEntryReader writes the manifest data entries that it reads to a + * given DataEntryWriter, updating their contents based on the renamed classes + * in the given ClassPool. + * + * @author Eric Lafortune + */ +public class ManifestRewriter extends DataEntryRewriter +{ + /** + * Creates a new ManifestRewriter. + */ + public ManifestRewriter(ClassPool classPool, + DataEntryWriter dataEntryWriter) + { + super(classPool, dataEntryWriter); + } + + + // Implementations for DataEntryRewriter. + + protected void copyData(Reader reader, + Writer writer) + throws IOException + { + super.copyData(new SplitLineReader(reader), + new SplitLineWriter(writer)); + } + + + /** + * This Reader reads manifest files, joining any split lines. + */ + private static class SplitLineReader extends FilterReader + { + private char[] buffer = new char[2]; + private int bufferIndex = 0; + private int bufferSize = 0; + + + public SplitLineReader(Reader reader) + { + super(reader); + } + + + // Implementations for Reader. + + public int read() throws IOException + { + while (true) + { + if (bufferIndex < bufferSize) + { + return buffer[bufferIndex++]; + } + + // Read the first character. + int c1 = super.read(); + if (c1 != '\n' && c1 != '\r') + { + return c1; + } + + bufferIndex = 0; + bufferSize = 0; + buffer[bufferSize++] = '\n'; + + // Read the second character. + int c2 = super.read(); + if (c2 == ' ') + { + bufferSize = 0; + continue; + } + + if (c1 != '\r' || c2 != '\n') + { + buffer[bufferSize++] = (char)c2; + continue; + } + + // Read the third character. + int c3 = super.read(); + if (c3 == ' ') + { + bufferSize = 0; + continue; + } + + buffer[bufferSize++] = (char)c3; + } + } + + + public int read(char[] cbuf, int off, int len) throws IOException + { + // Delegate to reading a single character at a time. + int count = 0; + while (count < len) + { + int c = read(); + if (c == -1) + { + break; + } + + cbuf[off + count++] = (char)c; + } + + return count; + } + + + public long skip(long n) throws IOException + { + // Delegate to reading a single character at a time. + int count = 0; + while (count < n) + { + int c = read(); + if (c == -1) + { + break; + } + + count++; + } + + return count; + } + } + + + /** + * This Writer writes manifest files, splitting any long lines. + */ + private static class SplitLineWriter extends FilterWriter + { + private int counter = 0; + + + public SplitLineWriter(Writer writer) + { + super(writer); + } + + + // Implementations for Reader. + + public void write(int c) throws IOException + { + // TODO: We should actually count the Utf-8 bytes, not the characters. + if (c == '\n') + { + // Reset the character count. + counter = 0; + } + else if (counter == 70) + { + // Insert are newline and space. + super.write('\n'); + super.write(' '); + + counter = 2; + } + else + { + counter++; + } + + super.write(c); + } + + + public void write(char[] cbuf, int off, int len) throws IOException + { + for (int count = 0; count < len; count++) + { + write(cbuf[off + count]); + } + } + + + public void write(String str, int off, int len) throws IOException + { + write(str.toCharArray(), off, len); + } + } +}
\ No newline at end of file diff --git a/src/proguard/io/NameFilter.java b/src/proguard/io/NameFilter.java new file mode 100644 index 0000000..2a9fbc3 --- /dev/null +++ b/src/proguard/io/NameFilter.java @@ -0,0 +1,83 @@ +/* + * 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.io; + +import proguard.util.*; + +import java.util.List; + +/** + * This DataEntryReader delegates to one of two other DataEntryReader instances, + * depending on the name of the data entry. + * + * @author Eric Lafortune + */ +public class NameFilter extends FilteredDataEntryReader +{ + /** + * Creates a new NameFilter that delegates to the given reader, depending + * on the given list of filters. + */ + public NameFilter(String regularExpression, + DataEntryReader acceptedDataEntryReader) + { + this(regularExpression, acceptedDataEntryReader, null); + } + + + /** + * Creates a new NameFilter that delegates to either of the two given + * readers, depending on the given list of filters. + */ + public NameFilter(String regularExpression, + DataEntryReader acceptedDataEntryReader, + DataEntryReader rejectedDataEntryReader) + { + super(new DataEntryNameFilter(new ListParser(new FileNameParser()).parse(regularExpression)), + acceptedDataEntryReader, + rejectedDataEntryReader); + } + + + /** + * Creates a new NameFilter that delegates to the given reader, depending + * on the given list of filters. + */ + public NameFilter(List regularExpressions, + DataEntryReader acceptedDataEntryReader) + { + this(regularExpressions, acceptedDataEntryReader, null); + } + + + /** + * Creates a new NameFilter that delegates to either of the two given + * readers, depending on the given list of filters. + */ + public NameFilter(List regularExpressions, + DataEntryReader acceptedDataEntryReader, + DataEntryReader rejectedDataEntryReader) + { + super(new DataEntryNameFilter(new ListParser(new FileNameParser()).parse(regularExpressions)), + acceptedDataEntryReader, + rejectedDataEntryReader); + } +}
\ No newline at end of file diff --git a/src/proguard/io/ParentDataEntryWriter.java b/src/proguard/io/ParentDataEntryWriter.java new file mode 100644 index 0000000..4f16d12 --- /dev/null +++ b/src/proguard/io/ParentDataEntryWriter.java @@ -0,0 +1,75 @@ +/* + * 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.io; + +import java.io.*; + +/** + * This DataEntryWriter lets another DataEntryWriter write the parent data + * entries. + * + * @author Eric Lafortune + */ +public class ParentDataEntryWriter implements DataEntryWriter +{ + private DataEntryWriter dataEntryWriter; + + + /** + * Creates a new ParentDataEntryWriter. + * @param dataEntryWriter the DataEntryWriter to which the writing will be + * delegated, passing the data entries' parents. + */ + public ParentDataEntryWriter(DataEntryWriter dataEntryWriter) + { + this.dataEntryWriter = dataEntryWriter; + } + + + // Implementations for DataEntryWriter. + + + public boolean createDirectory(DataEntry dataEntry) throws IOException + { + return getOutputStream(dataEntry) != null; + } + + + public OutputStream getOutputStream(DataEntry dataEntry) throws IOException + { + return getOutputStream(dataEntry, null); + } + + + public OutputStream getOutputStream(DataEntry dataEntry, + Finisher finisher) throws IOException + { + return dataEntryWriter.getOutputStream(dataEntry.getParent(), + finisher); + } + + + public void close() throws IOException + { + dataEntryWriter.close(); + dataEntryWriter = null; + } +} diff --git a/src/proguard/io/RenamedDataEntry.java b/src/proguard/io/RenamedDataEntry.java new file mode 100644 index 0000000..ae2d267 --- /dev/null +++ b/src/proguard/io/RenamedDataEntry.java @@ -0,0 +1,83 @@ +/* + * 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.io; + +import java.io.*; + +/** + * This DataEntry wraps another data entry, returning a different name instead + * of the wrapped data entry's name. + * + * @author Eric Lafortune + */ +public class RenamedDataEntry implements DataEntry +{ + private final DataEntry dataEntry; + private final String name; + + + public RenamedDataEntry(DataEntry dataEntry, + String name) + { + this.dataEntry = dataEntry; + this.name = name; + } + + + // Implementations for DataEntry. + + public String getName() + { + return name; + } + + + public boolean isDirectory() + { + return dataEntry.isDirectory(); + } + + + public InputStream getInputStream() throws IOException + { + return dataEntry.getInputStream(); + } + + + public void closeInputStream() throws IOException + { + dataEntry.closeInputStream(); + } + + + public DataEntry getParent() + { + return dataEntry.getParent(); + } + + + // Implementations for Object. + + public String toString() + { + return name + " == " + dataEntry; + } +} diff --git a/src/proguard/io/ZipDataEntry.java b/src/proguard/io/ZipDataEntry.java new file mode 100644 index 0000000..5779fd8 --- /dev/null +++ b/src/proguard/io/ZipDataEntry.java @@ -0,0 +1,98 @@ +/* + * 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.io; + +import proguard.classfile.ClassConstants; + +import java.io.*; +import java.util.zip.*; + +/** + * This <code>DataEntry</code> represents a ZIP entry. + * + * @author Eric Lafortune + */ +public class ZipDataEntry implements DataEntry +{ + private final DataEntry parent; + private final ZipEntry zipEntry; + private ZipInputStream zipInputStream; + + + public ZipDataEntry(DataEntry parent, + ZipEntry zipEntry, + ZipInputStream zipInputStream) + { + this.parent = parent; + this.zipEntry = zipEntry; + this.zipInputStream = zipInputStream; + } + + + // Implementations for DataEntry. + + public String getName() + { + // Get the right separators. + String name = zipEntry.getName() + .replace(File.separatorChar, ClassConstants.INTERNAL_PACKAGE_SEPARATOR); + + // Chop the trailing directory slash, if any. + int length = name.length(); + return length > 0 && + name.charAt(length-1) == ClassConstants.INTERNAL_PACKAGE_SEPARATOR ? + name.substring(0, length -1) : + name; + } + + + public boolean isDirectory() + { + return zipEntry.isDirectory(); + } + + + public InputStream getInputStream() throws IOException + { + return zipInputStream; + } + + + public void closeInputStream() throws IOException + { + zipInputStream.closeEntry(); + zipInputStream = null; + } + + + public DataEntry getParent() + { + return parent; + } + + + // Implementations for Object. + + public String toString() + { + return parent.toString() + ':' + getName(); + } +} diff --git a/src/proguard/io/package.html b/src/proguard/io/package.html new file mode 100644 index 0000000..4ad9f41 --- /dev/null +++ b/src/proguard/io/package.html @@ -0,0 +1,4 @@ +<body> +This package contains classes to read and write files, optionally wrapped in +jars, wars, ears, zips, directories,... +</body> |