1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 package proguard.io;
22 
23 import proguard.classfile.*;
24 
25 import java.io.*;
26 
27 /**
28  * This DataEntryReader writes the resource data entries that it reads to a
29  * given DataEntryWriter, updating their contents based on the renamed classes
30  * in the given ClassPool.
31  *
32  * @author Eric Lafortune
33  */
34 public class DataEntryRewriter extends DataEntryCopier
35 {
36     private final ClassPool classPool;
37 
38 
39     /**
40      * Creates a new DataEntryRewriter.
41      */
DataEntryRewriter(ClassPool classPool, DataEntryWriter dataEntryWriter)42     public DataEntryRewriter(ClassPool       classPool,
43                              DataEntryWriter dataEntryWriter)
44     {
45         super(dataEntryWriter);
46 
47         this.classPool = classPool;
48     }
49 
50 
51     // Implementations for DataEntryCopier.
52 
copyData(InputStream inputStream, OutputStream outputStream)53     protected void copyData(InputStream  inputStream,
54                             OutputStream outputStream)
55     throws IOException
56     {
57         Reader reader = new BufferedReader(new InputStreamReader(inputStream));
58         Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream));
59 
60         copyData(reader, writer);
61 
62         writer.flush();
63         outputStream.flush();
64     }
65 
66 
67     /**
68      * Copies all data that it can read from the given reader to the given
69      * writer.
70      */
copyData(Reader reader, Writer writer)71     protected void copyData(Reader reader,
72                             Writer writer)
73     throws IOException
74     {
75         StringBuffer word = new StringBuffer();
76 
77         while (true)
78         {
79             int i = reader.read();
80             if (i < 0)
81             {
82                 break;
83             }
84 
85             // Is the character part of a word?
86             char c = (char)i;
87             if (Character.isJavaIdentifierPart(c) ||
88                 c == '.' ||
89                 c == '-')
90             {
91                 // Collect the characters in this word.
92                 word.append(c);
93             }
94             else
95             {
96                 // Write out the updated word, if any.
97                 writeUpdatedWord(writer, word.toString());
98                 word.setLength(0);
99 
100                 // Write out the character that terminated it.
101                 writer.write(c);
102             }
103         }
104 
105         // Write out the final word.
106         writeUpdatedWord(writer, word.toString());
107     }
108 
109 
110     // Small utility methods.
111 
112     /**
113      * Writes the given word to the given writer, after having adapted it,
114      * based on the renamed class names.
115      */
writeUpdatedWord(Writer writer, String word)116     private void writeUpdatedWord(Writer writer, String word)
117     throws IOException
118     {
119         if (word.length() > 0)
120         {
121             String newWord = word;
122 
123             boolean containsDots = word.indexOf('.') >= 0;
124 
125             // Replace dots by forward slashes.
126             String className = containsDots ?
127                 word.replace('.', ClassConstants.PACKAGE_SEPARATOR) :
128                 word;
129 
130             // Find the class corrsponding to the word.
131             Clazz clazz = classPool.getClass(className);
132             if (clazz != null)
133             {
134                 // Update the word if necessary.
135                 String newClassName = clazz.getName();
136                 if (!className.equals(newClassName))
137                 {
138                     // Replace forward slashes by dots.
139                     newWord = containsDots ?
140                         newClassName.replace(ClassConstants.PACKAGE_SEPARATOR, '.') :
141                         newClassName;
142                 }
143             }
144 
145             writer.write(newWord);
146         }
147     }
148 }
149