001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 * 020 * $$Id$$ 021 */ 022 023package org.nuxeo.common.utils; 024 025import java.io.BufferedInputStream; 026import java.io.BufferedOutputStream; 027import java.io.File; 028import java.io.FileInputStream; 029import java.io.FileOutputStream; 030import java.io.IOException; 031import java.io.InputStream; 032import java.io.OutputStream; 033import java.net.URL; 034import java.util.ArrayList; 035import java.util.Enumeration; 036import java.util.List; 037import java.util.zip.ZipEntry; 038import java.util.zip.ZipFile; 039import java.util.zip.ZipInputStream; 040import java.util.zip.ZipOutputStream; 041 042/** 043 * @author bstefanescu 044 */ 045public final class ZipUtils { 046 047 // This is an utility class 048 private ZipUtils() { 049 } 050 051 // _____________________________ ZIP ________________________________ 052 053 public static void _putDirectoryEntry(String entryName, ZipOutputStream out) throws IOException { 054 ZipEntry zentry = new ZipEntry(entryName + '/'); 055 out.putNextEntry(zentry); 056 out.closeEntry(); 057 } 058 059 public static void _putFileEntry(File file, String entryName, ZipOutputStream out) throws IOException { 060 FileInputStream in = null; 061 try { 062 in = new FileInputStream(file); 063 _zip(entryName, in, out); 064 } finally { 065 if (in != null) { 066 in.close(); 067 } 068 } 069 } 070 071 public static void _zip(String entryName, InputStream in, ZipOutputStream out) throws IOException { 072 ZipEntry zentry = new ZipEntry(entryName); 073 out.putNextEntry(zentry); 074 // Transfer bytes from the input stream to the ZIP file 075 FileUtils.copy(in, out); 076 out.closeEntry(); 077 } 078 079 public static void _zip(String entryName, File file, ZipOutputStream out) throws IOException { 080 // System.out.println("Compressing "+entryName); 081 if (file.isDirectory()) { 082 entryName += '/'; 083 ZipEntry zentry = new ZipEntry(entryName); 084 out.putNextEntry(zentry); 085 out.closeEntry(); 086 File[] files = file.listFiles(); 087 for (int i = 0, len = files.length; i < len; i++) { 088 _zip(entryName + files[i].getName(), files[i], out); 089 } 090 } else { 091 InputStream in = null; 092 try { 093 in = new BufferedInputStream(new FileInputStream(file)); 094 _zip(entryName, in, out); 095 } finally { 096 if (in != null) { 097 in.close(); 098 } 099 } 100 } 101 } 102 103 public static void _zip(File[] files, ZipOutputStream out, String prefix) throws IOException { 104 if (prefix != null) { 105 int len = prefix.length(); 106 if (len == 0) { 107 prefix = null; 108 } else if (prefix.charAt(len - 1) != '/') { 109 prefix += '/'; 110 } 111 } 112 for (int i = 0, len = files.length; i < len; i++) { 113 String name = prefix != null ? prefix + files[i].getName() : files[i].getName(); 114 _zip(name, files[i], out); 115 } 116 } 117 118 public static void zip(File file, OutputStream out, String prefix) throws IOException { 119 if (prefix != null) { 120 int len = prefix.length(); 121 if (len == 0) { 122 prefix = null; 123 } else if (prefix.charAt(len - 1) != '/') { 124 prefix += '/'; 125 } 126 } 127 String name = prefix != null ? prefix + file.getName() : file.getName(); 128 ZipOutputStream zout = null; 129 try { 130 zout = new ZipOutputStream(out); 131 _zip(name, file, zout); 132 } finally { 133 if (zout != null) { 134 zout.finish(); 135 } 136 } 137 } 138 139 public static void zip(File[] files, OutputStream out, String prefix) throws IOException { 140 ZipOutputStream zout = null; 141 try { 142 zout = new ZipOutputStream(out); 143 _zip(files, zout, prefix); 144 } finally { 145 if (zout != null) { 146 zout.finish(); 147 } 148 } 149 } 150 151 public static void zip(File file, File zip) throws IOException { 152 OutputStream out = null; 153 try { 154 out = new BufferedOutputStream(new FileOutputStream(zip)); 155 zip(file, out, null); 156 } finally { 157 if (out != null) { 158 out.close(); 159 } 160 } 161 } 162 163 public static void zip(File[] files, File zip) throws IOException { 164 OutputStream out = null; 165 try { 166 out = new BufferedOutputStream(new FileOutputStream(zip)); 167 zip(files, out, null); 168 } finally { 169 if (out != null) { 170 out.close(); 171 } 172 } 173 } 174 175 public static void zip(File file, File zip, String prefix) throws IOException { 176 OutputStream out = null; 177 try { 178 out = new BufferedOutputStream(new FileOutputStream(zip)); 179 zip(file, out, prefix); 180 } finally { 181 if (out != null) { 182 out.close(); 183 } 184 } 185 } 186 187 public static void zip(File[] files, File zip, String prefix) throws IOException { 188 OutputStream out = null; 189 try { 190 out = new BufferedOutputStream(new FileOutputStream(zip)); 191 zip(files, out, prefix); 192 } finally { 193 if (out != null) { 194 out.close(); 195 } 196 } 197 } 198 199 public static void zipFilesUsingPrefix(String prefix, File[] files, OutputStream out) throws IOException { 200 ZipOutputStream zout = null; 201 try { 202 zout = new ZipOutputStream(out); 203 if (prefix != null && prefix.length() > 0) { 204 int p = prefix.indexOf('/'); 205 while (p > -1) { 206 _putDirectoryEntry(prefix.substring(0, p), zout); 207 p = prefix.indexOf(p + 1, '/'); 208 } 209 _putDirectoryEntry(prefix, zout); 210 prefix += '/'; 211 } else { 212 prefix = ""; 213 } 214 // prefix = prefix + '/'; 215 for (File file : files) { 216 _putFileEntry(file, prefix + file.getName(), zout); 217 } 218 } finally { 219 if (zout != null) { 220 zout.finish(); 221 } 222 } 223 } 224 225 // _____________________________ UNZIP ________________________________ 226 227 public static void unzip(String prefix, InputStream zipStream, File dir) throws IOException { 228 ZipInputStream in = null; 229 try { 230 in = new ZipInputStream(new BufferedInputStream(zipStream)); 231 unzip(prefix, in, dir); 232 } finally { 233 if (in != null) { 234 in.close(); 235 } 236 } 237 } 238 239 public static void unzip(InputStream zipStream, File dir) throws IOException { 240 ZipInputStream in = null; 241 try { 242 in = new ZipInputStream(new BufferedInputStream(zipStream)); 243 unzip(in, dir); 244 } finally { 245 if (in != null) { 246 in.close(); 247 } 248 } 249 } 250 251 public static void unzip(String prefix, URL zip, File dir) throws IOException { 252 ZipInputStream in = null; 253 try { 254 in = new ZipInputStream(new BufferedInputStream(zip.openStream())); 255 unzip(prefix, in, dir); 256 } finally { 257 if (in != null) { 258 in.close(); 259 } 260 } 261 } 262 263 public static void unzip(URL zip, File dir) throws IOException { 264 ZipInputStream in = null; 265 try { 266 in = new ZipInputStream(new BufferedInputStream(zip.openStream())); 267 unzip(in, dir); 268 } finally { 269 if (in != null) { 270 in.close(); 271 } 272 } 273 } 274 275 public static void unzip(String prefix, File zip, File dir) throws IOException { 276 ZipInputStream in = null; 277 try { 278 in = new ZipInputStream(new BufferedInputStream(new FileInputStream(zip))); 279 unzip(prefix, in, dir); 280 } finally { 281 if (in != null) { 282 in.close(); 283 } 284 } 285 } 286 287 public static void unzip(File zip, File dir) throws IOException { 288 ZipInputStream in = null; 289 try { 290 in = new ZipInputStream(new BufferedInputStream(new FileInputStream(zip))); 291 unzip(in, dir); 292 } finally { 293 if (in != null) { 294 in.close(); 295 } 296 } 297 } 298 299 public static void unzip(String prefix, ZipInputStream in, File dir) throws IOException { 300 dir.mkdirs(); 301 ZipEntry entry; 302 while ((entry = in.getNextEntry()) != null) { 303 String entryName = entry.getName(); 304 if (!entryName.startsWith(prefix) || entryName.contains("..")) { 305 continue; 306 } 307 308 File file = new File(dir, entryName.substring(prefix.length())); 309 if (entry.isDirectory()) { 310 file.mkdirs(); 311 } else { 312 file.getParentFile().mkdirs(); 313 FileUtils.copyToFile(in, file); 314 } 315 } 316 } 317 318 public static void unzip(ZipInputStream in, File dir) throws IOException { 319 dir.mkdirs(); 320 ZipEntry entry; 321 while ((entry = in.getNextEntry()) != null) { 322 if (entry.getName().contains("..")) { 323 continue; 324 } 325 326 File file = new File(dir, entry.getName()); 327 if (entry.isDirectory()) { 328 file.mkdirs(); 329 } else { 330 file.getParentFile().mkdirs(); 331 FileUtils.copyToFile(in, file); 332 } 333 } 334 } 335 336 public static void unzipIgnoreDirs(ZipInputStream in, File dir) throws IOException { 337 dir.mkdirs(); 338 ZipEntry entry = in.getNextEntry(); 339 while (entry != null) { 340 String entryName = entry.getName(); 341 if (entry.isDirectory()) { 342 } else { 343 int p = entryName.lastIndexOf('/'); 344 if (p > -1) { 345 entryName = entryName.substring(p + 1); 346 } 347 File file = new File(dir, entryName); 348 FileUtils.copyToFile(in, file); 349 } 350 entry = in.getNextEntry(); 351 } 352 } 353 354 public static void unzipIgnoreDirs(InputStream zipStream, File dir) throws IOException { 355 ZipInputStream in = null; 356 try { 357 in = new ZipInputStream(new BufferedInputStream(zipStream)); 358 unzipIgnoreDirs(in, dir); 359 } finally { 360 if (in != null) { 361 in.close(); 362 } 363 } 364 } 365 366 public static void unzip(File zip, File dir, PathFilter filter) throws IOException { 367 ZipInputStream in = null; 368 try { 369 in = new ZipInputStream(new BufferedInputStream(new FileInputStream(zip))); 370 unzip(in, dir, filter); 371 } finally { 372 if (in != null) { 373 in.close(); 374 } 375 } 376 } 377 378 public static void unzip(ZipInputStream in, File dir, PathFilter filter) throws IOException { 379 if (filter == null) { 380 unzip(in, dir); 381 return; 382 } 383 ZipEntry entry; 384 while ((entry = in.getNextEntry()) != null) { 385 String entryName = entry.getName(); 386 if (entryName.contains("..")) { 387 continue; 388 } 389 390 if (filter.accept(new Path(entryName))) { 391 // System.out.println("Extracting "+entryName); 392 File file = new File(dir, entryName); 393 if (entry.isDirectory()) { 394 file.mkdirs(); 395 } else { 396 file.getParentFile().mkdirs(); 397 FileUtils.copyToFile(in, file); 398 } 399 } 400 } 401 } 402 403 public static void unzip(String prefix, File zip, File dir, PathFilter filter) throws IOException { 404 ZipInputStream in = null; 405 try { 406 in = new ZipInputStream(new BufferedInputStream(new FileInputStream(zip))); 407 unzip(prefix, in, dir, filter); 408 } finally { 409 if (in != null) { 410 in.close(); 411 } 412 } 413 } 414 415 public static void unzip(String prefix, ZipInputStream in, File dir, PathFilter filter) throws IOException { 416 if (filter == null) { 417 unzip(prefix, in, dir); 418 return; 419 } 420 dir.mkdirs(); 421 422 ZipEntry entry; 423 while ((entry = in.getNextEntry()) != null) { 424 String entryName = entry.getName(); 425 if (entryName.contains("..")) { 426 continue; 427 } 428 429 if (filter.accept(new Path(entryName))) { 430 if (!entry.getName().startsWith(prefix)) { 431 continue; 432 } 433 File file = new File(dir, entry.getName().substring(prefix.length())); 434 if (entry.isDirectory()) { 435 file.mkdirs(); 436 } else { 437 file.getParentFile().mkdirs(); 438 FileUtils.copyToFile(in, file); 439 } 440 } 441 } 442 } 443 444 // ________________ Entries ________________ 445 /** 446 * Unzip directly the entry. The returned InputStream has to be closed. 447 * 448 * @return the input stream of the desired entry - has to be closed by the caller, or null if not found 449 * @param file the source file 450 * @param entryName the entry name that has to be extracted 451 */ 452 public static InputStream getEntryContentAsStream(File file, String entryName) throws IOException { 453 InputStream result = null; 454 ZipFile zip = new ZipFile(file); 455 ZipEntry entry = zip.getEntry(entryName); 456 if (entry != null) { 457 result = zip.getInputStream(entry); 458 } 459 return result; 460 } 461 462 /** 463 * Unzip directly the entry. 464 * 465 * @return the String content of the entry with name entryName 466 * @param file the source file 467 * @param entryName the entry name that has to be extracted 468 */ 469 public static String getEntryContentAsString(File file, String entryName) throws IOException { 470 InputStream resultStream = getEntryContentAsStream(file, entryName); 471 // resultStream has been closed by FileUtils call 472 return FileUtils.read(resultStream); 473 } 474 475 /** 476 * Unzips directly the entry. 477 * 478 * @return The byte array content of the entry with name entryName 479 * @param file the source file 480 * @param entryName the entry name that has to be extracted 481 */ 482 public static byte[] getEntryContentAsBytes(File file, String entryName) throws IOException { 483 InputStream resultStream = getEntryContentAsStream(file, entryName); 484 // resultStream has been closed by FileUtils call 485 return FileUtils.readBytes(resultStream); 486 } 487 488 /** 489 * Lists the entries on the zip file. 490 * 491 * @param file The zip file 492 * @return The list of entries 493 */ 494 public static List<String> getEntryNames(File file) throws IOException { 495 List<String> result = new ArrayList<String>(); 496 ZipFile zip = new ZipFile(file); 497 try { 498 Enumeration<? extends ZipEntry> entries = zip.entries(); 499 while (entries.hasMoreElements()) { 500 ZipEntry entry = entries.nextElement(); 501 result.add(entry.getName()); 502 } 503 } finally { 504 zip.close(); 505 } 506 return result; 507 } 508 509 /** 510 * Checks if a zip file contains a specified entry name. 511 * 512 * @param file the zip file 513 * @param entryName The content to be checked 514 * @return True if the file contains entryName. False otherwise 515 */ 516 public static boolean hasEntry(File file, String entryName) throws IOException { 517 List<String> elements = getEntryNames(file); 518 return elements.contains(entryName); 519 } 520 521 public static InputStream getEntryContentAsStream(InputStream stream, String entryName) throws IOException { 522 ZipInputStream zip = new ZipInputStream(stream); 523 ZipEntry entry = zip.getNextEntry(); 524 while (entry != null) { 525 if (entry.getName().equals(entryName)) { 526 return zip; 527 } 528 entry = zip.getNextEntry(); 529 } 530 return null; 531 } 532 533 public static String getEntryContentAsString(InputStream stream, String searchedEntryName) throws IOException { 534 InputStream resultStream = getEntryContentAsStream(stream, searchedEntryName); 535 // resultStream has been closed by FileUtils call 536 return FileUtils.read(resultStream); 537 } 538 539 public static byte[] getEntryContentAsBytes(InputStream stream, String searchedEntryName) throws IOException { 540 InputStream resultStream = getEntryContentAsStream(stream, searchedEntryName); 541 // resultStream has been closed by FileUtils call 542 return FileUtils.readBytes(resultStream); 543 } 544 545 public static List<String> getEntryNames(InputStream stream) throws IOException { 546 547 List<String> result = new ArrayList<String>(); 548 ZipInputStream zip = new ZipInputStream(stream); 549 try { 550 while (zip.available() == 1) { 551 ZipEntry entry = zip.getNextEntry(); 552 if (entry != null) { 553 result.add(entry.getName()); 554 } 555 } 556 } finally { 557 zip.close(); 558 } 559 return result; 560 } 561 562 public static boolean hasEntry(InputStream stream, String entryName) throws IOException { 563 List<String> elements = getEntryNames(stream); 564 return elements.contains(entryName); 565 } 566 567 public static InputStream getEntryContentAsStream(URL url, String entryName) throws IOException { 568 return getEntryContentAsStream(url.openStream(), entryName); 569 } 570 571 public static String getEntryContentAsString(URL url, String entryName) throws IOException { 572 InputStream resultStream = getEntryContentAsStream(url, entryName); 573 // resultStream has been closed by FileUtils call 574 return FileUtils.read(resultStream); 575 } 576 577 public static byte[] getEntryContentAsBytes(URL url, String entryName) throws IOException { 578 InputStream resultStream = getEntryContentAsStream(url, entryName); 579 // resultStream has been closed by FileUtils call 580 return FileUtils.readBytes(resultStream); 581 } 582 583 public static List<String> getEntryNames(URL url) throws IOException { 584 return getEntryNames(url.openStream()); 585 } 586 587 public static boolean hasEntry(URL url, String entryName) throws IOException { 588 return hasEntry(url.openStream(), entryName); 589 } 590 591}