/*************************************************************************************
* Copyright (c) 2014 Red Hat, Inc. and others.
* 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:
* JBoss by Red Hat - Initial implementation.
************************************************************************************/
package org.jboss.tools.runtime.core.extract.internal;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.jboss.tools.runtime.core.RuntimeCoreActivator;
import org.jboss.tools.runtime.core.extract.IOverwrite;
public class UnzipUtility implements IExtractUtility {
private static String EXTRACTING = "Extracting ..."; //$NON-NLS-1$
private static final String SEPARATOR = "/"; //$NON-NLS-1$
private File file;
private String discoveredRoot = null;
private boolean rootEntryImpossible = false;
public UnzipUtility(File file) {
this.file = file;
}
public IStatus extract(File destination, IOverwrite overwriteQuery, IProgressMonitor monitor) {
if( file == null || !file.exists()) {
return new Status(IStatus.ERROR, RuntimeCoreActivator.PLUGIN_ID,
"Error opening zip file: " + file.getAbsolutePath() + "; File does not exist");
}
String possibleRoot = null;
ZipFile zipFile = null;
int overwrite = IOverwrite.NO;
destination.mkdirs();
try {
zipFile = new ZipFile(file);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
monitor.beginTask(EXTRACTING, zipFile.size());
while (entries.hasMoreElements()) {
monitor.worked(1);
if (monitor.isCanceled() || overwrite == IOverwrite.CANCEL) {
return Status.CANCEL_STATUS;
}
ZipEntry entry = (ZipEntry) entries.nextElement();
String entryName = entry.getName();
File entryFile = new File(destination, entryName);
monitor.subTask(entry.getName());
if (overwrite != IOverwrite.ALL && overwrite != IOverwrite.NO_ALL && entryFile.exists()) {
overwrite = overwriteQuery.overwrite(entryFile);
switch (overwrite) {
case IOverwrite.CANCEL:
return Status.CANCEL_STATUS;
default:
break;
}
}
if (!entryFile.exists() || overwrite == IOverwrite.YES || overwrite == IOverwrite.ALL) {
createEntry(monitor, zipFile, entry, entryFile);
}
// Lets check for a possible root, to avoid scanning the archive again later
if( !rootEntryImpossible && discoveredRoot == null) {
// Check for a root
if (entryName == null || entryName.isEmpty() || entryName.startsWith(SEPARATOR) || entryName.indexOf(SEPARATOR) == -1) {
rootEntryImpossible = true;
possibleRoot = null;
} else {
String directory = entryName.substring(0, entryName.indexOf(SEPARATOR));
if (possibleRoot == null) {
possibleRoot = directory;
} else if (!directory.equals(possibleRoot)) {
rootEntryImpossible = true;
possibleRoot = null;
}
}
}
}
} catch (IOException e) {
boolean isZipped = false;
ZipInputStream test = null;
try {
test = new ZipInputStream(new FileInputStream(file));
isZipped = test.getNextEntry() != null;
} catch(IOException ioe) {
} finally {
if( test != null ) {
try {
test.close();
} catch(IOException ioe) {
// Ignore
}
}
}
String msg = "Error opening zip file " + file.getAbsolutePath();
if( !isZipped) {
msg += "; file may not be a properly formated zip file.";
}
return new Status(IStatus.ERROR, RuntimeCoreActivator.PLUGIN_ID, msg, e);
} finally {
if (zipFile != null) {
try {
zipFile.close();
} catch (IOException e) {
// ignore
}
}
monitor.done();
}
discoveredRoot = possibleRoot;
return Status.OK_STATUS;
}
private void createEntry(IProgressMonitor monitor, ZipFile zipFile,
ZipEntry entry, File entryFile) throws IOException,
FileNotFoundException {
monitor.setTaskName(EXTRACTING + entry.getName());
if (entry.isDirectory()) {
entryFile.mkdirs();
} else {
entryFile.getParentFile().mkdirs();
InputStream in = null;
OutputStream out = null;
try {
in = zipFile.getInputStream(entry);
out = new FileOutputStream(entryFile);
copy(in, out);
} finally {
if (in != null) {
try {
in.close();
} catch (Exception e) {
// ignore
}
}
if (out != null) {
try {
out.close();
} catch (Exception e) {
// ignore
}
}
}
}
}
private void copy(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[16 * 1024];
int len;
while ((len = in.read(buffer)) >= 0) {
out.write(buffer, 0, len);
}
}
/*
* Discover the new root folder of the extracted runtime.
*/
public String getRoot(IProgressMonitor monitor) throws CoreException {
// IF we found a root during the extract, use that.
if( discoveredRoot != null )
return discoveredRoot;
if( rootEntryImpossible)
return null;
monitor.beginTask("Locating root folder", 100);
ZipFile zipFile = null;
String root = null;
try {
zipFile = new ZipFile(file);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
if (monitor.isCanceled()) {
return null;
}
ZipEntry entry = (ZipEntry) entries.nextElement();
String entryName = entry.getName();
if (entryName == null || entryName.isEmpty()
|| entryName.startsWith(SEPARATOR) || entryName.indexOf(SEPARATOR) == -1) {
return null;
}
String directory = entryName.substring(0, entryName.indexOf(SEPARATOR));
if (root == null) {
root = directory;
continue;
}
if (!directory.equals(root)) {
return null;
}
}
} catch(IOException ioe) {
Status s = new Status(IStatus.ERROR, RuntimeCoreActivator.PLUGIN_ID, ioe.getLocalizedMessage(), ioe);
throw new CoreException(s);
} finally {
if (zipFile != null) {
try {
zipFile.close();
} catch (IOException e) {
// ignore
}
}
monitor.worked(100);
monitor.done();
}
return root;
}
}