Home | History | Annotate | Download | only in io
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 Eric Lafortune (eric (at) 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 
     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 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