DataEntryCopier.java revision 8a6199f0c36a778f22394364347a301b0b28e94b
1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2013 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 */
21package proguard.io;
22
23import proguard.util.ExtensionMatcher;
24
25import 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 */
34public 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
43    public DataEntryCopier(DataEntryWriter dataEntryWriter)
44    {
45        this.dataEntryWriter = dataEntryWriter;
46    }
47
48
49    // Implementations for DataEntryReader.
50
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     */
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     */
116    public static void main(String[] args)
117    {
118        try
119        {
120            String input  = args[0];
121            String output = args[1];
122
123            boolean outputIsJar = output.endsWith(".jar");
124            boolean outputIsWar = output.endsWith(".war");
125            boolean outputIsEar = output.endsWith(".ear");
126            boolean outputIsZip = output.endsWith(".zip");
127
128            DataEntryWriter writer = new DirectoryWriter(new File(output),
129                                                         outputIsJar ||
130                                                         outputIsWar ||
131                                                         outputIsEar ||
132                                                         outputIsZip);
133
134        if (!outputIsJar)
135        {
136            // Zip up any zips, if necessary.
137            DataEntryWriter zipWriter = new JarWriter(writer);
138            if (outputIsZip)
139            {
140                // Always zip.
141                writer = zipWriter;
142            }
143            else
144            {
145                // Only zip up zips.
146                writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
147                                                     new DataEntryNameFilter(
148                                                     new ExtensionMatcher(".zip"))),
149                                                     zipWriter,
150                                                     writer);
151            }
152
153            // Zip up any wars, if necessary.
154            DataEntryWriter warWriter = new JarWriter(writer);
155            if (outputIsWar)
156            {
157                // Always zip.
158                writer = warWriter;
159            }
160            else
161            {
162                // Only zip up wars.
163                writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
164                                                     new DataEntryNameFilter(
165                                                     new ExtensionMatcher(".war"))),
166                                                     warWriter,
167                                                     writer);
168            }
169        }
170
171        // Zip up any jars, if necessary.
172        DataEntryWriter jarWriter = new JarWriter(writer);
173        if (outputIsJar)
174        {
175            // Always zip.
176            writer = jarWriter;
177        }
178        else
179        {
180            // Only zip up jars.
181            writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
182                                                 new DataEntryNameFilter(
183                                                 new ExtensionMatcher(".jar"))),
184                                                 jarWriter,
185                                                 writer);
186        }
187
188
189            // Create the copying DataEntryReader.
190            DataEntryReader reader = new DataEntryCopier(writer);
191
192
193            boolean inputIsJar = input.endsWith(".jar");
194            boolean inputIsWar = input.endsWith(".war");
195            boolean inputIsZip = input.endsWith(".zip");
196
197            // Unzip any jars, if necessary.
198            DataEntryReader jarReader = new JarReader(reader);
199            if (inputIsJar)
200            {
201                // Always unzip.
202                reader = jarReader;
203            }
204            else
205            {
206                // Only unzip jar entries.
207                reader = new FilteredDataEntryReader(new DataEntryNameFilter(
208                                                     new ExtensionMatcher(".jar")),
209                                                     jarReader,
210                                                     reader);
211
212                // Unzip any wars, if necessary.
213                DataEntryReader warReader = new JarReader(reader);
214                if (inputIsWar)
215                {
216                    // Always unzip.
217                    reader = warReader;
218                }
219                else
220                {
221                    // Only unzip war entries.
222                    reader = new FilteredDataEntryReader(new DataEntryNameFilter(
223                                                         new ExtensionMatcher(".war")),
224                                                         warReader,
225                                                         reader);
226                }
227
228                // Unzip any zips, if necessary.
229                DataEntryReader zipReader = new JarReader(reader);
230                if (inputIsZip)
231                {
232                    // Always unzip.
233                    reader = zipReader;
234                }
235                else
236                {
237                    // Only unzip zip entries.
238                    reader = new FilteredDataEntryReader(new DataEntryNameFilter(
239                                                         new ExtensionMatcher(".zip")),
240                                                         zipReader,
241                                                         reader);
242                }
243            }
244
245            DirectoryPump directoryReader = new DirectoryPump(new File(input));
246
247            directoryReader.pumpDataEntries(reader);
248
249            writer.close();
250        }
251        catch (Exception ex)
252        {
253            ex.printStackTrace();
254        }
255    }
256}
257