• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.util.ExtensionMatcher;
24 
25 import java.io.*;
26 
27 
28 /**
29  * This DataEntryReader writes the ZIP entries and files that it reads to a
30  * given DataEntryWriter.
31  *
32  * @author Eric Lafortune
33  */
34 public class DataEntryCopier implements DataEntryReader
35 {
36     private static final int BUFFER_SIZE = 1024;
37 
38     private final DataEntryWriter dataEntryWriter;
39     private final byte[]          buffer = new byte[BUFFER_SIZE];
40 
41 
42 
DataEntryCopier(DataEntryWriter dataEntryWriter)43     public DataEntryCopier(DataEntryWriter dataEntryWriter)
44     {
45         this.dataEntryWriter = dataEntryWriter;
46     }
47 
48 
49     // Implementations for DataEntryReader.
50 
read(DataEntry dataEntry)51     public void read(DataEntry dataEntry) throws IOException
52     {
53         try
54         {
55             if (dataEntry.isDirectory())
56             {
57                 dataEntryWriter.createDirectory(dataEntry);
58             }
59             else
60             {
61                 // Get the output entry corresponding to this input entry.
62                 OutputStream outputStream = dataEntryWriter.getOutputStream(dataEntry);
63                 if (outputStream != null)
64                 {
65                     InputStream inputStream = dataEntry.getInputStream();
66 
67                     try
68                     {
69                         // Copy the data from the input entry to the output entry.
70                         copyData(inputStream, outputStream);
71                     }
72                     finally
73                     {
74                         // Close the data entries.
75                         dataEntry.closeInputStream();
76                     }
77                 }
78             }
79         }
80         catch (IOException ex)
81         {
82             System.err.println("Warning: can't write resource [" + dataEntry.getName() + "] (" + ex.getMessage() + ")");
83         }
84         catch (Exception ex)
85         {
86             throw (IOException)new IOException("Can't write resource ["+dataEntry.getName()+"] ("+ex.getMessage()+")").initCause(ex);
87         }
88     }
89 
90 
91     /**
92      * Copies all data that it can read from the given input stream to the
93      * given output stream.
94      */
copyData(InputStream inputStream, OutputStream outputStream)95     protected void copyData(InputStream  inputStream,
96                             OutputStream outputStream)
97     throws IOException
98     {
99         while (true)
100         {
101             int count = inputStream.read(buffer);
102             if (count < 0)
103             {
104                 break;
105             }
106             outputStream.write(buffer, 0, count);
107         }
108 
109         outputStream.flush();
110     }
111 
112 
113     /**
114      * A main method for testing file/jar/war/directory copying.
115      */
main(String[] args)116     public static void main(String[] args)
117     {
118         try
119         {
120             String input  = args[0];
121             String output = args[1];
122 
123             boolean outputIsApk = output.endsWith(".apk") ||
124                                   output.endsWith(".ap_");
125             boolean outputIsJar = output.endsWith(".jar");
126             boolean outputIsAar = output.endsWith(".aar");
127             boolean outputIsWar = output.endsWith(".war");
128             boolean outputIsEar = output.endsWith(".ear");
129             boolean outputIsZip = output.endsWith(".zip");
130 
131             DataEntryWriter writer = new DirectoryWriter(new File(output),
132                                                          outputIsApk ||
133                                                          outputIsJar ||
134                                                          outputIsAar ||
135                                                          outputIsWar ||
136                                                          outputIsEar ||
137                                                          outputIsZip);
138 
139             // Zip up any zips, if necessary.
140             DataEntryWriter zipWriter = new JarWriter(writer);
141             if (outputIsZip)
142             {
143                 // Always zip.
144                 writer = zipWriter;
145             }
146             else
147             {
148                 // Only zip up zips.
149                 writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
150                                                      new DataEntryNameFilter(
151                                                      new ExtensionMatcher(".zip"))),
152                                                      zipWriter,
153                                                      writer);
154             }
155 
156             // Zip up any ears, if necessary.
157             DataEntryWriter earWriter = new JarWriter(writer);
158             if (outputIsEar)
159             {
160                 // Always zip.
161                 writer = earWriter;
162             }
163             else
164             {
165                 // Only zip up ears.
166                 writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
167                                                      new DataEntryNameFilter(
168                                                      new ExtensionMatcher(".ear"))),
169                                                      earWriter,
170                                                      writer);
171             }
172 
173             // Zip up any wars, if necessary.
174             DataEntryWriter warWriter = new JarWriter(writer);
175             if (outputIsWar)
176             {
177                 // Always zip.
178                 writer = warWriter;
179             }
180             else
181             {
182                 // Only zip up wars.
183                 writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
184                                                      new DataEntryNameFilter(
185                                                      new ExtensionMatcher(".war"))),
186                                                      warWriter,
187                                                      writer);
188             }
189 
190             // Zip up any aars, if necessary.
191             DataEntryWriter aarWriter = new JarWriter(writer);
192             if (outputIsAar)
193             {
194                 // Always zip.
195                 writer = aarWriter;
196             }
197             else
198             {
199                 // Only zip up aars.
200                 writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
201                                                      new DataEntryNameFilter(
202                                                      new ExtensionMatcher(".aar"))),
203                                                      aarWriter,
204                                                      writer);
205             }
206 
207             // Zip up any jars, if necessary.
208             DataEntryWriter jarWriter = new JarWriter(writer);
209             if (outputIsJar)
210             {
211                 // Always zip.
212                 writer = jarWriter;
213             }
214             else
215             {
216                 // Only zip up jars.
217                 writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
218                                                      new DataEntryNameFilter(
219                                                      new ExtensionMatcher(".jar"))),
220                                                      jarWriter,
221                                                      writer);
222             }
223 
224             // Zip up any apks, if necessary.
225             DataEntryWriter apkWriter = new JarWriter(writer);
226             if (outputIsApk)
227             {
228                 // Always zip.
229                 writer = apkWriter;
230             }
231             else
232             {
233                 // Only zip up apks.
234                 writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
235                                                      new DataEntryNameFilter(
236                                                      new ExtensionMatcher(".apk"))),
237                                                      apkWriter,
238                                                      writer);
239             }
240 
241 
242             // Create the copying DataEntryReader.
243             DataEntryReader reader = new DataEntryCopier(writer);
244 
245             boolean inputIsApk = input.endsWith(".apk") ||
246                                  input.endsWith(".ap_");
247             boolean inputIsJar = input.endsWith(".jar");
248             boolean inputIsAar = input.endsWith(".aar");
249             boolean inputIsWar = input.endsWith(".war");
250             boolean inputIsEar = input.endsWith(".ear");
251             boolean inputIsZip = input.endsWith(".zip");
252 
253             // Unzip any apks, if necessary.
254             DataEntryReader apkReader = new JarReader(reader);
255             if (inputIsApk)
256             {
257                 // Always unzip.
258                 reader = apkReader;
259             }
260             else
261             {
262                 // Only unzip apk entries.
263                 reader = new FilteredDataEntryReader(new DataEntryNameFilter(
264                                                      new ExtensionMatcher(".apk")),
265                                                      apkReader,
266                                                      reader);
267 
268                 // Unzip any jars, if necessary.
269                 DataEntryReader jarReader = new JarReader(reader);
270                 if (inputIsJar)
271                 {
272                     // Always unzip.
273                     reader = jarReader;
274                 }
275                 else
276                 {
277                     // Only unzip jar entries.
278                     reader = new FilteredDataEntryReader(new DataEntryNameFilter(
279                                                          new ExtensionMatcher(".jar")),
280                                                          jarReader,
281                                                          reader);
282 
283                     // Unzip any aars, if necessary.
284                     DataEntryReader aarReader = new JarReader(reader);
285                     if (inputIsAar)
286                     {
287                         // Always unzip.
288                         reader = aarReader;
289                     }
290                     else
291                     {
292                         // Only unzip aar entries.
293                         reader = new FilteredDataEntryReader(new DataEntryNameFilter(
294                                                              new ExtensionMatcher(".aar")),
295                                                              aarReader,
296                                                              reader);
297 
298                         // Unzip any wars, if necessary.
299                         DataEntryReader warReader = new JarReader(reader);
300                         if (inputIsWar)
301                         {
302                             // Always unzip.
303                             reader = warReader;
304                         }
305                         else
306                         {
307                             // Only unzip war entries.
308                             reader = new FilteredDataEntryReader(new DataEntryNameFilter(
309                                                                  new ExtensionMatcher(".war")),
310                                                                  warReader,
311                                                                  reader);
312 
313                             // Unzip any ears, if necessary.
314                             DataEntryReader earReader = new JarReader(reader);
315                             if (inputIsEar)
316                             {
317                                 // Always unzip.
318                                 reader = earReader;
319                             }
320                             else
321                             {
322                                 // Only unzip ear entries.
323                                 reader = new FilteredDataEntryReader(new DataEntryNameFilter(
324                                                                      new ExtensionMatcher(".ear")),
325                                                                      earReader,
326                                                                      reader);
327 
328                                 // Unzip any zips, if necessary.
329                                 DataEntryReader zipReader = new JarReader(reader);
330                                 if (inputIsZip)
331                                 {
332                                     // Always unzip.
333                                     reader = zipReader;
334                                 }
335                                 else
336                                 {
337                                     // Only unzip zip entries.
338                                     reader = new FilteredDataEntryReader(new DataEntryNameFilter(
339                                                                          new ExtensionMatcher(".zip")),
340                                                                          zipReader,
341                                                                          reader);
342                                 }
343                             }
344                         }
345                     }
346                 }
347             }
348 
349             DirectoryPump directoryReader = new DirectoryPump(new File(input));
350 
351             directoryReader.pumpDataEntries(reader);
352 
353             writer.close();
354         }
355         catch (Exception ex)
356         {
357             ex.printStackTrace();
358         }
359     }
360 }
361