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