/*******************************************************************************
* Copyright (c) 2012 Pivotal Software, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.springsource.ide.eclipse.commons.core;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.springsource.ide.eclipse.commons.core.process.StandardProcessRunner;
import org.springsource.ide.eclipse.commons.core.util.OsUtils;
/**
* @author Steffen Pingel
* @author Leo Dos Santos
* @author Christian Dupuis
* @author Kris De Volder
* @since 2.0
*/
public class ZipFileUtil {
/**
* This Zip utility doesn't know how to extract file permission correctly
* from zip files (does Java ZipEntry even provide this info? It seems
* not!).
* <p>
* To remedy this problem, clients can provide their own logic for setting
* permissions they may care about. A subclass of PermissionSetter is used
* to determine the permission setting logic.
*
* @author Kris De Volder
*
* @since 2.8
*/
public static abstract class PermissionSetter {
/**
* Called after a file was succesfully extracted from the zip archive.
* @throws IOException
*/
public abstract void fileUnzipped(ZipEntry entry, File entryFile) throws IOException;
/**
* A permission setter that does nothing.
*/
public static final PermissionSetter NULL = new PermissionSetter() {
@Override
public void fileUnzipped(ZipEntry entry, File entryFile) {
// Do nothing
}
};
/**
* Creates an executable permission setter based on a list of file
* extensions.
* <p>
* Any file ending with the extension will be made executable.
*/
public static PermissionSetter executableExtensions(final String... exts) {
if (OsUtils.isWindows()) {
// It may be ok to do nothing for windows? (note: not tested!)
return NULL;
}
else {
// Assume we are unix if not Windows (Mac OS X is ok)
return new PermissionSetter() {
@Override
public void fileUnzipped(ZipEntry entry, File entryFile) throws IOException {
for (String ext : exts) {
if (entryFile.getName().endsWith(ext)) {
// This only works with Java 6:
// entryFile.setExecutable(true);
// This only works on Unix:
StandardProcessRunner runner = new StandardProcessRunner();
try {
runner.run(new File("."), "chmod", "a+x", entryFile.toString());
}
catch (InterruptedException e) {
// Restore the interrupted status (see
// http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html)
Thread.currentThread().interrupt();
}
return; // No sense making a file executable
// more than once.
}
}
}
};
}
}
}
private static final int BUFFER_SIZE = 512 * 1024;
public static void unzip(URL source, File targetFile, IProgressMonitor monitor) throws IOException {
unzip(source, targetFile, null, monitor);
}
public static void unzip(URL source, File targetFile, String prefix, IProgressMonitor monitor) throws IOException {
unzip(source, targetFile, prefix, PermissionSetter.NULL, monitor);
}
public static void unzip(URL source, File targetFile, String prefix, PermissionSetter permsetter,
IProgressMonitor monitor) throws IOException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
try {
monitor.beginTask("Extracting " + source.getFile(), IProgressMonitor.UNKNOWN);
byte[] buffer = new byte[BUFFER_SIZE];
ZipInputStream zipIn = new ZipInputStream(source.openStream());
try {
ZipEntry entry;
while ((entry = zipIn.getNextEntry()) != null) {
String name = entry.getName();
if (prefix != null && name.startsWith(prefix)) {
name = name.substring(prefix.length());
if (name.length() > 1) {
// cut off separator
name = name.substring(1);
}
}
Policy.checkCancelled(monitor);
monitor.subTask(name);
if (entry.isDirectory()) {
new File(targetFile, name).mkdirs();
}
else {
File entryFile = new File(targetFile, name);
entryFile.getParentFile().mkdirs();
FileOutputStream out = new FileOutputStream(entryFile);
try {
int len;
while ((len = zipIn.read(buffer)) >= 0) {
Policy.checkCancelled(monitor);
out.write(buffer, 0, len);
}
}
finally {
out.close();
}
long modTime = entry.getTime();
if (modTime > 0) {
entryFile.setLastModified(modTime);
}
permsetter.fileUnzipped(entry, entryFile);
}
}
}
finally {
zipIn.close();
}
}
finally {
monitor.done();
}
}
public static void unzip(File zipFile, File unzipDir, IProgressMonitor monitor) throws MalformedURLException, IOException {
unzip(zipFile.toURI().toURL(), unzipDir, monitor);
}
}