001: /*
002: * ProGuard -- shrinking, optimization, obfuscation, and preverification
003: * of Java bytecode.
004: *
005: * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
006: *
007: * This program is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the Free
009: * Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This program is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
015: * more details.
016: *
017: * You should have received a copy of the GNU General Public License along
018: * with this program; if not, write to the Free Software Foundation, Inc.,
019: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: package proguard.io;
022:
023: import proguard.classfile.*;
024:
025: import java.io.*;
026:
027: /**
028: * This DataEntryReader writes the resource data entries that it reads to a
029: * given DataEntryWriter, updating their contents based on the renamed classes
030: * in the given ClassPool.
031: *
032: * @author Eric Lafortune
033: */
034: public class DataEntryRewriter implements DataEntryReader {
035: private final ClassPool classPool;
036: private final DataEntryWriter dataEntryWriter;
037:
038: /**
039: * Creates a new DataEntryRewriter.
040: */
041: public DataEntryRewriter(ClassPool classPool,
042: DataEntryWriter dataEntryWriter) {
043: this .classPool = classPool;
044: this .dataEntryWriter = dataEntryWriter;
045: }
046:
047: // Implementations for DataEntryReader.
048:
049: public void read(DataEntry dataEntry) throws IOException {
050: try {
051: // Get the output entry corresponding to this input entry.
052: OutputStream outputStream = dataEntryWriter
053: .getOutputStream(dataEntry);
054: if (outputStream != null) {
055: InputStream inputStream = dataEntry.getInputStream();
056:
057: // Copy the data from the input entry to the output entry.
058: copyData(inputStream, outputStream);
059:
060: // Close the data entries.
061: dataEntry.closeInputStream();
062: }
063: } catch (IOException ex) {
064: System.err.println("Warning: can't write resource ["
065: + dataEntry.getName() + "] (" + ex.getMessage()
066: + ")");
067: }
068: }
069:
070: // Small utility methods.
071:
072: /**
073: * Copies all data that it can read from the given input stream to the
074: * given output stream.
075: */
076: private void copyData(InputStream inputStream,
077: OutputStream outputStream) throws IOException {
078: Reader reader = new BufferedReader(new InputStreamReader(
079: inputStream));
080: Writer writer = new BufferedWriter(new OutputStreamWriter(
081: outputStream));
082:
083: StringBuffer word = new StringBuffer();
084:
085: while (true) {
086: int i = reader.read();
087: if (i < 0) {
088: break;
089: }
090:
091: // Is the character part of a word?
092: char c = (char) i;
093: if (Character.isJavaIdentifierPart(c) || c == '.'
094: || c == '-') {
095: // Collect the characters in this word.
096: word.append(c);
097: } else {
098: // Write out the updated word, if any.
099: writeUpdatedWord(writer, word.toString());
100: word.setLength(0);
101:
102: // Write out the character that terminated it.
103: writer.write(c);
104: }
105: }
106:
107: // Write out the final word.
108: writeUpdatedWord(writer, word.toString());
109:
110: writer.flush();
111: outputStream.flush();
112: }
113:
114: /**
115: * Writes the given word to the given writer, after having adapted it,
116: * based on the renamed class names.
117: */
118: private void writeUpdatedWord(Writer writer, String word)
119: throws IOException {
120: if (word.length() > 0) {
121: String newWord = word;
122:
123: boolean containsDots = word.indexOf('.') >= 0;
124:
125: // Replace dots by forward slashes.
126: String className = containsDots ? word.replace('.',
127: ClassConstants.INTERNAL_PACKAGE_SEPARATOR) : word;
128:
129: // Find the class corrsponding to the word.
130: Clazz clazz = classPool.getClass(className);
131: if (clazz != null) {
132: // Update the word if necessary.
133: String newClassName = clazz.getName();
134: if (!className.equals(newClassName)) {
135: // Replace forward slashes by dots.
136: newWord = containsDots ? newClassName.replace(
137: ClassConstants.INTERNAL_PACKAGE_SEPARATOR,
138: '.') : newClassName;
139: }
140: }
141:
142: writer.write(newWord);
143: }
144: }
145: }
|