1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2009 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                    // Copy the data from the input entry to the output entry.
68                    copyData(inputStream, outputStream);
69
70                    // Close the data entries.
71                    dataEntry.closeInputStream();
72                }
73            }
74        }
75        catch (IOException ex)
76        {
77            System.err.println("Warning: can't write resource [" + dataEntry.getName() + "] (" + ex.getMessage() + ")");
78        }
79    }
80
81
82    /**
83     * Copies all data that it can read from the given input stream to the
84     * given output stream.
85     */
86    protected void copyData(InputStream  inputStream,
87                            OutputStream outputStream)
88    throws IOException
89    {
90        while (true)
91        {
92            int count = inputStream.read(buffer);
93            if (count < 0)
94            {
95                break;
96            }
97            outputStream.write(buffer, 0, count);
98        }
99
100        outputStream.flush();
101    }
102
103
104    /**
105     * A main method for testing file/jar/war/directory copying.
106     */
107    public static void main(String[] args)
108    {
109        try
110        {
111            String input  = args[0];
112            String output = args[1];
113
114            boolean outputIsJar = output.endsWith(".jar");
115            boolean outputIsWar = output.endsWith(".war");
116            boolean outputIsEar = output.endsWith(".ear");
117            boolean outputIsZip = output.endsWith(".zip");
118
119            DataEntryWriter writer = new DirectoryWriter(new File(output),
120                                                         outputIsJar ||
121                                                         outputIsWar ||
122                                                         outputIsEar ||
123                                                         outputIsZip);
124
125        if (!outputIsJar)
126        {
127            // Zip up any zips, if necessary.
128            DataEntryWriter zipWriter = new JarWriter(writer);
129            if (outputIsZip)
130            {
131                // Always zip.
132                writer = zipWriter;
133            }
134            else
135            {
136                // Only zip up zips.
137                writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
138                                                     new DataEntryNameFilter(
139                                                     new ExtensionMatcher(".zip"))),
140                                                     zipWriter,
141                                                     writer);
142            }
143
144            // Zip up any wars, if necessary.
145            DataEntryWriter warWriter = new JarWriter(writer);
146            if (outputIsWar)
147            {
148                // Always zip.
149                writer = warWriter;
150            }
151            else
152            {
153                // Only zip up wars.
154                writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
155                                                     new DataEntryNameFilter(
156                                                     new ExtensionMatcher(".war"))),
157                                                     warWriter,
158                                                     writer);
159            }
160        }
161
162        // Zip up any jars, if necessary.
163        DataEntryWriter jarWriter = new JarWriter(writer);
164        if (outputIsJar)
165        {
166            // Always zip.
167            writer = jarWriter;
168        }
169        else
170        {
171            // Only zip up jars.
172            writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
173                                                 new DataEntryNameFilter(
174                                                 new ExtensionMatcher(".jar"))),
175                                                 jarWriter,
176                                                 writer);
177        }
178
179
180            // Create the copying DataEntryReader.
181            DataEntryReader reader = new DataEntryCopier(writer);
182
183
184            boolean inputIsJar = input.endsWith(".jar");
185            boolean inputIsWar = input.endsWith(".war");
186            boolean inputIsZip = input.endsWith(".zip");
187
188            // Unzip any jars, if necessary.
189            DataEntryReader jarReader = new JarReader(reader);
190            if (inputIsJar)
191            {
192                // Always unzip.
193                reader = jarReader;
194            }
195            else
196            {
197                // Only unzip jar entries.
198                reader = new FilteredDataEntryReader(new DataEntryNameFilter(
199                                                     new ExtensionMatcher(".jar")),
200                                                     jarReader,
201                                                     reader);
202
203                // Unzip any wars, if necessary.
204                DataEntryReader warReader = new JarReader(reader);
205                if (inputIsWar)
206                {
207                    // Always unzip.
208                    reader = warReader;
209                }
210                else
211                {
212                    // Only unzip war entries.
213                    reader = new FilteredDataEntryReader(new DataEntryNameFilter(
214                                                         new ExtensionMatcher(".war")),
215                                                         warReader,
216                                                         reader);
217                }
218
219                // Unzip any zips, if necessary.
220                DataEntryReader zipReader = new JarReader(reader);
221                if (inputIsZip)
222                {
223                    // Always unzip.
224                    reader = zipReader;
225                }
226                else
227                {
228                    // Only unzip zip entries.
229                    reader = new FilteredDataEntryReader(new DataEntryNameFilter(
230                                                         new ExtensionMatcher(".zip")),
231                                                         zipReader,
232                                                         reader);
233                }
234            }
235
236            DirectoryPump directoryReader = new DirectoryPump(new File(input));
237
238            directoryReader.pumpDataEntries(reader);
239
240            writer.close();
241        }
242        catch (Exception ex)
243        {
244            ex.printStackTrace();
245        }
246    }
247}
248