001/* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2014 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * SonarQube is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * SonarQube is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.api.utils; 021 022import org.apache.commons.io.FileUtils; 023import org.apache.commons.io.IOUtils; 024 025import java.io.*; 026import java.util.Enumeration; 027import java.util.zip.ZipEntry; 028import java.util.zip.ZipFile; 029import java.util.zip.ZipInputStream; 030import java.util.zip.ZipOutputStream; 031 032/** 033 * @since 1.10 034 */ 035public final class ZipUtils { 036 037 private static final String ERROR_CREATING_DIRECTORY = "Error creating directory: "; 038 039 private ZipUtils() { 040 // only static methods 041 } 042 043 /** 044 * Unzip a file into a directory. The directory is created if it does not exist. 045 * 046 * @return the target directory 047 */ 048 public static File unzip(File zip, File toDir) throws IOException { 049 unzip(zip, toDir, new ZipEntryFilter() { 050 @Override 051 public boolean accept(ZipEntry entry) { 052 return true; 053 } 054 }); 055 return toDir; 056 } 057 058 public static File unzip(InputStream zip, File toDir) throws IOException { 059 unzip(zip, toDir, new ZipEntryFilter() { 060 @Override 061 public boolean accept(ZipEntry entry) { 062 return true; 063 } 064 }); 065 return toDir; 066 } 067 068 public static File unzip(InputStream stream, File toDir, ZipEntryFilter filter) throws IOException { 069 if (!toDir.exists()) { 070 FileUtils.forceMkdir(toDir); 071 } 072 073 ZipInputStream zipStream = new ZipInputStream(stream); 074 try { 075 ZipEntry entry; 076 while ((entry = zipStream.getNextEntry()) != null) { 077 if (filter.accept(entry)) { 078 File to = new File(toDir, entry.getName()); 079 if (entry.isDirectory()) { 080 throwExceptionIfDirectoryIsNotCreatable(to); 081 } else { 082 File parent = to.getParentFile(); 083 throwExceptionIfDirectoryIsNotCreatable(parent); 084 copy(zipStream, to); 085 } 086 } 087 } 088 return toDir; 089 090 } finally { 091 zipStream.close(); 092 } 093 } 094 095 private static void throwExceptionIfDirectoryIsNotCreatable(File to) throws IOException { 096 if (to != null && !to.exists() && !to.mkdirs()) { 097 throw new IOException(ERROR_CREATING_DIRECTORY + to); 098 } 099 } 100 101 public static File unzip(File zip, File toDir, ZipEntryFilter filter) throws IOException { 102 if (!toDir.exists()) { 103 FileUtils.forceMkdir(toDir); 104 } 105 106 ZipFile zipFile = new ZipFile(zip); 107 try { 108 Enumeration<? extends ZipEntry> entries = zipFile.entries(); 109 while (entries.hasMoreElements()) { 110 ZipEntry entry = entries.nextElement(); 111 if (filter.accept(entry)) { 112 File to = new File(toDir, entry.getName()); 113 if (entry.isDirectory()) { 114 throwExceptionIfDirectoryIsNotCreatable(to); 115 } else { 116 File parent = to.getParentFile(); 117 throwExceptionIfDirectoryIsNotCreatable(parent); 118 copy(zipFile, entry, to); 119 } 120 } 121 } 122 return toDir; 123 124 } finally { 125 zipFile.close(); 126 } 127 } 128 129 private static void copy(ZipInputStream zipStream, File to) throws IOException { 130 FileOutputStream fos = null; 131 try { 132 fos = new FileOutputStream(to); 133 IOUtils.copy(zipStream, fos); 134 } finally { 135 IOUtils.closeQuietly(fos); 136 } 137 } 138 139 private static void copy(ZipFile zipFile, ZipEntry entry, File to) throws IOException { 140 FileOutputStream fos = new FileOutputStream(to); 141 InputStream input = null; 142 try { 143 input = zipFile.getInputStream(entry); 144 IOUtils.copy(input, fos); 145 } finally { 146 IOUtils.closeQuietly(input); 147 IOUtils.closeQuietly(fos); 148 } 149 } 150 151 public static void zipDir(File dir, File zip) throws IOException { 152 OutputStream out = null; 153 ZipOutputStream zout = null; 154 try { 155 out = FileUtils.openOutputStream(zip); 156 zout = new ZipOutputStream(out); 157 zip(dir, zout); 158 159 } finally { 160 IOUtils.closeQuietly(zout); 161 IOUtils.closeQuietly(out); 162 } 163 } 164 165 private static void doZip(String entryName, InputStream in, ZipOutputStream out) throws IOException { 166 ZipEntry entry = new ZipEntry(entryName); 167 out.putNextEntry(entry); 168 IOUtils.copy(in, out); 169 out.closeEntry(); 170 } 171 172 private static void doZip(String entryName, File file, ZipOutputStream out) throws IOException { 173 if (file.isDirectory()) { 174 entryName += '/'; 175 ZipEntry entry = new ZipEntry(entryName); 176 out.putNextEntry(entry); 177 out.closeEntry(); 178 File[] files = file.listFiles(); 179 for (int i = 0, len = files.length; i < len; i++) { 180 doZip(entryName + files[i].getName(), files[i], out); 181 } 182 183 } else { 184 InputStream in = null; 185 try { 186 in = new BufferedInputStream(new FileInputStream(file)); 187 doZip(entryName, in, out); 188 } finally { 189 IOUtils.closeQuietly(in); 190 } 191 } 192 } 193 194 private static void zip(File file, ZipOutputStream out) throws IOException { 195 for (File child : file.listFiles()) { 196 String name = child.getName(); 197 doZip(name, child, out); 198 } 199 } 200 201 public interface ZipEntryFilter { 202 boolean accept(ZipEntry entry); 203 } 204 205}